branch: elpa/git-commit commit 95b432530a6b131e63bec7411ee768f1dee9f629 Author: Jonas Bernoulli <jo...@bernoul.li> Commit: Jonas Bernoulli <jo...@bernoul.li>
Do not set point when invoking context-menu --- docs/magit-section.org | 33 ++++++++++++++++- docs/magit-section.texi | 33 ++++++++++++++++- lisp/magit-diff.el | 8 ++-- lisp/magit-git.el | 10 ++--- lisp/magit-mode.el | 11 +++--- lisp/magit-section.el | 98 +++++++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 167 insertions(+), 26 deletions(-) diff --git a/docs/magit-section.org b/docs/magit-section.org index ce8d47b134..20397c3883 100644 --- a/docs/magit-section.org +++ b/docs/magit-section.org @@ -149,11 +149,15 @@ source for suitable examples before asking me for help. Thanks! - Function: magit-current-section :: - Return the section at point. + Return the section at point or where the context menu was invoked. + When using the context menu, return the section that the user + clicked on, provided the current buffer is the buffer in which + the click occured. Otherwise return the section at point. - Function magit-section-at &optional position :: - Return the section at POSITION, defaulting to point. + Return the section at POSITION, defaulting to point. Default to + point even when the context menu is used. - Function: magit-section-ident section :: @@ -188,6 +192,31 @@ source for suitable examples before asking me for help. Thanks! Return non-nil if SECTION has content or an unused washer function. +The next two functions are replacements for the Emacs functions that +have the same name except for the ~magit-~ prefix. Like +~magit-current-section~ they do not act on point, the cursors position, +but on the position where the user clicked to invoke the context menu. + +If your package provides a context menu and some of its commands act +on the "thing at point", even if just as a default, then use the +prefixed functions to teach them to instead use the click location +when appropriate. + +- Function magit-point :: + + Return point or the position where the context menu was invoked. + When using the context menu, return the position the user clicked + on, provided the current buffer is the buffer in which the click + occured. Otherwise return the same value as ~point~. + +- Function magit-thing-at-point thing &optional no-properties :: + + Return the THING at point or where the context menu was invoked. + When using the context menu, return the thing the user clicked + on, provided the current buffer is the buffer in which the click + occured. Otherwise return the same value as ~thing-at-point~. + For the meaning of THING and NO-PROPERTIES see that function. + * Matching Functions - Function: magit-section-match condition &optional (section (magit-current-section)) :: diff --git a/docs/magit-section.texi b/docs/magit-section.texi index 9fb8a09546..41fe361d97 100644 --- a/docs/magit-section.texi +++ b/docs/magit-section.texi @@ -193,12 +193,16 @@ buffer is reached. FUNCTION has to move point forward or return @chapter Core Functions @defun magit-current-section -Return the section at point. +Return the section at point or where the context menu was invoked. +When using the context menu, return the section that the user +clicked on, provided the current buffer is the buffer in which +the click occured. Otherwise return the section at point. @end defun @table @asis @item Function magit-section-at &optional position -Return the section at POSITION, defaulting to point. +Return the section at POSITION, defaulting to point. Default to +point even when the context menu is used. @end table @defun magit-section-ident section @@ -234,6 +238,31 @@ The return value has the form @code{(TYPE...)}. Return non-nil if SECTION has content or an unused washer function. @end defun +The next two functions are replacements for the Emacs functions that +have the same name except for the @code{magit-} prefix. Like +@code{magit-current-section} they do not act on point, the cursors position, +but on the position where the user clicked to invoke the context menu. + +If your package provides a context menu and some of its commands act +on the "thing at point", even if just as a default, then use the +prefixed functions to teach them to instead use the click location +when appropriate. + +@table @asis +@item Function magit-point +Return point or the position where the context menu was invoked. +When using the context menu, return the position the user clicked +on, provided the current buffer is the buffer in which the click +occured. Otherwise return the same value as @code{point}. + +@item Function magit-thing-at-point thing &optional no-properties +Return the THING at point or where the context menu was invoked. +When using the context menu, return the thing the user clicked +on, provided the current buffer is the buffer in which the click +occured. Otherwise return the same value as @code{thing-at-point}. +For the meaning of THING and NO-PROPERTIES see that function. +@end table + @node Matching Functions @chapter Matching Functions diff --git a/lisp/magit-diff.el b/lisp/magit-diff.el index d3d1593ac7..793a760527 100644 --- a/lisp/magit-diff.el +++ b/lisp/magit-diff.el @@ -1296,7 +1296,7 @@ for a revision." (interactive (pcase-let* ((mcommit (magit-section-value-if 'module-commit)) (atpoint (or mcommit - (thing-at-point 'git-revision t) + (magit-thing-at-point 'git-revision t) (magit-branch-or-commit-at-point))) (`(,args ,files) (magit-show-commit--arguments))) (list (or (and (not current-prefix-arg) atpoint) @@ -1677,7 +1677,7 @@ the Magit-Status buffer for DIRECTORY." (and magit-diff-visit-previous-blob (not in-worktree) (not (oref section combined)) - (not (< (point) (oref section content))) + (not (< (magit-point) (oref section content))) (= (char-after (line-beginning-position)) ?-))) (defvar magit-diff-visit-jump-to-change t) @@ -1703,7 +1703,7 @@ the Magit-Status buffer for DIRECTORY." offset))))) (defun magit-diff-hunk-column (section goto-from) - (if (or (< (point) + (if (or (< (magit-point) (oref section content)) (and (not goto-from) (= (char-after (line-beginning-position)) ?-))) @@ -3346,7 +3346,7 @@ last (visual) lines of the region." "Return non-nil if point is inside the body of a hunk." (and (magit-section-match 'hunk) (when-let ((content (oref (magit-current-section) content))) - (> (point) content)))) + (> (magit-point) content)))) ;;; Diff Extract diff --git a/lisp/magit-git.el b/lisp/magit-git.el index 80b88725b2..f300f29267 100644 --- a/lisp/magit-git.el +++ b/lisp/magit-git.el @@ -1457,13 +1457,13 @@ to, or to some other symbolic-ref that points to the same ref." (defun magit--painted-branch-at-point (&optional type) (or (and (not (eq type 'remote)) - (memq (get-text-property (point) 'font-lock-face) + (memq (get-text-property (magit-point) 'font-lock-face) (list 'magit-branch-local 'magit-branch-current)) - (when-let ((branch (thing-at-point 'git-revision t))) + (when-let ((branch (magit-thing-at-point 'git-revision t))) (cdr (magit-split-branch-name branch)))) (and (not (eq type 'local)) - (memq (get-text-property (point) 'font-lock-face) + (memq (get-text-property (magit-point) 'font-lock-face) (list 'magit-branch-remote 'magit-branch-remote-head)) (thing-at-point 'git-revision t)))) @@ -1486,7 +1486,7 @@ to, or to some other symbolic-ref that points to the same ref." (defun magit-commit-at-point () (or (magit-section-value-if 'commit) - (thing-at-point 'git-revision t) + (magit-thing-at-point 'git-revision t) (when-let ((chunk (magit-current-blame-chunk 'addition t))) (oref chunk orig-rev)) (and (derived-mode-p 'magit-stash-mode @@ -1506,7 +1506,7 @@ to, or to some other symbolic-ref that points to the same ref." (forge--pullreq-branch (oref it value)))) (magit-ref-p (format "refs/pullreqs/%s" (oref (oref it value) number)))))) - (thing-at-point 'git-revision t) + (magit-thing-at-point 'git-revision t) (when-let ((chunk (magit-current-blame-chunk 'addition t))) (oref chunk orig-rev)) (and magit-buffer-file-name diff --git a/lisp/magit-mode.el b/lisp/magit-mode.el index 54c054ec16..5bb9ed4139 100644 --- a/lisp/magit-mode.el +++ b/lisp/magit-mode.el @@ -1098,7 +1098,7 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." (lambda (window) (with-selected-window window (with-current-buffer buffer - (when-let ((section (magit-current-section))) + (when-let ((section (magit-section-at))) `(( ,window ,section ,@(magit-refresh-get-relative-position))))))) @@ -1135,16 +1135,17 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." (defun magit-refresh-get-relative-position () (when-let ((section (magit-current-section))) - (let ((start (oref section start))) - (list (- (line-number-at-pos (point)) + (let ((start (oref section start)) + (point (magit-point))) + (list (- (line-number-at-pos point) (line-number-at-pos start)) - (- (point) (line-beginning-position)) + (- point (line-beginning-position)) (and (magit-hunk-section-p section) (region-active-p) (progn (goto-char (line-beginning-position)) (when (looking-at "^[-+]") (forward-line)) (while (looking-at "^[ @]") (forward-line)) - (let ((beg (point))) + (let ((beg point)) (cond ((looking-at "^[-+]") (forward-line) (while (looking-at "^[-+]") (forward-line)) diff --git a/lisp/magit-section.el b/lisp/magit-section.el index 9a2b91e2f2..1bb6477a55 100644 --- a/lisp/magit-section.el +++ b/lisp/magit-section.el @@ -429,9 +429,39 @@ of this variable is set by `magit-insert-section' and you should never modify it.") (put 'magit-root-section 'permanent-local t) +(defvar-local magit--context-menu-section nil "For internal use only.") + +(defvar magit--context-menu-buffer nil "For internal use only.") + +(defun magit-point () + "Return point or the position where the context menu was invoked. +When using the context menu, return the position the user clicked +on, provided the current buffer is the buffer in which the click +occured. Otherwise return the same value as `point'." + (if magit--context-menu-section + (magit-menu-position) + (point))) + +(defun magit-thing-at-point (thing &optional no-properties) + "Return the THING at point or where the context menu was invoked. +When using the context menu, return the thing the user clicked +on, provided the current buffer is the buffer in which the click +occured. Otherwise return the same value as `thing-at-point'. +For the meaning of THING and NO-PROPERTIES see that function." + (if-let ((pos (magit-menu-position))) + (save-excursion + (goto-char pos) + (thing-at-point thing no-properties)) + (thing-at-point thing no-properties))) + (defun magit-current-section () - "Return the section at point." - (or (magit-section-at) magit-root-section)) + "Return the section at point or where the context menu was invoked. +When using the context menu, return the section that the user +clicked on, provided the current buffer is the buffer in which +the click occured. Otherwise return the section at point." + (or magit--context-menu-section + (magit-section-at) + magit-root-section)) (defun magit-section-at (&optional position) "Return the section at POSITION, defaulting to point." @@ -510,9 +540,14 @@ The return value has the form (TYPE...)." (defun magit-section-context-menu (menu click) "Populate MENU with Magit-Section commands at CLICK." - (mouse-set-point click) - (magit-section-update-highlight t) - (when-let ((section (magit-section-at))) + (when-let ((section (save-excursion + (unless (region-active-p) + (mouse-set-point click)) + (magit-section-at)))) + (unless (region-active-p) + (setq magit--context-menu-buffer (current-buffer)) + (setq magit--context-menu-section section) + (magit-section-update-highlight t)) (when (magit-section-content-p section) (define-key-after menu [magit-section-toggle] `(menu-item @@ -582,9 +617,39 @@ the expression (magit-menu-format-desc DESC) for that. See (when (and (stringp desc) (string-match-p "%[tTvsmMx]" desc)) (setq desc (list 'magit-menu-format-desc desc))) (define-key-after keymap key - `(menu-item ,desc ,def ,@props) + `( menu-item ,desc ,def ,@props + ;; Without this, the keys for point would be shown instead + ;; of the relevant ones from where the click occured. + ,@(and (not (region-active-p)) + (list :keys + (lambda () + (or (ignore-errors + (save-excursion + (goto-char (magit-menu-position)) + (key-description (where-is-internal def nil t)))) + ""))))) after)) +(defun magit-menu-position () + "Return the position where the context-menu was invoked. +If the current command wasn't invoked using the context-menu, +then return nil." + (and magit--context-menu-section + (ignore-errors + (posn-point (event-start (aref (this-command-keys-vector) 0)))))) + +(defun magit-menu-highlight-point-section () + (setq magit-section-highlight-force-update t) + (if (eq (current-buffer) magit--context-menu-buffer) + (setq magit--context-menu-section nil) + (if-let ((window (get-buffer-window magit--context-menu-buffer))) + (with-selected-window window + (setq magit--context-menu-section nil) + (magit-section-update-highlight)) + (with-current-buffer magit--context-menu-buffer + (setq magit--context-menu-section nil)))) + (setq magit--context-menu-buffer nil)) + (defvar magit--plural-append-es '(branch)) (cl-defgeneric magit-menu-common-value (_section) @@ -1477,12 +1542,29 @@ evaluated its BODY. Admittedly that's a bit of a hack." (defvar-local magit-section-unhighlight-sections nil) (defun magit-section-pre-command-hook () + (when (and (not (bound-and-true-p transient--prefix)) + (or magit--context-menu-buffer + magit--context-menu-section) + (not (eq (ignore-errors + (event-basic-type (aref (this-command-keys) 0))) + 'mouse-3))) + ;; This is the earliest opportunity to clean up after an aborted + ;; context-menu because that neither causes the command that created + ;; the menu to abort nor some abortion hook to be run. It is not + ;; possible to update highlighting before the first command invoked + ;; after the menu is aborted. Here we can only make sure it is + ;; updated afterwards. + (magit-menu-highlight-point-section)) (setq magit-section-pre-command-region-p (region-active-p)) (setq magit-section-pre-command-section (magit-current-section))) (defun magit-section-post-command-hook () - (unless (memq this-command '(magit-refresh magit-refresh-all)) - (magit-section-update-highlight))) + (unless (bound-and-true-p transient--prefix) + (when (or magit--context-menu-buffer + magit--context-menu-section) + (magit-menu-highlight-point-section)) + (unless (memq this-command '(magit-refresh magit-refresh-all)) + (magit-section-update-highlight)))) (defun magit-section-deactivate-mark () (setq magit-section-highlight-force-update t))