C-u C-SPC
可以"跳转到标记,并从弹出本地标记环的位置设置标记"。是否有一种方法可以沿着标记环相反的方向移动?比如说,你已经使用了多次C-u C-SPC命令,现在想要回到之前看到过的某个标记,而不用绕全部的标记环。C-u C-SPC
可以"跳转到标记,并从弹出本地标记环的位置设置标记"。是否有一种方法可以沿着标记环相反的方向移动?比如说,你已经使用了多次C-u C-SPC命令,现在想要回到之前看到过的某个标记,而不用绕全部的标记环。(defun unpop-to-mark-command ()
"Unpop off mark ring. Does nothing if mark ring is empty."
(interactive)
(when mark-ring
(setq mark-ring (cons (copy-marker (mark-marker)) mark-ring))
(set-marker (mark-marker) (car (last mark-ring)) (current-buffer))
(when (null (mark t)) (ding))
(setq mark-ring (nbutlast mark-ring))
(goto-char (marker-position (car (last mark-ring))))))
这是我刚刚花了太多时间解决的问题。与其他解决方案的不同之处在于它适用于缓冲区,即它适用于“全局标记环”。我的目标是模拟类似于Eclipse或IntelliJ的历史浏览。我将其绑定到M-left和M-right,显然你可以为此选择不同的键。
(defun marker-is-point-p (marker)
"test if marker is current point"
(and (eq (marker-buffer marker) (current-buffer))
(= (marker-position marker) (point))))
(defun push-mark-maybe ()
"push mark onto `global-mark-ring' if mark head or tail is not current location"
(if (not global-mark-ring) (error "global-mark-ring empty")
(unless (or (marker-is-point-p (car global-mark-ring))
(marker-is-point-p (car (reverse global-mark-ring))))
(push-mark))))
(defun backward-global-mark ()
"use `pop-global-mark', pushing current point if not on ring."
(interactive)
(push-mark-maybe)
(when (marker-is-point-p (car global-mark-ring))
(call-interactively 'pop-global-mark))
(call-interactively 'pop-global-mark))
(defun forward-global-mark ()
"hack `pop-global-mark' to go in reverse, pushing current point if not on ring."
(interactive)
(push-mark-maybe)
(setq global-mark-ring (nreverse global-mark-ring))
(when (marker-is-point-p (car global-mark-ring))
(call-interactively 'pop-global-mark))
(call-interactively 'pop-global-mark)
(setq global-mark-ring (nreverse global-mark-ring)))
(global-set-key [M-left] (quote backward-global-mark))
(global-set-key [M-right] (quote forward-global-mark))
在回复scottfrazer的非常方便的解决方案之后,这里提供一些建议,与该解决方案配合使用,使得可以轻松地根据需要在标记环中反向移动,而无需为每个方向使用不同的键绑定。
我使用cua-selection-mode
,因此对于我来说,C-SPC绑定到cua-set-mark
,但我已经将其编写为宏,以便通知绑定到C-SPC的任何函数,并验证它可以与默认的set-mark-command
一起工作。
要取消弹出,请只需提供负前缀参数。例如:C--C-SPC
cua-set-mark
的一个好处是,在初始的C-uC-SPC之后,您可以继续使用C-SPC连续弹出标记,我在这里包含了这种行为:在初始的C--C-SPC之后,您可以继续使用C-SPC取消弹出。要再次反转方向并调用pop-to-mark
,只需再次提供正参数,即C-uC-SPC。
(defmacro my-unpop-to-mark-advice ()
"Enable reversing direction with un/pop-to-mark."
`(defadvice ,(key-binding (kbd "C-SPC")) (around my-unpop-to-mark activate)
"Unpop-to-mark with negative arg"
(let* ((arg (ad-get-arg 0))
(num (prefix-numeric-value arg)))
(cond
;; Enabled repeated un-pops with C-SPC
((eq last-command 'unpop-to-mark-command)
(if (and arg (> num 0) (<= num 4))
ad-do-it ;; C-u C-SPC reverses back to normal direction
;; Otherwise continue to un-pop
(setq this-command 'unpop-to-mark-command)
(unpop-to-mark-command)))
;; Negative argument un-pops: C-- C-SPC
((< num 0)
(setq this-command 'unpop-to-mark-command)
(unpop-to-mark-command))
(t
ad-do-it)))))
(my-unpop-to-mark-advice)
C--
是 ctrl + -
(负号),它被绑定到了我的撤销操作上。我能否将其更改为其他按键绑定? - alperC-_
,因为这是 undo
的默认绑定,在某些键盘布局中 _
是 -
的 shifted 版本。 - phils(defun unpop-to-mark-command ()
"Unpop off mark ring into the buffer's actual mark.
Does not set point. Does nothing if mark ring is empty."
(interactive)
(let ((num-times (if (equal last-command 'pop-to-mark-command) 2
(if (equal last-command 'unpop-to-mark-command) 1
(error "Previous command was not a (un)pop-to-mark-command")))))
(dotimes (x num-times)
(when mark-ring
(setq mark-ring (cons (copy-marker (mark-marker)) mark-ring))
(set-marker (mark-marker) (+ 0 (car (last mark-ring))) (current-buffer))
(when (null (mark t)) (ding))
(setq mark-ring (nbutlast mark-ring))
(goto-char (mark t)))
(deactivate-mark))))
set-mark-command
的before-advice使C-u C-SPC
作为两个功能之间的切换? - phils有两个标记环:一个是当前缓冲区的本地环境,另一个是所有缓冲区共享的全局环境。
默认情况下,在 Icicles(在 Icicle 全局辅助模式中):
C-- C-SPC
可让您在本地标记之间切换C-- C-x C-SPC
可让您在全局标记之间切换IOW,使用负前缀 arg,C-SPC
和 C-x C-SPC
进行导航。如果没有,则它们将执行其正常操作(分别为 set-mark-command
和 pop-global-mark
)。
导航方式如下:
在输入期间可用的键包括:
up
, down
-- 在*Completions*
中循环候选项,而不导航到它们的位置
C-up
, C-down
-- 循环导航到每个位置
C-RET
, C-mouse-2
-- 直接转到当前/点击的候选项(例如在*Completions*
中)
RET
, mouse-2
-- 与上一条相同(转到候选项),但结束命令(完成)
S-TAB
-- apropos-complete(子字符串/正则表达式)
TAB
-- 前缀或模糊完成
虽然它不能完全满足您的要求,但是您可以尝试查找一个叫做marker-visit.el的软件包,它可以让您按照“缓冲区位置顺序”导航当前缓冲区中的标记。以下是该文件的一部分:
;;; Commentary:
;; This file provides a simple way to navigate among marks in a
;; buffer. C-u C-SPC is similar, but takes you haphazardly around the
;; buffer. Setting bookmarks is a lot of extra work if you just want
;; to jump around your buffer quickly; plus, you have to come up with
;; a name for every bookmark.
;; All the marks you've left while editing a buffer serve as bread
;; crumb trails of areas in the buffer you've edited. It is
;; convenient to navigate back and forth among these marks in order.
;; This file provides two methods to do just that, marker-visit-prev
;; and marker-visit-next. These two functions will take you, from
;; point, to the nearest mark in either direction. The function
;; marker-visit-truncate-mark-ring will truncate the mark ring.
;; The marks you can visit in a buffer consist of: "the mark" plus the
;; contents of the mark-ring.
我将[S-up]和[S-down]绑定到marker-visit-prev和marker-visit-next。
如果你真的想/需要按照mark-ring的当前顺序导航,那么你可以查看pop-to-mark-command和pop-mark函数,并实现自己的版本以相反的方向旋转mark-ring。
手册上说:
变量
mark-ring-max
指定了标记环中要保留的最大条目数。如果已经存在这么多条目并且又推入了另一个条目,则列表中最早的条目将被丢弃。重复使用“C-u C-'”可以循环浏览当前在环中的位置。
我建议您使用它来限制标记环的大小(例如3或4,我的当前为16)。然后,您可以使用前缀更快地移动它。
此外:
如果您想一遍又一遍地返回相同的位置,则标记环可能不够方便。如果是这样,您可以将位置记录在寄存器中以供以后检索(*参见在寄存器中保存位置:RegPos.)。
关于emacs按键绑定的问题,这里并没有直接的答案。
针对evil用户
我发现了一个适用于evil用户的better-jumper插件。如果你对evil-mode感兴趣,我真诚地建议你使用它。
在repository的主页中有详细的使用说明。
(with-eval-after-load 'evil-maps
(define-key evil-motion-state-map (kbd "C-o") 'better-jumper-jump-backward)
(define-key evil-motion-state-map (kbd "<C-i>") 'better-jumper-jump-forward))
回到光标的旧位置和前进到新位置非常容易。
此外,您可以使用其hook
函数创建新场景,例如更改缓冲区标记旧点等。
对于Emacs键绑定粉丝
我唯一能给出的默认键绑定样式建议是helm-all-mark-rings
。它提供了有关标记环的最佳可见性。
set-mark-command-repeat-pop
设置为非nil
,这将允许你在按一次C-u C-SPC
后仅需按C-SPC
。来自手册。 - quazgar