Magit intergration
EgorDuplensky opened this issue · 9 comments
I am implementing ivy-rich support for magit's ivy commands (mostly revision selection).
Would such pull request be acceptable for the project or I better to create a separate package?
Can you point me to which ivy commands for magit?
Magit does not really have ivy commands. It uses ivy-completing-read (see magit-completing-read) to form a command on the fly.
Basically I am creating counsel wrappers for those magit commands which eventually call ivy-completing-read (like magit-checkout) and then customizing them using ivy-rich framework. I haven't find a better way to do this.
The main obstacle here is that, for example, magit forms the list of the candidates for magit-checkout in scope of magit-checkout itself, it does not really have a function like magit-get-list-branches-to-checkout which I could use for counsel wrapper I am creating. So I have to call few internal magit functions (basically by coping 90% of magit-checkout code) which most likely are not supposed to be called from outside.
There is an example:
(defun magit-list-other-branch-or-commit ()
(let* ((current (magit-get-current-branch))
(atpoint (magit-branch-or-commit-at-point))
(exclude current)
(default (or (and (not (equal atpoint exclude))
(not (and (not current)
(magit-rev-equal atpoint "HEAD")))
atpoint)
(and (not (equal current exclude)) current)
(magit-get-previous-branch))))
(let ((result (delete exclude (magit-list-refnames))))
(if atpoint (cons atpoint result) result)
)
))
(defun magit-get-current-commit-sha-short (rev)
(magit-rev-parse "--short" rev))
(defun magit-comming-message (rev)
(magit-rev-format "%s" rev))
(defun magit-branch-or-commit-at-point-save ()
(let (atpoint (magit-branch-or-commit-at-point))
(if atpoint atpoint "")
))
(defun counsel-magit-checkout ()
"Forward to `describe-function'."
(interactive)
(ivy-read "Switch to branch: "
(magit-list-other-branch-or-commit)
:action 'magit-checkout
:caller 'counsel-magit-checkout))
;; counsel-magit-checkout
(:columns
((ivy-rich-candidate (:width 30))
(magit-get-current-commit-sha-short (:face magit-hash))
(magit-get-upstream-branch-save (:face font-lock-comment-face))
(magit-comming-message (:face font-lock-comment-face))))
(transient-replace-suffix 'magit-branch "b"
'("b" "branch/revision" counsel-magit-checkout))
I see. It seems you must first ivyfy a Magit command first. Although ivy-rich
support something like
(setq ivy-rich-display-transformers-list
(plist-put
ivy-rich-display-transformers-list
'execute-extended-command
'ivy-rich--counsel-M-x-transformer))
where execute-extended-command
use the internal completing-read
in read-extended-command
. But it does not work directly with Magit and I currently have no idea of it due to my limited Elisp.
Sorry for delay. I think I have found a way to define transformers without extra wrappers.
Could you please help with few issues I faced:
- The resulting ivy-rich buffer is quite slow. As far as I understand ivy refreshes all candidates upon each action, including, for example, ivy-next-line, and since git interaction is not completely free, it takes noticeable time (like 0.5 second) to get tag+branch+sha+commit_message for 10 candidates.
And the only way to mitigate this is to cache, right? - Is there any way to use a lisp function or variable as a transformer to avoid code duplication?
For example (which is not working):
(defun my-counsel-M-x-transformer ()
'(:columns
((counsel-M-x-transformer (:width 0.4))
(ivy-rich-counsel-function-docstring (:face font-lock-doc-face))))
(setq ivy-rich-display-transformers-list '(counsel-M-x
(my-counsel-M-x-transformer)
)
Summon @Yevgnen
Hi, I'm not sure if there's a way to speed up. Caching is definitely a possible way to do it. How does your transformer look like?
About the reusing the transformer, you can take a look of this.
magit transformers
(defun magit-get-current-commit-sha-short (rev)
(magit-rev-parse "--short" rev))
(defun magit-commit-message (rev)
(magit-rev-format "%s" rev))
(defun magit-get-branch-and-upstream (rev)
(let ((branch (magit-get-upstream-branch rev)))
(concat (propertize rev 'face 'default) (when branch
(put-text-property 0 (length branch) 'face 'magit-branch-remote-head branch)
(format " %s" branch)))
))
(defun magit-get-current-tag-save (rev)
(let ((tag (magit-git-str "describe" "--tags" "--exact-match" rev)))
(if tag tag "")
))
(setq ivy-rich-display-transformers-list (append ivy-rich-display-transformers-list
'(magit-checkout
(:columns
(
;;(ivy-rich-candidate (:width 30))
(magit-get-branch-and-upstream (:width 0.35))
(magit-get-current-commit-sha-short (:width 11 :face magit-hash))
(magit-get-current-tag-save (:width 10 :face magit-tag))
(magit-commit-message (:width 0.35 :face font-lock-comment-face))
)
)
magit-branch-and-checkout
(:columns
(
;; (ivy-rich-candidate (:width 30))
(magit-get-branch-and-upstream (:width 0.35))
(magit-get-current-commit-sha-short (:width 11 :face magit-hash))
(magit-get-current-tag-save (:width 10 :face magit-tag))
(magit-commit-message (:width 0.35 :face font-lock-comment-face))
)
)
magit-branch-create
(:columns
(
;; (ivy-rich-candidate (:width 30))
(magit-get-branch-and-upstream (:width 0.35))
(magit-get-current-commit-sha-short (:width 11 :face magit-hash))
(magit-get-current-tag-save (:width 10 :face magit-tag))
(magit-commit-message (:width 0.35 :face font-lock-comment-face))
)
)
)
))
(ivy-rich-set-display-transformer)
I use magit-get-branch-and-upstream instead of ivy-rich-candidate to have branch displayed in magit style, like branch[upstream]. In the first version I had a separate column for upstream branch.
Not relevant anymore