commit d6d4e2e09ff0692bd7575621cb58882a53a40ca5
parent 97e7b1f3f459f7f6678a349db06f0d86d099a514
Author: Shimmy Xu <shimmy.xu@shimmy1996.com>
Date: Mon, 25 Jun 2018 22:38:17 -0500
New post: Fun With Fonts in Emacs.
Diffstat:
6 files changed, 826 insertions(+), 1 deletion(-)
diff --git a/config.toml b/config.toml
@@ -12,6 +12,9 @@ pygmentsCodefencesGuessSyntax = false
pygmentsStyle = "emacs"
pygmentsOptions = "linenos="
+[Blackfriday]
+smartypants = false
+
[params]
soresuLatexOffByDefault = true
@@ -21,6 +24,7 @@ posts = "/posts/:year-:month-:day-:slug/"
[Taxonomies]
category = "categories"
tag = "tags"
+serie = "series"
[Languages]
[Languages.en]
diff --git a/content/posts/2018-06-24-fun-with-fonts-in-emacs.en.md b/content/posts/2018-06-24-fun-with-fonts-in-emacs.en.md
@@ -0,0 +1,213 @@
++++
+title = "Fun With Fonts in Emacs"
+date = 2018-06-24
+slug = "fun-with-fonts-in-emacs"
+tags = ["font", "typesetting", "emacs", "emacs-lisp"]
+categories = ["geekery"]
+draft = false
+series = ["fun-with-fonts"]
++++
+
+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 {#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:
+
+```emacs-lisp
+(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](https://www.gnu.org/software/emacs/manual/html%5Fnode/emacs/Fontsets.html), a fontset is essentially a mapping from Unicode
+range to a font or hierarchy of fonts and I can [modify](https://www.gnu.org/software/emacs/manual/html%5Fnode/emacs/Modifying-Fontsets.html) 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](https://lists.gnu.org/archive/html/emacs-devel/2006-12/msg00285.html).
+
+After all kinds of attempts and DuckDuckGoing (that really rolled right off the
+tongue, and no, I am [not the first one](https://www.reddit.com/r/duckduckgo/comments/8cm51u/what%5Fing%5Fverb%5Fdo%5Fyou%5Fuse%5Ffor%5Fduckduckgo/)), I finally found the [answer](https://stackoverflow.com/questions/17102692/using-a-list-of-fonts-with-a-daemonized-emacs): just define
+a new fontset instead of modifying existing ones.
+
+```emacs-lisp
+(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 {#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](https://github.com/emacs-mirror/emacs/blob/emacs-25.1/etc/NEWS#L1723).
+
+I ended up using [Symbola](http://users.teilar.gr/~g1951d/) as my emoji fallback font (actually I used it as a
+fallback for all Unicode characters), which provided comprehensive coverage over
+[all the emoji](https://unicode.org/Public/emoji/11.0/emoji-test.txt) and special characters. Also note that since Emacs 25,
+customization to the `symbols` [charset](https://www.gnu.org/software/emacs/manual/html%5Fnode/emacs/Charsets.html), which contains puncation marks, emoji,
+etc., requires [some extra work](https://github.com/emacs-mirror/emacs/blob/emacs-25/etc/NEWS#L58):
+
+```emacs-lisp
+(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`](https://github.com/iqbalansari/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 {#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](https://www.unicode.org/L2/L2014/14006-sv-western-vs-cjk.pdf) 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](https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html)---maybe we are just really bad at this.
+
+My fallback font configurations can be found on both [GitHub](https://github.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback) and [Trantor Network](https://git.shimmy1996.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback)
+and I'll list them here just for sake of completeness:
+
+```emacs-lisp
+(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 {#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 <kbd>C-x C-=</kbd> and <kbd>C-x C--</kbd>) 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`:
+
+```emacs-lisp
+(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](https://websemantics.uk/articles/font-size-conversion/)
+really useful):
+
+```nil
+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](https://www.emacswiki.org/emacs/FontSets) on Emacs Wiki sooner, as it also provides a neat write up of
+similar workarounds.
diff --git a/content/posts/2018-06-24-fun-with-fonts-in-emacs.zh.md b/content/posts/2018-06-24-fun-with-fonts-in-emacs.zh.md
@@ -0,0 +1,189 @@
++++
+title = "字体配置 Emacs 篇"
+date = 2018-06-24
+slug = "fun-with-fonts-in-emacs"
+tags = ["font", "typesetting", "emacs", "emacs-lisp"]
+categories = ["geekery"]
+draft = false
+series = ["fun-with-fonts"]
++++
+
+我终于花了些时间清理我 Emacs 里一团糟的字体设定。在折腾这些设定的过程中,我了解
+到了一些中日韩( CJK )字体排版上的豆知识。
+
+我主要使用 Emacs 的方式是使用一个图形 `emacsclient` 窗口链接在后台运行的守护进程。
+我所要解决的主要问题有三个:缺少精细控制字体映射的方法、字形宽度和字符宽度不一致、
+emoji 时常显示为豆腐块。虽然终端 Emacs 不大受这些问题的影响,但我不想放弃图形
+Emacs 的其他好处,例如系统剪贴板和更加丰富的键位选择,所以我只好迎难而上着手解决
+这些问题。
+
+
+## 使用字体集( Fontset )设置后备字体 {#使用字体集-fontset-设置后备字体}
+
+在最理想的状况下,我想指定两套字体,一套默认的等宽字体和一套专门显示中日韩字符的字
+体。我原来是这么设定 Emacs 字体的:
+
+```emacs-lisp
+(setq default-frame-alist '((font . "Iosevka-13")))
+```
+
+这种方法显然无法指定后备字体。不过 `font` 除了接受单一字体外,也可以接受字体集。
+根据 [Emacs手册](https://www.gnu.org/software/emacs/manual/html%5Fnode/emacs/Fontsets.html) ,字体集可以大致理解为从 Unicode 到字体的映射,并且我可以很容易地
+[修改](https://www.gnu.org/software/emacs/manual/html%5Fnode/emacs/Modifying-Fontsets.html) 字体集。
+
+听上去似乎很容易?且慢。我并不知道应该被修改的是哪一个字体集: Emacs 最终使用的
+字体集似乎会因语言环境( locale )、使用图形还是终端窗口、使用 `emacsclient` 还
+是 `emacs` 而变化。尽管有方法可以获得目前使用的字体集( `(frame-parameter nil
+'font)` ),但这 [并不完全可靠](https://lists.gnu.org/archive/html/emacs-devel/2006-12/msg00285.html) 。
+
+在不少失败的尝试之后,我终于找到了 [答案](https://stackoverflow.com/questions/17102692/using-a-list-of-fonts-with-a-daemonized-emacs) :直接定义一个新的字体集。
+
+```emacs-lisp
+(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))
+```
+
+由于我除了指定中日韩字体外还对字体集做了其他更改,我会在阐明所有改变后再贴出全部
+设定。
+
+
+### 显示 Emoji {#显示-emoji}
+
+解决 emoji 显示的方法与中日韩文字类似——找到一款支持 emoji 的字体不就好了吗——至少
+我是这么想的。我一开始试图使用 Noto Color Emoji 作为 emoji 用后备字体,但发现
+Emacs 目前并不支持彩色 emoji 字体。 Emacs 曾经在 macOS 上支持彩色 emoji字体,但
+后来 [移除](https://github.com/emacs-mirror/emacs/blob/emacs-25.1/etc/NEWS#L1723) 了。
+
+我最后选择了 [Symbola](http://users.teilar.gr/~g1951d/) 作为 emoji 后备字体(事实上我把它设为了所有 Unicode 字符的
+后备字体)。 Symbola 可以显示 [所有 emoji](https://unicode.org/Public/emoji/11.0/emoji-test.txt) 和许多特殊符号。还需要注意的一点是,在
+Emacs 25 之后,要想在字体集中自定义包含了大部分标点、特殊符号、 emoji 的
+`symbols` [字符集( charset )](https://www.gnu.org/software/emacs/manual/html%5Fnode/emacs/Charsets.html),需要[一些额外的设置](https://github.com/emacs-mirror/emacs/blob/emacs-25/etc/NEWS#L58):
+
+```emacs-lisp
+(setq use-default-font-for-symbols nil)
+```
+
+如果实在想要显示彩色 emoji 倒也不是完全没有办法,不过不是通过设置字体,而是将
+Unicode 字符替换为图片。[`emacs-emojify`](https://github.com/iqbalansari/emacs-emojify) 就是一个提供这种功能的 Emacs 包。由于这
+个包会给 Emacs 带来一定的延迟,而且大部分彩色 emoji 图片库并不完整,我最终决定不
+予采用。
+
+
+### 引号风波 {#引号风波}
+
+我一直习惯在书写中文时使用成对的全角弯引号(““””和“‘’”)以及在书写英文时
+使用 ASCII 里的对称直引号(“"”和“'”)。然而我并不知道“全角弯引号”其实根本
+不存在: Unicode 中只存在一组弯引号编码( U+2018 、 U+2019 、 U+201C 、U+201D ),
+而所谓的全角与半角弯引号之分完全是字体引起的。虽然已经有相关的 [提案](https://www.unicode.org/L2/L2014/14006-sv-western-vs-cjk.pdf) 建议将这两种
+不同的表示方法标准化,但目前弯引号就是这么一个烂摊子。
+
+了解来龙去脉之后,就不难理解为什么弯引号在 Emacs 里隶属 `symbol` 字符集而非某个
+中日韩字符集了。这也导致这些弯引号会使用我的默认等宽字体并显示为半角字符。我并没
+有从根本上解决这一问题的办法,所以为了保证显示风格和书写风格保持一致,我通过为特
+定的 Unicode 编码指定字体将这些弯引号字符统一显示为全角。当我知道直引号其实也有
+着 [充满误会的过去](https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html) 的时候,我已经不知道应该用什么表情来面对了——也许我们在这方面真
+的很糟糕。
+
+我的后备字体设置可以在 [GitHub](https://github.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback) 和 [川陀网络](https://git.shimmy1996.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback) 上找到。为了日志的完整性,我在这里也放
+一份:
+
+```emacs-lisp
+(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)
+```
+
+
+## 中日韩字体大小比例 {#中日韩字体大小比例}
+
+最后需要解决的问题就是中日韩字体字宽和等宽字体比例不一致的问题了。理论上全角的中
+日韩字符应该是半角字符宽度的两倍,但这并不在所有字号下成立。看起来原因是中日韩字
+体在字号上其实偷懒了:在使用 Noto Sans CJK SC 时, 16px 和 17px 大小的中日韩字符
+是没有任何大小区别的,直到 18px 才会出现大一号的字形,不像拉丁字符始终表现出预期
+的尺寸增幅。这一现象使得中日韩字符和拉丁字符在每隔数个字号后大小比例相称,但使用
+夹在中间的字号时中日韩字符会略微偏小。
+
+一种解决方式时在修改字体集时给中日韩字体设置一个稍大一些的默认字号。不过这会导致
+`text-scale-adjust` (通常被绑定在 <kbd>C-x C-=</kbd> 和 <kbd>C-x C--</kbd> 上)对中日韩字体不生效。
+一种更好的办法是修改 `face-font-rescale-alist` 设置缩放比例:
+
+```emacs-lisp
+(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)))))
+```
+
+虽然在使用 `text-scale-adjust` 后字体大小比例依然可能会乱掉,但我只要默认字号下
+对齐就行。具体的缩放比例只能通过反复测试来确定。我用以下几行字符是否对齐来判断缩
+放比例是否合适(这张 [表格](https://websemantics.uk/articles/font-size-conversion/) 会是很好的帮手):
+
+```nil
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云
+雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲
+ㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞ
+ああああああああああああああああああああああああああああああああああああああああ
+가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가
+```
+
+不巧的是,我所使用中日韩字体的谚文比其他全角字符都要窄,所以最终结果仍不完美——解
+决方案是再添加一个谚文专用的字体和缩放比例——不过对我来说够用了。
+
+我在解决这些看似简单的问题上花的精力比想象的多不少,不过值得庆幸的是 Emacs 提供
+了所需的各项工具。顺便一提, Emacs Wiki 上的 [这篇文章](https://www.emacswiki.org/emacs/FontSets) 也提供了一些类似的问题的解
+决方案:要是我早一些看到,配置过程大概会顺利许多。
diff --git a/i18n/en.toml b/i18n/en.toml
@@ -7,6 +7,9 @@ other = "Categories"
[tags]
other = "Tags"
+[series]
+other = "Series"
+
# Translation for categories
[geekery]
other = "Geekery"
@@ -24,11 +27,20 @@ other = "Arch Linux"
[design]
other = "Design"
+[emacs-lisp]
+other = "Emacs Lisp"
+
+[emacs]
+other = "Emacs"
+
[email]
other = "Email"
+[font]
+other = "Font"
+
[hugo]
-other = "hugo"
+other = "Hugo"
[keyboard]
other = "Keyboard"
@@ -47,3 +59,10 @@ other = "Server"
[social-network]
other = "Social Network"
+
+[typesetting]
+other = "Typesetting"
+
+# Translation for series
+[fun-with-fonts]
+other = "Fun With Fonts"+
\ No newline at end of file
diff --git a/i18n/zh.toml b/i18n/zh.toml
@@ -7,6 +7,9 @@ other = "分类"
[tags]
other = "标签"
+[series]
+other = "系列"
+
# Translation for categories
[geekery]
other = "折腾"
@@ -47,3 +50,19 @@ other = "服务器"
[social-network]
other = "社交网络"
+
+[font]
+other = "字体"
+
+[typesetting]
+other = "排版"
+
+[emacs]
+other = "Emacs"
+
+[emacs-lisp]
+other = "Emacs Lisp"
+
+# Translation for series
+[fun-with-fonts]
+other = "字体配置"+
\ No newline at end of file
diff --git a/org/2018.org b/org/2018.org
@@ -313,6 +313,385 @@ Planck 是另一块让我下心思设计布局的键盘。 40% 键盘所能塞
给键盘画像素画其实挺有意思,要想保持精确的比例几乎是不可能的,这就需要在精准和简约之间作微妙的平衡。我有时间时会继续更新这些像素画的。
+** TODO Fun With Fonts :font:typesetting:
+:PROPERTIES:
+:EXPORT_HUGO_CUSTOM_FRONT_MATTER: :series '(fun-with-fonts)
+:END:
+
+*** DONE Fun With Fonts In Emacs :emacs:emacs_lisp:
+:PROPERTIES:
+:EXPORT_DATE: 2018-06-24
+:EXPORT_HUGO_SLUG: fun-with-fonts-in-emacs
+:END:
+
+**** DONE en
+:PROPERTIES:
+:EXPORT_FILE_NAME: 2018-06-24-fun-with-fonts-in-emacs.en.md
+:EXPORT_TITLE: Fun With Fonts in Emacs
+:END:
+
+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:
+#+BEGIN_SRC emacs-lisp
+ (setq default-frame-alist '((font . "Iosevka-13")))
+#+END_SRC
+
+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 [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Fontsets.html][Emacs Manual]], a fontset is essentially a mapping from Unicode
+range to a font or hierarchy of fonts and I can [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Modifying-Fontsets.html][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 [[https://lists.gnu.org/archive/html/emacs-devel/2006-12/msg00285.html][this one]].
+
+After all kinds of attempts and DuckDuckGoing (that really rolled right off the
+tongue, and no, I am [[https://www.reddit.com/r/duckduckgo/comments/8cm51u/what_ing_verb_do_you_use_for_duckduckgo/][not the first one]]), I finally found the [[https://stackoverflow.com/questions/17102692/using-a-list-of-fonts-with-a-daemonized-emacs][answer]]: just define
+a new fontset instead of modifying existing ones.
+#+BEGIN_SRC emacs-lisp
+ (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))
+#+END_SRC
+
+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 [[https://github.com/emacs-mirror/emacs/blob/emacs-25.1/etc/NEWS#L1723][removed]].
+
+I ended up using [[http://users.teilar.gr/~g1951d/][Symbola]] as my emoji fallback font (actually I used it as a
+fallback for all Unicode characters), which provided comprehensive coverage over
+[[https://unicode.org/Public/emoji/11.0/emoji-test.txt][all the emoji]] and special characters. Also note that since Emacs 25,
+customization to the =symbols= [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Charsets.html][charset]], which contains puncation marks, emoji,
+etc., requires [[https://github.com/emacs-mirror/emacs/blob/emacs-25/etc/NEWS#L58][some extra work]]:
+#+BEGIN_SRC emacs-lisp
+ (setq use-default-font-for-symbols nil)
+#+END_SRC
+
+There does exist a workaround for colored emoji though, not with fancy fonts,
+but by replacing Unicode characters with images. [[https://github.com/iqbalansari/emacs-emojify][=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 [[https://www.unicode.org/L2/L2014/14006-sv-western-vs-cjk.pdf][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
+[[https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html][confusion]]---maybe we are just really bad at this.
+
+My fallback font configurations can be found on both [[https://github.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback][GitHub]] and [[https://git.shimmy1996.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback][Trantor Network]]
+and I'll list them here just for sake of completeness:
+#+BEGIN_SRC emacs-lisp
+ (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)
+#+END_SRC
+
+***** 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=:
+#+BEGIN_SRC emacs-lisp
+ (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)))))
+#+END_SRC
+
+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 [[https://websemantics.uk/articles/font-size-conversion/][this table]]
+really useful):
+#+BEGIN_SRC
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云
+雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲
+ㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞ
+ああああああああああああああああああああああああああああああああああああああああ
+가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가
+#+END_SRC
+
+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 [[https://www.emacswiki.org/emacs/FontSets][this article]] on Emacs Wiki sooner, as it also provides a neat write up of
+similar workarounds.
+
+**** DONE zh
+:PROPERTIES:
+:EXPORT_FILE_NAME: 2018-06-24-fun-with-fonts-in-emacs.zh.md
+:EXPORT_TITLE: 字体配置 Emacs 篇
+:END:
+
+我终于花了些时间清理我 Emacs 里一团糟的字体设定。在折腾这些设定的过程中,我了解
+到了一些中日韩( CJK )字体排版上的豆知识。
+
+我主要使用 Emacs 的方式是使用一个图形 =emacsclient= 窗口链接在后台运行的守护进程。
+我所要解决的主要问题有三个:缺少精细控制字体映射的方法、字形宽度和字符宽度不一致、
+emoji 时常显示为豆腐块。虽然终端 Emacs 不大受这些问题的影响,但我不想放弃图形
+Emacs 的其他好处,例如系统剪贴板和更加丰富的键位选择,所以我只好迎难而上着手解决
+这些问题。
+
+***** 使用字体集( Fontset )设置后备字体
+在最理想的状况下,我想指定两套字体,一套默认的等宽字体和一套专门显示中日韩字符的字
+体。我原来是这么设定 Emacs 字体的:
+#+BEGIN_SRC emacs-lisp
+ (setq default-frame-alist '((font . "Iosevka-13")))
+#+END_SRC
+
+这种方法显然无法指定后备字体。不过 =font= 除了接受单一字体外,也可以接受字体集。
+根据 [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Fontsets.html][Emacs手册]] ,字体集可以大致理解为从 Unicode 到字体的映射,并且我可以很容易地
+[[https://www.gnu.org/software/emacs/manual/html_node/emacs/Modifying-Fontsets.html][修改]] 字体集。
+
+听上去似乎很容易?且慢。我并不知道应该被修改的是哪一个字体集: Emacs 最终使用的
+字体集似乎会因语言环境( locale )、使用图形还是终端窗口、使用 =emacsclient= 还
+是 =emacs= 而变化。尽管有方法可以获得目前使用的字体集( =(frame-parameter nil
+'font)= ),但这 [[https://lists.gnu.org/archive/html/emacs-devel/2006-12/msg00285.html][并不完全可靠]] 。
+
+在不少失败的尝试之后,我终于找到了 [[https://stackoverflow.com/questions/17102692/using-a-list-of-fonts-with-a-daemonized-emacs][答案]] :直接定义一个新的字体集。
+#+BEGIN_SRC emacs-lisp
+ (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))
+#+END_SRC
+
+由于我除了指定中日韩字体外还对字体集做了其他更改,我会在阐明所有改变后再贴出全部
+设定。
+
+****** 显示 Emoji
+解决 emoji 显示的方法与中日韩文字类似——找到一款支持 emoji 的字体不就好了吗——至少
+我是这么想的。我一开始试图使用 Noto Color Emoji 作为 emoji 用后备字体,但发现
+Emacs 目前并不支持彩色 emoji 字体。 Emacs 曾经在 macOS 上支持彩色 emoji字体,但
+后来 [[https://github.com/emacs-mirror/emacs/blob/emacs-25.1/etc/NEWS#L1723][移除]] 了。
+
+我最后选择了 [[http://users.teilar.gr/~g1951d/][Symbola]] 作为 emoji 后备字体(事实上我把它设为了所有 Unicode 字符的
+后备字体)。 Symbola 可以显示 [[https://unicode.org/Public/emoji/11.0/emoji-test.txt][所有 emoji]] 和许多特殊符号。还需要注意的一点是,在
+Emacs 25 之后,要想在字体集中自定义包含了大部分标点、特殊符号、 emoji 的
+=symbols= [[https://www.gnu.org/software/emacs/manual/html_node/emacs/Charsets.html][字符集( charset )]],需要[[https://github.com/emacs-mirror/emacs/blob/emacs-25/etc/NEWS#L58][一些额外的设置]]:
+#+BEGIN_SRC emacs-lisp
+ (setq use-default-font-for-symbols nil)
+#+END_SRC
+
+如果实在想要显示彩色 emoji 倒也不是完全没有办法,不过不是通过设置字体,而是将
+Unicode 字符替换为图片。[[https://github.com/iqbalansari/emacs-emojify][=emacs-emojify=]] 就是一个提供这种功能的 Emacs 包。由于这
+个包会给 Emacs 带来一定的延迟,而且大部分彩色 emoji 图片库并不完整,我最终决定不
+予采用。
+
+****** 引号风波
+我一直习惯在书写中文时使用成对的全角弯引号(““””和“‘’”)以及在书写英文时
+使用 ASCII 里的对称直引号(“"”和“'”)。然而我并不知道“全角弯引号”其实根本
+不存在: Unicode 中只存在一组弯引号编码( U+2018 、 U+2019 、 U+201C 、U+201D ),
+而所谓的全角与半角弯引号之分完全是字体引起的。虽然已经有相关的 [[https://www.unicode.org/L2/L2014/14006-sv-western-vs-cjk.pdf][提案]] 建议将这两种
+不同的表示方法标准化,但目前弯引号就是这么一个烂摊子。
+
+了解来龙去脉之后,就不难理解为什么弯引号在 Emacs 里隶属 =symbol= 字符集而非某个
+中日韩字符集了。这也导致这些弯引号会使用我的默认等宽字体并显示为半角字符。我并没
+有从根本上解决这一问题的办法,所以为了保证显示风格和书写风格保持一致,我通过为特
+定的 Unicode 编码指定字体将这些弯引号字符统一显示为全角。当我知道直引号其实也有
+着 [[https://www.cl.cam.ac.uk/~mgk25/ucs/quotes.html][充满误会的过去]] 的时候,我已经不知道应该用什么表情来面对了——也许我们在这方面真
+的很糟糕。
+
+我的后备字体设置可以在 [[https://github.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback][GitHub]] 和 [[https://git.shimmy1996.com/shimmy1996/.emacs.d#fontset-with-cjk-and-unicode-fallback][川陀网络]] 上找到。为了日志的完整性,我在这里也放
+一份:
+#+BEGIN_SRC emacs-lisp
+ (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)
+#+END_SRC
+
+***** 中日韩字体大小比例
+最后需要解决的问题就是中日韩字体字宽和等宽字体比例不一致的问题了。理论上全角的中
+日韩字符应该是半角字符宽度的两倍,但这并不在所有字号下成立。看起来原因是中日韩字
+体在字号上其实偷懒了:在使用 Noto Sans CJK SC 时, 16px 和 17px 大小的中日韩字符
+是没有任何大小区别的,直到 18px 才会出现大一号的字形,不像拉丁字符始终表现出预期
+的尺寸增幅。这一现象使得中日韩字符和拉丁字符在每隔数个字号后大小比例相称,但使用
+夹在中间的字号时中日韩字符会略微偏小。
+
+一种解决方式时在修改字体集时给中日韩字体设置一个稍大一些的默认字号。不过这会导致
+=text-scale-adjust= (通常被绑定在 ~C-x C-=~ 和 ~C-x C--~ 上)对中日韩字体不生效。
+一种更好的办法是修改 =face-font-rescale-alist= 设置缩放比例:
+#+BEGIN_SRC emacs-lisp
+ (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)))))
+#+END_SRC
+
+虽然在使用 =text-scale-adjust= 后字体大小比例依然可能会乱掉,但我只要默认字号下
+对齐就行。具体的缩放比例只能通过反复测试来确定。我用以下几行字符是否对齐来判断缩
+放比例是否合适(这张 [[https://websemantics.uk/articles/font-size-conversion/][表格]] 会是很好的帮手):
+#+BEGIN_SRC
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云云
+雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲雲
+ㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞㄞ
+ああああああああああああああああああああああああああああああああああああああああ
+가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가가
+#+END_SRC
+
+不巧的是,我所使用中日韩字体的谚文比其他全角字符都要窄,所以最终结果仍不完美——解
+决方案是再添加一个谚文专用的字体和缩放比例——不过对我来说够用了。
+
+我在解决这些看似简单的问题上花的精力比想象的多不少,不过值得庆幸的是 Emacs 提供
+了所需的各项工具。顺便一提, Emacs Wiki 上的 [[https://www.emacswiki.org/emacs/FontSets][这篇文章]] 也提供了一些类似的问题的解
+决方案:要是我早一些看到,配置过程大概会顺利许多。
+
* Site Related :@site_related:
** DONE Trying Out Mastodon :social_network:mastodon:arch_linux:
:PROPERTIES: