branch: externals/diff-hl
commit 1a4dbc7a5528679dea7ba7e0741b12936540934d
Merge: a7b59bc681 7c57e8c740
Author: Dmitry Gutov <[email protected]>
Commit: GitHub <[email protected]>
Merge pull request #227 from wyuenho/refactor-show-hunk
Refactor show hunk to avoid circular dependency
---
diff-hl-inline-popup.el | 289 --------------------------------
diff-hl-show-hunk-inline.el | 400 ++++++++++++++++++++++++++++++++++++++++++++
diff-hl-show-hunk.el | 86 +---------
3 files changed, 405 insertions(+), 370 deletions(-)
diff --git a/diff-hl-inline-popup.el b/diff-hl-inline-popup.el
deleted file mode 100644
index 0f202aff5a..0000000000
--- a/diff-hl-inline-popup.el
+++ /dev/null
@@ -1,289 +0,0 @@
-;;; diff-hl-inline-popup.el --- inline popup using phantom overlays -*-
lexical-binding: t -*-
-
-;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
-
-;; Author: Álvaro González <[email protected]>
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs 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 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;; Shows inline popups using phantom overlays. The lines of the popup
-;; can be scrolled.
-;;; Code:
-
-(require 'subr-x)
-
-(defvar diff-hl-inline-popup--current-popup nil "The overlay of the current
inline popup.")
-(defvar diff-hl-inline-popup--current-lines nil "A list of the lines to show
in the popup.")
-(defvar diff-hl-inline-popup--current-index nil "First line showed in popup.")
-(defvar diff-hl-inline-popup--invokinkg-command nil "Command that invoked the
popup.")
-(defvar diff-hl-inline-popup--current-footer nil "String to be displayed in
the footer.")
-(defvar diff-hl-inline-popup--current-header nil "String to be displayed in
the header.")
-(defvar diff-hl-inline-popup--height nil "Height of the popup.")
-(defvar diff-hl-inline-popup--current-custom-keymap nil "Keymap to be added to
the keymap of the inline popup.")
-(defvar diff-hl-inline-popup--close-hook nil "Function to be called when the
popup closes.")
-
-(make-variable-buffer-local 'diff-hl-inline-popup--current-popup)
-(make-variable-buffer-local 'diff-hl-inline-popup--current-lines)
-(make-variable-buffer-local 'diff-hl-inline-popup--current-index)
-(make-variable-buffer-local 'diff-hl-inline-popup--current-header)
-(make-variable-buffer-local 'diff-hl-inline-popup--current-footer)
-(make-variable-buffer-local 'diff-hl-inline-popup--invokinkg-command)
-(make-variable-buffer-local 'diff-hl-inline-popup--current-custom-keymap)
-(make-variable-buffer-local 'diff-hl-inline-popup--height)
-(make-variable-buffer-local 'diff-hl-inline-popup--close-hook)
-
-(defun diff-hl-inline-popup--splice (list offset length)
- "Compute a sublist of LIST starting at OFFSET, of LENGTH."
- (butlast
- (nthcdr offset list)
- (- (length list) length offset)))
-
-(defun diff-hl-inline-popup--ensure-enough-lines (pos content-height)
- "Ensure there is enough lines below POS to show the inline popup.
-CONTENT-HEIGHT specifies the height of the popup."
- (let* ((line (line-number-at-pos pos))
- (end (line-number-at-pos (window-end nil t)))
- (height (+ 6 content-height))
- (overflow (- (+ line height) end)))
- (when (< 0 overflow)
- (run-with-timer 0.1 nil #'scroll-up overflow))))
-
-(defun diff-hl-inline-popup--compute-content-height (&optional content-size)
- "Compute the height of the inline popup.
-Default for CONTENT-SIZE is the size of the current lines"
- (let ((content-size (or content-size (length
diff-hl-inline-popup--current-lines)))
- (max-size (- (/(window-height) 2) 3)))
- (min content-size max-size)))
-
-(defun diff-hl-inline-popup--compute-content-lines (lines index window-size)
- "Compute the lines to show in the popup.
-Compute it from LINES starting at INDEX with a WINDOW-SIZE."
- (let* ((len (length lines))
- (window-size (min window-size len))
- (index (min index (- len window-size))))
- (diff-hl-inline-popup--splice lines index window-size)))
-
-(defun diff-hl-inline-popup--compute-header (width &optional header)
- "Compute the header of the popup.
-Compute it from some WIDTH, and some optional HEADER text."
- (let* ((scroll-indicator (if (eq diff-hl-inline-popup--current-index 0) "
" " ⬆ "))
- (header (or header ""))
- (new-width (- width (length header) (length scroll-indicator)))
- (header (if (< new-width 0) "" header))
- (new-width (- width (length header) (length scroll-indicator)))
- (line (propertize (concat (diff-hl-inline-popup--separator new-width)
- header scroll-indicator )
- 'face '(:underline t))))
- (concat line "\n") ))
-
-(defun diff-hl-inline-popup--compute-footer (width &optional footer)
- "Compute the header of the popup.
-Compute it from some WIDTH, and some optional FOOTER text."
- (let* ((scroll-indicator (if (>= diff-hl-inline-popup--current-index
- (- (length
diff-hl-inline-popup--current-lines)
- diff-hl-inline-popup--height))
- " "
- " ⬇ "))
- (footer (or footer ""))
- (new-width (- width (length footer) (length scroll-indicator)))
- (footer (if (< new-width 0) "" footer))
- (new-width (- width (length footer) (length scroll-indicator)))
- (blank-line (if (display-graphic-p)
- ""
- (concat "\n" (propertize
(diff-hl-inline-popup--separator width)
- 'face '(:underline t)))))
- (line (propertize (concat (diff-hl-inline-popup--separator new-width)
- footer scroll-indicator)
- 'face '(:overline t))))
- (concat blank-line "\n" line)))
-
-(defun diff-hl-inline-popup--separator (width &optional sep)
- "Return the horizontal separator with character SEP and a WIDTH."
- (let ((sep (or sep ?\s)))
- (make-string width sep)))
-
-(defun diff-hl-inline-popup--available-width ()
- "Compute the available width in chars."
- (let ((magic-adjust 3))
- (if (not (display-graphic-p))
- (let* ((linumber-width (line-number-display-width nil))
- (width (- (window-body-width) linumber-width magic-adjust)))
- width)
- (let* ((font-width (window-font-width))
- (window-width (window-body-width nil t))
- (linenumber-width (line-number-display-width t))
- (available-pixels (- window-width linenumber-width))
- (width (- (/ available-pixels font-width) magic-adjust)))
-
- ;;
https://emacs.stackexchange.com/questions/5495/how-can-i-determine-the-width-of-characters-on-the-screen
- width))))
-
-(defun diff-hl-inline-popup--compute-popup-str (lines index window-size header
footer)
- "Compute the string that represents the popup.
-There are some content LINES starting at INDEX, with a WINDOW-SIZE. HEADER and
-FOOTER are showed at start and end."
- (let* ((width (diff-hl-inline-popup--available-width))
- (content-lines (diff-hl-inline-popup--compute-content-lines lines
index window-size))
- (header (diff-hl-inline-popup--compute-header width header))
- (footer (diff-hl-inline-popup--compute-footer width footer)))
- (concat header (string-join content-lines "\n") footer "\n")))
-
-(defun diff-hl-inline-popup-scroll-to (index)
- "Scroll the inline popup to make visible the line at position INDEX."
- (when diff-hl-inline-popup--current-popup
- (setq diff-hl-inline-popup--current-index (max 0 (min index (- (length
diff-hl-inline-popup--current-lines) diff-hl-inline-popup--height))))
- (let* ((str (diff-hl-inline-popup--compute-popup-str
- diff-hl-inline-popup--current-lines
- diff-hl-inline-popup--current-index
- diff-hl-inline-popup--height
- diff-hl-inline-popup--current-header
- diff-hl-inline-popup--current-footer)))
- ;; https://debbugs.gnu.org/38563, `company--replacement-string'.
- (add-face-text-property 0 (length str) 'default t str)
- (put-text-property 0 1 'cursor 0 str)
- (overlay-put diff-hl-inline-popup--current-popup 'before-string str))))
-
-(defun diff-hl-inline-popup--popup-down()
- "Scrolls one line down."
- (interactive)
- (diff-hl-inline-popup-scroll-to (1+ diff-hl-inline-popup--current-index) ))
-
-(defun diff-hl-inline-popup--popup-up()
- "Scrolls one line up."
- (interactive)
- (diff-hl-inline-popup-scroll-to (1- diff-hl-inline-popup--current-index) ))
-
-(defun diff-hl-inline-popup--popup-pagedown()
- "Scrolls one page down."
- (interactive)
- (diff-hl-inline-popup-scroll-to (+ diff-hl-inline-popup--current-index
diff-hl-inline-popup--height) ))
-
-(defun diff-hl-inline-popup--popup-pageup()
- "Scrolls one page up."
- (interactive)
- (diff-hl-inline-popup-scroll-to (- diff-hl-inline-popup--current-index
diff-hl-inline-popup--height) ))
-
-(defvar diff-hl-inline-popup-transient-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "<prior>") #'diff-hl-inline-popup--popup-pageup)
- (define-key map (kbd "M-v") #'diff-hl-inline-popup--popup-pageup)
- (define-key map (kbd "<next>") #'diff-hl-inline-popup--popup-pagedown)
- (define-key map (kbd "C-v") #'diff-hl-inline-popup--popup-pagedown)
- (define-key map (kbd "<up>") #'diff-hl-inline-popup--popup-up)
- (define-key map (kbd "C-p") #'diff-hl-inline-popup--popup-up)
- (define-key map (kbd "<down>") #'diff-hl-inline-popup--popup-down)
- (define-key map (kbd "C-n") #'diff-hl-inline-popup--popup-down)
- (define-key map (kbd "C-g") #'diff-hl-inline-popup-hide)
- (define-key map [escape] #'diff-hl-inline-popup-hide)
- (define-key map (kbd "q") #'diff-hl-inline-popup-hide)
- ;;http://ergoemacs.org/emacs/emacs_mouse_wheel_config.html
- (define-key map (kbd "<mouse-4>") #'diff-hl-inline-popup--popup-up)
- (define-key map (kbd "<wheel-up>") #'diff-hl-inline-popup--popup-up)
- (define-key map (kbd "<mouse-5>") #'diff-hl-inline-popup--popup-down)
- (define-key map (kbd "<wheel-down>") #'diff-hl-inline-popup--popup-down)
- map)
- "Keymap for command `diff-hl-inline-popup-transient-mode'.
-Capture all the vertical movement of the point, and converts it
-to scroll in the popup")
-
-(defun diff-hl-inline-popup--ignorable-command-p (command)
- "Decide if COMMAND is a command allowed while showing an inline popup."
- ;;
https://emacs.stackexchange.com/questions/653/how-can-i-find-out-in-which-keymap-a-key-is-bound
- (let ((keys (where-is-internal command (list
diff-hl-inline-popup--current-custom-keymap
-
diff-hl-inline-popup-transient-mode-map ) t))
- (invoking (eq command diff-hl-inline-popup--invokinkg-command)))
- (or keys invoking)))
-
-(defun diff-hl-inline-popup--post-command-hook ()
- "Called each time a command is executed."
- (let ((allowed-command (or
- (string-match-p "diff-hl-inline-popup-" (symbol-name
this-command))
- (diff-hl-inline-popup--ignorable-command-p
this-command))))
- (unless allowed-command
- (diff-hl-inline-popup-hide))))
-
-(define-minor-mode diff-hl-inline-popup-transient-mode
- "Temporal minor mode to control an inline popup"
- :global nil
- (remove-hook 'post-command-hook #'diff-hl-inline-popup--post-command-hook t)
- (set-keymap-parent diff-hl-inline-popup-transient-mode-map nil)
-
- (when diff-hl-inline-popup-transient-mode
- (set-keymap-parent diff-hl-inline-popup-transient-mode-map
- diff-hl-inline-popup--current-custom-keymap)
- (add-hook 'post-command-hook #'diff-hl-inline-popup--post-command-hook 0
t)))
-
-;;;###autoload
-(defun diff-hl-inline-popup-hide()
- "Hide the current inline popup."
- (interactive)
- (when diff-hl-inline-popup-transient-mode
- (diff-hl-inline-popup-transient-mode -1))
- (when diff-hl-inline-popup--close-hook
- (funcall diff-hl-inline-popup--close-hook)
- (setq diff-hl-inline-popup--close-hook nil))
- (when diff-hl-inline-popup--current-popup
- (delete-overlay diff-hl-inline-popup--current-popup)
- (setq diff-hl-inline-popup--current-popup nil)))
-
-;;;###autoload
-(defun diff-hl-inline-popup-show (lines &optional header footer keymap
close-hook point height)
- "Create a phantom overlay to show the inline popup, with some
-content LINES, and a HEADER and a FOOTER, at POINT. KEYMAP is
-added to the current keymaps. CLOSE-HOOK is called when the popup
-is closed."
- (when diff-hl-inline-popup--current-popup
- (delete-overlay diff-hl-inline-popup--current-popup)
- (setq diff-hl-inline-popup--current-popup nil))
-
- (when (< (diff-hl-inline-popup--compute-content-height 99) 2)
- (user-error "There is no enough vertical space to show the inline popup"))
- (let* ((the-point (or point (line-end-position)))
- (the-buffer (current-buffer))
- (overlay (make-overlay the-point the-point the-buffer)))
- (overlay-put overlay 'phantom t)
- (overlay-put overlay 'diff-hl-inline-popup t)
- (setq diff-hl-inline-popup--current-popup overlay)
-
- (setq diff-hl-inline-popup--current-lines
- (mapcar (lambda (s) (replace-regexp-in-string "\n" " " s)) lines))
- (setq diff-hl-inline-popup--current-header header)
- (setq diff-hl-inline-popup--current-footer footer)
- (setq diff-hl-inline-popup--invokinkg-command this-command)
- (setq diff-hl-inline-popup--current-custom-keymap keymap)
- (setq diff-hl-inline-popup--close-hook close-hook)
- (setq diff-hl-inline-popup--height
(diff-hl-inline-popup--compute-content-height height))
- (setq diff-hl-inline-popup--height (min diff-hl-inline-popup--height
- (length
diff-hl-inline-popup--current-lines)))
- ;; (diff-hl-inline-popup--ensure-enough-lines point
diff-hl-inline-popup--height)
- (diff-hl-inline-popup-transient-mode 1)
- (diff-hl-inline-popup-scroll-to 0)
- overlay))
-
-(defun diff-hl-inline-popup--hide-all ()
- "Testing purposes, use in case some inline popups get stuck in a buffer."
- (interactive)
- (when diff-hl-inline-popup-transient-mode
- (diff-hl-inline-popup-transient-mode -1))
- (setq diff-hl-inline-popup--current-popup nil)
- (let* ((all-overlays (overlays-in (point-min) (point-max)))
- (overlays (cl-remove-if-not (lambda (o)(overlay-get o
'diff-hl-inline-popup)) all-overlays)))
- (dolist (o overlays)
- (delete-overlay o))))
-
-(provide 'diff-hl-inline-popup)
-;;; diff-hl-inline-popup ends here
diff --git a/diff-hl-show-hunk-inline.el b/diff-hl-show-hunk-inline.el
new file mode 100644
index 0000000000..ae2704d4a4
--- /dev/null
+++ b/diff-hl-show-hunk-inline.el
@@ -0,0 +1,400 @@
+;;; diff-hl-show-hunk-inline.el --- inline popup using phantom overlays -*-
lexical-binding: t -*-
+
+;; Copyright (C) 2020-2021 Free Software Foundation, Inc.
+
+;; Author: Álvaro González <[email protected]>
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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 of the License, or
+;; (at your option) any later version.
+
+;; GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;; Shows inline popups using phantom overlays. The lines of the popup
+;; can be scrolled.
+;;; Code:
+
+(require 'subr-x)
+
+(defvar diff-hl-show-hunk-inline--current-popup nil "The overlay of the
current inline popup.")
+(defvar diff-hl-show-hunk-inline--current-lines nil "A list of the lines to
show in the popup.")
+(defvar diff-hl-show-hunk-inline--current-index nil "First line showed in
popup.")
+(defvar diff-hl-show-hunk-inline--invoking-command nil "Command that invoked
the popup.")
+(defvar diff-hl-show-hunk-inline--current-footer nil "String to be displayed
in the footer.")
+(defvar diff-hl-show-hunk-inline--current-header nil "String to be displayed
in the header.")
+(defvar diff-hl-show-hunk-inline--height nil "Height of the popup.")
+(defvar diff-hl-show-hunk-inline--current-custom-keymap nil "Keymap to be
added to the keymap of the inline popup.")
+(defvar diff-hl-show-hunk-inline--close-hook nil "Function to be called when
the popup closes.")
+
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--current-popup)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--current-lines)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--current-index)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--current-header)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--current-footer)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--invoking-command)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--current-custom-keymap)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--height)
+(make-variable-buffer-local 'diff-hl-show-hunk-inline--close-hook)
+
+(defcustom diff-hl-show-hunk-inline-hide-hunk nil
+ "If t, inline-popup is shown over the hunk, hiding it."
+ :type 'boolean)
+
+(defcustom diff-hl-show-hunk-inline-smart-lines t
+ "If t, inline-popup tries to show only the deleted lines of the
+hunk. The added lines are shown when scrolling the popup. If
+the hunk consist only on added lines, then
+`diff-hl-show-hunk--no-lines-removed-message' it is shown."
+ :type 'boolean)
+
+(defun diff-hl-show-hunk-inline--splice (list offset length)
+ "Compute a sublist of LIST starting at OFFSET, of LENGTH."
+ (butlast
+ (nthcdr offset list)
+ (- (length list) length offset)))
+
+(defun diff-hl-show-hunk-inline--ensure-enough-lines (pos content-height)
+ "Ensure there is enough lines below POS to show the inline popup.
+CONTENT-HEIGHT specifies the height of the popup."
+ (let* ((line (line-number-at-pos pos))
+ (end (line-number-at-pos (window-end nil t)))
+ (height (+ 6 content-height))
+ (overflow (- (+ line height) end)))
+ (when (< 0 overflow)
+ (run-with-timer 0.1 nil #'scroll-up overflow))))
+
+(defun diff-hl-show-hunk-inline--compute-content-height (&optional
content-size)
+ "Compute the height of the inline popup.
+Default for CONTENT-SIZE is the size of the current lines"
+ (let ((content-size (or content-size (length
diff-hl-show-hunk-inline--current-lines)))
+ (max-size (- (/(window-height) 2) 3)))
+ (min content-size max-size)))
+
+(defun diff-hl-show-hunk-inline--compute-content-lines (lines index
window-size)
+ "Compute the lines to show in the popup.
+Compute it from LINES starting at INDEX with a WINDOW-SIZE."
+ (let* ((len (length lines))
+ (window-size (min window-size len))
+ (index (min index (- len window-size))))
+ (diff-hl-show-hunk-inline--splice lines index window-size)))
+
+(defun diff-hl-show-hunk-inline--compute-header (width &optional header)
+ "Compute the header of the popup.
+Compute it from some WIDTH, and some optional HEADER text."
+ (let* ((scroll-indicator (if (eq diff-hl-show-hunk-inline--current-index 0)
" " " ⬆ "))
+ (header (or header ""))
+ (new-width (- width (length header) (length scroll-indicator)))
+ (header (if (< new-width 0) "" header))
+ (new-width (- width (length header) (length scroll-indicator)))
+ (line (propertize (concat (diff-hl-show-hunk-inline--separator
new-width)
+ header scroll-indicator )
+ 'face '(:underline t))))
+ (concat line "\n") ))
+
+(defun diff-hl-show-hunk-inline--compute-footer (width &optional footer)
+ "Compute the header of the popup.
+Compute it from some WIDTH, and some optional FOOTER text."
+ (let* ((scroll-indicator (if (>= diff-hl-show-hunk-inline--current-index
+ (- (length
diff-hl-show-hunk-inline--current-lines)
+ diff-hl-show-hunk-inline--height))
+ " "
+ " ⬇ "))
+ (footer (or footer ""))
+ (new-width (- width (length footer) (length scroll-indicator)))
+ (footer (if (< new-width 0) "" footer))
+ (new-width (- width (length footer) (length scroll-indicator)))
+ (blank-line (if (display-graphic-p)
+ ""
+ (concat "\n" (propertize
(diff-hl-show-hunk-inline--separator width)
+ 'face '(:underline t)))))
+ (line (propertize (concat (diff-hl-show-hunk-inline--separator
new-width)
+ footer scroll-indicator)
+ 'face '(:overline t))))
+ (concat blank-line "\n" line)))
+
+(defun diff-hl-show-hunk-inline--separator (width &optional sep)
+ "Return the horizontal separator with character SEP and a WIDTH."
+ (let ((sep (or sep ?\s)))
+ (make-string width sep)))
+
+(defun diff-hl-show-hunk-inline--available-width ()
+ "Compute the available width in chars."
+ (let ((magic-adjust 3))
+ (if (not (display-graphic-p))
+ (let* ((linumber-width (line-number-display-width nil))
+ (width (- (window-body-width) linumber-width magic-adjust)))
+ width)
+ (let* ((font-width (window-font-width))
+ (window-width (window-body-width nil t))
+ (linenumber-width (line-number-display-width t))
+ (available-pixels (- window-width linenumber-width))
+ (width (- (/ available-pixels font-width) magic-adjust)))
+
+ ;;
https://emacs.stackexchange.com/questions/5495/how-can-i-determine-the-width-of-characters-on-the-screen
+ width))))
+
+(defun diff-hl-show-hunk-inline--compute-popup-str (lines index window-size
header footer)
+ "Compute the string that represents the popup.
+There are some content LINES starting at INDEX, with a WINDOW-SIZE. HEADER and
+FOOTER are showed at start and end."
+ (let* ((width (diff-hl-show-hunk-inline--available-width))
+ (content-lines (diff-hl-show-hunk-inline--compute-content-lines lines
index window-size))
+ (header (diff-hl-show-hunk-inline--compute-header width header))
+ (footer (diff-hl-show-hunk-inline--compute-footer width footer)))
+ (concat header (string-join content-lines "\n") footer "\n")))
+
+(defun diff-hl-show-hunk-inline-scroll-to (index)
+ "Scroll the inline popup to make visible the line at position INDEX."
+ (when diff-hl-show-hunk-inline--current-popup
+ (setq diff-hl-show-hunk-inline--current-index (max 0 (min index (- (length
diff-hl-show-hunk-inline--current-lines) diff-hl-show-hunk-inline--height))))
+ (let* ((str (diff-hl-show-hunk-inline--compute-popup-str
+ diff-hl-show-hunk-inline--current-lines
+ diff-hl-show-hunk-inline--current-index
+ diff-hl-show-hunk-inline--height
+ diff-hl-show-hunk-inline--current-header
+ diff-hl-show-hunk-inline--current-footer)))
+ ;; https://debbugs.gnu.org/38563, `company--replacement-string'.
+ (add-face-text-property 0 (length str) 'default t str)
+ (put-text-property 0 1 'cursor 0 str)
+ (overlay-put diff-hl-show-hunk-inline--current-popup 'before-string
str))))
+
+(defun diff-hl-show-hunk-inline--popup-down()
+ "Scrolls one line down."
+ (interactive)
+ (diff-hl-show-hunk-inline-scroll-to (1+
diff-hl-show-hunk-inline--current-index) ))
+
+(defun diff-hl-show-hunk-inline--popup-up()
+ "Scrolls one line up."
+ (interactive)
+ (diff-hl-show-hunk-inline-scroll-to (1-
diff-hl-show-hunk-inline--current-index) ))
+
+(defun diff-hl-show-hunk-inline--popup-pagedown()
+ "Scrolls one page down."
+ (interactive)
+ (diff-hl-show-hunk-inline-scroll-to (+
diff-hl-show-hunk-inline--current-index diff-hl-show-hunk-inline--height) ))
+
+(defun diff-hl-show-hunk-inline--popup-pageup()
+ "Scrolls one page up."
+ (interactive)
+ (diff-hl-show-hunk-inline-scroll-to (-
diff-hl-show-hunk-inline--current-index diff-hl-show-hunk-inline--height) ))
+
+(defvar diff-hl-show-hunk-inline-transient-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "<prior>") #'diff-hl-show-hunk-inline--popup-pageup)
+ (define-key map (kbd "M-v") #'diff-hl-show-hunk-inline--popup-pageup)
+ (define-key map (kbd "<next>") #'diff-hl-show-hunk-inline--popup-pagedown)
+ (define-key map (kbd "C-v") #'diff-hl-show-hunk-inline--popup-pagedown)
+ (define-key map (kbd "<up>") #'diff-hl-show-hunk-inline--popup-up)
+ (define-key map (kbd "C-p") #'diff-hl-show-hunk-inline--popup-up)
+ (define-key map (kbd "<down>") #'diff-hl-show-hunk-inline--popup-down)
+ (define-key map (kbd "C-n") #'diff-hl-show-hunk-inline--popup-down)
+ (define-key map (kbd "C-g") #'diff-hl-show-hunk-inline-hide)
+ (define-key map [escape] #'diff-hl-show-hunk-inline-hide)
+ (define-key map (kbd "q") #'diff-hl-show-hunk-inline-hide)
+ ;;http://ergoemacs.org/emacs/emacs_mouse_wheel_config.html
+ (define-key map (kbd "<mouse-4>") #'diff-hl-show-hunk-inline--popup-up)
+ (define-key map (kbd "<wheel-up>") #'diff-hl-show-hunk-inline--popup-up)
+ (define-key map (kbd "<mouse-5>") #'diff-hl-show-hunk-inline--popup-down)
+ (define-key map (kbd "<wheel-down>")
#'diff-hl-show-hunk-inline--popup-down)
+ map)
+ "Keymap for command `diff-hl-show-hunk-inline-transient-mode'.
+Capture all the vertical movement of the point, and converts it
+to scroll in the popup")
+
+(defun diff-hl-show-hunk-inline--ignorable-command-p (command)
+ "Decide if COMMAND is a command allowed while showing an inline popup."
+ ;;
https://emacs.stackexchange.com/questions/653/how-can-i-find-out-in-which-keymap-a-key-is-bound
+ (let ((keys (where-is-internal command (list
diff-hl-show-hunk-inline--current-custom-keymap
+
diff-hl-show-hunk-inline-transient-mode-map ) t))
+ (invoking (eq command diff-hl-show-hunk-inline--invoking-command)))
+ (or keys invoking)))
+
+(defun diff-hl-show-hunk-inline--post-command-hook ()
+ "Called each time a command is executed."
+ (let ((allowed-command (or
+ (string-match-p "diff-hl-show-hunk-inline-"
(symbol-name this-command))
+ (diff-hl-show-hunk-inline--ignorable-command-p
this-command))))
+ (unless allowed-command
+ (diff-hl-show-hunk-inline-hide))))
+
+(define-minor-mode diff-hl-show-hunk-inline-transient-mode
+ "Temporal minor mode to control an inline popup"
+ :global nil
+ (remove-hook 'post-command-hook
#'diff-hl-show-hunk-inline--post-command-hook t)
+ (set-keymap-parent diff-hl-show-hunk-inline-transient-mode-map nil)
+
+ (when diff-hl-show-hunk-inline-transient-mode
+ (set-keymap-parent diff-hl-show-hunk-inline-transient-mode-map
+ diff-hl-show-hunk-inline--current-custom-keymap)
+ (add-hook 'post-command-hook #'diff-hl-show-hunk-inline--post-command-hook
0 t)))
+
+;;;###autoload
+(defun diff-hl-show-hunk-inline-hide()
+ "Hide the current inline popup."
+ (interactive)
+ (when diff-hl-show-hunk-inline-transient-mode
+ (diff-hl-show-hunk-inline-transient-mode -1))
+ (when diff-hl-show-hunk-inline--close-hook
+ (funcall diff-hl-show-hunk-inline--close-hook)
+ (setq diff-hl-show-hunk-inline--close-hook nil))
+ (when diff-hl-show-hunk-inline--current-popup
+ (delete-overlay diff-hl-show-hunk-inline--current-popup)
+ (setq diff-hl-show-hunk-inline--current-popup nil)))
+
+;;;###autoload
+(defun diff-hl-show-hunk-inline-show (lines &optional header footer keymap
close-hook point height)
+ "Create a phantom overlay to show the inline popup, with some
+content LINES, and a HEADER and a FOOTER, at POINT. KEYMAP is
+added to the current keymaps. CLOSE-HOOK is called when the popup
+is closed."
+ (when diff-hl-show-hunk-inline--current-popup
+ (delete-overlay diff-hl-show-hunk-inline--current-popup)
+ (setq diff-hl-show-hunk-inline--current-popup nil))
+
+ (when (< (diff-hl-show-hunk-inline--compute-content-height 99) 2)
+ (user-error "There is no enough vertical space to show the inline popup"))
+ (let* ((the-point (or point (line-end-position)))
+ (the-buffer (current-buffer))
+ (overlay (make-overlay the-point the-point the-buffer)))
+ (overlay-put overlay 'phantom t)
+ (overlay-put overlay 'diff-hl-show-hunk-inline t)
+ (setq diff-hl-show-hunk-inline--current-popup overlay)
+
+ (setq diff-hl-show-hunk-inline--current-lines
+ (mapcar (lambda (s) (replace-regexp-in-string "\n" " " s)) lines))
+ (setq diff-hl-show-hunk-inline--current-header header)
+ (setq diff-hl-show-hunk-inline--current-footer footer)
+ (setq diff-hl-show-hunk-inline--invoking-command this-command)
+ (setq diff-hl-show-hunk-inline--current-custom-keymap keymap)
+ (setq diff-hl-show-hunk-inline--close-hook close-hook)
+ (setq diff-hl-show-hunk-inline--height
(diff-hl-show-hunk-inline--compute-content-height height))
+ (setq diff-hl-show-hunk-inline--height (min
diff-hl-show-hunk-inline--height
+ (length
diff-hl-show-hunk-inline--current-lines)))
+ ;; (diff-hl-show-hunk-inline--ensure-enough-lines point
diff-hl-show-hunk-inline--height)
+ (diff-hl-show-hunk-inline-transient-mode 1)
+ (diff-hl-show-hunk-inline-scroll-to 0)
+ overlay))
+
+(defun diff-hl-show-hunk-inline--hide-all ()
+ "Testing purposes, use in case some inline popups get stuck in a buffer."
+ (interactive)
+ (when diff-hl-show-hunk-inline-transient-mode
+ (diff-hl-show-hunk-inline-transient-mode -1))
+ (setq diff-hl-show-hunk-inline--current-popup nil)
+ (let* ((all-overlays (overlays-in (point-min) (point-max)))
+ (overlays (cl-remove-if-not (lambda (o)(overlay-get o
'diff-hl-show-hunk-inline)) all-overlays)))
+ (dolist (o overlays)
+ (delete-overlay o))))
+
+;;;###autoload
+(defun diff-hl-show-hunk-inline (buffer &optional _ignored-line)
+ "Implementation to show the hunk in a inline popup.
+BUFFER is a buffer with the hunk."
+ ;; prevent diff-hl-show-hunk-inline-hide from being called twice
+ (let ((diff-hl-show-hunk-inline--close-hook nil))
+ (diff-hl-show-hunk-inline-hide))
+ (setq diff-hl-show-hunk--hide-function #'diff-hl-show-hunk-inline-hide)
+ (let* ((lines (split-string (with-current-buffer buffer (buffer-string))
"[\n\r]+" ))
+ (smart-lines diff-hl-show-hunk-inline-smart-lines)
+ (original-lines-number (cl-count-if (lambda (s) (string-prefix-p "-"
s)) lines))
+ (lines (if (string= (car (last lines)) "" ) (butlast lines) lines))
+ (lines (if (and (eq original-lines-number 0) smart-lines)
+ diff-hl-show-hunk--no-lines-removed-message
+ lines))
+ (overlay diff-hl-show-hunk--original-overlay)
+ (type (overlay-get overlay 'diff-hl-hunk-type))
+ (point (if (eq type 'delete) (overlay-start overlay) (overlay-end
overlay)))
+ (propertize-line (lambda (l)
+ (propertize l 'face
+ (cond ((string-prefix-p "+" l)
+ 'diff-added)
+ ((string-prefix-p "-" l)
+ 'diff-removed)))))
+ (propertized-lines (mapcar propertize-line lines)))
+
+ (save-excursion
+ ;; Save point in case the hunk is hidden, so next/previous works as
expected
+ ;; If the hunk is delete type, then don't hide the hunk
+ ;; (because the hunk is located in a non deleted line)
+ (when (and diff-hl-show-hunk-inline-hide-hunk
+ (not (eq type 'delete)))
+ (let* ((invisible-overlay (make-overlay (overlay-start overlay)
+ (overlay-end overlay))))
+ ;; Make new overlay, since the diff-hl overlay can be changed by
diff-hl-flydiff
+ (overlay-put invisible-overlay 'invisible t)
+ ;; Change default hide popup function, to make the overlay visible
+ (setq diff-hl-show-hunk--hide-function
+ (lambda ()
+ (overlay-put invisible-overlay 'invisible nil)
+ (delete-overlay invisible-overlay)
+ (diff-hl-show-hunk-inline-hide)))))
+ (diff-hl-show-hunk--goto-hunk-overlay overlay)
+ (let ((height
+ (when smart-lines
+ (when (not (eq 0 original-lines-number))
+ original-lines-number)))
+ (footer "(q)Quit (p)Previous (n)Next (r)Revert (c)Copy
original"))
+ (unless diff-hl-show-staged-changes
+ (setq footer (concat footer " (S)Stage")))
+ (diff-hl-show-hunk-inline-show
+ propertized-lines
+ (if (and (boundp 'diff-hl-reference-revision)
diff-hl-reference-revision)
+ (concat "Diff with " diff-hl-reference-revision)
+ "Diff with HEAD")
+ footer
+ diff-hl-show-hunk-map
+ #'diff-hl-show-hunk-hide
+ point
+ height))
+ )))
+
+(define-obsolete-variable-alias 'diff-hl-inline-popup--current-popup
'diff-hl-show-hunk-inline--current-popup "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--current-lines
'diff-hl-show-hunk-inline--current-lines "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--current-index
'diff-hl-show-hunk-inline--current-index "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--invoking-command
'diff-hl-show-hunk-inline--invoking-command "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--current-footer
'diff-hl-show-hunk-inline--current-footer "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--current-header
'diff-hl-show-hunk-inline--current-header "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--height
'diff-hl-show-hunk-inline--height "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--current-custom-keymap
'diff-hl-show-hunk-inline--current-custom-keymap "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup--close-hook
'diff-hl-show-hunk-inline--close-hook "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-show-hunk-inline-popup-hide-hunk
'diff-hl-show-hunk-inline-hide-hunk "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-show-hunk-inline-popup-smart-lines
'diff-hl-show-hunk-inline-smart-lines "0.11.0")
+(define-obsolete-variable-alias 'diff-hl-inline-popup-transient-mode-map
'diff-hl-show-hunk-inline-transient-mode-map "0.11.0")
+
+(define-obsolete-function-alias 'diff-hl-inline-popup--splice
'diff-hl-show-hunk-inline--splice "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--ensure-enough-lines
'diff-hl-show-hunk-inline--ensure-enough-lines "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--compute-content-height
'diff-hl-show-hunk-inline--compute-content-height "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--compute-content-lines
'diff-hl-show-hunk-inline--compute-content-lines "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--compute-header
'diff-hl-show-hunk-inline--compute-header "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--compute-footer
'diff-hl-show-hunk-inline--compute-footer "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--separator
'diff-hl-show-hunk-inline--separator "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--available-width
'diff-hl-show-hunk-inline--available-width "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--compute-popup-str
'diff-hl-show-hunk-inline--compute-popup-str "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup-scroll-to
'diff-hl-show-hunk-inline-scroll-to "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--popup-down
'diff-hl-show-hunk-inline--popup-down "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--popup-up
'diff-hl-show-hunk-inline--popup-up "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--popup-pagedown
'diff-hl-show-hunk-inline--popup-pagedown "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--popup-pageup
'diff-hl-show-hunk-inline--popup-pageup "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--ignorable-command-p
'diff-hl-show-hunk-inline--ignorable-command-p "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--post-command-hook
'diff-hl-show-hunk-inline--post-command-hook "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup-transient-mode
'diff-hl-show-hunk-inline-transient-mode "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup-hide
'diff-hl-show-hunk-inline-hide "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup-show
'diff-hl-show-hunk-inline-show "0.11.0")
+(define-obsolete-function-alias 'diff-hl-inline-popup--hide-all
'diff-hl-show-hunk-inline--hide-all "0.11.0")
+
+(define-obsolete-function-alias 'diff-hl-show-hunk-inline-popup
'diff-hl-show-hunk-inline "0.11.0")
+
+(provide 'diff-hl-inline-popup)
+
+(provide 'diff-hl-show-hunk-inline)
+;;; diff-hl-show-hunk-inline ends here
diff --git a/diff-hl-show-hunk.el b/diff-hl-show-hunk.el
index 5a722f54b5..bc1ed4dae2 100644
--- a/diff-hl-show-hunk.el
+++ b/diff-hl-show-hunk.el
@@ -22,9 +22,9 @@
;;; Commentary:
;; `diff-hl-show-hunk' shows a popup with the modification hunk at point.
-;; `diff-hl-show-hunk-function' points to the backend used to show the
-;; hunk. Its default value is `diff-hl-show-hunk-inline-popup', that
-;; shows diffs inline using overlay. There is another built-in backend:
+;; `diff-hl-show-hunk-function' points to the backend used to show the hunk.
+;; Its default value is `diff-hl-show-hunk-inline', that shows diffs inline
+;; using overlay. There is another built-in backend:
;; `diff-hl-show-hunk-posframe' (based on posframe).
;;
;; `diff-hl-show-hunk-mouse-mode' adds interaction on clicking in the
@@ -36,7 +36,6 @@
;;; Code:
-(require 'diff-hl-inline-popup)
(require 'diff-hl)
(defvar diff-hl-show-hunk-mouse-mode-map
@@ -73,24 +72,13 @@
(defconst diff-hl-show-hunk-boundary "^@@.*@@")
(defconst diff-hl-show-hunk--no-lines-removed-message (list "<<no lines
removed>>"))
-(defcustom diff-hl-show-hunk-inline-popup-hide-hunk nil
- "If t, inline-popup is shown over the hunk, hiding it."
- :type 'boolean)
-
-(defcustom diff-hl-show-hunk-inline-popup-smart-lines t
- "If t, inline-popup tries to show only the deleted lines of the
-hunk. The added lines are shown when scrolling the popup. If
-the hunk consist only on added lines, then
-`diff-hl-show-hunk--no-lines-removed-message' it is shown."
- :type 'boolean)
-
-(defcustom diff-hl-show-hunk-function 'diff-hl-show-hunk-inline-popup
+(defcustom diff-hl-show-hunk-function 'diff-hl-show-hunk-inline
"The function used to render the hunk.
The function receives as first parameter a buffer with the
contents of the hunk, and as second parameter the line number
corresponding to the clicked line in the original buffer."
:type '(choice
- (const :tag "Show inline" diff-hl-show-hunk-inline-popup)
+ (const :tag "Show inline" diff-hl-show-hunk-inline)
(const :tag "Show using posframe" diff-hl-show-hunk-posframe)))
(defvar diff-hl-show-hunk--hide-function nil
@@ -229,70 +217,6 @@ Returns a list with the buffer and the line number of the
clicked line."
(define-key map (kbd "S") #'diff-hl-show-hunk-stage-hunk)
map))
-(defvar diff-hl-show-hunk--hide-function)
-
-;;;###autoload
-(defun diff-hl-show-hunk-inline-popup (buffer &optional _ignored-line)
- "Implementation to show the hunk in a inline popup.
-BUFFER is a buffer with the hunk."
- ;; prevent diff-hl-inline-popup-hide from being called twice
- (let ((diff-hl-inline-popup--close-hook nil))
- (diff-hl-inline-popup-hide))
- (setq diff-hl-show-hunk--hide-function #'diff-hl-inline-popup-hide)
- (let* ((lines (split-string (with-current-buffer buffer (buffer-string))
"[\n\r]+" ))
- (smart-lines diff-hl-show-hunk-inline-popup-smart-lines)
- (original-lines-number (cl-count-if (lambda (s) (string-prefix-p "-"
s)) lines))
- (lines (if (string= (car (last lines)) "" ) (butlast lines) lines))
- (lines (if (and (eq original-lines-number 0) smart-lines)
- diff-hl-show-hunk--no-lines-removed-message
- lines))
- (overlay diff-hl-show-hunk--original-overlay)
- (type (overlay-get overlay 'diff-hl-hunk-type))
- (point (if (eq type 'delete) (overlay-start overlay) (overlay-end
overlay)))
- (propertize-line (lambda (l)
- (propertize l 'face
- (cond ((string-prefix-p "+" l)
- 'diff-added)
- ((string-prefix-p "-" l)
- 'diff-removed)))))
- (propertized-lines (mapcar propertize-line lines)))
-
- (save-excursion
- ;; Save point in case the hunk is hidden, so next/previous works as
expected
- ;; If the hunk is delete type, then don't hide the hunk
- ;; (because the hunk is located in a non deleted line)
- (when (and diff-hl-show-hunk-inline-popup-hide-hunk
- (not (eq type 'delete)))
- (let* ((invisible-overlay (make-overlay (overlay-start overlay)
- (overlay-end overlay))))
- ;; Make new overlay, since the diff-hl overlay can be changed by
diff-hl-flydiff
- (overlay-put invisible-overlay 'invisible t)
- ;; Change default hide popup function, to make the overlay visible
- (setq diff-hl-show-hunk--hide-function
- (lambda ()
- (overlay-put invisible-overlay 'invisible nil)
- (delete-overlay invisible-overlay)
- (diff-hl-inline-popup-hide)))))
- (diff-hl-show-hunk--goto-hunk-overlay overlay)
- (let ((height
- (when smart-lines
- (when (not (eq 0 original-lines-number))
- original-lines-number)))
- (footer "(q)Quit (p)Previous (n)Next (r)Revert (c)Copy
original"))
- (unless diff-hl-show-staged-changes
- (setq footer (concat footer " (S)Stage")))
- (diff-hl-inline-popup-show
- propertized-lines
- (if (and (boundp 'diff-hl-reference-revision)
diff-hl-reference-revision)
- (concat "Diff with " diff-hl-reference-revision)
- "Diff with HEAD")
- footer
- diff-hl-show-hunk-map
- #'diff-hl-show-hunk-hide
- point
- height))
- )))
-
(defun diff-hl-show-hunk-copy-original-text ()
"Extracts all the lines from BUFFER starting with '-' to the kill ring."
(interactive)