1
0
mirror of https://github.com/m00natic/vlfi.git synced 2025-01-18 20:10:47 +00:00

Merge branch 'master' into chunk-opt2

This commit is contained in:
Andrey Kotlarski 2013-08-07 01:19:26 +03:00
parent 3c2fb6b93e
commit 02a37c4192
2 changed files with 67 additions and 57 deletions

View File

@ -1,13 +1,12 @@
* View Large Files Improved * View Large Files
An Emacs mode that allows viewing, editing and searching in large An Emacs mode that allows viewing, editing and searching in large
files in chunks. Batch size can be adjusted on the fly and bounds the files in chunks. Batch size can be adjusted on the fly and bounds the
memory that is to be used for operations on the file. memory that is to be used for operations on the file.
This mode builds on the bare bones GNU ELPA vlf.el. It adds the This is development version of the GNU ELPA [[http://elpa.gnu.org/packages/vlf][vlf.el]] package. Here's
following improvements: what it does in a nutshell:
- proper dealing with Unicode
- regular expression search on whole file (in constant memory - regular expression search on whole file (in constant memory
determined by current batch size) determined by current batch size)
- chunk editing (if size has changed, saving is done in constant - chunk editing (if size has changed, saving is done in constant
@ -18,8 +17,7 @@ following improvements:
- newly added content is acknowledged if file has changed size - newly added content is acknowledged if file has changed size
meanwhile meanwhile
- automatic scrolling of batches - automatic scrolling of batches
- VLFI is added as an option when opening large files and given dired - VLFI is added as an option when opening large files
key-binding
GNU Emacs 23 and 24 are supported. GNU Emacs 23 and 24 are supported.
@ -48,15 +46,15 @@ integer value), VLFI will probably not quite work.
VLFI is derived from special-mode and keeps all its properties. For VLFI is derived from special-mode and keeps all its properties. For
example you can directly press digits to enter prefix arguments. example you can directly press digits to enter prefix arguments.
** Changing major mode ** Change major mode
You can (temporarily) change major mode to whatever you like (for You can change major mode to whatever you like (for example
example hexl-mode). Saving will insert contents as intended. You can hexl-mode). Saving will insert contents as intended. You can return
return to *vlfi-mode* too. to *vlfi-mode* too.
* Detail usage * Detail usage
** Controlling batch size ** Control batch size
*+* and *-* control current batch size by factors of 2. *+* and *-* control current batch size by factors of 2.

104
vlfi.el
View File

@ -1,12 +1,14 @@
;;; vlfi.el --- View Large Files Improved -*- lexical-binding: t -*- ;;; vlfi.el --- View Large Files -*- lexical-binding: t -*-
;; Copyright (C) 2006, 2012, 2013 Free Software Foundation, Inc. ;; Copyright (C) 2006, 2012, 2013 Free Software Foundation, Inc.
;; Version: 0.8 ;; Version: 0.9.1
;; Keywords: large files, utilities ;; Keywords: large files, utilities
;; Maintainer: Andrey Kotlarski <m00naticus@gmail.com>
;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com> ;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com>
;; 2012 Sam Steingold <sds@gnu.org> ;; 2012 Sam Steingold <sds@gnu.org>
;; 2013 Andrey Kotlarski <m00naticus@gmail.com> ;; 2013 Andrey Kotlarski <m00naticus@gmail.com>
;; URL: https://github.com/m00natic/vlfi
;; This file is free software; you can redistribute it and/or modify ;; This file is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by ;; it under the terms of the GNU General Public License as published by
@ -30,7 +32,9 @@
;; The buffer uses VLFI mode, which defines several commands for ;; The buffer uses VLFI mode, which defines several commands for
;; moving around, searching and editing selected part of file. ;; moving around, searching and editing selected part of file.
;; This package is upgraded version of the vlf.el package. ;; This package was inspired by a snippet posted by Kevin Rodgers,
;; showing how to use `insert-file-contents' to extract part of a
;; file.
;;; Code: ;;; Code:
@ -49,6 +53,7 @@
"Absolute position of the visible chunk start.") "Absolute position of the visible chunk start.")
(defvar vlfi-end-pos 0 "Absolute position of the visible chunk end.") (defvar vlfi-end-pos 0 "Absolute position of the visible chunk end.")
(defvar vlfi-file-size 0 "Total size of presented file.") (defvar vlfi-file-size 0 "Total size of presented file.")
(defvar vlfi-encode-size 0 "Size in bytes of current batch decoded.")
(defvar vlfi-mode-map (defvar vlfi-mode-map
(let ((map (make-sparse-keymap))) (let ((map (make-sparse-keymap)))
@ -70,23 +75,25 @@
map) map)
"Keymap for `vlfi-mode'.") "Keymap for `vlfi-mode'.")
(put 'vlfi-batch-size 'permanent-local t)
(put 'vlfi-start-pos 'permanent-local t)
(put 'vlfi-end-pos 'permanent-local t)
(put 'vlfi-file-size 'permanent-local t)
(put 'vlfi-encode-size 'permanent-local t)
(define-derived-mode vlfi-mode special-mode "VLFI" (define-derived-mode vlfi-mode special-mode "VLFI"
"Mode to browse large files in." "Mode to browse large files in."
(setq buffer-read-only t) (setq buffer-read-only t)
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(buffer-disable-undo) (buffer-disable-undo)
(make-local-variable 'write-file-functions) (add-hook 'write-file-functions 'vlfi-write nil t)
(add-hook 'write-file-functions 'vlfi-write)
(make-local-variable 'revert-buffer-function) (make-local-variable 'revert-buffer-function)
(setq revert-buffer-function 'vlfi-revert) (setq revert-buffer-function 'vlfi-revert)
(make-local-variable 'vlfi-batch-size) (make-local-variable 'vlfi-batch-size)
(put 'vlfi-batch-size 'permanent-local t)
(make-local-variable 'vlfi-start-pos) (make-local-variable 'vlfi-start-pos)
(put 'vlfi-start-pos 'permanent-local t)
(make-local-variable 'vlfi-end-pos) (make-local-variable 'vlfi-end-pos)
(put 'vlfi-end-pos 'permanent-local t)
(make-local-variable 'vlfi-file-size) (make-local-variable 'vlfi-file-size)
(put 'vlfi-file-size 'permanent-local t)) (make-local-variable 'vlfi-encode-size))
;;;###autoload ;;;###autoload
(defun vlfi (file) (defun vlfi (file)
@ -96,9 +103,9 @@ buffer. You can customize number of bytes displayed by customizing
`vlfi-batch-size'." `vlfi-batch-size'."
(interactive "fFile to open: ") (interactive "fFile to open: ")
(with-current-buffer (generate-new-buffer "*vlfi*") (with-current-buffer (generate-new-buffer "*vlfi*")
(set-visited-file-name file)
(vlfi-mode) (vlfi-mode)
(setq buffer-file-name file (setq vlfi-file-size (vlfi-get-file-size buffer-file-name))
vlfi-file-size (vlfi-get-file-size file))
(vlfi-insert-file) (vlfi-insert-file)
(switch-to-buffer (current-buffer)))) (switch-to-buffer (current-buffer))))
@ -116,9 +123,12 @@ buffer. You can customize number of bytes displayed by customizing
'(define-key dired-mode-map "V" 'dired-vlfi)) '(define-key dired-mode-map "V" 'dired-vlfi))
;;;###autoload ;;;###autoload
(defun vlfi-if-file-too-large (size op-type &optional filename) (defadvice abort-if-file-too-large (around vlfi-if-file-too-large
(size op-type
&optional filename)
compile activate)
"If file SIZE larger than `large-file-warning-threshold', \ "If file SIZE larger than `large-file-warning-threshold', \
allow user to view file with `vlfi', open it normally or abort. allow user to view file with `vlfi', open it normally, or abort.
OP-TYPE specifies the file operation being performed over FILENAME." OP-TYPE specifies the file operation being performed over FILENAME."
(and large-file-warning-threshold size (and large-file-warning-threshold size
(> size large-file-warning-threshold) (> size large-file-warning-threshold)
@ -143,15 +153,12 @@ OP-TYPE specifies the file operation being performed over FILENAME."
((memq char '(?a ?A)) ((memq char '(?a ?A))
(error "Aborted")))))) (error "Aborted"))))))
;; hijack `abort-if-file-too-large'
;;;###autoload
(fset 'abort-if-file-too-large 'vlfi-if-file-too-large)
;; scroll auto batching ;; scroll auto batching
(defadvice scroll-up (around vlfi-scroll-up (defadvice scroll-up (around vlfi-scroll-up
activate compile) activate compile)
"Slide to next batch if at end of buffer in `vlfi-mode'." "Slide to next batch if at end of buffer in `vlfi-mode'."
(if (and (eq major-mode 'vlfi-mode) (if (and (derived-mode-p 'vlfi-mode)
(eobp)) (eobp))
(progn (vlfi-next-batch 1) (progn (vlfi-next-batch 1)
(goto-char (point-min))) (goto-char (point-min)))
@ -160,7 +167,7 @@ OP-TYPE specifies the file operation being performed over FILENAME."
(defadvice scroll-down (around vlfi-scroll-down (defadvice scroll-down (around vlfi-scroll-down
activate compile) activate compile)
"Slide to previous batch if at beginning of buffer in `vlfi-mode'." "Slide to previous batch if at beginning of buffer in `vlfi-mode'."
(if (and (eq major-mode 'vlfi-mode) (if (and (derived-mode-p 'vlfi-mode)
(bobp)) (bobp))
(progn (vlfi-prev-batch 1) (progn (vlfi-prev-batch 1)
(goto-char (point-max))) (goto-char (point-max)))
@ -180,8 +187,6 @@ OP-TYPE specifies the file operation being performed over FILENAME."
Normally, the value is doubled; Normally, the value is doubled;
with the prefix argument DECREASE it is halved." with the prefix argument DECREASE it is halved."
(interactive "P") (interactive "P")
(or (assq 'vlfi-batch-size (buffer-local-variables))
(error "%s is not local in this buffer" 'vlfi-batch-size))
(setq vlfi-batch-size (if decrease (setq vlfi-batch-size (if decrease
(/ vlfi-batch-size 2) (/ vlfi-batch-size 2)
(* vlfi-batch-size 2))) (* vlfi-batch-size 2)))
@ -204,6 +209,12 @@ with the prefix argument DECREASE it is halved."
"Get size in bytes of FILE." "Get size in bytes of FILE."
(nth 7 (file-attributes file))) (nth 7 (file-attributes file)))
(defun vlfi-verify-size ()
"Update file size information if necessary and visited file time."
(unless (verify-visited-file-modtime (current-buffer))
(setq vlfi-file-size (vlfi-get-file-size buffer-file-name))
(set-visited-file-modtime)))
(defun vlfi-insert-file (&optional from-end) (defun vlfi-insert-file (&optional from-end)
"Insert first chunk of current file contents in current buffer. "Insert first chunk of current file contents in current buffer.
With FROM-END prefix, start from the back." With FROM-END prefix, start from the back."
@ -225,13 +236,12 @@ With FROM-END prefix, start from the back."
(interactive) (interactive)
(vlfi-insert-file t)) (vlfi-insert-file t))
(defun vlfi-revert (&optional ignore-auto noconfirm) (defun vlfi-revert (&optional _ignore-auto noconfirm)
"Revert current chunk. Ignore IGNORE-AUTO. "Revert current chunk. Ignore _IGNORE-AUTO.
Ask for confirmation if NOCONFIRM is nil." Ask for confirmation if NOCONFIRM is nil."
(ignore ignore-auto) (if (or noconfirm
(or noconfirm (yes-or-no-p (format "Revert buffer from file %s? "
(yes-or-no-p (format "Revert buffer from file %s? " buffer-file-name)))
buffer-file-name))
(vlfi-move-to-chunk vlfi-start-pos vlfi-end-pos))) (vlfi-move-to-chunk vlfi-start-pos vlfi-end-pos)))
(defun vlfi-jump-to-chunk (n) (defun vlfi-jump-to-chunk (n)
@ -249,8 +259,7 @@ When prefix argument is supplied and positive
When prefix argument is negative When prefix argument is negative
append next APPEND number of batches to the existing buffer." append next APPEND number of batches to the existing buffer."
(interactive "p") (interactive "p")
(or (verify-visited-file-modtime (current-buffer)) (vlfi-verify-size)
(setq vlfi-file-size (vlfi-get-file-size buffer-file-name)))
(let* ((end (min (+ vlfi-end-pos (* vlfi-batch-size (let* ((end (min (+ vlfi-end-pos (* vlfi-batch-size
(abs append))) (abs append)))
vlfi-file-size)) vlfi-file-size))
@ -279,8 +288,7 @@ When prefix argument is negative
"Move to batch determined by START. "Move to batch determined by START.
Adjust according to file start/end and show `vlfi-batch-size' bytes. Adjust according to file start/end and show `vlfi-batch-size' bytes.
When given MINIMAL flag, skip non important operations." When given MINIMAL flag, skip non important operations."
(or (verify-visited-file-modtime (current-buffer)) (vlfi-verify-size)
(setq vlfi-file-size (vlfi-get-file-size buffer-file-name)))
(let ((start (max 0 start)) (let ((start (max 0 start))
(end (min (+ vlfi-start-pos vlfi-batch-size) (end (min (+ vlfi-start-pos vlfi-batch-size)
vlfi-file-size))) vlfi-file-size)))
@ -417,10 +425,13 @@ Return cons \(success-status . number-of-bytes-moved-back\)."
(defun vlfi-decode-status (size) (defun vlfi-decode-status (size)
"Check if decoding followed by encoding results in SIZE bytes." "Check if decoding followed by encoding results in SIZE bytes."
(= size (length (encode-coding-string (< (abs (- size (setq vlfi-encode-size
(decode-coding-region (point-min) (point-max) (length (encode-coding-string
buffer-file-coding-system t) (decode-coding-region
buffer-file-coding-system t)))) (point-min) (point-max)
buffer-file-coding-system t)
buffer-file-coding-system t)))))
4))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; search ;;; search
@ -666,9 +677,9 @@ Prematurely ending indexing will still show what's found so far."
(pos (point))) (pos (point)))
(vlfi-beginning-of-file) (vlfi-beginning-of-file)
(goto-char (point-min)) (goto-char (point-min))
(vlfi-build-occur regexp) (unwind-protect (vlfi-build-occur regexp)
(vlfi-move-to-chunk start-pos end-pos) (vlfi-move-to-chunk start-pos end-pos)
(goto-char pos))) (goto-char pos))))
(defun vlfi-build-occur (regexp) (defun vlfi-build-occur (regexp)
"Build occur style index for REGEXP." "Build occur style index for REGEXP."
@ -804,17 +815,19 @@ or \\[vlfi-discard-edit] to discard changes.")))
(defun vlfi-write () (defun vlfi-write ()
"Write current chunk to file. Always return true to disable save. "Write current chunk to file. Always return true to disable save.
If changing size of chunk shift remaining file content." If changing size of chunk, shift remaining file content."
(interactive) (interactive)
(when (and (buffer-modified-p) (when (and (buffer-modified-p)
(or (verify-visited-file-modtime (current-buffer)) (or (verify-visited-file-modtime (current-buffer))
(y-or-n-p "File has changed since visited or saved. \ (y-or-n-p "File has changed since visited or saved. \
Save anyway? "))) Save anyway? ")))
(let ((pos (point)) (let ((pos (point))
(size-change (- vlfi-end-pos vlfi-start-pos (size-change (- vlfi-encode-size
(length (encode-coding-region (setq vlfi-encode-size
(point-min) (point-max) (length (encode-coding-region
buffer-file-coding-system t))))) (point-min) (point-max)
buffer-file-coding-system
t))))))
(cond ((zerop size-change) (cond ((zerop size-change)
(write-region nil nil buffer-file-name vlfi-start-pos t)) (write-region nil nil buffer-file-name vlfi-start-pos t))
((< 0 size-change) ((< 0 size-change)
@ -840,6 +853,7 @@ Save anyway? ")))
(progress-reporter-update reporter read-start-pos)) (progress-reporter-update reporter read-start-pos))
;; pad end with space ;; pad end with space
(erase-buffer) (erase-buffer)
(vlfi-verify-size)
(insert-char 32 size-change) (insert-char 32 size-change)
(write-region nil nil buffer-file-name (- vlfi-file-size (write-region nil nil buffer-file-name (- vlfi-file-size
size-change) t) size-change) t)
@ -849,8 +863,7 @@ Save anyway? ")))
"Read `vlfi-batch-size' bytes from READ-POS and write them \ "Read `vlfi-batch-size' bytes from READ-POS and write them \
back at WRITE-POS. Return nil if EOF is reached, t otherwise." back at WRITE-POS. Return nil if EOF is reached, t otherwise."
(erase-buffer) (erase-buffer)
(or (verify-visited-file-modtime (current-buffer)) (vlfi-verify-size)
(setq vlfi-file-size (vlfi-get-file-size buffer-file-name)))
(let ((read-end (+ read-pos vlfi-batch-size))) (let ((read-end (+ read-pos vlfi-batch-size)))
(insert-file-contents-literally buffer-file-name nil (insert-file-contents-literally buffer-file-name nil
read-pos read-pos
@ -884,8 +897,7 @@ Done by saving content up front and then writing previous batch."
Then write initial buffer content to file at WRITE-POS. Then write initial buffer content to file at WRITE-POS.
If HIDE-READ is non nil, temporarily hide literal read content. If HIDE-READ is non nil, temporarily hide literal read content.
Return nil if EOF is reached, t otherwise." Return nil if EOF is reached, t otherwise."
(or (verify-visited-file-modtime (current-buffer)) (vlfi-verify-size)
(setq vlfi-file-size (vlfi-get-file-size buffer-file-name)))
(let ((read-more (< read-pos vlfi-file-size)) (let ((read-more (< read-pos vlfi-file-size))
(start-write-pos (point-min)) (start-write-pos (point-min))
(end-write-pos (point-max))) (end-write-pos (point-max)))