spacemacs有没有类似其他IDE代码跳转的back和forward的跳转功能?

在命令里查到了evil-jump-forward和evil-jump-backward的命令,这个似乎用的是evil的jump ring来回溯的,其他的跳转命令往往默认不会自动触发往jump ring里面增加条目(可能得手动入栈出栈,不知道是啥命令)。 另外一种是用mark, 很多跳转命令都会自动触发mark ring的入栈和出栈,mark ring分为buffer ring和global ring, buffer ring是只能单个文件内部跳转,global ring是只能跨文件跳转(实际实验global ring只保留每个文件的最后一个mark条目),而一般我们在梳理代码逻辑的时候都是即可能跨文件,又可能在一个文件内跳转,所以应该是buffer ring和global ring这两种方式的融合比较合理,但是没有找到能达到这种效果的命令。 本人是spacemacs develop分支,holy模式,经常用ccls来做c开发,敢问各位大神有没有能解决我说的问题的好办法,或者如何可以实现我说的这种效果?我主要是想能回到之前跳转的地方,又能从回退的地方再跳转回来

用 lsp-mode 的话, emacs 内置的 xref-find-definitions/xref-pop-marker-stack 应该直接就可以用啊

我是需要能回溯之前的跳转历史和从之前的回溯点前进回来,应该是跳转点,不一定有定义和直接引用的关系。xref-pop-marker-stack这种方式确实能回溯定义和引用之前的关系,不过这个看起来只能回溯,有办法再逆回来吗?

我看了一下 push-mark 函数的实现, 稍微改一下就可以让 global-mark-ring 记录所有的位置

(defun push-mark (&optional location nomsg activate)
  "Set mark at LOCATION (point, by default) and push old mark on mark ring.
If the last global mark pushed was not in the current buffer,
also push LOCATION on the global mark ring.
Display `Mark set' unless the optional second arg NOMSG is non-nil.

Novice Emacs Lisp programmers often try to use the mark for the wrong
purposes.  See the documentation of `set-mark' for more information.

In Transient Mark mode, activate mark if optional third arg ACTIVATE non-nil."
  (when (mark t)
    (let ((old (nth mark-ring-max mark-ring))
          (history-delete-duplicates nil))
      (add-to-history 'mark-ring (copy-marker (mark-marker)) mark-ring-max t)
      (when old
        (set-marker old nil))))
  (set-marker (mark-marker) (or location (point)) (current-buffer))
  ;; Don't push the mark on the global mark ring if the last global
  ;; mark pushed was in this same buffer.
  ;; 把 unless 这个条件注释掉
  ;; (unless (and global-mark-ring
  ;;              (eq (marker-buffer (car global-mark-ring)) (current-buffer)))
    (let ((old (nth global-mark-ring-max global-mark-ring))
          (history-delete-duplicates nil))
      (add-to-history
       'global-mark-ring (copy-marker (mark-marker)) global-mark-ring-max t)
      (when old
        (set-marker old nil)))
    ;; )
  (or nomsg executing-kbd-macro (> (minibuffer-depth) 0)
      (message "Mark set"))
  (if (or activate (not transient-mark-mode))
      (set-mark (mark t)))
  nil)

问下,我看这个是在simple.el.gz文件里,还有一个simple.el.elc编译后的文件,我这边是直接把simple.el.gz的内容替换下,然后重启就行吗?怎么让我的改动生效?

你可以在自己配置文件里加上

(with-eval-after-load 'simple
  (defun push-mark ....))

覆盖原来定义就行了

大神,我把你贴的那部分代码加到了我的配置文件里,验证不起作用。我就研究了一个方案,可以先回溯buffer-ring,单个buffer-ring回溯到最后一个之后,再回溯global-ring来跳buffer。但是不知道怎么实现判断buffer-ring到最后一个了,大神有没有啥招指导下,大致实现是以下函数 image

中间条件判断的地方不对,我是想在buffer内,就调用buffer-ring回溯,buffer-ring到最后一个,就用global-ring回溯,如果当前buffer没有mark,就直接global-ring回溯

hybrid ?

跳转可以用 spacemacs 实现的 jump-to-definition(-other-window) jump-to-reference(-other-window),会依次遍历多种跳转后端,包括 lsp,evil-jump,dump-jump 等。然后也会往 evil jump 记录中注册。

这样就可以用 gd(D),gr 以及 evil-jump-forward/backward(C-i, C-o) 跳转啦

ps 其实想要给一个命令注册也很简单:

  (evil-set-command-property 'jump-to-definition :jump t)
  (evil-set-command-property 'jump-to-reference :jump t)

holy模式,你这个是跨文件和同一个文件内跳转都能实现吗?如果g d/g r这些命令都得用这个evil-set-command-property 'xxxx命令 :jump t注册之后才能用evil-jump-forward/backward吧 image 我下面的三个配置是对的吧

mark ring 默认是一个环,pop_mark 会把开头mark的放到结尾,所以不太好实现

好吧,看来还是得想其他招了。你贴的代码实现能确认下是否会进入global ring吗?我这边用了之后感觉不起作用

哈哈哈,我以前还真不知道有这个 mode

对的,

这个 spacemacs 已经帮你写好了

我发现这个evil-jumps的队列是个持久化存储的队列,重启emacs上一次的历史还在,另外感觉evil-jump-backward好用,但是evil-jump-forward不正常,不往前跳,我是在holy模式,是不是在evil模式才正常?

我也会有没反应的情况,但是 backward 之后 forward 貌似是正常的,不过我一般都很少用 forward,不太清楚它逻辑是不是我想的那样。 好像确实有点问题

可能是这个?evil-jump-forward does not seem to work · Issue #1138 · emacs-evil/evil · GitHub

我这边backward之后,有时候能往前跳,有时候不行,这个感觉像是evil-jumps把backward的位置又重新push到栈顶1的位置上了,只能先对付着用了

我修改的那段代码在我这是没问题的.

原来每次 push-mark 的时候检查 global-mark-ring 开头的 maker 对应 buffer 是否是当前 buffer, 如果是的话就不记录.

注释掉那个条件检查应该就每次 push-mark 都记录了