在键入时修复双倍大写字母


23

我有点慢小指。随着其他手指打字的速度越来越快,我的小指无法跟上。这经常导致我键入句子,其第一个单词以两个大写字母开头。这是一个简短的例子。

THere's nothing in there. DEfinitely not a body.

通常我所做的就是击中M-b M-c(假设我立即发现它),但是我对此感到有些厌倦。

我如何让Emacs为我自动修复此问题?

也就是说,我希望Emacs能够检测到我输入的单词以两个大写字母开头,然后至少一个小写字母开头并自动修复。

Answers:


19

这是一个将DOuble CApitals转换为Single Capitals的函数。我最初建议将其添加到中post-self-insert-hook,但下面是美化的次要模式的一个选项,以便您仅在真正需要时添加到该钩子中:

(defun dcaps-to-scaps ()
  "Convert word in DOuble CApitals to Single Capitals."
  (interactive)
  (and (= ?w (char-syntax (char-before)))
       (save-excursion
         (and (if (called-interactively-p)
                  (skip-syntax-backward "w")
                (= -3 (skip-syntax-backward "w")))
              (let (case-fold-search)
                (looking-at "\\b[[:upper:]]\\{2\\}[[:lower:]]"))
              (capitalize-word 1)))))

(add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)

和次要模式定义:

(define-minor-mode dubcaps-mode
  "Toggle `dubcaps-mode'.  Converts words in DOuble CApitals to
Single Capitals as you type."
  :init-value nil
  :lighter (" DC")
  (if dubcaps-mode
      (add-hook 'post-self-insert-hook #'dcaps-to-scaps nil 'local)
    (remove-hook 'post-self-insert-hook #'dcaps-to-scaps 'local)))

值得一试的是,使用以下版本:

  • 很简单:只需手动或在模式挂钩中将其打开/关闭即可;
  • 不需要更改键绑定,因此您不会丢失任何其他功能。

即使将其添加到中post-self-insert-hook,至少根据一些简单的基准测试,开销几乎是不存在的。在我的机器上,这是我获得的10,000次重复的结果,每个重复都非常简单,而且dcaps-to-scaps功能很简单:

(benchmark-run-compiled 10000 (+ 1 1))          ; => .001 to .003 -ish
(benchmark-run-compiled 10000 (dcaps-to-scaps)) ; => .003 to .006 -ish

因此,是的,它比加1 + 1慢,但是从绝对意义上讲您永远不会注意到。


您可以使用looking-at-p,它根本不会设置匹配数据(没关系,因为您不需要或在此处使用它)。
YoungFrog 2015年

一些更多的言论,大多是不重要的(但我更喜欢你的答案,所以我想贡献; P):使用forward-word将不能很好地工作subword-mode,通过(char-syntax (char-before))将(我猜)忽略任何语法类集合与性质(其他的解决办法:(syntax-after (1- (point))) ,以及(最后但并非最不重要的)正则表达式不会找到带重音的字母(例如法语中的“ÉMincer”)
YoungFrog 2015年

@YoungFrog:已更新以处理该forward-word问题,并更改了正则表达式以处理重音符号。

是否有一个理由,更喜欢andwhen,特别是在第一个实例?
克莱门特

@Clément:and发生短路,因此逻辑类似于when此处。我不确定是否有关于使用一种相对于另一种的最佳实践,但是似乎在此站点上会提出一个很好的问题(无论如何我都会赞成)。

8

我的喜好是简单地创建一个新功能,该功能可以执行通常的功能self-insert-command以及更多功能

原因如下:

  • 对哪些主要模式应具有此自动校正功能进行更精细的控制。对于这种使用情况下,它可以是纯文字模式,如org-modetext-mode等。
  • 对于修正的类型的问题提出要求,用户通常会击中SPCRET.后字键。因此,使用类似方法post-self-insert-hook可能会过大,并且每次敲击任何键时,我们都会进行额外的处理。

因此,下面提出的解决方案仅将此SPC键与该功能绑定org-mode-map(忽略转义情况,即单词可能是一行中的最后一个单词)。如果需要,用户可以将类似的包装器功能绑定到更多键。

(defun space-plus-more ()
  (interactive)
  (save-excursion
    (backward-word 1)
    (let ((case-fold-search))
      (when (looking-at-p "[A-Z]\\{2\\}.*?[a-z]+.*?\\b")
        (capitalize-word 1))))
  (self-insert-command 1))

(define-key org-mode-map (kbd "<SPC>") #'space-plus-more)

这是一个有趣的elisp练习:)

我个人不想将此绑定到,RET因为那样的话,我可能会丢失默认绑定,org-mode并且可能还会丢失其他主要模式。但是了解elt和有趣this-command-keys-vector

(defun my/fix-double-caps ()
  (interactive)
  (save-excursion
    (backward-word 1)
    (let ((case-fold-search))
      (when (looking-at-p "[A-Z]\\{2\\}.*?[a-z]+.*?\\b")
        (capitalize-word 1))))
  (if (eq 13 (elt (this-command-keys-vector) 0)) ; detect RET
      (newline)
    (self-insert-command 1)))

(let ((maps-list (list org-mode-map
                       text-mode-map))
      (keys-list (list "<SPC>" "<RET>" ".")))
  (dolist (map maps-list)
    (dolist (key keys-list)
      (define-key map (kbd key) #'my/fix-double-caps))))

哦,是的,将其限制为文本衍生模式绝对是个好主意。:)
马拉巴巴

@Malabarba对于从prog-mode派生的模式,您是否不希望这种行为出现在字符串中?
YoungFrog

@YoungFrog当然可以,但是然后它必须检查它实际上是否在字符串中,否则它会妨碍您的操作。
马拉巴巴

0

也许这个答案没有提供您所期望的解决方案(键入时对单词进行交互式更正),我想分享我解决此类问题的方法。

首先,我不喜欢无声地更改文本的内容(大写字母等,如果您想输入单词IBuffer,我认为这样的“校正器”是错误的方法),所以我建议两件事:

首先,尝试启用功能“粘滞键”。乍一看似乎很奇怪,但我一直都在使用它。此功能在OS /桌面环境级别可用,不是Emacs的东西。启用此功能后,您先按 ⇧ Shift,然后再按另一个要大写的键。这样,您的问题甚至不会出现,在这种顺序方式中只有一个字母大写!它还可以减少您的手需要握住⇧ Shift钥匙的工作。我认为现在输入更加容易。

其次,现在您仍然可以⇧ Shift在认为有必要时正常使用(持有)密钥,但是我想向您提出一个名为Fix Word的Emacs软件包。即使您不喜欢“粘滞键”,也可以轻松地将单词更正为正确的形式,并且可以连续纠正多个单词而不会浪费光标。试试看,我一直都在用。(如果您输入了多个单词并且您需要大写的单词在中间,那么纠正问题仍然很困难。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.