Skip to content

Commit

Permalink
[wip] redo dwim to support args
Browse files Browse the repository at this point in the history
  • Loading branch information
Przemyslaw Kryger authored and Przemyslaw Kryger committed Jan 21, 2024
1 parent 546b074 commit f4bb756
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 49 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Description

The `difftastic` is designed to integrate [`difftastic`](https://github.com/wilfred/difftastic) - a structural diff tool - into your Emacs workflow, enhancing your code review and comparison experience. This package automatically displays `difftastic`'s output within Emacs using faces from your user theme, ensuring consistency with your overall coding environment.
The `difftastic` Emacs package is designed to integrate [`difftastic`](https://github.com/wilfred/difftastic) - a structural diff tool - into your Emacs workflow, enhancing your code review and comparison experience. This package automatically displays `difftastic`'s output within Emacs using faces from your user theme, ensuring consistency with your overall coding environment.

## Features

Expand Down Expand Up @@ -56,14 +56,14 @@ Or, if you use `use-package`:
("S" "Difftastic show" difftastic-magit-show)])))
```


## Usage
There are four commands to interact with `difftastic`:
The following commands are meant to help to interact with `difftastic`:

- `difftastic-magit-diff` - show the result of `git diff ARG` with `difftastic`. It tries to guess `ARG`, and ask for it when can't. When called with prefix argument it will ask for `ARG`.
- `difftastic-magit-diff` - show the result of `git diff ARGS -- FILES` with `difftastic`. This is the main entry point for DWIM action, so it tries to guess revision or range.
- `difftastic-magit-show` - show the result of `git show ARG` with `difftastic`. It tries to guess `ARG`, and ask for it when can't. When called with prefix argument it will ask for `ARG`.
- `difftastic-files` - show the result of `difft FILE-A FILE-B`. When called with prefix argument it will ask for language to use, instead of relaying on `difftastic`'s detection mechanism.
- `difftastic-buffers` - show the result of `difft BUFFER-A BUFFER-B`. Language is guessed based on buffers modes. When called with prefix argument it will ask for language to use.
- `difftastic-git-diff-range` - transform `ARGS` for difftastic and show the result of `git diff ARGS REV-OR-RANGE -- FILES` with `difftastic`.

## Customization

Expand Down
152 changes: 107 additions & 45 deletions difftastic.el
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@

;;; Commentary:

;; The difftastic is designed to integrate difftastic - a structural diff tool
;; - (https://github.com/wilfred/difftastic) into your Emacs workflow,
;; enhancing your code review and comparison experience. This package
;; automatically displays difftastic's output within Emacs using faces from
;; your user theme, ensuring consistency with your overall coding environment.
;; The difftastic Emacs package is designed to integrate difftastic - a
;; structural diff tool - (https://github.com/wilfred/difftastic) into your
;; Emacs workflow, enhancing your code review and comparison experience. This
;; package automatically displays difftastic's output within Emacs using faces
;; from your user theme, ensuring consistency with your overall coding
;; environment.
;;
;; Configuration
;;
Expand Down Expand Up @@ -63,11 +64,11 @@
;;
;; Usage
;;
;; There are four commands to interact with difftastic:
;; The following commands are meant to help to interact with difftastic:
;;
;; - `difftastic-magit-diff' - show the result of 'git diff ARG' with
;; difftastic. It tries to guess ARG, and ask for it when can't. When called
;; with prefix argument it will ask for ARG.
;; - `difftastic-magit-diff' - show the result of 'git diff ARGS -- FILES' with
;; difftastic. This is the main entry point for DWIM action, so it tries to
;; guess revision or range.
;;
;; - `difftastic-magit-show' - show the result of 'git show ARG' with
;; difftastic. It tries to guess ARG, and ask for it when can't. When called
Expand All @@ -80,6 +81,9 @@
;; - `difftastic-buffers' - show the result of 'difft BUFFER-A BUFFER-B'.
;; Language is guessed based on buffers modes. When called with prefix
;; argument it will ask for language to use.
;;
;; - `difftastic-git-diff-range' - transform ARGS for difftastic and show the
;; result of 'git diff ARGS REV-OR-RANGE -- FILES' with difftastic.

;;; Code:

Expand Down Expand Up @@ -528,7 +532,7 @@ Utilise `difftastic--ansi-color-add-background-cache' to cache
difftastic--ansi-color-add-background-cache)
face)))

(defun difftastic--magit-with-difftastic (buffer command)
(defun difftastic--git-with-difftastic (buffer command)
"Run COMMAND with GIT_EXTERNAL_DIFF then show result in BUFFER."
(let* ((requested-width (funcall difftastic-requested-window-width-function))
(process-environment
Expand Down Expand Up @@ -599,6 +603,98 @@ perform cleanup."
(message "Process %s returned no output"
(mapconcat #'identity command " "))))))))

(defun difftastic--transform-diff-arguments (args)
"Transform \\='git diff\\=' ARGS to be compatible with difftastic.
I.e., remove --stat and --no-ext-diff."
;; @todo - other args from diff dispatch
(cl-remove-if (lambda (arg)
(member arg '("--stat" "--no-ext-diff")))
args))

;;;###autoload
(defun difftastic-git-diff-range (&optional rev-or-range args files)
"Show difference between two commits using difftastic.
The meaning of REV-OR-RANGE, ARGS, and FILES is like in
`magit-diff-range', but ARGS are adjusted for difftastic with
`difftastic--transform-diff-arguments'."
(interactive (cons (magit-diff-read-range-or-commit "Diff for range"
nil current-prefix-arg)
(magit-diff-arguments)))
(message "***diff-range %s %s %s" rev-or-range args files)
(let* ((args (difftastic--transform-diff-arguments args))
(buffer-name
(concat
"*difftastic git diff"
(if args
(mapconcat #'identity (cons "" args) " ")
"")
(if rev-or-range (concat " " rev-or-range)
"")
(if files
(mapconcat #'identity (cons " --" files) " ")
"")
"*")))
(difftastic--git-with-difftastic
(get-buffer-create buffer-name)
`("git" "--no-pager" "diff" "--ext-diff"
,@(when args args)
,@(when rev-or-range (list rev-or-range))
,@(when files (cons "--" files))))))


