Add lisp-data-mode for editing non-code Lisp data

Fixes: bug#40573

The new mode can be used stand-alone or inherited from by modes
intended to edit programs. The existing emacs-lisp-mode and lisp-mode
are examples.

Thanks to Juri Linkov and Basil L. Contovounesios for researching some
data files in Emacs that can be automatically set to use the new mode.

* lisp/files.el (auto-mode-alist): Add entry for ".dir-locals" and
".dir-locals-2"

* lisp/emacs-lisp/lisp-mode.el: (lisp-data-mode): New major mode.
(lisp-mode): Inherit from lisp-data-mode.  Set special lisp-mode
stuff here.

* lisp/progmodes/elisp-mode.el (emacs-lisp-mode): Inherit from
lisp-data-mode.

* lisp/bookmark.el (bookmark-insert-file-format-version-stamp):
Use lisp-data-mode.

* lisp/saveplace.el (save-place-alist-to-file): Use
lisp-data-mode.

* lisp/net/eww.el (eww-write-bookmarks): Use lisp-data-mode.

* lisp/net/nsm.el (nsm-write-settings): Use lisp-data-mode.

* lisp/net/tramp-cache.el (tramp-dump-connection-properties): Use
lisp-data-mode.

* etc/NEWS: Mention lisp-data-mode.

* doc/lispref/modes.texi (Example Major Modes): Update example.
This commit is contained in:
João Távora 2020-04-18 02:46:04 +01:00
parent 7fa3e754cb
commit 43fded12d5
10 changed files with 45 additions and 38 deletions

View file

