pkryger / difftastic.el

Wrapper for difftastic
GNU General Public License v3.0
45 stars 4 forks source link

Adapt for window width change #2

Closed uqix closed 6 months ago

uqix commented 6 months ago

After C-x 1 in difftastic git diff window, the content does not redisplay to adapt for new window width.

pkryger commented 6 months ago

Unfortunately, this is one of the things that kinda fall into "works as designed" category. The difftastic.el merely wraps a call to difft and the latter produces all the output, including colouring and layout. This output is later colourised using user theme and displayed to the user in a window. Hence, when window size changes the content is not re-flown to fit the window.

When a call to difft is made the requested window width is passed (as a value to --width parameter). The value is a result to a call to a function defined in a user customisable variable difftastic-requested-window-width-function. By default, the latter is set to difftastic-requested-window-width, which applies some (rather crude) heuristic to calculate requested width (i.e., it tries to put it into a side window). Perhaps you could set it to something that will yield a width of a window to be displayed standalone in a frame, i.e.,

(defun my/difftastic--requested-window-width-single-window ()
   (- (frame-width) (fringe-columns 'left) (fringe-columns 'right)))

;; example command that uses the above
(defun my/difftastic-magit-diff-single-window ()
  (interactive)
  (let ((difftastic-requested-window-width-function #'my/difftastic--requested-window-width-single-window))
    ;; I think you can also bind `difftastic-display-buffer-function' to a function that will pop the buffer to a single window,
    ;; but will need to make sure that such a binding is respected in an asynchronous callback.
    (call-interactively #'difftastic-magit-diff)))

Your question sparkled an alternative idea. For a while, I have been thinking about adding an option to re-run difft command to a difftastic-mode. But I couldn't really find a good reason to have such a functionality. But now I can see that such a re-reun could read current window width (which is a window in difftastic-mode) and yield the window width. That way after a window resize, one can just press g (like many in many other places) and have the difft to run again with content (hopefully) re-flown to the current window width. It will be a bit slow at times (i.e., all the diffing and rendering would need to happen again), but could be a reasonable idea. Please let me know if you think such a functionality is something you'll find useful.

uqix commented 6 months ago

That way after a window resize, one can just press g (like many in many other places) and have the difft to run again with content (hopefully) re-flown to the current window width.

This is exact what I wish for.

We can also consider ediff way due to the two-sides nature of difftastic:

(setopt ediff-split-window-function #'split-window-horizontally)
(setopt ediff-window-setup-function #'ediff-setup-windows-plain)

(add-hook 'ediff-after-quit-hook-internal #'winner-undo)
uqix commented 6 months ago

As for now, I can use this config:

(defun my/difftastic/requested-window-width ()
  (- (frame-width)
     (fringe-columns 'left)
     (fringe-columns 'right)))

(setopt difftastic-requested-window-width-function
        #'my/difftastic/requested-window-width)

with a manual winner-undo after C-x 1.

Thank you.

pkryger commented 6 months ago

That way after a window resize, one can just press g (like many in many other places) and have the difft to run again with content (hopefully) re-flown to the current window width.

This is exact what I wish for.

I think I'll add such a functionality. Probably with a prompt to user, before rerunning (that may be a lengthy operation). With an option do disable the prompt.

We can also consider ediff way due to the two-sides nature of difftastic:

(setopt ediff-split-window-function #'split-window-horizontally)
(setopt ediff-window-setup-function #'ediff-setup-windows-plain)

(add-hook 'ediff-after-quit-hook-internal #'winner-undo)

This kinda already exists. You can setup your own difftastic-display-buffer-function. However, this is called asynchronously, so I'd probably need to add capture the value of the variable and call the captured one. With that you can just change it for a single invocation. I'd also need to add something along difftastic-after-quit-hook.

As for now, I can use this config:

(defun my/difftastic/requested-window-width ()
  (- (frame-width)
     (fringe-columns 'left)
     (fringe-columns 'right)))

(setopt difftastic-requested-window-width-function
        #'my/difftastic/requested-window-width)

with a manual winner-undo after C-x 1.

Glad this can serve as a workaround.

pkryger commented 6 months ago

That way after a window resize, one can just press g (like many in many other places) and have the difft to run again with content (hopefully) re-flown to the current window width.

This is exact what I wish for.

I think I'll add such a functionality. Probably with a prompt to user, before rerunning (that may be a lengthy operation). With an option do disable the prompt.

@uqix I implemented the difftastic-rerun(bound to g). No prompt yet though. But one have an option to force language when called with prefix. Let me know what you think.