1
0
mirror of https://github.com/m00natic/vlfi.git synced 2025-11-09 03:21:39 +00:00

209 Commits
0.3 ... 1.4

Author SHA1 Message Date
Andrey Kotlarski
0199c2468a Lower tramp verbosity level when dealing with multiple batches. 2014-01-30 01:58:57 +02:00
Andrey Kotlarski
ffac6972ed Keep undo list after occur or unsuccessful line search. 2014-01-27 02:15:56 +02:00
Andrey Kotlarski
a71ee32508 Skip adjustment in some cases of overlapping chunk. 2014-01-27 01:18:07 +02:00
Andrey Kotlarski
9510c70860 Retry decoding when the initial attempt seems wrong. 2014-01-27 01:16:00 +02:00
Andrey Kotlarski
cc9b115486 Update docstring for vlf-ediff-adjust. 2014-01-23 02:30:02 +02:00
Andrey Kotlarski
f83a212c52 Temporarily disable font-lock during multiple batch operations. 2014-01-23 02:11:44 +02:00
Andrey Kotlarski
1a1ce27d37 Add progress reporters for the optimized part of line search. 2014-01-23 02:10:52 +02:00
Andrey Kotlarski
5c604c48a4 Optimize vlf-goto-line not to decode batches as long as possible. 2014-01-22 02:42:52 +02:00
Andrey Kotlarski
0fa8e8d6bf Update buffer name on user interruption during ediff. 2014-01-22 02:40:53 +02:00
Andrey Kotlarski
d7766f2a3b Update documentation and mark autoloaded functions as interactive. 2014-01-21 01:34:32 +02:00
Andrey Kotlarski
30d2bb0d25 VLF buffer ediff now starts from the current chunks. 2014-01-21 01:33:04 +02:00
Andrey Kotlarski
c533bce956 Add command to set batch size explicitly. 2014-01-21 01:32:21 +02:00
Andrey Kotlarski
5d30eb4826 Use single ediff pass to adjust borders. Protect against user
interruption while searching for difference.
2014-01-21 01:29:37 +02:00
Andrey Kotlarski
d5d9cd71ee Improve refining of differences and readjustment. 2014-01-20 02:40:26 +02:00
Andrey Kotlarski
e747de4495 Unify and optimize deletion. 2014-01-20 02:37:51 +02:00
Andrey Kotlarski
82fd5b943b Refine diff adjustment and in case of equality after it - make another
search for difference.
2014-01-18 16:26:25 +02:00
Andrey Kotlarski
9646b00215 Adjust chunk borders to minimize shift differences and optimize
detection of identical batches when ediff-ing.
2014-01-17 03:01:41 +02:00
Andrey Kotlarski
27e3bbb320 Reuse initial ediff session for all chunks. 2014-01-15 02:17:33 +02:00
Andrey Kotlarski
117935db98 Add progress reporter when searching for difference. 2014-01-14 01:11:59 +02:00
Andrey Kotlarski
38e8f6c4e1 Update file size when moving to end of buffer. 2014-01-14 01:11:07 +02:00
Andrey Kotlarski
98ddc3afd9 Add by batch Ediff functionality. 2014-01-13 01:36:20 +02:00
Andrey Kotlarski
4d82c781b8 - don't nullify default buffer coding system
- make vlf return the newly created VLF buffer
- simplify beginning and end jumps
2014-01-13 01:15:08 +02:00
Andrey Kotlarski
429a8ff016 Widen region when measuring encoded content length. 2014-01-11 19:00:00 +02:00
Andrey Kotlarski
88dba8bb25 Remove unnecessary addition to load-path on compile. 2014-01-07 23:49:56 +02:00
Andrey Kotlarski
47c154cc1f Fix detection of good chunk start. 2014-01-07 13:57:17 +02:00
Andrey Kotlarski
9343095096 Fix installation interfile dependencies and fix setting of local
variables for GNU Emasc 23.
2014-01-07 13:38:24 +02:00
Andrey Kotlarski
dd43af51ff Manually decode and use several bytes buffer when loading chunk. 2014-01-07 01:55:27 +02:00
Andrey Kotlarski
df8c9ea5dd Detect change of file when loading chunk and act more cautiously. Move
some functions around.
2014-01-07 01:54:00 +02:00
Andrey Kotlarski
0dc6d0643e Completely decouple vlf integration from other functionality. 2014-01-07 01:47:39 +02:00
Andrey Kotlarski
66db665d82 Fix follow functionality and explicitly set variable as buffer local. 2014-01-07 01:43:14 +02:00
Andrey Kotlarski
95e625938e Add convenience macro to disable VLF application during execution of
specific function.
2014-01-01 16:47:04 +02:00
Andrey Kotlarski
516584e6c9 Break VLF into components. 2014-01-01 16:42:45 +02:00
Andrey Kotlarski
deec75dfc9 Enlarge minimum sample chunk for decoding size. 2014-01-01 00:41:06 +02:00
Andrey Kotlarski
7794b2cab6 Merge branch 'shift-undo' into chunk-move
Conflicts:
	vlf.el
