Revisit VLF setup

This commit is contained in:
TEC 2022-07-22 21:56:22 +08:00
parent c10537ac54
commit 12982abd0e
Signed by: tec
GPG Key ID: 779591AFDB81F06C
1 changed files with 105 additions and 4 deletions

View File

@ -1746,17 +1746,118 @@ have the following.
The /very large files/ mode loads large files in chunks, allowing one to open
ridiculously large files.
#+begin_src emacs-lisp :tangle packages.el
(package! vlf :recipe (:host github :repo "m00natic/vlfi" :files ("*.el"))
:pin "cc02f2533782d6b9b628cec7e2dcf25b2d05a27c" :disable t)
(package! vlf :recipe (:host github :repo "emacs-straight/vlf" :files ("*.el"))
:pin "cacdb359f8c37c6e7e4c7937462b632d22462130")
#+end_src
To make VLF available without delaying startup, we'll just load it in quiet moments.
#+begin_src emacs-lisp
#+begin_src emacs-lisp :noweb no-export
(use-package! vlf-setup
:defer-incrementally vlf-tune vlf-base vlf-write vlf-search vlf-occur vlf-follow vlf-ediff vlf)
:defer-incrementally vlf-tune vlf-base vlf-write
vlf-search vlf-occur vlf-follow vlf-ediff vlf
:commands vlf vlf-mode
:init
<<vlf-largefile-prompt>>
:config
(advice-remove 'abort-if-file-too-large #'ad-Advice-abort-if-file-too-large)
<<vlf-linenum-offset>>
)
#+end_src
Now, there are one or two tweaks worth applying to VLF. For starters, it goes to
the liberty of advising ~abort-if-file-too-large~, and in doing so removes the
option of opening files literally. I think that's a bit much, so we can remove
the advice and instead override ~files--ask-user-about-large-file~ (the more
appropriate function, I think) as a simpler approach, just sacrificing the
original behaviour with src_elisp{(setq vlf-application 'always)} (which I can't
imagine using anyway).
#+name: vlf-largefile-prompt
#+begin_src emacs-lisp :tangle no
(defadvice! +files--ask-about-large-file-vlf (size op-type filename offer-raw)
"Like `files--ask-user-about-large-file', but with support for `vlf'."
:override #'files--ask-user-about-large-file
(if (eq vlf-application 'dont-ask)
(progn (vlf filename) (error ""))
(let ((prompt (format "File %s is large (%s), really %s?"
(file-name-nondirectory filename)
(funcall byte-count-to-string-function size) op-type)))
(if (not offer-raw)
(if (y-or-n-p prompt) nil 'abort)
(let ((choice
(car
(read-multiple-choice
prompt '((?y "yes")
(?n "no")
(?l "literally")
(?v "vlf"))
(files--ask-user-about-large-file-help-text
op-type (funcall byte-count-to-string-function size))))))
(cond ((eq choice ?y) nil)
((eq choice ?l) 'raw)
((eq choice ?v)
(vlf filename)
(error ""))
(t 'abort)))))))
#+end_src
As you go from one chunk fetched by VLF to the next, the displayed line number
of the first line /in each chunk/ is unchanged. I think it's reasonable to hope
for an /overall/ line number, and by tracking chunk's cumulative line numbers we
can implement this behaviour fairly easily.
#+name: vlf-linenum-offset
#+begin_src emacs-lisp :tangle no
(defvar-local +vlf-cumulative-linenum '((0 . 0))
"An alist keeping track of the cumulative line number.")
(defun +vlf-update-linum ()
"Update the line number offset."
(let ((linenum-offset (alist-get vlf-start-pos +vlf-cumulative-linenum)))
(setq display-line-numbers-offset (or linenum-offset 0))
(when (and linenum-offset (not (assq vlf-end-pos +vlf-cumulative-linenum)))
(push (cons vlf-end-pos (+ linenum-offset
(count-lines (point-min) (point-max))))
+vlf-cumulative-linenum))))
(add-hook 'vlf-after-chunk-update-hook #'+vlf-log-poses-a)
;; Since this only works with absolute line numbers, let's make sure we use them.
(add-hook! 'vlf-mode-hook (setq-local display-line-numbers t))
#+end_src
The other thing that doesn't work too well with VLF is searching with anything
other than =M-x occur=. This is because trying to go to the next match at the end
of a chunk usually wraps the point to the beginning of the chunk, instead of
moving to the next chunk.
#+begin_src emacs-lisp :tangle no
(defun +vlf-next-chunk-or-start ()
(if (= vlf-file-size vlf-end-pos)
(vlf-jump-to-chunk 1)
(vlf-next-batch 1))
(goto-char (point-min)))
(defun +vlf-last-chunk-or-end ()
(if (= 0 vlf-start-pos)
(vlf-end-of-file)
(vlf-prev-batch 1))
(goto-char (point-max)))
(defun +vlf-isearch-wrap ()
(if isearch-forward
(+vlf-next-chunk-or-start)
(+vlf-last-chunk-or-end)))
(add-hook! 'vlf-mode-hook (setq-local isearch-wrap-function #'+vlf-isearch-wrap))
#+end_src
Unfortunately, since evil-search doesn't have an analogue to
~isearch-wrap-function~, we can't easily add support to it.
*** Eros
#+begin_quote