From cd391a035a7ff935b2247707c819351fa759d805 Mon Sep 17 00:00:00 2001 From: Jonas Bernoulli Date: Tue, 16 Apr 2019 09:19:00 +0200 Subject: Restore bookmark support Differences to the old implementation include: - The format of bookmark names has changed. - It now depends on the used `bookmark' command in what window a bookmark is opened. Previously both `magit' and `bookmark' displayed the buffer, which for some commands and buffers resulted in it being displayed in multiple windows. - `magit-submodules-mode' is no longer supported because it does not derive from `magit-mode' and therefore does not conform to the interface we now rely on. Bookmarking such buffers isn't particularly useful because just using the regular command is likely more efficient than using a bookmark. --- default.mk | 1 + lisp/Makefile | 1 + lisp/magit-bookmark.el | 202 +++++++++++++++++++++++++++++++++++++++++++++++++ lisp/magit-mode.el | 5 +- lisp/magit.el | 6 +- 5 files changed, 213 insertions(+), 2 deletions(-) create mode 100644 lisp/magit-bookmark.el diff --git a/default.mk b/default.mk index 8523d0a..63b2d2f 100644 --- a/default.mk +++ b/default.mk @@ -89,6 +89,7 @@ ELS += magit-gitignore.el ELS += magit-extras.el ELS += git-rebase.el ELS += magit-imenu.el +ELS += magit-bookmark.el ELCS = $(ELS:.el=.elc) ELMS = magit.el $(filter-out $(addsuffix .el,$(PACKAGES)),$(ELS)) ELGS = magit-autoloads.el magit-version.el diff --git a/lisp/Makefile b/lisp/Makefile index 5bd89e8..8a3698d 100644 --- a/lisp/Makefile +++ b/lisp/Makefile @@ -58,6 +58,7 @@ magit-gitignore.elc: magit.elc magit-extras.elc: magit.elc magit-merge.elc git-rebase.elc: magit.elc magit-imenu.elc: magit.elc git-rebase.elc +magit-bookmark.elc: magit.elc magit-obsolete.elc: magit.elc ## Build ############################################################# diff --git a/lisp/magit-bookmark.el b/lisp/magit-bookmark.el new file mode 100644 index 0000000..b5fef67 --- /dev/null +++ b/lisp/magit-bookmark.el @@ -0,0 +1,202 @@ +;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2019 The Magit Project Contributors +;; +;; You should have received a copy of the AUTHORS.md file which +;; lists all contributors. If not, see http://magit.vc/authors. + +;; Author: Jonas Bernoulli +;; Maintainer: Jonas Bernoulli + +;; Inspired by an earlier implementation by Yuri Khan. + +;; Magit is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; Magit is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with Magit. If not, see http://www.gnu.org/licenses. + +;;; Commentary: + +;; Support for bookmarks for most Magit buffers. + +;;; Code: + +(eval-when-compile + (require 'subr-x)) + +(require 'magit) +(require 'bookmark) + +;;; Core + +(defun magit--make-bookmark () + "Create a bookmark for the current Magit buffer. +Input values are the major-mode's `magit-bookmark-name' method, +and the buffer-local values of the variables referenced in its +`magit-bookmark-variables' property." + (if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables) + (let ((bookmark (bookmark-make-record-default 'no-file))) + (bookmark-prop-set bookmark 'handler 'magit--handle-bookmark) + (bookmark-prop-set bookmark 'mode major-mode) + (bookmark-prop-set bookmark 'filename (magit-toplevel)) + (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name))) + (dolist (var (get major-mode 'magit-bookmark-variables)) + (bookmark-prop-set bookmark var (symbol-value var))) + (bookmark-prop-set + bookmark 'magit-hidden-sections + (--keep (and (oref it hidden) + (cons (oref it type) + (if (derived-mode-p 'magit-stash-mode) + (replace-regexp-in-string + (regexp-quote magit-buffer-revision) + magit-buffer-revision-hash + (oref it value)) + (oref it value)))) + (oref magit-root-section children))) + bookmark) + (user-error "Bookmarking is not implemented for %s buffers" major-mode))) + +(defun magit--handle-bookmark (bookmark) + "Open a bookmark created by `magit--make-bookmark'. +Call the `magit-*-setup-buffer' function of the the major-mode +with the variables' values as arguments, which were recorded by +`magit--make-bookmark'. Ignore `magit-display-buffer-function'." + (let ((buffer (let ((default-directory (bookmark-get-filename bookmark)) + (mode (bookmark-prop-get bookmark 'mode)) + (magit-display-buffer-function #'identity) + (magit-display-buffer-noselect t)) + (apply (intern (format "%s-setup-buffer" + (substring (symbol-name mode) 0 -5))) + (--map (bookmark-prop-get bookmark it) + (get mode 'magit-bookmark-variables)))))) + (set-buffer buffer) ; That is the interface we have to adhere to. + (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections))) + (with-current-buffer buffer + (dolist (child (oref magit-root-section children)) + (if (member (cons (oref child type) + (oref child value)) + hidden) + (magit-section-hide child) + (magit-section-show child))))) + nil)) + +(cl-defgeneric magit-bookmark-name () + "Return name for bookmark to current buffer." + (format "%s%s" + (substring (symbol-name major-mode) 0 -5) + (if-let ((vars (get major-mode 'magit-bookmark-variables))) + (cl-mapcan (lambda (var) + (let ((val (symbol-value var))) + (if (and val (atom val)) + (list val) + val))) + vars) + ""))) + +;;; Diff +;;;; Diff + +(put 'magit-diff-mode 'magit-bookmark-variables + '(magit-buffer-range-hashed + magit-buffer-typearg + magit-buffer-diff-args + magit-buffer-diff-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode)) + (format "magit-diff(%s%s)" + (pcase (magit-diff-type) + (`staged "staged") + (`unstaged "unstaged") + (`committed magit-buffer-range) + (`undefined + (delq nil (list magit-buffer-typearg magit-buffer-range-hashed)))) + (if magit-buffer-diff-files + (concat " -- " (mapconcat #'identity magit-buffer-diff-files " ")) + ""))) + +;;;; Revision + +(put 'magit-revision-mode 'magit-bookmark-variables + '(magit-buffer-revision-hash + magit-buffer-diff-args + magit-buffer-diff-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode)) + (format "magit-revision(%s %s)" + (magit-rev-abbrev magit-buffer-revision) + (if magit-buffer-diff-files + (mapconcat #'identity magit-buffer-diff-files " ") + (magit-rev-format "%s" magit-buffer-revision)))) + +;;;; Stash + +(put 'magit-stash-mode 'magit-bookmark-variables + '(magit-buffer-revision-hash + magit-buffer-diff-args + magit-buffer-diff-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode)) + (format "magit-stash(%s %s)" + (magit-rev-abbrev magit-buffer-revision) + (if magit-buffer-diff-files + (mapconcat #'identity magit-buffer-diff-files " ") + (magit-rev-format "%s" magit-buffer-revision)))) + +;;; Log +;;;; Log + +(put 'magit-log-mode 'magit-bookmark-variables + '(magit-buffer-revisions + magit-buffer-log-args + magit-buffer-log-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode)) + (format "magit-log(%s%s)" + (mapconcat #'identity magit-buffer-revisions " ") + (if magit-buffer-log-files + (concat " -- " (mapconcat #'identity magit-buffer-log-files " ")) + ""))) + +;;;; Cherry + +(put 'magit-cherry-mode 'magit-bookmark-variables + '(magit-buffer-refname + magit-buffer-upstream)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode)) + (format "magit-cherry(%s > %s)" + magit-buffer-refname + magit-buffer-upstream)) + +;;;; Reflog + +(put 'magit-reflog-mode 'magit-bookmark-variables + '(magit-buffer-refname)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode)) + (format "magit-reflog(%s)" magit-buffer-refname)) + +;;; Misc + +(put 'magit-status-mode 'magit-bookmark-variables nil) + +(put 'magit-refs-mode 'magit-bookmark-variables + '(magit-buffer-upstream + magit-buffer-arguments)) + +(put 'magit-stashes-mode 'magit-bookmark-variables nil) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode)) + (format "magit-states(%s)" magit-buffer-refname)) + +;;; _ +(provide 'magit-bookmark) +;;; magit-bookmark.el ends here diff --git a/lisp/magit-mode.el b/lisp/magit-mode.el index d3b5879..faabfec 100644 --- a/lisp/magit-mode.el +++ b/lisp/magit-mode.el @@ -55,6 +55,8 @@ (declare-function magit-process-unset-mode-line-error-status "magit-process" ()) ;; For `magit-mode-setup-internal' (declare-function magit-status-goto-initial-section "magit-status" ()) +;; For `magit-mode' from `bookmark' +(defvar bookmark-make-record-function) (require 'format-spec) (require 'help-mode) @@ -605,7 +607,8 @@ Magit is documented in info node `(magit)'." (when (and (fboundp 'display-line-numbers-mode) (bound-and-true-p global-display-line-numbers-mode)) (display-line-numbers-mode -1)) - (add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache)) + (add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache) + (setq-local bookmark-make-record-function 'magit--make-bookmark)) ;;; Highlighting diff --git a/lisp/magit.el b/lisp/magit.el index 382d3c2..d5ee11f 100644 --- a/lisp/magit.el +++ b/lisp/magit.el @@ -580,7 +580,11 @@ For X11 something like ~/.xinitrc should work.\n" (require 'magit-gitignore) (require 'magit-extras) (require 'git-rebase) - (require 'magit-imenu))) + (require 'magit-imenu) + (require 'magit-bookmark))) + +(eval-after-load 'bookmark + '(require 'magit-bookmark)) (if after-init-time (progn (magit-startup-asserts) -- cgit v1.0