1
0
mirror of https://github.com/m00natic/vlfi.git synced 2024-10-05 18:30:51 +01:00
vlfi/vlf.el

302 lines
11 KiB
EmacsLisp
Raw Normal View History

2013-08-25 15:57:43 +01:00
;;; vlf.el --- View Large Files -*- lexical-binding: t -*-
2014-01-01 13:43:14 +00:00
;; Copyright (C) 2006, 2012-2014 Free Software Foundation, Inc.
2014-01-01 13:43:14 +00:00
;; Version: 1.3
;; Keywords: large files, utilities
;; Maintainer: Andrey Kotlarski <m00naticus@gmail.com>
;; Authors: 2006 Mathias Dahl <mathias.dahl@gmail.com>
;; 2012 Sam Steingold <sds@gnu.org>
2014-01-01 13:43:14 +00:00
;; 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
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
2013-08-25 15:57:43 +01:00
;; This package provides the M-x vlf command, which visits part of a
2013-05-01 00:02:28 +01:00
;; large file without loading the entire file.
2013-08-25 15:57:43 +01:00
;; The buffer uses VLF mode, which defines several commands for
2013-05-01 00:02:28 +01:00
;; moving around, searching and editing selected part of file.
;; This package was inspired by a snippet posted by Kevin Rodgers,
;; showing how to use `insert-file-contents' to extract part of a
;; file.
;;; Code:
2014-01-01 13:43:14 +00:00
;;;###autoload
(require 'vlf-integrate)
(require 'vlf-base)
2013-08-25 15:57:43 +01:00
(defcustom vlf-batch-size 1024
"Defines how large each batch of file data is (in bytes)."
:group 'vlf
:type 'integer)
2013-08-25 15:57:43 +01:00
(put 'vlf-batch-size 'permanent-local t)
;;; Keep track of file position.
2013-08-25 15:57:43 +01:00
(defvar vlf-start-pos 0
"Absolute position of the visible chunk start.")
2013-08-25 15:57:43 +01:00
(put 'vlf-start-pos 'permanent-local t)
2013-08-25 15:57:43 +01:00
(defvar vlf-end-pos 0 "Absolute position of the visible chunk end.")
(put 'vlf-end-pos 'permanent-local t)
(defvar vlf-file-size 0 "Total size of presented file.")
(put 'vlf-file-size 'permanent-local t)
2014-01-01 13:43:14 +00:00
(autoload 'vlf-write "vlf-write" "Write current chunk to file.")
(autoload 'vlf-re-search-forward "vlf-search"
"Search forward for REGEXP prefix COUNT number of times.")
(autoload 'vlf-re-search-backward "vlf-search"
"Search backward for REGEXP prefix COUNT number of times.")
(autoload 'vlf-goto-line "vlf-search" "Go to line.")
(autoload 'vlf-occur "vlf-occur"
"Make whole file occur style index for REGEXP.")
(autoload 'vlf-toggle-follow "vlf-follow"
"Toggle continuous chunk recenter around current point.")
2013-08-25 15:57:43 +01:00
(defvar vlf-mode-map
(let ((map (make-sparse-keymap)))
(define-key map "n" 'vlf-next-batch)
(define-key map "p" 'vlf-prev-batch)
(define-key map " " 'vlf-next-batch-from-point)
2013-08-25 15:57:43 +01:00
(define-key map "+" 'vlf-change-batch-size)
2013-04-01 01:07:20 +01:00
(define-key map "-"
2013-08-25 15:57:43 +01:00
(lambda () "Decrease vlf batch size by factor of 2."
2013-04-13 20:36:33 +01:00
(interactive)
2013-08-25 15:57:43 +01:00
(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)
2014-01-01 13:43:14 +00:00
(define-key map "f" 'vlf-toggle-follow)
(define-key map "g" 'vlf-revert)
map)
2013-08-25 15:57:43 +01:00
"Keymap for `vlf-mode'.")
(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'.")
(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))))
2013-12-02 00:08:24 +00:00
(define-minor-mode vlf-mode
"Mode to browse large files in."
2013-12-02 00:08:24 +00:00
:lighter " VLF"
2013-12-03 22:20:02 +00:00
:group 'vlf
:keymap vlf-prefix-map
2013-12-02 00:08:24 +00:00
(if vlf-mode
(progn
(set (make-local-variable 'require-final-newline) nil)
2013-12-02 00:08:24 +00:00
(add-hook 'write-file-functions 'vlf-write nil t)
(set (make-local-variable 'revert-buffer-function)
'vlf-revert)
(make-local-variable 'vlf-batch-size)
(set (make-local-variable 'vlf-file-size)
(vlf-get-file-size buffer-file-truename))
(set (make-local-variable 'vlf-start-pos) 0)
(set (make-local-variable 'vlf-end-pos) 0)
(set (make-local-variable 'vlf-follow-timer) nil)
2013-12-02 00:08:24 +00:00
(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-following)
2013-12-02 00:08:24 +00:00
(when (or (not large-file-warning-threshold)
(< vlf-file-size large-file-warning-threshold)
2013-12-03 22:20:02 +00:00
(y-or-n-p (format "Load whole file (%s)? "
2013-12-02 00:08:24 +00:00
(file-size-human-readable
vlf-file-size))))
(kill-local-variable 'require-final-newline)
2013-12-02 00:08:24 +00:00
(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))
2013-12-02 00:08:24 +00:00
(goto-char (byte-to-position pos)))
(rename-buffer (file-name-nondirectory buffer-file-name) t))))
2013-04-13 20:49:08 +01:00
;;;###autoload
2013-08-25 15:57:43 +01:00
(defun vlf (file)
2013-12-02 00:08:24 +00:00
"View Large FILE in batches.
You can customize number of bytes displayed by customizing
2013-08-25 15:57:43 +01:00
`vlf-batch-size'."
(interactive "fFile to open: ")
2013-08-25 15:57:43 +01:00
(with-current-buffer (generate-new-buffer "*vlf*")
(set-visited-file-name file)
2013-12-02 00:08:24 +00:00
(set-buffer-modified-p nil)
(vlf-mode 1)
2013-04-13 20:49:08 +01:00
(switch-to-buffer (current-buffer))))
2013-04-14 00:50:31 +01:00
;; scroll auto batching
2013-08-25 15:57:43 +01:00
(defadvice scroll-up (around vlf-scroll-up
2013-04-14 00:50:31 +01:00
activate compile)
2013-08-25 15:57:43 +01:00
"Slide to next batch if at end of buffer in `vlf-mode'."
(if (and vlf-mode (pos-visible-in-window-p (point-max)))
2013-08-25 15:57:43 +01:00
(progn (vlf-next-batch 1)
2013-04-14 00:50:31 +01:00
(goto-char (point-min)))
ad-do-it))
2013-08-25 15:57:43 +01:00
(defadvice scroll-down (around vlf-scroll-down
2013-04-14 00:50:31 +01:00
activate compile)
2013-12-03 22:20:02 +00:00
"Slide to previous batch if at beginning of buffer in `vlf-mode'."
(if (and vlf-mode (pos-visible-in-window-p (point-min)))
2013-08-25 15:57:43 +01:00
(progn (vlf-prev-batch 1)
2013-04-14 00:50:31 +01:00
(goto-char (point-max)))
ad-do-it))
2013-04-13 20:49:08 +01:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; utilities
2013-08-25 15:57:43 +01:00
(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")
2013-08-25 15:57:43 +01:00
(setq vlf-batch-size (if decrease
2013-12-02 00:08:24 +00:00
(/ vlf-batch-size 2)
(* vlf-batch-size 2)))
2013-08-25 15:57:43 +01:00
(vlf-move-to-batch vlf-start-pos))
2013-02-02 14:12:30 +00:00
2013-08-25 15:57:43 +01:00
(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))
2013-08-25 15:57:43 +01:00
(defun vlf-get-file-size (file)
2013-04-13 22:52:07 +01:00
"Get size in bytes of FILE."
(or (nth 7 (file-attributes file)) 0))
2013-04-13 22:52:07 +01:00
2013-08-25 15:57:43 +01:00
(defun vlf-verify-size ()
"Update file size information if necessary and visited file time."
(unless (verify-visited-file-modtime (current-buffer))
(setq vlf-file-size (vlf-get-file-size buffer-file-truename))
(set-visited-file-modtime)))
2013-08-25 15:57:43 +01:00
(defun vlf-insert-file (&optional from-end)
2013-04-13 20:49:08 +01:00
"Insert first chunk of current file contents in current buffer.
With FROM-END prefix, start from the back."
(let ((start 0)
(end vlf-batch-size))
(if from-end
(setq start (- vlf-file-size vlf-batch-size)
end vlf-file-size)
(setq end (min vlf-batch-size vlf-file-size)))
(vlf-move-to-chunk start end)))
2013-04-13 20:49:08 +01:00
2013-08-25 15:57:43 +01:00
(defun vlf-beginning-of-file ()
2013-04-13 20:49:08 +01:00
"Jump to beginning of file content."
(interactive)
2013-08-25 15:57:43 +01:00
(vlf-insert-file))
2013-04-13 20:49:08 +01:00
2013-08-25 15:57:43 +01:00
(defun vlf-end-of-file ()
2013-04-13 20:49:08 +01:00
"Jump to end of file content."
(interactive)
2013-08-25 15:57:43 +01:00
(vlf-insert-file t))
2013-04-13 20:49:08 +01:00
2013-08-25 15:57:43 +01:00
(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)
(set-visited-file-modtime)
(vlf-move-to-chunk-2 vlf-start-pos vlf-end-pos)))
2013-04-13 20:49:08 +01:00
2013-08-25 15:57:43 +01:00
(defun vlf-jump-to-chunk (n)
2013-04-13 20:57:09 +01:00
"Go to to chunk N."
(interactive "nGoto to chunk: ")
2013-08-25 15:57:43 +01:00
(vlf-move-to-batch (* (1- n) vlf-batch-size)))
2013-04-13 20:57:09 +01:00
(defun vlf-no-modifications ()
"Ensure there are no buffer modifications."
(if (buffer-modified-p)
(error "Save or discard your changes first")
t))
2013-04-13 20:49:08 +01:00
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; batch movement
2013-08-25 15:57:43 +01:00
(defun vlf-next-batch (append)
"Display the next batch of file data.
When prefix argument is supplied and positive
jump over APPEND number of batches.
When prefix argument is negative
append next APPEND number of batches to the existing buffer."
(interactive "p")
2013-08-25 15:57:43 +01:00
(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)))
2013-08-25 15:57:43 +01:00
(defun vlf-prev-batch (prepend)
"Display the previous batch of file data.
When prefix argument is supplied and positive
jump over PREPEND number of batches.
When prefix argument is negative
append previous PREPEND number of batches to the existing buffer."
(interactive "p")
2013-08-25 15:57:43 +01:00
(if (zerop vlf-start-pos)
(error "Already at BOF"))
(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)))
2013-08-25 15:57:43 +01:00
(defun vlf-move-to-batch (start &optional minimal)
"Move to batch determined by START.
2013-08-25 15:57:43 +01:00
Adjust according to file start/end and show `vlf-batch-size' bytes.
When given MINIMAL flag, skip non important operations."
2013-08-25 15:57:43 +01:00
(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)))
2013-08-25 15:57:43 +01:00
(provide 'vlf)
2013-08-25 15:57:43 +01:00
;;; vlf.el ends here