【问题标题】:Emacs: remove spaces between expressionsEmacs:删除表达式之间的空格
【发布时间】:2013-09-20 19:37:01
【问题描述】:

在编写 Clojure 代码时,我经常在最后一个表达式和右括号之间添加空格。类似的东西

(defn myfunction
  [arg]
  (do
    (expr1)
    (expr2)|
  ))

在哪里 |是光标的位置。 Emacs 中是否有删除 (expr2) 和最后括号之间空格的快捷方式?目标是结束

(defn myfunction
  [arg]
  (do
    (expr1)
    (expr2)))

【问题讨论】:

  • 在这种情况下我只是做C-k M-\,但也许paredit有更好的东西。

标签: emacs clojure elisp whitespace key-bindings


【解决方案1】:

M-^ (command delete-indentation) 已经按照您的要求完成了,至少在您给出的示例中(和类似的)。请参阅(省略号)User-Level Deletion

【讨论】:

  • 是的,但是你必须在底线的某个地方(包含))的那个)才能工作。
  • 这是正确的答案,也是 Evil-mode 复制 Vim 的 S-j behavior 的方式。要加入以下行,只需给它一个参数。虽然我建议窃取和绑定我链接的 evil-join 函数,该函数将为您选择的每一行运行 (join-line 1)
  • 您可以从“更高的行”(包含(expr2)的行)中使用它。您所要做的就是在另一个方向运行delete-indention,使用negative-argument。简而言之,M-- M-^.negative-argument 是非常强大的参数,它绑定到所有修饰符 C--M--C-M--,这使得它在任何其他键绑定之前非常容易使用(你可以将它与任何东西一起使用不释放任何修饰符)。
【解决方案2】:

将前缀参数发送到 M-^:

C-u M-^

没有前缀,M-^ 将当前行与上一行连接起来。

使用前缀(C-u),M-^ 将下一行与当前行连接起来。