;;;###autoload
(defun difftastic-magit-diff (&optional args files)
"Show the result of \\='git diff ARGS -- FILES\\=' with difftastic."
(interactive (magit-diff-arguments))
(let ((default-directory (magit-toplevel))
(section (magit-current-section)))
(cond
((magit-section-match 'module section) ;; @todo - test
(setq default-directory
(expand-file-name
(file-name-as-directory (oref section value))))
(difftastic-git-diff-range (oref section range)))
(t ;; @todo
(when (magit-section-match 'module-commit section)
(setq args nil)
(setq files nil)
(setq default-directory
(expand-file-name
(file-name-as-directory (magit-section-parent-value section)))))
(pcase (magit-diff--dwim)
('unmerged ;;@todo - test
(message "*** unmerged %s %s" args files)
(unless (magit-merge-in-progress-p)
(user-error "No merge is in progress"))
(difftastic-git-diff-range (magit--merge-range) args files))
('unstaged
(message "*** unstaged %s %s" args files) ;; d D on Unstaged
(difftastic-git-diff-range nil args files))
('staged ;;@todo - test
(message "*** staged %s %s" args files)
(let ((file (magit-file-at-point)))
(if (and file (equal (cddr (car (magit-file-status file))) '(?D ?U)))
;; File was deleted by us and modified by them. Show the latter.
(progn
(unless (magit-merge-in-progress-p)
(user-error "No merge is in progress"))
(difftastic-git-diff-range (magit--merge-range) args (list file)))
(difftastic-git-diff-range
nil (cl-pushnew "--cached" args :test #'string=) files))))
(`(stash . ,value)
;; `magit-diff--dwim' evaluates to `commit' when on stash ATM
(message "*** stash %s %s" value args)
(difftastic-git-diff-range (format "%s^..%s" value value) args files))
(`(commit . ,value)
(message "*** commit %s %s %s" value args files) ;; d D on a commit
(difftastic-git-diff-range (format "%s^..%s" value value) args files))
((and range (pred stringp))
(message "*** range %s %s %s" range args files) ;; d D with range of commits
(difftastic-git-diff-range range args files))
(_
(message "*** _") ;; C-c M-g D D in a modified file
(call-interactively #'difftastic-git-diff-range)))))))

;;;###autoload
(defun difftastic-magit-show (rev)
"Show the result of \\='git show REV\\=' with difftastic.
Expand All @@ -614,44 +710,10 @@ When REV couldn't be guessed or called with prefix arg ask for REV."
(magit-read-branch-or-commit "Revision"))))
(if (not rev)
(error "No revision specified")
(difftastic--magit-with-difftastic
(difftastic--git-with-difftastic
(get-buffer-create (concat "*difftastic git show " rev "*"))
(list "git" "--no-pager" "show" "--ext-diff" rev))))

;;;###autoload
(defun difftastic-magit-diff (arg)
"Show the result of \\='git diff ARG\\=' with difftastic.
When ARG couldn't be guessed or called with prefix arg ask for ARG."
(interactive
(list (or
(and current-prefix-arg
(magit-diff-read-range-or-commit "Range/Commit"))
;; Otherwise, auto-guess based on position of point, e.g., in a file
;; or based on the Staged or Unstaged section.
(when-let ((file (magit-file-relative-name)))
(save-buffer)
file)
(pcase (magit-diff--dwim)
('unmerged (error "Unmerged is not yet implemented"))
('unstaged nil)
('staged "--cached")
(`(stash . ,_) (error "Stash is not yet implemented"))
(`(commit . ,value) (format "%s^..%s" value value))
((and range (pred stringp)) range)
(_ (magit-diff-read-range-or-commit "Range/Commit"))))))
(let* ((name (concat "*difftastic git diff"
(if arg (concat " " arg) "")
"*"))
(file (magit-file-relative-name))
(default-directory (if file
(magit-toplevel)
default-directory)))
(difftastic--magit-with-difftastic
(get-buffer-create name)
`("git" "--no-pager" "diff" "--ext-diff"
,@(when file (list "--"))
,@(when arg (list arg))))))

(defun difftastic---make-temp-file (prefix buffer)
"Make a temp file for BUFFER content that with PREFIX included in file name."
;; adapted from `make-auto-save-file-name'
Expand Down

0 comments on commit f4bb756

Please sign in to comment.