From 12982abd0e72013bd302efa009f323b8f0b9be27 Mon Sep 17 00:00:00 2001 From: TEC Date: Fri, 22 Jul 2022 21:56:22 +0800 Subject: [PATCH] Revisit VLF setup --- config.org | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/config.org b/config.org index 169a19a..cd1bc4b 100644 --- a/config.org +++ b/config.org @@ -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 + <> + :config + (advice-remove 'abort-if-file-too-large #'ad-Advice-abort-if-file-too-large) + <> + ) #+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