clsty
1
org-mode 中,中文标记与单词内部的标记(比如首字母下划线),都涉及到怎样处理额外空格的问题。
这也是个老问题了,站内贴子很多:
最常见的解决方案是利用零宽空格(Zero Width Space,ZWS)。
当然也包括一些不用零宽空格的做法,比如
在尝试多种方案之后,出于对稳定性的偏好,我还是决定使用零宽空格,并且在导出、复制时自动清除零宽空格。
以下配置来自 Emacs China 的大家的智慧,再加 tecosaur 这篇旧文,再加我三个小时的试错整合。
优点:
- 此配置不依赖额外的包,
prettify-symbols
和 org
都是内置的。
- 非常稳定(指 robust),目前没有找到什么需要特别处理的例外情况。
;; 配置 prettify
(setq prettify-symbols-unprettify-at-point t)
(defun org-prettify-set ()
(interactive)
(setq prettify-symbols-alist
(mapcan (lambda (x) (list x (cons (upcase (car x)) (cdr x)))) '(
; 这里还能再加更多 pretty symbol
("\u200b" . ?▾) ; 零宽空格
))) (prettify-symbols-mode 1))
(add-hook 'org-mode-hook 'org-prettify-set)
;; 快速插入零宽空格
(define-key org-mode-map (kbd "M-SPC M-SPC")
(lambda () (interactive) (insert "\u200b")))
;; 导出时(导出为 org 时除外),去除零宽空格
(defun +org-export-remove-zero-width-space (text _backend _info)
"Remove zero width spaces from TEXT."
(unless (org-export-derived-backend-p 'org)
(replace-regexp-in-string "\u200b" "" text)))
(with-eval-after-load 'ox ; 没有这一行的话,会因变量未定义而报错。
(add-to-list 'org-export-filter-final-output-functions #'+org-export-remove-zero-width-space t))
使用方法也很简单,用 M-SPC M-SPC
插入零宽空格,显示为 ▾
,导出 latex 等会自动去除。
如果不喜欢 ▾
,也可以使用其他符号(C-X 8 RET
会弹出一个可插入的符号列表,自己找找看),比如 ˔
。
Linux 下复制时自动去除零宽空格的配置见 2 楼。
7 个赞
clsty
2
Linux wayland 下可以增加以下配置,在复制到系统剪贴板时去除零宽空格,在 Emacs 内部保留原样。
(修改自 Emacs Wiki)
(setq wl-copy-process nil)
(defun wl-copy (text)
(setq wl-copy-process (make-process :name "wl-copy"
:buffer nil
:command '("wl-copy" "-f" "-n")
:connection-type 'pipe
:noquery t))
(setq cleaned-text (replace-regexp-in-string "\u200b" "" text))
(process-send-string wl-copy-process cleaned-text)
(process-send-eof wl-copy-process))
(defun wl-paste ()
(if (and wl-copy-process (process-live-p wl-copy-process))
nil ; should return nil if we're the current paste owner
(shell-command-to-string "wl-paste -n | tr -d \r")))
(setq interprogram-cut-function 'wl-copy)
(setq interprogram-paste-function 'wl-paste)
x11 下应该也是类似的,无非是把 wl-copy -f -n
改为 xclip
之类的。
4 个赞
多按个M-SPC M-SPC不是跟多输入个空格差不多?只不过显示上减少了空格符那个空间。
我是类似electric-pair一样,输入*自动变**并加上零宽空格:
(add-hook
'org-mode-hook
(lambda ()
;; emphasis字符加上零宽空格
(defmacro add_zero_space_char (ch)
`(lambda ()
(interactive)
;; r支持region!但注意有些键`easy-mark'会影响到,如=
(tempel-insert (list "" "\x200B" ,ch 'r ,ch "\x200B"))))
(local-set-key "*" (add_zero_space_char "*"))
(local-set-key "/" (add_zero_space_char "/"))
(local-set-key "_" (add_zero_space_char "_"))
(local-set-key "=" (add_zero_space_char "="))
(local-set-key "~" (add_zero_space_char "~"))
(local-set-key "+" (add_zero_space_char "+"))
(local-set-key "`" (add_zero_space_char "`"))))
用到了tempel的tempel-insert
,这个支持对选中内容加上pair。
搜了下相关讨论,主要是为了中文不打空格实现org-mode的标记样式吗?
clsty
5
你说的“差不多”是指按键次数,对吧?确实如此,但我所关注与普通空格的差别,主要是导出与复制时,零宽空格因其特殊性,被简单稳定地去除,而不需要像普通空格那样对各种情况进行判定。
感谢分享。
这种做法或许也不错,但是有时我并不想它这么自动化,尤其是我其实会大量用到数学公式、其他 LaTeX 环境以及代码块,在这些环境下又要判别是否应当自动化的话——数学环境的判定其实就已经是个大难点了,比如如果用 texmathp
,那么行内代码中如果出现奇数个 $
,则其后的普通正文也会被当成行内公式。如果一种自动化需要对各种特殊情况分别打补丁,甚至有引发连锁反应的风险,我是宁可不要它带来的便利也要手动进行的。
总之不适合我吧。
大家按需来就好。
正是如此。
clsty
6
这个方案还有一个用途:保留 Org-mode 快捷地打出上下标的特性。
常规的解决下划线 _
被识别为下标格式、^
被识别为上标格式的方法是 #+options: ^:nil
,但这会对全文生效,无法快捷地打出上下标。
如果也需要局部用到上下标的话,就可以利用零宽空格。
例:按照本贴方案,以下文本(注意 P3 和 P4 内含零宽空格)
\(\text{P}_0\) P_1 P_{2} P_3 P_4
在导出 LaTeX 后,不再含零宽空格,变成
\(\text{P}_0\) P\textsubscript{1} P\textsubscript{2} P\_3 P\_4
这样就通过零宽空格实现了局部禁用上下标的效果(P3 P4),同时也保留了上下标的特性(P1 P2)。
至于 P0 则展示了利用行内 LaTeX 数学公式打出上下标的方法。
这种方法在启用了 #+options: ^:nil
时,可能是使用上下标的唯二方法之一;另一种是 HTML。显然它麻烦得多,且实现的效果也不完全一致。
相关贴子:
是不是必须前后都加上零宽空格,导出时才能识别为粗体?
在 org-mode中,只要有后零宽空格,就有粗体渲染:
导出html,必须前后都加上零宽空格,才能识别为粗体
这是必须的么?还是可以有其他trick?
clsty
8
是的,我认为这是比较规范的用法,即前后都加上零宽空格。
至于你说的 org-mode 的 buffer 内渲染和导出,很可能因为有不同的实现,所以仅仅使用后零宽空格在 buffer 内渲染时才可识别为粗体。这种区别我猜测可能有性能等方面的考虑,或者单纯是 bug。总之,统一在前后都加零宽空格就可以了。
所以你是 输入零宽空格-输入格式标记和相关内容-再输入零宽空格?
那是不是把插入零宽空格的函数改为插入两个零宽空格,并把光标定位到两个零宽空格之间更方便?
(lambda ()
(interactive)
(insert-char #x200b)
(insert-char #x200b)
(backward-char))
或者有没有其他更简单的方法?例如选中文本后可以快速加上*,并加上零宽空格?
1 个赞
clsty
11
这种用途就只需要一个零宽空格。
并且,即使是输入两个零宽空格,在整个部分都输入完毕之后,还要再 C-f
向右移动光标到零宽空格右边,以输入后续内容。总体的效率提升并没有多大。不过,也不失为一种思路,每个人都有自己的使用习惯。
顺便一提,用 yasnippet 来实现这方面的自动化,可能更灵活,也更方便。
如果能实现的话,我觉得很不错。
你说的这个问题我也注意到了,之前我没太在意,看来不是孤例。
可能是我对 prettify-symbols 的配置还有问题,也可能是它自身的 bug。有待进一步解决。
确实,考虑打出上下标之需要一个空格的话,你的方案更合适。
可以展开说明 yasnippet 的思路么?目前更多应用在更大层面的模版,例如特定类型的笔记模板。对于这么轻量级的功能我还没有很好的思路。
clsty
13
yasnippet 我也是随口一提,自己并没有实践过,只是很常规的用法而已。
这里就加粗来简单给个示例。为 org-mode 新建一个 yasnippet:
# -*- mode: snippet -*-
# name: org-bold
# key: ;;ob
# condition: (and t 'auto)
# --
<ZWS>*$1*<ZWS>$0
(记得把 <ZWS>
替换为零宽空格)
这里利用了自动展开,所以还需要如下配置:
;;允许snippet自动展开
(defvar yas-auto-expand-local-toggle t)
(defun my-yas-try-expanding-auto-snippets ()
(when (and (boundp 'yas-minor-mode) yas-minor-mode)
(let ((yas-buffer-local-condition ''(require-snippet-condition . auto)))
(yas-expand))))
(add-hook 'post-command-hook #'my-yas-try-expanding-auto-snippets)
这样,在 org-mode 下输入 ;;ob
之后就会自动展开为 <ZWS>**<ZWS>
的形态,光标位于正中间,并且在输入完毕之后可用 yas-next-field
(一般都会绑个键位的,默认好像是 TAB)来跳至末尾。