On a side note, despite my effort to minimize social media/external services I use, I started using Strava to track my runs. I made the switch mainly because I recently found out the Moves app that I regularly use was bought by Facebook years ago. Now I need something else to track my runs and without better options, I picked Strava.

Apr 24th: 2.2 miles in 00:18.

Apr 27th: 6.1 miles in 00:49.

Apr 29th: 5 miles (trail) in 01:01.

May 1st: 1.2 miles in 00:11.

May 3rd: 4.9 miles in 00:41.

May 4th: 4.1 miles in 00:34.

May 5th: 6.3 miles in 00:55.

I'm preparing for a upcoming trail half-marathon, so I mixed in some trail runs over the weekends. Running on trails was a lot more fun, although I hope I can find a trail with fewer cyclers.

Construction Finished

After eight months, my blog have finally reached a place where I feel comfortable taking down the "under heavy construction" notice on my home page. In stead of out right deleting the site road map though, I'm stashing it into a blog post.

Site Road Map

  • Find new hosting location. Currently using DigitalOcean.
  • ☑ Install Arch Linux on server.
  • Search for WP replacement. Hugo is pretty good.
  • Find a suitable theme. Currently using hugo-xmin , may consider forking it and write my own ( soresu ).
  • ☑ Server side config, like post-receive for git auto deploy.
  • ☑ Language switcher that does more than redirecting to home page.
  • ☑ Enable Disqus.
  • ☑ Support \(\LaTeX\) expressions via MathJax KaTeX.
  • ☑ Copy-paste fixed page contents from old site (and translate them).
  • ☑ Enable https.
  • ☑ Backup old WP site.
  • ☑ Transfer domain to Google Domains and ensure DNS works as intended.
  • ☑ Find out how to write with org-mode or R markdown.
  • ☑ Configure multilingual support, including footer text, title, etc.
  • ☑ Find out how to make emacs work with fcitx .
  • ☑ Use Google's Noto Sans font Oxygen Sans and Source Code Pro Iosevka for code.
  • ☑ Find a suitable icon/favicon.
  • ☑ Improve templates for posts to display tags and categories.
  • ☑ Cosmetic changes, i.e. no underlines for hyperlinks.
  • ☑ Deal with some nuances in using org-mode with hugo , like how to get syntax highlighting to work properly.
  • ☑ Host my own email.
  • ☑ Customize hugo new to make it more useful, i.e. create multilingual versions directly.
  • ☑ Self-host commenting system as a replacement of Disqus.
  • ☑ Use Let's Encrypt's wildcard certificate.
  • ☑ Restore/rewrite and translate some of the more valuable old posts.

What's on Home Page Now?

I already have an about page and a contact page for whatever I think people might be interested in knowing about myself, so I have no clue what I should put on home page. Since I found the old site road map to be a great way of reminding myself the stuffs I need to get done, I'll replace the road map with another to-do list: my goals for 2018. I am definitely not the most motivated kind of person, but seeing an unfinished to-do list every once in a while does get on my nerves. Let's see how well this is gonna work.

May 7th-13th: 21.0 miles in 03:06.

May 14th-20th: 13.4 miles in 01:54.

May 21st-27th: 19.9 miles in 04:12.

I ran my first trail half marathon yesterday and finished in just over 3 hours, inline with my expectations.

I am planning on hosting most personal repositories on my Gitea instance now that Github is acquired by Microsoft. Gitea is a breeze to setup and a lot less resource hungry than Gitlab. Hopefully Github remains awesome - I feel Github is basically Youtube of online git repositories because of its large traffic compared to other services.

Fun With Fonts in Emacs

I finally took some time to look at the my font configurations in Emacs and cleaned them up as much as possible. This dive into the rabbit hole have been tiring yet fruitful, revealing the cravat of typesetting that I didn't know before, especially for CJK characters.

I primarily use Emacs by running a daemon and connecting to it via a graphical emacsclient frame, and I am attempting to tackle three major problems: I don't have granular control over font mapping, glyph widths are sometimes inconsistent with character widths, and emoji show up as weird blocks. Terminal Emacs doesn't suffer as much from these problems, yet I don't want to give away the nice perks like system clipboard access and greater key binding options, so here goes nothing.

Font Fallback Using Fontsets

Ideally, I want to specify two sets of fonts, a default monospace font and a CJK-specific font. Here's how I originally specified the font in Emacs:

(setq default-frame-alist '((font . "Iosevka-13")))

The method above obviously leaves no ground for fallback fonts. However, it turns out I can specify the font to be a fontset instead of an individual font. According to Emacs Manual, a fontset is essentially a mapping from Unicode range to a font or hierarchy of fonts and I can modify one with relative ease.

Sounds like an easy job now? Not so fast. I don't really know which fontset to modify: fontset behavior is quirky in that the fontset Emacs ends up using seems to differ between emacsclient and normal emacs, between terminal and graphical frames, and even between different locales. While there is a way to get the current active fontset ((frame-parameter nil 'font)), this method is unreliable and may cause errors like this one.

After all kinds of attempts and DuckDuckGoing (that really rolled right off the tongue, and no, I am not the first one), I finally found the answer: just define a new fontset instead of modifying existing ones.

(defvar user/standard-fontset
  (create-fontset-from-fontset-spec standard-fontset-spec)
  "Standard fontset for user.")

;; Ensure user/standard-fontset gets used for new frames.
(add-to-list 'default-frame-alist (cons 'font user/standard-fontset))
(add-to-list 'initial-frame-alist (cons 'font user/standard-fontset))

I won't bore you with the exact logic just yet, as I also made other changes to the fontset.

Displaying Emoji

Solution to emoji display is similar—just specify a fallback font with emoji support—or so I thought. I tried to use Noto Color Emoji as my emoji font, only to find Emacs does not yet support colored emoji font. Emacs used to support colored emoji on macOS, but this functionality was later removed.

I ended up using Symbola as my emoji fallback font (actually I used it as a fallback for all Unicode characters), which provided comprehensive coverage over all the emoji and special characters. Also note that since Emacs 25, customization to the symbols charset, which contains puncation marks, emoji, etc., requires some extra work:

(setq use-default-font-for-symbols nil)

There does exist a workaround for colored emoji though, not with fancy fonts, but by replacing Unicode characters with images. emacs-emojify is a package that provides this functionality. I ultimately decided against it as it does slow down Emacs quite noticeably and the colored emoji image library is not as comprehensive.

Quotation Marks

I've always used full-width directional curly quotation marks ("“”" and "‘’") when typing in Chinese, and ASCII style ambidextrous straight quotation marks (""" and "'") when typing in English. Little did I know there really is no such thing as full-width curly quotation marks: there is only one set of curly quotation mark codepoints in Unicode (U+2018, U+2019, U+201C, and U+201D) and the difference between alleged full-width and half-width curly quotation marks is caused solely by fonts. There have been proposals to standardize the two distinct representations, but for now I'm stuck with this ambiguous mess.

It came as no surprise that these curly quotation marks are listed under symbols charset, instead of a CJK one, thus using normal monospace font despite the fact that I want them to show up as full-width characters. I don't have a true solution for this—being consistent is the only thing I can do, so I forced curly quotation marks to display as full width characters by overriding these exact Unicode codepoints in my fontset. I'm not really sure how I feel when I then realized ASCII style quotation marks also suffered from confusion—maybe we are just really bad at this.

My fallback font configurations can be found on both GitHub and Trantor Holocron and I'll list them here just for sake of completeness:

(defvar user/cjk-font "Noto Sans CJK SC"
  "Default font for CJK characters.")

(defvar user/latin-font "Iosevka Term"
  "Default font for Latin characters.")

(defvar user/unicode-font "Symbola"
  "Default font for Unicode characters, including emojis.")

(defvar user/font-size 17
  "Default font size in px.")

(defun user/set-font ()
  "Set Unicode, Latin and CJK font for user/standard-fontset."
  ;; Unicode font.
  (set-fontset-font user/standard-fontset 'unicode
                    (font-spec :family user/unicode-font)
                    nil 'prepend)
  ;; Latin font.
  ;; Only specify size here to allow text-scale-adjust work on other fonts.
  (set-fontset-font user/standard-fontset 'latin
                    (font-spec :family user/latin-font :size user/font-size)
                    nil 'prepend)
  ;; CJK font.
  (dolist (charset '(kana han cjk-misc hangul kanbun bopomofo))
    (set-fontset-font user/standard-fontset charset
                      (font-spec :family user/cjk-font)
                      nil 'prepend))
  ;; Special settings for certain CJK puncuation marks.
  ;; These are full-width characters but by default uses half-width glyphs.
  (dolist (charset '((#x2018 . #x2019)    ;; Curly single quotes "‘’"
                     (#x201c . #x201d)))  ;; Curly double quotes "“”"
    (set-fontset-font user/standard-fontset charset
                      (font-spec :family user/cjk-font)
                      nil 'prepend)))

;; Apply changes.
(user/set-font)
;; For emacsclient.
(add-hook 'before-make-frame-hook #'user/set-font)

CJK Font Scaling

My other gripe is the width of CJK fonts does not always match up with that of monospace font. Theoretically, full-width CJK characters should be exactly twice of that half-width characters, but this is not the case, at least not in all font sizes. It seems that CJK fonts provide less granularity in size, i.e. 16px and 17px versions of CJK characters in Noto Sans CJK SC are exactly the same, and does not increase until size is bumped up to 18px, while Latin characters always display the expected size increase. This discrepancy means their size would match every couple sizes, but different in between with CJK fonts being a bit too small.

One solution is to specify a slightly larger default size for CJK fonts in the fontset. However, this method would render text-scale-adjust (normally bound to C-x C-= and C-x C--) ineffective against CJK fonts for some reason. A better way that preserves this functionality is to scale the CJK fonts up by customizing face-font-rescale-alist:

(defvar user/cjk-font "Noto Sans CJK SC"
  "Default font for CJK characters.")

(defvar user/font-size 17
  "Default font size in px.")

(defvar user/cjk-font-scale
  '((16 . 1.0)
    (17 . 1.1)
    (18 . 1.0))
  "Scaling factor to use for cjk font of given size.")

;; Specify scaling factor for CJK font.
(setq face-font-rescale-alist
      (list (cons user/cjk-font
                  (cdr (assoc user/font-size user/cjk-font-scale)))))

bWhile the font sizes might still go out of sync after text-scale-adjust, I am not too bothered. The exact scaling factor took me a few trial and error to find out. I just kept adjusting the factor until these line up (I found this table really useful):

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云
雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲
ㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞ
ああああああああああああああああああああああああああああああああああああああああ
가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가

Unfortunately, the CJK font I used has narrower Hangul than other full-width CJK characters, so this is still not perfect—the solution would be to specify a Hangul specific font and scaling factor—but good enough for me.

It took me quite some effort to fix what may seem like a minor annoyance, but at least Emacs did offer the appropriate tools. By the way, I certainly wish I had found this article on Emacs Wiki sooner, as it also provides a neat write up of similar workarounds.

It just occurred to me nearly half of 2018 has passed. So far I'm a bit behind the pace on my 1000-mile goal, with only 340 miles so far. I totally blame the weather on this one---running at 100 °F is pretty exhausting. I've finished 5 blog posts this year (that's 10 counting both languages), with 3 more in the works, which is pretty good progress.