4

考虑以下 Lisp 代码行:

        (some-function 7 8 | 9) ;; some comment. note the extra indentation

该点位于“8”和“9”之间。如果我执行(move-beginning-of-line),该点将放置在该行的绝对开头,而不是'('。

同样适用于move-end-of-line:如果我执行一次,我会发现将点放在')' 处更可取,如果我第二次执行它,则放在行的绝对末尾。一些 IDE 的行为就是这样。

我试图实现这一点,但被卡住了,我的解决方案在缓冲区末尾附近表现得特别糟糕,在 minibuffer 上也是如此。是否有提供此功能的库?

4

4 回答 4

5

我不知道任何库,但可以在几行 Elisp 中完成。

对于行首部分,捆绑的函数beginning-of-line-textback-to-indentation( M-m) 移动到行的“有趣”部分的开头。back-to-indentation仅忽略空格而beginning-of-line-text跳过填充前缀(在编程语言中,如果在注释中,这通常是注释标记)。请参阅Emacs 中的 Smart home,了解如何在实际行和逻辑行的开头之间切换。

对于行尾部分,以下函数实现了您所描述的内容。该函数end-of-line-code移动到行尾,除了尾随空格和可选的尾随注释。该函数end-of-line-or-code执行此操作,除非该点已经在目标位置,或者如果该行仅包含空格和注释,则该点将移动到实际行的末尾。

(defun end-of-line-code ()
  (interactive "^")
  (save-match-data
    (let* ((bolpos (progn (beginning-of-line) (point)))
           (eolpos (progn (end-of-line) (point))))
      (if (comment-search-backward bolpos t)
          (search-backward-regexp comment-start-skip bolpos 'noerror))
      (skip-syntax-backward " " bolpos))))

(defun end-of-line-or-code ()
  (interactive "^")
  (let ((here (point)))
    (end-of-line-code)
    (if (or (= here (point))
        (bolp))
        (end-of-line))))
于 2013-01-09T20:34:31.823 回答
2

一些几乎可以满足您要求的建议:

在 lisp 代码中,您可以使用 sexp 移动命令来做您想做的事情。要从中间的某处到达表达式的开头,请使用backward-up-list,它绑定到M-C-u。在您的示例中,这会将您带到左括号。要向后移动列表中的单个元素,请使用backward-sexp, 绑定到M-C-b; forward-sexp向另一个方向移动,并且必然M-C-fM-C-n从一个 sexp 的开头,您可以使用;跳到下一个。与M-C-p.

这些命令实际上都没有查看您所在的物理线路,因此它们会在多条线路上返回或前进。

其他选项包括Ace Jump 模式,这是一种非常巧妙的方式,可以快速导航到屏幕上任何可见单词的开头。这可能会消除您使用特定于行的命令的需要。为了在一行内快速移动,我通常使用M-fandM-b来跳过单词。在点击或时按住M键足够快,以至于我在大多数情况下默认使用它。bf

编辑:

忘记了另一个不错的命令 - back-to-indentation,绑定到M-m. 这将使您回到一行中的第一个非空白字符。您可以建议它在第一次调用时正常运行,然后在第二次调用时备份到行首:

(defadvice back-to-indentation (around back-to-back)
  (if (eq last-command this-command)
      (beginning-of-line)
    ad-do-it))

(ad-activate 'back-to-indentation)
于 2013-01-09T18:17:32.437 回答
1

我刚刚编写了这两个具有您正在寻找的行为的函数。

(defun move-beginning-indent ()
  (interactive)
  (if (eq last-command this-command)
      (beginning-of-line)
    (back-to-indentation))
)


(defun move-end-indent ()
  (interactive)
  (if (eq last-command this-command)
      (end-of-line)
    (end-of-line)
    (search-backward-regexp "\\s)" nil t)   ; searches backwards for a 
    (forward-char 1))                       ; closed delimiter such as ) or ]
)

(global-set-key [f7] 'move-beginning-indent)          
(global-set-key [f8] 'move-end-indent)  

试一试,它们的行为应该完全符合您的要求。

于 2013-01-09T19:47:51.537 回答
1

我用这个:

(defun beginning-of-line-or-text (arg)
  "Move to BOL, or if already there, to the first non-whitespace character."
  (interactive "p")
  (if (bolp)
      (beginning-of-line-text arg)
    (move-beginning-of-line arg)))
(put 'beginning-of-line-or-text 'CUA 'move)
;; <home> is still bound to move-beginning-of-line
(global-set-key (kbd "C-a") 'beginning-of-line-or-text)

(defun end-of-code-or-line ()
  "Move to EOL. If already there, to EOL sans comments.
    That is, the end of the code, ignoring any trailing comment
    or whitespace.  Note this does not handle 2 character
    comment starters like // or /*.  Such will not be skipped."
  (interactive)
  (if (not (eolp))
      (end-of-line)
    (skip-chars-backward " \t")
    (let ((pt (point))
          (lbp (line-beginning-position))
          (comment-start-re (concat (if comment-start
                                        (regexp-quote
                                         (replace-regexp-in-string
                                          "[[:space:]]*" "" comment-start))
                                      "[^[:space:]][[:space:]]*$")
                                    "\\|\\s<"))
          (comment-stop-re "\\s>")
          (lim))
      (when (re-search-backward comment-start-re lbp t)
        (setq lim (point))
        (if (re-search-forward comment-stop-re (1- pt) t)
            (goto-char pt)
          (goto-char lim)               ; test here ->
          (while (looking-back comment-start-re (1- (point)))
            (backward-char))
          (skip-chars-backward " \t"))))))
(put 'end-of-code-or-line 'CUA 'move)
;; <end> is still bound to end-of-visual-line
(global-set-key (kbd "C-e") 'end-of-code-or-line)
于 2013-01-09T20:32:57.937 回答