Emacs:删除空格或单词

Posted

技术标签:

【中文标题】Emacs:删除空格或单词【英文标题】:Emacs: delete whitespaces or a word 【发布时间】:2013-07-31 06:30:33 【问题描述】:

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

【问题讨论】:

我想弄清楚当你提到这些热键时你想到的现代编辑器......我还没有真正遇到你描述的行为。我刚刚尝试过的大多数事情要么什么都不做,要么是任意不相关的事情,比如删除整行或浏览文档打开的历史记录。所以,我真的不知道你想到了什么样的空白删除。是像M-\ 这样的吗?还是应该只在该点之前/之后删除? 另外:emacswiki.org/emacs/DeletingWhitespace 这里有大量用户提交的代码来执行各种空格删除。 @wvxvw 抱歉,它应该是 Alt 键。 eclipse、visual studio 和 sublime text 等编辑器。 @woodings,你能发布一个带有一些文本和光标位置的用例吗?此外,Alt-D 会删除该单词,而不仅仅是删除它(您可以稍后将其拉出)。 【参考方案1】:
(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)
"http://***.com/a/20456861/2112489"
(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))) )))

【讨论】:

我喜欢这个功能,但我发现它不是很“通用”。即1)一旦你删除到一行的开头,它不会环绕删除前一行,它只是'停止' 如果你有一行尾随空格,它根本不会开始删除字符? @Leo Ufimtsev -- 我在行尾添加了一个处理空格的条件。当点位于行尾且空格位于左侧时,则删除左侧的所有空格。这是删除左侧空格的唯一情况。感谢您帮助我改进此功能。我想考虑一下在删除当前段落后是否应该增加函数的范围以向前或向后删除行。我犹豫的原因是,包括我自己在内的许多用户有时会过于热衷于重复该功能。 完美。现在的生活更甜蜜了。我也愿意使用正向版本,例如带有可选的“正向”参数。 @LeoUfimtsev - 我添加了一个附加条件,用于当点位于空行但不在缓冲区末尾时的情况。如果在这种情况下存在一个通用参数——即C-u——那么函数delete-forward-character会触发一次。此时,我更喜欢保留前向删除新行以需要额外的步骤——例如,一个C-u。对于那些我热衷的功能,我喜欢通过编辑线程来不断改进它们。我努力将编辑限制在一个线程内——即使这会阻止我回答相关问题。【参考方案2】:

这很可能以前已经解决了,但是我们可以编写自己的代码,而不是寻找代码。太有趣了!

这就是我的做法,希望对您有所帮助。

(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)

【讨论】:

我主要在寻找一种 kill-whitespace-or-word-backward 功能。向后删除单词,但主要在 \n 上停止。我觉得这段代码可以适用于此,但我对 elisp 太无知了,无法弄清楚:/【参考方案3】:

在使用 Emacs 一段时间后,我发现即使我可以更改基本功能,但在效率方面通常不会带来太多回报。事实上,在我做了几次之后,我开始后悔并取消了它。这并非一直如此,一些键绑定真的很不舒服或很少有用,但我认为 kill word 的工作方式并非如此。事实上,我现在才意识到:我确实尝试过 Eclipse 中的键绑定,但我一直在将它与 Emacs 风格的键绑定一起使用......

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

    M-SPC 将单词之间的空格减少到只有一个空格。如果该点位于单词之间并且我想删除分隔单词的额外空格,这就是我会使用的。

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

    如果您想要实现的是某种“稀疏”格式,如:


int foo          = 42;
unsigned int bar = 43;

然后有 M-xalign-regexp 可以做到这一点。

    我只是从来没有碰巧有 a) 长时间的后续运行 whitepsace,除非它是缩进,如果是缩进,TAB 通常会更好地处理它。 b)即使有很长的后续空格,我也很少一次移动一个字符,所以很难想到我会发现这个点被几个空格包围的情况。想到艺术家模式或点图之类的东西,但在代码编辑期间不会发生。

    最后,如果你想,好吧,假设你只是编辑一个任意的文本文件,并且你想在单词之间添加或删除水平空格......再次,有 Mx@ 987654323@ 来做到这一点,或者您可以使用对矩形进行操作的命令,如果这些命令当时是几行。好吧,Emacs 甚至会识别临时选项卡,并会尝试对齐文本,例如当您点击 TAB 时匹配该点之前的最后一行。

最后,如果由于某种原因我无法理解 :) 我真的需要完全按照您的描述做,那么我会这样做:kM-\BACKSPACE (它可以是任何其他键而不是“k” - 它就在您的手指下方,因此输入速度很快 :) 或者,如果我懒得想它:M-SPCMfMbCw - 可能听起来很多,但这些是您将使用的所有命令无论如何,它不会影响您的速度。

【讨论】:

【参考方案4】:

如果您使用基于 CC 模式的缓冲区,您可能正在寻找 Hungry Delete Mode 次要模式。

在几个地方尝试 Cc DELCc DELETE 感受一下不同之处。

如果您喜欢它的工作方式,您可以通过 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) Hungry WS Deletion 了解更多信息。

【讨论】:

以上是关于Emacs:删除空格或单词的主要内容,如果未能解决你的问题,请参考以下文章

删除字符串中的一个单词(或两个空格之间)

Emacs 不将M-Del删除的单词加入粘贴板

删除字符和单词之间的空格[重复]

c ++ char vector,删除带有数字的单词加上坏单词后的空格

仅用连字符替换单词之间的空格并删除所有其他空格[重复]

编写程序,输入字符串(包含空格),统计其中单词的个数,单词之间以一个或多个空格分隔。