Category Archives: org

2020-09-07 Emacs news

Almost forgot to say: EmacsConf 2020 Call for Proposals is open until Sept 30, 2020. Please encourage someone you’d like to hear from! =)

Links from reddit.com/r/emacs, r/orgmode, r/spacemacs, r/planetemacs, Hacker News, planet.emacslife.com, YouTube, the Emacs NEWS file and emacs-devel.

Updated my blog index using Org Mode

I just spent 40 minutes updating my blog index to include all the non-Emacs News and non-weekly/monthly-review posts since April 2017. I had kept a blog index as a way to quickly organize my posts into finer-grained categories without mucking around too much with WordPress. Updating it was pretty easy since I had built an Org Mode list view into my theme eight years ago. A URL like https://sachachua.com/blog/2020/?org=1 gets me a list like:

- [[https://sachachua.com/blog/2020/01/2020-01-06-emacs-news/][2020-01-06 Emacs news]] 
- [[https://sachachua.com/blog/2020/01/weekly-review-week-ending-december-13-2019/][Weekly review: Week ending December 13, 2019]] 
- [[https://sachachua.com/blog/2020/01/weekly-review-week-ending-december-20-2019/][Weekly review: Week ending December 20, 2019]] 
- [[https://sachachua.com/blog/2020/01/weekly-review-week-ending-january-3-2020/][Weekly review: Week ending January  3, 2020]] 
- [[https://sachachua.com/blog/2020/01/weekly-review-week-ending-december-27-2019/][Weekly review: Week ending December 27, 2019]] 
- [[https://sachachua.com/blog/2020/01/2020-01-13-emacs-news/][2020-01-13 Emacs news]] 
- [[https://sachachua.com/blog/2020/01/2020-01-20-emacs-news/][2020-01-20 Emacs news]]
...

which is easy to narrow to in Emacs with narrow-to-region (C-x n n) and filter with flush-lines to get rid of all the fairly routine weekly reviews and Emacs news posts. Then I could use my/org-file-blog-index-entries from my Emacs config to file things to the high-level trees, and (while t (my/org-move-current-item-to-category (completing-read "Category: " (my/org-get-list-categories)))) to file things within a list.

Yay Emacs!

Having fun kerning using Org Mode and FontForge

It turns out that working with font bearings and kerning tables using Org Mode makes lots of things so much easier.

Bearings in the top left, kerning matrix in the top right

While trying to figure out kerning, I came across this issue that described how you sometimes need a character-pair kern table instead of just class-based kerning. Since I had figured out character-based kerning before I figured out class-based kerning, it was easy to restore my Python code that takes the same kerning matrix and generates character pairs. Here’s what that code looks like.

def kern_by_char(font, kerning_matrix):
  # Add kerning by character as backup
  font.addLookupSubtable("kern", "kern-2")
  offsets = np.asarray(kerning_matrix)
  classes_right = [None if (x == "" or x == "None") else x.split(",") for x in offsets[0,1:]]
  classes_left = [None if (x == "" or x == "None") else x.split(',') for x in offsets[1:,0]]
  for r, row in enumerate(classes_left):
    if row is None: continue
    for first_letter in row:
      g = font.createMappedChar(first_letter)
      for c, column in enumerate(classes_right):
        if column is None: continue
        for second_letter in column:
          if kerning_matrix[r + 1][c + 1]:
            g.addPosSub("kern-2", second_letter, 0, 0, kerning_matrix[r + 1][c + 1], 0, 0, 0, 0, 0)
  return font

I wanted to be able to easily compare different versions of my font: my original glyphs versus my tweaked glyphs, simple spacing versus kerned. This was a hassle with FontForge, since I had to open different font files in different Metrics windows. If I execute a little bit of source code in my Org Mode, though, I can use my test web page to view all the different versions. By arranging my Emacs windows a certain way and adding :eval no to the Org Babel blocks I’m not currently using, I can easily change the relevant table entries and evaluate the whole buffer to regenerate the font versions, including exports to OTF and WOFF. Here’s the code for that:

<<params>>
<<def_import_glyphs>>
<<def_set_bearings>>
<<def_kern_classes>>
<<def_kern_by_char>>
font = fontforge.font()
font = import_glyphs(font, params)
font = set_bearings(font, bearings)
save_font(font, {**params, "new_otf": "sachacHandRaw.otf"})
font = kern_classes(font, kerning_matrix)
font = kern_by_char(font, kerning_matrix)
save_font(font, {**params, "new_otf": "sachacHandRawKerned.otf"})
font = load_font('SachaHandEdited.sfd')
font = set_bearings(font, bearings)
font.removeLookup('kern')
save_font(font, {**params, "new_otf": "sachacHandEdited.otf"})
font = kern_classes(font, kerning_matrix)
font = kern_by_char(font, kerning_matrix)
save_font(font, {**params, "new_otf": "sachacHand.otf"})

I also like the way it’s pretty easy to update multiple kerning values without clicking around. I sometimes use FontForge to get the number to set it to and then copy that into my table, but I also sometimes just tweak the number in Org Mode directly.

To see the results, I can generate a test HTML that shows me text with different versions of my font. I can also look at lots of kerning pairs at the same time. Here are the components of that test page:

def test_css(fonts):
  doc, tag, text, line = Doc().ttl()
  with tag('style'):
    for f in fonts:
      text("@font-face { font-family: '%s'; src: url('%s'); }" % (f[0], f[1]))
      text(".%s { font-family: '%s'; }" % (f[0], f[0]))
    text("table { font-size: inherit; font-weight: inherit }")
    text("td { text-align: left }")
    text(".blog-heading { font-weight: bold; font-size: 32px }")
    text(".default { color: gray }")
    text("body { font-family: woff, Arial, sans-serif; font-size: 32px; padding: 10px }")
  return doc.getvalue()
def test_html(strings):
  doc, tag, text, line = Doc().ttl()
  with doc.tag('table', style='border-bottom: 1px solid gray; width: 100%; border-collapse: collapse'):
    for s in strings:
      for i, f in enumerate(fonts):
        style = 'border-top: 1px solid gray' if (i == 0) else ""
        with tag('tr', klass=f[0], style=style):
          line('td', f[0])
          line('td', s)
  return doc.getvalue()
def test_kerning_matrix(kerning_matrix):
  doc, tag, text, line = Doc().ttl()
  with tag('table'):
    for r, row in enumerate(classes_left):
      if row is None: continue
      for first_letter in row:
        with tag('tr'):
          line('td', first_letter)
          for c, column in enumerate(classes_right):
            if column is None: continue
            for second_letter in column:
              klass = "kerned" if kerning_matrix[r + 1][c + 1] else "default"
              line('td', aglfn.to_glyph(first_letter) + aglfn.to_glyph(second_letter), klass=klass)
  return doc.getvalue()

This code actually generates the test file:

from yattag import Doc
import numpy as np
import aglfn
<<def_test_html>>
doc, tag, text, line = Doc().ttl()
fonts = [['raw', 'sachacHandRaw.otf'],
         ['raw-kerned', 'sachacHandRawKerned.otf'],
         ['edited', 'sachacHandEdited.otf'],
         ['woff', 'sachacHand.woff']]
strings = ["Python+FontForge+Org: I made a font based on my handwriting!",
           "Monthly review: May 2020",
           "Emacs News 2020-06-01"]
offsets = np.asarray(kerning_matrix)
classes_left = [None if (x == "" or x == "None") else x.split(',') for x in offsets[1:,0]]
classes_right = [None if (x == "" or x == "None") else x.split(",") for x in offsets[0,1:]]
with tag('html'):
  with tag('head'): 
    doc.asis(test_css(fonts))
  with tag('body'):
    line('h1', 'Test headings')
    with tag('div', klass="blog-heading"):
      doc.asis(test_html(strings))
    line('h1', 'Kerning matrix')
    doc.asis(test_kerning_matrix(kerning_matrix))
return doc.getvalue()

And here’s what that test.html looks like:

Testing the font with a few blog headings
Kerning pairs: black for specified pairs, gray for defaults

Not bad… Now Emacs is my font editor! The code is at https://github.com/sachac/sachac-hand .

Python+FontForge+Org: I made a font based on my handwriting!

I wanted to make a font based on my handwriting using only free software. It turns out that FontForge can be scripted with Python. I know just a little about Python and even less about typography, but I managed to hack together something that worked for me. If you’re reading this on my blog at https://sachachua.com/blog/ , you’ll probably see the new font being used on the blog post titles. Whee!

My rough notes are at https://github.com/sachac/sachac-hand/ . I wanted to write it as a literate program using Org Babel blocks. It’s not really fully reproducible yet, but it might be a handy starting point. The basic workflow was:

  1. Generate a template using other fonts as the base.
  2. Import the template into Medibang Paint on my phone and draw letters on a different layer. (I almost forgot the letter q, so I had to add it at the last minute.)
  3. Export just the layer with my writing.
  4. Cut the image into separate glyphs using Python and autotrace each one.
  5. Import each glyph into FontForge as an SVG and a PNG.
  6. Set the left side and right side bearing, overriding as needed based on a table.
  7. Figure out kerning classes.
  8. Hand-tweak the contours and kerning.
  9. Use sfnt2woff to export the web font file for use on my blog, and modify the stylesheet to include it.

I really liked being able to specify kerning classes through an Org Mode table like this:

  None o,a,c,e,d,g,q,w f,t,x,v,y,z h,b,l,i,k j m,n,p,r,u s T zero
None 0 0 0 0 0 0 0 0 0
f 0 -102 -61 -30 0 -60 0 -120 -70
t 0 -70 -41 -25 0 0 0 -120 -10
r 0 -82 -41 -25 0 -20 0 -120 29
k 0 -50 -81 -20 0 -20 -48 -120 -79
l 0 -41 -50 0 0 0 0 -120 -52
v 0 -40 -35 -30 0 0 0 -120 30
b,o,p 0 -20 -80 0 0 0 0 -120 43
a 0 -23 -60 0 0 0 0 -120 7
W 0 -40 -30 -20 0 0 0 -120 17
T 0 -190 -120 -60 0 -130 0 0 -188
F 0 -100 -90 -60 0 -70 -100 -40 -166
two 0 0 0 0 0 0 0 0 -53

I had a hard time defining classes using the FontForge interface because I occasionally ended up clearing my glyph selection, so it was great being able to just edit my columns and rows.

Clearly my kerning is still very rough–no actual values for j, for example–but it’s a start. Also, I can probably figure out how to combine this with character pair kerning and have two tables for easier tweaking.

A- insisted on tracing my handwriting template a few times, so I might actually be able to go through the same process to convert her handwriting into a font. Whee!

Python, Org Mode, and writing Org tables to CSVs so that I can read them back

I’ve been getting deeper into Python so that I can model our personal finances. I really like using the pandas library to manipulate data. All those years I spent trying to juggle increasing complex spreadsheets… Working with Python code in Org Babel blocks is just so much more fun. I like being able to keep my assumptions in tables without having to fuss around with naming cells for easy-to-read formulas, slice and summarize parts of my data frames, organize my notes in outlines and add commentary, and define more complicated functions that I don’t have to squeeze into a single line.

I haven’t quite been able to tempt W- into the world of Org Babel Python blocks. Still, I don’t want to give up the awesomeness of having pretty tables that I can easily edit and use. So I have a bunch of named tables (using #+NAME:), and some code that exports my tables to CSVs:

#+NAME: tables
| Table         | Key                 |
|---------------+---------------------|
| assets_w      | Description         |
| assets_s      | Description         |
| tax_rates     |                     |
| disposition   | Asset               |
| probate_rates | Asset               |
| basic         | Client information  |
| base_expenses | Category            |
| general       | General assumptions |

#+begin_src emacs-lisp :results silent :var tables=tables :tangle no
  (defun my-tbl-export (row)
    "Search for table named `NAME` and export."
    (interactive "s")
    (save-excursion
      (goto-char (point-min))
      (let ((case-fold-search t))
        (when (search-forward-regexp (concat "#\\+NAME: +" (car row)) nil t)
          (next-line)
          (org-table-export (format "%s.csv" (car row)) "orgtbl-to-csv")))))
  (mapc 'my-tbl-export tables)
#+end_src

and some code that imports them back in, and formats tables nicely if I’m displaying them in Org. The in_org block doesn’t get tangled into index.py, so I don’t clutter command-line use with Org table markup.

#+begin_src python :results silent :tangle no
  in_org=1
#+end_src

#+begin_src python :results silent :exports code
  import pandas as pd
  import numpy as np
  import orgbabelhelper as ob
  def out(df, **kwargs):
    if 'in_org' in globals():
      print(ob.dataframe_to_orgtable(df, **kwargs))
    else:
      print(df)
    return df
#+end_src

#+begin_src python :results silent :var tables=tables :colnames yes
  for row in tables:
    table = row[0]
    index = row[1] 
    if row[1] == '':
      index = None
    globals()[table] = pd.read_csv(table + '.csv', index_col=index).apply(pd.to_numeric, errors='ignore')
    # print(globals()[table])
#+end_src

Then I can use C-c C-v C-b (org-babel-execute-buffer) to update everything if I change the table in my Org file, and I can use C-c C-v C-t (org-babel-tangle) to create an index.py that W- can read through or run without needing Org.

Turning an Org Mode outline into an HTML table with a column for more notes

The last time A- had a babysitter, I quickly scribbled down some ideas for activities that A- might enjoy. The babysitter found the list very helpful, so I figured I’d make a list that I could easily update as A-‘s interests change. I wanted a two-column table with space for notes, but I didn’t want to fiddle with LibreOffice or manually writing HTML. Org Mode to the rescue! To turn something like this:

* Activity ideas  :noexport:
** Gross motor
*** Balance on one leg
*** Coast on the balance bike
** Fine motor
*** Cut along a curve or shape
...

into a table like this:

Two-column table

I wrote this bit of code inside a #+begin_src emacs-lisp :exports results :results value html#+end_src block:

(let* ((elements (org-element-parse-buffer))
       (activity-ideas
        (org-element-contents
         (org-export-resolve-link
          "Activity ideas"
          `(:parse-tree ,elements)))))
  (format
   "<table><tr><th width=\"50%%\">Activity ideas</th><th width=\"50%%\">Notes</th></tr>%s</table>"
   (mapconcat
    (lambda (section)
      (format "<tr><td><h2>%s</h2><ul>%s</ul></td><td></td></tr>"
              (org-element-property :raw-value section)
              (mapconcat (lambda (idea)
                           (format "<li>%s</li>"
                                   (org-element-property :raw-value idea)))
                         (org-element-contents section)
                         "")))
    (org-element-contents activity-ideas)
    "")))

I can then export the buffer to HTML and get my nice neat table by itself, since the data comes from a subtree with the :noexport: tag. The code parses the elements in the buffer, looks at the children under the “Activity ideas” header, turns each child into a table row, and turns the children of those nodes into list items.

The code coincidentally takes advantage of the org-export-resolve-link I wrote to help someone with an Org feature request. Yay for multipurpose code!

For the next step, I’ll probably put TODO state filtering in so that I can keep a long list of activities and then select a few for each category. It’s nice to have an outline I can easily update!