From: Phillip Wood Date: Wed, 23 Nov 2022 14:58:27 GMT Subject: Re: [PATCH v5 3/3] git-jump: invoke emacs/emacsclient Message-ID: In-Reply-To: Hi Yoichi On 23/11/2022 07:04, Yoichi Nakayama via GitGitGadget wrote: > From: Yoichi Nakayama > > It works with GIT_EDITOR="emacs", "emacsclient" or "emacsclient -t" > > Signed-off-by: Yoichi Nakayama > --- > contrib/git-jump/git-jump | 17 ++++++++++++++++- > 1 file changed, 16 insertions(+), 1 deletion(-) > > diff --git a/contrib/git-jump/git-jump b/contrib/git-jump/git-jump > index cc97b0dcf02..316e9628725 100755 > --- a/contrib/git-jump/git-jump > +++ b/contrib/git-jump/git-jump > @@ -23,7 +23,22 @@ EOF > > open_editor() { > editor=`git var GIT_EDITOR` > - eval "$editor -q \$1" > + case "$editor" in > + *emacs*) > + # Supported editor values are: > + # - emacs > + # - emacsclient > + # - emacsclient -t > + # > + # Wait for completion of the asynchronously executed process > + # to avoid race conditions in case of "emacsclient". > + eval "$editor --eval \"(prog1 (pop-to-buffer (compilation-start \\\"cat $@\\\" 'grep-mode)) (while (get-buffer-process (current-buffer)) (sleep-for 0.1)) (select-frame-set-input-focus (selected-frame)))\"" I've just tried this out and it is much nicer than v4, thank you for tweaking it. It is a little sluggish to pop up the emacs window though - are you sure we need the while loop? I've commented it out and it seems to work just fine. The documentation for pop-to-buffer says it selects the frame displaying the buffer so I don't think we need to wait before calling select-frame-set-input-focus (I'm no emacs expert though). I do think it would be better to quote the filename or better still call git-jump from compilation-start as Peff suggested. It would also be nice to stop emacsclient from printing anything in the terminal. It would be nice to be able to run git-jump from within emacs. I came up with the code below which prompts the user for the directory to run git-jump in (which only matters for grep and diff --relative I think) and then checks for modified buffers visiting files in that repository before running git-jump. Best Wishes Phillip ---- >8 ---- (require 'cl-lib) (defun git-jump (dir) "Run 'git jump', prompts for the directory to run in. Also prompts to save modified buffers visiting files in the repository containing DIR" (interactive "DDirectory:") (let* ((dir (expand-file-name dir)) (worktree (git-jump--get-worktree dir))) (unless worktree (error "Not in a git repository")) (git-jump--save-worktree-buffers worktree) ;; Use "cd" rather than "git -C" so emacs can tell which directory ;; the command is being run in. (compilation-start (concat "cd " (shell-quote-argument dir) " && git jump --stdout " (read-string "Jump command: ")) 'grep-mode (lambda (mode) "*git-jump*")))) (defun git-jump--save-worktree-buffers (worktree) "Prompt the user to save all the modified buffers in WORKTREE" (let ((ht (make-hash-table :test 'equal)) (off (length worktree)) (buffers nil)) (dolist (b (buffer-list)) (when (buffer-modified-p b) (let ((file (buffer-file-name b))) (when file (let ((path (file-truename file))) (when (string-prefix-p worktree path) (puthash (substring path off) b ht))))))) (let ((modified (hash-table-keys ht))) (when modified (git-jump--ls-files worktree modified (lambda (path) (push (gethash path ht) buffers))) (when buffers (save-some-buffers nil (lambda () (memq (current-buffer) buffers)))))))) (defun git-jump--get-worktree (dir) "Get the git worktree containing DIR. Returns nil if DIR is not in a repository" (message (concat "dir: " dir)) (let* ((toplevel "") (filter (lambda (_proc text) (setf toplevel (concat toplevel text)))) (proc (make-process :name "rev-parse--toplevel" :buffer nil :coding (or file-name-coding-system default-file-name-coding-system) :command (list "git" "-C" dir "rev-parse" "--show-toplevel") :connection-type 'pipe :filter filter))) (while (or (accept-process-output proc 120) (not (memq (process-status proc) '(exit signal))))) (prog1 (if (and (eq (process-status proc) 'exit) (zerop (process-exit-status proc))) (concat (substring toplevel 0 -1) "/") nil) (delete-process proc)))) (defun git-jump--ls-files (worktree paths func) "Run FUNC on PATHS that are tracked by worktree. NB takes paths not pathspecs" (let* ((remainder "") (filter (lambda (_proc text) (let* ((text (concat remainder text)) (len (length text)) (pos 0)) (while (< pos len) (cond ((= pos (string-match "\\([^\0]+\\)\0" text pos)) (funcall func (match-string 1 text)) (setq pos (match-end 0))) (t (setq remainder (substring text pos)) (setq pos len))))))) (proc (make-process :name "ls-files" :buffer nil :coding (or file-name-coding-system default-file-name-coding-system) :command (cl-list* "git" "-C" worktree "--literal-pathspecs" "ls-files" "-z" "--" paths) :connection-type 'pipe :filter filter))) (while (or (accept-process-output proc 120) (not (memq (process-status proc) '(exit signal))))) (delete-process proc))) (provide 'git-jump)