gilbertw1 / better-jumper Goto Github PK
View Code? Open in Web Editor NEWA configurable jump list implementation for Emacs
License: GNU General Public License v3.0
A configurable jump list implementation for Emacs
License: GNU General Public License v3.0
better-jump--last-jump-pos
is added at 7ae4011 to resolve #5, but it causes unexpected behavior (when use evil-mode).
Steps to reproduce:
Insert text:
abc-123
abc-456
abc-789
Search abc
three times starting from the top of text by press /
once and press n
twice in normal state (NOTE: I use evil-search
search module). After searching, the cursor position should at the third abc
. Press C-o
to go back to the second abc
and then press /
to search 456
. Finally, press C-o
again, I expect the cursor should go back to the second abc
, but it goes to the first abc
.
The reason is that better-jump--last-jump-pos
is the same as (point)
when I search 456
thus ignored by the advice of evil-set-jump
.
Maybe we should use evil--jumps-jumping-backward
to resolve #5 instead?
The following workaround seems work fine:
(with-eval-after-load 'better-jumper
(define-advice better-jumper--jump (:after (&rest _))
"Don't use `better-jump--last-jump-pos' to detect duplicate calls of `better-jumper-set-jump'."
(setq better-jump--last-jump-pos nil))
;; Instead, set `evil--jumps-jumping-backward' to non-nil to let
;; evil-mode know that we just jumped backward. It will be cleared
;; by evil-mode automatically.
(add-hook 'better-jumper-post-jump-hook
(lambda () (setq evil--jumps-jumping-backward t))))
It might be helpful to show a minibuffer message when one tries to jump past the first or last buffer list item.
Currently there is no feedback. This might be interpreted as if:
In my config I have
(advice-add #'markdown-follow-wiki-link :around #'better-jumper-set-jump)
What's the best way to get this sort of thing upstreamed? Is there some basic emacs call that could be added to the markdown-mode.el that would work with better-jumper? Just seeking advice, feel free to close.
What did you expect to happen?
better-jumper-jump-forward (C-i) jump buffers (files)
What actually happened?
better-jumper-jump-forward (C-i) don't jump buffers like the backward version (C-o)
Steps to reproduce:
Issue from doom emacs:
doomemacs/doomemacs#4050
Hey I have the following which I feel should work, what am I doing wrong? From the readme shouldn't better-jumper piggy back off of the built in jumplist implementation to track when jumps occur? Or maybe Im misunderstanding what you mean by "built in jump list implemention"?
(use-package better-jumper
:config
(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))
(use-package evil
:config
(setq evil-jmp-triggers
'(xref-goto-xref xref-quit-and-goto-xref evil-scroll-page-down
evil-scroll-page-up jump-to-register switch-to-buffer
previous-buffer helm-gtags-find-tag
spacemacs/c-c++-lsp-ccls-find-callers spacemacs/c-c++-lsp-ccls-find-callees
spacemacs/c-c++-lsp-ccls-find-refs-read spacemacs/c-c++-lsp-ccls-find-refs-write))
(dolist (cmd evil-jmp-triggers)
(evil-add-command-properties cmd :jmp t))
(advice-add 'evil-jump-backward
:around (lambda (oldfn &rest args)
(apply oldfn args)
(run-at-time ".1 sec") nil #'recenter)
(redraw-display))
(advice-add 'evil-jump-forward
:around (lambda (oldfn &rest args)
(apply oldfn args)
(run-at-time ".1 sec") nil #'recenter)
(redraw-display))
(better-jumper-mode)
) ; end use-package 'evil
Opening two files: a.txt
and b.txt
and closing them in the order: b.txt
then a.txt
jumping backwards opens b.txt
first.
a.txt
should probably open first since it was the most recently closed file.
With just Emacs and better-jumper
installed.
C-x f
c:/temp/a.txt
RET
C-x f
c:/temp/b.txt
RET
S-M-;
(better-jumper-set-jump)
RET
("c:/temp/b.txt" 1 "nwod2k")
C-x k
RET
S-M-;
(better-jumper-set-jump)
RET
("c:/temp/a.txt" 1 "hh4233")
C-x k
RET
M-x
better-jumper-jump-backward
RET
b.txt
opened.
If one tries to jump backwards one or more times:
M-x
better-jumper-jump-backward
RET
Then nothing happens.
The jump list: S-M-;
(better-jumper-get-jumps)
RET
contains:
#s(better-jumper-jump-list-struct (0 2 . [("c:/temp/b.txt" 1 "nwod2k") ("c:/temp/a.txt" 1 "hh4233") nil nil nil nil nil nil nil nil nil nil ...]) 1)
a.txt
should probably have opened since it was the most recently closed file.
better-jumper-20210110.1317
GNU Emacs 27.2 (build 1, x86_64-w64-mingw32) of 2021-03-26
Windows 10 Version 2004
Doom has helper functions to use ivy
, helm
, vertico
, etc to view the jumplist. They use the following code to fetch the jumplist:
(cddr (better-jumper-jump-list-struct-ring
(better-jumper-get-jumps (better-jumper--get-current-context))))
This doesn't seem sorted according to recency. Any ways to get the jumplist sorted properly?
PS: Here is the complete ivy
function:
(defun +ivy/jump-list ()
"Go to an entry in evil's (or better-jumper's) jumplist."
(interactive)
;; REVIEW Refactor me
(let (buffers)
(unwind-protect
(ivy-read "jumplist: "
(nreverse
(delete-dups
(delq
nil
(mapcar (lambda (mark)
(when mark
(cl-destructuring-bind (path pt _id) mark
(let ((buf (get-file-buffer path)))
(unless buf
(push (setq buf (find-file-noselect path t))
buffers))
(with-current-buffer buf
(goto-char pt)
(font-lock-fontify-region (line-beginning-position) (line-end-position))
(cons (format "%s:%d: %s"
(buffer-name)
(line-number-at-pos)
(string-trim-right (or (thing-at-point 'line) "")))
(point-marker)))))))
(cddr (better-jumper-jump-list-struct-ring
(better-jumper-get-jumps (better-jumper--get-current-context))))))))
:sort nil
:require-match t
:action (lambda (cand)
(let ((mark (cdr cand)))
(delq! (marker-buffer mark) buffers)
(mapc #'kill-buffer buffers)
(setq buffers nil)
(with-current-buffer (switch-to-buffer (marker-buffer mark))
(goto-char (marker-position mark)))))
:caller '+ivy/jump-list)
(mapc #'kill-buffer buffers))))
Apologies in advance if is intentional but I couldn't find anything mentioning it in the repository.
It looks like indirect buffers are not supported. If I make an indirect buffer, for example with clone-indirect-buffer
, and then jump somewhere in that buffer and try to jump backwards, I go back to a previous jump that is not in the indirect buffer.
Looking at the code, I can see that in better-jumper--push
:
(file-name (buffer-file-name))
...
(when (and (not file-name)
(string-match-p better-jumper--buffer-targets buffer-name))
(setq file-name buffer-name))
(when file-name
...
However, (buffer-file-name)
returns nil for indirect buffers.
Perhaps the predicate of the (setq file-name buffer-name)
should allow for indirect buffers? Just like it allows for the *scratch*
buffer. One way to test for an indirect buffer would be (buffer-base-buffer (get-buffer buffer-name))
, since buffer-base-buffer
returns non-nil for indirect buffers.
I tried using this but it failed because the file name stored was the buffer name for the indirect buffer, and when the jump actually happens, we have in better-jumper--jump
:
...
(if (string-match-p better-jumper--buffer-targets file-name)
(switch-to-buffer file-name)
(find-file file-name))
...
But find-file
will fail this. If minimizing code changes is prioritized, one can handle this by just setting better-jumper--buffer-targets
to include patterns for indirect buffers. If going for this solution, should better-jumper--buffer-targets
be changed to be non-internal and defined with defcustom
?
Adding another option for the regexp to accommodate indirect buffers, solves the issue:
(setq better-jumper--buffer-targets "\\*\\(new\\|scratch\\)\\*\\|<[0-9]+>$")
Where \\*\\(new\\|scratch\\)\\*
is the default value.
But other people might have different naming schemes for their indirect buffers so the assignment itself probably can't be considered a general solution.
Hi! I want to remove ring entries that contain the name of each buffer that I close (so I don't re-open them when jumping back). I've tried:
Here's my stab at it:
(defun ++remove-from-jump-list (file-name)
(interactive)
(let* ((context (better-jumper--get-current-context))
(old-struct (better-jumper--get-struct))
(struct (better-jumper--copy-struct old-struct))
(jumps (ring-elements (better-jumper--get-struct-jump-list struct)))
(jumps-filtered (->> jumps
(reverse)
(-filter (lambda (jump) (not (equal (car jump) file-name))))))
(jump-list (ring-convert-sequence-to-ring jumps-filtered)))
(message "Removing %s from jump-list" file-name)
(setf (better-jumper-jump-list-struct-ring struct) jump-list)
(better-jumper--set-struct context struct)
(better-jumper--get-struct context)))
(defun ++remove-current-buffer-from-jump-list ()
(condition-case ex
(and buffer-file-name (++remove-from-jump-list buffer-file-name))
('error (message (format "Failed to remove buffer %s from jump list: %s" buffer-file-name ex)))))
(advice-add #'kill-current-buffer :before #'++remove-current-buffer-from-jump-list)
but I get this strange error
"Failed to remove buffer /Users/raf/.doom.d/packages.el from jump list: (void-function (setf better-jumper-jump-list-struct-ring))"
Hi, thanks for better-jumper!
It seems doom emacs uses better-jumper instead of some evil jumping functions, so here's a [long] question. As a vim user, I am missing the separate "tag stack" functionality when using emacs, and I was wondering if better-jumper could work for that.
Basically, the jump list is polluted by several commands (for example, evil-window-top
, evil-forward-section-begin
, evil-scroll-down
...) that are inconsequential to code navigation, and it would be nice to jump backward and forward only to places where there are definitions of functions, for example. Those intermediate jumps -- in, for example, the current file -- can be distracting when trying to go back to the last function definition. Of course, there are cases where they are valuable.
I took a look at better-jumper.el
and wondered if there could be a better-jumper-set-definition-jump
(like better-jumper-set-jump
) the uses a separate jump list struct. This would probably need to be similar to the 'window
context since you'd be navigating to different files with something like evil-goto-definition
.
I don't fully understand the code, but it seems that the calls to better-jumper--get-struct
and better-jumper--push
could have some more args to be able to differentiate between this "better-jumper-set-definition-jump
" proposal and better-jumper-set-jump
, to make sure the correct jump list is used.
Thoughts?
I am not sure that I am opening the issue in the right place but it would be great if better-jumper would support workspaces.
Here is a related issue from doomemacs/doomemacs#2826
The implementation of better-jumper--window-configuration-hook
assumes that window creation commands don't focus the new window. When evil-vsplit-window-right
or evil-split-window-below
is set to t
, this is not the case and the jump list is not copied.
Details to reproduce are mentioned in the (not so) related doom-emacs issue.
Hi - many thanks for this package! :) I use it a lot with doom-emacs.
It was working fine for a while, and it stopped working over the past couple of months. I usually use lsp-find-definition
to get to the definition and better-jumper-backward
to jump backward. definitions are in the same or different buffers. better-jumper-forward
would take me back to the definition.
Now I'm seeing it fail to work - I can't really tell why. There's no response for jump-forward
/jump-backward
Doom Emacs with gccemacs on OSX if it helps.
Just wondering why better-jumper-set-jump
isn't (interactive)
since the POS
argument defaults to point.
Is there supposed to be a M-x better-jumper-get-jumps, cause I don't have that?
Is there some other way to get the list?
I find the jumping behavior of better jumper unintuitive, If I isearch up or down within a buffer, my first jump will usually take me out of the buffer altogether. I have been using a combination of better jumper and pop-mark.
Is is possible to configure better jumper to include "mark set" in its jump points?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.