branch: externals/autorevert-tail-truncate commit 662a27f883c01648a099f5859e166ee8f24021fa Author: shipmints <shipmi...@gmail.com> Commit: shipmints <shipmi...@gmail.com>
Actual initial commit --- .elpaignore | 1 + .gitignore | 7 ++ README.md | 76 ++++++++++++++- autorevert-tail-truncate.el | 219 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 302 insertions(+), 1 deletion(-) diff --git a/.elpaignore b/.elpaignore new file mode 100644 index 0000000000..6b1d0bfabc --- /dev/null +++ b/.elpaignore @@ -0,0 +1 @@ +LICENSE diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..9d48fea457 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*-autoloads.el +*-pkg.el +*.elc +*.info +*.texi +*~ +\#*\# diff --git a/README.md b/README.md index d46d87459d..233a484df8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,76 @@ +<!-- -*- mode: gfm; coding: utf-8; tab-width: 2; fill-column: 130; eval: (visual-line-mode t) -*- --> + # autorevert-tail-truncate.el -Extend Emacs extends auto-revert-tail-mode to optimize memory and cpu + +Extend Emacs auto-revert-tail-mode to optimize memory and CPU. + +`auto-revert-tail-truncate-mode` extends `auto-revert-tail-mode` to automate truncating the tailed buffer to a +user-specified number of lines. This allows you, for example, to tail log files in an auto-reverting buffer forever without +running out of memory. By default, a newly tailed buffer is immediately truncated for the same reason. Also, by default, the +buffer's undo log is disabled along with font-lock to both preserve memory and optimize CPU consumption. + +Use the command `auto-revert-tail-truncate-file` to open a file in a new buffer with `auto-revert-tail-truncate-mode` +enabled. + +Add a function (example, below) to `auto-revert-tail-truncate-mode-hook` to control additional features in your tailed buffers; +e.g., `truncate-lines`, controlling `so-long-mode` threshold, disabling spell checking, or enabling other minor modes for +specific log-file formats (the visual features of which may require you to enable font-lock for those buffers). + +If you want this mode enabled for all *.log files, run the command +`auto-revert-tail-mode-on-log-files` or add this to your `init.el` file. + +Refer to the source code or docstrings for details on user options. + +## Installation + +`autorevert-tail-truncate.el` is not yet part of Emacs (it will be submitted for consideration to be included in Emacs 31) and has not yet been published on ELPA. + +If you use Emacs 29.1+, use `package-vc-install`. In your `*scratch*` buffer, copy/paste or type the following, and run it via +the command `eval-last-sexp`, which see: + +``` elisp +(package-vc-install '(autorevert-tail-truncate :url "https://github.com/shipmints/autorevert-tail-truncate.el")) +``` + +Or, if you use Emacs 30+, uncomment the :vc stanza, below. + +``` elisp +(use-package autorevert-tail-truncate + ;; :vc ( + ;; :url "https://github.com/shipmints/autorevert-tail-truncate.el" + ;; :branch "master") + :config + (setq auto-revert-tail-truncate-max-lines 5000) ; default 5000 + (setq auto-revert-tail-truncate-file-size-hint 64) ; default 64 + (setq auto-revert-tail-truncate-immediately t) ; default t + (setq auto-revert-tail-truncate-verbose nil) ; default nil + (setq auto-revert-tail-truncate-immediately t) ; default t + (setq auto-revert-tail-truncate-read-only t) ; deault t + (setq auto-revert-tail-truncate-disable-undo t) ; default t + (setq auto-revert-tail-truncate-disable-font-lock t) ; default t + + (defun my/auto-revert-tail-truncate-mode-hook () + "Custom `auto-revert-tail-truncate-mode' hook." + (setq-local auto-revert-tail-truncate-max-lines 10000) + (setq-local truncate-lines t) + (when (fboundp 'so-long-mode) + (setq-local so-long-threshold 25000)) + (when (eq my:spell-checker 'jinx) + (jinx-mode -1)) + (when (fboundp 'show-smartparens-mode) + (show-smartparens-mode -1))) + (add-hook 'auto-revert-tail-truncate-mode-hook #'my/auto-revert-tail-truncate-mode-hook) + ;; add auto-mode-alist entry for .log files to use auto-revert-tail-mode + (auto-revert-tail-mode-on-log-files)) +``` + +## Coda + +I put this into the package because the earliest Emacs I can easily support is 29.x. This will likely be altered if the package is +published in ELPA and most certainly will be removed as a part of Emacs 31, if accepted. + + ;; Package-Requires: ((emacs "29.1")) + +This is a new package, and though the author successfully uses it, your mileage may vary. The author does not used specialized +log-file modes such as https://github.com/doublep/logview or https://github.com/emacsmirror/log4j-mode -- if you do, and find +issues that you cannot resolve via your configuration, file an issue here. diff --git a/autorevert-tail-truncate.el b/autorevert-tail-truncate.el new file mode 100644 index 0000000000..9104143628 --- /dev/null +++ b/autorevert-tail-truncate.el @@ -0,0 +1,219 @@ +;;; autorevert-tail-truncate.el -- Summary;: -*- mode: emacs-lisp; lexical-binding: t; -*- + +;; Copyright (C) 2025 Stephane Marks +;; Copyright (C) 2025 Free Software Foundation, Inc. + +;; Author: Stephane Marks <shipmi...@gmail.com> +;; Maintainer: Stephane Marks <shipmi...@gmail.com> +;; Url: https://github.com/shipmints/autorevert-tail-truncate.el +;; Created: 2025-02-03 +;; Version: 1.0 +;; Package-Requires: ((emacs "29.1")) +;; Keywords: convenience, tools, log files, autorevert + +;; This program 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 of the License, or +;; (at your option) any later version. +;; +;; This program 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 this program. If not, see <https://www.gnu.org/licenses/>. + +;;; Commentary: + +;; `auto-revert-tail-truncate-mode' extends `auto-revert-tail-mode' to +;; automate truncating the tailed buffer to a user-specified number of +;; lines. This allows you, for example, to tail log files in an +;; auto-reverting buffer forever without running out of memory. By +;; default, a newly tailed buffer is immediately truncated for the +;; same reason. Also, by default, the buffer's undo log is disabled +;; along with font-lock to both preserve memory and optimize CPU +;; consumption. +;; +;; Use the command auto-revert-tail-truncate-file to open a file in a +;; new buffer with `auto-revert-tail-truncate-mode' enabled. +;; +;; Add a function to `auto-revert-tail-truncate-mode-hook' to control +;; additional features in your tailed buffers; e.g., truncate-lines, +;; controlling so-long-mode threshold, disabling spell checking, or +;; enabling other minor modes for specific log-file formats (the +;; visual features of which may require you to enable font-lock for +;; those buffers). +;; +;; If you want this mode enabled for all *.log files, run the command +;; `auto-revert-tail-mode-on-log-files'. + +;;; Code: + +(require 'autorevert) + +(defcustom auto-revert-tail-truncate-max-lines 5000 + "Truncate buffer to this maximum number of lines. +If nil, truncation is disabled. Bind this as a buffer-local variable to +control the maximum number lines to retain for specific buffers." + :group 'auto-revert + :type 'natnum + :version "31.1") + +(defcustom auto-revert-tail-truncate-file-size-hint 64 + "Bytes per line hint to `auto-revert-tail-truncate-file'. +This is multiplied by `auto-revert-tail-truncate-max-lines' to compute +the initial bytes to load." + :group 'auto-revert + :type 'natnum + :version "31.1") + +(defcustom auto-revert-tail-truncate-revert-interval auto-revert-interval + "Number of seconds between Auto-Revert Tail Truncate Mode file checks. +The default value is `auto-revert-interval', which see." + :group 'auto-revert + :type 'natnum + :version "31.1") + +(defcustom auto-revert-tail-truncate-verbose auto-revert-verbose + "When nil, `auto-revert-tail-truncate-mode' does not generate messages. +When non-nil, a message is generated whenever a buffer is reverted. +The default value is `auto-revert-verbose', which see." + :group 'auto-revert + :type 'boolean + :version "31.1") + +(defcustom auto-revert-tail-truncate-immediately t + "If non-nil, buffer is truncated when this mode is enabled. +Set the maximum number of lines to retain in the buffer using the +option `auto-revert-tail-truncate-max-lines', which see." + :group 'auto-revert + :type 'boolean + :version "31.1") + +(defcustom auto-revert-tail-truncate-read-only t + "If non-nil, the tailed buffer is set to be read only." + :group 'auto-revert + :type 'boolean + :version "31.1") + +(defcustom auto-revert-tail-truncate-disable-undo t + "If non-nil, the buffer's undo log is disabled to save memory." + :group 'auto-revert + :type 'boolean + :version "31.1") + +(defcustom auto-revert-tail-truncate-disable-font-lock t + "If non-nil, font-lock is disabled on the tailed buffer." + :group 'auto-revert + :type 'boolean + :version "31.1") + +(defcustom auto-revert-tail-truncate-check-vc-info auto-revert-check-vc-info + "If non-nil `auto-revert-tail-truncate-mode' updates vc info. +The default value is `auto-revert-check-vc-info', which see." + :group 'auto-revert + :type 'boolean + :version "31.1") + +(defcustom auto-revert-tail-truncate-mode-text " TailTrunc" + "Mode line string when `auto-revert-tail-truncate-mode' is active." + :group 'auto-revert + :type 'string + :version "31.1") + +(defvar-local auto-revert-tail-truncate-mode nil + "Non-nil when `auto-revert-tail-truncate-mode' is active. +Never set this variable directly, use the command +`auto-revert-tail-truncate-mode' instead.") +(put 'auto-revert-tail-truncate-mode 'permanent-local t) + +;;;###autoload +(define-minor-mode auto-revert-tail-truncate-mode + "`auto-revert-tail-mode' with automatic buffer line truncation. +Truncation does not affect the content of underlying file, only the +buffer in which it is displayed. + +Customize `auto-revert-tail-mode-hook' to control features such as +`truncate-lines' for the tailed buffer." + :group 'find-file + :lighter auto-revert-tail-truncate-mode-text + (if auto-revert-tail-truncate-mode + (progn + (setq-local auto-revert-tail-mode-text nil) ; this mode's lighter has priority + (auto-revert-tail-mode) + (make-local-variable 'auto-revert-interval) + (make-local-variable 'auto-revert-timer) + (setopt auto-revert-interval auto-revert-tail-truncate-revert-interval) + (setq-local auto-revert-verbose auto-revert-tail-truncate-verbose) + (when auto-revert-tail-truncate-read-only + (read-only-mode)) + (when auto-revert-tail-truncate-disable-undo + (buffer-disable-undo)) + (when auto-revert-tail-truncate-disable-font-lock + (font-lock-mode -1)) + (make-local-variable 'auto-revert-check-vc-info) + (setq auto-revert-check-vc-info auto-revert-tail-truncate-check-vc-info) + (goto-char (point-max)) + (when auto-revert-tail-truncate-immediately + (auto-revert--tail-truncate)) + (add-hook 'after-revert-hook #'auto-revert--tail-truncate nil 'local)) + (remove-hook 'after-revert-hook #'auto-revert--tail-truncate 'local) + (auto-revert-tail-mode -1))) + +(defun turn-on-auto-revert-tail-truncate-mode () + "Turn on `auto-revert-tail-truncate-mode'. + +This function is designed to be added to hooks, for example: +\(add-hook \\='my-logfile-mode-hook #\\='turn-on-auto-revert-tail-truncate-mode)" + (auto-revert-tail-truncate-mode 1)) + +(defun auto-revert--tail-truncate () + "Called via buffer local `after-revert-hook' to truncate the buffer." + (when auto-revert-tail-truncate-max-lines + (with-silent-modifications + (save-restriction + (widen) + (save-excursion + (goto-char (point-max)) + (forward-line (- auto-revert-tail-truncate-max-lines)) + (beginning-of-line) + (let ((inhibit-read-only t)) + (delete-region (point-min) (point)))))))) + +;;;###autoload +(defun auto-revert-tail-truncate-file (filename) + "Prompt for a file to tail using `auto-revert-tail-truncate-mode'. +Invoke programmatically specifying FILENAME." + (interactive "fFile to auto revert tail (with truncate): ") + (let* ((filename (abbreviate-file-name (expand-file-name filename))) + (max-size (* auto-revert-tail-truncate-max-lines + auto-revert-tail-truncate-file-size-hint)) + (size (file-attribute-size (file-attributes filename))) + (beg (if (< size max-size) 0 (- size max-size))) + (end size) + (existing-buf (get-file-buffer filename)) + (buf)) + (when existing-buf + (when (y-or-n-p "Use and truncate the existing buffer (\"no\" makes a new buffer)?") + (setq buf existing-buf))) + (unless buf + (setq buf (create-file-buffer filename)) + (with-current-buffer buf + (with-silent-modifications + (insert-file-contents filename nil beg end) + (set-visited-file-name filename nil t) + (set-buffer-modified-p nil)))) ; also silences auto-revert-tail-mode "Buffer is modified..." warning + (with-current-buffer buf + (auto-revert-tail-truncate-mode)) + (pop-to-buffer buf))) + +;;;###autoload +(defun auto-revert-tail-mode-on-log-files () + "Enable `auto-revert-tail-truncate-mode' for all *.log files." + (interactive) + (add-to-list 'auto-mode-alist '("\\.log\\'" . auto-revert-tail-truncate-mode))) + +(provide 'autorevert-tail-truncate) + +;;; autorevert-tail-truncate.el ends here