【讨论】:

    【解决方案3】:

    改进上面@wvxvw 的评论,您可以将以下内容添加到您的.emacs 文件中。然后,C-z m(或您选择的任何其他组合键)将执行您想要的操作。事实上,如果您在包含(expr1) 的行的任何位置,它都会起作用。

    (global-set-key "\C-zm" 'join-lines-removing-spaces)
    (defun join-lines-removing-spaces ()
      "Join the current line with the next, removing all whitespace at this point."
      (move-end-of-line nil)
      (kill-line)
      (delete-horizontal-space))
    

    【讨论】:

      【解决方案4】:

      这是我对解决此问题的看法: 在您的示例中,您当时可能想要做的是退出列表。 那么为什么不将空白清理附加到列表退出呢?

      (global-set-key (kbd "C-M-e") 'up-list-robust)
      
      (defun up-list-robust ()
        (interactive)
        (remove-gaps)
        (let ((s (syntax-ppss)))
            (when (nth 3 s)
              (goto-char (nth 8 s)))
            (ignore-errors (up-list))
            (remove-gaps)))
      
      (defun remove-gaps ()
        (when (looking-back ")\\([ \t\n]+\\))")
          (delete-region (match-beginning 1)
                         (match-end 1))))
      

      所以现在,每当你退出一个列表时,最近的空白区域就会被困在 删除了两个括号。

      我刚刚写了它,欢迎提出改进建议, 但我已经用了几分钟,我喜欢它。 您可能还想将此绑定到更好的快捷方式,C-M-eup-list 的默认设置。

      【讨论】:

        【解决方案5】:

        这是我为自己解决这个特定问题而编写的一个函数。

        (defun delete-surrounding-whitespace ()
          (interactive)
          (let ((skip-chars "\t\n\r "))
            (skip-chars-backward skip-chars)
            (let* ((start (point))
                   (end (progn
                          (skip-chars-forward skip-chars)
                          (point))))
              (delete-region start end))))
        

        本着教钓鱼胜过提供鱼的精神,我将分享如何从 Emacs 中发现这一点。

        如果您知道想要更多信息的函数或变量的名称,那么您可以使用 apropos 进行更深入的挖掘。但是,如果您不知道该命令可能被调用的内容怎么办?

        例如,我可能会使用 apropos 并搜索 del.*white、zap.*space、del.*space 等……但从来没有遇到像 just-one-space 这样有用的空白函数。

        要扩大搜索范围,您可以从 Emacs 内部搜索 Emacs 的文档,方法是按 C-h i 进入 Texinfo 文档。按 mEmacs 进入文档中特定于 Emacs 的部分(也有一些包的部分)。进入 Emacs 部分后,按 s 搜索并执行类似 delete.*white 的搜索,然后您将被带到文档的删除部分,在那里您将看到各种有用的删除方法。

        12.1.1 Deletion
        ---------------
        
        Deletion means erasing text and not saving it in the kill ring.  For the
        most part, the Emacs commands that delete text are those that erase just
        one character or only whitespace.
        
        ‘<DEL>’
        ‘<BACKSPACE>’
             Delete the previous character, or the text in the region if it is
             active (‘delete-backward-char’).
        
        ‘<Delete>’
             Delete the next character, or the text in the region if it is
             active (‘delete-forward-char’).
        
        ‘C-d’
             Delete the next character (‘delete-char’).
        
        ‘M-\’
             Delete spaces and tabs around point (‘delete-horizontal-space’).
        ‘M-<SPC>’
             Delete spaces and tabs around point, leaving one space
             (‘just-one-space’).
        ‘C-x C-o’
             Delete blank lines around the current line (‘delete-blank-lines’).
        ‘M-^’
             Join two lines by deleting the intervening newline, along with any
             indentation following it (‘delete-indentation’).
        

        我没有看到任何东西完全符合我的要求。但是,通过使用 apropos 搜索和提取某些函数的帮助缓冲区,我可以看到它们是如何实现的,并使用这些相同的技术来编写我需要的确切函数。

        在 simple.el.gz 中查看函数 just-one-space,我看到附近有一个名为 cycle-spacing 的函数,它看起来已经接近具有我需要的功能。

        (defun cycle-spacing (&optional n preserve-nl-back mode)
          "Manipulate whitespace around point in a smart way.
        In interactive use, this function behaves differently in successive
        consecutive calls.
        
        The first call in a sequence acts like `just-one-space'.
        It deletes all spaces and tabs around point, leaving one space
        \(or N spaces).  N is the prefix argument.  If N is negative,
        it deletes newlines as well, leaving -N spaces.
        \(If PRESERVE-NL-BACK is non-nil, it does not delete newlines before point.)
        
        The second call in a sequence deletes all spaces.
        
        The third call in a sequence restores the original whitespace (and point).
        
        If MODE is `single-shot', it only performs the first step in the sequence.
        If MODE is `fast' and the first step would not result in any change
        \(i.e., there are exactly (abs N) spaces around point),
        the function goes straight to the second step.
        
        Repeatedly calling the function with different values of N starts a
        new sequence each time."
          (interactive "*p")
          (let ((orig-pos    (point))
            (skip-characters (if (and n (< n 0)) " \t\n\r" " \t"))
            (num         (abs (or n 1))))
            (skip-chars-backward (if preserve-nl-back " \t" skip-characters))
            (constrain-to-field nil orig-pos)
            (cond
             ;; Command run for the first time, single-shot mode or different argument
             ((or (eq 'single-shot mode)
              (not (equal last-command this-command))
              (not cycle-spacing--context)
              (not (eq (car cycle-spacing--context) n)))
              (let* ((start (point))
                 (num   (- num (skip-chars-forward " " (+ num (point)))))
                 (mid   (point))
                 (end   (progn
                      (skip-chars-forward skip-characters)
                      (constrain-to-field nil orig-pos t))))
            (setq cycle-spacing--context  ;; Save for later.
                  ;; Special handling for case where there was no space at all.
                  (unless (= start end)
                        (cons n (cons orig-pos (buffer-substring start (point))))))
            ;; If this run causes no change in buffer content, delete all spaces,
            ;; otherwise delete all excess spaces.
            (delete-region (if (and (eq mode 'fast) (zerop num) (= mid end))
                       start mid) end)
                (insert (make-string num ?\s))))
        
             ;; Command run for the second time.
             ((not (equal orig-pos (point)))
              (delete-region (point) orig-pos))
        
             ;; Command run for the third time.
             (t
              (insert (cddr cycle-spacing--context))
              (goto-char (cadr cycle-spacing--context))
              (setq cycle-spacing--context nil)))))
        

        我可以稍微简化一下,因为我不需要有条件地删除换行符并留下 n 个剩余空格。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-26
          • 2019-03-05
          • 2023-04-08
          相关资源
          最近更新 更多