2013-12-31 22:21:51 +02:00
Andrey Kotlarski
161a4ec76e Prevent inserting of too small file regions for GNU Emacs later than
24.3.
2013-12-31 20:46:06 +02:00
Andrey Kotlarski
4f99eaa5e7 Fixes to tiny chunk moves. 2013-12-31 19:55:21 +02:00
Andrey Kotlarski
e36492b82f Optimize chunk jumping for current GNU Emacs releases. Fix moving by
just few bytes.
2013-12-25 03:18:29 +02:00
Andrey Kotlarski
2470fc0f67 Fix vlf-shift-undo-list to reverse resulting list. 2013-12-21 00:18:36 +02:00
Andrey Kotlarski
c58d0d84ff Shift buffer-undo-list elements when chunk beginning moves. 2013-12-18 02:24:02 +02:00
Andrey Kotlarski
386d85656c Restore undo information after temporarily disabling it. 2013-12-18 00:04:54 +02:00
Andrey Kotlarski
d88080f436 Don't apply VLF over ebrowse and TAGS databases. 2013-12-17 23:49:20 +02:00
Andrey Kotlarski
4134de068f Add intelligent recenter chunk around point functionality. 2013-12-13 17:23:16 +02:00
Andrey Kotlarski
290c4ac885 Fix save with adjustment. 2013-12-13 17:08:13 +02:00
Andrey Kotlarski
db1da304d5 Use buffer-file-truename for file size determination and remove
superfluous checks to vlf-verify-size when saving.  Fix vlf-revert not
to ask unnecessary.
2013-12-13 02:32:30 +02:00
Andrey Kotlarski
655805ce48 Fix vlf-next-batch-from-point behaviour near end of file. 2013-12-13 02:30:29 +02:00
Andrey Kotlarski
bb482f0b0f Fix file size determination for symbolic links. 2013-12-12 16:16:32 +02:00
Andrey Kotlarski
9ffb968793 Remove defadvice abort-if-file-too-large argument list so it works
correctly with GNU Emacs 23.
2013-12-12 14:47:28 +02:00
Andrey Kotlarski
099adab959 Fix abort-if-file-too-large advice not to activate VLF in case of empty
file.
2013-12-12 13:47:49 +02:00
Andrey Kotlarski
65b4d7413f Refactor vlf-write. 2013-12-12 02:20:03 +02:00
Andrey Kotlarski
2e2bca6999 Fix file size determination after save and move vlf-with-undo-disabled
macro before vlf-mode declaration.
2013-12-12 02:07:25 +02:00
Andrey Kotlarski
ea46386cbc Don't apply VLF by default over image and pdf files. 2013-12-11 16:15:26 +02:00
Andrey Kotlarski
d1af56d776 Fix opening of files for GNU Emacs 23. 2013-12-11 16:07:14 +02:00
Andrey Kotlarski
152462a654 Fix autoloads in last commit. 2013-12-11 16:01:12 +02:00
Andrey Kotlarski
9c50487982 Introduce list of major modes where VLF will not activate. 2013-12-11 15:58:35 +02:00
Andrey Kotlarski
88924f9c05 Fix vlf-write behaviour for newly created file. 2013-12-11 13:07:51 +02:00
Andrey Kotlarski
2aea17ab38 Fix behaviour when size is missing (creating file) in
abort-if-file-too-large, vlf-mode is started over existing buffer.
Rename default vlf-application value to `ask'.
2013-12-11 12:01:26 +02:00
Andrey Kotlarski
72fec35f44 Update README and bump version. 2013-12-11 03:21:08 +02:00
Andrey Kotlarski
a0cafa71ea Explicitly offer vlf-prefix-map so user can easily define another prefix
for vlf-mode-map.  Remove vlf-refresh and refine vlf-revert.
2013-12-11 02:56:01 +02:00
Andrey Kotlarski
c68c34ea90 Add vlf-application customization which refines control over when
vlf-mode is automatically invoked or offered.
2013-12-11 02:54:44 +02:00
Andrey Kotlarski
c0a85cdcfe Fix position when moving to overlapping chunk. 2013-12-11 02:51:46 +02:00
Andrey Kotlarski
371c560f4b Bump version and remove warning - save is now reliable. 2013-12-11 01:11:13 +02:00
Andrey Kotlarski
a3901b8f1a Fix deletion when moving to partially overlapping chunk and enable more
intelligent behaviour in cases of overlapping and modifications.
2013-12-09 01:55:41 +02:00
Andrey Kotlarski
f4ee23c07f Fix chunk end adjustment and save for current and older Emacsen. 2013-12-08 21:11:08 +02:00
Andrey Kotlarski
959bbc7661 Disable undo in cases of partial chunk move. 2013-12-08 17:22:23 +02:00
Andrey Kotlarski
0080991fa9 Fix chunk end adjustment and save for trunk Emacs. 2013-12-08 17:21:34 +02:00
Andrey Kotlarski
46e39a0fd8 Version 1.0. 2013-12-07 20:20:41 +02:00
Andrey Kotlarski
51d95ec0a3 Add command to display batch starting from point. 2013-12-07 20:18:07 +02:00
Andrey Kotlarski
d6c722376c Delete obsolete vlfi.el. 2013-12-07 19:50:19 +02:00
Andrey Kotlarski
a42247cac4 Automatically scroll to adjacent batch when start or end of chunk is
visible.
2013-12-04 15:11:04 +02:00
Andrey Kotlarski
3e8098af61 Rename vlf-discard-edit -> vlf-refresh. 2013-12-04 14:44:11 +02:00
Andrey Kotlarski
28646fbfee Reduce scope of vlf-with-undo-disabled usages. 2013-12-04 14:40:07 +02:00
Andrey Kotlarski
177c680288 Revert to showing batch size in buffer name instead of the mode-line. 2013-12-04 14:00:24 +02:00
Andrey Kotlarski
2ac3e7d577 Fix prematurely ending search/occur not to ask for modified buffer
confirmation.
2013-12-04 13:59:08 +02:00
Andrey Kotlarski
931ca52688 Stylistic refinements. 2013-12-04 00:20:02 +02:00
Andrey Kotlarski
42e581da61 Add command to unconditionally open fresh VLF buffer to visit occur
match.
2013-12-04 00:15:31 +02:00
Andrey Kotlarski
a65f3a431d Check for unsaved changes before search query and don't enable undo if
it was previously disabled.
2013-12-04 00:03:29 +02:00
Andrey Kotlarski
f34986a9b8 Update README. 2013-12-03 02:54:33 +02:00
Andrey Kotlarski
452b7eb42d Ensure there are no modifications when executing searches. 2013-12-03 02:37:13 +02:00
Andrey Kotlarski
2dba838015 In case original VLF buffer has been killed, try to find existing VLF
buffer for the same file when visiting occur results.
2013-12-03 02:04:27 +02:00
Andrey Kotlarski
cb47e19128 Use temporary buffer for occur in case of modifications. 2013-12-03 01:50:03 +02:00
Andrey Kotlarski
efae918a83 Turn vlf into minor mode. 2013-12-02 02:08:24 +02:00
Andrey Kotlarski
7a141091c8 Fix search for GNU Emacs 23 (no assert). 2013-08-26 12:29:39 +03:00
Andrey Kotlarski
8ab1c6a4f2 Disable undo and mark buffer as not modified when invoking search or
indexing.
2013-08-26 12:03:18 +03:00
Andrey Kotlarski
ae2237d7ea Minor adjustments:
- fix batch position formatting
- unconditionally update chunk on revert
- do nothing if same chunk is requested in `vlf-move-to-chunk'
2013-08-26 00:39:51 +03:00
Andrey Kotlarski
9b22b74f21 Add gitignore. 2013-08-25 23:01:55 +03:00
Andrey Kotlarski
025399a644 Merge branch 'master' into keep-edit
Conflicts:
	README.org
	vlfi.el
