g
reverts the Dired buffer. It invokes function revert-buffer
, which uses the function bound to variable revert-buffer-function
. In a Dired buffer, that function is dired-revert
.
Following what dired-revert
does (e.g. using debug-on-entry
) you find that it is dired-goto-file
that scrolls the listing, to put the file where the cursor was when you hit g
in the middle of the window vertically. It does this because the last thing it does is call search-forward
, and that function does the recentering.
You can't prevent it from doing that - search-forward
is coded in C, and there's no parameter to modify this part of its behavior (and I don't know of any global variable that will do so).
But you can make the buffer/window scroll, when dired-revert
is done, that is, after search-forward
centers the cursor vertically, to put the cursor's file where you want it in the window. You can do that by advising dired-revert
with an :after
function that scrolls the window the way you want.
The function you want, to scroll the window, is recenter
. Its doc (C-h f recenter
) tells you that you can pass it a numeric arg ARG, to put "putting point on screen line ARG
relative to the selected window." And if ARG
is negative then it does so relative to the bottom of the window. So an ARG
value of -1
puts the line you want at the bottom of the window - which is where I guess you're asking to put it.
;; Function to use at end of `dired-revert'.
(defun foo (_arg _noconfirm)
"Put cursor line at bottom of window."
(recenter -1))
;; Do `foo' at the end of `dired-revert'.
(advice-add 'dired-goto-file :after 'foo)
Of course, maybe you don't always want the current line (where the cursor is) to end up at the bottom of the window. In that case, you'll have to do something else.
You can, for example, find out where in the window, vertically, the cursor is before you hit g
, and then have a function such as foo
recenter to that vertical window position, instead of always using -1
as the arg to recenter
.
I don't think there's a function that gives you the window line, that is, the current line number relative to the window beginning. You can do that this way:
(defun window-line-at-point ()
(let ((bow (save-excursion (move-to-window-line 0) (point))))
(count-screen-lines bow (point))))
And then you can move to that window line using function recenter
.
But you need to use window-line-at-point
at the outset, when dired-revert
is called, so you need to advise that function (with :around
) to get the window line, bind it to a variable, and then call recenter
to move to that window line at the end. This does that:
(defun foo (old-fn _a _b)
(let ((curr-line (window-line-at-point)))
(funcall old-fn)
(recenter (1- curr-line))))
(advice-add 'dired-revert :around 'foo)
(Alternatively, you could define your own revert function, and bind that to revert-function
in Dired buffers, instead of it being bound to dired-revert
.)