Emacs:删除表达式之间的空格

时间:2013-09-20 19:37:02

标签: emacs clojure elisp whitespace key-bindings

在编写Clojure代码时,我经常在最后一个表达式和结束括号之间留出空格。像

这样的东西
(defn myfunction
  [arg]
  (do
    (expr1)
    (expr2)|
  ))

其中|是光标的位置。 Emacs中是否有一个快捷方式来删除(expr2)和最后一个括号之间的空格?目标是最终

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

5 个答案:

答案 0 :(得分:4)

M-^(命令delete-indentation)已经按照您的要求执行了操作,至少在您提供的示例中(以及类似)。见(elisp)User-Level Deletion

答案 1 :(得分:2)

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

C-u M-^

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

使用前缀(C-u),M- ^连接下一行和当前。

答案 2 :(得分:1)

改进@ 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))

答案 3 :(得分:1)

以下是我对此问题解决方案的看法: 在您的示例中,您当时可能要执行的操作是退出列表。 那么为什么不将空白清理附加到列表退出?

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

所以现在,无论何时退出列表,最近的空白区域都会被困在之间 两个parens被删除。

我刚刚写完了,欢迎提出改进建议, 但我已经用了几分钟而我喜欢它。 您也可能希望将其绑定到更好的快捷方式, C-M-e up-list的默认快捷方式。

答案 4 :(得分:0)

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

(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等...,而从未遇到过像单一个空格这样有用的空格功能。

要扩大搜索范围,您可以通过按C-h i进入Texinfo文档,从Emacs内部搜索Emacs文档。按mEmacs进入文档中特定于Emacs的部分(某些软件包也有相应的部分)。进入Emacs部分后,按s进行搜索并执行诸如delete。* white之类的搜索,您将被带到文档的Delete部分,在这里您将看到各种有用的删除方法。

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的函数中,我只看到一个空格,就看到附近的一个叫做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个剩余空间。