m00natic pushed a commit to branch master in repository elpa. commit bdea86718db09678b8f16b2756ef458c544daaef Author: Andrey Kotlarski <m00nati...@gmail.com> Date: Sat Sep 20 18:41:06 2014 +0300
* packages/vlf: Perform search, occur and ediff operations over hexl content instead over raw data when hexl-mode is active. Allow vlf-occur results be saved to file and later reused. * vlf.el (vlf): Use minimal batch size on remote files or if manually specified. Remove hooks used to disable/enable hexl-mode. * vlf-integrate.el (abort-if-file-too-large): Don't use vlf-mode if file size is less than default batch size. * vlf-base.el (vlf-batch-size): Increase default batch size. (vlf-move-to-chunk-1, vlf-move-to-chunk-2): Restore hexl-mode if has been active on start. * vlf-write.el (vlf-write): Restore hexl-mode if active on start and don't ask spurious questions. * vlf-search.el (vlf-re-search): Search over hexl content in case hexl-mode is active on start. (vlf-goto-line): Don't optimize search in case hexl-mode is active. * vlf-ediff.el (vlf-ediff-files): Use minimal batch size before applying specified. (vlf-ediff-next): Ediff over hexl-mode content when active instead over raw data. * vlf-occur.el (vlf-occur-vlf-file, vlf-occur-vlf-buffer) (vlf-occur-regexp, vlf-occur-hexl, vlf-occur-lines): New variables. (vlf-occur-mode-map): Add save binding. (vlf-occur-mode): Hook custom save function. (vlf-occur-next-match, vlf-occur-prev-match): Use get-text-property instead of get-char-property. (vlf-occur-visit): Activate hexl-mode if it has been used during occur. (vlf-occur, vlf-build-occur): Perform occur over hexl content if hexl-mode is active on start. (vlf-occur-save, vlf-occur-load): New commands. --- packages/vlf/vlf-base.el | 204 +++++++++++++++++++++---------------- packages/vlf/vlf-ediff.el | 23 +++-- packages/vlf/vlf-integrate.el | 7 +- packages/vlf/vlf-occur.el | 229 +++++++++++++++++++++++++++++++++-------- packages/vlf/vlf-search.el | 86 +++++++++------- packages/vlf/vlf-write.el | 66 +++++++------ packages/vlf/vlf.el | 35 ++---- 7 files changed, 416 insertions(+), 234 deletions(-) diff --git a/packages/vlf/vlf-base.el b/packages/vlf/vlf-base.el index 98b6831..30e9b27 100644 --- a/packages/vlf/vlf-base.el +++ b/packages/vlf/vlf-base.el @@ -27,8 +27,8 @@ ;;; Code: -(defcustom vlf-batch-size 1024 - "Defines how large each batch of file data is (in bytes)." +(defcustom vlf-batch-size 1000000 + "Defines how large each batch of file data initially is (in bytes)." :group 'vlf :type 'integer) (put 'vlf-batch-size 'permanent-local t) @@ -108,8 +108,7 @@ bytes added to the end." 0))) (setq vlf-start-pos place vlf-end-pos place) - (if (not minimal) - (vlf-update-buffer-name)) + (or minimal (vlf-update-buffer-name)) (cons (- start place) (- place end))))) ((or (/= start vlf-start-pos) (/= end vlf-end-pos)) @@ -126,85 +125,113 @@ bytes added to the end." (let* ((modified (buffer-modified-p)) (start (max 0 start)) (end (min end vlf-file-size)) + (hexl (derived-mode-p 'hexl-mode)) + restore-hexl hexl-undo-list (edit-end (if modified - (+ vlf-start-pos - (length (encode-coding-region - (point-min) (point-max) - buffer-file-coding-system t))) - vlf-end-pos))) - (cond - ((or (< edit-end start) (< end vlf-start-pos) - (not (verify-visited-file-modtime (current-buffer)))) - (when (or (not modified) - (y-or-n-p "Chunk modified, are you sure? ")) ;full chunk renewal - (set-buffer-modified-p nil) - (vlf-move-to-chunk-2 start end))) - ((and (= start vlf-start-pos) (= end edit-end)) - (or modified (vlf-move-to-chunk-2 start end))) - ((or (and (<= start vlf-start-pos) (<= edit-end end)) - (not modified) - (y-or-n-p "Chunk modified, are you sure? ")) - (run-hooks 'vlf-before-chunk-update) - (let ((shift-start 0) - (shift-end 0)) - (let ((pos (+ (position-bytes (point)) vlf-start-pos)) - (inhibit-read-only t)) - (cond ((= end vlf-start-pos) - (or (eq buffer-undo-list t) - (setq buffer-undo-list nil)) - (vlf-with-undo-disabled (erase-buffer)) - (setq modified nil)) - ((< end edit-end) - (setq end (car (vlf-delete-region - (point-min) vlf-start-pos edit-end - end (min (or (byte-to-position - (- end vlf-start-pos)) - (point-min)) - (point-max)) - nil)))) - ((< edit-end end) - (vlf-with-undo-disabled - (setq shift-end (cdr (vlf-insert-file-contents - vlf-end-pos end nil t - (point-max))))))) - (setq vlf-end-pos (+ end shift-end)) - (cond ((= start edit-end) - (or (eq buffer-undo-list t) - (setq buffer-undo-list nil)) - (vlf-with-undo-disabled - (delete-region (point-min) (point))) - (setq modified nil)) - ((< vlf-start-pos start) - (let ((del-info (vlf-delete-region - (point-min) vlf-start-pos - vlf-end-pos start - (min (or (byte-to-position - (- start vlf-start-pos)) - (point)) - (point-max)) t))) - (setq start (car del-info)) - (vlf-shift-undo-list (- (point-min) - (cdr del-info))))) - ((< start vlf-start-pos) - (let ((edit-end-pos (point-max))) - (vlf-with-undo-disabled - (setq shift-start (car (vlf-insert-file-contents - start vlf-start-pos t nil - edit-end-pos))) - (goto-char (point-min)) - (insert (delete-and-extract-region - edit-end-pos (point-max)))) - (vlf-shift-undo-list (- (point-max) - edit-end-pos))))) - (setq start (- start shift-start)) - (goto-char (or (byte-to-position (- pos start)) - (byte-to-position (- pos vlf-start-pos)) - (point-max))) - (setq vlf-start-pos start)) - (set-buffer-modified-p modified) - (set-visited-file-modtime) - (run-hooks 'vlf-after-chunk-update) - (cons shift-start shift-end)))))) + (progn + (when hexl + (setq restore-hexl t + hexl-undo-list buffer-undo-list + buffer-undo-list t) + (hexl-mode-exit)) + (+ vlf-start-pos + (length (encode-coding-region + (point-min) (point-max) + buffer-file-coding-system t)))) + vlf-end-pos)) + (shifts + (cond + ((or (< edit-end start) (< end vlf-start-pos) + (not (verify-visited-file-modtime (current-buffer)))) + (when (or (not modified) + (y-or-n-p "Chunk modified, are you sure? ")) ;full chunk renewal + (set-buffer-modified-p nil) + (if (consp hexl-undo-list) + (setq hexl-undo-list nil)) + (vlf-move-to-chunk-2 start end))) + ((and (= start vlf-start-pos) (= end edit-end)) + (unless modified + (if (consp hexl-undo-list) + (setq hexl-undo-list nil)) + (vlf-move-to-chunk-2 start end))) + ((or (and (<= start vlf-start-pos) (<= edit-end end)) + (not modified) + (y-or-n-p "Chunk modified, are you sure? ")) + (run-hooks 'vlf-before-chunk-update) + (when (and hexl (not restore-hexl)) + (if (consp buffer-undo-list) + (setq buffer-undo-list nil)) + (hexl-mode-exit)) + (let ((shift-start 0) + (shift-end 0)) + (let ((pos (+ (position-bytes (point)) vlf-start-pos)) + (inhibit-read-only t)) + (cond ((= end vlf-start-pos) + (or (eq buffer-undo-list t) + (setq buffer-undo-list nil)) + (vlf-with-undo-disabled (erase-buffer)) + (setq modified nil)) + ((< end edit-end) + (setq end (car (vlf-delete-region + (point-min) vlf-start-pos + edit-end end + (min (or (byte-to-position + (- end vlf-start-pos)) + (point-min)) + (point-max)) + nil)))) + ((< edit-end end) + (vlf-with-undo-disabled + (setq shift-end (cdr (vlf-insert-file-contents + vlf-end-pos end nil t + (point-max))))))) + (setq vlf-end-pos (+ end shift-end)) + (cond ((= start edit-end) + (or (eq buffer-undo-list t) + (setq buffer-undo-list nil)) + (vlf-with-undo-disabled + (delete-region (point-min) (point))) + (setq modified nil)) + ((< vlf-start-pos start) + (let ((del-info (vlf-delete-region + (point-min) vlf-start-pos + vlf-end-pos start + (min (or + (byte-to-position + (- start vlf-start-pos)) + (point)) + (point-max)) t))) + (setq start (car del-info)) + (vlf-shift-undo-list (- (point-min) + (cdr del-info))))) + ((< start vlf-start-pos) + (let ((edit-end-pos (point-max))) + (vlf-with-undo-disabled + (setq shift-start (car + (vlf-insert-file-contents + start vlf-start-pos t nil + edit-end-pos))) + (goto-char (point-min)) + (insert (delete-and-extract-region + edit-end-pos (point-max)))) + (vlf-shift-undo-list (- (point-max) + edit-end-pos))))) + (setq start (- start shift-start)) + (goto-char (or (byte-to-position (- pos start)) + (byte-to-position (- pos vlf-start-pos)) + (point-max))) + (setq vlf-start-pos start)) + (set-buffer-modified-p modified) + (set-visited-file-modtime) + (when hexl + (hexl-mode) + (setq restore-hexl nil)) + (run-hooks 'vlf-after-chunk-update) + (cons shift-start shift-end)))))) + (when restore-hexl + (hexl-mode) + (setq buffer-undo-list hexl-undo-list)) + shifts)) (defun vlf-move-to-chunk-2 (start end) "Unconditionally move to chunk enclosed by START END bytes. @@ -218,11 +245,14 @@ bytes added to the end." (let ((inhibit-read-only t) (pos (position-bytes (point)))) (vlf-with-undo-disabled - (erase-buffer) - (setq shifts (vlf-insert-file-contents vlf-start-pos - vlf-end-pos t t) - vlf-start-pos (- vlf-start-pos (car shifts)) - vlf-end-pos (+ vlf-end-pos (cdr shifts))) + (let ((hexl (derived-mode-p 'hexl-mode))) + (if hexl (hexl-mode-exit t)) + (erase-buffer) + (setq shifts (vlf-insert-file-contents vlf-start-pos + vlf-end-pos t t) + vlf-start-pos (- vlf-start-pos (car shifts)) + vlf-end-pos (+ vlf-end-pos (cdr shifts))) + (if hexl (hexl-mode))) (goto-char (or (byte-to-position (+ pos (car shifts))) (point-max))))) (set-buffer-modified-p nil) diff --git a/packages/vlf/vlf-ediff.el b/packages/vlf/vlf-ediff.el index 2b7c63f..ef9d5c7 100644 --- a/packages/vlf/vlf-ediff.el +++ b/packages/vlf/vlf-ediff.el @@ -34,7 +34,6 @@ "If non nil, specifies that ediff is done over VLF buffers.") (make-variable-buffer-local 'vlf-ediff-session) -;;;###autoload (defun vlf-ediff-buffers (buffer-A buffer-B) "Run batch by batch ediff over VLF buffers BUFFER-A and BUFFER-B. Batch size is determined by the size in BUFFER-A. @@ -93,10 +92,10 @@ respectively of difference list, runs ediff over the adjacent chunks." dir-B))) (ediff-get-default-file-name f 1))) (read-number "Batch size (in bytes): " vlf-batch-size)))) - (let ((buffer-A (vlf file-A))) + (let ((buffer-A (vlf file-A t))) (set-buffer buffer-A) (vlf-set-batch-size batch-size) - (let ((buffer-B (vlf file-B))) + (let ((buffer-B (vlf file-B t))) (vlf-ediff-buffers buffer-A buffer-B)))) (defadvice ediff-next-difference (around vlf-ediff-next-difference @@ -161,12 +160,14 @@ logical chunks in case there is no difference at the current ones." (point-max-A (point-max)) (font-lock-A font-lock-mode) (min-file-size vlf-file-size) - (forward-p (eq next-func 'vlf-next-chunk))) + (forward-p (eq next-func 'vlf-next-chunk)) + (is-hexl (derived-mode-p 'hexl-mode))) (font-lock-mode 0) (set-buffer buffer-B) (run-hook-with-args 'vlf-before-batch-functions 'ediff) (setq buffer-B (current-buffer) - min-file-size (min min-file-size vlf-file-size)) + min-file-size (min min-file-size vlf-file-size) + is-hexl (or is-hexl (derived-mode-p 'hexl-mode))) (let ((tramp-verbose (if (boundp 'tramp-verbose) (min tramp-verbose 2))) (end-B (= vlf-start-pos vlf-end-pos)) @@ -187,7 +188,7 @@ logical chunks in case there is no difference at the current ones." buffer-B (point-min) (point-max))) (with-current-buffer ediff-buffer (ediff-update-diffs) - (and (not end-A) (not end-B) + (and (not end-A) (not end-B) (not is-hexl) (vlf-ediff-refine buffer-A buffer-B)) (zerop ediff-number-of-differences)))) @@ -221,9 +222,10 @@ logical chunks in case there is no difference at the current ones." (vlf-beginning-of-file)) (set-buffer ediff-buffer) (ediff-update-diffs) - (if (or (not forward-p) - (and (not end-A) (not end-B))) - (vlf-ediff-refine buffer-A buffer-B))) + (or is-hexl + (if (or (not forward-p) + (and (not end-A) (not end-B))) + (vlf-ediff-refine buffer-A buffer-B)))) (setq done t)) (unless done (set-buffer buffer-A) @@ -234,7 +236,8 @@ logical chunks in case there is no difference at the current ones." (vlf-move-to-chunk (car chunk-B) (cdr chunk-B)) (set-buffer ediff-buffer) (ediff-update-diffs) - (vlf-ediff-refine buffer-A buffer-B)) + (or is-hexl + (vlf-ediff-refine buffer-A buffer-B))) (set-buffer buffer-A) (if font-lock-A (font-lock-mode 1)) (run-hook-with-args 'vlf-after-batch-functions 'ediff) diff --git a/packages/vlf/vlf-integrate.el b/packages/vlf/vlf-integrate.el index 435ac45..7bc8f94 100644 --- a/packages/vlf/vlf-integrate.el +++ b/packages/vlf/vlf-integrate.el @@ -29,6 +29,10 @@ (defgroup vlf nil "View Large Files in Emacs." :prefix "vlf-" :group 'files) +(defcustom vlf-batch-size 1000000 + "Defines how large each batch of file data initially is (in bytes)." + :group 'vlf :type 'integer) + (defcustom vlf-application 'ask "Determines when `vlf' will be offered on opening files. Possible values are: nil to never use it; @@ -98,7 +102,8 @@ OP-TYPE specifies the file operation being performed over FILENAME." (vlf filename) (error "")) ((and large-file-warning-threshold - (< large-file-warning-threshold size)) + (< large-file-warning-threshold size) + (< vlf-batch-size size)) (if (eq vlf-application 'dont-ask) (progn (vlf filename) (error "")) diff --git a/packages/vlf/vlf-occur.el b/packages/vlf/vlf-occur.el index cea885e..2dac4a4 100644 --- a/packages/vlf/vlf-occur.el +++ b/packages/vlf/vlf-occur.el @@ -29,6 +29,21 @@ (require 'vlf) +(defvar vlf-occur-vlf-file nil "VLF file that is searched.") +(make-variable-buffer-local 'vlf-occur-vlf-file) + +(defvar vlf-occur-vlf-buffer nil "VLF buffer that is scanned.") +(make-variable-buffer-local 'vlf-occur-vlf-buffer) + +(defvar vlf-occur-regexp) +(make-variable-buffer-local 'vlf-occur-regexp) + +(defvar vlf-occur-hexl nil "Is `hexl-mode' active?") +(make-variable-buffer-local 'vlf-occur-hexl) + +(defvar vlf-occur-lines 0 "Number of lines scanned by `vlf-occur'.") +(make-variable-buffer-local 'vlf-occur-lines) + (defvar vlf-occur-mode-map (let ((map (make-sparse-keymap))) (define-key map "n" 'vlf-occur-next-match) @@ -37,16 +52,18 @@ (define-key map "\M-\r" 'vlf-occur-visit-new-buffer) (define-key map [mouse-1] 'vlf-occur-visit) (define-key map "o" 'vlf-occur-show) + (define-key map [remap save-buffer] 'vlf-occur-save) map) "Keymap for command `vlf-occur-mode'.") (define-derived-mode vlf-occur-mode special-mode "VLF[occur]" - "Major mode for showing occur matches of VLF opened files.") + "Major mode for showing occur matches of VLF opened files." + (add-hook 'write-file-functions 'vlf-occur-save nil t)) (defun vlf-occur-next-match () "Move cursor to next match." (interactive) - (if (eq (get-char-property (point) 'face) 'match) + (if (eq (get-text-property (point) 'face) 'match) (goto-char (next-single-property-change (point) 'face))) (goto-char (or (text-property-any (point) (point-max) 'face 'match) (text-property-any (point-min) (point) @@ -55,9 +72,9 @@ (defun vlf-occur-prev-match () "Move cursor to previous match." (interactive) - (if (eq (get-char-property (point) 'face) 'match) + (if (eq (get-text-property (point) 'face) 'match) (goto-char (previous-single-property-change (point) 'face))) - (while (not (eq (get-char-property (point) 'face) 'match)) + (while (not (eq (get-text-property (point) 'face) 'match)) (goto-char (or (previous-single-property-change (point) 'face) (point-max))))) @@ -91,26 +108,38 @@ EVENT may hold details of the invocation." (goto-char (posn-point (event-end event)))) (let* ((pos (point)) (pos-relative (- pos (line-beginning-position) 1)) - (file (get-char-property pos 'file))) - (if file - (let ((chunk-start (get-char-property pos 'chunk-start)) - (chunk-end (get-char-property pos 'chunk-end)) - (vlf-buffer (get-char-property pos 'buffer)) + (chunk-start (get-text-property pos 'chunk-start))) + (if chunk-start + (let ((chunk-end (get-text-property pos 'chunk-end)) + (file (if (file-exists-p vlf-occur-vlf-file) + vlf-occur-vlf-file + (setq vlf-occur-vlf-file + (read-file-name + (concat vlf-occur-vlf-file + " doesn't exist, locate it: "))))) + (vlf-buffer vlf-occur-vlf-buffer) + (not-hexl (not vlf-occur-hexl)) (occur-buffer (current-buffer)) - (match-pos (+ (get-char-property pos 'line-pos) + (match-pos (+ (get-text-property pos 'line-pos) pos-relative))) (cond (current-prefix-arg - (setq vlf-buffer (vlf file)) + (setq vlf-buffer (vlf file t)) + (or not-hexl (hexl-mode)) (switch-to-buffer occur-buffer)) ((not (buffer-live-p vlf-buffer)) - (or (catch 'found - (dolist (buf (buffer-list)) - (set-buffer buf) - (and vlf-mode (equal file buffer-file-name) - (setq vlf-buffer buf) - (throw 'found t)))) - (setq vlf-buffer (vlf file))) - (switch-to-buffer occur-buffer))) + (unless (catch 'found + (dolist (buf (buffer-list)) + (set-buffer buf) + (and vlf-mode + (equal file buffer-file-name) + (eq (not (derived-mode-p 'hexl-mode)) + not-hexl) + (setq vlf-buffer buf) + (throw 'found t)))) + (setq vlf-buffer (vlf file t)) + (or not-hexl (hexl-mode))) + (switch-to-buffer occur-buffer) + (setq vlf-occur-vlf-buffer vlf-buffer))) (pop-to-buffer vlf-buffer) (vlf-move-to-chunk chunk-start chunk-end) (goto-char match-pos))))) @@ -124,14 +153,19 @@ Prematurely ending indexing will still show what's found so far." (if (buffer-modified-p) ;use temporary buffer not to interfere with modifications (let ((vlf-buffer (current-buffer)) (file buffer-file-name) - (batch-size vlf-batch-size)) + (batch-size vlf-batch-size) + (is-hexl (derived-mode-p 'hexl-mode))) (with-temp-buffer - (setq buffer-file-name file) + (setq buffer-file-name file + buffer-file-truename file + buffer-undo-list t) (set-buffer-modified-p nil) (set (make-local-variable 'vlf-batch-size) batch-size) (vlf-mode 1) - (goto-char (point-min)) + (if is-hexl + (hexl-mode)) (run-hook-with-args 'vlf-before-batch-functions 'occur) + (goto-char (point-min)) (vlf-with-undo-disabled (vlf-build-occur regexp vlf-buffer)) (run-hook-with-args 'vlf-after-batch-functions 'occur))) @@ -155,7 +189,6 @@ Prematurely ending indexing will still show what's found so far." (line 1) (last-match-line 0) (last-line-pos (point-min)) - (file buffer-file-name) (total-matches 0) (match-end-pos (+ vlf-start-pos (position-bytes (point)))) (occur-buffer (generate-new-buffer @@ -165,10 +198,13 @@ Prematurely ending indexing will still show what's found so far." (line-regexp (concat "\\(?5:[\n\C-m]\\)\\|\\(?10:" regexp "\\)")) (batch-step (/ vlf-batch-size 8)) + (is-hexl (derived-mode-p 'hexl-mode)) (end-of-file nil) (reporter (make-progress-reporter (concat "Building index for " regexp "...") vlf-start-pos vlf-file-size))) + (with-current-buffer occur-buffer + (setq buffer-undo-list t)) (unwind-protect (progn (while (not end-of-file) @@ -197,8 +233,6 @@ Prematurely ending indexing will still show what's found so far." (number-to-string line) 'face 'shadow))) (insert (propertize line-text ; insert line - 'file file - 'buffer vlf-buffer 'chunk-start chunk-start 'chunk-end chunk-end 'mouse-face '(highlight) @@ -222,35 +256,142 @@ Prematurely ending indexing will still show what's found so far." (setq end-of-file (= vlf-end-pos vlf-file-size)) (unless end-of-file (let ((batch-move (- vlf-end-pos batch-step))) - (vlf-move-to-batch (if (< batch-move match-end-pos) - match-end-pos - batch-move) t)) - (goto-char (if (< vlf-start-pos match-end-pos) - (or (byte-to-position (- match-end-pos - vlf-start-pos)) - (point-min)) - (point-min))) + (vlf-move-to-batch (if (or is-hexl + (< match-end-pos + batch-move)) + batch-move + match-end-pos) t)) + (goto-char (if (or is-hexl + (<= match-end-pos vlf-start-pos)) + (point-min) + (or (byte-to-position (- match-end-pos + vlf-start-pos)) + (point-min)))) (setq last-match-line 0 last-line-pos (line-beginning-position)) (progress-reporter-update reporter vlf-end-pos)))) (progress-reporter-done reporter)) (set-buffer-modified-p nil) (if (zerop total-matches) - (progn (with-current-buffer occur-buffer - (set-buffer-modified-p nil)) - (kill-buffer occur-buffer) + (progn (kill-buffer occur-buffer) (message "No matches for \"%s\"" regexp)) - (with-current-buffer occur-buffer - (goto-char (point-min)) - (insert (propertize - (format "%d matches in %d lines for \"%s\" \ + (let ((file buffer-file-name) + (dir default-directory)) + (with-current-buffer occur-buffer + (goto-char (point-min)) + (insert (propertize + (format "%d matches from %d lines for \"%s\" \ in file: %s" total-matches line regexp file) - 'face 'underline)) - (set-buffer-modified-p nil) - (forward-char 2) - (vlf-occur-mode)) + 'face 'underline)) + (set-buffer-modified-p nil) + (forward-char 2) + (vlf-occur-mode) + (setq default-directory dir + vlf-occur-vlf-file file + vlf-occur-vlf-buffer vlf-buffer + vlf-occur-regexp regexp + vlf-occur-hexl is-hexl + vlf-occur-lines line))) (display-buffer occur-buffer))))) + +;; save, load vlf-occur data + +(defun vlf-occur-save (file) + "Serialize `vlf-occur' results to FILE which can later be reloaded." + (interactive (list (or buffer-file-name + (read-file-name "Save vlf-occur results in: " + nil nil nil + (concat + (file-name-nondirectory + vlf-occur-vlf-file) + ".vlfo"))))) + (setq buffer-file-name file) + (let ((vlf-occur-save-buffer + (generate-new-buffer (concat "*VLF-occur-save " + (file-name-nondirectory file) + "*")))) + (with-current-buffer vlf-occur-save-buffer + (setq buffer-file-name file + buffer-undo-list t) + (insert ";; -*- eval: (vlf-occur-load) -*-\n")) + (prin1 (list vlf-occur-vlf-file vlf-occur-regexp vlf-occur-hexl + vlf-occur-lines) + vlf-occur-save-buffer) + (save-excursion + (goto-char (point-min)) + (while (zerop (forward-line)) + (let* ((pos (1+ (point))) + (line (get-char-property (1- pos) 'before-string))) + (if line + (prin1 (list (string-to-number line) + (get-text-property pos 'chunk-start) + (get-text-property pos 'chunk-end) + (get-text-property pos 'line-pos) + (buffer-substring-no-properties + pos (line-end-position))) + vlf-occur-save-buffer))))) + (with-current-buffer vlf-occur-save-buffer + (save-buffer)) + (kill-buffer vlf-occur-save-buffer)) + t) + +;;;###autoload +(defun vlf-occur-load () + "Load serialized `vlf-occur' results from current buffer." + (interactive) + (goto-char (point-min)) + (let* ((vlf-occur-data-buffer (current-buffer)) + (header (read vlf-occur-data-buffer)) + (vlf-file (nth 0 header)) + (regexp (nth 1 header)) + (all-lines (nth 3 header)) + (file buffer-file-name) + (vlf-occur-buffer + (generate-new-buffer (concat "*VLF-occur " + (file-name-nondirectory file) + "*")))) + (switch-to-buffer vlf-occur-buffer) + (setq buffer-file-name file + buffer-undo-list t) + (goto-char (point-min)) + (let ((match-count 0) + (form 0)) + (while (setq form (ignore-errors (read vlf-occur-data-buffer))) + (goto-char (point-max)) + (insert "\n:") + (let* ((overlay-pos (1- (point))) + (overlay (make-overlay overlay-pos (1+ overlay-pos))) + (line (number-to-string (nth 0 form))) + (pos (point))) + (overlay-put overlay 'before-string + (propertize line 'face 'shadow)) + (insert (propertize (nth 4 form) 'chunk-start (nth 1 form) + 'chunk-end (nth 2 form) + 'mouse-face '(highlight) + 'line-pos (nth 3 form) + 'help-echo (concat "Move to line " + line))) + (goto-char pos) + (while (re-search-forward regexp nil t) + (add-text-properties + (match-beginning 0) (match-end 0) + (list 'face 'match 'help-echo + (format "Move to match %d" + (setq match-count (1+ match-count)))))))) + (kill-buffer vlf-occur-data-buffer) + (goto-char (point-min)) + (insert (propertize + (format "%d matches from %d lines for \"%s\" in file: %s" + match-count all-lines regexp vlf-file) + 'face 'underline))) + (set-buffer-modified-p nil) + (vlf-occur-mode) + (setq vlf-occur-vlf-file vlf-file + vlf-occur-regexp regexp + vlf-occur-hexl (nth 2 header) + vlf-occur-lines all-lines))) + (provide 'vlf-occur) ;;; vlf-occur.el ends here diff --git a/packages/vlf/vlf-search.el b/packages/vlf/vlf-search.el index 0462cb2..3b81d57 100644 --- a/packages/vlf/vlf-search.el +++ b/packages/vlf/vlf-search.el @@ -43,6 +43,7 @@ BATCH-STEP is amount of overlap between successive chunks." (match-start-pos (+ vlf-start-pos (position-bytes (point)))) (match-end-pos match-start-pos) (to-find count) + (is-hexl (derived-mode-p 'hexl-mode)) (font-lock font-lock-mode) (reporter (make-progress-reporter (concat "Searching for " regexp "...") @@ -72,16 +73,18 @@ BATCH-STEP is amount of overlap between successive chunks." (- vlf-batch-size batch-step)))) (vlf-move-to-batch - (if (< match-start-pos batch-move) - (- match-start-pos vlf-batch-size) - batch-move) t)) - (goto-char (if (< match-start-pos - vlf-end-pos) - (or (byte-to-position + (if (or is-hexl + (<= batch-move match-start-pos)) + batch-move + (- match-start-pos vlf-batch-size)) t)) + (goto-char (if (or is-hexl + (<= vlf-end-pos + match-start-pos)) + (point-max) + (or (byte-to-position (- match-start-pos vlf-start-pos)) - (point-max)) - (point-max))) + (point-max)))) (progress-reporter-update reporter (- vlf-file-size vlf-start-pos))))) @@ -100,15 +103,17 @@ BATCH-STEP is amount of overlap between successive chunks." (throw 'end-of-file nil)) (t (let ((batch-move (- vlf-end-pos batch-step))) (vlf-move-to-batch - (if (< batch-move match-end-pos) - match-end-pos - batch-move) t)) - (goto-char (if (< vlf-start-pos match-end-pos) - (or (byte-to-position + (if (or is-hexl + (< match-end-pos batch-move)) + batch-move + match-end-pos) t)) + (goto-char (if (or is-hexl + (<= match-end-pos vlf-start-pos)) + (point-min) + (or (byte-to-position (- match-end-pos vlf-start-pos)) - (point-min)) - (point-min))) + (point-min)))) (progress-reporter-update reporter vlf-end-pos))))) (progress-reporter-done reporter)) @@ -189,6 +194,7 @@ Search is performed chunk by chunk in `vlf-batch-size' memory." (start-pos vlf-start-pos) (end-pos vlf-end-pos) (pos (point)) + (is-hexl (derived-mode-p 'hexl-mode)) (font-lock font-lock-mode) (success nil)) (font-lock-mode 0) @@ -203,19 +209,20 @@ Search is performed chunk by chunk in `vlf-batch-size' memory." (inhibit-read-only t)) (setq n (1- n)) (vlf-with-undo-disabled - (while (and (< (- end start) n) - (< n (- vlf-file-size start))) - (erase-buffer) - (insert-file-contents-literally buffer-file-name - nil start end) - (goto-char (point-min)) - (while (re-search-forward "[\n\C-m]" nil t) - (setq n (1- n))) - (vlf-verify-size) - (setq start end - end (min vlf-file-size - (+ start vlf-batch-size))) - (progress-reporter-update reporter start)) + (or is-hexl + (while (and (< (- end start) n) + (< n (- vlf-file-size start))) + (erase-buffer) + (insert-file-contents-literally buffer-file-name + nil start end) + (goto-char (point-min)) + (while (re-search-forward "[\n\C-m]" nil t) + (setq n (1- n))) + (vlf-verify-size) + (setq start end + end (min vlf-file-size + (+ start vlf-batch-size))) + (progress-reporter-update reporter start))) (when (< n (- vlf-file-size end)) (vlf-move-to-chunk-2 start end) (goto-char (point-min)) @@ -229,17 +236,18 @@ Search is performed chunk by chunk in `vlf-batch-size' memory." (inhibit-read-only t)) (setq n (- n)) (vlf-with-undo-disabled - (while (and (< (- end start) n) (< n end)) - (erase-buffer) - (insert-file-contents-literally buffer-file-name nil - start end) - (goto-char (point-max)) - (while (re-search-backward "[\n\C-m]" nil t) - (setq n (1- n))) - (setq end start - start (max 0 (- end vlf-batch-size))) - (progress-reporter-update reporter - (- vlf-file-size end))) + (or is-hexl + (while (and (< (- end start) n) (< n end)) + (erase-buffer) + (insert-file-contents-literally buffer-file-name + nil start end) + (goto-char (point-max)) + (while (re-search-backward "[\n\C-m]" nil t) + (setq n (1- n))) + (setq end start + start (max 0 (- end vlf-batch-size))) + (progress-reporter-update reporter + (- vlf-file-size end)))) (when (< n end) (vlf-move-to-chunk-2 start end) (goto-char (point-max)) diff --git a/packages/vlf/vlf-write.el b/packages/vlf/vlf-write.el index 1c5db49..5c94113 100644 --- a/packages/vlf/vlf-write.el +++ b/packages/vlf/vlf-write.el @@ -37,37 +37,43 @@ If changing size of chunk, shift remaining file content." (or (verify-visited-file-modtime (current-buffer)) (y-or-n-p "File has changed since visited or saved.\ Save anyway? "))) + (widen) (run-hook-with-args 'vlf-before-batch-functions 'write) - (if (zerop vlf-file-size) ;new file - (progn (write-region nil nil buffer-file-name vlf-start-pos t) - (setq vlf-file-size (vlf-get-file-size - buffer-file-truename) - vlf-end-pos vlf-file-size) - (vlf-update-buffer-name)) - (widen) - (let* ((region-length (length (encode-coding-region - (point-min) (point-max) - buffer-file-coding-system t))) - (size-change (- vlf-end-pos vlf-start-pos - region-length))) - (if (zerop size-change) - (write-region nil nil buffer-file-name vlf-start-pos t) - (let ((tramp-verbose (if (boundp 'tramp-verbose) - (min tramp-verbose 2))) - (pos (point)) - (font-lock font-lock-mode)) - (font-lock-mode 0) - (if (< 0 size-change) - (vlf-file-shift-back size-change) - (vlf-file-shift-forward (- size-change))) - (if font-lock (font-lock-mode 1)) - (vlf-move-to-chunk-2 vlf-start-pos - (if (< (- vlf-end-pos vlf-start-pos) - vlf-batch-size) - (+ vlf-start-pos vlf-batch-size) - vlf-end-pos)) - (vlf-update-buffer-name) - (goto-char pos))))) + (let ((hexl (derived-mode-p 'hexl-mode))) + (when hexl + (if (consp buffer-undo-list) + (setq buffer-undo-list nil)) + (hexl-mode-exit)) + (if (zerop vlf-file-size) ;new file + (progn (write-region nil nil buffer-file-name vlf-start-pos t) + (setq vlf-file-size (vlf-get-file-size + buffer-file-truename) + vlf-end-pos vlf-file-size) + (vlf-update-buffer-name)) + (let* ((region-length (length (encode-coding-region + (point-min) (point-max) + buffer-file-coding-system t))) + (size-change (- vlf-end-pos vlf-start-pos + region-length))) + (if (zerop size-change) + (write-region nil nil buffer-file-name vlf-start-pos t) + (let ((tramp-verbose (if (boundp 'tramp-verbose) + (min tramp-verbose 2))) + (pos (point)) + (font-lock font-lock-mode)) + (font-lock-mode 0) + (if (< 0 size-change) + (vlf-file-shift-back size-change) + (vlf-file-shift-forward (- size-change))) + (if font-lock (font-lock-mode 1)) + (vlf-move-to-chunk-2 vlf-start-pos + (if (< (- vlf-end-pos vlf-start-pos) + vlf-batch-size) + (+ vlf-start-pos vlf-batch-size) + vlf-end-pos)) + (vlf-update-buffer-name) + (goto-char pos))))) + (if hexl (hexl-mode))) (run-hook-with-args 'vlf-after-batch-functions 'write)) t) diff --git a/packages/vlf/vlf.el b/packages/vlf/vlf.el index 2e3c9a1..8eb2a4c 100644 --- a/packages/vlf/vlf.el +++ b/packages/vlf/vlf.el @@ -145,17 +145,22 @@ values are: `write', `ediff', `occur', `search', `goto-line'." (setq vlf-mode t)) ;;;###autoload -(defun vlf (file) - "View Large FILE in batches. +(defun vlf (file &optional minimal) + "View Large FILE in batches. When MINIMAL load just a few bytes. You can customize number of bytes displayed by customizing `vlf-batch-size'. Return newly created buffer." - (interactive "fFile to open: ") + (interactive (list (read-file-name "File to open: ") nil)) (let ((vlf-buffer (generate-new-buffer "*vlf*"))) (set-buffer vlf-buffer) (set-visited-file-name file) (set-buffer-modified-p nil) + (if (or minimal (file-remote-p file)) + (set (make-local-variable 'vlf-batch-size) 1024)) (vlf-mode 1) + (when minimal ;restore batch size to default value + (kill-local-variable 'vlf-batch-size) + (make-local-variable 'vlf-batch-size)) (switch-to-buffer vlf-buffer) vlf-buffer)) @@ -206,24 +211,8 @@ When prefix argument is negative (goto-char (point-max))) ad-do-it)) -;; hexl mode integration -(defun vlf-hexl-before (&optional operation) - "Temporarily disable `hexl-mode' for OPERATION." - (when (derived-mode-p 'hexl-mode) - (hexl-mode-exit) - (set (make-local-variable 'vlf-restore-hexl-mode) operation))) - -(defun vlf-hexl-after (&optional operation) - "Re-enable `hexl-mode' if active before OPERATION." - (when (and (boundp 'vlf-restore-hexl-mode) - (eq vlf-restore-hexl-mode operation)) - (hexl-mode) - (kill-local-variable 'vlf-restore-hexl-mode))) - -(add-hook 'vlf-before-batch-functions 'vlf-hexl-before) -(add-hook 'vlf-after-batch-functions 'vlf-hexl-after) -(add-hook 'vlf-before-chunk-update 'vlf-hexl-before) -(add-hook 'vlf-after-chunk-update 'vlf-hexl-after) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; hexl mode integration (eval-after-load "hexl" '(progn @@ -279,8 +268,8 @@ with the prefix argument DECREASE it is halved." (vlf-verify-size) (vlf-move-to-batch vlf-file-size)) -(defun vlf-revert (&optional _ignore-auto noconfirm) - "Revert current chunk. Ignore _IGNORE-AUTO. +(defun vlf-revert (&optional _auto noconfirm) + "Revert current chunk. Ignore _AUTO. Ask for confirmation if NOCONFIRM is nil." (interactive) (when (or noconfirm