1
0
mirror of https://github.com/m00natic/vlfi.git synced 2025-11-07 02:21:38 +00:00

17 Commits
0.3 ... 0.4

Author SHA1 Message Date
Andrey Kotlarski
42693f6938 Update README. 2013-03-31 20:48:08 +03:00
Andrey Kotlarski
b40bb60aa3 Tweaks and fixes to searching. 2013-03-31 20:47:50 +03:00
Andrey Kotlarski
2a7625afe6 Improve correctness of search forward. 2013-03-31 02:36:54 +02:00
Andrey Kotlarski
91fecb78c9 Simplify key-bindings. 2013-03-31 02:35:41 +02:00
Andrey Kotlarski
36411c3632 Enhance search to cover in between chunk boundaries. 2013-03-30 02:51:12 +02:00
Andrey Kotlarski
9e27aeb057 Keep stable cursor position when moving through chunks. 2013-03-30 02:45:51 +02:00
Andrey Kotlarski
fb9aa670cc Remove clutter form file name indicators. 2013-03-30 02:17:34 +02:00
Andrey Kotlarski
30e495901b Add direct jumps to first and last chunks. 2013-03-30 02:16:47 +02:00
Andrey Kotlarski
375c96f89b Add backward whole file search. 2013-03-29 18:12:20 +02:00
Andrey Kotlarski
c812288ab7 Fix small issues with forward search and add report progress. 2013-03-29 17:42:28 +02:00
Andrey Kotlarski
81e4fe19ac Merge branch 'search' of https://github.com/m00natic/vlfi into search
Conflicts:
	vlfi.el
2013-03-29 16:04:26 +02:00
Andrey Kotlarski
853386f82e Add regex search forward functionality. 2013-03-29 16:02:34 +02:00
Andrey Kotlarski
0dd4ba87aa Add regex search forward functionality. 2013-03-29 15:53:39 +02:00
Andrey Kotlarski
e693e8f24a Disable undo information for VLFI buffers. 2013-03-29 15:53:15 +02:00
Andrey Kotlarski
c3051e6131 Show file position in percentages. 2013-03-29 15:52:55 +02:00
Andrey Kotlarski
c0d143b632 Rename vlf to vlfi and update README. 2013-02-02 16:12:30 +02:00
Andrey Kotlarski
e3087a8531 Rename vlf.el. 2013-02-02 16:08:57 +02:00
3 changed files with 384 additions and 223 deletions

View File

@@ -1,4 +1,12 @@
* View Large File
* View Large File Improved
An Emacs mode that allows viewing files in chunks. This is a fork
that builds on the GNU ELPA vlf.el.
that builds on the GNU ELPA vlf.el. It adds the following
improvements:
- by chunk search
- options to jump to end or beginning of file
- ability to jump/insert given number of batches at once
- ability to view newly added content if the file has grown meanwhile
- vlfi is added as an option when opening large files

221
vlf.el
View File

