Here is my super hacky way to simulate key down/up event binding by taking advantage of timers.
Overall I would suggest going by Sigma's answer, but you asked for a way to close the preview by letting go so I'm obliged to try.
Basically what you can do is bind some function that will be your "keydown" function to a keybinding and inside that action, start an idle timer that that executes a function that is your "keyup" function, as long as you are holding down the given keys, "keydown" function will fire over and over and this will inhibit the idle timers from running. Of course you need to compensate for the fact that the command will fire over and over, likely by rebinding the key to some sort of noop function in your "keydown" function, then rebinding the "keydown" function in the "keyup" function.
So for your use case your "keydown" function will open up a preview buffer with the contents of the file at point and in that preview buffer bind the same key combo to some noop like command. You "keydown" function will also start an idle timer that will delete your preview buffer and restore you back where you were.
Long story short here is the code:
Bind this function to a key combo (I used C-M-v), when you press it down on top of a file name it will open a new buffer displaying the contents of the file at point, when you let go you will be switched back to the original buffer.
(setq lexical-binding t)
(defun quick-view-file-at-point ()
"Preview the file at point then jump back after some idle time.
In order for this to work you need to bind this function to a key combo,
you cannot call it from the minibuffer and let it work.
The reason it works is that by holding the key combo down, you inhibit
idle timers from running so as long as you hold the key combo, the
buffer preview will still display."
(interactive)
(let* ((buffer (current-buffer))
(file (thing-at-point 'filename t))
(file-buffer-name (format "*preview of %s*" file)))
(if (and file (file-exists-p file))
(let ((contents))
(if (get-buffer file)
(setq contents (save-excursion
(with-current-buffer (get-buffer file)
(font-lock-fontify-buffer)
(buffer-substring (point-min) (point-max)))))
(let ((new-buffer (find-file-noselect file)))
(with-current-buffer new-buffer
(font-lock-mode t)
(font-lock-fontify-buffer)
(setq contents (buffer-substring (point-min) (point-max))))
(kill-buffer new-buffer)))
(switch-to-buffer (get-buffer-create file-buffer-name))
(setq-local header-line-format "%60b")
(delete-region (point-min) (point-max))
(save-excursion (insert contents))
(local-set-key (kbd "C-M-v") (lambda () (interactive) (sit-for .2)))
(run-with-idle-timer
.7
nil
(lambda ()
(switch-to-buffer buffer)
(kill-buffer file-buffer-name))))
(message "no file to preview at point!"))))
Also here is a gif of it in action, all I do is:
- place my cursor over the file
- press and hold my keybinding
- the preview is displayed
- when I let go, the preview is killed and you're back where you were.
One important thing to note is the idle timer's seconds, in my code I used .7
but it's kind of a magic number, you want to keep it really small, but if you see the preview flashing twice try raising it 1/10th a second each time until your find the right spot for your machine.
*Also note that in the function I try to do some fontification of the preview buffer but I couldn't get it to work, that'll be the next step in making it more useful.**
dired-display-file
anddired-view-file
(M-RET
andgo
in doomemacs).