2013-08-25 19:17:04 +03:00
Andrey Kotlarski
bfcbfd33cb Make error message more descriptive. 2013-08-25 18:23:06 +03:00
Andrey Kotlarski
bc68eed5a2 Add dummy vlfi.el that urges move to the vlf package. 2013-08-25 18:14:53 +03:00
Andrey Kotlarski
17c66122d9 Rename anything vlfi -> vlf. 2013-08-25 17:57:43 +03:00
Andrey Kotlarski
4c631bcbe5 Rename vlfi.el to vlf.el. 2013-08-25 17:51:34 +03:00
Andrey Kotlarski
e5457690fb Fix adjusting of end chunk bytes. 2013-08-25 17:48:28 +03:00
Andrey Kotlarski
d1b34dcefb Add autoload cookie for `file-size-human-readable' not to break GNU
Emacs 23 opening of large files.
2013-08-13 12:39:55 +03:00
Andrey Kotlarski
737c1e9979 Remove encode size bookkeeping. 2013-08-09 02:00:34 +03:00
Andrey Kotlarski
2d71996d9e Add end character shift when adjusting chunk. Apply partial chunk
update when buffer is not modified too.
2013-08-09 01:59:32 +03:00
Andrey Kotlarski
0ecb40a5ee Keep as much editing as possible when moving to intersecting chunk. 2013-08-08 12:43:00 +03:00
Andrey Kotlarski
02a37c4192 Merge branch 'master' into chunk-opt2 2013-08-07 01:19:26 +03:00
Andrey Kotlarski
7cb047407d Add forgotten vlfi-encode-size local variable creation. 2013-08-06 16:41:16 +03:00
Andrey Kotlarski
34dfbd202d Use set-visited-file-name and abstract getting current file size and
updating visited time.
2013-08-06 16:23:04 +03:00
Andrey Kotlarski
ce9441fc83 Update info as VLFI is merging back to VLF. Bump version. 2013-08-06 02:14:39 +03:00
Andrey Kotlarski
563d9ca423 Fix vlfi-revert to revert on user confirmation. 2013-08-06 02:13:01 +03:00
Andrey Kotlarski
298d8f59d9 Keep track of current batch encoded size and allow fluctuation when
searching for proper decoding.
2013-08-06 02:11:21 +03:00
Andrey Kotlarski
8ed919209a Review fixes:
- move put statements to top level
- add write-file-functions hook locally
- vlfi-if-file-too-large becomes around advice
- minor style changes
2013-08-06 02:07:36 +03:00
Andrey Kotlarski
c1aedbc307 Update README: VLFI is now development version of VLF. 2013-08-06 02:02:02 +03:00
Andrey Kotlarski
a0b8d5f67a Merge pull request #3 from danlamanna/master
Alters vlfi to respect the default-directory variable when opening
files.
2013-07-25 01:17:35 -07:00
Dan LaManna
616d676330 Alters vlfi to respect the default-directory variable when opening
files.
2013-07-24 21:49:14 -04:00
Andrey Kotlarski
b943008eca Bump version and update README. 2013-06-09 02:34:52 +03:00
Andrey Kotlarski
4589c25d96 Return to current position after occur ending with quit. 2013-05-07 15:43:52 +03:00
Andrey Kotlarski
3c2fb6b93e Merge branch 'master' into chunk-opt2 2013-05-05 15:57:16 +03:00
Andrey Kotlarski
c827c3e186 Prevent standard save procedure invocation in case user postpones
saving.
2013-05-04 23:53:17 +03:00
Andrey Kotlarski
36d2ed4d09 Update README. 2013-05-02 14:25:39 +03:00
Andrey Kotlarski
de1948ed36 Merge branch 'master' into chunk-opt2 2013-05-02 14:19:50 +03:00
Andrey Kotlarski
ae775f88f9 Extend vlfi-goto-line to count lines from the end with negative
argument.
2013-05-02 14:18:41 +03:00
Andrey Kotlarski
1ac1eece40 Turn vlfi-get-file-size to function. 2013-05-02 12:04:12 +03:00
Andrey Kotlarski
bbda9abc7d Merge branch 'master' into chunk-opt2
Conflicts:
	vlfi.el
2013-05-01 02:25:39 +03:00
Andrey Kotlarski
67732485d8 Optimize a bit goto line. 2013-05-01 02:18:37 +03:00
Andrey Kotlarski
3d652fe71d Minor documentation fixes. 2013-05-01 02:02:28 +03:00
Andrey Kotlarski
7bfe665524 More secure chunk decode adjustment and minor fixes. 2013-05-01 01:51:36 +03:00
Andrey Kotlarski
ca13beac24 Try utf-8 and if not successful, auto detect when adjusting chunk for
proper decoding.
2013-04-28 01:12:07 +03:00
Andrey Kotlarski
d2bd47c2b4 More attempts to optimize decoding. 2013-04-24 01:32:50 +03:00
Andrey Kotlarski
57eb4c270a Initial attempt at optimizing chunk access. 2013-04-24 01:32:50 +03:00
Colin Marquardt
28255a2aa2 Correctly print MB (for older emacsen). 2013-04-23 19:15:43 +03:00
Andrey Kotlarski
fbe081417c Fix occur indexing not to skip last chunk. 2013-04-23 00:53:54 +03:00
Andrey Kotlarski
fd9c258fc8 Use permanent buffer local write hook and update README. 2013-04-17 14:46:50 +03:00
Andrey Kotlarski
a63ea7a5d0 Grammar fixes. 2013-04-17 13:19:37 +03:00
Andrey Kotlarski
fbc3a37ce5 Add tip for ability to change major mode and more section hierarchy. 2013-04-17 13:11:40 +03:00
Andrey Kotlarski
eaf85e5cff Add key-binding to vlfi-mode-map in vlfi-edit-mode-map. 2013-04-17 13:00:37 +03:00
Andrey Kotlarski
e4d886a3e3 Add check if VLFI buffer has been modified before occur jumping to new
chunk.
2013-04-17 12:49:29 +03:00
Andrey Kotlarski
b8cc34422e Add more detailed usage details. 2013-04-17 12:33:04 +03:00
Andrey Kotlarski
a5fec57e32 Mostly documentation and commentary added. 2013-04-17 11:55:02 +03:00
Andrey Kotlarski
70719b0917 Add vlfi-occur-show command for showing match but still staying in
occur buffer.
2013-04-17 11:53:49 +03:00
Andrey Kotlarski
54927afb8f Update README and bump version. 2013-04-16 15:56:10 +03:00
Andrey Kotlarski
f14ef6ce9e Usability improvements to vlfi-occur. 2013-04-16 15:51:30 +03:00
Andrey Kotlarski
1dcd12288b Use overlays for number indicators. 2013-04-16 15:38:36 +03:00
Andrey Kotlarski
641ff4b961 First feature complete version of vlfi-occur. 2013-04-16 14:44:34 +03:00
Andrey Kotlarski
681d3d94fc Add vlfi-occur-mode. 2013-04-16 12:25:06 +03:00
Andrey Kotlarski
ba439de0f6 Initial generation of vlfi-occur results. 2013-04-16 02:16:03 +03:00
Andrey Kotlarski
b34bd2e5fb Don't use temporary buffer when adjusting expanded file content. 2013-04-15 23:38:14 +03:00
Andrey Kotlarski
1589cf9736 Make custom revert function local only for vlfi buffers. 2013-04-15 17:42:11 +03:00
Andrey Kotlarski
83eb8a586b Fixes for GNU Emacs 23. 2013-04-15 17:27:23 +03:00
Andrey Kotlarski
e3be8d5d98 Don't adjust chunk with more that 3 bytes and inhibit spurious update
messages when saving content with changes size.
2013-04-15 15:04:22 +03:00
Andrey Kotlarski
5aef3e1c27 Update file size changes more lazily. 2013-04-15 01:26:58 +03:00
Andrey Kotlarski
ca8ba42ec4 Fix position handling to correctly deal with multibyte characters. 2013-04-15 00:57:10 +03:00
Andrey Kotlarski
a31be70613 Update README and bump version. 2013-04-14 20:01:10 +03:00
Andrey Kotlarski
538a9e6049 Apply chunk decoding adjustment implicitly. 2013-04-14 19:48:20 +03:00
Andrey Kotlarski
469900878d Make chunk adjusting automatic. 2013-04-14 19:28:41 +03:00
Andrey Kotlarski
473536e050 Add adjust command for cases where chunk starts with part of multibyte symbol. 2013-04-14 18:58:30 +03:00
Andrey Kotlarski
74febeb183 Remove ability to launch VLFI from file end. It's superseded by
vlfi-end-of-file and may break decoding of file.
2013-04-14 18:27:31 +03:00
Andrey Kotlarski
fc689d5c88 Make coding system conversion on write more idiomatic. 2013-04-14 18:19:49 +03:00
Andrey Kotlarski
3fb898e83a Add automatic batching when scrolling. 2013-04-14 02:50:31 +03:00
Andrey Kotlarski
f1ade8106c Add go to line command. 2013-04-14 02:21:49 +03:00
Andrey Kotlarski
e67895afc4 Optionally strip superfluous operations when inserting batches. 2013-04-14 01:09:13 +03:00
Andrey Kotlarski
4cbefdeeca Optimize chunk save buffers for multiple insert/erase operations. 2013-04-14 00:54:16 +03:00
Andrey Kotlarski
9fad430601 Fix positioning after save. 2013-04-14 00:53:24 +03:00
Andrey Kotlarski
6ea7a2aa1e Add macro for file size determination. 2013-04-14 00:52:07 +03:00
Andrey Kotlarski
705f9ce0eb Add issue section to the README. 2013-04-13 23:45:30 +03:00
Andrey Kotlarski
b52ca6c044 Don't change encoding for edited chunk, leave it to the user in case
of problem characters.
2013-04-13 23:45:06 +03:00
Andrey Kotlarski
8637ce5ceb Update README and version. 2013-04-13 23:10:47 +03:00
Andrey Kotlarski
2f201c56d5 Add jump to chunk command. 2013-04-13 22:57:09 +03:00
Andrey Kotlarski
d5f2a36086 Rearrange code in sections. 2013-04-13 22:49:08 +03:00
Andrey Kotlarski
cedd0b4e82 Fix spaces and indent. 2013-04-13 22:36:33 +03:00
Andrey Kotlarski
c14c7f00ce Add shift forward of file contents when edited chunk grows in size. 2013-04-13 22:34:54 +03:00
Andrey Kotlarski
f23262e826 Add shift back of file contents when edited chunk shrinks in size. 2013-04-13 20:47:29 +03:00
Andrey Kotlarski
8f6299c6c2 Simplify detection of buffer size change. 2013-04-13 01:29:12 +03:00
Andrey Kotlarski
8787186619 Show paging according to batch size instead of percentage. 2013-04-12 01:01:42 +03:00
Andrey Kotlarski
24675d8741 Manage modification times when attempting to save. 2013-04-12 00:21:14 +03:00
Andrey Kotlarski
e115e7e56a Add custom revert function. 2013-04-11 23:00:34 +03:00
Andrey Kotlarski
7985f0f453 Fix `vlfi-if-file-too-large' to be more tolerable on GNU Emacs 23. 2013-04-11 18:36:39 +03:00
Andrey Kotlarski
a3c405fd37 Make detection of buffer size change on save more correct when dealing
with Unicode.
2013-04-11 18:08:34 +03:00
Andrey Kotlarski
56134a8281 Make vlfi usable under GNU Emacs 23. 2013-04-11 17:45:35 +03:00
Andrey Kotlarski
2525ebf069 Improvements to file saving. 2013-04-11 17:44:32 +03:00
Andrey Kotlarski
c4f87f9ec7 Move save interception to vlfi-mode. 2013-04-11 16:53:38 +03:00
Andrey Kotlarski
467154ad06 Add documentation. 2013-04-10 02:10:00 +03:00
Andrey Kotlarski
06108220e2 Make saving with change of size correct. 2013-04-10 02:08:54 +03:00
Andrey Kotlarski
5405a30de4 Intercept buffer saving with vlfi-write. 2013-04-08 23:24:48 +03:00
Andrey Kotlarski
f3132c0970 Keep current position when moving around chunks. 2013-04-08 12:49:17 +03:00
Andrey Kotlarski
db3d2af04a Update version, README and commentary section. 2013-04-08 01:08:15 +03:00
Andrey Kotlarski
995a7a0988 Change some VLFI key-bindings not to override special-mode ones. 2013-04-08 00:57:53 +03:00
Andrey Kotlarski
1948f3ea4e Make VLFI edit mode actually working. 2013-04-08 00:56:42 +03:00
Andrey Kotlarski
0ff2f3eb9b Merge branch 'master' into edit 2013-04-07 18:54:40 +03:00
Andrey Kotlarski
03f323337b Don't reinsert content and move on successful search. 2013-04-07 18:53:50 +03:00
Andrey Kotlarski
9abee0425a Merge branch 'master' into edit 2013-04-05 00:43:15 +03:00
Andrey Kotlarski
80ca6b638b Fix vlfi invocation when prompted for large files. 2013-04-04 11:49:19 +03:00
Andrey Kotlarski
8a33dbfb89 Add something like edit minor mode. 2013-04-02 02:55:53 +03:00
Andrey Kotlarski
e387ed5f09 Add forgotten local variable statement and documentation. 2013-04-02 01:46:45 +03:00
Andrey Kotlarski
c36db11b86 Return correct search success status. 2013-04-01 14:38:50 +03:00
Andrey Kotlarski
ab20671a93 Abstract batch overlapping during search and optimize a bit. 2013-04-01 14:32:10 +03:00
Andrey Kotlarski
ac382e90dc Add temporary highlight of match. 2013-04-01 12:57:58 +03:00
Andrey Kotlarski
670561e811 Optimize search a bit. 2013-04-01 12:06:48 +03:00
Andrey Kotlarski
88cf03caba Interactive change of batch size immediately updates content. 2013-04-01 11:47:49 +03:00
Andrey Kotlarski
8e65e13dd9 Refactor and simplify search procedures. Always use batch sized
chunks.
2013-04-01 03:09:32 +03:00
Andrey Kotlarski
090cebc2ab Add procedure to insert strictly batch sized chunk (if possible). 2013-04-01 03:08:14 +03:00
Andrey Kotlarski
748fd1406e More key-binding simplification. 2013-04-01 03:07:20 +03:00
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
10 changed files with 1986 additions and 157 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.elc
*~

