Emacs:删除空格或单词

11

如何配置emacs以与其他现代编辑器相同的方式工作,在按下 Alt+DAlt+Backspace 后删除相邻的空格或一个单词? 默认情况下,emacs总是删除一个单词。


我正在尝试弄清楚你提到这些热键时所想的现代编辑器是什么...我实际上没有遇到你描述的行为。大多数我尝试的事情要么什么都不做,要么做一些与此无关的任意操作,比如删除整行或浏览文档打开历史记录。所以,我真的不知道你所想的空格删除是什么样的。它是否像“M-\”那样?还是只应该在光标前/后删除? - user797257
1
此外:http://www.emacswiki.org/emacs/DeletingWhitespace 这里有一个大型的用户提交代码集合,可以执行各种空格删除操作。 - user797257
@wvxvw 抱歉,应该是 Alt 键。像 Eclipse、Visual Studio 和 Sublime Text 这样的编辑器。 - woodings
@woodings,你能发布一个带有文本和光标位置的用例吗?另外,Alt-D 不仅删除单词,还会杀死它(你稍后可以复制它)。 - abo-abo
4个回答

14

通过使用Emacs一段时间后,我发现即使我可以改变基本功能,但通常在效率方面并没有太大的回报。事实上,在我多次这样做之后,我开始后悔并撤销了它。这并不总是正确的,有些按键绑定确实很不舒服或很少有用,但我认为kill word的工作方式不是这种情况。事实上,我刚才意识到:我尝试过在Eclipse中使用该按键绑定,但自从我使用Emacs风格的按键绑定以来,我一直在使用它...

无论如何,正如我刚才说的,在“修复”该功能之前,请确保它真的出了问题:)我从来没有发现自己需要您描述的那种功能,也许这就是原因:

  1. M-SPC将单词之间的空格减少到一个空格。如果光标位于单词之间,并且我想删除分隔单词的额外空格,那么这就是我要使用的。

  2. M-\删除所有水平空格。这将连接由空格分隔的两个单词。

  3. 如果您想要实现某种“稀疏”格式,例如:


int foo          = 42;
unsigned int bar = 43;

然后有M-xalign-regexp来完成这个任务。

  1. 我通常不会有a) 连续很长的空格,除非是缩进,而在这种情况下,TAB通常处理得更好。b) 即使有连续很长的空格,我也很少一次移动一个字符,所以很难想象我会发现光标被几个空格包围的情况。像艺术家模式或点图之类的东西会出现在脑海中,但在代码编辑过程中并不会发生。

  2. 最后,如果您正在尝试编辑任意文本文件,并且想要添加或删除单词之间的水平空格...同样,有M-xalign-regexp来完成这个任务,或者您可以使用操作矩形的命令,如果那些是每次几行。嗯,当您按下TAB时,Emacs甚至会识别临时制表符,并尝试对齐文本以匹配光标前的最后一行。

最后,如果出于某些我无法理解的原因 :) 我真的需要按照您所描述的方式进行操作,那么我会这样做:kM-\BACKSPACE(可以是任何其他键,而不仅仅是“k” - 它就在你的手指下面,所以打起来很快 :) 或者,如果我懒得思考: M-SPCM-fM-bC-w - 可能听起来很多,但这些命令你无论如何都会使用,所以它不会影响你的速度。