@@ -1,221 +0,0 @@
;;; vlf.el --- View Large Files
;;; -*- lexical-bind: t -*-
;; Copyright (C) 2006, 2012, 2013 Free Software Foundation, Inc.
;; Version: 0.3
;; Keywords: large files, utilities
;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com>
;; 2012 Sam Steingold <sds@gnu.org>
;; 2013 Andrey Kotlarski <m00naticus@gmail.com>
;; 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
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; This package provides the M-x vlf command, which visits part of a
;; large file in a read-only buffer without visiting the entire file.
;; The buffer uses VLF mode, which defines the commands M-<next>
;; (vlf-next-batch) and M-<prior> (vlf-prev-batch) to visit other
;; parts of the file. The option `vlf-batch-size' specifies the size
;; of each batch, in bytes.
;; 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:
(defgroup vlf nil
"View Large Files in Emacs."
:prefix "vlf-"
:group 'files)
(defcustom vlf-batch-size 1024
"Defines how large each batch of file data is (in bytes)."
:type 'integer
:group 'vlf)
;; Keep track of file position.
(defvar vlf-start-pos)
(defvar vlf-end-pos)
(defvar vlf-file-size)
(defvar vlf-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [M-next] 'vlf-next-batch)
(define-key map [M-prior] 'vlf-prev-batch)
(define-key map (kbd "M-+") 'vlf-change-batch-size)
(define-key map (kbd "M--")
(lambda () "Decrease vlf batch size by factor of 2."
(interactive)
(vlf-change-batch-size t)))
map)
"Keymap for `vlf-mode'.")
(define-derived-mode vlf-mode special-mode "VLF"
"Mode to browse large files in."
(setq buffer-read-only t)
(set-buffer-modified-p nil)
(make-local-variable 'vlf-batch-size)
(make-local-variable 'vlf-start-pos)
(make-local-variable 'vlf-file-size))
(defun vlf-change-batch-size (decrease)
"Change the buffer-local value of `vlf-batch-size'.
Normally, the value is doubled;
with the prefix argument DECREASE it is halved."
(interactive "P")
(or (assq 'vlf-batch-size (buffer-local-variables))
(error "%s is not local in this buffer" 'vlf-batch-size))
(setq vlf-batch-size
(if decrease
(/ vlf-batch-size 2)
(* vlf-batch-size 2)))
(vlf-update-buffer-name))
(defun vlf-format-buffer-name ()
"Return format for vlf buffer name."
(format "%s(%s)[%d,%d](%d)"
(file-name-nondirectory buffer-file-name)
(file-size-human-readable vlf-file-size)
vlf-start-pos vlf-end-pos vlf-batch-size))
(defun vlf-update-buffer-name ()
"Update the current buffer name."
(rename-buffer (vlf-format-buffer-name) t))
(defun vlf-next-batch (append)
"Display the next batch of file data.
When prefix argument is supplied and positive
jump over APPEND number of batches.
When prefix argument is negative
append next APPEND number of batches to the existing buffer."
(interactive "p")
(let ((end (+ vlf-end-pos (* vlf-batch-size
(abs append)))))
(when (< vlf-file-size end) ; re-check file size
(setq vlf-file-size (nth 7 (file-attributes buffer-file-name)))
(cond ((= vlf-end-pos vlf-file-size)
(error "Already at EOF"))
((< vlf-file-size end)
(setq end vlf-file-size))))
(let ((inhibit-read-only t)
(do-append (< append 0)))
(if do-append
(goto-char (point-max))
(setq vlf-start-pos (- end vlf-batch-size))
(erase-buffer))
(insert-file-contents buffer-file-name nil
(if do-append
vlf-end-pos
vlf-start-pos)
end))
(setq vlf-end-pos end))
(set-buffer-modified-p nil)
(vlf-update-buffer-name))
(defun vlf-prev-batch (prepend)
"Display the previous batch of file data.
When prefix argument is supplied and positive
jump over PREPEND number of batches.
When prefix argument is negative
append previous PREPEND number of batches to the existing buffer."
(interactive "p")
(if (zerop vlf-start-pos)
(error "Already at BOF"))
(let ((inhibit-read-only t)
(start (max 0 (- vlf-start-pos (* vlf-batch-size
(abs prepend)))))
(do-prepend (< prepend 0)))
(if do-prepend
(goto-char (point-min))
(setq vlf-end-pos (+ start vlf-batch-size))
(erase-buffer))
(insert-file-contents buffer-file-name nil start
(if do-prepend
vlf-start-pos
vlf-end-pos))
(setq vlf-start-pos start))
(set-buffer-modified-p nil)
(vlf-update-buffer-name))
;;;###autoload
(defun vlf (from-end file)
"View a Large File in Emacs.
With FROM-END prefix, view from the back.
FILE is the file to open.
Batches of the file data from FILE will be displayed in a
read-only buffer.
You can customize the number of bytes to
display by customizing `vlf-batch-size'."
(interactive "P\nfFile to open: ")
(with-current-buffer (generate-new-buffer "*vlf*")
(setq buffer-file-name file
vlf-file-size (nth 7 (file-attributes file)))
(if from-end
(setq vlf-start-pos (max 0 (- vlf-file-size vlf-batch-size))
vlf-end-pos vlf-file-size)
(setq vlf-start-pos 0
vlf-end-pos (min vlf-batch-size vlf-file-size)))
(vlf-update-buffer-name)
(insert-file-contents buffer-file-name nil
vlf-start-pos vlf-end-pos)
(vlf-mode)
(switch-to-buffer (current-buffer))))
;;;###autoload
(defun dired-vlf (from-end)
"In Dired, visit the file on this line in VLF mode.
With FROM-END prefix, view from the back."
(interactive "P")
(vlf from-end (dired-get-file-for-visit)))
;;;###autoload
(eval-after-load "dired"
'(define-key dired-mode-map "V" 'dired-vlf))
;;;###autoload
(defun vlf-if-file-too-large (size op-type &optional filename)
"If file SIZE larger than `large-file-warning-threshold', \
allow user to view file with `vlf', open it normally or abort.
OP-TYPE specifies the file operation being performed over FILENAME."
(and large-file-warning-threshold size
(> size large-file-warning-threshold)
(let ((char nil))
(while (not (memq (setq char
(read-event
(propertize
(format "File %s is large (%s): %s normally (o), %s with vlf (v) or abort (a)"
(file-name-nondirectory filename)
(file-size-human-readable size)
op-type op-type)
'face 'minibuffer-prompt)))
'(?o ?O ?v ?V ?a ?A))))
(cond ((memq char '(?o ?O)))
((memq char '(?v ?V))
(vlf nil filename)
(error ""))
((memq char '(?a ?A))
(error "Aborted"))))))
;;; hijack `abort-if-file-too-large'
;;;###autoload
(fset 'abort-if-file-too-large 'vlf-if-file-too-large)
(provide 'vlf)
;;; vlf.el ends here

374
vlfi.el Normal file
View File

@@ -0,0 +1,374 @@
;;; vlfi.el --- View Large Files Improved
;;; -*- lexical-bind: t -*-
;; Copyright (C) 2006, 2012, 2013 Free Software Foundation, Inc.
;; Version: 0.4
;; Keywords: large files, utilities
;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com>
;; 2012 Sam Steingold <sds@gnu.org>
;; 2013 Andrey Kotlarski <m00naticus@gmail.com>
;; 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
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; This package provides the M-x vlfi command, which visits part of a
;; large file in a read-only buffer without visiting the entire file.
;; The buffer uses VLFI mode, which defines the commands M-<next>
;; (vlfi-next-batch) and M-<prior> (vlfi-prev-batch) to visit other
;; parts of the file. The option `vlfi-batch-size' specifies the size
;; of each batch, in bytes.
;; This package is an improved fork of the vlf.el package.
;;; Code:
(defgroup vlfi nil
"View Large Files in Emacs."
:prefix "vlfi-"
:group 'files)
(defcustom vlfi-batch-size 1024
"Defines how large each batch of file data is (in bytes)."
:type 'integer
:group 'vlfi)
;; Keep track of file position.
(defvar vlfi-start-pos)
(defvar vlfi-end-pos)
(defvar vlfi-file-size)
(defvar vlfi-mode-map
(let ((map (make-sparse-keymap)))
(define-key map [M-next] 'vlfi-next-batch)
(define-key map [M-prior] 'vlfi-prev-batch)
(define-key map (kbd "M-+") 'vlfi-change-batch-size)
(define-key map (kbd "M--")
(lambda () "Decrease vlfi batch size by factor of 2."
(interactive)
(vlfi-change-batch-size t)))
(define-key map "s" 'vlfi-re-search-forward)
(define-key map "r" 'vlfi-re-search-backward)
(define-key map ">" (lambda () "Jump to end of file content."
(interactive)
(vlfi-insert-file buffer-file-name t)))
(define-key map "<" (lambda () "Jump to beginning of file content."
(interactive)
(vlfi-insert-file buffer-file-name)))
map)
"Keymap for `vlfi-mode'.")
(define-derived-mode vlfi-mode special-mode "VLFI"
"Mode to browse large files in."
(setq buffer-read-only t)
(set-buffer-modified-p nil)
(make-local-variable 'vlfi-batch-size)
(make-local-variable 'vlfi-start-pos)
(make-local-variable 'vlfi-file-size))
(defun vlfi-change-batch-size (decrease)
"Change the buffer-local value of `vlfi-batch-size'.
Normally, the value is doubled;
with the prefix argument DECREASE it is halved."
(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
(/ vlfi-batch-size 2)
(* vlfi-batch-size 2)))
(vlfi-update-buffer-name))
(defun vlfi-format-buffer-name ()
"Return format for vlfi buffer name."
(format "%s(%s)[%.2f%%%%](%d)"
(file-name-nondirectory buffer-file-name)
(file-size-human-readable vlfi-file-size)
(/ (* 100 vlfi-end-pos) (float vlfi-file-size))
vlfi-batch-size))
(defun vlfi-update-buffer-name ()
"Update the current buffer name."
(rename-buffer (vlfi-format-buffer-name) t))
(defun vlfi-next-batch (append)
"Display the next batch of file data.
When prefix argument is supplied and positive
jump over APPEND number of batches.
When prefix argument is negative
append next APPEND number of batches to the existing buffer."
(interactive "p")
(let ((end (+ vlfi-end-pos (* vlfi-batch-size
(abs append)))))
(when (< vlfi-file-size end) ; re-check file size
(setq vlfi-file-size (nth 7 (file-attributes buffer-file-name)))
(cond ((= vlfi-end-pos vlfi-file-size)
(error "Already at EOF"))
((< vlfi-file-size end)
(setq end vlfi-file-size))))
(let ((inhibit-read-only t)
(do-append (< append 0))
(pos (point)))
(if do-append
(goto-char (point-max))
(setq vlfi-start-pos (- end vlfi-batch-size))
(erase-buffer))
(insert-file-contents buffer-file-name nil
(if do-append
vlfi-end-pos
vlfi-start-pos)
end)
(goto-char pos))
(setq vlfi-end-pos end))
(set-buffer-modified-p nil)
(vlfi-update-buffer-name))
(defun vlfi-prev-batch (prepend)
"Display the previous batch of file data.
When prefix argument is supplied and positive
jump over PREPEND number of batches.
When prefix argument is negative
append previous PREPEND number of batches to the existing buffer."
(interactive "p")
(if (zerop vlfi-start-pos)
(error "Already at BOF"))
(let ((inhibit-read-only t)
(start (max 0 (- vlfi-start-pos (* vlfi-batch-size
(abs prepend)))))
(do-prepend (< prepend 0))
(pos (- (point-max) (point))))
(if do-prepend
(goto-char (point-min))
(setq vlfi-end-pos (+ start vlfi-batch-size))
(erase-buffer))
(insert-file-contents buffer-file-name nil start
(if do-prepend
vlfi-start-pos
vlfi-end-pos))
(goto-char (- (point-max) pos))
(setq vlfi-start-pos start))
(set-buffer-modified-p nil)
(vlfi-update-buffer-name))
(defun vlfi-move-to-chunk (start end)
"Move to chunk determined by START END."
(if (< vlfi-file-size end) ; re-check file size
(setq vlfi-file-size (nth 7
(file-attributes buffer-file-name))))
(setq vlfi-start-pos (max 0 start)
vlfi-end-pos (min end vlfi-file-size))
(let ((inhibit-read-only t))
(erase-buffer)
(insert-file-contents buffer-file-name nil
vlfi-start-pos vlfi-end-pos))
(set-buffer-modified-p nil)
(vlfi-update-buffer-name))
(defun vlfi-insert-file (file &optional from-end)
"Insert first chunk of FILE contents in current buffer.
With FROM-END prefix, start from the back."
(if from-end
(setq vlfi-start-pos (max 0 (- vlfi-file-size vlfi-batch-size))
vlfi-end-pos vlfi-file-size)
(setq vlfi-start-pos 0
vlfi-end-pos (min vlfi-batch-size vlfi-file-size)))
(vlfi-move-to-chunk vlfi-start-pos vlfi-end-pos))
;;;###autoload
(defun vlfi (file &optional from-end)
"View Large FILE. With FROM-END prefix, view from the back.
Batches of the file data from FILE will be displayed in a read-only
buffer. You can customize number of bytes displayed by customizing
`vlfi-batch-size'."
(interactive "fFile to open: \nP")
(with-current-buffer (generate-new-buffer "*vlfi*")
(buffer-disable-undo)
(setq buffer-file-name file
vlfi-file-size (nth 7 (file-attributes file)))
(vlfi-insert-file file from-end)
(vlfi-mode)
(switch-to-buffer (current-buffer))))
;;;###autoload
(defun dired-vlfi (from-end)
"In Dired, visit the file on this line in VLFI mode.
With FROM-END prefix, view from the back."
(interactive "P")
(vlfi (dired-get-file-for-visit) from-end))
;;;###autoload
(eval-after-load "dired"
'(define-key dired-mode-map "V" 'dired-vlfi))
;;;###autoload
(defun vlfi-if-file-too-large (size op-type &optional filename)
"If file SIZE larger than `large-file-warning-threshold', \
allow user to view file with `vlfi', open it normally or abort.
OP-TYPE specifies the file operation being performed over FILENAME."
(and large-file-warning-threshold size
(> size large-file-warning-threshold)
(let ((char nil))
(while (not (memq (setq char
(read-event
(propertize
(format "File %s is large (%s): \
%s normally (o), %s with vlfi (v) or abort (a)"
(file-name-nondirectory filename)
(file-size-human-readable size)
op-type op-type)
'face 'minibuffer-prompt)))
'(?o ?O ?v ?V ?a ?A))))
(cond ((memq char '(?o ?O)))
((memq char '(?v ?V))
(vlfi nil filename)
(error ""))
((memq char '(?a ?A))
(error "Aborted"))))))
;;; hijack `abort-if-file-too-large'
;;;###autoload
(fset 'abort-if-file-too-large 'vlfi-if-file-too-large)
(defun vlfi-re-search-forward (regexp count)
"Search forward for REGEXP prefix COUNT number of times."
(interactive (list (read-regexp "Search whole file"
(if regexp-history
(car regexp-history))
'regexp-history)
(or current-prefix-arg 1)))
(let ((match-chunk-start vlfi-start-pos)
(match-chunk-end vlfi-end-pos)
(match-start-pos (point))
(match-end-pos (point))
(to-find count)
(search-reporter (make-progress-reporter
(concat "Searching for " regexp)
vlfi-start-pos vlfi-file-size))
(initial-chunk t))
(unwind-protect
(catch 'end-of-file
(while (not (zerop to-find))
(cond ((re-search-forward regexp nil t)
(setq to-find (if (= match-start-pos
(match-beginning 0))
to-find
(1- to-find))
match-start-pos (match-beginning 0)
match-end-pos (match-end 0)
match-chunk-start vlfi-start-pos
match-chunk-end vlfi-end-pos)
(if (and (< vlfi-batch-size match-start-pos)
(> (- vlfi-end-pos vlfi-start-pos)
vlfi-batch-size))
(setq match-chunk-start
(+ match-chunk-start vlfi-batch-size)
match-start-pos (- match-start-pos
vlfi-batch-size)
match-end-pos (- match-end-pos
vlfi-batch-size))))
((= vlfi-end-pos vlfi-file-size)
(throw 'end-of-file nil))
(t (if initial-chunk
(progn (setq initial-chunk nil)
(vlfi-next-batch -1))
(vlfi-move-to-chunk (+ vlfi-start-pos
vlfi-batch-size)
(+ vlfi-end-pos
vlfi-batch-size)))
(goto-char (if (< vlfi-start-pos match-chunk-end)
match-start-pos
(point-min)))
(goto-char match-start-pos)
(progress-reporter-update search-reporter
vlfi-end-pos))))
(progress-reporter-done search-reporter))
(vlfi-end-search match-chunk-start match-chunk-end
match-end-pos count to-find))))
(defun vlfi-re-search-backward (regexp count)
"Search backward for REGEXP prefix COUNT number of times."
(interactive (list (read-regexp "Search whole file"
(if regexp-history
(car regexp-history))
'regexp-history)
(or current-prefix-arg 1)))
(let ((match-chunk-start vlfi-start-pos)
(match-chunk-end vlfi-end-pos)
(match-start-pos (point))
(match-end-pos (point))
(to-find count)
(search-reporter (make-progress-reporter
(concat "Searching for " regexp)
(- vlfi-file-size vlfi-end-pos)
vlfi-file-size))
(initial-chunk t))
(unwind-protect
(catch 'start-of-file
(while (not (zerop to-find))
(cond ((re-search-backward regexp nil t)
(setq to-find (if (= match-end-pos
(match-end 0))
to-find
(1- to-find))
match-start-pos (match-beginning 0)
match-end-pos (match-end 0)
match-chunk-start vlfi-start-pos
match-chunk-end vlfi-end-pos)
(if (and (< match-end-pos vlfi-batch-size)
(> (- vlfi-end-pos vlfi-start-pos)
vlfi-batch-size))
(setq match-chunk-end
(- match-chunk-end
vlfi-batch-size))))
((zerop vlfi-start-pos)
(throw 'start-of-file nil))
(t (if initial-chunk
(progn (setq initial-chunk nil)
(vlfi-prev-batch -1))
(vlfi-move-to-chunk (- vlfi-start-pos
vlfi-batch-size)
(- vlfi-end-pos
vlfi-batch-size)))
(goto-char (if (< match-chunk-start vlfi-end-pos)
match-end-pos
(point-max)))
(setq last-chunk-match nil)
(progress-reporter-update search-reporter
(- vlfi-file-size
vlfi-start-pos)))))
(progress-reporter-done search-reporter))
(vlfi-end-search match-chunk-start match-chunk-end
match-start-pos count to-find))))
(defun vlfi-end-search (match-chunk-start match-chunk-end
match-pos count to-find)
"Move to chunk determined by MATCH-CHUNK-START and MATCH-CHUNK-END.
Go to MATCH-POS and according to COUNT and left TO-FIND show if search
has been successful. Return nil if nothing found."
(vlfi-move-to-chunk match-chunk-start match-chunk-end)
(goto-char match-pos)
(cond ((zerop to-find) t)
((< to-find count)
(message "Moved to the %d match which is last found"
(- count to-find))
t)
(t (message "Not found")
nil)))
(provide 'vlfi)
;;; vlfi.el ends here