View File

@@ -1,4 +1,161 @@
* View Large File
* View Large Files
An Emacs mode that allows viewing files in chunks. This is a fork
that builds on the GNU ELPA vlf.el.
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 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:
- 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
- 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
- by batch Ediff comparison
- VLF is added as an option when opening large files
GNU Emacs 23 and 24 are supported.
* Overview and tips
M-x vlf PATH-TO-FILE
** Unicode
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.
** 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
integer value).
** Memory control
*vlf-batch-size* bounds the memory used for all operations.
* Detail usage
** Applicability
To have *vlf* offered as choice when opening large files:
#+BEGIN_EXAMPLE
(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:
#+BEGIN_EXAMPLE
(custom-set-variables
'(vlf-application 'dont-ask))
#+END_EXAMPLE
*** Disable for specific mode
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
*func* defined in file *file.el*:
#+BEGIN_EXAMPLE
(vlf-disable-for-function func "file")
#+END_EXAMPLE
** 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*):
#+BEGIN_EXAMPLE
(eval-after-load "vlf"
'(define-key vlf-prefix-map "\C-xv" vlf-mode-map))
#+END_EXAMPLE
** 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.
** Move around
Scrolling automatically triggers moving to previous or next chunk at
the beginning or end respectively of the current one.
*C-c C-v n* and *C-c C-v p* move batch by batch. With positive
prefix argument they move prefix number of batches. With negative -
append prefix number of batches.
*C-c C-v SPC* displays batch starting from current point.
*C-c C-v [* and *C-c C-v ]* take you to the beginning and end of file
respectively.
*C-c C-v j* jumps to given chunk. To see where you are in file and
how many chunks there are (using the current batch size), look at the
parenthesized part of the buffer name, batch size is also indicated at
the end.
** Follow point
Continuous chunk recenter around point in current buffer can be
toggled with *C-c C-v f*.
** Search whole file
*C-c C-v s* and *C-c C-v r* search forward and backward respectively
over the whole file. This is done batch by batch so if you have
really huge file - you'd better set somewhat bigger batch size
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.
** Jump to line
*C-c C-v l* jumps to given line in file. This is done by searching
from the beginning, so again the bigger current batch size, the
quicker. With negative argument, lines are counted from the end of
file.
** Edit and save
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.

420
vlf-base.el Normal file
View File

@@ -0,0 +1,420 @@
;;; vlf-base.el --- VLF primitive operations -*- lexical-binding: t -*-
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Keywords: large files, chunk
;; 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 basic chunk operations for VLF,
;; most notable being the `vlf-move-to-chunk' function.
;;; 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)
(put 'vlf-batch-size 'permanent-local t)
;;; Keep track of file position.
(defvar vlf-start-pos 0
"Absolute position of the visible chunk start.")
(make-variable-buffer-local 'vlf-start-pos)
(put 'vlf-start-pos 'permanent-local t)
(defvar vlf-end-pos 0 "Absolute position of the visible chunk end.")
(make-variable-buffer-local 'vlf-end-pos)
(put 'vlf-end-pos 'permanent-local t)
(defvar vlf-file-size 0 "Total size of presented file.")
(make-variable-buffer-local 'vlf-file-size)
(put 'vlf-file-size 'permanent-local t)
(defconst vlf-sample-size 24
"Minimal number of bytes that can be properly decoded.")
(defun vlf-get-file-size (file)
"Get size in bytes of FILE."
(or (nth 7 (file-attributes file)) 0))
(defun vlf-verify-size (&optional update-visited-time)
"Update file size information if necessary and visited file time.
If non-nil, UPDATE-VISITED-TIME."
(unless (verify-visited-file-modtime (current-buffer))
(setq vlf-file-size (vlf-get-file-size buffer-file-truename))
(if update-visited-time
(set-visited-file-modtime))))
(unless (fboundp 'file-size-human-readable)
(defun file-size-human-readable (file-size)
"Print FILE-SIZE in MB."
(format "%.3fMB" (/ file-size 1048576.0))))
(defun vlf-update-buffer-name ()
"Update the current buffer name."
(rename-buffer (format "%s(%d/%d)[%s]"
(file-name-nondirectory buffer-file-name)
(/ vlf-end-pos vlf-batch-size)
(/ vlf-file-size vlf-batch-size)
(file-size-human-readable vlf-batch-size))
t))
(defmacro vlf-with-undo-disabled (&rest body)
"Execute BODY with temporarily disabled undo."
`(let ((undo-list buffer-undo-list))
(setq buffer-undo-list t)
(unwind-protect (progn ,@body)
(setq buffer-undo-list undo-list))))
(defun vlf-move-to-chunk (start end &optional minimal)
"Move to chunk enclosed by START END bytes.
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."
(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))))
(defun vlf-move-to-chunk-1 (start end)
"Move to chunk enclosed by START END keeping as much edits if any.
Return number of bytes moved back for proper decoding and number of
bytes added to the end."
(widen)
(let* ((modified (buffer-modified-p))
(start (max 0 start))
(end (min end vlf-file-size))
(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? "))
(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)
(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."
(vlf-verify-size t)
(setq vlf-start-pos (max 0 start)
vlf-end-pos (min end vlf-file-size))
(let (shifts)
(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)))
(goto-char (or (byte-to-position (+ pos (car shifts)))
(point-max)))))
(set-buffer-modified-p nil)
(setq buffer-undo-list nil)
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\
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
bytes added to the end."
(setq adjust-start (and adjust-start (not (zerop start)))
adjust-end (and adjust-end (< end vlf-file-size))
position (or position (point-min)))
(goto-char position)
(let ((shift-start 0)
(shift-end 0)
(safe-end (if adjust-end
(min vlf-file-size (+ end 4))
end)))
(if adjust-start
(setq shift-start (vlf-adjust-start start safe-end position
adjust-end)
start (- start shift-start))
(vlf-insert-file-contents-1 start safe-end position))
(if adjust-end
(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 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)))
(when (eq (detect-coding-region position (min (+ position
vlf-sample-size)
(point-max)) t)
'no-conversion)
(delete-region position (point-max))
(insert-file-contents-literally buffer-file-name nil start end)
(let ((coding-system-for-read nil))
(decode-coding-inserted-region position (point-max)
buffer-file-name nil start end)))
(setq buffer-file-coding-system last-coding-system-used))
(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.
ADJUST-END is non-nil if end would be adjusted later.
Return number of bytes moved back for proper decoding."
(let* ((safe-start (max 0 (- start 4)))
(sample-end (min end (+ safe-start vlf-sample-size)))
(chunk-size (- sample-end safe-start))
(strict (or (= sample-end vlf-file-size)
(and (not adjust-end) (= sample-end end))))
(shift 0))
(while (and (progn (vlf-insert-file-contents-1
safe-start sample-end position)
(not (zerop safe-start)))
(< shift 3)
(let ((diff (- chunk-size
(length
(encode-coding-region
position (point-max)
buffer-file-coding-system t)))))
(if strict
(not (zerop diff))
(or (< diff -3) (< 0 diff)))))
(setq shift (1+ shift)
safe-start (1- safe-start)
chunk-size (1+ chunk-size))
(delete-region position (point-max)))
(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-1 safe-start end position))
(- start safe-start)))
(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)))
(+ 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)
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)
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."
(or (eq buffer-undo-list t)
(setq buffer-undo-list
(nreverse
(let ((min (point-min))
undo-list)
(catch 'end
(dolist (el buffer-undo-list undo-list)
(push
(cond
((null el) nil)
((numberp el) (let ((pos (+ el n)))
(if (< pos min)
(throw 'end undo-list)
pos)))
(t (let ((head (car el)))
(cond ((numberp head)
(let ((beg (+ head n)))
(if (< beg min)
(throw 'end undo-list)
(cons beg (+ (cdr el) n)))))
((stringp head)
(let* ((pos (cdr el))
(positive (< 0 pos))
(new (+ (abs pos) n)))
(if (< new min)
(throw 'end undo-list)
(cons head (if positive
new
(- new))))))
((null head)
(let ((beg (+ (nth 3 el) n)))
(if (< beg min)
(throw 'end undo-list)
(cons
nil
(cons
(cadr el)
(cons
(nth 2 el)
(cons beg
(+ (cddr
(cddr el)) n))))))))
((and (eq head 'apply)
(numberp (cadr el)))
(let ((beg (+ (nth 2 el) n)))
(if (< beg min)
(throw 'end undo-list)
(cons
'apply
(cons
(cadr el)
(cons
beg
(cons
(+ (nth 3 el) n)
(cons (nth 4 el)
(cdr (last el))))))))))
(t el)))))
undo-list))))))))
(provide 'vlf-base)
;;; vlf-base.el ends here

325
vlf-ediff.el Normal file
View File

@@ -0,0 +1,325 @@
;;; vlf-ediff.el --- VLF ediff functionality
;; 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)
(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)
(setq buffer-B (current-buffer)
min-file-size (min min-file-size vlf-file-size))
(let ((tramp-verbose (min 2 tramp-verbose))
(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))
(when font-lock-A
(set-buffer buffer-A)
(font-lock-mode 1))
(when font-lock-B
(set-buffer buffer-B)
(font-lock-mode 1))
(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))))))
(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

85
vlf-follow.el Normal file
View File

@@ -0,0 +1,85 @@
;;; vlf-follow.el --- VLF chunk follows point functionality -*- lexical-binding: t -*-
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Keywords: large files, follow, recenter
;; 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 `vlf-toggle-follow' command which toggles
;; continuous recenter of chunk around current point.
;;; Code:
(require 'vlf)
(defvar vlf-follow-timer nil
"Contains timer if vlf buffer is set to continuously recenter.")
(make-variable-buffer-local 'vlf-follow-timer)
(put 'vlf-follow-timer 'permanent-local t)
(defun vlf-recenter (vlf-buffer)
"Recenter chunk around current point in VLF-BUFFER."
(and vlf-follow-timer
(eq (current-buffer) vlf-buffer)
(or (pos-visible-in-window-p (point-min))
(pos-visible-in-window-p (point-max)))
(let ((current-pos (+ vlf-start-pos (position-bytes (point))))
(half-batch (/ vlf-batch-size 2)))
(if (buffer-modified-p)
(progn
(let ((edit-end (+ (position-bytes (point-max))
vlf-start-pos)))
(vlf-move-to-chunk (min vlf-start-pos
(- current-pos half-batch))
(max edit-end
(+ current-pos half-batch))))
(goto-char (byte-to-position (- current-pos
vlf-start-pos))))
(vlf-move-to-batch (- current-pos half-batch))
(and (< half-batch current-pos)
(< half-batch (- vlf-file-size current-pos))
(goto-char (byte-to-position (- current-pos
vlf-start-pos))))))))
(defun vlf-stop-follow ()
"Stop continuous recenter."
(when vlf-follow-timer
(cancel-timer vlf-follow-timer)
(setq vlf-follow-timer nil)))
(defun vlf-start-follow (interval)
"Continuously recenter chunk around point every INTERVAL seconds."
(setq vlf-follow-timer (run-with-idle-timer interval interval
'vlf-recenter
(current-buffer)))
(add-hook 'kill-buffer-hook 'vlf-stop-follow nil t))
(defun vlf-toggle-follow ()
"Toggle continuous chunk recenter around current point."
(interactive)
(if vlf-mode
(if vlf-follow-timer
(progn (vlf-stop-follow)
(message "Following stopped"))
(vlf-start-follow (read-number "Number of seconds: " 1)))))
(provide 'vlf-follow)
;;; vlf-follow.el ends here

156
vlf-integrate.el Normal file
View File

@@ -0,0 +1,156 @@
;;; vlf-integrate.el --- VLF integration with other packages -*- lexical-binding: t -*-
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Keywords: large files, integration
;; 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 enables VLF play seamlessly with rest of Emacs.
;;; Code:
(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.
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)
(const :format "%v " ask)
(const :format "%v " dont-ask)
(const :format "%v" always)))
(defcustom vlf-forbidden-modes-list
'(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))
(unless (fboundp 'file-size-human-readable)
(defun file-size-human-readable (file-size)
"Print FILE-SIZE in MB."
(format "%.3fMB" (/ file-size 1048576.0))))
(defun vlf-determine-major-mode (filename)
"Determine major mode from FILENAME."
(let ((name filename)
(remote-id (file-remote-p filename))
mode)
;; Remove backup-suffixes from file name.
(setq name (file-name-sans-versions name))
;; Remove remote file name identification.
(and (stringp remote-id)
(string-match (regexp-quote remote-id) name)
(setq name (substring name (match-end 0))))
(setq mode
(if (memq system-type '(windows-nt cygwin))
;; System is case-insensitive.
(let ((case-fold-search t))
(assoc-default name auto-mode-alist 'string-match))
;; System is case-sensitive.
(or ;; First match case-sensitively.
(let ((case-fold-search nil))
(assoc-default name auto-mode-alist 'string-match))
;; Fallback to case-insensitive match.
(and auto-mode-case-fold
(let ((case-fold-search t))
(assoc-default name auto-mode-alist
'string-match))))))
(if (and mode (consp mode))
(cadr mode)
mode)))
(autoload 'vlf "vlf" "View Large FILE in batches." t)
(defadvice abort-if-file-too-large (around vlf-if-file-too-large
compile activate)
"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."
(cond
((or (not size) (zerop size)))
((or (not vlf-application)
(not filename)
(memq (vlf-determine-major-mode filename)
vlf-forbidden-modes-list))
ad-do-it)
((eq vlf-application 'always)
(vlf filename)
(error ""))
((and large-file-warning-threshold
(< large-file-warning-threshold size))
(if (eq vlf-application 'dont-ask)
(progn (vlf filename)
(error ""))
(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)"
(if filename
(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 '(?v ?V))
(vlf filename)
(error ""))
((memq char '(?a ?A))
(error "Aborted"))))))))
;; disable for some functions
(defmacro vlf-disable-for-function (func file)
"Build advice to disable VLF during execution of FUNC\
defined in FILE."
`(eval-after-load ,file
'(defadvice ,func (around ,(intern (concat "vlf-"
(symbol-name func)))
compile activate)
"Temporarily disable `vlf-mode'."
(let ((vlf-application nil))
ad-do-it))))
(vlf-disable-for-function tags-verify-table "etags")
(vlf-disable-for-function tag-find-file-of-tag-noselect "etags")
(vlf-disable-for-function helm-etags-create-buffer "helm-tags")
;; dired
(defun dired-vlf ()
"In Dired, visit the file on this line in VLF mode."
(interactive)
(vlf (dired-get-file-for-visit)))
(eval-after-load "dired"
'(define-key dired-mode-map "V" 'dired-vlf))
(provide 'vlf-integrate)
;;; vlf-integrate.el ends here

251
vlf-occur.el Normal file
View File

@@ -0,0 +1,251 @@
;;; vlf-occur.el --- Occur-like functionality for VLF -*- lexical-binding: t -*-
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Keywords: large files, indexing, occur
;; 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 the `vlf-occur' command which builds
;; index of search occurrences in large file just like occur.
;;; Code:
(require 'vlf)
(defvar vlf-occur-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "n" 'vlf-occur-next-match)
(define-key map "p" 'vlf-occur-prev-match)
(define-key map "\C-m" 'vlf-occur-visit)
(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)
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.")
(defun vlf-occur-next-match ()
"Move cursor to next match."
(interactive)
(if (eq (get-char-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)
'face 'match))))
(defun vlf-occur-prev-match ()
"Move cursor to previous match."
(interactive)
(if (eq (get-char-property (point) 'face) 'match)
(goto-char (previous-single-property-change (point) 'face)))
(while (not (eq (get-char-property (point) 'face) 'match))
(goto-char (or (previous-single-property-change (point) 'face)
(point-max)))))
(defun vlf-occur-show (&optional event)
"Visit current `vlf-occur' link in a vlf buffer but stay in the \
occur buffer. If original VLF buffer has been killed,
open new VLF session each time.
EVENT may hold details of the invocation."
(interactive (list last-nonmenu-event))
(let ((occur-buffer (if event
(window-buffer (posn-window
(event-end event)))
(current-buffer))))
(vlf-occur-visit event)
(pop-to-buffer occur-buffer)))
(defun vlf-occur-visit-new-buffer ()
"Visit `vlf-occur' link in new vlf buffer."
(interactive)
(let ((current-prefix-arg t))
(vlf-occur-visit)))
(defun vlf-occur-visit (&optional event)
"Visit current `vlf-occur' link in a vlf buffer.
With prefix argument or if original VLF buffer has been killed,
open new VLF session.
EVENT may hold details of the invocation."
(interactive (list last-nonmenu-event))
(when event
(set-buffer (window-buffer (posn-window (event-end event))))
(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))
(occur-buffer (current-buffer))
(match-pos (+ (get-char-property pos 'line-pos)
pos-relative)))
(cond (current-prefix-arg
(setq vlf-buffer (vlf file))
(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)))
(pop-to-buffer vlf-buffer)
(vlf-move-to-chunk chunk-start chunk-end)
(goto-char match-pos)))))
(defun vlf-occur (regexp)
"Make whole file occur style index for REGEXP.
Prematurely ending indexing will still show what's found so far."
(interactive (list (read-regexp "List lines matching regexp"
(if regexp-history
(car regexp-history)))))
(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))
(with-temp-buffer
(setq buffer-file-name file)
(set-buffer-modified-p nil)
(set (make-local-variable 'vlf-batch-size) batch-size)
(vlf-mode 1)
(goto-char (point-min))
(vlf-with-undo-disabled
(vlf-build-occur regexp vlf-buffer))))
(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))
(unwind-protect (vlf-build-occur regexp (current-buffer))
(vlf-move-to-chunk start-pos end-pos)
(goto-char pos))))))
(defun vlf-build-occur (regexp vlf-buffer)
"Build occur style index for REGEXP over VLF-BUFFER."
(let ((tramp-verbose (min 2 tramp-verbose))
(case-fold-search t)
(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
(concat "*VLF-occur " (file-name-nondirectory
buffer-file-name)
"*")))
(line-regexp (concat "\\(?5:[\n\C-m]\\)\\|\\(?10:"
regexp "\\)"))
(batch-step (/ vlf-batch-size 8))
(end-of-file nil)
(reporter (make-progress-reporter
(concat "Building index for " regexp "...")
vlf-start-pos vlf-file-size)))
(unwind-protect
(progn
(while (not end-of-file)
(if (re-search-forward line-regexp nil t)
(progn
(setq match-end-pos (+ vlf-start-pos
(position-bytes
(match-end 0))))
(if (match-string 5)
(setq line (1+ line) ; line detected
last-line-pos (point))
(let* ((chunk-start vlf-start-pos)
(chunk-end vlf-end-pos)
(line-pos (line-beginning-position))
(line-text (buffer-substring
line-pos (line-end-position))))
(with-current-buffer occur-buffer
(unless (= line last-match-line) ;new match line
(insert "\n:") ; insert line number
(let* ((overlay-pos (1- (point)))
(overlay (make-overlay
overlay-pos
(1+ overlay-pos))))
(overlay-put overlay 'before-string
(propertize
(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)
'line-pos line-pos
'help-echo
(format "Move to line %d"
line))))
(setq last-match-line line
total-matches (1+ total-matches))
(let ((line-start (1+
(line-beginning-position)))
(match-pos (match-beginning 10)))
(add-text-properties ; mark match
(+ line-start match-pos (- last-line-pos))
(+ line-start (match-end 10)
(- last-line-pos))
(list 'face 'match
'help-echo
(format "Move to match %d"
total-matches))))))))
(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)))
(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)
(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\" \
in file: %s" total-matches line regexp file)
'face 'underline))
(set-buffer-modified-p nil)
(forward-char 2)
(vlf-occur-mode))
(display-buffer occur-buffer)))))
(provide 'vlf-occur)
;;; vlf-occur.el ends here

251
vlf-search.el Normal file
View File

@@ -0,0 +1,251 @@
;;; vlf-search.el --- Search functionality for VLF -*- lexical-binding: t -*-
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Keywords: large files, search
;; 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 search utilities for dealing with large files
;; in constant memory.
;;; Code:
(require 'vlf)
(defun vlf-re-search (regexp count backward batch-step)
"Search for REGEXP COUNT number of times forward or BACKWARD.
BATCH-STEP is amount of overlap between successive chunks."
(if (<= count 0)
(error "Count must be positive"))
(let* ((tramp-verbose (min 2 tramp-verbose))
(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
(if backward
(while (not (zerop to-find))
(cond ((re-search-backward regexp nil t)
(setq to-find (1- to-find)
match-chunk-start vlf-start-pos
match-chunk-end vlf-end-pos
match-start-pos (+ vlf-start-pos
(position-bytes
(match-beginning 0)))
match-end-pos (+ vlf-start-pos
(position-bytes
(match-end 0)))))
((zerop vlf-start-pos)
(throw 'end-of-file nil))
(t (let ((batch-move (- vlf-start-pos
(- 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
(- match-start-pos
vlf-start-pos))
(point-max))
(point-max)))
(progress-reporter-update
reporter (- vlf-file-size
vlf-start-pos)))))
(while (not (zerop to-find))
(cond ((re-search-forward regexp nil t)
(setq to-find (1- to-find)
match-chunk-start vlf-start-pos
match-chunk-end vlf-end-pos
match-start-pos (+ vlf-start-pos
(position-bytes
(match-beginning 0)))
match-end-pos (+ vlf-start-pos
(position-bytes
(match-end 0)))))
((= vlf-end-pos vlf-file-size)
(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
(- match-end-pos
vlf-start-pos))
(point-min))
(point-min)))
(progress-reporter-update reporter
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))))))
(defun vlf-goto-match (match-chunk-start match-chunk-end
match-pos-start
match-pos-end
count to-find)
"Move to MATCH-CHUNK-START MATCH-CHUNK-END surrounding \
MATCH-POS-START and MATCH-POS-END.
According to COUNT and left TO-FIND, show if search has been
successful. Return nil if nothing found."
(if (= count to-find)
(progn (vlf-move-to-chunk match-chunk-start match-chunk-end)
(goto-char (or (byte-to-position (- match-pos-start
vlf-start-pos))
(point-max)))
(message "Not found")
nil)
(let ((success (zerop to-find)))
(if success
(vlf-update-buffer-name)
(vlf-move-to-chunk match-chunk-start match-chunk-end))
(let* ((match-end (or (byte-to-position (- match-pos-end
vlf-start-pos))
(point-max)))
(overlay (make-overlay (byte-to-position
(- match-pos-start
vlf-start-pos))
match-end)))
(overlay-put overlay 'face 'match)
(unless success
(goto-char match-end)
(message "Moved to the %d match which is last"
(- count to-find)))
(unwind-protect (sit-for 3)
(delete-overlay overlay))
t))))
(defun vlf-re-search-forward (regexp count)
"Search forward for REGEXP prefix COUNT number of times.
Search is performed chunk by chunk in `vlf-batch-size' memory."
(interactive (if (vlf-no-modifications)
(list (read-regexp "Search whole file"
(if regexp-history
(car regexp-history)))
(or current-prefix-arg 1))))
(vlf-re-search regexp count nil (/ vlf-batch-size 8)))
(defun vlf-re-search-backward (regexp count)
"Search backward for REGEXP prefix COUNT number of times.
Search is performed chunk by chunk in `vlf-batch-size' memory."
(interactive (if (vlf-no-modifications)
(list (read-regexp "Search whole file backward"
(if regexp-history
(car regexp-history)))
(or current-prefix-arg 1))))
(vlf-re-search regexp count t (/ vlf-batch-size 8)))
(defun vlf-goto-line (n)
"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: "))))
(vlf-verify-size)
(let ((tramp-verbose (min 2 tramp-verbose))
(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)
(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))
(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))
(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))
(goto-char pos)
(message "Unable to find line")))))
(provide 'vlf-search)
;;; vlf-search.el ends here

151
vlf-write.el Normal file
View File

@@ -0,0 +1,151 @@
;;; vlf-write.el --- Saving functionality for VLF -*- lexical-binding: t -*-
;; Copyright (C) 2014 Free Software Foundation, Inc.
;; Keywords: large files, saving
;; 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 the `vlf-write' command which takes care of
;; saving changes where only part of file is viewed and updated.
;;; Code:
(require 'vlf-base)
(defun vlf-write ()
"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)
(or (verify-visited-file-modtime (current-buffer))
(y-or-n-p "File has changed since visited or saved. \
Save anyway? "))
(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 (min 2 tramp-verbose))
(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))))))
t)
(defun vlf-file-shift-back (size-change)
"Shift file contents SIZE-CHANGE bytes back."
(write-region nil nil buffer-file-name vlf-start-pos t)
(let ((read-start-pos vlf-end-pos)
(coding-system-for-write 'no-conversion)
(reporter (make-progress-reporter "Adjusting file content..."
vlf-end-pos
vlf-file-size)))
(vlf-with-undo-disabled
(while (vlf-shift-batch read-start-pos (- read-start-pos
size-change))
(setq read-start-pos (+ read-start-pos vlf-batch-size))
(progress-reporter-update reporter read-start-pos))
;; pad end with space
(erase-buffer)
(vlf-verify-size t)
(insert-char 32 size-change))
(write-region nil nil buffer-file-name (- vlf-file-size
size-change) t)
(progress-reporter-done reporter)))
(defun vlf-shift-batch (read-pos write-pos)
"Read `vlf-batch-size' bytes from READ-POS and write them \
back at WRITE-POS. Return nil if EOF is reached, t otherwise."
(erase-buffer)
(vlf-verify-size t)
(let ((read-end (+ read-pos vlf-batch-size)))
(insert-file-contents-literally buffer-file-name nil
read-pos
(min vlf-file-size read-end))
(write-region nil nil buffer-file-name write-pos 0)
(< read-end vlf-file-size)))
(defun vlf-file-shift-forward (size-change)
"Shift file contents SIZE-CHANGE bytes forward.
Done by saving content up front and then writing previous batch."
(let ((read-size (max (/ vlf-batch-size 2) size-change))
(read-pos vlf-end-pos)
(write-pos vlf-start-pos)
(reporter (make-progress-reporter "Adjusting file content..."
vlf-start-pos
vlf-file-size)))
(vlf-with-undo-disabled
(when (vlf-shift-batches read-size read-pos write-pos t)
(setq write-pos (+ read-pos size-change)
read-pos (+ read-pos read-size))
(progress-reporter-update reporter write-pos)
(let ((coding-system-for-write 'no-conversion))
(while (vlf-shift-batches read-size read-pos write-pos nil)
(setq write-pos (+ read-pos size-change)
read-pos (+ read-pos read-size))
(progress-reporter-update reporter write-pos)))))
(progress-reporter-done reporter)))
(defun vlf-shift-batches (read-size read-pos write-pos hide-read)
"Append READ-SIZE bytes of file starting at READ-POS.
Then write initial buffer content to file at WRITE-POS.
If HIDE-READ is non nil, temporarily hide literal read content.
Return nil if EOF is reached, t otherwise."
(vlf-verify-size t)
(let ((read-more (< read-pos vlf-file-size))
(start-write-pos (point-min))
(end-write-pos (point-max)))
(when read-more
(goto-char end-write-pos)
(insert-file-contents-literally buffer-file-name nil read-pos
(min vlf-file-size
(+ read-pos read-size))))
;; write
(if hide-read ; hide literal region if user has to choose encoding
(narrow-to-region start-write-pos end-write-pos))
(write-region start-write-pos end-write-pos
buffer-file-name write-pos 0)
(delete-region start-write-pos end-write-pos)
(if hide-read (widen))
read-more))
(provide 'vlf-write)
;;; vlf-write.el ends here

339
vlf.el
View File

@@ -1,13 +1,14 @@
;;; vlf.el --- View Large Files
;;; -*- lexical-bind: t -*-
;;; vlf.el --- View Large Files -*- lexical-binding: t -*-
;; Copyright (C) 2006, 2012, 2013 Free Software Foundation, Inc.
;; Copyright (C) 2006, 2012-2014 Free Software Foundation, Inc.
;; Version: 0.3
;; Version: 1.4
;; Keywords: large files, utilities
;; Maintainer: Andrey Kotlarski <m00naticus@gmail.com>
;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com>
;; 2012 Sam Steingold <sds@gnu.org>
;; 2013 Andrey Kotlarski <m00naticus@gmail.com>
;; 2013-2014 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
@@ -25,13 +26,12 @@
;; 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 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,
;; comparing and editing selected part of file.
;; To have it offered when opening large files:
;; (require 'vlf-integrate)
;; This package was inspired by a snippet posted by Kevin Rodgers,
;; showing how to use `insert-file-contents' to extract part of a
@@ -39,64 +39,99 @@
;;; Code:
(defgroup vlf nil
"View Large Files in Emacs."
:prefix "vlf-"
:group 'files)
(require 'vlf-base)
(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)
(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." t)
(autoload 'vlf-re-search-backward "vlf-search"
"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." t)
(autoload 'vlf-toggle-follow "vlf-follow"
"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)))
(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--")
(define-key map "n" 'vlf-next-batch)
(define-key map "p" 'vlf-prev-batch)
(define-key map " " 'vlf-next-batch-from-point)
(define-key map "+" 'vlf-change-batch-size)
(define-key map "-"
(lambda () "Decrease vlf batch size by factor of 2."
(interactive)
(vlf-change-batch-size t)))
(interactive)
(vlf-change-batch-size t)))
(define-key map "s" 'vlf-re-search-forward)
(define-key map "r" 'vlf-re-search-backward)
(define-key map "o" 'vlf-occur)
(define-key map "[" 'vlf-beginning-of-file)
(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)
"Keymap for `vlf-mode'.")
(define-derived-mode vlf-mode special-mode "VLF"
(defvar vlf-prefix-map
(let ((map (make-sparse-keymap)))
(define-key map "\C-c\C-v" vlf-mode-map)
map)
"Prefixed keymap for `vlf-mode'.")
(define-minor-mode vlf-mode
"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))
:lighter " VLF"
:group 'vlf
:keymap vlf-prefix-map
(if vlf-mode
(progn
(set (make-local-variable 'require-final-newline) nil)
(add-hook 'write-file-functions 'vlf-write nil t)
(set (make-local-variable 'revert-buffer-function)
'vlf-revert)
(make-local-variable 'vlf-batch-size)
(setq vlf-file-size (vlf-get-file-size buffer-file-truename)
vlf-start-pos 0
vlf-end-pos 0)
(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-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 'require-final-newline)
(remove-hook 'write-file-functions 'vlf-write t)
(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))))
(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))
;;;###autoload
(defun vlf (file)
"View Large FILE in batches.
You can customize number of bytes displayed by customizing
`vlf-batch-size'.
Return newly created buffer."
(interactive "fFile to open: ")
(let ((vlf-buffer (generate-new-buffer "*vlf*")))
(set-buffer vlf-buffer)
(set-visited-file-name file)
(set-buffer-modified-p nil)
(vlf-mode 1)
(switch-to-buffer vlf-buffer)
vlf-buffer))
(defun vlf-next-batch (append)
"Display the next batch of file data.
@@ -105,28 +140,13 @@ When prefix argument is supplied and positive
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))
(vlf-verify-size)
(let* ((end (min (+ vlf-end-pos (* vlf-batch-size (abs append)))
vlf-file-size))
(start (if (< append 0)
vlf-start-pos
(- end vlf-batch-size))))
(vlf-move-to-chunk start end)))
(defun vlf-prev-batch (prepend)
"Display the previous batch of file data.
@@ -137,84 +157,95 @@ When prefix argument is negative
(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))
(let* ((start (max 0 (- vlf-start-pos (* vlf-batch-size (abs prepend)))))
(end (if (< prepend 0)
vlf-end-pos
(+ start vlf-batch-size))))
(vlf-move-to-chunk start end)))
;;;###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))))
;; scroll auto batching
(defadvice scroll-up (around vlf-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)))
(progn (vlf-next-batch 1)
(goto-char (point-min)))
ad-do-it))
;;;###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."
(defadvice scroll-down (around vlf-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
(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")
(vlf from-end (dired-get-file-for-visit)))
(vlf-set-batch-size (if decrease (/ vlf-batch-size 2)
(* vlf-batch-size 2))))
;;;###autoload
(eval-after-load "dired"
'(define-key dired-mode-map "V" 'dired-vlf))
(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))
;;;###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"))))))
(defun vlf-beginning-of-file ()
"Jump to beginning of file content."
(interactive)
(vlf-move-to-batch 0))
;;; hijack `abort-if-file-too-large'
;;;###autoload
(fset 'abort-if-file-too-large 'vlf-if-file-too-large)
(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)
"Revert current chunk. Ignore _IGNORE-AUTO.
Ask for confirmation if NOCONFIRM is nil."
(interactive)
(when (or noconfirm
(yes-or-no-p (format "Revert buffer from file %s? "
buffer-file-name)))
(set-buffer-modified-p nil)
(vlf-move-to-chunk-2 vlf-start-pos vlf-end-pos)))
(defun vlf-jump-to-chunk (n)
"Go to to chunk N."
(interactive "nGoto to chunk: ")
(vlf-move-to-batch (* (1- n) vlf-batch-size)))
(defun vlf-no-modifications ()
"Ensure there are no buffer modifications."
(if (buffer-modified-p)
(error "Save or discard your changes first")
t))
(defun vlf-move-to-batch (start &optional minimal)
"Move to batch determined by START.
Adjust according to file start/end and show `vlf-batch-size' bytes.
When given MINIMAL flag, skip non important operations."
(vlf-verify-size)
(let* ((start (max 0 start))
(end (min (+ start vlf-batch-size) vlf-file-size)))
(if (= vlf-file-size end) ; re-adjust start
(setq start (max 0 (- end vlf-batch-size))))
(vlf-move-to-chunk start end minimal)))
(defun vlf-next-batch-from-point ()
"Display batch of file data starting from current point."
(interactive)
(let ((start (+ vlf-start-pos (position-bytes (point)) -1)))
(vlf-move-to-chunk start (+ start vlf-batch-size)))
(goto-char (point-min)))
(provide 'vlf)