joodland / bm Goto Github PK
View Code? Open in Web Editor NEWbm.el -- Visual Bookmarks for GNU Emacs
Home Page: http://joodland.github.io/bm/
License: GNU General Public License v2.0
bm.el -- Visual Bookmarks for GNU Emacs
Home Page: http://joodland.github.io/bm/
License: GNU General Public License v2.0
When bm-cycle-all-buffers is true, is it possible to make bm-next and bm-previous jump to the original window where the bookmark was defined instead of opening the bookmark buffer in the current window?
I like to have multiple windows open, each with its own unique buffer, and I was hoping to set a bookmark in each window and then use bm-next and bm-previous to jump from window to window to each of the bookmarks.
Instead it jumps from buffer to buffer in the current window, which might be a nice option for some work flows, but not what I was hoping.
I'm trying to make the bm bookmarks persistent across sessions (and load when the file is opened).
This is my setup based on my understanding now:
(use-package bm
:ensure t
:diminish helm-mode
:init
(progn
(setq bm-repository-size 100) ; nil means unlimitted
(setq bm-marker 'bm-marker-left)
(setq bm-highlight-style 'bm-highlight-only-fringe)
(setq-default bm-buffer-persistence t)
(setq-default bm-repository-file "~/.emacs.d/data/bm-bookmarks")
(setq bm-restore-repository-on-load t)
)
:bind
(("<M-S-f1>" . bm-toggle)
("<M-f1>" . bm-next)
("<S-f1>" . bm-previous))
:config
(progn (
(add-hook' after-init-hook 'bm-repository-load)
(add-hook 'find-file-hooks 'bm-buffer-restore)
(add-hook 'kill-buffer-hook 'bm-buffer-save)
(add-hook 'kill-emacs-hook '(lambda nil
(bm-buffer-save-all)
(bm-repository-save)))
)))
While I don't get errors (and the bookmarks work), the repository file is never created or loaded.
Any idea what am I doing incorrectly?
Thank you very much!
Hi @joodland,
Would you please tag a new release? MELPA Stable and Debian have 201905, so a number of users are currently affected.
Kind regards,
Nicholas
For added convenience on systems with touchscreens, the Filenames/line-numbers in the bm-show-all command should be clickable links. Currently you have to press enter after moving the cursor to the desired line.
Follow these steps and the bookmark will lose track of the correct line number to jump to:
Could you please add tags when a release is ready so MELPA Stable will pick it up? Thanks.
MELPA, of course, grabs the tip of the master branch, but stable only grabs tagged releases.
Is it possible to configure bm.el to start the line number at 1 rather than 0?
It would be great if it was possible to remove bookmarks at point and in a region in the bm-show buffer.
Thanks for writing this very useful package!
(global-set-key (kbd "<left-fringe> <mouse-5>") 'bm-next-mouse)
(global-set-key (kbd "<left-fringe> <mouse-4>") 'bm-previous-mouse)
(global-set-key (kbd "<left-fringe> <mouse-1>") 'bm-toggle-mouse)
In the use-package example in the README.md file, "add-hook 'find-file-hooks" is duplicated.
I have the following setup:
(use-package bm
:ensure t
:config
(setq bm-in-lifo-order t)
(setq bm-cycle-all-buffers t)
(setq bm-repository-file "~/.emacs.d/bm")
(setq-default bm-buffer-persistence t)
(add-hook' after-init-hook 'bm-repository-load)
(add-hook 'kill-buffer-hook #'bm-buffer-save)
(add-hook 'after-save-hook #'bm-buffer-save)
(add-hook 'kill-emacs-hook #'(lambda nil
(bm-buffer-save-all)
(bm-repository-save)))
(add-hook 'find-file-hooks #'bm-buffer-restore)
(add-hook 'after-revert-hook #'bm-buffer-restore)
(global-set-key (kbd "<C-f2>") 'bm-toggle)
(global-set-key (kbd "<f2>") 'bm-next)
(global-set-key (kbd "<S-f2>") 'bm-previous)
(global-set-key (kbd "M-<f2>") 'bm-show-all))
yet for some reason nothing is persisting. Yes, the folder "bm" does exist but it is sadly empty.
Hi bm-mode developers,
Thanks very much for an incredibly useful mode which I have been using daily for many years. I'd like to improve my workflow with regards to how bm integrates with org-mode, but I did not manage to find any solutions via googling. My basic problem is that I tend to collapse org documents a lot, as they are quite large, and then make use of bm to find particular spots of interest as required. However, the problem then is that the tree does not uncollapse as I move to the bookmark. Apparently a similar issue is face with traditional bookmakrs [1, 2], and it is addressed by the following function: org-bookmark-jump-unhide
. It is used like so:
(add-hook 'bookmark-after-jump-hook 'org-bookmark-jump-unhide)
My question is: what is the bm equivalent to bookmark-after-jump-hook
so that I can bind this function in a similar fashion? I assume bm does not use this hook as I tried this binding to no avail, but if my assumption is incorrect do let me know.
Many thanks for your time.
[1] SO: bookmark-jump to org-mode file with collapsed headings not working as expected
[2] SO: Go to a bookmark that is not visible currently due to narrowing
The idea is basically the same helm-mark-ring
Here is some prototype code for this (by me GPL license)
(defvar bm-helm--buffer nil "Buffer that bm-helm is running on")
(require 'bm)
(defun bm-helm ()
(interactive)
(setq bm-helm--buffer (current-buffer) )
(helm :sources (list (bm-helm--source))))
(defun bm-helm--source ()
(list
(cons 'name "Jump to bm bookmark")
(cons 'action (bm-helm--actions))
(cons 'candidates 'bm-helm--candidates)))
(defun bm-helm--actions ()
"Actions for used by helm. On return run DEFAULT-ACTION."
(list
(cons "Default action" 'bm-helm--goto)
(cons "Goto action" 'bm-helm--goto)))
(defun bm-helm--goto (x)
(interactive)
(message "Goto %S" x)
(with-current-buffer bm-helm--buffer
(bm-goto x)))
(defun bm-helm--candidates ()
(with-current-buffer bm-helm--buffer
(mapcar (lambda (overlay)
(cons (bm-helm--line overlay) overlay))
(bm-overlays-lifo-order bm-cycle-all-buffers))))
(defun bm-helm--line (overlay)
(save-excursion
(goto-char (overlay-start overlay))
(s-trim (thing-at-point 'line))))
when cycle through bookmarks in all open buffers, could you make it support
most recently set ones come first, oldest ones come last
First of all, many thanks for bm. I have used it for years. 8-)
Is there a way to silence those "2 bookmark(s) restored." messages?
Package dtrt-indent, for example, has a setting dtrt-indent-verbosity to make it less chatty.
It would be great if bookmark markers could be shown in terminal emacs.
Since terminal emacs doesn't have the fringe, they obviously can't go there. So there has to be some other way to display them.
Perhaps overlays could be used, with user-configurable properties, such as background and/or foreground color.
This way, maybe bookmarked lines could be indicated with, say, a user-configurable background color on lines that have bookmarks.
Allowing these markers to be toggled on and off would prevent them from permanently interfering with existing text properties or overlays in the buffer.
If persistent bookmarks are set somewhere, e.g., the first line, and the remaining part of the buffer is then narrowed down (narrow-to-region
), bm will show "args out of range" error when I quit emacs. Non-file buffers don't have the problem.
My bm settings:
(setq-default bm-buffer-persistence t)
(setq bm-restore-repository-on-load t
bm-highlight-style 'bm-highlight-only-fringe)
(add-hook 'after-init-hook 'bm-repository-load)
(add-hook 'find-file-hooks 'bm-buffer-restore)
(add-hook 'kill-buffer-hook 'bm-buffer-save)
(add-hook 'kill-emacs-hook '(lambda nil
(bm-buffer-save-all)
(bm-repository-save)))
(add-hook 'after-save-hook 'bm-buffer-save)
(add-hook 'after-revert-hook 'bm-buffer-restore)
(add-hook 'vc-before-checkin-hook 'bm-buffer-save)
Backtrace:
Debugger entered--Lisp error: (args-out-of-range #<buffer bm-test.el> 1 326)
buffer-substring-no-properties(326 1)
(let ((context-start (max (point-min) (- position bm-bookmark-context-size)))) (buffer-substring-no-properties context-start position))
(cons (quote before-context-string) (let ((context-start (max (point-min) (- position bm-bookmark-context-size)))) (buffer-substring-no-properties context-start position)))
(list (cons (quote position) position) (cons (quote time) (overlay-get bm (quote time))) (cons (quote temporary-bookmark) (overlay-get bm (quote temporary-bookmark))) (cons (quote annotation) (overlay-get bm (quote annotation))) (cons (quote before-context-string) (let ((context-start (max (point-min) (- position bm-bookmark-context-size)))) (buffer-substring-no-properties context-start position))) (cons (quote after-context-string) (let ((context-end (min (+ position bm-bookmark-context-size) (point-max)))) (buffer-substring-no-properties position context-end))))
(let ((position (marker-position (overlay-get bm (quote position))))) (list (cons (quote position) position) (cons (quote time) (overlay-get bm (quote time))) (cons (quote temporary-bookmark) (overlay-get bm (quote temporary-bookmark))) (cons (quote annotation) (overlay-get bm (quote annotation))) (cons (quote before-context-string) (let ((context-start (max (point-min) (- position bm-bookmark-context-size)))) (buffer-substring-no-properties context-start position))) (cons (quote after-context-string) (let ((context-end (min (+ position bm-bookmark-context-size) (point-max)))) (buffer-substring-no-properties position context-end)))))
(lambda (bm) (let ((position (marker-position (overlay-get bm (quote position))))) (list (cons (quote position) position) (cons (quote time) (overlay-get bm (quote time))) (cons (quote temporary-bookmark) (overlay-get bm (quote temporary-bookmark))) (cons (quote annotation) (overlay-get bm (quote annotation))) (cons (quote before-context-string) (let ((context-start (max ... ...))) (buffer-substring-no-properties context-start position))) (cons (quote after-context-string) (let ((context-end (min ... ...))) (buffer-substring-no-properties position context-end))))))(#<overlay from 1 to 78 in bm-test.el>)
mapcar((lambda (bm) (let ((position (marker-position (overlay-get bm (quote position))))) (list (cons (quote position) position) (cons (quote time) (overlay-get bm (quote time))) (cons (quote temporary-bookmark) (overlay-get bm (quote temporary-bookmark))) (cons (quote annotation) (overlay-get bm (quote annotation))) (cons (quote before-context-string) (let ((context-start (max ... ...))) (buffer-substring-no-properties context-start position))) (cons (quote after-context-string) (let ((context-end (min ... ...))) (buffer-substring-no-properties position context-end)))))) (#<overlay from 1 to 78 in bm-test.el>))
(let ((bookmarks (bm-lists))) (mapcar (function (lambda (bm) (let ((position (marker-position ...))) (list (cons (quote position) position) (cons (quote time) (overlay-get bm ...)) (cons (quote temporary-bookmark) (overlay-get bm ...)) (cons (quote annotation) (overlay-get bm ...)) (cons (quote before-context-string) (let ... ...)) (cons (quote after-context-string) (let ... ...)))))) (append (car bookmarks) (cdr bookmarks))))
(cons (quote bookmarks) (let ((bookmarks (bm-lists))) (mapcar (function (lambda (bm) (let ((position ...)) (list (cons ... position) (cons ... ...) (cons ... ...) (cons ... ...) (cons ... ...) (cons ... ...))))) (append (car bookmarks) (cdr bookmarks)))))
(list (bm-buffer-file-name) (cons (quote version) bm-bookmark-repository-version) (cons (quote size) (point-max)) (cons (quote timestamp) (current-time)) (cons (quote bookmarks) (let ((bookmarks (bm-lists))) (mapcar (function (lambda (bm) (let (...) (list ... ... ... ... ... ...)))) (append (car bookmarks) (cdr bookmarks))))))
(let ((buffer-data (list (bm-buffer-file-name) (cons (quote version) bm-bookmark-repository-version) (cons (quote size) (point-max)) (cons (quote timestamp) (current-time)) (cons (quote bookmarks) (let ((bookmarks ...)) (mapcar (function ...) (append ... ...))))))) (bm-repository-remove (car buffer-data)) (let ((count (length (cdr (assoc (quote bookmarks) buffer-data))))) (if (> count 0) (bm-repository-add buffer-data)) (if (called-interactively-p (quote interactive)) (message "%d bookmark(s) saved to repository." count))))
(if bm-buffer-persistence (let ((buffer-data (list (bm-buffer-file-name) (cons (quote version) bm-bookmark-repository-version) (cons (quote size) (point-max)) (cons (quote timestamp) (current-time)) (cons (quote bookmarks) (let (...) (mapcar ... ...)))))) (bm-repository-remove (car buffer-data)) (let ((count (length (cdr (assoc ... buffer-data))))) (if (> count 0) (bm-repository-add buffer-data)) (if (called-interactively-p (quote interactive)) (message "%d bookmark(s) saved to repository." count)))) (if (called-interactively-p (quote interactive)) (message "No bookmarks saved. Buffer is not persistent.")))
(if (bm-buffer-file-name) (if bm-buffer-persistence (let ((buffer-data (list (bm-buffer-file-name) (cons (quote version) bm-bookmark-repository-version) (cons (quote size) (point-max)) (cons (quote timestamp) (current-time)) (cons (quote bookmarks) (let ... ...))))) (bm-repository-remove (car buffer-data)) (let ((count (length (cdr ...)))) (if (> count 0) (bm-repository-add buffer-data)) (if (called-interactively-p (quote interactive)) (message "%d bookmark(s) saved to repository." count)))) (if (called-interactively-p (quote interactive)) (message "No bookmarks saved. Buffer is not persistent."))) (if (called-interactively-p (quote interactive)) (message "Unable to save bookmarks in non-file buffers.")))
bm-buffer-save()
(lambda (buffer) (set-buffer buffer) (bm-buffer-save))(#<buffer bm-test.el>)
mapc((lambda (buffer) (set-buffer buffer) (bm-buffer-save)) (#<buffer bm-test.el> #<buffer *Minibuf-1*> #<buffer *scratch*> #<buffer *Minibuf-0*> #<buffer *Messages*> #<buffer *code-conversion-work*> #<buffer *Echo Area 0*> #<buffer *Echo Area 1*> #<buffer *Disabled Command*> #<buffer *Help*>))
(save-current-buffer (mapc (function (lambda (buffer) (set-buffer buffer) (bm-buffer-save))) (buffer-list)))
bm-buffer-save-all()
(lambda nil (bm-buffer-save-all) (bm-repository-save))()
kill-emacs()
save-buffers-kill-emacs()
Due to a bug in the current emacs git head (29.0.60, https://debbugs.gnu.org/cgi/bugreport.cgi?bug=60058), bm.el does not work at all as overlays-list
is broken. The following snippet provides a work around for now:
(defun bm-lists (&optional direction predicate)
"Return a pair of lists giving all the bookmarks of the current buffer.
The car has all the bookmarks before the overlay center;
the cdr has all the bookmarks after the overlay center.
A bookmark implementation of `overlay-lists'.
If optional argument DIRECTION is provided, only return bookmarks
in the specified direction.
If optional argument PREDICATE is provided, it is used as a
selection criteria for filtering the lists."
(if (null predicate)
(setq predicate 'bm-bookmarkp))
(overlay-recenter (point))
(cond ((equal 'forward direction)
(cons nil (remq nil (mapcar predicate (overlays-in (point) (point-max))))))
((equal 'backward direction)
(cons (remq nil (mapcar predicate (overlays-in (point-min) (point)))) nil))
(t
(cons
(remq nil (mapcar predicate (overlays-in (point-min) (point))))
(remq nil (mapcar predicate (overlays-in (point) (point-max))))))))
Hi Jo,
Please could you add a function which will display all bookmarks that exist, not just those in open buffers.
Currently, you have to open a file before the bookmarks become available. Instead, it would be nice to use the bookmark list as an entry point to opening files.
Simple way to change color of highlighter should be added.
projectile
or persp-mode
or whatever, right now it goes jumping around between unrelated projects, perspectives, etc.
Hi. i love using bm yet for the life if me i cant get them to save between sessions. i added the following config after googling to try and get the bm's to be persistant
(use-package bm
:ensure t
:config
;;restore on load (even before you require bm)
(setq bm-restore-repository-on-load t)
(require 'bm)
;; Allow cross-buffer 'next'
(setq bm-cycle-all-buffers t)
;;where to store persistant files
(setq bm-repository-file "~/.emacs.d/bm-repository")
;; save bookmarks
(setq-default bm-buffer-persistence t)
;; Loading the repository from file when on start up.
(add-hook' after-init-hook 'bm-repository-load)
;; Restoring bookmarks when on file find.
(add-hook 'find-file-hooks 'bm-buffer-restore)
;; Saving bookmarks
(add-hook 'kill-buffer-hook #'bm-buffer-save)
;; Saving the repository to file when on exit.
;; kill-buffer-hook is not called when Emacs is killed, so we
;; must save all bookmarks first.
(defun modi/bm-save-all-bm-to-repository ()
(bm-buffer-save-all)
(bm-repository-save))
(add-hook 'kill-emacs-hook #'modi/bm-save-all-bm-to-repository)
(add-hook 'after-save-hook #'bm-buffer-save)
;; The `after-save-hook' is not necessary to use to achieve persistence,
;; but it makes the bookmark data in repository more in sync with the file
;; state.
;; Restoring bookmarks
(add-hook 'find-file-hooks #'bm-buffer-restore)
(add-hook 'after-revert-hook #'bm-buffer-restore)
;; The `after-revert-hook' is not necessary to use to achieve persistence,
;; but it makes the bookmark data in repository more in sync with the file
;; state. This hook might cause trouble when using packages
;; that automatically reverts the buffer (like vc after a check-in).
;; This can easily be avoided if the package provides a hook that is
;; called before the buffer is reverted (like `vc-before-checkin-hook').
;; Then new bookmarks can be saved before the buffer is reverted.
;; Make sure bookmarks is saved before check-in (and revert-buffer)
(add-hook 'vc-before-checkin-hook #'bm-buffer-save)
)
im using arch linux with latest emacs (24.4) and latest bm from MELPA
from the above config i should see the bm saves in ~/.emacs.d/bm-repository correct?
the current file has nothing in it:
;; bm.el -- persistent bookmarks. Do not edit this file.
nil
any clue?
thx
Z
Hello,
The function ivy-switch-buffer
use the build in variable bookmark-alist
to incorporate bookmarks to its options, but with bm
the variable bookmark-alist
has always nil value.
The code (load-bookmark bm-repository-file)
says that the bm-repository-file
is not in the "standard form".
Is there a way to get bookmark-alist
syncronized with bm-repository-file
or at least a way to get a file in "standard form" with the bookmarks of bm-repository-file
??
Thank you very much.
Hi there, I copied the suggested customization but I can't seem to get persistence working. The only change I made was in saving them to my ~/.emacs.d/bm/ folder.
Here is my code:
(use-package bm
:ensure t
:demand t
:init
;; restore on load (even before you require bm)
(setq bm-restore-repository-on-load t)
:config
(setq bm-cycle-all-buffers t)
(setq bm-repository-file "~/.emacs.d/bm") ;; yes there is a folder called ~/.emacs.d/bm
(setq-default bm-buffer-persistence t)
(add-hook' after-init-hook 'bm-repository-load)
(add-hook 'find-file-hooks 'bm-buffer-restore)
(add-hook 'kill-buffer-hook #'bm-buffer-save)
(add-hook 'kill-emacs-hook #'(lambda nil
(bm-buffer-save-all)
(bm-repository-save)))
(add-hook 'after-save-hook #'bm-buffer-save)
(add-hook 'find-file-hooks #'bm-buffer-restore)
(add-hook 'after-revert-hook #'bm-buffer-restore)
(add-hook 'vc-before-checkin-hook #'bm-buffer-save)
:bind (("<f2>" . bm-next)
("S-<f2>" . bm-previous)
("C-<f2>" . bm-toggle))
)
Dear Jo,
Thank you for maintaining bm.el. As 20170815.1609 has been in use for almost a year now, would you please consider tagging it as a stable release?
The Debian Emacsen Team is currently in the process of transitioning from emacs-goodies-el to a set of ELPA and MELPA packages. As we have a policy of only using tagged releases it would be a shame to use 201610
, which only has 321 downloads rather than 20170815.1609
which is clearly the version most people want, as it has 11 531 downloads.
Thank you :-)
Nicholas
Hi Jo,
Today I was surprised to discover that bm still isn't in Debian, so I reviewed the package again, and found that a full-text copy of the GPL-2+ was missing. I think there's a github button that will add it as either LICENSE or COPYRIGHT. Alternatively, here is a link for your convenience: https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
Sorry I missed this back in July! Would you please tag another stable release after adding this file?
Thanks,
Nicholas
For example, when there are three bookmarks in the current buffer,
and then remove the last bookmark, then run bm-previous
,
the point goes to the first bookmark instead of the second bookmark.
The script to reproduce:
;; FILE: /tmp/reproduce.el
;;
;; $ emacs -Q -nw -l bm.el /tmp/reproduce.el
;;
;; In Emacs:
;; 1. M-x end-of-buffer RET
;; 2. M-x edebug-defun RET
(progn
;; prepare bookmarks
(require 'bm)
(save-excursion
(goto-line 1) (bm-bookmark-add)
(goto-line 3) (bm-bookmark-add)
(goto-line 5) (bm-bookmark-add)
(bm-bookmark-remove) ;; remove the 3rd bookmark
)
(progn
(goto-char (point-max))
(setq bm-in-lifo-order t)
(bm-previous)
(when (equal (point) (point-min))
(message "Point in the first bookmark, but shouldn't be in the second bookmark?")))
)
It would be handy if the total number of bookmarks in the current buffer could be included in the modeline, something simple like this is would do....
BM: 6
This allows a quick glance to see if there are actually any bookmarks in the buffer (6 in this case) without having to open a new window with bm-show
This is a great package by the way, very useful, thanks for creating it
When bm-buffer-persistence
is t
, it looks like it's trying to save all bm information.
However, it doesn't seem to work.
I got
bm-buffer-save: Wrong type argument: listp, \.\.\.
The Backtrace shows
bm-repository-remove("/Users/ysong/org/personal/data/98/7982F8-57F5-4B57-8959-697522A860FE/MonkeyIsland2-Walkthrough-Daniel2.txt")
bm-buffer-save()
#f(compiled-function (buffer) #<bytecode 0x1fef21e97305>)(#<buffer MonkeyIsland2-Walkthrough-Daniel2.txt<7982F8-57F5-4B57-8959-697522A860FE>>)
mapc(#f(compiled-function (buffer) #<bytecode 0x1fef21e97305>) (#<buffer *Messages*> #<buffer bm.el> #<buffer *Minibuf-1*> #<buffer *Help*> #<buffer todo_personal_project.org> #<buffer note_emacs.org> #<buffer *scratch*> #<buffer MonkeyIsland2-Walkthrough-Daniel2.txt<7982F8-57F5-4B57-8959-697522A860FE>> #<buffer *spacemacs*> #<buffer *Minibuf-0*> #<buffer *code-conversion-work*> #<buffer *Echo Area 0*> #<buffer *Echo Area 1*> #<buffer MonkeyIsland2-Walkthrough-Daniel.txt> #<buffer MonkeyIsland2-Walkthrough-Daniel2.txt<MonkeyIsland2>> #<buffer MonkeyIsland2-Walkthrough.txt> #<buffer magit: .spacemacs.d<4>> ...))
bm-buffer-save-all()
Could you figure out why it happens?
Hi
Just saw this today:
Experimental code for synchronizing with standard bookmarks.
is there any documentation on that? that sounds very cool :D
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.