[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 5a59059b24 2/3: Add a new mode for editing and viewing the Emacs
From: |
Lars Ingebrigtsen |
Subject: |
master 5a59059b24 2/3: Add a new mode for editing and viewing the Emacs NEWS file |
Date: |
Sat, 16 Apr 2022 09:42:17 -0400 (EDT) |
branch: master
commit 5a59059b240fa55c0c6832e6619305ae9b2b939c
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>
Add a new mode for editing and viewing the Emacs NEWS file
* etc/NEWS (mode): Use emacs-news-mode.
* lisp/help.el (view-emacs-news): Use emacs-news-mode.
* lisp/textmodes/emacs-news-mode.el: New mode for editing and
viewing the Emacs NEWS file.
---
etc/NEWS | 9 ++-
lisp/help.el | 4 +-
lisp/textmodes/emacs-news-mode.el | 144 ++++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+), 2 deletions(-)
diff --git a/etc/NEWS b/etc/NEWS
index c9f8ae4630..72b1309cef 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -603,6 +603,13 @@ script that was used in ancient South Asia.
* Changes in Specialized Modes and Packages in Emacs 29.1
+---
+** New mode for editing and viewing the NEWS file.
+It's called 'emacs-news-mode', and adds some highlighting, fixes the
+'M-q' command, and has commands for doing maintenance. When in read
+only mode (which you get when doing 'C-h N', for instance), it also
+adds buttons to manual entries and symbol references.
+
---
** kmacro
Kmacros are now OClosures and have a new constructor 'kmacro' which
@@ -1997,6 +2004,6 @@ along with GNU Emacs. If not, see
<https://www.gnu.org/licenses/>.
Local variables:
coding: utf-8
-mode: outline
+mode: emacs-news
paragraph-separate: "[ ]*$"
end:
diff --git a/lisp/help.el b/lisp/help.el
index 780f5daac7..e326ea5d00 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -453,7 +453,9 @@ With argument, display info only for the selected version."
((< vn 18) "NEWS.1-17")
(t (format "NEWS.%d" vn))))
res)
- (view-file (expand-file-name file data-directory))
+ (find-file (expand-file-name file data-directory))
+ (setq buffer-read-only t)
+ (emacs-news-mode)
(widen)
(goto-char (point-min))
(when (stringp version)
diff --git a/lisp/textmodes/emacs-news-mode.el
b/lisp/textmodes/emacs-news-mode.el
new file mode 100644
index 0000000000..5099a7435f
--- /dev/null
+++ b/lisp/textmodes/emacs-news-mode.el
@@ -0,0 +1,144 @@
+;;; emacs-news-mode.el --- major mode to edit and view the NEWS file -*-
lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Keywords: tools
+
+;; This file is part of GNU Emacs.
+
+;; GNU Emacs 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.
+
+;; GNU Emacs 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. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(eval-when-compile (require 'cl-lib))
+
+(defgroup emacs-news-mode nil
+ "Major mode for editing and viewing the Emacs NEWS file."
+ :group 'lisp)
+
+(defface emacs-news-is-documented
+ '((t :inherit font-lock-type-face))
+ "Face used for displaying the \"is documented\" tag."
+ :version "29.1")
+
+(defface emacs-news-does-not-need-documentation
+ '((t :inherit font-lock-preprocessor-face))
+ "Face used for displaying the \"does not need documentation\" tag."
+ :version "29.1")
+
+(defvar-keymap emacs-news-mode-map
+ "C-c C-s" #'emacs-news-next-untagged-entry)
+
+(defvar emacs-news-mode-font-lock-keywords
+ `(("^---$" 0 'emacs-news-does-not-need-documentation)
+ ("^\\+\\+\\+$" 0 'emacs-news-is-documented)))
+
+;;;###autoload
+(define-derived-mode emacs-news-mode text-mode "NEWS"
+ "Major mode for editing and viewind the Emacs NEWS file."
+ (setq-local font-lock-defaults '(emacs-news-mode-font-lock-keywords t))
+ (setq-local outline-regexp "^\\*+ "
+ outline-minor-mode-cycle t
+ outline-minor-mode-highlight 'append)
+ (setq-local fill-paragraph-function #'emacs-news--fill-paragraph)
+ (outline-minor-mode 1)
+ (when buffer-read-only
+ (emacs-news--buttonize)
+ (button-mode)))
+
+(defun emacs-news--fill-paragraph (&optional justify)
+ (cond
+ ;; We're in a heading -- do nothing.
+ ((save-excursion
+ (beginning-of-line)
+ (looking-at "\\*+ "))
+ )
+ ;; We're in a news item -- exclude the heading before filling.
+ ((and (save-excursion
+ (re-search-backward (concat "^\\(?:" paragraph-start "\\|\\*+ \\)")
+ nil t))
+ (= (char-after (match-beginning 0)) ?*))
+ (save-restriction
+ (narrow-to-region (save-excursion
+ (goto-char (match-beginning 0))
+ (forward-line 1)
+ (point))
+ (point-max))
+ (fill-paragraph justify)))
+ ;; Fill normally.
+ (t
+ (fill-paragraph justify))))
+
+(defun emacs-news-next-untagged-entry ()
+ "Go to the next untagged NEWS entry."
+ (interactive nil emacs-news-mode)
+ (let ((start (point))
+ (found nil))
+ ;; Don't consider the current line, because that would stop
+ ;; progress if calling this command repeatedly.
+ (forward-line 1)
+ (while (and (not found)
+ (re-search-forward "\\(\\*+\\) " nil t)
+ (not (save-excursion
+ (forward-line -1)
+ (looking-at "---$\\|\\+\\+\\+$"))))
+ ;; We have an entry without a tag before it, but check whether
+ ;; it's a heading (which we can determine if the next entry has
+ ;; more asterisks).
+ (let ((level (length (match-string 1))))
+ (when (save-excursion
+ (re-search-forward "^\\(\\*+\\) " nil t))
+ (when (<= (length (match-string 1)) level)
+ ;; It wasn't a sub-heading, so we've found one.
+ (setq found t)))))
+ (if found
+ (progn
+ (message "Untagged entry")
+ (beginning-of-line))
+ (message "No further untagged entries")
+ (goto-char start))))
+
+(defun emacs-news--buttonize ()
+ "Make manual and symbol references into buttons."
+ (save-excursion
+ (with-silent-modifications
+ (let ((inhibit-read-only t))
+ ;; Do functions and variables.
+ (goto-char (point-min))
+ (search-forward "\f" nil t)
+ (while (re-search-forward "'\\([^-][^ \t\n]+\\)'" nil t)
+ ;; Filter out references to key sequences.
+ (let ((string (match-string 1)))
+ (unless (key-valid-p string)
+ (when-let ((symbol (intern-soft string)))
+ (when (or (boundp symbol)
+ (fboundp symbol))
+ (buttonize-region (match-beginning 1) (match-end 1)
+ (lambda (symbol)
+ (describe-symbol symbol))
+ symbol))))))
+ ;; Do manual references.
+ (goto-char (point-min))
+ (search-forward "\f" nil t)
+ (while (re-search-forward "\"\\(([a-z0-9]+)[ \n][^\"]\\{1,80\\}\\)\""
+ nil t)
+ (buttonize-region (match-beginning 1) (match-end 1)
+ (lambda (node) (info node))
+ (match-string 1)))))))
+
+(provide 'emacs-news-mode)
+
+;;; emacs-news-mode.el ends here