mirror of
https://github.com/m00natic/vlfi.git
synced 2025-11-11 04:15:38 +00:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f9ba7ce5f | ||
|
|
8ba5bead36 | ||
|
|
ee19f811ae | ||
|
|
6476c1be6a | ||
|
|
2c231dfb15 | ||
|
|
6bb60b72ad | ||
|
|
b235cf907c | ||
|
|
859c1e4c45 | ||
|
|
8c61b776d6 | ||
|
|
074f9e960d | ||
|
|
b05255b225 | ||
|
|
924d6b18fa | ||
|
|
0199c2468a | ||
|
|
ffac6972ed | ||
|
|
a71ee32508 | ||
|
|
9510c70860 | ||
|
|
cc9b115486 | ||
|
|
f83a212c52 | ||
|
|
1a1ce27d37 | ||
|
|
5c604c48a4 | ||
|
|
0fa8e8d6bf | ||
|
|
d7766f2a3b | ||
|
|
30d2bb0d25 | ||
|
|
c533bce956 | ||
|
|
5d30eb4826 | ||
|
|
d5d9cd71ee | ||
|
|
e747de4495 | ||
|
|
82fd5b943b | ||
|
|
9646b00215 | ||
|
|
27e3bbb320 | ||
|
|
117935db98 | ||
|
|
38e8f6c4e1 | ||
|
|
98ddc3afd9 |
86
README.org
86
README.org
@@ -1,25 +1,31 @@
|
||||
* View Large Files
|
||||
|
||||
Emacs minor mode that allows viewing, editing and searching large
|
||||
files in batches. Batch size can be adjusted on the fly and bounds
|
||||
the memory that is to be used for operations on the file.
|
||||
Emacs minor mode that allows viewing, editing, searching and comparing
|
||||
large files in batches. Batch size can be adjusted on the fly and
|
||||
bounds the memory that is to be used for operations on the file. This
|
||||
way multiple large files (like terabytes or whatever) can be instantly
|
||||
and simultaneously accessed without swapping and degraded
|
||||
performance.
|
||||
|
||||
This is development version of the GNU ELPA [[http://elpa.gnu.org/packages/vlf][vlf.el]] package. Here's
|
||||
what it does in a nutshell:
|
||||
This is development version of the GNU ELPA [[http://elpa.gnu.org/packages/vlf][VLF]] package. Here's what
|
||||
it offers in a nutshell:
|
||||
|
||||
- regular expression search on whole file (in constant memory
|
||||
determined by current batch size)
|
||||
- chunk editing (if size has changed, saving is done in constant
|
||||
memory determined by current batch size)
|
||||
- occur like indexing
|
||||
- [[http://www.emacswiki.org/emacs/OccurMode][Occur]] like indexing
|
||||
- options to jump to beginning, end or arbitrary file chunk
|
||||
- ability to jump/insert given number of batches at once
|
||||
- newly added content is acknowledged if file has changed size
|
||||
meanwhile
|
||||
- automatic scrolling of batches
|
||||
- as VLF is minor mode, font locking and functionality of the
|
||||
respective major mode is also present
|
||||
- VLF is added as an option when opening large files
|
||||
- as a minor mode, font locking and functionality of the respective
|
||||
major mode is also present
|
||||
- by batch [[http://www.emacswiki.org/emacs/EdiffMode][Ediff]] comparison
|
||||
- can be added as option to automatically open large files
|
||||
- smooth integration with [[http://www.emacswiki.org/emacs/HexlMode][hexl-mode]]
|
||||
- works with [[http://www.emacswiki.org/emacs/TrampMode][TRAMP]] so accessing network files is fine
|
||||
|
||||
GNU Emacs 23 and 24 are supported.
|
||||
|
||||
@@ -31,12 +37,12 @@ M-x vlf PATH-TO-FILE
|
||||
|
||||
Emacs' Unicode support is leveraged so you'll not see bare bytes but
|
||||
characters decoded as if file is normally opened. This holds for
|
||||
editing, search and indexing.
|
||||
editing, search, indexing and comparison.
|
||||
|
||||
** 32-bit GNU Emacs
|
||||
|
||||
Regular Emacs integers are used, so if you use 32-bit Emacs without
|
||||
bignum support, VLF will not work with files over 512 MB (maximum
|
||||
bignum support, *VLF* will not work with files over 512 MB (maximum
|
||||
integer value).
|
||||
|
||||
** Memory control
|
||||
@@ -53,12 +59,12 @@ To have *vlf* offered as choice when opening large files:
|
||||
(require 'vlf-integrate)
|
||||
#+END_EXAMPLE
|
||||
|
||||
You can control when vlf-mode is invoked or offered with the
|
||||
*vlf-application* customization option. By default it will offer VLF
|
||||
when opening large files. There are also options to never use it (you
|
||||
can still call *vlf* command explicitly); to use it without asking for
|
||||
large files or to invoke it on all files. Here's example setup such
|
||||
that vlf-mode automatically launches for large files:
|
||||
You can control when *vlf-mode* is invoked or offered with the
|
||||
*vlf-application* customization option. By default it will offer
|
||||
*VLF* when opening large files. There are also options to never use
|
||||
it (you can still call *vlf* command explicitly); to use it without
|
||||
asking for large files or to invoke it on all files. Here's example
|
||||
setup such that *vlf-mode* automatically launches for large files:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
(custom-set-variables
|
||||
@@ -67,12 +73,12 @@ that vlf-mode automatically launches for large files:
|
||||
|
||||
*** Disable for specific mode
|
||||
|
||||
To disable automatic usage of VLF for a major mode, add it to
|
||||
To disable automatic usage of *VLF* for a major mode, add it to
|
||||
*vlf-forbidden-modes-list*.
|
||||
|
||||
*** Disable for specific function
|
||||
|
||||
To disable automatic usage of VLF for a function, for example named
|
||||
To disable automatic usage of *VLF* for a function, for example named
|
||||
*func* defined in file *file.el*:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
@@ -81,8 +87,8 @@ To disable automatic usage of VLF for a function, for example named
|
||||
|
||||
** Keymap
|
||||
|
||||
All VLF operations are grouped under the *C-c C-v* prefix by default.
|
||||
Here's example how to add another prefix (*C-x v*):
|
||||
All *VLF* operations are grouped under the *C-c C-v* prefix by
|
||||
default. Here's example how to add another prefix (*C-x v*):
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
(eval-after-load "vlf"
|
||||
@@ -91,12 +97,12 @@ Here's example how to add another prefix (*C-x v*):
|
||||
|
||||
** Control batch size
|
||||
|
||||
Use *M-x vlf-set-batch-size* to change batch size and update chunk
|
||||
immediately.
|
||||
|
||||
*C-c C-v +* and *C-c C-v -* control current batch size by factors
|
||||
of 2.
|
||||
|
||||
You can also set by hand local variable *vlf-batch-size* and then
|
||||
refresh with *C-c C-v g*.
|
||||
|
||||
** Move around
|
||||
|
||||
Scrolling automatically triggers moving to previous or next chunk at
|
||||
@@ -130,10 +136,10 @@ beforehand.
|
||||
|
||||
** Occur over whole file
|
||||
|
||||
*C-c C-v o* builds index for given regular expression just like
|
||||
*M-x occur*. It does this batch by batch over the whole file. Note
|
||||
that even if you prematurely stop it with *C-g*, it will still show
|
||||
index of what's found so far.
|
||||
*C-c C-v o* builds index for given regular expression just like M-x
|
||||
occur*. It does so batch by batch over the whole file. Note that
|
||||
even if you prematurely stop it with *C-g*, it will still show index
|
||||
of what's found so far.
|
||||
|
||||
** Jump to line
|
||||
|
||||
@@ -147,3 +153,27 @@ file.
|
||||
If editing doesn't change size of the chunk, only this chunk is saved.
|
||||
Otherwise the remaining part of the file is adjusted batch by batch,
|
||||
so again you'd better have bigger current batch size.
|
||||
|
||||
** By batch Ediff
|
||||
|
||||
Use *M-x vlf-ediff-files* and *M-x vlf-ediff-buffers* to compare
|
||||
files/buffers batch by batch (batch size is queried in case of files
|
||||
or taken from the first buffer in case of buffers). Moving after the
|
||||
last difference in current chunk searches for following one with
|
||||
difference. The other way around if looking for difference before the
|
||||
first one.
|
||||
|
||||
* Extending
|
||||
|
||||
** Move hooks
|
||||
|
||||
A couple of hooks are run whenever updating chunk:
|
||||
*vlf-before-chunk-update* and *vlf-after-chunk-update*.
|
||||
|
||||
** Batch move hooks
|
||||
|
||||
Some operations may trigger multiple chunk moves. There are a couple
|
||||
of hooks that run in such cases: *vlf-before-batch-functions* and
|
||||
*vlf-after-batch-functions*. They are passed one argument that
|
||||
specifies type of operation that runs. Possible values are the
|
||||
symbols: *write*, *ediff*, *occur*, *search* and *goto-line*.
|
||||
|
||||
211
vlf-base.el
211
vlf-base.el
@@ -27,17 +27,19 @@
|
||||
|
||||
;;; 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)."
|
||||
:group 'vlf
|
||||
:type 'integer)
|
||||
:group 'vlf :type 'integer)
|
||||
(put 'vlf-batch-size 'permanent-local t)
|
||||
|
||||
(defcustom vlf-before-chunk-update nil
|
||||
"Hook that runs before chunk update."
|
||||
:group 'vlf :type 'hook)
|
||||
|
||||
(defcustom vlf-after-chunk-update nil
|
||||
"Hook that runs after chunk update."
|
||||
:group 'vlf :type 'hook)
|
||||
|
||||
;;; Keep track of file position.
|
||||
(defvar vlf-start-pos 0
|
||||
"Absolute position of the visible chunk start.")
|
||||
@@ -94,13 +96,27 @@ When given MINIMAL flag, skip non important operations.
|
||||
If same as current chunk is requested, do nothing.
|
||||
Return number of bytes moved back for proper decoding and number of
|
||||
bytes added to the end."
|
||||
(unless (and (= start vlf-start-pos)
|
||||
(= end vlf-end-pos))
|
||||
(vlf-verify-size)
|
||||
(cond ((or (<= end start) (<= end 0)
|
||||
(<= vlf-file-size start))
|
||||
(when (or (not (buffer-modified-p))
|
||||
(y-or-n-p "Chunk modified, are you sure? "))
|
||||
(erase-buffer)
|
||||
(set-buffer-modified-p nil)
|
||||
(let ((place (if (<= vlf-file-size start)
|
||||
vlf-file-size
|
||||
0)))
|
||||
(setq vlf-start-pos place
|
||||
vlf-end-pos place)
|
||||
(if (not minimal)
|
||||
(vlf-update-buffer-name))
|
||||
(cons (- start place) (- place end)))))
|
||||
((or (/= start vlf-start-pos)
|
||||
(/= end vlf-end-pos))
|
||||
(let ((shifts (vlf-move-to-chunk-1 start end)))
|
||||
(and shifts (not minimal)
|
||||
(vlf-update-buffer-name))
|
||||
shifts)))
|
||||
shifts))))
|
||||
|
||||
(defun vlf-move-to-chunk-1 (start end)
|
||||
"Move to chunk enclosed by START END keeping as much edits if any.
|
||||
@@ -128,66 +144,73 @@ bytes added to the 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 edit-end)
|
||||
(let* ((del-pos (1+ (or (byte-to-position
|
||||
(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))
|
||||
0)))
|
||||
(del-len (length (encode-coding-region
|
||||
del-pos (point-max)
|
||||
buffer-file-coding-system
|
||||
t))))
|
||||
(setq end (- (if (zerop vlf-end-pos)
|
||||
vlf-file-size
|
||||
vlf-end-pos)
|
||||
del-len))
|
||||
(vlf-with-undo-disabled
|
||||
(delete-region del-pos (point-max)))))
|
||||
(point-min))
|
||||
(point-max))
|
||||
nil))))
|
||||
((< edit-end end)
|
||||
(vlf-with-undo-disabled
|
||||
(setq shift-end (cdr (vlf-insert-file-contents
|
||||
vlf-end-pos end
|
||||
(/= start vlf-end-pos) t
|
||||
vlf-end-pos end nil t
|
||||
(point-max)))))))
|
||||
(cond ((< vlf-start-pos start)
|
||||
(let* ((del-pos (1+ (byte-to-position
|
||||
(- start vlf-start-pos))))
|
||||
(del-len (length (encode-coding-region
|
||||
(point-min) del-pos
|
||||
buffer-file-coding-system
|
||||
t))))
|
||||
(setq start (+ vlf-start-pos del-len))
|
||||
(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) del-pos))
|
||||
(vlf-shift-undo-list (- (point-min) del-pos))))
|
||||
(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
|
||||
(/= end vlf-start-pos)
|
||||
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)))))
|
||||
(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
|
||||
vlf-end-pos (+ end shift-end)))
|
||||
(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))))))
|
||||
|
||||
(defun vlf-move-to-chunk-2 (start end)
|
||||
"Unconditionally move to chunk enclosed by START END bytes.
|
||||
Return number of bytes moved back for proper decoding and number of
|
||||
bytes added to the end."
|
||||
(run-hooks 'vlf-before-chunk-update)
|
||||
(vlf-verify-size t)
|
||||
(setq vlf-start-pos (max 0 start)
|
||||
vlf-end-pos (min end vlf-file-size))
|
||||
@@ -203,13 +226,15 @@ bytes added to the end."
|
||||
(goto-char (or (byte-to-position (+ pos (car shifts)))
|
||||
(point-max)))))
|
||||
(set-buffer-modified-p nil)
|
||||
(setq buffer-undo-list nil)
|
||||
(or (eq buffer-undo-list t)
|
||||
(setq buffer-undo-list nil))
|
||||
(run-hooks 'vlf-after-chunk-update)
|
||||
shifts))
|
||||
|
||||
(defun vlf-insert-file-contents (start end adjust-start adjust-end
|
||||
&optional position)
|
||||
"Adjust chunk at absolute START to END till content can be\
|
||||
properly decoded. ADJUST-START determines if trying to prepend bytes\
|
||||
properly decoded. ADJUST-START determines if trying to prepend bytes
|
||||
to the beginning, ADJUST-END - append to the end.
|
||||
Use buffer POSITION as start if given.
|
||||
Return number of bytes moved back for proper decoding and number of
|
||||
@@ -227,11 +252,19 @@ bytes added to the end."
|
||||
(setq shift-start (vlf-adjust-start start safe-end position
|
||||
adjust-end)
|
||||
start (- start shift-start))
|
||||
(vlf-insert-file-contents-safe start safe-end position))
|
||||
(vlf-insert-file-contents-1 start safe-end))
|
||||
(if adjust-end
|
||||
(setq shift-end (vlf-adjust-end start end position)))
|
||||
(setq shift-end (- (car (vlf-delete-region position start
|
||||
safe-end end
|
||||
(point-max)
|
||||
nil 'start))
|
||||
end)))
|
||||
(cons shift-start shift-end)))
|
||||
|
||||
(defun vlf-insert-file-contents-1 (start end)
|
||||
"Extract decoded file bytes START to END."
|
||||
(insert-file-contents buffer-file-name nil start end))
|
||||
|
||||
(defun vlf-adjust-start (start end position adjust-end)
|
||||
"Adjust chunk beginning at absolute START to END till content can\
|
||||
be properly decoded. Use buffer POSITION as start.
|
||||
@@ -243,8 +276,8 @@ Return number of bytes moved back for proper decoding."
|
||||
(strict (or (= sample-end vlf-file-size)
|
||||
(and (not adjust-end) (= sample-end end))))
|
||||
(shift 0))
|
||||
(while (and (progn (vlf-insert-file-contents-safe
|
||||
safe-start sample-end position)
|
||||
(while (and (progn (vlf-insert-file-contents-1 safe-start
|
||||
sample-end)
|
||||
(not (zerop safe-start)))
|
||||
(< shift 3)
|
||||
(let ((diff (- chunk-size
|
||||
@@ -259,53 +292,59 @@ Return number of bytes moved back for proper decoding."
|
||||
safe-start (1- safe-start)
|
||||
chunk-size (1+ chunk-size))
|
||||
(delete-region position (point-max)))
|
||||
(let ((cut-pos position)
|
||||
(cut-len 0))
|
||||
(while (< safe-start start)
|
||||
(setq cut-len (length (encode-coding-region
|
||||
cut-pos (1+ cut-pos)
|
||||
buffer-file-coding-system t))
|
||||
cut-pos (1+ cut-pos)
|
||||
safe-start (+ safe-start cut-len)))
|
||||
(if (< start safe-start)
|
||||
(setq safe-start (- safe-start cut-len)
|
||||
cut-pos (1- cut-pos)))
|
||||
(if (= sample-end end)
|
||||
(delete-region position cut-pos)
|
||||
(setq safe-start (car (vlf-delete-region position safe-start
|
||||
sample-end start
|
||||
position t 'start)))
|
||||
(unless (= sample-end end)
|
||||
(delete-region position (point-max))
|
||||
(vlf-insert-file-contents-safe safe-start end position)))
|
||||
(vlf-insert-file-contents-1 safe-start end))
|
||||
(- start safe-start)))
|
||||
|
||||
(defun vlf-adjust-end (start end position)
|
||||
"Adjust chunk end at absolute START to END starting at POSITION.
|
||||
Remove characters from the end until length is closest to expected.
|
||||
Return number of bytes added over expected."
|
||||
(let ((expected-size (- end start))
|
||||
(current-size (length (encode-coding-region
|
||||
position (point-max)
|
||||
(defun vlf-delete-region (position start end border cut-point from-start
|
||||
&optional encode-direction)
|
||||
"Delete from chunk starting at POSITION enclosing absolute file\
|
||||
positions START to END at absolute position BORDER. Start search for
|
||||
best cut at CUT-POINT. Delete from buffer beginning if FROM-START is
|
||||
non nil or up to buffer end otherwise. ENCODE-DIRECTION determines
|
||||
which side of the region to use to calculate cut position's absolute
|
||||
file position. Possible values are: `start' - from the beginning;
|
||||
`end' - from end; nil - the shorter side.
|
||||
Return actual absolute position of new border and buffer point at
|
||||
which deletion was performed."
|
||||
(let* ((encode-from-end (if encode-direction
|
||||
(eq encode-direction 'end)
|
||||
(< (- end border) (- border start))))
|
||||
(dist (if encode-from-end
|
||||
(- end (length (encode-coding-region
|
||||
cut-point (point-max)
|
||||
buffer-file-coding-system t)))
|
||||
(cut-point (point-max))
|
||||
(cut-len 0))
|
||||
(while (< expected-size current-size)
|
||||
(setq cut-len (length (encode-coding-region
|
||||
(1- cut-point) cut-point
|
||||
(+ start (length (encode-coding-region
|
||||
position cut-point
|
||||
buffer-file-coding-system t)))))
|
||||
(len 0))
|
||||
(if (< border dist)
|
||||
(while (< border dist)
|
||||
(setq len (length (encode-coding-region
|
||||
cut-point (1- cut-point)
|
||||
buffer-file-coding-system t))
|
||||
cut-point (1- cut-point)
|
||||
current-size (- current-size cut-len)))
|
||||
(if (< current-size expected-size)
|
||||
dist (- dist len)))
|
||||
(while (< dist border)
|
||||
(setq len (length (encode-coding-region
|
||||
cut-point (1+ cut-point)
|
||||
buffer-file-coding-system t))
|
||||
cut-point (1+ cut-point)
|
||||
dist (+ dist len)))
|
||||
(or (= dist border)
|
||||
(setq cut-point (1- cut-point)
|
||||
dist (- dist len))))
|
||||
(and (not from-start) (/= dist border)
|
||||
(setq cut-point (1+ cut-point)
|
||||
current-size (+ current-size cut-len)))
|
||||
(delete-region cut-point (point-max))
|
||||
(- current-size expected-size)))
|
||||
|
||||
(defun vlf-insert-file-contents-safe (start end position)
|
||||
"Extract decoded file bytes START to END at POSITION."
|
||||
(let ((coding buffer-file-coding-system))
|
||||
(insert-file-contents-literally buffer-file-name nil start end)
|
||||
(let ((coding-system-for-read coding))
|
||||
(decode-coding-inserted-region position (point-max)
|
||||
buffer-file-name nil start end)))
|
||||
(setq buffer-file-coding-system last-coding-system-used))
|
||||
dist (+ dist len)))
|
||||
(vlf-with-undo-disabled
|
||||
(if from-start (delete-region position cut-point)
|
||||
(delete-region cut-point (point-max))))
|
||||
(cons dist (1+ cut-point))))
|
||||
|
||||
(defun vlf-shift-undo-list (n)
|
||||
"Shift undo list element regions by N."
|
||||
|
||||
328
vlf-ediff.el
Normal file
328
vlf-ediff.el
Normal file
@@ -0,0 +1,328 @@
|
||||
;;; vlf-ediff.el --- VLF ediff functionality -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Keywords: large files, compare, ediff
|
||||
;; Author: Andrey Kotlarski <m00naticus@gmail.com>
|
||||
;; URL: https://github.com/m00natic/vlfi
|
||||
|
||||
;; 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 3, 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 ediff functionality for VLF managed buffers
|
||||
;; in face of the `vlf-ediff-buffers' and `vlf-ediff-files' commands.
|
||||
|
||||
;;; Code:
|
||||
|
||||
(require 'vlf)
|
||||
(require 'ediff)
|
||||
|
||||
(defvar vlf-ediff-session nil
|
||||
"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.
|
||||
Requesting next or previous difference at the end or beginning
|
||||
respectively of difference list, runs ediff over the adjacent chunks."
|
||||
(interactive
|
||||
(let (bf)
|
||||
(list (setq bf (read-buffer "Buffer A to compare: "
|
||||
(ediff-other-buffer "") t))
|
||||
(read-buffer "Buffer B to compare: "
|
||||
(progn
|
||||
;; realign buffers so that two visible bufs will be
|
||||
;; at the top
|
||||
(save-window-excursion (other-window 1))
|
||||
(ediff-other-buffer bf))
|
||||
t))))
|
||||
(set-buffer buffer-A)
|
||||
(setq buffer-A (current-buffer)) ;names change, so reference by buffer object
|
||||
(let ((batch-size vlf-batch-size))
|
||||
(set-buffer buffer-B)
|
||||
(setq buffer-B (current-buffer))
|
||||
(vlf-set-batch-size batch-size))
|
||||
(ediff-buffers buffer-A buffer-B
|
||||
'((lambda () (setq vlf-ediff-session t)
|
||||
(vlf-ediff-next ediff-buffer-A ediff-buffer-B
|
||||
ediff-control-buffer
|
||||
'vlf-next-chunk)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun vlf-ediff-files (file-A file-B batch-size)
|
||||
"Run batch by batch ediff over FILE-A and FILE-B.
|
||||
Files are processed with VLF with BATCH-SIZE chunks.
|
||||
Requesting next or previous difference at the end or beginning
|
||||
respectively of difference list, runs ediff over the adjacent chunks."
|
||||
(interactive
|
||||
(let ((dir-A (if ediff-use-last-dir
|
||||
ediff-last-dir-A
|
||||
default-directory))
|
||||
dir-B f)
|
||||
(list (setq f (ediff-read-file-name
|
||||
"File A to compare"
|
||||
dir-A
|
||||
(ediff-get-default-file-name)
|
||||
'no-dirs))
|
||||
(ediff-read-file-name "File B to compare"
|
||||
(setq dir-B
|
||||
(if ediff-use-last-dir
|
||||
ediff-last-dir-B
|
||||
(file-name-directory f)))
|
||||
(progn
|
||||
(ediff-add-to-history
|
||||
'file-name-history
|
||||
(ediff-abbreviate-file-name
|
||||
(expand-file-name
|
||||
(file-name-nondirectory f)
|
||||
dir-B)))
|
||||
(ediff-get-default-file-name f 1)))
|
||||
(read-number "Batch size (in bytes): " vlf-batch-size))))
|
||||
(let ((buffer-A (vlf file-A)))
|
||||
(set-buffer buffer-A)
|
||||
(vlf-set-batch-size batch-size)
|
||||
(let ((buffer-B (vlf file-B)))
|
||||
(vlf-ediff-buffers buffer-A buffer-B))))
|
||||
|
||||
(defadvice ediff-next-difference (around vlf-ediff-next-difference
|
||||
compile activate)
|
||||
"Move to the next VLF chunk and search for difference if at the end\
|
||||
of difference list."
|
||||
(if (and vlf-ediff-session
|
||||
(<= (1- ediff-number-of-differences)
|
||||
ediff-current-difference))
|
||||
(let ((buffer-A ediff-buffer-A)
|
||||
(buffer-B ediff-buffer-B)
|
||||
(ediff-buffer (current-buffer)))
|
||||
(save-excursion
|
||||
(set-buffer buffer-A)
|
||||
(vlf-next-chunk)
|
||||
(set-buffer buffer-B)
|
||||
(vlf-next-chunk)
|
||||
(vlf-ediff-next buffer-A buffer-B ediff-buffer
|
||||
'vlf-next-chunk))
|
||||
(or (zerop ediff-number-of-differences)
|
||||
(ediff-jump-to-difference 1)))
|
||||
ad-do-it))
|
||||
|
||||
(defadvice ediff-previous-difference (around vlf-ediff-prev-difference
|
||||
compile activate)
|
||||
"Move to the previous VLF chunk and search for difference if at the\
|
||||
beginning of difference list."
|
||||
(if (and vlf-ediff-session
|
||||
(<= ediff-current-difference 0))
|
||||
(let ((buffer-A ediff-buffer-A)
|
||||
(buffer-B ediff-buffer-B)
|
||||
(ediff-buffer (current-buffer)))
|
||||
(save-excursion
|
||||
(set-buffer buffer-A)
|
||||
(vlf-prev-chunk)
|
||||
(set-buffer buffer-B)
|
||||
(vlf-prev-chunk)
|
||||
(vlf-ediff-next buffer-A buffer-B ediff-buffer
|
||||
'vlf-prev-chunk))
|
||||
(or (zerop ediff-number-of-differences)
|
||||
(ediff-jump-to-difference -1)))
|
||||
ad-do-it))
|
||||
|
||||
(defun vlf-next-chunk ()
|
||||
"Move to next chunk."
|
||||
(vlf-move-to-chunk vlf-end-pos (+ vlf-end-pos vlf-batch-size) t))
|
||||
|
||||
(defun vlf-prev-chunk ()
|
||||
"Move to previous chunk."
|
||||
(vlf-move-to-chunk (- vlf-start-pos vlf-batch-size) vlf-start-pos t))
|
||||
|
||||
(defun vlf-ediff-next (buffer-A buffer-B ediff-buffer
|
||||
&optional next-func)
|
||||
"Find next pair of chunks that differ in BUFFER-A and BUFFER-B\
|
||||
governed by EDIFF-BUFFER. NEXT-FUNC is used to jump to the next
|
||||
logical chunks in case there is no difference at the current ones."
|
||||
(set-buffer buffer-A)
|
||||
(run-hook-with-args 'vlf-before-batch-functions 'ediff)
|
||||
(setq buffer-A (current-buffer)) ;names change, so reference by buffer object
|
||||
(let ((end-A (= vlf-start-pos vlf-end-pos))
|
||||
(chunk-A (cons vlf-start-pos vlf-end-pos))
|
||||
(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)))
|
||||
(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))
|
||||
(let ((tramp-verbose (if (boundp 'tramp-verbose)
|
||||
(min tramp-verbose 2)))
|
||||
(end-B (= vlf-start-pos vlf-end-pos))
|
||||
(chunk-B (cons vlf-start-pos vlf-end-pos))
|
||||
(font-lock-B font-lock-mode)
|
||||
(done nil)
|
||||
(reporter (make-progress-reporter
|
||||
"Searching for difference..."
|
||||
(if forward-p vlf-start-pos
|
||||
(- min-file-size vlf-end-pos))
|
||||
min-file-size)))
|
||||
(font-lock-mode 0)
|
||||
(unwind-protect
|
||||
(progn
|
||||
(while (and (or (not end-A) (not end-B))
|
||||
(or (zerop (compare-buffer-substrings
|
||||
buffer-A (point-min) point-max-A
|
||||
buffer-B (point-min) (point-max)))
|
||||
(with-current-buffer ediff-buffer
|
||||
(ediff-update-diffs)
|
||||
(and (not end-A) (not end-B)
|
||||
(vlf-ediff-refine buffer-A
|
||||
buffer-B))
|
||||
(zerop ediff-number-of-differences))))
|
||||
(funcall next-func)
|
||||
(setq end-B (= vlf-start-pos vlf-end-pos))
|
||||
(with-current-buffer buffer-A
|
||||
(funcall next-func)
|
||||
(setq end-A (= vlf-start-pos vlf-end-pos)
|
||||
point-max-A (point-max)))
|
||||
(progress-reporter-update reporter
|
||||
(if forward-p vlf-end-pos
|
||||
(- vlf-file-size
|
||||
vlf-start-pos))))
|
||||
(progress-reporter-done reporter)
|
||||
(if (or (not end-A) (not end-B))
|
||||
(progn (vlf-update-buffer-name)
|
||||
(set-buffer buffer-A)
|
||||
(vlf-update-buffer-name))
|
||||
(if forward-p
|
||||
(let ((max-file-size vlf-file-size))
|
||||
(vlf-move-to-chunk (- max-file-size vlf-batch-size)
|
||||
max-file-size)
|
||||
(set-buffer buffer-A)
|
||||
(setq max-file-size (max max-file-size
|
||||
vlf-file-size))
|
||||
(vlf-move-to-chunk (- max-file-size
|
||||
vlf-batch-size)
|
||||
max-file-size))
|
||||
(vlf-beginning-of-file)
|
||||
(set-buffer buffer-A)
|
||||
(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)))
|
||||
(setq done t))
|
||||
(unless done
|
||||
(set-buffer buffer-A)
|
||||
(set-buffer-modified-p nil)
|
||||
(vlf-move-to-chunk (car chunk-A) (cdr chunk-A))
|
||||
(set-buffer buffer-B)
|
||||
(set-buffer-modified-p nil)
|
||||
(vlf-move-to-chunk (car chunk-B) (cdr chunk-B))
|
||||
(set-buffer ediff-buffer)
|
||||
(ediff-update-diffs)
|
||||
(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)
|
||||
(set-buffer buffer-B)
|
||||
(if font-lock-B (font-lock-mode 1))
|
||||
(run-hook-with-args 'vlf-after-batch-functions 'ediff)))))
|
||||
|
||||
(defun vlf-ediff-refine (buffer-A buffer-B)
|
||||
"Try to minimize differences between BUFFER-A and BUFFER-B.
|
||||
This can happen if first or last difference is at the start/end of
|
||||
buffer."
|
||||
(or (zerop ediff-number-of-differences)
|
||||
(let ((adjust-p (vlf-ediff-adjust buffer-A buffer-B)))
|
||||
(setq adjust-p (or (vlf-ediff-adjust buffer-A buffer-B t)
|
||||
adjust-p))
|
||||
(if adjust-p (ediff-update-diffs)))))
|
||||
|
||||
(defun vlf-ediff-adjust (buf-A buf-B &optional end)
|
||||
"Additionally adjust buffer borders for BUF-A and BUF-B.
|
||||
Adjust beginning if END is nil. Return t if refining is needed,
|
||||
nil otherwise."
|
||||
(let* ((diff-num (if end (1- ediff-number-of-differences) 0))
|
||||
(diff-A (ediff-get-diff-overlay diff-num 'A))
|
||||
(diff-B (ediff-get-diff-overlay diff-num 'B))
|
||||
diff-A-str diff-B-str adjust-p)
|
||||
(with-current-buffer buf-A
|
||||
(setq adjust-p (if end (= (overlay-end diff-A) (point-max))
|
||||
(= (overlay-start diff-A) (point-min)))
|
||||
diff-A-str (and adjust-p (buffer-substring-no-properties
|
||||
(overlay-start diff-A)
|
||||
(overlay-end diff-A))))
|
||||
(set-buffer buf-B)
|
||||
(setq adjust-p (and adjust-p
|
||||
(if end (= (overlay-end diff-B) (point-max))
|
||||
(= (overlay-start diff-B) (point-min))))
|
||||
diff-B-str (and adjust-p (buffer-substring-no-properties
|
||||
(overlay-start diff-B)
|
||||
(overlay-end diff-B))))
|
||||
(if adjust-p
|
||||
(let ((len-A (length diff-A-str))
|
||||
(len-B (length diff-B-str))
|
||||
(adjust-func (if end 'vlf-ediff-adjust-end
|
||||
'vlf-ediff-adjust-start)))
|
||||
(cond
|
||||
((< len-A len-B)
|
||||
(or (funcall adjust-func diff-A-str diff-B-str buf-B)
|
||||
(setq adjust-p nil)))
|
||||
((< len-B len-A)
|
||||
(or (funcall adjust-func diff-B-str diff-A-str buf-A)
|
||||
(setq adjust-p nil)))
|
||||
(t (setq adjust-p nil))))))
|
||||
adjust-p))
|
||||
|
||||
(defun vlf-ediff-adjust-start (diff-short diff-long vlf-buffer)
|
||||
"Remove difference between DIFF-SHORT and DIFF-LONG from beginning\
|
||||
of VLF-BUFFER."
|
||||
(when (string-suffix-p diff-short diff-long)
|
||||
(set-buffer vlf-buffer)
|
||||
(vlf-move-to-chunk (+ vlf-start-pos
|
||||
(length (encode-coding-string
|
||||
(substring diff-long 0
|
||||
(- (length diff-long)
|
||||
(length diff-short)))
|
||||
buffer-file-coding-system t)))
|
||||
vlf-end-pos)))
|
||||
|
||||
(defun vlf-ediff-adjust-end (diff-short diff-long vlf-buffer)
|
||||
"Remove difference between DIFF-SHORT and DIFF-LONG from the end of\
|
||||
VLF-BUFFER."
|
||||
(when (string-prefix-p diff-short diff-long)
|
||||
(set-buffer vlf-buffer)
|
||||
(vlf-move-to-chunk vlf-start-pos
|
||||
(- vlf-end-pos
|
||||
(length (encode-coding-string
|
||||
(substring diff-long
|
||||
(length diff-short))
|
||||
buffer-file-coding-system t))))))
|
||||
|
||||
(unless (fboundp 'string-suffix-p)
|
||||
(defun string-suffix-p (suffix string &optional ignore-case)
|
||||
"Return non-nil if SUFFIX is a suffix of STRING.
|
||||
If IGNORE-CASE is non-nil, the comparison is done without paying
|
||||
attention to case differences."
|
||||
(let ((start-pos (- (length string) (length suffix))))
|
||||
(and (>= start-pos 0)
|
||||
(eq t (compare-strings suffix nil nil string start-pos nil
|
||||
ignore-case))))))
|
||||
|
||||
(provide 'vlf-ediff)
|
||||
|
||||
;;; vlf-ediff.el ends here
|
||||
@@ -26,10 +26,8 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup vlf nil
|
||||
"View Large Files in Emacs."
|
||||
:prefix "vlf-"
|
||||
:group 'files)
|
||||
(defgroup vlf nil "View Large Files in Emacs."
|
||||
:prefix "vlf-" :group 'files)
|
||||
|
||||
(defcustom vlf-application 'ask
|
||||
"Determines when `vlf' will be offered on opening files.
|
||||
@@ -37,8 +35,7 @@ Possible values are: nil to never use it;
|
||||
`ask' offer `vlf' when file size is beyond `large-file-warning-threshold';
|
||||
`dont-ask' automatically use `vlf' for large files;
|
||||
`always' use `vlf' for all files."
|
||||
:group 'vlf
|
||||
:type '(radio (const :format "%v " nil)
|
||||
:group 'vlf :type '(radio (const :format "%v " nil)
|
||||
(const :format "%v " ask)
|
||||
(const :format "%v " dont-ask)
|
||||
(const :format "%v" always)))
|
||||
@@ -47,8 +44,7 @@ Possible values are: nil to never use it;
|
||||
'(archive-mode tar-mode jka-compr git-commit-mode image-mode
|
||||
doc-view-mode doc-view-mode-maybe ebrowse-tree-mode)
|
||||
"Major modes which VLF will not be automatically applied to."
|
||||
:group 'vlf
|
||||
:type '(list symbol))
|
||||
:group 'vlf :type '(list symbol))
|
||||
|
||||
(unless (fboundp 'file-size-human-readable)
|
||||
(defun file-size-human-readable (file-size)
|
||||
|
||||
14
vlf-occur.el
14
vlf-occur.el
@@ -131,21 +131,27 @@ Prematurely ending indexing will still show what's found so far."
|
||||
(set (make-local-variable 'vlf-batch-size) batch-size)
|
||||
(vlf-mode 1)
|
||||
(goto-char (point-min))
|
||||
(run-hook-with-args 'vlf-before-batch-functions 'occur)
|
||||
(vlf-with-undo-disabled
|
||||
(vlf-build-occur regexp vlf-buffer))))
|
||||
(vlf-build-occur regexp vlf-buffer))
|
||||
(run-hook-with-args 'vlf-after-batch-functions 'occur)))
|
||||
(run-hook-with-args 'vlf-before-batch-functions 'occur)
|
||||
(let ((start-pos vlf-start-pos)
|
||||
(end-pos vlf-end-pos)
|
||||
(pos (point)))
|
||||
(vlf-with-undo-disabled
|
||||
(vlf-beginning-of-file)
|
||||
(goto-char (point-min))
|
||||
(vlf-with-undo-disabled
|
||||
(unwind-protect (vlf-build-occur regexp (current-buffer))
|
||||
(vlf-move-to-chunk start-pos end-pos)
|
||||
(goto-char pos))))))
|
||||
(goto-char pos))))
|
||||
(run-hook-with-args 'vlf-after-batch-functions 'occur)))
|
||||
|
||||
(defun vlf-build-occur (regexp vlf-buffer)
|
||||
"Build occur style index for REGEXP over VLF-BUFFER."
|
||||
(let ((case-fold-search t)
|
||||
(let ((tramp-verbose (if (boundp 'tramp-verbose)
|
||||
(min tramp-verbose 2)))
|
||||
(case-fold-search t)
|
||||
(line 1)
|
||||
(last-match-line 0)
|
||||
(last-line-pos (point-min))
|
||||
|
||||
@@ -34,18 +34,23 @@
|
||||
BATCH-STEP is amount of overlap between successive chunks."
|
||||
(if (<= count 0)
|
||||
(error "Count must be positive"))
|
||||
(let* ((case-fold-search t)
|
||||
(run-hook-with-args 'vlf-before-batch-functions 'search)
|
||||
(let* ((tramp-verbose (if (boundp 'tramp-verbose)
|
||||
(min tramp-verbose 2)))
|
||||
(case-fold-search t)
|
||||
(match-chunk-start vlf-start-pos)
|
||||
(match-chunk-end vlf-end-pos)
|
||||
(match-start-pos (+ vlf-start-pos (position-bytes (point))))
|
||||
(match-end-pos match-start-pos)
|
||||
(to-find count)
|
||||
(font-lock font-lock-mode)
|
||||
(reporter (make-progress-reporter
|
||||
(concat "Searching for " regexp "...")
|
||||
(if backward
|
||||
(- vlf-file-size vlf-end-pos)
|
||||
vlf-start-pos)
|
||||
vlf-file-size)))
|
||||
(font-lock-mode 0)
|
||||
(vlf-with-undo-disabled
|
||||
(unwind-protect
|
||||
(catch 'end-of-file
|
||||
@@ -108,13 +113,15 @@ BATCH-STEP is amount of overlap between successive chunks."
|
||||
vlf-end-pos)))))
|
||||
(progress-reporter-done reporter))
|
||||
(set-buffer-modified-p nil)
|
||||
(if font-lock (font-lock-mode 1))
|
||||
(if backward
|
||||
(vlf-goto-match match-chunk-start match-chunk-end
|
||||
match-end-pos match-start-pos
|
||||
count to-find)
|
||||
(vlf-goto-match match-chunk-start match-chunk-end
|
||||
match-start-pos match-end-pos
|
||||
count to-find))))))
|
||||
count to-find))
|
||||
(run-hook-with-args 'vlf-after-batch-functions 'search)))))
|
||||
|
||||
(defun vlf-goto-match (match-chunk-start match-chunk-end
|
||||
match-pos-start
|
||||
@@ -175,23 +182,76 @@ Search is performed chunk by chunk in `vlf-batch-size' memory."
|
||||
"Go to line N. If N is negative, count from the end of file."
|
||||
(interactive (if (vlf-no-modifications)
|
||||
(list (read-number "Go to line: "))))
|
||||
(let ((start-pos vlf-start-pos)
|
||||
(run-hook-with-args 'vlf-before-batch-functions 'goto-line)
|
||||
(vlf-verify-size)
|
||||
(let ((tramp-verbose (if (boundp 'tramp-verbose)
|
||||
(min tramp-verbose 2)))
|
||||
(start-pos vlf-start-pos)
|
||||
(end-pos vlf-end-pos)
|
||||
(pos (point))
|
||||
(font-lock font-lock-mode)
|
||||
(success nil))
|
||||
(font-lock-mode 0)
|
||||
(unwind-protect
|
||||
(if (< 0 n)
|
||||
(progn (vlf-beginning-of-file)
|
||||
(let ((start 0)
|
||||
(end (min vlf-batch-size vlf-file-size))
|
||||
(reporter (make-progress-reporter
|
||||
(concat "Searching for line "
|
||||
(number-to-string n) "...")
|
||||
0 vlf-file-size))
|
||||
(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))
|
||||
(setq success (vlf-re-search "[\n\C-m]" (1- n)
|
||||
nil 0)))
|
||||
(vlf-end-of-file)
|
||||
(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))
|
||||
(setq success (vlf-re-search "[\n\C-m]" n nil 0)))))
|
||||
(let ((start (max 0 (- vlf-file-size vlf-batch-size)))
|
||||
(end vlf-file-size)
|
||||
(reporter (make-progress-reporter
|
||||
(concat "Searching for line -"
|
||||
(number-to-string n) "...")
|
||||
0 vlf-file-size))
|
||||
(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))
|
||||
(setq success (vlf-re-search "[\n\C-m]" (- n) t 0)))
|
||||
(if success
|
||||
(message "Onto line %s" n)
|
||||
(vlf-move-to-chunk start-pos end-pos)
|
||||
(goto-char pos)))))
|
||||
(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))
|
||||
(setq success (vlf-re-search "[\n\C-m]" n t 0))))))
|
||||
(if font-lock (font-lock-mode 1))
|
||||
(unless success
|
||||
(vlf-with-undo-disabled
|
||||
(vlf-move-to-chunk-2 start-pos end-pos))
|
||||
(vlf-update-buffer-name)
|
||||
(goto-char pos)
|
||||
(message "Unable to find line"))
|
||||
(run-hook-with-args 'vlf-after-batch-functions 'goto-line))))
|
||||
|
||||
(provide 'vlf-search)
|
||||
|
||||
|
||||
18
vlf-write.el
18
vlf-write.el
@@ -33,13 +33,13 @@
|
||||
"Write current chunk to file. Always return true to disable save.
|
||||
If changing size of chunk, shift remaining file content."
|
||||
(interactive)
|
||||
(and (buffer-modified-p)
|
||||
(when (and (buffer-modified-p)
|
||||
(or (verify-visited-file-modtime (current-buffer))
|
||||
(y-or-n-p "File has changed since visited or saved.\
|
||||
Save anyway? "))
|
||||
Save anyway? ")))
|
||||
(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)
|
||||
(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)
|
||||
@@ -52,17 +52,23 @@ Save anyway? "))
|
||||
region-length)))
|
||||
(if (zerop size-change)
|
||||
(write-region nil nil buffer-file-name vlf-start-pos t)
|
||||
(let ((pos (point)))
|
||||
(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))))))
|
||||
(goto-char pos)))))
|
||||
(run-hook-with-args 'vlf-after-batch-functions 'write))
|
||||
t)
|
||||
|
||||
(defun vlf-file-shift-back (size-change)
|
||||
|
||||
131
vlf.el
131
vlf.el
@@ -2,7 +2,7 @@
|
||||
|
||||
;; Copyright (C) 2006, 2012-2014 Free Software Foundation, Inc.
|
||||
|
||||
;; Version: 1.3
|
||||
;; Version: 1.5
|
||||
;; Keywords: large files, utilities
|
||||
;; Maintainer: Andrey Kotlarski <m00naticus@gmail.com>
|
||||
;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com>
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
;;; Commentary:
|
||||
;; This package provides the M-x vlf command, which visits part of
|
||||
;; large file without loading it entirely.
|
||||
;; The buffer uses VLF mode, which provides several commands for
|
||||
;; moving around, searching and editing selected part of file.
|
||||
;; large file without loading it entirely. The buffer uses VLF mode,
|
||||
;; which provides several commands for moving around, searching,
|
||||
;; comparing and editing selected part of file.
|
||||
;; To have it offered when opening large files:
|
||||
;; (require 'vlf-integrate)
|
||||
|
||||
@@ -39,20 +39,36 @@
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup vlf nil "View Large Files in Emacs."
|
||||
:prefix "vlf-" :group 'files)
|
||||
|
||||
(defcustom vlf-before-batch-functions nil
|
||||
"Hook that runs before multiple batch operations.
|
||||
One argument is supplied that specifies current action. Possible
|
||||
values are: `write', `ediff', `occur', `search', `goto-line'."
|
||||
:group 'vlf :type 'hook)
|
||||
|
||||
(defcustom vlf-after-batch-functions nil
|
||||
"Hook that runs after multiple batch operations.
|
||||
One argument is supplied that specifies current action. Possible
|
||||
values are: `write', `ediff', `occur', `search', `goto-line'."
|
||||
:group 'vlf :type 'hook)
|
||||
|
||||
(require 'vlf-base)
|
||||
|
||||
(autoload 'vlf-write "vlf-write" "Write current chunk to file.")
|
||||
(autoload 'vlf-write "vlf-write" "Write current chunk to file." t)
|
||||
(autoload 'vlf-re-search-forward "vlf-search"
|
||||
"Search forward for REGEXP prefix COUNT number of times.")
|
||||
"Search forward for REGEXP prefix COUNT number of times." t)
|
||||
(autoload 'vlf-re-search-backward "vlf-search"
|
||||
"Search backward for REGEXP prefix COUNT number of times.")
|
||||
(autoload 'vlf-goto-line "vlf-search" "Go to line.")
|
||||
"Search backward for REGEXP prefix COUNT number of times." t)
|
||||
(autoload 'vlf-goto-line "vlf-search" "Go to line." t)
|
||||
(autoload 'vlf-occur "vlf-occur"
|
||||
"Make whole file occur style index for REGEXP.")
|
||||
"Make whole file occur style index for REGEXP." t)
|
||||
(autoload 'vlf-toggle-follow "vlf-follow"
|
||||
"Toggle continuous chunk recenter around current point.")
|
||||
(autoload 'vlf-stop-follow "vlf-follow"
|
||||
"Stop continuous recenter.")
|
||||
"Toggle continuous chunk recenter around current point." t)
|
||||
(autoload 'vlf-stop-follow "vlf-follow" "Stop continuous recenter." t)
|
||||
(autoload 'vlf-ediff-buffers "vlf-ediff"
|
||||
"Run batch by batch ediff over VLF buffers." t)
|
||||
|
||||
(defvar vlf-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
@@ -71,6 +87,7 @@
|
||||
(define-key map "]" 'vlf-end-of-file)
|
||||
(define-key map "j" 'vlf-jump-to-chunk)
|
||||
(define-key map "l" 'vlf-goto-line)
|
||||
(define-key map "e" 'vlf-ediff-buffers)
|
||||
(define-key map "f" 'vlf-toggle-follow)
|
||||
(define-key map "g" 'vlf-revert)
|
||||
map)
|
||||
@@ -84,11 +101,8 @@
|
||||
|
||||
(define-minor-mode vlf-mode
|
||||
"Mode to browse large files in."
|
||||
:lighter " VLF"
|
||||
:group 'vlf
|
||||
:keymap vlf-prefix-map
|
||||
(if vlf-mode
|
||||
(progn
|
||||
:lighter " VLF" :group 'vlf :keymap vlf-prefix-map
|
||||
(cond (vlf-mode
|
||||
(set (make-local-variable 'require-final-newline) nil)
|
||||
(add-hook 'write-file-functions 'vlf-write nil t)
|
||||
(set (make-local-variable 'revert-buffer-function)
|
||||
@@ -100,27 +114,42 @@
|
||||
(let* ((pos (position-bytes (point)))
|
||||
(start (* (/ pos vlf-batch-size) vlf-batch-size)))
|
||||
(goto-char (byte-to-position (- pos start)))
|
||||
(vlf-move-to-batch start)))
|
||||
(kill-local-variable 'revert-buffer-function)
|
||||
(vlf-stop-follow)
|
||||
(when (or (not large-file-warning-threshold)
|
||||
(vlf-move-to-batch start))
|
||||
(add-hook 'after-change-major-mode-hook 'vlf-keep-alive t t)
|
||||
(vlf-keep-alive))
|
||||
((or (not large-file-warning-threshold)
|
||||
(< vlf-file-size large-file-warning-threshold)
|
||||
(y-or-n-p (format "Load whole file (%s)? "
|
||||
(file-size-human-readable
|
||||
vlf-file-size))))
|
||||
(kill-local-variable 'revert-buffer-function)
|
||||
(vlf-stop-follow)
|
||||
(kill-local-variable 'require-final-newline)
|
||||
(remove-hook 'write-file-functions 'vlf-write t)
|
||||
(remove-hook 'after-change-major-mode-hook
|
||||
'vlf-keep-alive t)
|
||||
(let ((hexl (derived-mode-p 'hexl-mode)))
|
||||
(if hexl (hexl-mode-exit))
|
||||
(let ((pos (+ vlf-start-pos (position-bytes (point)))))
|
||||
(vlf-with-undo-disabled
|
||||
(insert-file-contents buffer-file-name t nil nil t))
|
||||
(goto-char (byte-to-position pos)))
|
||||
(rename-buffer (file-name-nondirectory buffer-file-name) t))))
|
||||
(if hexl (hexl-mode)))
|
||||
(rename-buffer (file-name-nondirectory buffer-file-name) t))
|
||||
(t (setq vlf-mode t))))
|
||||
|
||||
(defun vlf-keep-alive ()
|
||||
"Keep `vlf-mode' on major mode change."
|
||||
(if (derived-mode-p 'hexl-mode)
|
||||
(set (make-local-variable 'revert-buffer-function) 'vlf-revert))
|
||||
(setq vlf-mode t))
|
||||
|
||||
;;;###autoload
|
||||
(defun vlf (file)
|
||||
"View Large FILE in batches.
|
||||
You can customize number of bytes displayed by customizing
|
||||
`vlf-batch-size'."
|
||||
`vlf-batch-size'.
|
||||
Return newly created buffer."
|
||||
(interactive "fFile to open: ")
|
||||
(let ((vlf-buffer (generate-new-buffer "*vlf*")))
|
||||
(set-buffer vlf-buffer)
|
||||
@@ -177,6 +206,51 @@ 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)
|
||||
|
||||
(eval-after-load "hexl"
|
||||
'(progn
|
||||
(defadvice hexl-save-buffer (around vlf-hexl-save
|
||||
activate compile)
|
||||
"Prevent hexl save if `vlf-mode' is active."
|
||||
(if vlf-mode
|
||||
(vlf-write)
|
||||
ad-do-it))
|
||||
|
||||
(defadvice hexl-scroll-up (around vlf-hexl-scroll-up
|
||||
activate compile)
|
||||
"Slide to next batch if at end of buffer in `vlf-mode'."
|
||||
(if (and vlf-mode (pos-visible-in-window-p (point-max))
|
||||
(or (not (numberp arg)) (< 0 arg)))
|
||||
(progn (vlf-next-batch 1)
|
||||
(goto-char (point-min)))
|
||||
ad-do-it))
|
||||
|
||||
(defadvice hexl-scroll-down (around vlf-hexl-scroll-down
|
||||
activate compile)
|
||||
"Slide to previous batch if at beginning of buffer in `vlf-mode'."
|
||||
(if (and vlf-mode (pos-visible-in-window-p (point-min)))
|
||||
(progn (vlf-prev-batch 1)
|
||||
(goto-char (point-max)))
|
||||
ad-do-it))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;; utilities
|
||||
|
||||
@@ -185,9 +259,13 @@ When prefix argument is negative
|
||||
Normally, the value is doubled;
|
||||
with the prefix argument DECREASE it is halved."
|
||||
(interactive "P")
|
||||
(setq vlf-batch-size (if decrease
|
||||
(/ vlf-batch-size 2)
|
||||
(* vlf-batch-size 2)))
|
||||
(vlf-set-batch-size (if decrease (/ vlf-batch-size 2)
|
||||
(* vlf-batch-size 2))))
|
||||
|
||||
(defun vlf-set-batch-size (size)
|
||||
"Set batch to SIZE bytes and update chunk."
|
||||
(interactive (list (read-number "Size in bytes: " vlf-batch-size)))
|
||||
(setq vlf-batch-size size)
|
||||
(vlf-move-to-batch vlf-start-pos))
|
||||
|
||||
(defun vlf-beginning-of-file ()
|
||||
@@ -198,6 +276,7 @@ with the prefix argument DECREASE it is halved."
|
||||
(defun vlf-end-of-file ()
|
||||
"Jump to end of file content."
|
||||
(interactive)
|
||||
(vlf-verify-size)
|
||||
(vlf-move-to-batch vlf-file-size))
|
||||
|
||||
(defun vlf-revert (&optional _ignore-auto noconfirm)
|
||||
|
||||
Reference in New Issue
Block a user