考虑以下Lisp代码行:
(some-function 7 8 | 9) ;; some comment. note the extra indentation
该点位于'8'和'9'之间。如果我执行(move-beginning-of-line)
,则该点将位于该行的绝对开头,而不是'('。
同样适用于move-end-of-line
:如果我执行一次,我会发现将点放在')',如果我第二次执行它,则更好地放在行的绝对末尾。有些IDE表现得那样。
我试图实现这个但是卡住了,我的解决方案在缓冲区结束时表现得特别糟糕,并且在迷你缓冲区也是如此。 是否有提供此功能的库?
答案 0 :(得分:5)
我不知道任何库,但可以在几行Elisp中完成。
对于行部分的开头,捆绑的函数beginning-of-line-text
和back-to-indentation
(M-m
)移动到行的“有趣”部分的开头。 back-to-indentation
仅忽略空格,而beginning-of-line-text
忽略fill prefix(在编程语言中,这通常是注释标记,如果在注释中)。有关如何在实际行和逻辑行的开头之间进行切换,请参阅Smart home in Emacs。
对于行结尾部分,以下函数实现了您所描述的内容。函数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))))
答案 1 :(得分:2)
一些建议几乎可以满足您的要求:
在lisp代码中,您可以使用sexp移动命令对所需内容进行排序。要从中间的某个位置到达表达式的开头,请使用绑定到backward-up-list
的{{1}}。在您的示例中,这将带您进入左括号。要向后移动列表中的各个元素,请使用绑定到M-C-u
的{{1}}; backward-sexp
以相反的方式移动,并且绑定到M-C-b
。从性别开始,您可以使用forward-sexp
跳到下一个;与M-C-f
相反。
这些命令中没有一个实际上是在查看您所在的物理线路,因此它们将在多条线路上返回或前进。
其他选项包括Ace Jump mode,这是一种非常灵活的方式,可以快速导航到屏幕上可见的任何单词的开头。这可能会消除您使用特定于行的命令的需要。为了在一行内快速移动,我通常使用M-C-n
和M-C-p
来跳过单词。点击M-f
或M-b
时按住M
键的速度非常快,以至于我大部分时间默认使用该键。
编辑:
忘了另一个很好的命令 - b
,绑定到f
。这将使您返回到行中的第一个非空白字符。您可以建议这在第一次通话时表现正常,然后在第二次通话时备份到该行的开头:
back-to-indentation
答案 2 :(得分: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)
试试看,他们应该按照你想要的方式行事。
答案 3 :(得分: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)