11
(defvar movement-syntax-table
  (let ((st (make-syntax-table)))
    ;; ` default = punctuation
    ;; ' default = punctuation
    ;; , default = punctuation
    ;; ; default = punctuation
    (modify-syntax-entry ?{ "." st)  ;; { = punctuation
    (modify-syntax-entry ?} "." st)  ;; } = punctuation
    (modify-syntax-entry ?\" "." st) ;; " = punctuation
    (modify-syntax-entry ?\\ "_" st) ;; \ = symbol
    (modify-syntax-entry ?\$ "_" st) ;; $ = symbol
    (modify-syntax-entry ?\% "_" st) ;; % = symbol
    st)
  "Syntax table used while executing custom movement functions.")

(defun delete-word-or-whitespace (&optional arg)
"https://dev59.com/mmMl5IYBdhLWcg3w_rKD#20456861"
(interactive "P")
  (with-syntax-table movement-syntax-table
    (let* (
        beg
        end
        (word-regexp "\\sw")
        (punctuation-regexp "\\s.")
        (symbol-regexp "\\s_\\|\\s(\\|\\s)"))
      (cond
        ;; Condition # 1
        ;; right of cursor = word or punctuation or symbol
        ((or
            (save-excursion (< 0 (skip-syntax-forward "w")))
            (save-excursion (< 0 (skip-syntax-forward ".")))
            (save-excursion (< 0 (skip-syntax-forward "_()"))))
          ;; Condition #1 -- Step 1 of 2
          (cond
            ;; right of cursor = word
            ((save-excursion (< 0 (skip-syntax-forward "w")))
              (skip-syntax-forward "w")
              (setq end (point))
              (while (looking-back word-regexp)
                (backward-char))
              (setq beg (point))
              (delete-region beg end))
            ;; right of cursor = punctuation
            ((save-excursion (< 0 (skip-syntax-forward ".")))
              (skip-syntax-forward ".")
              (setq end (point))
              (while (looking-back punctuation-regexp)
                (backward-char))
              (setq beg (point))
              (delete-region beg end))
            ;; right of cursor = symbol
            ((save-excursion (< 0 (skip-syntax-forward "_()")))
              (skip-syntax-forward "_()")
              (setq end (point))
              (while (looking-back symbol-regexp)
                (backward-char))
              (setq beg (point))
              (delete-region beg end)))
          ;; Condition #1 -- Step 2 of 2
          (cond
            ;; right of cursor = whitespace
            ;; left of cursor = not word / not symbol / not punctuation = whitespace or bol
            ((and
                (save-excursion (< 0 (skip-chars-forward "\s\t")))
                (not (save-excursion (> 0 (skip-syntax-backward "w"))))
                (not (save-excursion (> 0 (skip-syntax-backward "."))))
                (not (save-excursion (> 0 (skip-syntax-backward "_()")))))
              (setq beg (point))
              (skip-chars-forward "\s\t")
              (setq end (point))
              (delete-region beg end))
            ;; right of cursor = whitespace
            ;; left of cursor = word or symbol or punctuation
            ((and
                (save-excursion (< 0 (skip-chars-forward "\s\t")))
                (or
                  (save-excursion (> 0 (skip-syntax-backward "w")))
                  (save-excursion (> 0 (skip-syntax-backward ".")))
                  (save-excursion (> 0 (skip-syntax-backward "_()")))))
              (fixup-whitespace))))
        ;; Condition # 2
        ;; right of cursor = whitespace
        ;; left of cursor = bol | left of cursor = whitespace | right of cursor = whitespace + eol
        ((and 
            (save-excursion (< 0 (skip-chars-forward "\s\t")))
            (or
              (bolp)
              (save-excursion (> 0 (skip-chars-backward "\s\t")))
              (save-excursion (< 0 (skip-chars-forward "\s\t")) (eolp))))
          (setq beg (point))
          (skip-chars-forward "\s\t")
          (setq end (point))
          (delete-region beg end))
        ;; Condition # 3
        ;; right of cursor = whitespace or eol
        ;; left of cursor = word or symbol or punctuation
        ;; not bol + word or symbol or punctuation
        ;; not bol + whitespace + word or symbol or punctuation
        ((and 
            (or (save-excursion (< 0 (skip-chars-forward "\s\t"))) (eolp))
            (or
              (save-excursion (> 0 (skip-syntax-backward "w")))
              (save-excursion (> 0 (skip-syntax-backward ".")))
              (save-excursion (> 0 (skip-syntax-backward "_()"))))
            (not (save-excursion (> 0 (skip-syntax-backward "w")) (bolp)))
            (not (save-excursion (> 0 (skip-syntax-backward ".")) (bolp)))
            (not (save-excursion (> 0 (skip-syntax-backward "_()")) (bolp)))
            (not (save-excursion (and (> 0 (skip-syntax-backward "w")) (> 0 (skip-chars-backward "\s\t")) (bolp))))
            (not (save-excursion (and (> 0 (skip-syntax-backward ".")) (> 0 (skip-chars-backward "\s\t")) (bolp))))
            (not (save-excursion (and (> 0 (skip-syntax-backward "_()")) (> 0 (skip-chars-backward "\s\t")) (bolp)))))
          (setq end (point))
          (cond
            ((save-excursion (> 0 (skip-syntax-backward "w")))
              (while (looking-back word-regexp)
                (backward-char)))
            ((save-excursion (> 0 (skip-syntax-backward ".")))
              (while (looking-back punctuation-regexp)
                (backward-char)))
            ((save-excursion (> 0 (skip-syntax-backward "_()")))
              (while (looking-back symbol-regexp)
                (backward-char))))
          (setq beg (point))
          (when (save-excursion (> 0 (skip-chars-backward "\s\t")))
            (skip-chars-backward "\s\t")
            (setq beg (point)))
          (delete-region beg end)
          (skip-chars-forward "\s\t"))
        ;; Condition # 4
        ;; not bol = eol
        ;; left of cursor = bol + word or symbol or punctuation | bol + whitespace + word or symbol or punctuation
        ((and
            (not (and (bolp) (eolp)))
            (or
              (save-excursion (> 0 (skip-syntax-backward "w")) (bolp))
              (save-excursion (> 0 (skip-syntax-backward ".")) (bolp))
              (save-excursion (> 0 (skip-syntax-backward "_()")) (bolp))
              (save-excursion (and (> 0 (skip-syntax-backward "w")) (> 0 (skip-chars-backward "\s\t")) (bolp)))
              (save-excursion (and (> 0 (skip-syntax-backward ".")) (> 0 (skip-chars-backward "\s\t")) (bolp)))
              (save-excursion (and (> 0 (skip-syntax-backward "_()")) (> 0 (skip-chars-backward "\s\t")) (bolp)))))
          (skip-chars-forward "\s\t")
          (setq end (point))
          (setq beg (point-at-bol))
          (delete-region beg end))
        ;; Condition # 5
        ;; point = eol
        ;; not an empty line
        ;; whitespace to the left of eol
        ((and
            (not (and (bolp) (eolp)))
            (eolp)
            (save-excursion (> 0 (skip-chars-backward "\s\t"))))
          (setq end (point))
          (skip-chars-backward "\s\t")
          (setq beg (point))
          (delete-region beg end))
        ;; Condition # 6
        ;; point = not eob
        ;; point = bolp and eolp
        ;; universal argument = C-u = '(4)
        ((and
            (not (eobp))
            (and (bolp) (eolp))
            (equal arg '(4)))
          (delete-forward-char 1))) )))

2
我喜欢这个函数的整体表现,但是我发现它并不完全“通用”。即 1) 一旦你删除到行的开头,它不会环绕删除前面的行,而只是“停止”。 - Leo Ufimtsev
如果您的代码行末尾有空格,它是否根本不会开始删除字符? - Leo Ufimtsev
1
@Leo Ufimtsev -- 我添加了一个条件来处理行末的空格。当光标位于行末且左侧有空格时,删除所有左侧的空格。这是唯一删除左侧空格的情况。感谢您帮助我改进此函数。我想考虑一下是否应该扩大函数的范围,在当前段落被删除后向前或向后删除行。我犹豫的原因是许多用户,包括我自己,有时会过度使用该功能。 - lawlist
顺便说一下,如果您在这个Emacs问题的链接中发布了这个答案:http://emacs.stackexchange.com/questions/10644/backward-kill-word-ignores-whitespaces-is-there-another-friendlier-version 我会很高兴地接受它。 - Leo Ufimtsev
2
@LeoUfimtsev--我为当点位于空行而不是缓冲区末尾的情况增加了一个附加条件。如果在这种情况下有一个通用参数,即C-u,则函数delete-forward-character会触发一次。此时,我更喜欢保留删除新行的向前删除需要额外步骤,例如一个C-u。对于那些我热衷的功能,我喜欢通过编辑线程不断改进它们。我努力将编辑限制在一个线程中-即使这样做可能会防止我回答相关问题。 - lawlist
显示剩余3条评论

6
这个问题很可能以前已经被解决过了,但是我们可以自己写代码而不是寻找。这样会更有趣!以下是我的做法,希望能对你有所帮助。
(defun kill-whitespace-or-word ()
  (interactive)
  (if (looking-at "[ \t\n]")
      (let ((p (point)))
        (re-search-forward "[^ \t\n]" nil :no-error)
        (backward-char)
        (kill-region p (point)))
    (kill-word 1)))

然后将其绑定到一个键:

(global-set-key (kbd "M-d") 'kill-whitespace-or-word)

我主要是在寻找一个删除空格或向后删除单词的功能。大多数情况下向后删除单词,但在遇到 \n 时停止。我觉得这段代码可以适应这种情况,但我对 elisp 太无知了,无法弄清楚 :/ - mtourne

1
如果你正在使用基于CC-Mode的缓冲区,你可能正在寻找Hungry Delete Mode次要模式。
尝试在几个位置上按下 C-cDELC-cDELETE ,感受它们之间的差异。
如果你喜欢它的工作方式,可以通过M-x c-toggle-hungry-state切换饥饿删除以适应标准键,或者将饥饿删除函数重新绑定到你喜欢的绑定键。
如果你仍然认为你需要借助一个键来执行向前删除单词空白符,则可以类似于c-hungry-delete-forward做一些操作,或者临时重新绑定c-delete-function并调用它。
(defun c-hungry-delete-forward-word ()
  "Delete the following word or all following whitespace
up to the next non-whitespace character.
See also \\[c-hungry-delete-backwards]."
  (interactive)
  (let ((c-delete-function (function kill-word)))
    (c-hungry-delete-forward)))

查看信息页面(ccmode)饥饿WS删除以获取更多信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接