@ -1352,19 +1352,11 @@ illustrate how these modes are written.
@end smallexample
The three modes for Lisp share much of their code. For instance,
each calls the following function to set various variables:
@smallexample
@group
(defun lisp-mode-variables (&optional syntax keywords-case-insensitive elisp)
(when syntax
(set-syntax-table lisp-mode-syntax-table))
@dots{}
@end group
@end smallexample
Lisp mode and Emacs Lisp mode inherit from Lisp Data mode and Lisp
Interaction Mode inherits from Emacs Lisp mode.
@noindent
Amongst other things, this function sets up the @code{comment-start}
Amongst other things, Lisp Data mode sets up the @code{comment-start}
variable to handle Lisp comments:
@smallexample
@ -1414,7 +1406,7 @@ Finally, here is the major mode command for Lisp mode:
@smallexample
@group
(define-derived-mode lisp-mode prog-mode "Lisp"
(define-derived-mode lisp-mode lisp-data-mode "Lisp"
"Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
Commands:
Delete converts tabs to spaces as it moves back.
@ -1425,7 +1417,6 @@ Note that `run-lisp' may be used either to start an inferior Lisp job
or to switch back to an existing one."
@end group
@group
(lisp-mode-variables nil t)
(setq-local find-tag-default-function 'lisp-find-tag-default)
(setq-local comment-start-skip
"\\(\\(^\\|[^\\\n]\\)\\(\\\\\\\\\\)*\\)\\(;+\\|#|\\) *")

View file

@ -291,6 +291,12 @@ These new navigation commands are bound to 'n' and 'p' in
* New Modes and Packages in Emacs 28.1
*** Lisp Data mode
The new command 'lisp-data-mode' enables a major mode for buffers
composed of Lisp symbolic expressions that do not form a computer
program. The '.dir-locals.el' file is automatically set to use this
mode, as are other data files produced by Emacs.
* Incompatible Editing Changes in Emacs 28.1

View file

@ -734,8 +734,10 @@ CODING is the symbol of the coding-system in which the file is encoded."
(if (memq (coding-system-base coding) '(undecided prefer-utf-8))
(setq coding 'utf-8-emacs))
(insert
(format ";;;; Emacs Bookmark Format Version %d ;;;; -*- coding: %S -*-\n"
bookmark-file-format-version (coding-system-base coding)))
(format
";;;; Emacs Bookmark Format Version %d\
;;;; -*- coding: %S mode: lisp-data -*-\n"
bookmark-file-format-version (coding-system-base coding)))
(insert ";;; This format is meant to be slightly human-readable;\n"
";;; nevertheless, you probably don't want to edit it.\n"
";;; "

View file

@ -611,6 +611,8 @@ Value for `adaptive-fill-function'."
;; a single docstring. Let's fix it here.
(if (looking-at "\\s-+\"[^\n\"]+\"\\s-*$") ""))
;; Maybe this should be discouraged/obsoleted and users should be
;; encouraged to use `lisp-data-mode` instead.
(defun lisp-mode-variables (&optional lisp-syntax keywords-case-insensitive
elisp)
"Common initialization routine for lisp modes.
@ -658,6 +660,14 @@ font-lock keywords will not be case sensitive."
(setq-local electric-pair-skip-whitespace 'chomp)
(setq-local electric-pair-open-newline-between-pairs nil))
;;;###autoload
(define-derived-mode lisp-data-mode prog-mode "Lisp-Data"
"Major mode for buffers holding data written in Lisp syntax."
:group 'lisp
(lisp-mode-variables t t nil)
(setq-local electric-quote-string t)
(setq imenu-case-fold-search nil))
(defun lisp-outline-level ()
"Lisp mode `outline-level' function."
(let ((len (- (match-end 0) (match-beginning 0))))
@ -737,7 +747,7 @@ font-lock keywords will not be case sensitive."
"Keymap for ordinary Lisp mode.
All commands in `lisp-mode-shared-map' are inherited by this map.")
(define-derived-mode lisp-mode prog-mode "Lisp"
(define-derived-mode lisp-mode lisp-data-mode "Lisp"
"Major mode for editing Lisp code for Lisps other than GNU Emacs Lisp.
Commands:
Delete converts tabs to spaces as it moves back.
@ -746,7 +756,6 @@ Blank lines separate paragraphs. Semicolons start comments.
\\{lisp-mode-map}
Note that `run-lisp' may be used either to start an inferior Lisp job
or to switch back to an existing one."
(lisp-mode-variables nil t)
(setq-local lisp-indent-function 'common-lisp-indent-function)
(setq-local find-tag-default-function 'lisp-find-tag-default)
(setq-local comment-start-skip

View file

@ -2657,6 +2657,13 @@ since only a single case-insensitive search through the alist is made."
("\\.ltx\\'" . latex-mode)
("\\.dtx\\'" . doctex-mode)
("\\.org\\'" . org-mode)
;; .dir-locals.el is not really elisp. Could use the
;; `dir-locals-file' constant if it weren't defined below.
("\\.dir-locals\\(-2\\)?\\.el\\'" . lisp-data-mode)
("eww-bookmarks\\'" . lisp-data-mode)
("tramp\\'" . lisp-data-mode)
("places\\'" . lisp-data-mode)
("\\.emacs-places\\'" . lisp-data-mode)
("\\.el\\'" . emacs-lisp-mode)
("Project\\.ede\\'" . emacs-lisp-mode)
("\\.\\(scm\\|stk\\|ss\\|sch\\)\\'" . scheme-mode)

View file

@ -1733,7 +1733,7 @@ If CHARSET is nil then use UTF-8."
(defun eww-write-bookmarks ()
(with-temp-file (expand-file-name "eww-bookmarks" eww-bookmarks-directory)
(insert ";; Auto-generated file; don't edit\n")
(insert ";; Auto-generated file; don't edit -*- mode: lisp-data -*-\n")
(pp eww-bookmarks (current-buffer))))
(defun eww-read-bookmarks ()

View file

@ -964,6 +964,7 @@ protocol."
(defun nsm-write-settings ()
(with-temp-file nsm-settings-file
(insert ";;;; -*- mode: lisp-data -*-\n")
(insert "(\n")
(dolist (setting nsm-permanent-host-settings)
(insert " ")

View file

@ -472,7 +472,7 @@ used to cache connection properties of the local machine."
;; Dump it.
(with-temp-file tramp-persistency-file-name
(insert
";; -*- emacs-lisp -*-"
";; -*- lisp-data -*-"
;; `time-stamp-string' might not exist in all Emacs flavors.
(condition-case nil
(progn

View file

@ -250,7 +250,7 @@ Comments in the form will be lost."
map))
;;;###autoload
(define-derived-mode emacs-lisp-mode prog-mode
(define-derived-mode emacs-lisp-mode lisp-data-mode
`("ELisp"
(lexical-binding (:propertize "/l"
help-echo "Using lexical-binding mode")
@ -268,35 +268,26 @@ Blank lines separate paragraphs. Semicolons start comments.
\\{emacs-lisp-mode-map}"
:group 'lisp
(defvar project-vc-external-roots-function)
(lisp-mode-variables nil nil 'elisp)
(setcar font-lock-defaults
'(lisp-el-font-lock-keywords
lisp-el-font-lock-keywords-1
lisp-el-font-lock-keywords-2))
(setf (nth 2 font-lock-defaults) nil)
(add-hook 'after-load-functions #'elisp--font-lock-flush-elisp-buffers)
(if (boundp 'electric-pair-text-pairs)
(setq-local electric-pair-text-pairs
(append '((?\` . ?\') (?\ . ?\))
electric-pair-text-pairs))
(add-hook 'electric-pair-mode-hook #'emacs-lisp-set-electric-text-pairs))
(setq-local electric-quote-string t)
(setq imenu-case-fold-search nil)
(add-hook 'eldoc-documentation-functions
#'elisp-eldoc-documentation-function nil t)
(add-hook 'xref-backend-functions #'elisp--xref-backend nil t)
(setq-local project-vc-external-roots-function #'elisp-load-path-roots)
(add-hook 'completion-at-point-functions
#'elisp-completion-at-point nil 'local)
;; .dir-locals.el and lock files will cause the byte-compiler and
;; checkdoc emit spurious warnings, because they don't follow the
;; conventions of Emacs Lisp sources. Until we have a better fix,
;; like teaching elisp-mode about files that only hold data
;; structures, we disable the ELisp Flymake backend for these files.
(unless
(let* ((bfname (buffer-file-name))
(fname (and (stringp bfname) (file-name-nondirectory bfname))))
(and (stringp fname)
(or (string-match "\\`\\.#" fname)
(string-equal dir-locals-file fname))))
(add-hook 'flymake-diagnostic-functions #'elisp-flymake-checkdoc nil t)
(add-hook 'flymake-diagnostic-functions
#'elisp-flymake-byte-compile nil t)))
(add-hook 'flymake-diagnostic-functions #'elisp-flymake-checkdoc nil t)
(add-hook 'flymake-diagnostic-functions
#'elisp-flymake-byte-compile nil t))
;; Font-locking support.

View file

@ -248,7 +248,7 @@ may have changed) back to `save-place-alist'."
(delete-region (point-min) (point-max))
(when save-place-forget-unreadable-files
(save-place-forget-unreadable-files))
(insert (format ";;; -*- coding: %s -*-\n"
(insert (format ";;; -*- coding: %s mode: lisp-data -*-\n"
(symbol-name coding-system-for-write)))
(let ((print-length nil)
(print-level nil))