commit 4331771222fe670bd45c460b5e4f68e0dd4dc3c1 (HEAD, refs/remotes/origin/master) Author: Stefan Kangas Date: Fri Dec 16 08:47:27 2022 +0100 ; Fix merge errors diff --git a/etc/NEWS b/etc/NEWS index 4efa75fce21..af7f1050b76 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -99,14 +99,6 @@ point is not in a comment or a string. It is by default bound to * Incompatible Lisp Changes in Emacs 30.1 -*** New major mode 'go-ts-mode'. -A major mode based on the tree-sitter library for editing programs in -the Go language. It is auto-enabled for files with the ".go" extension. - -*** New major mode 'go-mod-ts-mode'. -A major mode based on the tree-sitter library for editing "go.mod" -files. It is auto-enabled for files which are named "go.mod". - * Lisp Changes in Emacs 30.1 diff --git a/etc/NEWS.29 b/etc/NEWS.29 index 701e414fdbb..dd11b3c2715 100644 --- a/etc/NEWS.29 +++ b/etc/NEWS.29 @@ -3081,6 +3081,14 @@ A major mode based on the tree-sitter library for editing files written in TOML, a format for writing configuration files. It is auto-enabled for files with the ".toml" extension. +*** New major mode 'go-ts-mode'. +A major mode based on the tree-sitter library for editing programs in +the Go language. It is auto-enabled for files with the ".go" extension. + +*** New major mode 'go-mod-ts-mode'. +A major mode based on the tree-sitter library for editing "go.mod" +files. It is auto-enabled for files which are named "go.mod". + * Incompatible Lisp Changes in Emacs 29.1 commit 03892d4f7c1253bc1affeedd227eb0a1520de90e Merge: b52d0147e9e 033071692c7 Author: Stefan Kangas Date: Fri Dec 16 08:45:06 2022 +0100 Merge from origin/emacs-29 033071692c7 ; Fix typos f4a513344d9 Add lambda_expression-rule to java-ts-mode (bug#60091) 546aed35434 eglot: Add support for new language server csharp-ls cb761eb7ac4 Use the new tree-sitter commands 037407ad95a Add "function" feature to python-ts-mode (bug#59977) fee2efe1b03 Add go-ts-mode and go-mod-ts-mode (Bug#60025) e8f7ab67ad1 Add basic support for hideshow in python-ts-mode (bug#60044) cac070b23e4 Add "this" keyword to java-ts-mode (bug#60086) c8d75046a2f When completing relative project file names, use relative... 3b618d0e3ed Avoid segfaults due to invalid selected-window's buffer # Conflicts: # lisp/progmodes/sh-script.el commit b52d0147e9ef7900f4fc07e8c2bf816b1a4ae145 Author: Stefan Kangas Date: Fri Dec 16 08:33:47 2022 +0100 Fix typo in rcirc function name * lisp/net/rcirc.el (rcirc-format-strike-through): Rename from 'rcirc-format-strike-trough'. Make old name into obsolete function alias. Update all uses. diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el index 7d4f275dc9b..81a572250af 100644 --- a/lisp/net/rcirc.el +++ b/lisp/net/rcirc.el @@ -1396,10 +1396,10 @@ rcirc-format-underline (interactive "P") (rcirc-format "\^_" replace)) -(defun rcirc-format-strike-trough (replace) - "Insert strike-trough formatting. +(defun rcirc-format-strike-through (replace) + "Insert strike-through formatting. If REPLACE is non-nil or a prefix argument is given, any prior -formatting will be replaced before the strike-trough formatting +formatting will be replaced before the strike-through formatting is inserted." (interactive "P") (rcirc-format "\^^" replace)) @@ -1421,7 +1421,7 @@ rcirc-mode-map "C-c C-f C-b" #'rcirc-format-bold "C-c C-f C-i" #'rcirc-format-italic "C-c C-f C-u" #'rcirc-format-underline - "C-c C-f C-s" #'rcirc-format-strike-trough + "C-c C-f C-s" #'rcirc-format-strike-through "C-c C-f C-f" #'rcirc-format-fixed-width "C-c C-f C-t" #'rcirc-format-fixed-width ;as in AucTeX "C-c C-f C-d" #'rcirc-unformat @@ -1807,7 +1807,7 @@ rcirc-multiline-minor-mode-map "C-c C-f C-b" #'rcirc-format-bold "C-c C-f C-i" #'rcirc-format-italic "C-c C-f C-u" #'rcirc-format-underline - "C-c C-f C-s" #'rcirc-format-strike-trough + "C-c C-f C-s" #'rcirc-format-strike-through "C-c C-f C-f" #'rcirc-format-fixed-width "C-c C-f C-t" #'rcirc-format-fixed-width ;as in AucTeX "C-c C-f C-d" #'rcirc-unformat @@ -4004,6 +4004,9 @@ rcirc-server-parameter-value (string-equal (downcase (car setting)) parameter)) return (cadr setting))) +(define-obsolete-function-alias 'rcirc-format-strike-trough + 'rcirc-format-strike-through "30.1") + (provide 'rcirc) ;;; rcirc.el ends here commit 033071692c7cd1cd550d25170d4b3168668567ac (refs/remotes/origin/emacs-29) Author: Stefan Kangas Date: Thu Dec 15 02:41:20 2022 +0100 ; Fix typos diff --git a/ChangeLog.2 b/ChangeLog.2 index 143be59c9e9..5d4c1afc369 100644 --- a/ChangeLog.2 +++ b/ChangeLog.2 @@ -28676,7 +28676,7 @@ * lisp/faces.el (set-face-attribute): Don't be fooled too easily by a hyphen in a font's name. - Fix value of posn-at-pont in R2L lines + Fix value of posn-at-point in R2L lines * src/keyboard.c (Fposn_at_x_y, Fposn_at_point): Allow X pixel coordinate of -1, for a newline in a right-to-left line that overflowed into the left fringe. diff --git a/ChangeLog.3 b/ChangeLog.3 index b162f96cb11..4b3507bae31 100644 --- a/ChangeLog.3 +++ b/ChangeLog.3 @@ -14724,7 +14724,7 @@ * lisp/icomplete.el (icomplete-vertical-mode): (fido-vertical-mode): Tweak docstring. Turn on - icomplete-mode. and fido-mdoe + icomplete-mode. and fido-mode 2021-08-16 Glenn Morris @@ -20654,7 +20654,7 @@ * lisp/progmodes/cc-engine.el (c-clear-<-pair-props, c-clear->-pair-props) (c-clear-<-pair-props-if-match-after, c-clear->-pair-props-if-match-before) (c-forward-<>-arglist-recur): - Invalidate caches with c-trunctate-lit-pos-cache. + Invalidate caches with c-truncate-lit-pos-cache. (c-forward-<>-arglist-recur): If in a matching <...> expression, the < has a syntax-table property, but the > not, remove that property. @@ -28297,7 +28297,7 @@ 2021-04-17 Eli Zaretskii - * src/emacs.c (load_pdump): Fix compilation on picky-complier platforms. + * src/emacs.c (load_pdump): Fix compilation on picky-compiler platforms. 2021-04-17 Daniel Martín @@ -29362,7 +29362,7 @@ Make the function correctly recognize a brace block preceded by an introductory line without a parameter list. - * lisp/progmodes/cc-cmds.el (c-where-wrt-brace-contruct): Reintroduce the use + * lisp/progmodes/cc-cmds.el (c-where-wrt-brace-construct): Reintroduce the use of c-beginning-of-decl-1, which was removed some weeks ago, in place of a c-syntactic-skip-backward. Reformulate the code generally. @@ -31051,7 +31051,7 @@ 2021-03-28 Lars Ingebrigtsen - Clarify the doc string of plist-memeber and plist-put + Clarify the doc string of plist-member and plist-put * src/fns.c (Fplist_member): (Fplist_put): Clarify what comparison function is used for PROP @@ -35236,7 +35236,7 @@ 2021-03-04 Andrea Corallo - * src/comp.c (hash_native_abi): Account for `system-configuraton-options'. + * src/comp.c (hash_native_abi): Account for `system-configuration-options'. 2021-03-04 Glenn Morris @@ -46491,7 +46491,7 @@ Fix Quit button in dictionary buffer - * lisp/net/dictionary.el (dictionay-close): Changing the arity of the + * lisp/net/dictionary.el (dictionary-close): Changing the arity of the function in cc5f2803785c5dc785f09a292313cf799e8d29bb was a mistake. Restore it, but mark the argument as unused to avoid a wrong-number-of-arguments error when using the Quit button. @@ -80628,7 +80628,7 @@ 2020-05-17 Andrea Corallo - Fix Garbage Collector for missing calle-saved regs content (Bug#41357) + Fix Garbage Collector for missing callee-saved regs content (Bug#41357) * src/alloc.c (SET_STACK_TOP_ADDRESS): Do not call __builtin_unwind_init. @@ -88998,7 +88998,7 @@ 2020-01-19 Stefan Kangas - Make arguments to dired-chage-marks non-optional + Make arguments to dired-change-marks non-optional * lisp/dired.el (dired-change-marks): Make arguments non-optional. (Bug#29842) @@ -103735,7 +103735,7 @@ Fixes bug#38131. - This is not the best way to have fido-mdoe emulate that particular bit + This is not the best way to have fido-mode emulate that particular bit of ido-mode. This reverts commit 5761a1a3939e23d8e8c725241dd9398a12f191b0. @@ -118445,7 +118445,7 @@ internal variable... (browse-url-browser-function, browse-url-external-browser): Used by these two; the latter of which is a new variable. - (browse-url-botton-regexp): New variable. + (browse-url-button-regexp): New variable. (browse-url-button-map): New keymap. (browse-url-button): New face. (browse-url-add-buttons): New function to add clickable browse-url @@ -139023,7 +139023,7 @@ Add 'breakpoint' to builtins for Python * lisp/progmodes/python.el (python-font-lock-keywords-level-2) - (python-font-lock-keywords-maxiumum-decoration): Add 'breakpoint' + (python-font-lock-keywords-maximum-decoration): Add 'breakpoint' to the list of builtins, it's new as of Python 3.7. 2019-03-01 Eli Zaretskii @@ -143055,7 +143055,7 @@ 2019-01-05 João Távora - New flymake-supress-zero-counters defcustom + New flymake-suppress-zero-counters defcustom A feature suggested by Yuri Khan . @@ -185861,7 +185861,7 @@ (flymake-start-syntax-check-on-find-file): Obsolete alias for flymake-start-on-flymake-mode. (flymake-start): Redesign. Affect the global post-command-hook - and local window-configuraiton-change-hook. + and local window-configuration-change-hook. (flymake--schedule-timer-maybe) (flymake-after-change-function, flymake-after-save-hook): Pass t to flymake-start. @@ -190903,7 +190903,7 @@ (initFrameFromEmacs) [NS_IMPL_COCOA]: Handle ns-appearance and ns-transparent-titlebar frame parameters. * doc/lispref/frames.texi (Window Management Parameters): Document - ns-apperance and ns-transparent-titlebar. + ns-appearance and ns-transparent-titlebar. 2017-08-22 Alan Mackenzie @@ -204016,7 +204016,7 @@ 2017-04-02 Michael Albinus - Apply connecion-local variables for shells + Apply connection-local variables for shells * doc/misc/tramp.texi (Remote processes): Show use of connection-local variables. Don't mention Emacs 23 anymore. @@ -204027,7 +204027,7 @@ (connection-local-set-profiles, with-connection-local-profiles): Adapt docstring. - * lisp/shell.el (shell): Apply connecion-local variables. + * lisp/shell.el (shell): Apply connection-local variables. 2017-04-01 Evgeni Kolev (tiny change) @@ -206673,7 +206673,7 @@ * lisp/emacs-lisp/package.el (package-initialize): Check `after-init-time' rather than `load-file-name' to decide if `package--ensure-init-file' should be called. Depending on - `load-file-name' will fail if the user calls `pacakge-initialize' in + `load-file-name' will fail if the user calls `package-initialize' in file which is loaded from the init file (Bug#24643, Bug#25819). 2017-02-26 Eli Zaretskii @@ -229958,7 +229958,7 @@ Use #' read syntax for functions. (file-notify-test05-dir-validity) (file-notify-test06-many-events): Simplify directory creation. - (file-notify-test09-sufficient-ressources): New test. + (file-notify-test09-sufficient-resources): New test. 2016-03-04 Lars Ingebrigtsen @@ -231088,7 +231088,7 @@ * lisp/gnus/gnus-rfc1843.el: New file for Gnus/rfc1843 interface functions. - * lisp/gnus/gnus-rfc1843.el: Move all Gnus-specifig functions to + * lisp/gnus/gnus-rfc1843.el: Move all Gnus-specific functions to gnus-rfc1843. 2016-02-22 Lars Ingebrigtsen diff --git a/doc/lispref/ChangeLog.1 b/doc/lispref/ChangeLog.1 index 7c7d49967cd..82840aed1d6 100644 --- a/doc/lispref/ChangeLog.1 +++ b/doc/lispref/ChangeLog.1 @@ -886,7 +886,7 @@ 2014-03-15 Dmitry Gutov * display.texi (Blinking): Update WRT to the new - `blink-matchin-paren' behavior. + `blink-matching-paren' behavior. 2014-03-14 Martin Rudalics diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index c472f9b4411..9ff9614a667 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -5015,7 +5015,7 @@ Parser-based Indentation modes, treesit-comment-start}). This function assumes @var{parent} is the comment node. -@item coment-start-skip +@item comment-start-skip This anchor is a function that is called with 3 arguments: @var{node}, @var{parent}, and @var{bol}, and returns the position after the comment-start token and any whitespace characters following that diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index bc5a4cf24a6..58f2703c8b5 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -719,7 +719,7 @@ Sequence Functions then with that result and the third element of @var{sequence}, etc. @var{function} should be a function of two arguments. -@var{function} is called with two arguments. @var{intial-value} +@var{function} is called with two arguments. @var{initial-value} (and then the accumulated value) is used as the first argument, and the elements in @var{sequence} are used for the second argument. diff --git a/lisp/ChangeLog.16 b/lisp/ChangeLog.16 index 1d7684be812..ef230bf9edb 100644 --- a/lisp/ChangeLog.16 +++ b/lisp/ChangeLog.16 @@ -4866,7 +4866,7 @@ 2012-10-12 Fabián Ezequiel Gallina * progmodes/python.el (python-mode-map): - Replace subtitute-key-definition with proper command remapping. + Replace substitute-key-definition with proper command remapping. (python-nav--up-list): Fix behavior for blocks on the same level. 2012-10-11 Stefan Monnier @@ -24325,7 +24325,7 @@ Pass nil for `after-find-file-from-revert-buffer'. * saveplace.el (save-place-find-file-hook): Use new variable - `rever-buffer-in-progress-p', not `after-find-file-from-revert-buffer'. + `revert-buffer-in-progress-p', not `after-find-file-from-revert-buffer'. 2011-04-06 Glenn Morris diff --git a/lisp/ChangeLog.17 b/lisp/ChangeLog.17 index c494f438967..57620513e3b 100644 --- a/lisp/ChangeLog.17 +++ b/lisp/ChangeLog.17 @@ -25522,7 +25522,7 @@ * textmodes/ispell.el (ispell-add-per-file-word-list): Fix `flyspell-correct-word-before-point' error when accepting - words and `coment-padding' is an integer by using + words and `comment-padding' is an integer by using `comment-normalize-vars' (Bug #14214). 2013-04-17 Fabián Ezequiel Gallina diff --git a/lisp/epa-ks.el b/lisp/epa-ks.el index 4c539b56a37..bb64b61b8fa 100644 --- a/lisp/epa-ks.el +++ b/lisp/epa-ks.el @@ -109,7 +109,7 @@ epa-ks-mark-key-to-fetch actually import the keys. When called interactively, `epa-ks-mark-key-to-fetch' will always -add a \"F\" tag. Non-interactivly the tag must be specified by +add a \"F\" tag. Non-interactively the tag must be specified by setting the TAG parameter." (interactive (list "F")) (if (region-active-p) diff --git a/lisp/gnus/ChangeLog.2 b/lisp/gnus/ChangeLog.2 index fd5fa0542f4..4ac69b575f5 100644 --- a/lisp/gnus/ChangeLog.2 +++ b/lisp/gnus/ChangeLog.2 @@ -10070,7 +10070,7 @@ * gnus-group.el (gnus-group-delete-group): Nix the entry in gnus-cache-active-hashtb. - * gnus-agent.el (gnus-agent-mark-unread-afer-downloaded): New variable. + * gnus-agent.el (gnus-agent-mark-unread-after-downloaded): New variable. (gnus-agent-summary-fetch-group): Use it. * gnus-msg.el (gnus-debug-files): New variable. diff --git a/lisp/gnus/ChangeLog.3 b/lisp/gnus/ChangeLog.3 index 3b41e9edc94..8c1073dc8db 100644 --- a/lisp/gnus/ChangeLog.3 +++ b/lisp/gnus/ChangeLog.3 @@ -6032,7 +6032,7 @@ Make `default' the default, for compatibility with open-network-stream. Handle the no-parameter case exactly as open-network-stream, with no additional stream processing. Search plists using plist-get. - Explicitly add :end-of-commend parameter if it is missing. + Explicitly add :end-of-comment parameter if it is missing. (proto-stream-open-default): Rename from proto-stream-open-network-only. Return 'default as the type. (proto-stream-open-starttls): Rename from proto-stream-open-network. diff --git a/lisp/org/ChangeLog.1 b/lisp/org/ChangeLog.1 index f79d8bf6743..4f51c6a1ebb 100644 --- a/lisp/org/ChangeLog.1 +++ b/lisp/org/ChangeLog.1 @@ -1867,7 +1867,7 @@ * org.el: Use `org-define-obsolete-{function,variable}-alias´instead of - `define-obsolate{function,variable}-alias´. + `define-obsolete-{function,variable}-alias´. * org-compat.el (user-error): Defalias to `error´ for Emacsen that don't have it. diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el index cd2fc7c7079..395c51d5421 100644 --- a/lisp/progmodes/idlwave.el +++ b/lisp/progmodes/idlwave.el @@ -133,7 +133,7 @@ ;; limited to comments only and occurs only when a comment ;; paragraph is filled via `idlwave-fill-paragraph'. ;; -;; Muti-statement lines (using "&") on block begin and end lines can +;; Multi-statement lines (using "&") on block begin and end lines can ;; ruin the formatting. For example, multiple end statements on a ;; line: endif & endif. Using "&" outside of block begin/end lines ;; should be okay. diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 8ec14cf7ad1..a776ff91f9b 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -1928,7 +1928,7 @@ js--unary-keyword-p ;; identified as such), then the `syntax-propertize' region won’t be ;; extended backwards to the start of the JSXOpeningElement: ;; -;;
← Despite completing the JSX, the next ;; ^ `syntax-propertize' region wouldn’t magically ;; extend back a few lines. @@ -2090,7 +2090,7 @@ js-jsx--enclosing-tag-pos ;; JSXOpeningElement has been found, so keep ;; looking backwards for an enclosing one). (or (not close-tag-pos) (<= start close-tag-pos))))))))) - ;; Don’t return the last tag pos, as it wasn’t enclosing. + ;; Don't return the last tag pos, as it wasn't enclosing. (setq tag-beg nil close-tag-pos nil)) (and tag-beg (list tag-beg-pos tag-end-pos close-tag-pos)))) diff --git a/lisp/so-long.el b/lisp/so-long.el index 661f5ee57a9..fc991623255 100644 --- a/lisp/so-long.el +++ b/lisp/so-long.el @@ -986,7 +986,7 @@ so-long-mode-line-inactive ;; Modes that go slowly and line lengths excessive ;; Font-lock performance becoming oppressive ;; All of my CPU tied up with strings -;; These are a few of my least-favourite things +;; These are a few of my least-favorite things (defvar-local so-long-original-values nil "Alist holding the buffer's original `major-mode' value, and other data. diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el index 26a3eb69d8d..bca6a5e81ad 100644 --- a/lisp/textmodes/toml-ts-mode.el +++ b/lisp/textmodes/toml-ts-mode.el @@ -159,7 +159,7 @@ toml-ts-mode ;; Comments (setq-local comment-start "# ") - (setq-local commend-end "") + (setq-local comment-end "") ;; Indent. (setq-local treesit-simple-indent-rules toml-ts-mode--indent-rules) diff --git a/lisp/treesit.el b/lisp/treesit.el index 353a9bc12c1..74476f18619 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1977,9 +1977,9 @@ treesit-inspect-node-at-point collect node)) (largest-node (car (last node-list))) (parent (treesit-node-parent largest-node)) - ;; node-list-acending contains all the node bottom-up, then + ;; node-list-ascending contains all the node bottom-up, then ;; the parent. - (node-list-acending + (node-list-ascending (if (null largest-node) ;; If there are no nodes that start at point, just show ;; the node at point and its parent. @@ -1990,7 +1990,7 @@ treesit-inspect-node-at-point (name "")) ;; We draw nodes like (parent field-name: (node)) recursively, ;; so it could be (node1 field-name: (node2 field-name: (node3))). - (dolist (node node-list-acending) + (dolist (node node-list-ascending) (setq name (concat diff --git a/oldXMenu/ChangeLog.1 b/oldXMenu/ChangeLog.1 index ebbbcd2df24..b739a231f5d 100644 --- a/oldXMenu/ChangeLog.1 +++ b/oldXMenu/ChangeLog.1 @@ -46,7 +46,7 @@ * Makefile.in (mostlyclean, clean, distclean, maintainer-clean, tags): Declare as PHONY. - (boostrap-clean): New. + (bootstrap-clean): New. 2013-10-24 Glenn Morris diff --git a/src/ChangeLog.12 b/src/ChangeLog.12 index 7f77c0ca077..f455c4de382 100644 --- a/src/ChangeLog.12 +++ b/src/ChangeLog.12 @@ -10836,7 +10836,7 @@ * gtkutil.c (xg_maybe_add_timer): Port to higher-res time stamps. * image.c (prepare_image_for_display, clear_image_cache) - (lookup_image): Port to higer-resolution time stamps. + (lookup_image): Port to higher-resolution time stamps. * keyboard.c (start_polling, bind_polling_period): Check for time stamp overflow. diff --git a/src/ChangeLog.13 b/src/ChangeLog.13 index 91f8005ac51..0c4e2909ced 100644 --- a/src/ChangeLog.13 +++ b/src/ChangeLog.13 @@ -10579,7 +10579,7 @@ (../src/$(OLDXMENU), $(OLDXMENU)): Remove. (temacs$(EXEEXT)): Depend on $(LIBXMENU), not stamp-oldxmenu. ($(lwlibdir)/liblw.a, $(oldXMenudir)/libXMenu11.a, FORCE): New targets. - (boostrap-clean): No need to remove stamp-oldxmenu. + (bootstrap-clean): No need to remove stamp-oldxmenu. Fix recently introduced bool vector overrun. This was due to an optimization that went awry. diff --git a/src/fns.c b/src/fns.c index d8744c1a4de..b6e871ad49c 100644 --- a/src/fns.c +++ b/src/fns.c @@ -3938,7 +3938,7 @@ DEFUN ("base64-decode-region", Fbase64_decode_region, Sbase64_decode_region, If the region can't be decoded, signal an error and don't modify the buffer. Optional third argument BASE64URL determines whether to use the URL variant of the base 64 encoding, as defined in RFC 4648. -If optional fourth argument INGORE-INVALID is non-nil invalid characters +If optional fourth argument IGNORE-INVALID is non-nil invalid characters are ignored instead of signaling an error. */) (Lisp_Object beg, Lisp_Object end, Lisp_Object base64url, Lisp_Object ignore_invalid) diff --git a/test/lisp/delim-col-tests.el b/test/lisp/delim-col-tests.el index 97fa0f1e8f1..2bf54d9b44c 100644 --- a/test/lisp/delim-col-tests.el +++ b/test/lisp/delim-col-tests.el @@ -100,7 +100,7 @@ delim-col-tests-delimit-columns-str-before-after "aaa [ bbb, cccc ] dddd\n" "aa [ bb, ccccccc ] ddd\n")))))) -(ert-deftest delim-col-tests-delimit-colummns-before-after () +(ert-deftest delim-col-tests-delimit-columns-before-after () (let ((delimit-columns-before "<") (delimit-columns-after ">")) (with-temp-buffer diff --git a/test/lisp/emacs-lisp/cconv-tests.el b/test/lisp/emacs-lisp/cconv-tests.el index e666fe0a4c2..537f6bfe721 100644 --- a/test/lisp/emacs-lisp/cconv-tests.el +++ b/test/lisp/emacs-lisp/cconv-tests.el @@ -60,7 +60,7 @@ cconv-tests-cl-defun-:documentation "cl-defun documentation")) (should (eq (cconv-tests-cl-defun) 'cl-defun-result))) -;; FIXME: The byte-complier croaks on this. See Bug#28557. +;; FIXME: The byte-compiler croaks on this. See Bug#28557. ;; (defmacro cconv-tests-defmacro () ;; (:documentation (concat "defmacro" " documentation")) ;; '(quote defmacro-result)) @@ -70,7 +70,7 @@ cconv-tests-cl-defun-:documentation ;; "defmacro documentation")) ;; (should (eq (cconv-tests-defmacro) 'defmacro-result))) -;; FIXME: The byte-complier croaks on this. See Bug#28557. +;; FIXME: The byte-compiler croaks on this. See Bug#28557. ;; (cl-defmacro cconv-tests-cl-defmacro () ;; (:documentation (concat "cl-defmacro" " documentation")) ;; '(quote cl-defmacro-result)) diff --git a/test/lisp/emacs-lisp/checkdoc-tests.el b/test/lisp/emacs-lisp/checkdoc-tests.el index 289476f0246..c17415cbdd1 100644 --- a/test/lisp/emacs-lisp/checkdoc-tests.el +++ b/test/lisp/emacs-lisp/checkdoc-tests.el @@ -130,25 +130,25 @@ checkdoc-tests--abbrev-test (re-search-forward goto-string) (checkdoc-in-abbreviation-p (point)))) -(ert-deftest checkdoc-tests-in-abbrevation-p/basic-case () +(ert-deftest checkdoc-tests-in-abbreviation-p/basic-case () (should (checkdoc-tests--abbrev-test "foo bar e.g. baz" "e.g")) (should (checkdoc-tests--abbrev-test "behavior/errors etc. that" "etc")) (should (checkdoc-tests--abbrev-test "foo vs. bar" "vs")) (should (checkdoc-tests--abbrev-test "spy a.k.a. spy" "a.k.a"))) -(ert-deftest checkdoc-tests-in-abbrevation-p/with-parens () +(ert-deftest checkdoc-tests-in-abbreviation-p/with-parens () (should (checkdoc-tests--abbrev-test "foo bar (e.g. baz)" "e.g"))) -(ert-deftest checkdoc-tests-in-abbrevation-p/with-escaped-parens () +(ert-deftest checkdoc-tests-in-abbreviation-p/with-escaped-parens () (should (checkdoc-tests--abbrev-test "foo\n\\(e.g. baz)" "e.g"))) -(ert-deftest checkdoc-tests-in-abbrevation-p/single-char () +(ert-deftest checkdoc-tests-in-abbreviation-p/single-char () (should (checkdoc-tests--abbrev-test "a. foo bar" "a"))) -(ert-deftest checkdoc-tests-in-abbrevation-p/with-em-dash () +(ert-deftest checkdoc-tests-in-abbreviation-p/with-em-dash () (should (checkdoc-tests--abbrev-test "foo bar baz---e.g." "e.g"))) -(ert-deftest checkdoc-tests-in-abbrevation-p/incorrect-abbreviation () +(ert-deftest checkdoc-tests-in-abbreviation-p/incorrect-abbreviation () (should-not (checkdoc-tests--abbrev-test "foo bar a.b.c." "a.b.c"))) (defun checkdoc-test-error-format-is-good (msg &optional reverse literal) diff --git a/test/lisp/emacs-lisp/find-func-tests.el b/test/lisp/emacs-lisp/find-func-tests.el index d18a9dc1a94..8c432f87200 100644 --- a/test/lisp/emacs-lisp/find-func-tests.el +++ b/test/lisp/emacs-lisp/find-func-tests.el @@ -87,7 +87,7 @@ find-func-tests--locate-library (test-locate-helper #'forward-char '(forward-char . "cmds.c")) (should-error (test-locate-helper 'wrong-function))) -(ert-deftest find-func-tests--locate-adviced-symbols () +(ert-deftest find-func-tests--locate-advised-symbols () (defun my-message () (message "Hello!")) (advice-add #'mark-sexp :around 'my-message) diff --git a/test/lisp/erc/resources/services/auth-source/recon.eld b/test/lisp/erc/resources/services/auth-source/recon.eld index 40ea3c9157d..2ab52c9bec8 100644 --- a/test/lisp/erc/resources/services/auth-source/recon.eld +++ b/test/lisp/erc/resources/services/auth-source/recon.eld @@ -21,7 +21,7 @@ (0.00 ":irc.foonet.net 376 tester :End of message of the day.")) ((mode-a 10 "MODE tester +i") - (0.00 ":irc.foonet.net 501 tester x :is not a recognised user mode.") + (0.00 ":irc.foonet.net 501 tester x :is not a recognized user mode.") (0.04 ":tester!tester@10.0.2.100 MODE tester :+i") (0.00 ":NickServ!NickServ@services.int NOTICE tester :This nickname is registered. Please choose a different nickname, or identify via \2/msg NickServ identify \2.")) commit 0c4ca9f007c773bb45cc6070bbffb643c830040b Author: Stefan Kangas Date: Fri Dec 16 07:49:17 2022 +0100 Fix typo in rcirc variable name * lisp/net/rcirc.el (rcirc-track-abbreviate-flag): Rename from misspelled 'rcirc-track-abbrevate-flag'. Make old name into obsolete variable alias. * doc/misc/rcirc.texi (Channels): Update above variable name. diff --git a/doc/misc/rcirc.texi b/doc/misc/rcirc.texi index 84933a9ca72..37d62c7c41a 100644 --- a/doc/misc/rcirc.texi +++ b/doc/misc/rcirc.texi @@ -691,11 +691,11 @@ Channels channel or nick name. Use @kbd{C-c C-@key{SPC}} to switch to these buffers. -@cindex rcirc-track-abbrevate-flag +@cindex rcirc-track-abbreviate-flag By default the channel names are abbreviated, set -@code{rcirc-track-abbrevate-flag} to a non-@code{nil} value. This might be -interesting if the IRC activities are not tracked in the mode line, -but somewhere else. +@code{rcirc-track-abbreviate-flag} to a non-@code{nil} value. This +might be interesting if the IRC activities are not tracked in the mode +line, but somewhere else. @vindex rcirc-mode-hook If you prefer not to load @code{rcirc} immediately, you can delay the diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el index 29957a62d04..7d4f275dc9b 100644 --- a/lisp/net/rcirc.el +++ b/lisp/net/rcirc.el @@ -2371,9 +2371,11 @@ rcirc-track-minor-mode-map "C-c C-@" #'rcirc-next-active-buffer "C-c C-SPC" #'rcirc-next-active-buffer) -(defcustom rcirc-track-abbrevate-flag t +(define-obsolete-variable-alias 'rcirc-track-abbrevate-flag + 'rcirc-track-abbreviate-flag "30.1") +(defcustom rcirc-track-abbreviate-flag t "Non-nil means `rcirc-track-minor-mode' should abbreviate names." - :version "28.1" + :version "30.1" :type 'boolean) ;;;###autoload @@ -2559,7 +2561,7 @@ rcirc-short-buffer-name (funcall rcirc-channel-filter (replace-regexp-in-string "@.*?\\'" "" - (or (and rcirc-track-abbrevate-flag + (or (and rcirc-track-abbreviate-flag rcirc-short-buffer-name) (buffer-name)))))) commit d9ab1027b18512e65c55d282fb3697f34a2277bb Author: Juanma Barranquero Date: Fri Dec 16 07:10:28 2022 +0100 Fix lisp/bs.el change in commit e0a057c16b of 2022-12-07 * lisp/bs.el (bs-default-action-list): Before creating a window first try `display-buffer-reuse-window', but make sure it never chooses a window in another frame. diff --git a/lisp/bs.el b/lisp/bs.el index d5e6030fac0..c976ed283c4 100644 --- a/lisp/bs.el +++ b/lisp/bs.el @@ -488,7 +488,9 @@ bs-mode-map "" #'bs-mouse-select "" #'bs-mouse-select-other-frame) -(defcustom bs-default-action-list '((display-buffer-below-selected) +(defcustom bs-default-action-list '((display-buffer-reuse-window + display-buffer-below-selected) + (reusable-frames . nil) (window-height . window-min-height)) "Default action list for showing the '*bs-selection*' buffer. commit b8eef7b8c1066cf446ca1b37d3fd5c1ea3e3ab07 Author: Jim Porter Date: Sun Dec 11 20:19:57 2022 -0800 ; Rename 'eshell-flatten-args' token to 'eshell-splice-immediately' This is for symmetry with 'eshell-splice-args' (which performs a splice later on). Since this is just an internal symbol not exposed to users, changing it is safe. * lisp/eshell/esh-arg.el (eshell-parse-arguments, eshell-finish-arg): Use 'eshell-splice-immediately'. diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index 0b175be713e..87121196715 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -301,7 +301,8 @@ eshell-finish-arg (setq eshell-current-argument (car arguments)) (cl-assert (and (not eshell-arg-listified) (not eshell-current-modifiers))) - (setq eshell-current-argument (cons 'eshell-flatten-args arguments)))) + (setq eshell-current-argument + (cons 'eshell-splice-immediately arguments)))) (throw 'eshell-arg-done t)) (defun eshell-quote-argument (string) @@ -342,7 +343,8 @@ eshell-parse-arguments (buffer-substring here (point-max)))) (when arg (nconc args - (if (eq (car-safe arg) 'eshell-flatten-args) + (if (eq (car-safe arg) + 'eshell-splice-immediately) (cdr arg) (list arg)))))))) (throw 'eshell-incomplete (if (listp delim) commit e63ef66c57ee74b24998a16b34949f67bbb73d8d Author: Jim Porter Date: Tue Nov 8 22:49:23 2022 -0800 Add support for the "splice operator" in Eshell This allows splicing lists in-place in argument lists, which is particularly important when defining aliases using the '$*' special variable (bug#59960). * lisp/eshell/esh-var.el (eshell-parse-variable): Add support for the splice operator. (eshell-interpolate-variable): Let 'eshell-parse-variable' handle adding 'eshell-escape-arg'. (eshell-complete-variable-reference): Handle the splice operator. * lisp/eshell/esh-arg.el (eshell-concat-groups) (eshell-prepare-splice): New functions... (eshell-resolve-current-argument): ... use them. (eshell-splice-args): New function. * lisp/eshell/esh-cmd.el (eshell-rewrite-named-command): Handle 'eshell-splice-args'. * lisp/eshell/esh-util.el (eshell-list-to-string): New function... (eshell-flatten-and-stringify): ... use it. * lisp/eshell/em-cmpl.el (eshell-complete-parse-arguments): Remove 'eshell-splice-args' sigils in Eshell command forms so that we can perform completion on splice-expansions. * lisp/eshell/em-unix.el (eshell-complete-host-reference): Don't try to complete arguments containing "$@". * test/lisp/eshell/esh-var-tets.el (esh-var-test/interp-list-var) (esh-var-test/interp-list-var-concat, esh-var-test/interp-var-splice) (esh-var-test/interp-var-splice-concat) (esh-var-test/quoted-interp-list-var) (esh-var-test/quoted-interp-list-var-concat) (esh-var-test/quoted-interp-var-splice) (esh-var-test/quoted-interp-var-splice-concat): New tests. * test/lisp/eshell/em-alias-tests.el (em-alias-test/alias-all-args-var-splice): New test. * doc/misc/eshell.texi (Dollars Expansion): Explain the splice operator. (Aliases): Expand documentation and use '$@*'. (Built-ins, Bugs and Ideas): Use '$@*' where appropriate. * etc/NEWS: Announce this change. diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index 1383b412ce7..f9796d69a9a 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -349,9 +349,9 @@ Built-ins @example ~ $ which sudo eshell/sudo is a compiled Lisp function in `em-tramp.el'. -~ $ alias sudo '*sudo $*' +~ $ alias sudo '*sudo $@@*' ~ $ which sudo -sudo is an alias, defined as "*sudo $*" +sudo is an alias, defined as "*sudo $@@*" @end example @vindex eshell-prefer-lisp-functions @@ -475,7 +475,7 @@ Built-ins If @code{eshell-plain-diff-behavior} is non-@code{nil}, then this command does not use Emacs's internal @code{diff}. This is the same -as using @samp{alias diff '*diff $*'}. +as using @samp{alias diff '*diff $@@*'}. @item dirname @cmindex dirname @@ -545,9 +545,9 @@ Built-ins If @code{eshell-plain-grep-behavior} is non-@code{nil}, then these commands do not use Emacs's internal @code{grep}. This is the same as -using @samp{alias grep '*grep $*'}, though this setting applies to all -of the built-in commands for which you would need to create a separate -alias. +using @samp{alias grep '*grep $@@*'}, though this setting applies to +all of the built-in commands for which you would need to create a +separate alias. @item history @cmindex history @@ -603,7 +603,7 @@ Built-ins If @code{eshell-plain-locate-behavior} is non-@code{nil}, then Emacs's internal @code{locate} is not used. This is the same as using -@samp{alias locate '*locate $*'}. +@samp{alias locate '*locate $@@*'}. @item ls @cmindex ls @@ -1027,25 +1027,47 @@ Variables @node Aliases @section Aliases -@vindex $* -@findex eshell-expand-history-references +@findex eshell-read-aliases-list Aliases are commands that expand to a longer input line. For example, -@command{ll} is a common alias for @code{ls -l}, and would be defined -with the command invocation @kbd{alias ll 'ls -l $*'}; with this defined, -running @samp{ll foo} in Eshell will actually run @samp{ls -l foo}. -Aliases defined (or deleted) by the @command{alias} command are -automatically written to the file named by @code{eshell-aliases-file}, -which you can also edit directly. After doing so, use @w{@kbd{M-x -eshell-read-aliases-list}} to load the edited aliases. - -@vindex $1, $2, @dots{} +@command{ll} is a common alias for @code{ls -l}. To define this alias +in Eshell, you can use the command invocation @kbd{alias ll 'ls -l +$@@*'}; with this defined, running @samp{ll foo} in Eshell will +actually run @samp{ls -l foo}. Aliases defined (or deleted) by the +@command{alias} command are automatically written to the file named by +@code{eshell-aliases-file}, which you can also edit directly. After +doing so, use @w{@kbd{M-x eshell-read-aliases-list}} to load the +edited aliases. + Note that unlike aliases in Bash, arguments must be handled -explicitly. Typically the alias definition would end in @samp{$*} to -pass all arguments along. More selective use of arguments via -@samp{$1}, @samp{$2}, etc., is also possible. For example, +explicitly. Within aliases, you can use the special variables +@samp{$*}, @samp{$0}, @samp{$1}, @samp{$2}, etc. to refer to the +arguments passed to the alias. + +@table @code + +@vindex $* +@item $* +This expands to the list of arguments passed to the alias. For +example, if you run @code{my-alias 1 2 3}, then @samp{$*} would be the +list @code{(1 2 3)}. Note that since this variable is a list, using +@samp{$*} in an alias will pass this list as a single argument to the +aliased command. Therefore, when defining an alias, you should +usually use @samp{$@@*} to pass all arguments along, splicing them +into your argument list (@pxref{Dollars Expansion}). + +@vindex $0 +@item $0 +This expands to the name of the alias currently being executed. + +@vindex $1, $2, @dots{}, $9 +@item $1, $2, @dots{}, $9 +These variables expand to the nth argument (starting at 1) passed to +the alias. This lets you selectively use an alias's arguments, so @kbd{alias mcd 'mkdir $1 && cd $1'} would cause @kbd{mcd foo} to create and switch to a directory called @samp{foo}. +@end table + @node History @section History @cmindex history @@ -1307,12 +1329,36 @@ Dollars Expansion number. For example, @samp{$@var{var}[: 0]} will return the first element of a colon-delimited string. +@cindex length operator, in variable expansion @item $#@var{expr} -Expands to the length of the result of @var{expr}, an expression in -one of the above forms. For example, @samp{$#@var{var}} returns the -length of the variable @var{var} and @samp{$#@var{var}[0]} returns the -length of the first element of @var{var}. Again, signals an error if -the result of @var{expr} is not a string or a sequence. +This is the @dfn{length operator}. It expands to the length of the +result of @var{expr}, an expression in one of the above forms. For +example, @samp{$#@var{var}} returns the length of the variable +@var{var} and @samp{$#@var{var}[0]} returns the length of the first +element of @var{var}. Again, signals an error if the result of +@var{expr} is not a string or a sequence. + +@cindex splice operator, in variable expansion +@item $@@@var{expr} +This is the @dfn{splice operator}. It ``splices'' the elements of +@var{expr} (an expression of one of the above forms) into the +resulting list of arguments, much like the @samp{,@@} marker in Emacs +Lisp (@pxref{Backquote, , , elisp, The Emacs Lisp Reference Manual}). +The elements of @var{expr} become arguments at the same level as the +other arguments around it. For example, if @var{numbers} is the list +@code{(1 2 3)}, then: + +@example +@group +~ $ echo 0 $numbers +(0 + (1 2 3)) +@end group +@group +~ $ echo 0 $@@numbers +(0 1 2 3) +@end group +@end example @end table @@ -2031,7 +2077,7 @@ Bugs and ideas @example alias arg=blah -function arg () @{ blah $* @} +function arg () @{ blah $@@* @} @end example @item Pcomplete sometimes gets stuck diff --git a/etc/NEWS b/etc/NEWS index 9c60e444c08..af7f1050b76 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -71,6 +71,16 @@ switches for shortlogs, such as the one produced by 'C-x v L'. You can now configure how to display the "*buffer-selection*" buffer using this new option. (Or set 'display-buffer-alist' directly.) +** Eshell + ++++ +*** New splice operator for Eshell dollar expansions. +Dollar expansions in Eshell now let you splice the elements of the +expansion in-place using '$@expr'. This makes it easier to fill lists +of arguments into a command, such as when defining aliases. For more +information, see the "(eshell) Dollars Expansion" node in the Eshell +manual. + +++ *** 'eshell-read-aliases-list' is now an interactive command. After manually editing 'eshell-aliases-file', you can use diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el index ac82e3f225c..2c721eb9e31 100644 --- a/lisp/eshell/em-cmpl.el +++ b/lisp/eshell/em-cmpl.el @@ -342,17 +342,23 @@ eshell-complete-parse-arguments (setq pos (1+ pos)))) (setq posns (cdr posns)) (cl-assert (= (length args) (length posns))) - (let ((a args) - (i 0) - l) + (let ((a args) (i 0) new-start) (while a - (if (and (consp (car a)) - (eq (caar a) 'eshell-operator)) - (setq l i)) - (setq a (cdr a) i (1+ i))) - (and l - (setq args (nthcdr (1+ l) args) - posns (nthcdr (1+ l) posns)))) + ;; Remove any top-level `eshell-splice-args' sigils. These + ;; are meant to be rewritten and can't actually be called. + (when (and (consp (car a)) + (eq (caar a) 'eshell-splice-args)) + (setcar a (cadar a))) + ;; If there's an unreplaced `eshell-operator' sigil, consider + ;; the token after it the new start of our arguments. + (when (and (consp (car a)) + (eq (caar a) 'eshell-operator)) + (setq new-start i)) + (setq a (cdr a) + i (1+ i))) + (when new-start + (setq args (nthcdr (1+ new-start) args) + posns (nthcdr (1+ new-start) posns)))) (cl-assert (= (length args) (length posns))) (when (and args (eq (char-syntax (char-before end)) ? ) (not (eq (char-before (1- end)) ?\\))) diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index 4b5e4dd53ed..3f7ec618a33 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -786,10 +786,14 @@ 'eshell-complete-hostname (defun eshell-complete-host-reference () "If there is a host reference, complete it." - (let ((arg (pcomplete-actual-arg)) - index) - (when (setq index (string-match "@[a-z.]*\\'" arg)) - (setq pcomplete-stub (substring arg (1+ index)) + (let ((arg (pcomplete-actual-arg))) + (when (string-match + (rx ;; Match an "@", but not immediately following a "$". + (or string-start (not "$")) "@" + (group (* (any "a-z."))) + string-end) + arg) + (setq pcomplete-stub (substring arg (match-beginning 1)) pcomplete-last-completion-raw t) (throw 'pcomplete-completions (pcomplete-read-host-names))))) diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el index cfec04e183d..0b175be713e 100644 --- a/lisp/eshell/esh-arg.el +++ b/lisp/eshell/esh-arg.el @@ -238,13 +238,53 @@ eshell-concat-1 (eshell-convert-to-number result) result))) +(defun eshell-concat-groups (quoted &rest args) + "Concatenate groups of arguments in ARGS and return the result. +QUOTED is passed to `eshell-concat' (which see) and, if non-nil, +allows values to be converted to numbers where appropriate. + +ARGS should be a list of lists of arguments, such as that +produced by `eshell-prepare-slice'. \"Adjacent\" values of +consecutive arguments will be passed to `eshell-concat'. For +example, if ARGS is + + ((list a) (list b) (list c d e) (list f g)), + +then the result will be: + + ((eshell-concat QUOTED a b c) + d + (eshell-concat QUOTED e f) + g)." + (let (result current-arg) + (dolist (arg args) + (when arg + (push (car arg) current-arg) + (when (length> arg 1) + (push (apply #'eshell-concat quoted (nreverse current-arg)) + result) + (dolist (inner (butlast (cdr arg))) + (push inner result)) + (setq current-arg (list (car (last arg))))))) + (when current-arg + (push (apply #'eshell-concat quoted (nreverse current-arg)) + result)) + (nreverse result))) + (defun eshell-resolve-current-argument () "If there are pending modifications to be made, make them now." (when eshell-current-argument (when eshell-arg-listified - (setq eshell-current-argument - (append (list 'eshell-concat eshell-current-quoted) - eshell-current-argument)) + (if-let ((grouped-terms (eshell-prepare-splice + eshell-current-argument))) + (setq eshell-current-argument + `(eshell-splice-args + (eshell-concat-groups ,eshell-current-quoted + ,@grouped-terms))) + ;; If no terms are spliced, use a simpler command form. + (setq eshell-current-argument + (append (list 'eshell-concat eshell-current-quoted) + eshell-current-argument))) (setq eshell-arg-listified nil)) (while eshell-current-modifiers (setq eshell-current-argument @@ -348,6 +388,10 @@ eshell-operator "A stub function that generates an error if a floating operator is found." (error "Unhandled operator in input text")) +(defsubst eshell-splice-args (&rest _args) + "A stub function that generates an error if a floating splice is found." + (error "Splice operator is not permitted in this context")) + (defsubst eshell-looking-at-backslash-return (pos) "Test whether a backslash-return sequence occurs at POS." (and (eq (char-after pos) ?\\) @@ -500,5 +544,32 @@ eshell-parse-delimiter (char-to-string (char-after))))) (goto-char end))))))) +(defun eshell-prepare-splice (args) + "Prepare a list of ARGS for splicing, if any arg requested a splice. +This looks for `eshell-splice-args' as the CAR of each argument, +and if found, returns a grouped list like: + + ((list arg-1) (list arg-2) spliced-arg-3 ...) + +This allows callers of this function to build the final spliced +list by concatenating each element together, e.g. with (apply +#'append grouped-list). + +If no argument requested a splice, return nil." + (let* ((splicep nil) + ;; Group each arg like ((list arg-1) (list arg-2) ...), + ;; splicing in `eshell-splice-args' args. This lets us + ;; apply spliced args correctly elsewhere. + (grouped-args + (mapcar (lambda (i) + (if (eq (car-safe i) 'eshell-splice-args) + (progn + (setq splicep t) + (cadr i)) + `(list ,i))) + args))) + (when splicep + grouped-args))) + (provide 'esh-arg) ;;; esh-arg.el ends here diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index 4a41bbe8fa1..1fb84991120 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -480,11 +480,16 @@ eshell-rewrite-named-command (let ((sym (if eshell-in-pipeline-p 'eshell-named-command* 'eshell-named-command)) - (cmd (car terms)) - (args (cdr terms))) - (if args - (list sym cmd `(list ,@(cdr terms))) - (list sym cmd)))) + (grouped-terms (eshell-prepare-splice terms))) + (cond + (grouped-terms + `(let ((terms (nconc ,@grouped-terms))) + (,sym (car terms) (cdr terms)))) + ;; If no terms are spliced, use a simpler command form. + ((cdr terms) + (list sym (car terms) `(list ,@(cdr terms)))) + (t + (list sym (car terms)))))) (defvar eshell-command-body) (defvar eshell-test-body) diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el index 0ec11e8a0b3..aceca28befb 100644 --- a/lisp/eshell/esh-util.el +++ b/lisp/eshell/esh-util.el @@ -362,9 +362,13 @@ eshell-stringify-list "Convert each element of ARGS into a string value." (mapcar #'eshell-stringify args)) +(defsubst eshell-list-to-string (list) + "Convert LIST into a single string separated by spaces." + (mapconcat #'eshell-stringify list " ")) + (defsubst eshell-flatten-and-stringify (&rest args) "Flatten and stringify all of the ARGS into a single string." - (mapconcat #'eshell-stringify (flatten-tree args) " ")) + (eshell-list-to-string (flatten-tree args))) (defsubst eshell-directory-files (regexp &optional directory) "Return a list of files in the given DIRECTORY matching REGEXP." diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index 5824da6dc0e..61e9af01a4d 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -86,6 +86,13 @@ ;; Returns the length of the value of $EXPR. This could also be ;; done using the `length' Lisp function. ;; +;; $@EXPR +;; +;; Splices the value of $EXPR in-place into the current list of +;; arguments. This is analogous to the `,@' token in Elisp +;; backquotes, and works as if the user typed '$EXPR[0] $EXPR[1] +;; ... $EXPR[N]'. +;; ;; There are also a few special variables defined by Eshell. '$$' is ;; the value of the last command (t or nil, in the case of an external ;; command). This makes it possible to chain results: @@ -320,10 +327,9 @@ eshell-interpolate-variable "Parse a variable interpolation. This function is explicit for adding to `eshell-parse-argument-hook'." (when (and (eq (char-after) ?$) - (/= (1+ (point)) (point-max))) + (/= (1+ (point)) (point-max))) (forward-char) - (list 'eshell-escape-arg - (eshell-parse-variable)))) + (eshell-parse-variable))) (defun eshell/define (var-alias definition) "Define a VAR-ALIAS using DEFINITION." @@ -453,6 +459,8 @@ eshell-parse-variable process any indices that come after the variable reference." (let* ((get-len (when (eq (char-after) ?#) (forward-char) t)) + (splice (when (eq (char-after) ?@) + (forward-char) t)) value indices) (setq value (eshell-parse-variable-ref get-len) indices (and (not (eobp)) @@ -464,7 +472,13 @@ eshell-parse-variable (when get-len (setq value `(length ,value))) (when eshell-current-quoted - (setq value `(eshell-stringify ,value))) + (if splice + (setq value `(eshell-list-to-string ,value) + splice nil) + (setq value `(eshell-stringify ,value)))) + (setq value `(eshell-escape-arg ,value)) + (when splice + (setq value `(eshell-splice-args ,value))) value)) (defun eshell-parse-variable-ref (&optional modifier-p) @@ -753,7 +767,7 @@ eshell-complete-variable-reference "If there is a variable reference, complete it." (let ((arg (pcomplete-actual-arg))) (when (string-match - (rx "$" (? "#") + (rx "$" (? (or "#" "@")) (? (group (regexp eshell-variable-name-regexp))) string-end) arg) diff --git a/test/lisp/eshell/em-alias-tests.el b/test/lisp/eshell/em-alias-tests.el index aca622220e3..0a26e8d2011 100644 --- a/test/lisp/eshell/em-alias-tests.el +++ b/test/lisp/eshell/em-alias-tests.el @@ -72,6 +72,15 @@ em-alias-test/alias-all-args-var (eshell-match-command-output "show-all-args a" "a\n") (eshell-match-command-output "show-all-args a b c" "a\nb\nc\n"))) +(ert-deftest em-alias-test/alias-all-args-var-splice () + "Test alias with splicing the $* variable" + (with-temp-eshell + (eshell-insert-command "alias show-all-args 'echo args: $@*'") + (eshell-match-command-output "show-all-args" "args:\n") + (eshell-match-command-output "show-all-args a" "(\"args:\" \"a\")\n") + (eshell-match-command-output "show-all-args a b c" + "(\"args:\" \"a\" \"b\" \"c\")\n"))) + (ert-deftest em-alias-test/alias-all-args-var-indices () "Test alias with the $* variable using indices" (with-temp-eshell diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 96fde026a54..d95669fdaf8 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -60,6 +60,18 @@ esh-var-test/interp-quoted-var-concat (eshell-command-result-equal "echo $\"user-login-name\"-foo" (concat user-login-name "-foo"))) +(ert-deftest esh-var-test/interp-list-var () + "Interpolate list variable" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo $eshell-test-value" + '(1 2 3)))) + +(ert-deftest esh-var-test/interp-list-var-concat () + "Interpolate and concat list variable" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo a$'eshell-test-value'z" + '("a1" 2 "3z")))) + (ert-deftest esh-var-test/interp-var-indices () "Interpolate list variable with indices" (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) @@ -131,6 +143,26 @@ esh-var-test/interp-var-length-alist (eshell-command-result-equal "echo $#eshell-test-value" 1) (eshell-command-result-equal "echo $#eshell-test-value[foo]" 3))) +(ert-deftest esh-var-test/interp-var-splice () + "Splice-interpolate list variable" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo a $@eshell-test-value z" + '("a" 1 2 3 "z")))) + +(ert-deftest esh-var-test/interp-var-splice-concat () + "Splice-interpolate and concat list variable" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo it is a$@'eshell-test-value'z" + '("it" "is" "a1" 2 "3z")) + ;; This is a tricky case. We're concatenating a spliced list and + ;; a non-spliced list. The general rule is that splicing should + ;; work as though the user typed "$X[0] $X[1] ... $X[N]". That + ;; means that the last value of our splice should get concatenated + ;; into the first value of the non-spliced list. + (eshell-command-result-equal + "echo it is $@'eshell-test-value'$eshell-test-value" + '("it" "is" 1 2 (31 2 3))))) + (ert-deftest esh-var-test/interp-lisp () "Interpolate Lisp form evaluation" (eshell-command-result-equal "+ $(+ 1 2) 3" 6)) @@ -197,6 +229,9 @@ esh-var-test/interp-concat-cmd-external (eshell-match-command-output "echo ${echo hi}-${*echo there}" "hi-there\n"))) + +;; Quoted variable interpolation + (ert-deftest esh-var-test/quoted-interp-var () "Interpolate variable inside double-quotes" (eshell-command-result-equal "echo \"$user-login-name\"" @@ -209,6 +244,18 @@ esh-var-test/quoted-interp-quoted-var (eshell-command-result-equal "echo \"hi, $\\\"user-login-name\\\"\"" (concat "hi, " user-login-name))) +(ert-deftest esh-var-test/quoted-interp-list-var () + "Interpolate list variable inside double-quotes" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo \"$eshell-test-value\"" + "(1 2 3)"))) + +(ert-deftest esh-var-test/quoted-interp-list-var-concat () + "Interpolate and concat list variable inside double-quotes" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo \"a$'eshell-test-value'z\"" + "a(1 2 3)z"))) + (ert-deftest esh-var-test/quoted-interp-var-indices () "Interpolate string variable with indices inside double-quotes" (let ((eshell-test-value '("zero" "one" "two" "three" "four"))) @@ -291,6 +338,18 @@ esh-var-test/quoted-interp-var-length-alist (eshell-command-result-equal "echo \"$#eshell-test-value[foo]\"" "3"))) +(ert-deftest esh-var-test/quoted-interp-var-splice () + "Splice-interpolate list variable inside double-quotes" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo a \"$@eshell-test-value\" z" + '("a" "1 2 3" "z")))) + +(ert-deftest esh-var-test/quoted-interp-var-splice-concat () + "Splice-interpolate and concat list variable inside double-quotes" + (let ((eshell-test-value '(1 2 3))) + (eshell-command-result-equal "echo \"a$@'eshell-test-value'z\"" + "a1 2 3z"))) + (ert-deftest esh-var-test/quoted-interp-lisp () "Interpolate Lisp form evaluation inside double-quotes" (eshell-command-result-equal "echo \"hi $(concat \\\"the\\\" \\\"re\\\")\"" @@ -324,6 +383,21 @@ esh-var-test/quoted-interp-concat-cmd (eshell-command-result-equal "echo \"${echo \\\"foo\nbar\\\"} baz\"" "foo\nbar baz")) + +;; Interpolating commands + +(ert-deftest esh-var-test/command-interp () + "Interpolate a variable as a command name" + (let ((eshell-test-value "printnl")) + (eshell-command-result-equal "$eshell-test-value hello there" + "hello\nthere\n"))) + +(ert-deftest esh-var-test/command-interp-splice () + "Interpolate a splice variable as a command name with arguments" + (let ((eshell-test-value '("printnl" "hello" "there"))) + (eshell-command-result-equal "$@eshell-test-value" + "hello\nthere\n"))) + ;; Interpolated variable conversion commit 66ac920b0c233e472c7f54d108503dfe9236d3c0 Author: Jim Porter Date: Sat Dec 10 20:52:28 2022 -0800 Support completion of variables with the length operator in Eshell These are forms like '$#VARIABLE'. * lisp/eshell/esh-var.el (eshell-complete-variable-reference): Support the length operator. diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index 57ea42f4933..5824da6dc0e 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -751,12 +751,13 @@ eshell-index-value (defun eshell-complete-variable-reference () "If there is a variable reference, complete it." - (let ((arg (pcomplete-actual-arg)) index) - (when (setq index - (string-match - (concat "\\$\\(" eshell-variable-name-regexp - "\\)?\\'") arg)) - (setq pcomplete-stub (substring arg (1+ index))) + (let ((arg (pcomplete-actual-arg))) + (when (string-match + (rx "$" (? "#") + (? (group (regexp eshell-variable-name-regexp))) + string-end) + arg) + (setq pcomplete-stub (substring arg (match-beginning 1))) (throw 'pcomplete-completions (eshell-variables-list))))) (defun eshell-variables-list () commit f4a513344d95badf2b75b0577016edcdd9ea5fbe Author: Theodor Thornhill Date: Thu Dec 15 14:54:17 2022 +0100 Add lambda_expression-rule to java-ts-mode (bug#60091) * lisp/progmodes/java-ts-mode.el (java-ts-mode--indent-rules): New rule. diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 559a4efef25..9da2c254f87 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -86,6 +86,7 @@ java-ts-mode--indent-rules ((parent-is "method_invocation") parent-bol java-ts-mode-indent-offset) ((parent-is "switch_rule") parent-bol java-ts-mode-indent-offset) ((parent-is "ternary_expression") parent-bol java-ts-mode-indent-offset) + ((parent-is "lambda_expression") parent-bol java-ts-mode-indent-offset) ((parent-is "element_value_array_initializer") parent-bol java-ts-mode-indent-offset) ((parent-is "function_definition") parent-bol 0) ((parent-is "conditional_expression") first-sibling 0) commit 546aed35434fb2cd4082dc2cee93236b9b62a60c Author: Jostein Kjønigsen Date: Thu Dec 15 13:44:39 2022 +0100 eglot: Add support for new language server csharp-ls C# has two popular language servers: Omnisharp Roslyn (already supported) and csharp-ls (newer, more performant). * lisp/progmodes/eglot.el: Add new C# language server csharp-ls. (Bug#60089) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 02bb6bb665d..bb07a06dde8 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -241,7 +241,9 @@ eglot-server-programs ((clojure-mode clojurescript-mode clojurec-mode) . ("clojure-lsp")) ((csharp-mode csharp-ts-mode) - . ("omnisharp" "-lsp")) + . ,(eglot-alternatives + '(("omnisharp" "-lsp") + ("csharp-ls")))) (purescript-mode . ("purescript-language-server" "--stdio")) ((perl-mode cperl-mode) . ("perl" "-MPerl::LanguageServer" "-e" "Perl::LanguageServer::run")) (markdown-mode . ("marksman" "server"))) commit cb761eb7ac4197706658a68bb853c3fc8909d84e Author: Yuan Fu Date: Thu Dec 15 17:44:07 2022 -0800 Use the new tree-sitter commands * lisp/progmodes/c-ts-mode.el (c-ts-mode--defun-valid-p) (c-ts-mode--defun-skipper): New functions. (c-ts-base-mode): Setup defun navigation. * lisp/progmodes/sh-script.el (bash-ts-mode): Setup defun navigation. * lisp/treesit.el (treesit-beginning-of-defun) (treesit-end-of-defun): Change to new implementation, which is intended to be used as commands. (treesit-major-mode-setup): Setup remap for beginning/end-of-defun commands. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index ff2ff63fd82..97e29ca13bc 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -531,6 +531,27 @@ c-ts-mode--end-of-defun (if (looking-at "\\s<\\|\n") (forward-line 1))))) +(defun c-ts-mode--defun-valid-p (node) + (if (string-match-p + (rx (or "struct_specifier" + "enum_specifier" + "union_specifier")) + (treesit-node-type node)) + (null + (treesit-node-top-level + node (rx (or "function_definition" + "type_definition")))) + t)) + +(defun c-ts-mode--defun-skipper () + "Custom defun skipper for `c-ts-mode' and friends. +Structs in C ends with a semicolon, but the semicolon is not +considered part of the struct node, so point would stop before +the semicolon. This function skips the semicolon." + (when (looking-at (rx (* (or " " "\t")) ";")) + (goto-char (match-end 0))) + (treesit-default-defun-skipper)) + (defun c-ts-mode-indent-defun () "Indent the current top-level declaration syntactically. @@ -559,12 +580,14 @@ c-ts-base-mode ;; Navigation. (setq-local treesit-defun-type-regexp - (regexp-opt '("function_definition" - "type_definition" - "struct_specifier" - "enum_specifier" - "union_specifier" - "class_specifier"))) + (cons (regexp-opt '("function_definition" + "type_definition" + "struct_specifier" + "enum_specifier" + "union_specifier" + "class_specifier")) + #'c-ts-mode--defun-valid-p)) + (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper) ;; Nodes like struct/enum/union_specifier can appear in ;; function_definitions, so we need to find the top-level node. diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 76e8d5b0748..85da9e89f9a 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1613,6 +1613,7 @@ bash-ts-mode not written in Bash or sh." :syntax-table sh-mode-syntax-table (when (treesit-ready-p 'bash) + (treesit-parser-create 'bash) (setq-local treesit-font-lock-feature-list '(( comment function) ( command declaration-command keyword string) @@ -1620,6 +1621,7 @@ bash-ts-mode ( bracket delimiter misc-punctuation operator))) (setq-local treesit-font-lock-settings sh-mode--treesit-settings) + (setq-local treesit-defun-type-regexp "function_definition") (treesit-major-mode-setup))) (advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode diff --git a/lisp/treesit.el b/lisp/treesit.el index 58b85ddba39..353a9bc12c1 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1624,40 +1624,37 @@ treesit--defun-maybe-top-level finally return node)))) (defun treesit-beginning-of-defun (&optional arg) - "Tree-sitter `beginning-of-defun' function. -ARG is the same as in `beginning-of-defun'." - (let ((arg (or arg 1)) - (node (treesit-node-at (point)))) - (if (> arg 0) - ;; Go backward. - (while (and (> arg 0) - (setq node (treesit-search-forward-goto - node treesit-defun-type-regexp t t))) - (setq node (treesit--defun-maybe-top-level node)) - (setq arg (1- arg))) - ;; Go forward. - (while (and (< arg 0) - (setq node (treesit-search-forward-goto - node treesit-defun-type-regexp))) - (setq node (treesit--defun-maybe-top-level node)) - (setq arg (1+ arg)))) - (when node - (goto-char (treesit-node-start node)) - t))) - -(defun treesit-end-of-defun () - "Tree-sitter `end-of-defun' function." - ;; Why not simply get the largest node at point: when point is at - ;; (point-min), that gives us the root node. - (let* ((node (treesit-search-forward - (treesit-node-at (point)) treesit-defun-type-regexp t t)) - (top (treesit--defun-maybe-top-level node))) - ;; Technically `end-of-defun' should only call this function when - ;; point is at the beginning of a defun, so TOP should always be - ;; non-nil, but things happen, and we want to be safe, so check - ;; for TOP anyway. - (when top - (goto-char (treesit-node-end top))))) + "Move backward to the beginning of a defun. + +With argument ARG, do it that many times. Negative ARG means +move forward to the ARGth following beginning of defun. + +If search is successful, return t, otherwise return nil. + +This is a tree-sitter equivalent of `beginning-of-defun'. +Behavior of this function depends on `treesit-defun-type-regexp' +and `treesit-defun-skipper'." + (interactive "^p") + (when-let ((dest (treesit--navigate-defun (point) (- arg) 'beg))) + (goto-char dest) + (when treesit-defun-skipper + (funcall treesit-defun-skipper)) + t)) + +(defun treesit-end-of-defun (&optional arg _) + "Move forward to next end of defun. + +With argument ARG, do it that many times. +Negative argument -N means move back to Nth preceding end of defun. + +This is a tree-sitter equivalent of `end-of-defun'. Behavior of +this function depends on `treesit-defun-type-regexp' and +`treesit-defun-skipper'." + (interactive "^p\nd") + (when-let ((dest (treesit--navigate-defun (point) arg 'end))) + (goto-char dest) + (when treesit-defun-skipper + (funcall treesit-defun-skipper)))) (defun treesit-default-defun-skipper () "Skips spaces after navigating a defun. @@ -1953,8 +1950,10 @@ treesit-major-mode-setup (setq-local indent-region-function #'treesit-indent-region)) ;; Navigation. (when treesit-defun-type-regexp - (setq-local beginning-of-defun-function #'treesit-beginning-of-defun) - (setq-local end-of-defun-function #'treesit-end-of-defun))) + (keymap-set (current-local-map) " " + #'treesit-beginning-of-defun) + (keymap-set (current-local-map) " " + #'treesit-end-of-defun))) ;;; Debugging commit 037407ad95a55df900bd508ca3c44499735d7c2a Author: Yuan Fu Date: Thu Dec 15 17:25:06 2022 -0800 Add "function" feature to python-ts-mode (bug#59977) * lisp/progmodes/python.el (python--treesit-settings): Add feature. (python-ts-mode): Add feature. And fix indentation for the python-indent-guess-indent-offset code. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index a10359b384a..bdc9e6fa78c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1095,6 +1095,14 @@ python--treesit-settings (class_definition name: (identifier) @font-lock-type-face)) + :feature 'function + :language 'python + '((function_definition + name: (identifier) @font-lock-function-name-face) + (call function: (identifier) @font-lock-function-name-face) + (call function: (attribute + attribute: (identifier) @font-lock-function-name-face))) + :feature 'keyword :language 'python `([,@python--treesit-keywords] @font-lock-keyword-face @@ -6629,7 +6637,7 @@ python-ts-mode ( keyword string type) ( assignment builtin constant decorator escape-sequence number property string-interpolation ) - ( bracket delimiter operator))) + ( function bracket delimiter operator))) (setq-local treesit-font-lock-settings python--treesit-settings) (setq-local imenu-create-index-function #'python-imenu-treesit-create-index) @@ -6637,8 +6645,8 @@ python-ts-mode "_definition")) (treesit-major-mode-setup) - (when python-indent-guess-indent-offset - (python-indent-guess-indent-offset)))) + (when python-indent-guess-indent-offset + (python-indent-guess-indent-offset)))) ;;; Completion predicates for M-x ;; Commands that only make sense when editing Python code commit fee2efe1b035d601ac53a32801227402e9be8bca Author: Randy Taylor Date: Sun Dec 11 18:41:16 2022 -0500 Add go-ts-mode and go-mod-ts-mode (Bug#60025) * admin/notes/tree-sitter/build-module/batch.sh: * admin/notes/tree-sitter/build-module/build.sh: Add go-mod support. * etc/NEWS: Mention them. * lisp/progmodes/eglot.el (eglot-server-programs): Add them. * lisp/progmodes/go-ts-mode.el: New major modes with tree-sitter support. diff --git a/admin/notes/tree-sitter/build-module/batch.sh b/admin/notes/tree-sitter/build-module/batch.sh index e7ef45cf57d..c50b9df37ed 100755 --- a/admin/notes/tree-sitter/build-module/batch.sh +++ b/admin/notes/tree-sitter/build-module/batch.sh @@ -9,6 +9,7 @@ languages= 'c-sharp' 'dockerfile' 'go' + 'go-mod' 'html' 'javascript' 'json' diff --git a/admin/notes/tree-sitter/build-module/build.sh b/admin/notes/tree-sitter/build-module/build.sh index 4195ea58c3c..b6c83ea9b99 100755 --- a/admin/notes/tree-sitter/build-module/build.sh +++ b/admin/notes/tree-sitter/build-module/build.sh @@ -26,6 +26,11 @@ grammardir= "cmake") org="uyha" ;; + "go-mod") + # The parser is called "gomod". + lang="gomod" + org="camdencheek" + ;; "typescript") sourcedir="tree-sitter-typescript/typescript/src" grammardir="tree-sitter-typescript/typescript" diff --git a/etc/NEWS b/etc/NEWS index 701e414fdbb..dd11b3c2715 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3081,6 +3081,14 @@ A major mode based on the tree-sitter library for editing files written in TOML, a format for writing configuration files. It is auto-enabled for files with the ".toml" extension. +*** New major mode 'go-ts-mode'. +A major mode based on the tree-sitter library for editing programs in +the Go language. It is auto-enabled for files with the ".go" extension. + +*** New major mode 'go-mod-ts-mode'. +A major mode based on the tree-sitter library for editing "go.mod" +files. It is auto-enabled for files which are named "go.mod". + * Incompatible Lisp Changes in Emacs 29.1 diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 9c5a361df7b..02bb6bb665d 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -211,7 +211,8 @@ eglot-server-programs (elm-mode . ("elm-language-server")) (mint-mode . ("mint" "ls")) (kotlin-mode . ("kotlin-language-server")) - ((go-mode go-dot-mod-mode go-dot-work-mode) . ("gopls")) + ((go-mode go-dot-mod-mode go-dot-work-mode go-ts-mode go-mod-ts-mode) + . ("gopls")) ((R-mode ess-r-mode) . ("R" "--slave" "-e" "languageserver::run()")) ((java-mode java-ts-mode) . ("jdtls")) diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el new file mode 100644 index 00000000000..124d9b044a2 --- /dev/null +++ b/lisp/progmodes/go-ts-mode.el @@ -0,0 +1,354 @@ +;;; go-ts-mode.el --- tree-sitter support for Go -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Free Software Foundation, Inc. + +;; Author : Randy Taylor +;; Maintainer : Randy Taylor +;; Created : December 2022 +;; Keywords : go languages tree-sitter + +;; 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 . + +;;; Commentary: +;; + +;;; Code: + +(require 'treesit) +(eval-when-compile (require 'rx)) + +(declare-function treesit-parser-create "treesit.c") +(declare-function treesit-induce-sparse-tree "treesit.c") +(declare-function treesit-node-child "treesit.c") +(declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-node-start "treesit.c") +(declare-function treesit-node-type "treesit.c") + +(defcustom go-ts-mode-indent-offset 4 + "Number of spaces for each indentation step in `go-ts-mode'." + :version "29.1" + :type 'integer + :safe 'integerp + :group 'go) + +(defvar go-ts-mode--syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?^ "." table) + (modify-syntax-entry ?! "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + table) + "Syntax table for `go-ts-mode'.") + +(defvar go-ts-mode--indent-rules + `((go + ((node-is ")") parent-bol 0) + ((node-is "]") parent-bol 0) + ((node-is "}") parent-bol 0) + ((node-is "labeled_statement") no-indent) + ((parent-is "argument_list") parent-bol go-ts-mode-indent-offset) + ((parent-is "block") parent-bol go-ts-mode-indent-offset) + ((parent-is "const_declaration") parent-bol go-ts-mode-indent-offset) + ((parent-is "default_case") parent-bol go-ts-mode-indent-offset) + ((parent-is "expression_case") parent-bol go-ts-mode-indent-offset) + ((parent-is "expression_switch_statement") parent-bol 0) + ((parent-is "field_declaration_list") parent-bol go-ts-mode-indent-offset) + ((parent-is "import_spec_list") parent-bol go-ts-mode-indent-offset) + ((parent-is "labeled_statement") parent-bol go-ts-mode-indent-offset) + ((parent-is "literal_value") parent-bol go-ts-mode-indent-offset) + ((parent-is "type_spec") parent-bol go-ts-mode-indent-offset) + ((parent-is "var_declaration") parent-bol go-ts-mode-indent-offset) + (no-node parent-bol 0))) + "Tree-sitter indent rules for `go-ts-mode'.") + +(defvar go-ts-mode--keywords + '("break" "case" "chan" "const" "continue" "default" "defer" "else" + "fallthrough" "for" "func" "go" "goto" "if" "import" "interface" "map" + "package" "range" "return" "select" "struct" "switch" "type" "var") + "Go keywords for tree-sitter font-locking.") + +(defvar go-ts-mode--operators + '("+" "&" "+=" "&=" "&&" "==" "!=" "-" "|" "-=" "|=" "||" "<" "<=" + "*" "^" "*=" "^=" "<-" ">" ">=" "/" "<<" "/=" "<<=" "++" "=" ":=" "%" + ">>" "%=" ">>=" "--" "!" "..." "&^" "&^=" "~") + "Go operators for tree-sitter font-locking.") + +(defvar go-ts-mode--font-lock-settings + (treesit-font-lock-rules + :language 'go + :feature 'bracket + '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face) + + :language 'go + :feature 'comment + '((comment) @font-lock-comment-face) + + :language 'go + :feature 'constant + '([(false) (iota) (nil) (true)] @font-lock-constant-face + (const_declaration + (const_spec name: (identifier) @font-lock-constant-face))) + + :language 'go + :feature 'delimiter + '((["," "." ";" ":"]) @font-lock-delimiter-face) + + :language 'go + :feature 'function + '((call_expression + function: (identifier) @font-lock-function-name-face) + (call_expression + function: (selector_expression + field: (field_identifier) @font-lock-function-name-face)) + (function_declaration + name: (identifier) @font-lock-function-name-face) + (method_declaration + name: (field_identifier) @font-lock-function-name-face)) + + :language 'go + :feature 'keyword + `([,@go-ts-mode--keywords] @font-lock-keyword-face) + + :language 'go + :feature 'label + '((label_name) @font-lock-constant-face) + + :language 'go + :feature 'number + '([(float_literal) + (imaginary_literal) + (int_literal)] @font-lock-number-face) + + :language 'go + :feature 'string + '([(interpreted_string_literal) + (raw_string_literal) + (rune_literal)] @font-lock-string-face) + + :language 'go + :feature 'type + '([(package_identifier) (type_identifier)] @font-lock-type-face) + + :language 'go + :feature 'variable + '((identifier) @font-lock-variable-name-face) + + :language 'go + :feature 'escape-sequence + :override t + '((escape_sequence) @font-lock-escape-face) + + :language 'go + :feature 'property + :override t + '((field_identifier) @font-lock-property-face + (keyed_element (_ (identifier) @font-lock-property-face))) + + :language 'go + :feature 'error + :override t + '((ERROR) @font-lock-warning-face)) + "Tree-sitter font-lock settings for `go-ts-mode'.") + +(defun go-ts-mode--imenu () + "Return Imenu alist for the current buffer." + (let* ((node (treesit-buffer-root-node)) + (func-tree (treesit-induce-sparse-tree + node "function_declaration" nil 1000)) + (type-tree (treesit-induce-sparse-tree + node "type_spec" nil 1000)) + (func-index (go-ts-mode--imenu-1 func-tree)) + (type-index (go-ts-mode--imenu-1 type-tree))) + (append + (when func-index `(("Function" . ,func-index))) + (when type-index `(("Type" . ,type-index)))))) + +(defun go-ts-mode--imenu-1 (node) + "Helper for `go-ts-mode--imenu'. +Find string representation for NODE and set marker, then recurse +the subtrees." + (let* ((ts-node (car node)) + (children (cdr node)) + (subtrees (mapcan #'go-ts-mode--imenu-1 + children)) + (name (when ts-node + (treesit-node-text + (pcase (treesit-node-type ts-node) + ("function_declaration" + (treesit-node-child-by-field-name ts-node "name")) + ("type_spec" + (treesit-node-child-by-field-name ts-node "name")))))) + (marker (when ts-node + (set-marker (make-marker) + (treesit-node-start ts-node))))) + (cond + ((or (null ts-node) (null name)) subtrees) + (subtrees + `((,name ,(cons name marker) ,@subtrees))) + (t + `((,name . ,marker)))))) + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode)) + +;;;###autoload +(define-derived-mode go-ts-mode prog-mode "Go" + "Major mode for editing Go, powered by tree-sitter." + :group 'go + :syntax-table go-ts-mode--syntax-table + + (when (treesit-ready-p 'go) + (treesit-parser-create 'go) + + ;; Comments. + (setq-local comment-start "// ") + (setq-local comment-end "") + (setq-local comment-start-skip (rx "//" (* (syntax whitespace)))) + + ;; Imenu. + (setq-local imenu-create-index-function #'go-ts-mode--imenu) + (setq-local which-func-functions nil) + + ;; Indent. + (setq-local indent-tabs-mode t + treesit-simple-indent-rules go-ts-mode--indent-rules) + + ;; Font-lock. + (setq-local treesit-font-lock-settings go-ts-mode--font-lock-settings) + (setq-local treesit-font-lock-feature-list + '(( comment) + ( keyword string type) + ( constant escape-sequence function label number + property variable) + ( bracket delimiter error operator))) + + (treesit-major-mode-setup))) + +;; go.mod support. + +(defvar go-mod-ts-mode--syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?\n "> b" table) + table) + "Syntax table for `go-mod-ts-mode'.") + +(defvar go-mod-ts-mode--indent-rules + `((gomod + ((node-is ")") parent-bol 0) + ((parent-is "exclude_directive") parent-bol go-ts-mode-indent-offset) + ((parent-is "module_directive") parent-bol go-ts-mode-indent-offset) + ((parent-is "replace_directive") parent-bol go-ts-mode-indent-offset) + ((parent-is "require_directive") parent-bol go-ts-mode-indent-offset) + ((parent-is "retract_directive") parent-bol go-ts-mode-indent-offset) + ((go-mod-ts-mode--in-directive-p) no-indent go-ts-mode-indent-offset) + (no-node no-indent 0))) + "Tree-sitter indent rules for `go-mod-ts-mode'.") + +(defun go-mod-ts-mode--in-directive-p () + "Return non-nil if inside a directive. +When entering an empty directive or adding a new entry to one, no node +will be present meaning none of the indentation rules will match, +because there is no parent to match against. This function determines +what the parent of the node would be if it were a node." + (lambda (node _ _ &rest _) + (unless (treesit-node-type node) + (save-excursion + (backward-up-list) + (back-to-indentation) + (pcase (treesit-node-type (treesit-node-at (point))) + ("exclude" t) + ("module" t) + ("replace" t) + ("require" t) + ("retract" t)))))) + +(defvar go-mod-ts-mode--keywords + '("exclude" "go" "module" "replace" "require" "retract") + "go.mod keywords for tree-sitter font-locking.") + +(defvar go-mod-ts-mode--font-lock-settings + (treesit-font-lock-rules + :language 'gomod + :feature 'bracket + '((["(" ")"]) @font-lock-bracket-face) + + :language 'gomod + :feature 'comment + '((comment) @font-lock-comment-face) + + :language 'gomod + :feature 'keyword + `([,@go-mod-ts-mode--keywords] @font-lock-keyword-face) + + :language 'gomod + :feature 'number + '([(go_version) (version)] @font-lock-number-face) + + :language 'gomod + :feature 'operator + '((["=>"]) @font-lock-operator-face) + + :language 'gomod + :feature 'error + :override t + '((ERROR) @font-lock-warning-face)) + "Tree-sitter font-lock settings for `go-mod-ts-mode'.") + +;;;###autoload +(add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode)) + +;;;###autoload +(define-derived-mode go-mod-ts-mode prog-mode "Go Mod" + "Major mode for editing go.mod files, powered by tree-sitter." + :group 'go + :syntax-table go-mod-ts-mode--syntax-table + + (when (treesit-ready-p 'gomod) + (treesit-parser-create 'gomod) + + ;; Comments. + (setq-local comment-start "// ") + (setq-local comment-end "") + (setq-local comment-start-skip (rx "//" (* (syntax whitespace)))) + + ;; Indent. + (setq-local indent-tabs-mode t + treesit-simple-indent-rules go-mod-ts-mode--indent-rules) + + ;; Font-lock. + (setq-local treesit-font-lock-settings go-mod-ts-mode--font-lock-settings) + (setq-local treesit-font-lock-feature-list + '((comment) + (keyword) + (number) + (bracket error operator))) + + (treesit-major-mode-setup))) + +(provide 'go-ts-mode) + +;;; go-ts-mode.el ends here commit e8f7ab67ad18063155f6a7ba14a29e3679dc1e76 Author: Yuan Fu Date: Thu Dec 15 17:16:28 2022 -0800 Add basic support for hideshow in python-ts-mode (bug#60044) * lisp/progmodes/python.el (python-base-mode): Add setup for python-ts-mode. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index ee05862550d..a10359b384a 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -6564,19 +6564,21 @@ python-base-mode (add-function :before-until (local 'eldoc-documentation-function) #'python-eldoc-function)))) - (add-to-list - 'hs-special-modes-alist - `(python-mode - ,python-nav-beginning-of-block-regexp - ;; Use the empty string as end regexp so it doesn't default to - ;; "\\s)". This way parens at end of defun are properly hidden. - "" - "#" - python-hideshow-forward-sexp-function - nil - python-nav-beginning-of-block - python-hideshow-find-next-block - python-info-looking-at-beginning-of-block)) + ;; TODO: Use tree-sitter to figure out the block in `python-ts-mode'. + (dolist (mode '(python-mode python-ts-mode)) + (add-to-list + 'hs-special-modes-alist + `(,mode + ,python-nav-beginning-of-block-regexp + ;; Use the empty string as end regexp so it doesn't default to + ;; "\\s)". This way parens at end of defun are properly hidden. + "" + "#" + python-hideshow-forward-sexp-function + nil + python-nav-beginning-of-block + python-hideshow-find-next-block + python-info-looking-at-beginning-of-block))) (setq-local outline-regexp (python-rx (* space) block-start)) (setq-local outline-level commit cac070b23e4d555a194d67c3a842fad81285df72 Author: Theodor Thornhill Date: Thu Dec 15 11:48:32 2022 +0100 Add "this" keyword to java-ts-mode (bug#60086) * lisp/progmodes/java-ts-mode.el (java-ts-mode--font-lock-settings): Add the node to the keyword feature. diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index ac591a08599..559a4efef25 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -144,9 +144,10 @@ java-ts-mode--font-lock-settings :language 'java :override t :feature 'keyword - `([,@java-ts-mode--keywords] @font-lock-keyword-face - (labeled_statement - (identifier) @font-lock-keyword-face)) + `([,@java-ts-mode--keywords + (this)] @font-lock-keyword-face + (labeled_statement + (identifier) @font-lock-keyword-face)) :language 'java :override t :feature 'operator commit c585ca89a64ab613e08576b5603949767ad8d079 Author: Juanma Barranquero Date: Fri Dec 16 00:21:16 2022 +0100 * lisp/bs.el: Use modern height preserving method instead of hooks * lisp/bs.el (bs--track-window-changes, bs--remove-hooks): Remove. (bs-mode): Do not set window-change tracking hooks. (bs--set-window-height): Pass PRESERVE-SIZE to `fit-window-to-buffer'. diff --git a/lisp/bs.el b/lisp/bs.el index 59672c4fd4b..d5e6030fac0 100644 --- a/lisp/bs.el +++ b/lisp/bs.el @@ -602,21 +602,6 @@ bs--current-config-message (format "Show buffer by configuration %S" bs-current-configuration))) -(defun bs--track-window-changes (frame) - "Track window changes to refresh the buffer list. -Used from `window-size-change-functions'." - (let ((win (get-buffer-window "*buffer-selection*" frame))) - (when win - (with-selected-window win - (bs--set-window-height))))) - -(defun bs--remove-hooks () - "Remove `bs--track-window-changes' and auxiliary hooks." - (remove-hook 'window-size-change-functions 'bs--track-window-changes) - ;; Remove itself - (remove-hook 'kill-buffer-hook 'bs--remove-hooks t) - (remove-hook 'change-major-mode-hook 'bs--remove-hooks t)) - (put 'bs-mode 'mode-class 'special) (define-derived-mode bs-mode nil "Buffer-Selection-Menu" @@ -675,10 +660,7 @@ bs-mode (setq-local font-lock-defaults '(bs-mode-font-lock-keywords t)) (setq-local font-lock-verbose nil) (setq-local font-lock-global-modes '(not bs-mode)) - (setq-local revert-buffer-function 'bs-refresh) - (add-hook 'window-size-change-functions 'bs--track-window-changes) - (add-hook 'kill-buffer-hook 'bs--remove-hooks nil t) - (add-hook 'change-major-mode-hook 'bs--remove-hooks nil t)) + (setq-local revert-buffer-function 'bs-refresh)) (defun bs-kill () "Let buffer disappear and reset window configuration." @@ -708,7 +690,9 @@ bs-refresh (defun bs--set-window-height () "Change the height of the selected window to suit the current buffer list." (unless (one-window-p t) - (fit-window-to-buffer (selected-window) bs-max-window-height))) + (fit-window-to-buffer (selected-window) bs-max-window-height nil nil nil + ;; preserve-size + t))) (defun bs--current-buffer () "Return buffer on current line. commit c8d75046a2f1b5d29e073ac2e4a987145343b0b7 Author: Dmitry Gutov Date: Fri Dec 16 00:45:55 2022 +0200 When completing relative project file names, use relative history * lisp/progmodes/project.el: Require 'cl-lib'. * lisp/progmodes/project.el (project--read-file-cpd-relative): Pre-process history entries around completing-read (bug#58447). This includes both filtering by common-parent-directory prefix and mapping into relative names. diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 4fd855255b0..559da6dd649 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -174,6 +174,7 @@ ;;; Code: (require 'cl-generic) +(require 'cl-lib) (require 'seq) (eval-when-compile (require 'subr-x)) @@ -1038,7 +1039,14 @@ project--read-file-cpd-relative (_ (when included-cpd (setq substrings (cons "./" substrings)))) (new-collection (project--file-completion-table substrings)) - (relname (let ((history-add-new-input nil)) + (abbr-cpd (abbreviate-file-name common-parent-directory)) + (relname (cl-letf ((history-add-new-input nil) + ((symbol-value hist) + (mapcan + (lambda (s) + (and (string-prefix-p abbr-cpd s) + (list (substring s (length abbr-cpd))))) + (symbol-value hist)))) (project--completing-read-strict prompt new-collection predicate commit 3b618d0e3ed91c5b954b47f9044f7f3f3aa67c66 Author: Eli Zaretskii Date: Thu Dec 15 23:39:58 2022 +0200 Avoid segfaults due to invalid selected-window's buffer * lisp/startup.el (initial-scratch-message): Don't use \\[...] commands for substitute-command-keys. * lisp/simple.el (get-scratch-buffer-create): Don't call substitute-command-keys on initial-scratch-message, to avoid signaling an error in rare cases. (Bug#60096) diff --git a/lisp/simple.el b/lisp/simple.el index 654b56a0886..dcc2242e49f 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10683,7 +10683,12 @@ get-scratch-buffer-create ;; we just created it. (with-current-buffer scratch (when initial-scratch-message - (insert (substitute-command-keys initial-scratch-message)) + ;; We used to run this through substitute-command-keys, + ;; but that might be unsafe in some rare cases, and this + ;; function must never fail and signal an error, because + ;; it is called from other_buffer_safely, which must + ;; always produce a valid buffer. + (insert initial-scratch-message) (set-buffer-modified-p nil)) (funcall initial-major-mode)) scratch))) diff --git a/lisp/startup.el b/lisp/startup.el index 6270de2ace6..7f8e8d55db8 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1669,7 +1669,7 @@ x-apply-session-resources (defcustom initial-scratch-message (purecopy "\ ;; This buffer is for text that is not saved, and for Lisp evaluation. -;; To create a file, visit it with \\[find-file] and enter text in its buffer. +;; To create a file, visit it with \"C-x C-f\" and enter text in its buffer. ") "Initial documentation displayed in *scratch* buffer at startup. commit 0d60579b6b6f2648a881572783322b1bcf931a73 Merge: e17c1b01d8c 99aa00e6e34 Author: Stefan Kangas Date: Thu Dec 15 21:13:16 2022 +0100 Merge from origin/emacs-29 99aa00e6e34 Revert 21b387c39bd with last-minute hasty changes (bug#60... 386d6e74d83 Replace an erroneous eq with an equal in cc-defs.el eb069470631 * lisp/tab-bar.el ([tab-bar]): Use 'make-sparse-keymap' i... 26243f7b65e compile.el: Fix regression with nb of errors in modeline 6e2923d80f8 Make tab-bar-tab-group-format-function backwards-compatib... b211a63455c Make tab-bar-tab-group-format-function also handle curren... 367022f316e Ensure package directories for source packages from check... 3a633bdd6df ; * etc/NEWS: Fix recent changes. 6aa5d16c643 * test/README (SELECTOR): Add eglot-tests.el to remote fi... bb27be36ddf Fix bug#60060 in Tramp d4c2aa4f913 ; * lisp/net/tramp-crypt.el: Fix comment. 8404253d17a * .gitignore: Ignore GDB history files. 12684c3a199 Mention 'tree-sitter' in user manual and NEWS 49d7e0cec6a ; * etc/NEWS: Rearrange entries for tree-sitter supported... 0ad2112a2f0 ; Announce 'toml-ts-mode' in NEWS. # Conflicts: # etc/NEWS commit e17c1b01d8c096493f00f5b65ac2562cc348feb1 Merge: eacdac3c6e4 98ea7054a71 Author: Stefan Kangas Date: Thu Dec 15 21:13:15 2022 +0100 ; Merge from origin/emacs-29 The following commit was skipped: 98ea7054a71 ; Auto-commit of loaddefs files. commit eacdac3c6e43459104d25594cebc930b2a081f17 Merge: 037889c4a9a a15cd55044c Author: Stefan Kangas Date: Thu Dec 15 21:13:14 2022 +0100 Merge from origin/emacs-29 a15cd55044c ; Don't quote nil in comments da39200c4be ; Checkdoc fixes in dired-aux.el fd403a5c5a8 Fix ruby-add-log-current-method after nested class defini... 2ca06aed7b3 Add indent rules to js/typescript/tsx-ts-mode (bug#60074) a54d5f500c1 Improve fontification in csharp-ts-mode (bug#59897) 3db2f560bb7 Revert "Add expression for generic_name in csharp-ts-mode" 1985762fbd7 Introduce support for TOML config-format 622838b957e Fix handling of % when searching in .tex or .dtx files 3b226b60248 Treat C++ classes as defuns in C Tree-sitter mode (bug#60... 480f41c7deb Add < and > to the syntax table in c++-ts-mode (bug#60049) fbf0d3b796a Improve fontifications in Typescript mode f93a5180a61 Update the documentation of overlays (bug#59996) d51b66ed540 ; Improve description of scoping and let-bindings 752f9dde631 ; Fix a typo in window.el 102a3e3b445 Don't send erc-sasl-user as USER command argument f0c90888781 Set erc-network to a "given" ID instead of failing 09c0c6b2ba3 Limit casemapping to appropriate ranges in ERC 44b04c0ac1c Actually accept non-symbols as IDs in erc-open 75f26646d4a ; Be nicer when updating browse-url var in erc-compat 0155fc67be3 Respect a nil erc-session-password when reconnecting 9ac80e8a6e4 Add dedicated auth-source section in ERC manual 2d96a18cd09 ; * lisp/emacs-lisp/shortdoc.el: fix mistakes in previous... 1d3cbba7dfa ; * lisp/progmodes/cmake-ts-mode.el (auto-mode-alist): $ ... 0cc199f1a61 Better shortdoc examples 931d97bf563 Shortdoc: read and evaluate strings after :eval be165f75332 Fix Tramp tests in eglot-tests, prefix tests uniquely 8c30cb90ba9 * lisp/vc/vc-git.el (vc-git-checkin): Use make-nearby-tem... 3efe4df1d20 Delete temp files after icalendar tests # Conflicts: # etc/NEWS commit 037889c4a9aca524d31c75614f5df06088ed9264 Merge: fa70076974b 33e0a104649 Author: Stefan Kangas Date: Thu Dec 15 21:13:14 2022 +0100 ; Merge from origin/emacs-29 The following commit was skipped: 33e0a104649 ; * lisp/keymap.el (keymap-substitute): Doc fix. (Bug#60... commit fa70076974b5f9ed21438946fb6a1a8bf76b7c5a Merge: db69249b761 fafcf02c856 Author: Stefan Kangas Date: Thu Dec 15 21:13:13 2022 +0100 Merge from origin/emacs-29 fafcf02c856 Fix syntax tables of tree-sitter modes (bug#59807) 91b8d9b7db4 ; * admin/notes/tree-sitter/build-module/build.sh: Minor ... 1b0e282a7f8 ; Comment and stylistic change in treesit.el 489b02d03cf * doc/misc/Makefile.in (need_emacsver): Add use-package. commit 99aa00e6e34b65169dd8328cb76cce648ba97e9d Author: Juri Linkov Date: Thu Dec 15 21:24:48 2022 +0200 Revert 21b387c39bd with last-minute hasty changes (bug#60048). * lisp/simple.el (completion-list-mode-map): Unbind [up] and [down]. (previous-line-completion, next-line-completion): Remove. diff --git a/etc/NEWS b/etc/NEWS index 02922e1fb7b..701e414fdbb 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1752,10 +1752,9 @@ the second one will switch to the "*Completions*" buffer. --- *** New user option 'completion-auto-wrap'. -When non-nil, the commands 'next-completion', 'previous-completion', -'next-line-completion' and 'previous-line-completion' automatically -wrap around on reaching the beginning or the end of the "*Completions*" -buffer. +When non-nil, the commands 'next-completion' and 'previous-completion' +automatically wrap around on reaching the beginning or the end of +the "*Completions*" buffer. +++ *** New values for the 'completion-auto-help' user option. diff --git a/lisp/simple.el b/lisp/simple.el index 893a43b03fc..654b56a0886 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -9578,8 +9578,6 @@ completion-list-mode-map (define-key map "\C-m" 'choose-completion) (define-key map "\e\e\e" 'delete-completion-window) (define-key map [remap keyboard-quit] #'delete-completion-window) - (define-key map [up] 'previous-line-completion) - (define-key map [down] 'next-line-completion) (define-key map [left] 'previous-completion) (define-key map [right] 'next-completion) (define-key map [?\t] 'next-completion) @@ -9639,8 +9637,7 @@ delete-completion-window (defcustom completion-auto-wrap t "Non-nil means to wrap around when selecting completion options. -This affects the commands `next-completion', `previous-completion', -`next-line-completion' and `previous-line-completion'. +This affects the commands `next-completion' and `previous-completion'. When `completion-auto-select' is t, it wraps through the minibuffer for the commands bound to the TAB key." :type 'boolean @@ -9746,73 +9743,6 @@ next-completion (when (/= 0 n) (switch-to-minibuffer)))) -(defun previous-line-completion (&optional n) - "Move to the item on the previous line in the completion list. -With prefix argument N, move back N items line-wise (negative N -means move forward). - -Also see the `completion-auto-wrap' variable." - (interactive "p") - (next-line-completion (- n))) - -(defun next-line-completion (&optional n) - "Move to the item on the next line in the completion list. -With prefix argument N, move N items line-wise (negative N -means move backward). - -Also see the `completion-auto-wrap' variable." - (interactive "p") - (let ((column (current-column)) - pos) - (catch 'bound - (while (> n 0) - (setq pos nil) - (save-excursion - (while (and (not pos) (not (eobp))) - (forward-line 1) - (when (and (not (eobp)) - (eq (move-to-column column) column) - (get-text-property (point) 'mouse-face)) - (setq pos (point))))) - (if pos (goto-char pos) - (when completion-auto-wrap - (save-excursion - (goto-char (point-min)) - (when (and (eq (move-to-column column) column) - (get-text-property (point) 'mouse-face)) - (setq pos (point))) - (while (and (not pos) (not (eobp))) - (forward-line 1) - (when (and (eq (move-to-column column) column) - (get-text-property (point) 'mouse-face)) - (setq pos (point))))) - (if pos (goto-char pos)))) - (setq n (1- n))) - - (while (< n 0) - (setq pos nil) - (save-excursion - (while (and (not pos) (not (bobp))) - (forward-line -1) - (when (and (not (bobp)) - (eq (move-to-column column) column) - (get-text-property (point) 'mouse-face)) - (setq pos (point))))) - (if pos (goto-char pos) - (when completion-auto-wrap - (save-excursion - (goto-char (point-max)) - (when (and (eq (move-to-column column) column) - (get-text-property (point) 'mouse-face)) - (setq pos (point))) - (while (and (not pos) (not (bobp))) - (forward-line -1) - (when (and (eq (move-to-column column) column) - (get-text-property (point) 'mouse-face)) - (setq pos (point))))) - (if pos (goto-char pos)))) - (setq n (1+ n)))))) - (defun choose-completion (&optional event no-exit no-quit) "Choose the completion at point. If EVENT, use EVENT's position to determine the starting position. commit 386d6e74d83a2b7cff68bd3e072e640784bb3446 Author: Alan Mackenzie Date: Thu Dec 15 19:23:19 2022 +0000 Replace an erroneous eq with an equal in cc-defs.el * lisp/progmodes/cc-defs.el (c-looking-at-non-alphnumspace): Replace eq with equal in the XEmacs branch. diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el index b13f6a5914e..dd6d33009db 100644 --- a/lisp/progmodes/cc-defs.el +++ b/lisp/progmodes/cc-defs.el @@ -1826,7 +1826,7 @@ c-looking-at-non-alphnumspace '(or (looking-at "\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\)" (let ((prop (c-get-char-property (point) 'syntax-table))) - (eq prop '(14))))))) ; '(14) is generic comment delimiter. + (equal prop '(14))))))) ; '(14) is generic comment delimiter. (defsubst c-intersect-lists (list alist) commit eb069470631d63d8a4ed2b74ce5f9b9ee10cde13 Author: Juri Linkov Date: Thu Dec 15 21:10:28 2022 +0200 * lisp/tab-bar.el ([tab-bar]): Use 'make-sparse-keymap' instead of 'ignore'. This helps to avoid the error in 'where-is-internal' that should not call :filter unnecessarily (bug#9923). diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 1baa857e9e9..f040bc9786d 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -416,7 +416,7 @@ tab-bar-map "S-" #'tab-bar-move-tab) (global-set-key [tab-bar] - `(menu-item ,(purecopy "tab bar") ignore + `(menu-item ,(purecopy "tab bar") ,(make-sparse-keymap) :filter tab-bar-make-keymap)) (defun tab-bar-make-keymap (&optional _ignore) commit 26243f7b65e015a1676ed7f4a8a8e712ed7d6193 Author: Stefan Monnier Date: Thu Dec 15 13:36:14 2022 -0500 compile.el: Fix regression with nb of errors in modeline * lisp/progmodes/compile.el (compilation-mode-line-errors): Mark it as risky-local, like `defconst` used to do for us. diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index e8ada9388e1..319dc97e699 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -186,6 +186,7 @@ compilation-mode-line-errors face compilation-info help-echo "Number of informational messages so far") "]")) +(put 'compilation-mode-line-errors 'risky-local-variable t) ;; If you make any changes to `compilation-error-regexp-alist-alist', ;; be sure to run the ERT test in test/lisp/progmodes/compile-tests.el. commit 6e2923d80f822e6da470860f51ba13bcad10d0a3 Author: Juri Linkov Date: Thu Dec 15 20:03:24 2022 +0200 Make tab-bar-tab-group-format-function backwards-compatible (bug#60073) * lisp/tab-bar.el (tab-bar--format-tab-group): Add condition-case with wrong-number-of-arguments for backwards-compatibility. (tab-bar-tab-group-format-default): Simplify. diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 1f25ee6d7e4..1baa857e9e9 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -844,9 +844,9 @@ tab-bar-tab-group-default (defcustom tab-bar-tab-group-format-function #'tab-bar-tab-group-format-default "Function to format a tab group name. -Function gets three arguments, a tab with a group name, its -number and an optional t when the tab is current, and should -return the formatted tab group name to display in the tab bar." +Function gets three arguments, a tab with a group name, its number, and +an optional value that is non-nil when the tab is from the current group. +It should return the formatted tab group name to display in the tab bar." :type 'function :initialize 'custom-initialize-default :set (lambda (sym val) @@ -856,12 +856,10 @@ tab-bar-tab-group-format-function :version "28.1") (defun tab-bar-tab-group-format-default (tab i &optional current-p) - (let ((name (concat (if tab-bar-tab-hints (format "%d " i) "") - (funcall tab-bar-tab-group-function tab))) - (face (if current-p - 'tab-bar-tab-group-current - 'tab-bar-tab-group-inactive))) - (propertize name 'face face))) + (propertize + (concat (if (and tab-bar-tab-hints (not current-p)) (format "%d " i) "") + (funcall tab-bar-tab-group-function tab)) + 'face (if current-p 'tab-bar-tab-group-current 'tab-bar-tab-group-inactive))) (defcustom tab-bar-tab-group-face-function #'tab-bar-tab-group-face-default "Function to define a tab group face. @@ -884,7 +882,16 @@ tab-bar--format-tab-group `((,(intern (format "sep-%i" i)) menu-item ,(tab-bar-separator) ignore)) `((,(intern (format "group-%i" i)) menu-item - ,(funcall tab-bar-tab-group-format-function tab i current-p) + ,(if current-p + (condition-case nil + (funcall tab-bar-tab-group-format-function tab i current-p) + ;; We used to define tab-bar-tab-group-format-function as + ;; taking two arguments but after adding the third argument + ;; we need to provide backwards-compatibility. + (wrong-number-of-arguments + (propertize (funcall tab-bar-tab-group-function tab) + 'face 'tab-bar-tab-group-current))) + (funcall tab-bar-tab-group-format-function tab i)) ,(if current-p 'ignore (or (alist-get 'binding tab) commit b211a63455cad72f4883ef1494502633f8ac19be Author: Gabriel do Nascimento Ribeiro Date: Thu Dec 15 11:58:30 2022 -0300 Make tab-bar-tab-group-format-function also handle current group * lisp/tab-bar.el (tab-bar--format-tab-group): Call 'tab-bar-tab-group-format-default' to format current group tab. (tab-bar-tab-group-format-default): Update function to also handle current group tab (bug#60073). diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 162e63fe230..1f25ee6d7e4 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -844,8 +844,9 @@ tab-bar-tab-group-default (defcustom tab-bar-tab-group-format-function #'tab-bar-tab-group-format-default "Function to format a tab group name. -Function gets two arguments, a tab with a group name and its number, -and should return the formatted tab group name to display in the tab bar." +Function gets three arguments, a tab with a group name, its +number and an optional t when the tab is current, and should +return the formatted tab group name to display in the tab bar." :type 'function :initialize 'custom-initialize-default :set (lambda (sym val) @@ -854,11 +855,13 @@ tab-bar-tab-group-format-function :group 'tab-bar :version "28.1") -(defun tab-bar-tab-group-format-default (tab i) - (propertize - (concat (if tab-bar-tab-hints (format "%d " i) "") - (funcall tab-bar-tab-group-function tab)) - 'face 'tab-bar-tab-group-inactive)) +(defun tab-bar-tab-group-format-default (tab i &optional current-p) + (let ((name (concat (if tab-bar-tab-hints (format "%d " i) "") + (funcall tab-bar-tab-group-function tab))) + (face (if current-p + 'tab-bar-tab-group-current + 'tab-bar-tab-group-inactive))) + (propertize name 'face face))) (defcustom tab-bar-tab-group-face-function #'tab-bar-tab-group-face-default "Function to define a tab group face. @@ -881,10 +884,7 @@ tab-bar--format-tab-group `((,(intern (format "sep-%i" i)) menu-item ,(tab-bar-separator) ignore)) `((,(intern (format "group-%i" i)) menu-item - ,(if current-p - (propertize (funcall tab-bar-tab-group-function tab) - 'face 'tab-bar-tab-group-current) - (funcall tab-bar-tab-group-format-function tab i)) + ,(funcall tab-bar-tab-group-format-function tab i current-p) ,(if current-p 'ignore (or (alist-get 'binding tab) commit 367022f316e22619dd223a4a0fcd523397ffc84e Author: Philip Kaludercic Date: Thu Dec 15 18:21:24 2022 +0100 Ensure package directories for source packages from checkouts * lisp/emacs-lisp/package-vc.el (package-vc-install-from-checkout): Set the :dir entry, since `package-vc--unpack-1' assumes the field is set, as is the case when invoking `package-vc--unpack'. diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el index db54e0e130e..8f0eedd2f88 100644 --- a/lisp/emacs-lisp/package-vc.el +++ b/lisp/emacs-lisp/package-vc.el @@ -783,6 +783,7 @@ package-vc-install-from-checkout (package-vc--unpack-1 (package-desc-create :name (intern name) + :dir pkg-dir :kind 'vc) (file-name-as-directory pkg-dir)))) commit 3a633bdd6dfd5e65cfb95c9fe8d6dbc78abb26dd Author: Randy Taylor Date: Thu Dec 15 11:44:10 2022 -0500 ; * etc/NEWS: Fix recent changes. diff --git a/etc/NEWS b/etc/NEWS index 6f0d1f65bf2..02922e1fb7b 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3069,14 +3069,15 @@ Bash shell scripts. *** New major mode 'dockerfile-ts-mode'. A major mode based on the tree-sitter library for editing Dockerfiles. This mode is auto-enabled for files which are named -"Dockerfile" or have the ".dockerfile" extension. +"Dockerfile", have the "Dockerfile." prefix, or have the ".dockerfile" +extension. *** New major mode 'cmake-ts-mode'. A major mode based on the tree-sitter library for editing CMake files. -It is auto-enabled for files whose name is "Cmakefile.txt" or whose +It is auto-enabled for files whose name is "CMakeLists.txt" or whose extension is ".cmake". -*** New major mode toml-ts-mode'. +*** New major mode 'toml-ts-mode'. A major mode based on the tree-sitter library for editing files written in TOML, a format for writing configuration files. It is auto-enabled for files with the ".toml" extension. commit 6aa5d16c6431f85952cf69d1c2ffc9fca9402491 Author: Michael Albinus Date: Thu Dec 15 16:37:36 2022 +0100 * test/README (SELECTOR): Add eglot-tests.el to remote file using libraries. diff --git a/test/README b/test/README index 17783a4bacf..eb6314c74d6 100644 --- a/test/README +++ b/test/README @@ -118,7 +118,7 @@ If the $EMACS_TEST_JUNIT_REPORT environment variable is set to a file name, a JUnit test report is generated under this name. Some of the tests require a remote temporary directory -(autorevert-tests.el, dnd-tests.el, filenotify-tests.el, +(autorevert-tests.el, dnd-tests.el, eglot-tests.el, filenotify-tests.el, shadowfile-tests.el and tramp-tests.el). Per default, a mock-up connection method is used (this might not be possible when running on MS Windows). If you want to test a real remote connection, set commit bb27be36ddfd753a8f78e638f23cc782c7b2c3de Author: Michael Albinus Date: Thu Dec 15 16:37:16 2022 +0100 Fix bug#60060 in Tramp * lisp/net/tramp-sh.el (tramp-sh-handle-file-local-copy): Delete `tmpfile' in case of error. (Bug#60060) diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index df5800f4e9d..6087f16431e 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -3431,6 +3431,7 @@ tramp-sh-handle-file-local-copy (signal (car err) (cdr err))))) ;; Impossible to copy. Trigger `file-missing' error. + (delete-file tmpfile) (setq tmpfile nil)))) (defun tramp-sh-handle-write-region commit d4c2aa4f913d07d627296c3e96125c4a8c143bd7 Author: Michael Albinus Date: Thu Dec 15 16:36:38 2022 +0100 ; * lisp/net/tramp-crypt.el: Fix comment. diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el index fa40f968180..249b3fcd4d7 100644 --- a/lisp/net/tramp-crypt.el +++ b/lisp/net/tramp-crypt.el @@ -318,7 +318,7 @@ tramp-crypt-maybe-open-connection (process-put p 'vector vec) (set-process-query-on-exit-flag p nil))) - ;; The following operations must be performed w/o + ;; The following operations must be performed without ;; `tramp-crypt-file-name-handler'. (let* (tramp-crypt-enabled ;; Don't check for a proper method. commit db69249b761a80158c1469b2a169d6f5c8509ae1 Author: Po Lu Date: Thu Dec 15 20:06:37 2022 +0800 Handle selection transfer errors earlier * src/xselect.c (x_decline_selection_request, struct transfer) (struct x_selection_request, x_cancel_selection_transfer) (x_start_selection_transfer, x_continue_selection_transfer): Give the right serial to x_ignore_errors_for_next_request. (x_handle_selection_error): New function. (x_reply_selection_request): Give the right serial to x_ignore_errors_for_next_request. * src/xterm.c (x_ignore_errors_for_next_request): New arg `selection_serial'. All callers changed. (x_error_handler): Call selection error handler. * src/xterm.h (struct x_failable_request): New field `selection_serial'. diff --git a/src/xfns.c b/src/xfns.c index 2bf282fd243..668f711bdb5 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1367,7 +1367,7 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval) XCreateFontCursor is not a request that waits for a reply, and as such can return IDs that will not actually be used by the server. */ - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); /* Free any successfully created cursors. */ for (i = 0; i < mouse_cursor_max; i++) diff --git a/src/xselect.c b/src/xselect.c index 191f0770337..05548be311f 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -460,7 +460,7 @@ x_decline_selection_request (struct selection_input_event *event) /* The reason for the error may be that the receiver has died in the meantime. Handle that case. */ block_input (); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, reply->requestor, False, 0, &reply_base); x_stop_ignoring_errors (dpyinfo); @@ -523,6 +523,9 @@ x_decline_selection_request (struct selection_input_event *event) /* The atimer for the timeout. */ struct atimer *timeout; + /* The selection serial. */ + unsigned int serial; + /* Flags. */ int flags; }; @@ -543,6 +546,9 @@ #define SELECTED_EVENTS 1 /* Linked list of the above (in support of MULTIPLE targets). */ struct selection_data *converted_selections; + /* The serial used to handle X errors. */ + unsigned int serial; + /* Whether or not conversion was successful. */ bool converted; }; @@ -557,6 +563,10 @@ #define SELECTED_EVENTS 1 struct transfer outstanding_transfers; +/* A counter for selection serials. */ + +static unsigned int selection_serial; + struct prop_location @@ -793,7 +803,7 @@ x_cancel_selection_transfer (struct transfer *transfer) /* Ignore errors generated by the change window request in case the window has gone away. */ block_input (); - x_ignore_errors_for_next_request (transfer->dpyinfo); + x_ignore_errors_for_next_request (transfer->dpyinfo, 0); XSelectInput (transfer->dpyinfo->display, transfer->requestor, NoEventMask); x_stop_ignoring_errors (transfer->dpyinfo); @@ -885,12 +895,23 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, transfer->next->last = transfer; transfer->last->next = transfer; + /* Find a valid (non-zero) serial for the selection transfer. + Any asynchronously trapped errors will then cause the + selection transfer to be cancelled. */ + transfer->serial = (++selection_serial + ? selection_serial + : ++selection_serial); + /* Now, write the INCR property to begin incremental selection transfer. offset is currently 0. */ data_size = selection_data_size (&transfer->data); - x_ignore_errors_for_next_request (dpyinfo); + /* Set SELECTED_EVENTS before the actual XSelectInput + request. */ + transfer->flags |= SELECTED_EVENTS; + + x_ignore_errors_for_next_request (dpyinfo, transfer->serial); XChangeProperty (dpyinfo->display, requestor, transfer->data.property, dpyinfo->Xatom_INCR, 32, PropModeReplace, @@ -903,7 +924,6 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, manager) asks Emacs for selection data, things will subtly go wrong. */ XSelectInput (dpyinfo->display, requestor, PropertyChangeMask); - transfer->flags |= SELECTED_EVENTS; x_stop_ignoring_errors (dpyinfo); } else @@ -917,7 +937,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, Window requestor, " %zu elements directly to requestor window", remaining); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XChangeProperty (dpyinfo->display, requestor, transfer->data.property, transfer->data.type, @@ -951,7 +971,7 @@ x_continue_selection_transfer (struct transfer *transfer) signal EOF and remove the transfer. */ TRACE0 (" x_continue_selection_transfer: writing 0 items to" " indicate EOF"); - x_ignore_errors_for_next_request (transfer->dpyinfo); + x_ignore_errors_for_next_request (transfer->dpyinfo, 0); XChangeProperty (transfer->dpyinfo->display, transfer->requestor, transfer->data.property, @@ -970,7 +990,10 @@ x_continue_selection_transfer (struct transfer *transfer) "; current offset is %zu", remaining, transfer->offset); eassert (remaining <= INT_MAX); - x_ignore_errors_for_next_request (transfer->dpyinfo); + transfer->offset += remaining; + + x_ignore_errors_for_next_request (transfer->dpyinfo, + transfer->serial); XChangeProperty (transfer->dpyinfo->display, transfer->requestor, transfer->data.property, @@ -979,7 +1002,6 @@ x_continue_selection_transfer (struct transfer *transfer) PropModeReplace, xdata, remaining); x_stop_ignoring_errors (transfer->dpyinfo); - transfer->offset += remaining; } } @@ -999,6 +1021,40 @@ x_remove_selection_transfers (struct x_display_info *dpyinfo) } } +/* Handle an X error generated trying to write to a window. SERIAL + identifies the outstanding incremental selection transfer, which is + immediately removed. */ + +void +x_handle_selection_error (unsigned int serial, XErrorEvent *error) +{ + struct transfer *next, *last; + + if (error->error_code != BadWindow) + /* The error was not caused by the window going away. As such, + Emacs must deselect for PropertyChangeMask from the requestor + window, which isn't safe here. Return and wait for the timeout + to run. */ + return; + + next = outstanding_transfers.next; + while (next != &outstanding_transfers) + { + last = next; + next = next->next; + + if (last->serial == serial) + { + /* Clear SELECTED_EVENTS, so x_cancel_selection_transfer + will not make X requests. That is unsafe inside an error + handler, and unnecessary because the window has already + gone. */ + last->flags &= ~SELECTED_EVENTS; + x_cancel_selection_transfer (last); + } + } +} + /* Send the reply to a selection request event EVENT. */ static void @@ -1033,7 +1089,7 @@ x_reply_selection_request (struct selection_input_event *event, /* Send the SelectionNotify event to the requestor, telling it that the property data has arrived. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, SELECTION_EVENT_REQUESTOR (event), False, NoEventMask, &message); x_stop_ignoring_errors (dpyinfo); diff --git a/src/xterm.c b/src/xterm.c index 968dec6fbdd..278a8dda10b 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2587,7 +2587,7 @@ xm_send_drop_message (struct x_display_info *dpyinfo, Window source, *((uint32_t *) &msg.xclient.data.b[12]) = dmsg->index_atom; *((uint32_t *) &msg.xclient.data.b[16]) = dmsg->source_window; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2614,7 +2614,7 @@ xm_send_top_level_enter_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2645,7 +2645,7 @@ xm_send_drag_motion_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2704,7 +2704,7 @@ xm_send_top_level_leave_message (struct x_display_info *dpyinfo, Window source, msg.xclient.data.b[18] = 0; msg.xclient.data.b[19] = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -2999,7 +2999,7 @@ x_dnd_free_toplevels (bool display_alive) if (n_windows) { eassume (dpyinfo); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); for (i = 0; i < n_windows; ++i) { @@ -3369,7 +3369,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) if (dpyinfo->xshape_supported_p) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XShapeSelectInput (dpyinfo->display, toplevels[i], ShapeNotifyMask); @@ -3534,7 +3534,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo) } #endif - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSelectInput (dpyinfo->display, toplevels[i], (attrs.your_event_mask | StructureNotifyMask @@ -4059,7 +4059,7 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo, event.xbutton.type = ButtonPress; event.xbutton.time = before + 1; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, child, True, ButtonPressMask, &event); @@ -4571,7 +4571,7 @@ x_dnd_send_enter (struct frame *f, Window target, Window toplevel, so we don't have to set it again. */ x_dnd_init_type_lists = true; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -4643,7 +4643,7 @@ x_dnd_send_position (struct frame *f, Window target, Window toplevel, return; } - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); @@ -4670,7 +4670,7 @@ x_dnd_send_leave (struct frame *f, Window target, Window toplevel) x_dnd_waiting_for_status_window = None; x_dnd_pending_send_position.type = 0; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); } @@ -4703,7 +4703,7 @@ x_dnd_send_drop (struct frame *f, Window target, Window toplevel, if (supported >= 1) msg.xclient.data.l[2] = timestamp; - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_stop_ignoring_errors (dpyinfo); return true; @@ -6815,7 +6815,7 @@ x_set_frame_alpha (struct frame *f) Do this unconditionally as this function is called on reparent when alpha has not changed on the frame. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); if (!FRAME_PARENT_FRAME (f)) { @@ -11339,7 +11339,7 @@ XTring_bell (struct frame *f) implementation. */ block_input (); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); #ifdef HAVE_XKB XkbBell (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, None); #else @@ -11593,7 +11593,7 @@ x_frame_highlight (struct frame *f) the window-manager in use, tho something more is at play since I've been using that same window-manager binary for ever. Let's not crash just because of this (bug#9310). */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->border_pixel); x_stop_ignoring_errors (dpyinfo); @@ -11616,7 +11616,7 @@ x_frame_unhighlight (struct frame *f) block_input (); /* Same as above for XSetWindowBorder (bug#9310). */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), f->output_data.x->border_tile); x_stop_ignoring_errors (dpyinfo); @@ -18611,7 +18611,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_dnd_waiting_for_status_window = None; else { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSendEvent (dpyinfo->display, target, False, NoEventMask, &x_dnd_pending_send_position); @@ -21480,7 +21480,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf))) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), RevertToParent, event->xbutton.time); x_stop_ignoring_errors (dpyinfo); @@ -23178,7 +23178,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* This can generate XI_BadDevice if the device's attachment was destroyed server-side. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XISetFocus (dpyinfo->display, device->attachment, /* Note that the input extension only supports RevertToParent-type @@ -23191,7 +23191,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, events to handle focus. Errors are still caught here in case the window is not viewable. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), RevertToParent, xev->time); x_stop_ignoring_errors (dpyinfo); @@ -24200,7 +24200,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifndef HAVE_GTK3 else if (x_input_grab_touch_events) { - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XIAllowTouchEvents (dpyinfo->display, xev->deviceid, xev->detail, xev->event, XIRejectTouch); x_stop_ignoring_errors (dpyinfo); @@ -25637,10 +25637,17 @@ x_clean_failable_requests (struct x_display_info *dpyinfo) x_uncatch_errors_after_check is that this function does not sync to catch errors if requests were made. It should be used instead of those two functions for catching errors around requests that do not - require a reply. */ + require a reply. + + As a special feature intended to support xselect.c, + SELECTION_SERIAL may be an arbitrary number greater than zero: when + that is the case, x_select_handle_selection_error is called with + the specified number to delete the selection request that + encountered the error. */ void -x_ignore_errors_for_next_request (struct x_display_info *dpyinfo) +x_ignore_errors_for_next_request (struct x_display_info *dpyinfo, + unsigned int selection_serial) { struct x_failable_request *request, *max; unsigned long next_request; @@ -25694,6 +25701,7 @@ x_ignore_errors_for_next_request (struct x_display_info *dpyinfo) request->start = next_request; request->end = 0; + request->selection_serial = selection_serial; dpyinfo->next_failable_request++; } @@ -26208,6 +26216,12 @@ x_error_handler (Display *display, XErrorEvent *event) + (last - fail)); } + /* If a selection transfer is the cause of this error, + remove the selection transfer now. */ + if (fail->selection_serial) + x_handle_selection_error (fail->selection_serial, + event); + return 0; } } @@ -27704,7 +27718,7 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) && deviceid != -1) { block_input (); - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None, FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y); x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); @@ -28001,7 +28015,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, Window window, { eassert (device->use == XIMasterPointer); - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XISetFocus (dpyinfo->display, device->attachment, /* Note that the input extension only supports RevertToParent-type @@ -28016,7 +28030,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, Window window, /* Otherwise, use the pointer device that the X server says is the client pointer. */ - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); XSetInputFocus (dpyinfo->display, window, RevertToParent, time); x_stop_ignoring_errors (dpyinfo); } @@ -28158,7 +28172,7 @@ xembed_send_message (struct frame *f, Time t, enum xembed_message msg, but I don't understand why: there is no way for clients to survive the death of the parent anyway. */ - x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f)); + x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0); XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc, False, NoEventMask, &event); x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f)); @@ -31335,7 +31349,7 @@ x_catch_errors_for_lisp (struct x_display_info *dpyinfo) if (!x_fast_protocol_requests) x_catch_errors (dpyinfo->display); else - x_ignore_errors_for_next_request (dpyinfo); + x_ignore_errors_for_next_request (dpyinfo, 0); } void diff --git a/src/xterm.h b/src/xterm.h index a888f57823f..832ffc172b9 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -334,6 +334,9 @@ #define MAX_CLIP_RECTS 2 /* If this is zero, then the request has not yet been made. Otherwise, this is the request that ends this sequence. */ unsigned long end; + + /* Any selection event serial associated with this error trap. */ + unsigned int selection_serial; }; #ifdef HAVE_XFIXES @@ -1670,7 +1673,8 @@ #define SELECTION_EVENT_TIME(eventp) \ extern void x_unwind_errors_to (int); extern void x_uncatch_errors (void); extern void x_uncatch_errors_after_check (void); -extern void x_ignore_errors_for_next_request (struct x_display_info *); +extern void x_ignore_errors_for_next_request (struct x_display_info *, + unsigned int); extern void x_stop_ignoring_errors (struct x_display_info *); extern void x_clear_errors (Display *); extern void x_set_window_size (struct frame *, bool, int, int); @@ -1830,6 +1834,7 @@ x_mutable_colormap (XVisualInfo *visual) extern void x_handle_selection_event (struct selection_input_event *); extern void x_clear_frame_selections (struct frame *); extern void x_remove_selection_transfers (struct x_display_info *); +extern void x_handle_selection_error (unsigned int, XErrorEvent *); extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom); extern Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object); commit 8404253d17a6daf2cbd6269491234c0b70fa2039 Author: Manuel Giraud Date: Thu Dec 15 09:50:32 2022 +0100 * .gitignore: Ignore GDB history files. diff --git a/.gitignore b/.gitignore index f4d2c15f516..af0ba0eb410 100644 --- a/.gitignore +++ b/.gitignore @@ -334,3 +334,7 @@ lib-src/seccomp-filter-exec.pfc # Ignore a directory used by dap-mode. .vscode /test/gmp.h + +# GDB history +.gdb_history +_gdb_history commit 12684c3a199d691899c74c67ff85723a0279c272 Author: Eli Zaretskii Date: Thu Dec 15 10:47:11 2022 +0200 Mention 'tree-sitter' in user manual and NEWS * doc/emacs/programs.texi (Program Modes): Mention tree-sitter and the modes supported by it. * etc/NEWS: Mention tree-sitter in the Installation Changes section. diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi index ba8475e86ac..954f4c892e2 100644 --- a/doc/emacs/programs.texi +++ b/doc/emacs/programs.texi @@ -88,6 +88,10 @@ Program Modes @cindex JSON mode @cindex SQL mode @cindex TypeScript mode +@cindex CSS mode +@cindex Dockerfile mode +@cindex CMake mode +@cindex TOML mode Emacs has programming language modes for Lisp, Scheme, the Scheme-based DSSSL expression language, Ada, ASM, AWK, C, C++, C#, Fortran, Icon, IDL (CORBA), IDLWAVE, Java, Javascript, M4, Makefiles, @@ -97,13 +101,20 @@ Program Modes alternative mode for Perl is called CPerl mode. Modes are also available for the scripting languages of the common GNU and Unix shells, and MS-DOS/MS-Windows @samp{BAT} files, JSON, DNS master -files, and various sorts of configuration files. +files, CSS (Cascading Style Sheets), Dockerfiles, CMake files, and various sorts of configuration files. Ideally, Emacs should have a major mode for each programming language that you might want to edit. If it doesn't have a mode for your favorite language, the mode might be implemented in a package not distributed with Emacs (@pxref{Packages}); or you can contribute one. +@cindex tree-sitter library, supported major modes + If Emacs has been compiled with the @samp{tree-sitter} library, it +offers several optional editing modes based on that library, which +utilize the incremental parsing capabilities provided by +@samp{tree-sitter}. These modes have @samp{-ts-} in their names; for +example @code{c-ts-mode}, @code{python-ts-mode}, etc. + @kindex DEL @r{(programming modes)} @findex backward-delete-char-untabify In most programming languages, indentation should vary from line to diff --git a/etc/NEWS b/etc/NEWS index ccaf111f6a6..6f0d1f65bf2 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -30,6 +30,16 @@ Use '--with-native-compilation=aot' to specify that all the Lisp files in the Emacs tree should be natively compiled ahead of time. (This is slow on most machines.) ++++ +** Emacs can be built with the 'tree-sitter' parsing library. +This library, together with grammar libraries, provides incremental +parsing capabilities for several popular programming languages and +other formatted files. Emacs built with this library offers major +modes, described elsewhere in this file, that are based on the +'tree-sitter's parsers. If you have the 'tree-sitter' library +installed, the configure script will automatically include it in the +build; use '--without-tree-sitter' at configure time to disable that. + +++ ** Emacs can be built with built-in support for accessing SQLite databases. This uses the popular sqlite3 library, and can be disabled by using commit 49d7e0cec6a91aa5509d98dcbe1b418f9eaa92d9 Author: Eli Zaretskii Date: Thu Dec 15 10:25:27 2022 +0200 ; * etc/NEWS: Rearrange entries for tree-sitter supported modes. diff --git a/etc/NEWS b/etc/NEWS index 8eb9d801a66..ccaf111f6a6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3003,76 +3003,73 @@ Emacs buffers, like indentation and the like. The new ert function This is a lightweight variant of 'js-mode' that is used by default when visiting JSON files. -** New major mode 'typescript-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the TypeScript language. It includes support for font-locking, -indentation, and navigation. This mode will be auto-enabled for -files with the ".ts" extension. +** New major mode 'csharp-mode'. +A major mode based on CC Mode for editing programs in the C# language. +This mode is auto-enabled for files with the ".cs" extension. -** New major mode 'tsx-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the TypeScript language, with support for TSX. It includes -support for font-locking, indentation, and navigation. This mode -will be auto-enabled for files with the ".tsx" extension. +** New major modes based on the tree-sitter library. +These new major modes are available if Emacs was built with the +tree-sitter library. They provide support for font-locking, +indentation, and navigation by defuns based on parsing the buffer text +by a tree-sitter parser. Some major modes also offer support for +Imenu and 'which-func'. -** New major mode 'c-ts-mode'. +*** New major mode 'typescript-ts-mode'. A major mode based on the tree-sitter library for editing programs -in the C language. It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +in the TypeScript language. This mode is auto-enabled for files with +the ".ts" extension. -** New major mode 'c++-ts-mode'. +*** New major mode 'tsx-ts-mode'. A major mode based on the tree-sitter library for editing programs -in the C++ language. It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +in the TypeScript language, with support for TSX. This mode is +auto-enabled for files with the ".tsx" extension. -** New major mode 'java-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the Java language. It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +*** New major mode 'c-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the C language. -** New major mode 'python-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the Python language. It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +*** New major mode 'c++-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the C++ language. -** New major mode 'css-ts-mode'. -A major mode based on the tree-sitter library for editing CSS -(Cascading Style Sheets). It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +*** New major mode 'java-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the Java language. -** New major mode 'json-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the JSON language. It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +*** New major mode 'python-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the Python language. -** New major mode 'csharp-ts-mode'. -A major mode based on the tree-sitter library for editing programs -in the C# language. It includes support for font-locking, -indentation, Imenu, which-func, and navigation. +*** New major mode 'css-ts-mode'. +An optional major mode based on the tree-sitter library for editing +CSS (Cascading Style Sheets). -** New major mode 'csharp-mode'. -A major mode based on CC Mode for editing programs in the C# language. +*** New major mode 'json-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the JSON language. + +*** New major mode 'csharp-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the C# language. -** New major mode 'bash-ts-mode'. -A major mode based on the tree-sitter library for editing Bash shell -scripts. It includes support for font-locking, indentation, Imenu, -which-func, and navigation. +*** New major mode 'bash-ts-mode'. +Am optional major mode based on the tree-sitter library for editing +Bash shell scripts. -** New major mode 'dockerfile-ts-mode'. +*** New major mode 'dockerfile-ts-mode'. A major mode based on the tree-sitter library for editing -Dockerfiles. It includes support for font-locking, indentation, Imenu, -and which-func. +Dockerfiles. This mode is auto-enabled for files which are named +"Dockerfile" or have the ".dockerfile" extension. -** New major mode 'cmake-ts-mode'. +*** New major mode 'cmake-ts-mode'. A major mode based on the tree-sitter library for editing CMake files. -It includes support for font-locking, indentation, Imenu, and -which-func. +It is auto-enabled for files whose name is "Cmakefile.txt" or whose +extension is ".cmake". -** New major mode toml-ts-mode'. +*** New major mode toml-ts-mode'. A major mode based on the tree-sitter library for editing files -written in TOML, a format for writing configuration files. It -includes support for font-locking, indentation, Imenu, and -'which-func'. +written in TOML, a format for writing configuration files. It is +auto-enabled for files with the ".toml" extension. * Incompatible Lisp Changes in Emacs 29.1 commit 0ad2112a2f04d122d96c06381b196c4336ee72a9 Author: Eli Zaretskii Date: Thu Dec 15 10:09:25 2022 +0200 ; Announce 'toml-ts-mode' in NEWS. diff --git a/etc/NEWS b/etc/NEWS index 662c3125e07..8eb9d801a66 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3068,6 +3068,12 @@ A major mode based on the tree-sitter library for editing CMake files. It includes support for font-locking, indentation, Imenu, and which-func. +** New major mode toml-ts-mode'. +A major mode based on the tree-sitter library for editing files +written in TOML, a format for writing configuration files. It +includes support for font-locking, indentation, Imenu, and +'which-func'. + * Incompatible Lisp Changes in Emacs 29.1 commit 98ea7054a71d73f2eaaa802645a932580ede9ec9 Author: Stefan Kangas Date: Thu Dec 15 05:11:35 2022 +0100 ; Auto-commit of loaddefs files. diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el index fb89baf0949..3f3983751df 100644 --- a/lisp/ldefs-boot.el +++ b/lisp/ldefs-boot.el @@ -2934,7 +2934,7 @@ "semantic/bovine/c" Major mode for editing C++, powered by tree-sitter. (fn)" t) -(register-definition-prefixes "c-ts-mode" '("c-ts-mode-")) +(register-definition-prefixes "c-ts-mode" '("c++-ts-mode--syntax-table" "c-ts-mode-")) ;;; Generated autoloads from calendar/cal-bahai.el @@ -4628,6 +4628,16 @@ "cl-seq" (fn START END SUBST)" t) (register-definition-prefixes "cmacexp" '("c-macro-")) + +;;; Generated autoloads from progmodes/cmake-ts-mode.el + +(add-to-list 'auto-mode-alist '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode)) +(autoload 'cmake-ts-mode "cmake-ts-mode" "\ +Major mode for editing CMake files, powered by tree-sitter. + +(fn)" t) +(register-definition-prefixes "cmake-ts-mode" '("cmake-ts-mode-")) + ;;; Generated autoloads from cmuscheme.el @@ -7980,7 +7990,7 @@ "doc-view" ;;; Generated autoloads from progmodes/dockerfile-ts-mode.el -(add-to-list 'auto-mode-alist '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)$" . dockerfile-ts-mode)) +(add-to-list 'auto-mode-alist '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" . dockerfile-ts-mode)) (autoload 'dockerfile-ts-mode "dockerfile-ts-mode" "\ Major mode for editing Dockerfiles, powered by tree-sitter. @@ -25065,7 +25075,7 @@ "ede/proj-shared" ;;; Generated autoloads from progmodes/project.el -(push (purecopy '(project 0 9 2)) package--builtin-versions) +(push (purecopy '(project 0 9 3)) package--builtin-versions) (autoload 'project-current "project" "\ Return the project instance in DIRECTORY, defaulting to `default-directory'. @@ -32372,6 +32382,16 @@ "tmm" (fn)" t) (register-definition-prefixes "todo-mode" '("todo-")) + +;;; Generated autoloads from textmodes/toml-ts-mode.el + +(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode)) +(autoload 'toml-ts-mode "toml-ts-mode" "\ +Major mode for editing TOML, powered by tree-sitter. + +(fn)" t) +(register-definition-prefixes "toml-ts-mode" '("toml-ts-mode-")) + ;;; Generated autoloads from tool-bar.el commit a15cd55044c6bb4d4e9f9aec23b8b5b9cbcb38ac Author: Stefan Kangas Date: Thu Dec 15 02:24:56 2022 +0100 ; Don't quote nil in comments diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 0486baba83c..4896f4c2937 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -399,7 +399,7 @@ read-process-name "Query the user for a process and return the process object." ;; Currently supports only the PROCESS argument. ;; Must either return a list containing a process, or signal an error. - ;; (Returning `nil' would mean the current buffer's process.) + ;; (Returning nil would mean the current buffer's process.) (unless (fboundp 'process-list) (error "Asynchronous subprocesses are not supported on this system")) ;; Local function to return cons of a complete-able name, and the diff --git a/lisp/external-completion.el b/lisp/external-completion.el index 8dd75b77193..e1c3d763142 100644 --- a/lisp/external-completion.el +++ b/lisp/external-completion.el @@ -154,7 +154,7 @@ external-completion-table ;; very often doesn't equate the full set of candidates ;; (many tools cap to sth like 100-1000 results). ;; - ;; * when `_method' is `nil' or `lambda' which some + ;; * when `_method' is nil or `lambda' which some ;; frontends will invoke. Here, `all' should be ;; sufficient information for `complete-with-action' to ;; do the job correctly. diff --git a/lisp/org/ob-clojure.el b/lisp/org/ob-clojure.el index b424cf48ff9..b045b4e6e54 100644 --- a/lisp/org/ob-clojure.el +++ b/lisp/org/ob-clojure.el @@ -248,8 +248,8 @@ ob-clojure-eval-with-cider "value"))) result0))) (ob-clojure-string-or-list - ;; Filter out s-expressions that return `nil' (string "nil" - ;; from nrepl eval) or comment forms (actual `nil' from nrepl) + ;; Filter out s-expressions that return nil (string "nil" + ;; from nrepl eval) or comment forms (actual nil from nrepl) (reverse (delete "" (mapcar (lambda (r) (replace-regexp-in-string "nil" "" (or r ""))) result0))))))) diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el index 1a32ed01020..9645dea7d9e 100644 --- a/lisp/org/org-persist.el +++ b/lisp/org/org-persist.el @@ -134,7 +134,7 @@ ;; from the persistent storage at the end of Emacs session. The ;; expiry condition can be set when saving/registering data ;; containers. The expirty condition can be `never' - data will never -;; expire; `nil' - data will expire at the end of current Emacs session; +;; expire; nil - data will expire at the end of current Emacs session; ;; a number - data will expire after the number days from last access; ;; a function - data will expire if the function, called with a single ;; argument - collection, returns non-nil. commit da39200c4be29463ad58148dbe373f9095aab929 Author: Stefan Kangas Date: Thu Dec 15 02:22:45 2022 +0100 ; Checkdoc fixes in dired-aux.el * lisp/dired-aux.el (dired-compare-directories, dired-do-chmod) (dired-do-chgrp, dired-do-chown, dired-do-touch) (dired-minibuffer-default-add-shell-commands) (dired-read-shell-command, dired-mark-prefix) (dired-mark-postfix, dired-mark-separator, dired-kill-line) (dired-reset-subdir-switches, dired-add-entry) (dired-remove-file) (dired-create-destination-dirs-on-trailing-dirsep) (dired-maybe-insert-subdir, dired-tree-up, dired-tree-down): Checkdoc fixes. diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index 5e1745069fd..7499e590a0c 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -1,7 +1,6 @@ ;;; dired-aux.el --- less commonly used parts of dired -*- lexical-binding: t -*- -;; Copyright (C) 1985-1986, 1992, 1994, 1998, 2000-2022 Free Software -;; Foundation, Inc. +;; Copyright (C) 1985-2022 Free Software Foundation, Inc. ;; Author: Sebastian Kremer . ;; Maintainer: emacs-devel@gnu.org @@ -25,7 +24,7 @@ ;;; Commentary: -;; The parts of dired mode not normally used. This is a space-saving hack +;; The parts of Dired mode not normally used. This is a space-saving hack ;; to avoid having to load a large mode when all that's wanted are a few ;; functions. @@ -37,8 +36,6 @@ ;;; Code: (require 'cl-lib) -;; We need macros in dired.el to compile properly, -;; and we call subroutines in it too. (require 'dired) (defvar dired-create-files-failures nil @@ -135,7 +132,7 @@ dired--no-subst-explain %s -\(Press ^ to %s markers below these occurrences.) +(Press ^ to %s markers below these occurrences.) " "`" (string (aref command (car char-positions))) @@ -298,7 +295,7 @@ dired-backup-diff ;;;###autoload (defun dired-compare-directories (dir2 predicate) - "Mark files with different file attributes in two dired buffers. + "Mark files with different file attributes in two Dired buffers. Compare file attributes of files in the current directory with file attributes in directory DIR2 using PREDICATE on pairs of files with the same name. Mark files for which PREDICATE returns non-nil. @@ -312,8 +309,8 @@ dired-compare-directories fa1, fa2 - list of file attributes returned by function `file-attributes' - where 1 refers to attribute of file in the current dired buffer - and 2 to attribute of file in second dired buffer. + where 1 refers to attribute of file in the current Dired buffer + and 2 to attribute of file in second Dired buffer. Examples of PREDICATE: @@ -489,7 +486,8 @@ dired-do-chxxx (defun dired-do-chmod (&optional arg) "Change the mode of the marked (or next ARG) files. Both octal numeric modes like `644' and symbolic modes like `g+w' -are supported. Type M-n to pull the file attributes of the file +are supported. Type \\\ +\\[next-history-element] to pull the file attributes of the file at point into the minibuffer. See Info node `(coreutils)File permissions' for more information. @@ -538,7 +536,8 @@ dired-do-chmod ;;;###autoload (defun dired-do-chgrp (&optional arg) "Change the group of the marked (or next ARG) files. -Type M-n to pull the file attributes of the file at point +Type \\\\[next-history-element] \ +to pull the file attributes of the file at point into the minibuffer." (interactive "P") (if (and (memq system-type '(ms-dos windows-nt)) @@ -549,7 +548,8 @@ dired-do-chgrp ;;;###autoload (defun dired-do-chown (&optional arg) "Change the owner of the marked (or next ARG) files. -Type M-n to pull the file attributes of the file at point +Type \\\\[next-history-element] \ +to pull the file attributes of the file at point into the minibuffer." (interactive "P") (if (and (memq system-type '(ms-dos windows-nt)) @@ -561,7 +561,8 @@ dired-do-chown (defun dired-do-touch (&optional arg) "Change the timestamp of the marked (or next ARG) files. This calls touch. -Type M-n to pull the file attributes of the file at point +Type Type \\\\[next-history-element] \ +to pull the file attributes of the file at point into the minibuffer." (interactive "P") (dired-do-chxxx "Timestamp" dired-touch-program 'touch arg)) @@ -761,7 +762,7 @@ dired-trample-file-versions (defvar dired-aux-files) (defun dired-minibuffer-default-add-shell-commands () - "Return a list of all commands associated with current dired files. + "Return a list of all commands associated with current Dired files. This function is used to add all related commands retrieved by `mailcap' to the end of the list of defaults just after the default value." (interactive) @@ -774,7 +775,7 @@ dired-minibuffer-default-add-shell-commands ;; This is an extra function so that you can redefine it, e.g., to use gmhist. (defun dired-read-shell-command (prompt arg files) - "Read a dired shell command. + "Read a Dired shell command. PROMPT should be a format string with one \"%s\" format sequence, which is replaced by the value returned by `dired-mark-prompt', with ARG and FILES as its arguments. FILES should be a list of @@ -921,11 +922,11 @@ dired-do-shell-command ;; Might use {,} for bash or csh: (defvar dired-mark-prefix "" - "Prepended to marked files in dired shell commands.") + "Prepended to marked files in Dired shell commands.") (defvar dired-mark-postfix "" - "Appended to marked files in dired shell commands.") + "Appended to marked files in Dired shell commands.") (defvar dired-mark-separator " " - "Separates marked files in dired shell commands.") + "Separates marked files in Dired shell commands.") (defun dired-shell-stuff-it (command file-list on-each &optional _raw-arg) ;; "Make up a shell command line from COMMAND and FILE-LIST. @@ -1336,7 +1337,7 @@ dired-guess-shell-command (defun dired-kill-line (&optional arg) "Kill the current line (not the files). With a prefix argument, kill that many lines starting with the current line. -\(A negative argument kills backward.)" +(A negative argument kills backward.)" (interactive "P") (setq arg (prefix-numeric-value arg)) (let (buffer-read-only file) @@ -1844,7 +1845,7 @@ dired-do-redisplay (message "Redisplaying...done"))) (defun dired-reset-subdir-switches () - "Set `dired-switches-alist' to nil and revert dired buffer." + "Set `dired-switches-alist' to nil and revert Dired buffer." (interactive) (setq dired-switches-alist nil) (revert-buffer)) @@ -1880,7 +1881,7 @@ dired-omit-mode (defvar dired-omit-localp) (defun dired-add-entry (filename &optional marker-char relative) - "Add a new dired entry for FILENAME. + "Add a new Dired entry for FILENAME. Optionally mark it with MARKER-CHAR (a character, else uses `dired-marker-char'). Note that this adds the entry `out of order' if files are sorted by time, etc. @@ -2008,7 +2009,7 @@ dired-after-subdir-garbage ;;;###autoload (defun dired-remove-file (file) - "Remove entry FILE on each dired buffer. + "Remove entry FILE on each Dired buffer. Note this doesn't delete FILE in the file system. See `dired-delete-file' in case you wish that." (dired-fun-in-all-buffers @@ -2107,7 +2108,7 @@ dired-create-destination-dirs-on-trailing-dirsep `new_name' does not exists already, it will be created and `old_name' be moved into it. If only `new_name' (without the trailing /) is given or this option or -`dired-create-destination-dirs' is `nil', `old_name' will be +`dired-create-destination-dirs' is nil, `old_name' will be renamed to `new_name'." :type '(choice (const :tag @@ -3077,7 +3078,7 @@ dired-downcase ;;;###autoload (defun dired-maybe-insert-subdir (dirname &optional switches no-error-if-not-dir-p) - "Insert this subdirectory into the same dired buffer. + "Insert this subdirectory into the same Dired buffer. If it is already present, just move to it (type \\[dired-do-redisplay] to refresh), else inserts it at its natural place (as `ls -lR' would have done). With a prefix arg, you may edit the ls switches used for this listing. @@ -3427,7 +3428,7 @@ dired-unsubdir ;;;###autoload (defun dired-tree-up (arg) - "Go up ARG levels in the dired tree." + "Go up ARG levels in the Dired tree." (interactive "p") (let ((dir (dired-current-directory))) (while (>= arg 1) @@ -3439,7 +3440,7 @@ dired-tree-up ;;;###autoload (defun dired-tree-down () - "Go down in the dired tree." + "Go down in the Dired tree." (interactive) (let ((dir (dired-current-directory)) ; has slash pos case-fold-search) ; filenames are case sensitive commit fd403a5c5a87adb8cf42f82c9c0cea4e029767d6 Author: Dmitry Gutov Date: Thu Dec 15 03:21:14 2022 +0200 Fix ruby-add-log-current-method after nested class definition * lisp/progmodes/ruby-mode.el (ruby--add-log-current-indent): New function. (ruby-add-log-current-method): Use it. Check for "class" and "module" indentation to filter out the definitions which don't include the given position. Also try to match "def" only once (for performance), because if the closest one doesn't include the given position, none will. * test/lisp/progmodes/ruby-mode-tests.el (ruby-add-log-current-method-after-inner-class-outside-methods) (ruby-add-log-current-method-after-inner-class-outside-methods-with-text): New tests. diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 17467b55549..4ac289d529f 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -1611,7 +1611,8 @@ ruby-add-log-current-method See `add-log-current-defun-function'." (condition-case nil (save-excursion - (let* ((indent 0) mname mlist + (let* ((indent (ruby--add-log-current-indent)) + mname mlist (start (point)) (make-definition-re (lambda (re &optional method-name?) @@ -1626,18 +1627,30 @@ ruby-add-log-current-method (definition-re (funcall make-definition-re ruby-defun-beg-re t)) (module-re (funcall make-definition-re "\\(class\\|module\\)"))) ;; Get the current method definition (or class/module). - (when (re-search-backward definition-re nil t) + (when (catch 'found + (while (and (re-search-backward definition-re nil t) + (if (if (string-equal "def" (match-string 1)) + ;; We're inside a method. + (if (ruby-block-contains-point start) + t + ;; Try to match a method only once. + (setq definition-re module-re) + nil) + ;; Class/module. For performance, + ;; comparing indentation. + (or (not (numberp indent)) + (> indent (current-indentation)))) + (throw 'found t) + t)))) (goto-char (match-beginning 1)) (if (not (string-equal "def" (match-string 1))) (setq mlist (list (match-string 2))) - ;; We're inside the method. For classes and modules, - ;; this check is skipped for performance. - (when (ruby-block-contains-point start) - (setq mname (match-string 2)))) + (setq mname (match-string 2))) (setq indent (current-column)) (beginning-of-line)) ;; Walk up the class/module nesting. - (while (and (> indent 0) + (while (and indent + (> indent 0) (re-search-backward module-re nil t)) (goto-char (match-beginning 1)) (when (< (current-column) indent) @@ -1691,6 +1704,17 @@ ruby-block-contains-point (ruby-forward-sexp)) (> (point) pt)))) +(defun ruby--add-log-current-indent () + (save-excursion + (back-to-indentation) + (cond + ((looking-at "[[:graph:]]") + (current-indentation)) + (ruby-use-smie + (smie-indent-calculate)) + (t + (ruby-calculate-indent))))) + (defun ruby-brace-to-do-end (orig end) (let (beg-marker end-marker) (goto-char end) diff --git a/test/lisp/progmodes/ruby-mode-tests.el b/test/lisp/progmodes/ruby-mode-tests.el index 33fded5a59b..e90a9e40753 100644 --- a/test/lisp/progmodes/ruby-mode-tests.el +++ b/test/lisp/progmodes/ruby-mode-tests.el @@ -578,6 +578,33 @@ ruby-add-log-current-method-after-inner-class (search-backward "_") (should (string= (ruby-add-log-current-method) "M::C#foo")))) +(ert-deftest ruby-add-log-current-method-after-inner-class-outside-methods () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | class D + | end + | + |_ + | end + |end") + (search-backward "_") + (delete-char 1) + (should (string= (ruby-add-log-current-method) "M::C")))) + +(ert-deftest ruby-add-log-current-method-after-inner-class-outside-methods-with-text () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | class D + | end + | + | FOO = 5 + | end + |end") + (search-backward "FOO") + (should (string= (ruby-add-log-current-method) "M::C")))) + (defvar ruby-block-test-example (ruby-test-string "class C commit 2ca06aed7b39afdc00041ab7cd9c7a8cb50332f6 Author: Theodor Thornhill Date: Wed Dec 14 21:23:33 2022 +0100 Add indent rules to js/typescript/tsx-ts-mode (bug#60074) * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode--indent-rules): Add in binary_expression and jsx_fragment. * lisp/progmodes/js.el (js--treesit-indent-rules): Add the same rules. diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 02990813ef4..8ec14cf7ad1 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3445,12 +3445,15 @@ js--treesit-indent-rules ((parent-is "pair") parent-bol js-indent-level) ((parent-is "arrow_function") parent-bol js-indent-level) ((parent-is "parenthesized_expression") parent-bol js-indent-level) + ((parent-is "binary_expression") parent-bol js-indent-level) ((parent-is "class_body") parent-bol js-indent-level) ((parent-is ,switch-case) parent-bol js-indent-level) ((parent-is "statement_block") parent-bol js-indent-level) ;; JSX ((parent-is "jsx_opening_element") parent js-indent-level) + ((match "<" "jsx_fragment") parent 0) + ((parent-is "jsx_fragment") parent js-indent-level) ((node-is "jsx_closing_element") parent 0) ((node-is "jsx_text") parent js-indent-level) ((parent-is "jsx_element") parent js-indent-level) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index b8a921e9c24..e7bd65c5e2f 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -92,9 +92,12 @@ typescript-ts-mode--indent-rules ((parent-is "class_body") parent-bol typescript-ts-mode-indent-offset) ((parent-is "arrow_function") parent-bol typescript-ts-mode-indent-offset) ((parent-is "parenthesized_expression") parent-bol typescript-ts-mode-indent-offset) + ((parent-is "binary_expression") parent-bol typescript-ts-mode-indent-offset) ,@(when (eq language 'tsx) `(((parent-is "jsx_opening_element") parent typescript-ts-mode-indent-offset) + ((match "<" "jsx_fragment") parent 0) + ((parent-is "jsx_fragment") parent typescript-ts-mode-indent-offset) ((node-is "jsx_closing_element") parent 0) ((parent-is "jsx_element") parent typescript-ts-mode-indent-offset) ((node-is "/") parent 0) commit a54d5f500c1a9959b1f87c731aa9ac1b7eed27c9 Author: Jostein Kjønigsen Date: Thu Dec 8 11:07:15 2022 +0100 Improve fontification in csharp-ts-mode (bug#59897) Fixes highlighting of generic methods like the one below: instance.MethodWithTypeArguments(...); InClassMethodWithTypeArguments(...); * lisp/progmodes/csharp-mode.el (csharp-ts-mode--font-lock-settings): Add new rule. diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index dfe98cc49e6..2d13ae6930c 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -791,7 +791,15 @@ csharp-ts-mode--font-lock-settings (invocation_expression (identifier) @font-lock-function-name-face) (invocation_expression - (member_access_expression (identifier) @font-lock-function-name-face)) + (member_access_expression + expression: (identifier) @font-lock-variable-name-face)) + (invocation_expression + function: [(generic_name (identifier)) @font-lock-function-name-face + (generic_name (type_argument_list + ["<"] @font-lock-bracket-face + (identifier) @font-lock-type-face + [">"] @font-lock-bracket-face) + )]) (catch_declaration ((identifier) @font-lock-type-face)) commit 3db2f560bb7c41d93de4bebc0247e5fc597bd534 Author: Yuan Fu Date: Wed Dec 14 14:28:29 2022 -0800 Revert "Add expression for generic_name in csharp-ts-mode" I applied the wrong commit, the next commit will be the right one, sorry about that! This reverts commit 647b6a8099f414e5a7b162efd3658e174064dfe7. diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index dda0b105b74..dfe98cc49e6 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -784,10 +784,6 @@ csharp-ts-mode--font-lock-settings (invocation_expression (member_access_expression (generic_name (identifier) @font-lock-function-name-face))) - (invocation_expression - (member_access_expression - expression: (identifier) @font-lock-variable-name-face - name: (generic_name (type_argument_list (identifier))))) (invocation_expression (member_access_expression ((identifier) @font-lock-variable-name-face commit 1985762fbd727024cecef463a079ad25fb8c1482 Author: Jostein Kjønigsen Date: Sun Dec 11 13:05:29 2022 +0100 Introduce support for TOML config-format This commit introduces support for the semi-popular TOML config-format[1] through a new major-mode: toml-ts-mode. I've read through the full spec[2], and from what I can see this major-mode should provide correct syntax-highligting for every sort of config-declaration which adheres to the specification. Besides that it also adds support for imenu and basic tree-sitter based navigation. [1] https://toml.io/en/ [2] https://toml.io/en/v1.0.0 diff --git a/admin/notes/tree-sitter/build-module/batch.sh b/admin/notes/tree-sitter/build-module/batch.sh index c3954499774..e7ef45cf57d 100755 --- a/admin/notes/tree-sitter/build-module/batch.sh +++ b/admin/notes/tree-sitter/build-module/batch.sh @@ -1,6 +1,7 @@ #!/bin/bash languages=( + 'bash' 'c' 'cmake' 'cpp' @@ -13,8 +14,9 @@ languages= 'json' 'python' 'rust' - 'typescript' + 'toml' 'tsx' + 'typescript' ) for language in "${languages[@]}" diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el new file mode 100644 index 00000000000..26a3eb69d8d --- /dev/null +++ b/lisp/textmodes/toml-ts-mode.el @@ -0,0 +1,187 @@ +;;; toml-ts-mode.el --- tree-sitter support for TOML -*- lexical-binding: t; -*- + +;; Copyright (C) 2022 Free Software Foundation, Inc. + +;; Author : Jostein Kjønigsen +;; Maintainer : Jostein Kjønigsen +;; Created : December 2022 +;; Keywords : toml languages tree-sitter + +;; 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 . + +;;; Commentary: +;; + +;;; Code: + +(require 'treesit) + +(declare-function treesit-parser-create "treesit.c") +(declare-function treesit-induce-sparse-tree "treesit.c") +(declare-function treesit-node-start "treesit.c") +(declare-function treesit-node-child-by-field-name "treesit.c") + +(defcustom toml-ts-mode-indent-offset 2 + "Number of spaces for each indentation step in `toml-ts-mode'." + :version "29.1" + :type 'integer + :safe 'integerp + :group 'toml) + +(defvar toml-ts-mode--syntax-table + (let ((table (make-syntax-table))) + (modify-syntax-entry ?_ "_" table) + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?\' "\"" table) + (modify-syntax-entry ?# "<" table) + (modify-syntax-entry ?\n "> b" table) + (modify-syntax-entry ?\^m "> b" table) + table) + "Syntax table for `toml-ts-mode'.") + +(defvar toml-ts-mode--indent-rules + `((toml + ((node-is "]") parent-bol 0) + ((parent-is "string") parent-bol toml-ts-mode-indent-offset) + ((parent-is "array") parent-bol toml-ts-mode-indent-offset)))) + +(defvar toml-ts-mode--font-lock-settings + (treesit-font-lock-rules + :language 'toml + :feature 'comment + '((comment) @font-lock-comment-face) + + :language 'toml + :feature 'constant + '((boolean) @font-lock-constant-face) + + :language 'toml + :feature 'delimiter + '((["="]) @font-lock-delimiter-face) + + :language 'toml + :feature 'number + '([(integer) (float) (local_date) (local_date_time) (local_time)] + @font-lock-number-face) + + :language 'toml + :feature 'string + '((string) @font-lock-string-face) + + :language 'toml + :feature 'escape-sequence + :override t + '((escape_sequence) @font-lock-escape-face) + + :language 'toml + :feature 'pair + :override t ; Needed for overriding string face on keys. + '((bare_key) @font-lock-property-face + (quoted_key) @font-lock-property-face + (table ("[" @font-lock-bracket-face + (_) @font-lock-type-face + "]" @font-lock-bracket-face)) + (table_array_element ("[[" @font-lock-bracket-face + (_) @font-lock-type-face + "]]" @font-lock-bracket-face)) + (table (quoted_key) @font-lock-type-face) + (table (dotted_key (quoted_key)) @font-lock-type-face)) + + :language 'toml + :feature 'error + :override t + '((ERROR) @font-lock-warning-face)) + "Font-lock settings for TOML.") + +(defun toml-ts-mode--get-table-name (node) + "Obtains the header-name for the associated tree-sitter `NODE'." + (if node + (treesit-node-text + (car (cdr (treesit-node-children node)))) + "Root table")) + +(defun toml-ts-mode--imenu-1 (node) + "Helper for `toml-ts-mode--imenu'. +Find string representation for NODE and set marker, then recurse +the subtrees." + (let* ((ts-node (car node)) + (subtrees (mapcan #'toml-ts-mode--imenu-1 (cdr node))) + (name (toml-ts-mode--get-table-name ts-node)) + (marker (when ts-node + (set-marker (make-marker) + (treesit-node-start ts-node))))) + (cond + ((null ts-node) subtrees) + (subtrees + `((,name ,(cons name marker) ,@subtrees))) + (t + `((,name . ,marker)))))) + +(defun toml-ts-mode--imenu () + "Return Imenu alist for the current buffer." + (let* ((node (treesit-buffer-root-node)) + (table-tree (treesit-induce-sparse-tree + node "^table$" nil 1000)) + (table-array-tree (treesit-induce-sparse-tree + node "^table_array_element$" nil 1000)) + (table-index (toml-ts-mode--imenu-1 table-tree)) + (table-array-index (toml-ts-mode--imenu-1 table-array-tree))) + (append + (when table-index `(("Headers" . ,table-index))) + (when table-array-index `(("Arrays" . ,table-array-index)))))) + + +;;;###autoload +(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode)) + +;;;###autoload +(define-derived-mode toml-ts-mode text-mode "TOML" + "Major mode for editing TOML, powered by tree-sitter." + :group 'toml-mode + :syntax-table toml-ts-mode--syntax-table + + (when (treesit-ready-p 'toml) + (treesit-parser-create 'toml) + + ;; Comments + (setq-local comment-start "# ") + (setq-local commend-end "") + + ;; Indent. + (setq-local treesit-simple-indent-rules toml-ts-mode--indent-rules) + + ;; Navigation. + (setq-local treesit-defun-type-regexp + (rx (or "table" "table_array_element"))) + + ;; Font-lock. + (setq-local treesit-font-lock-settings toml-ts-mode--font-lock-settings) + (setq-local treesit-font-lock-feature-list + '((comment) + (constant number pair string) + (escape-sequence) + (delimiter error))) + + ;; Imenu. + (setq-local imenu-create-index-function #'toml-ts-mode--imenu) + (setq-local which-func-functions nil) ;; Piggyback on imenu + + (treesit-major-mode-setup))) + +(provide 'toml-ts-mode) + +;;; toml-ts-mode.el ends here commit 622838b957e240d700585050e9ddbd036e690513 Author: Arash Esbati Date: Wed Dec 14 21:17:30 2022 +0100 Fix handling of % when searching in .tex or .dtx files * lisp/textmodes/reftex.el (reftex-compile-variables): Consider % when building the regexp for searching only in .dtx files. (AUCTeX bug#59638) diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el index f815419ea44..126b3777f55 100644 --- a/lisp/textmodes/reftex.el +++ b/lisp/textmodes/reftex.el @@ -1004,10 +1004,13 @@ reftex-compile-variables reftex-section-levels)) ;; Calculate the regular expressions - (let* ( -; (wbol "\\(\\`\\|[\n\r]\\)[ \t]*") - (wbol "\\(^\\)%?[ \t]*") ; Need to keep the empty group because - ; match numbers are hard coded + (let* (;; (wbol "\\(\\`\\|[\n\r]\\)[ \t]*") + ;; Need to keep the empty group because match numbers are + ;; hard coded + (wbol (concat "\\(^\\)" + (when (string-suffix-p ".dtx" (buffer-file-name) t) + "%") + "[ \t]*")) (label-re (concat "\\(?:" (mapconcat #'identity reftex-label-regexps "\\|") "\\)")) commit 3b226b60248d47c5fbd9d04aa01d56f3222e0669 Author: Daniel Martín Date: Tue Dec 13 21:35:40 2022 +0100 Treat C++ classes as defuns in C Tree-sitter mode (bug#60047) * lisp/progmodes/c-ts-mode.el (c-ts-base-mode): Add "class_specifier" as a node of type "defun". diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 821e8f5fd96..ff2ff63fd82 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -563,7 +563,8 @@ c-ts-base-mode "type_definition" "struct_specifier" "enum_specifier" - "union_specifier"))) + "union_specifier" + "class_specifier"))) ;; Nodes like struct/enum/union_specifier can appear in ;; function_definitions, so we need to find the top-level node. commit 480f41c7deb4d3a45a862a5308950b35085f835d Author: Daniel Martín Date: Tue Dec 13 22:28:13 2022 +0100 Add < and > to the syntax table in c++-ts-mode (bug#60049) * lisp/progmodes/c-ts-mode.el (c++-ts-mode--syntax-table): Add a specific syntax table for C++. Consider "<" and ">" open/close delimiters (C++ templates). (c++-ts-mode): Use the new syntax table. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 4cf06e10ebf..821e8f5fd96 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -83,6 +83,14 @@ c-ts-mode--syntax-table table) "Syntax table for `c-ts-mode'.") +(defvar c++-ts-mode--syntax-table + (let ((table (make-syntax-table c-ts-mode--syntax-table))) + ;; Template delimiters. + (modify-syntax-entry ?< "(" table) + (modify-syntax-entry ?> ")" table) + table) + "Syntax table for `c++-ts-mode'.") + (defun c-ts-mode--indent-styles (mode) "Indent rules supported by `c-ts-mode'. MODE is either `c' or `cpp'." @@ -616,6 +624,7 @@ c-ts-mode (define-derived-mode c++-ts-mode c-ts-base-mode "C++" "Major mode for editing C++, powered by tree-sitter." :group 'c++ + :syntax-table c++-ts-mode--syntax-table (unless (treesit-ready-p 'cpp) (error "Tree-sitter for C++ isn't available")) commit fbf0d3b796ac1b891be35b642878a1fd412ee5ea Author: Jostein Kjønigsen Date: Wed Dec 7 09:27:42 2022 +0100 Improve fontifications in Typescript mode * lisp/progmodes/typescript-ts-mode.el: Improve fontification of variables. (Bug#59831) diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index e4d188971a0..b8a921e9c24 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -225,7 +225,31 @@ typescript-ts-mode--font-lock-settings (binary_expression left: (identifier) @font-lock-variable-name-face) (binary_expression right: (identifier) @font-lock-variable-name-face) - (arguments (identifier) @font-lock-variable-name-face)) + (arguments (identifier) @font-lock-variable-name-face) + + (parenthesized_expression (identifier) @font-lock-variable-name-face) + (parenthesized_expression (_ (identifier)) @font-lock-variable-name-face)) + + :language language + :override t + :feature 'property + `((property_signature + name: (property_identifier) @font-lock-property-face) + (public_field_definition + name: (property_identifier) @font-lock-property-face) + (member_expression + object: (identifier) @font-lock-variable-name-face) + (member_expression + property: (_) @font-lock-property-face) + + (pair key: (property_identifier) @font-lock-variable-name-face) + + (pair value: (identifier) @font-lock-variable-name-face) + + ((shorthand_property_identifier) @font-lock-property-face) + + ((shorthand_property_identifier_pattern) + @font-lock-property-face)) :language language :override t @@ -291,22 +315,8 @@ typescript-ts-mode--font-lock-settings :override t '((escape_sequence) @font-lock-escape-face) - :language language - :override t - :feature 'property - `((property_signature - name: (property_identifier) @font-lock-property-face) - (public_field_definition - name: (property_identifier) @font-lock-property-face) - (pair key: (property_identifier) @font-lock-variable-name-face) - - (pair value: (identifier) @font-lock-variable-name-face) - - ((shorthand_property_identifier) @font-lock-property-face) - - ((shorthand_property_identifier_pattern) - @font-lock-property-face)))) + )) ;;;###autoload (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode)) commit f93a5180a61070c14906a86d5665c615bdbc652a Author: Eli Zaretskii Date: Wed Dec 14 20:13:47 2022 +0200 Update the documentation of overlays (bug#59996) * src/buffer.c (Foverlay_recenter, Foverlay_lists): Update the doc strings. * lisp/subr.el (copy-overlay): Update comment. * doc/lispref/internals.texi (Buffer Internals): Remove buffer fields relevant to the old implementation; add the new interval tree field. * doc/lispref/display.texi (Overlays, Managing Overlays): Update text to be consistent with the new implementation of overlays. (Managing Overlays): Remove documentation of 'overlay-recenter'. * etc/NEWS: Mention incompatible aspects of overlay reimplementation. diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 13dc228261a..4111a86aa7e 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -1460,7 +1460,8 @@ Overlays the screen, for the sake of presentation features. An overlay is an object that belongs to a particular buffer, and has a specified beginning and end. It also has properties that you can examine and set; -these affect the display of the text within the overlay. +these affect the display of the text within the overlaid portion of +the buffer. Editing the text of the buffer adjusts the beginning and end of each overlay so that it stays with the text. When you create the overlay, @@ -1482,7 +1483,7 @@ Managing Overlays This section describes the functions to create, delete and move overlays, and to examine their contents. Overlay changes are not recorded in the buffer's undo list, since the overlays are not -part of the buffer's contents. +considered part of the buffer's contents. @defun overlayp object This function returns @code{t} if @var{object} is an overlay. @@ -1504,15 +1505,14 @@ Managing Overlays cause it to be deleted by giving it the @samp{evaporate} property (@pxref{Overlay Properties, evaporate property}). -The arguments @var{front-advance} and @var{rear-advance} specify the -marker insertion type for the start of the overlay and for the end of -the overlay, respectively. @xref{Marker Insertion Types}. If they -are both @code{nil}, the default, then the overlay extends to include -any text inserted at the beginning, but not text inserted at the end. -If @var{front-advance} is non-@code{nil}, text inserted at the -beginning of the overlay is excluded from the overlay. If -@var{rear-advance} is non-@code{nil}, text inserted at the end of the -overlay is included in the overlay. +The arguments @var{front-advance} and @var{rear-advance} specify what +happens when text is inserted at the beginning (i.e., before +@var{start}) and at the end. If they are both @code{nil}, the +default, then the overlay extends to include any text inserted at the +beginning, but not text inserted at the end. If @var{front-advance} +is non-@code{nil}, text inserted at the beginning of the overlay is +excluded from the overlay. If @var{rear-advance} is non-@code{nil}, +text inserted at the end of the overlay is included in the overlay. @end defun @defun overlay-start overlay @@ -1531,36 +1531,36 @@ Managing Overlays @end defun @defun delete-overlay overlay -This function deletes @var{overlay}. The overlay continues to exist as -a Lisp object, and its property list is unchanged, but it ceases to be -attached to the buffer it belonged to, and ceases to have any effect on -display. +This function deletes the specified @var{overlay}. The overlay +continues to exist as a Lisp object, and its property list is +unchanged, but it ceases to be attached to the buffer it belonged to, +and ceases to have any effect on display. A deleted overlay is not permanently disconnected. You can give it a position in a buffer again by calling @code{move-overlay}. @end defun @defun move-overlay overlay start end &optional buffer -This function moves @var{overlay} to @var{buffer}, and places its bounds -at @var{start} and @var{end}. Both arguments @var{start} and @var{end} -must specify buffer positions; they may be integers or markers. +This function moves @var{overlay} to @var{buffer}, and places its +bounds at @var{start} and @var{end} in that buffer. Both arguments +@var{start} and @var{end} must specify buffer positions; they may be +integers or markers. If @var{buffer} is omitted, @var{overlay} stays in the same buffer it -was already associated with; if @var{overlay} was deleted, it goes into -the current buffer. +was already associated with; if @var{overlay} was previously deleted +(and thus isn't associated with any buffer), it goes into the current +buffer. The return value is @var{overlay}. -This is the only valid way to change the endpoints of an overlay. Do -not try modifying the markers in the overlay by hand, as that fails to -update other vital data structures and can cause some overlays to be -lost. +This function is the only valid way to change the endpoints of an +overlay. @end defun @defun remove-overlays &optional start end name value This function removes all the overlays between @var{start} and -@var{end} whose property @var{name} has the value @var{value}. It can -move the endpoints of the overlays in the region, or split them. +@var{end} whose property @var{name} has the specified @var{value}. It +can move the endpoints of the overlays in the region, or split them. If @var{name} is omitted or @code{nil}, it means to delete all overlays in the specified region. If @var{start} and/or @var{end} are omitted or @@ -1571,20 +1571,24 @@ Managing Overlays @defun copy-overlay overlay This function returns a copy of @var{overlay}. The copy has the same -endpoints and properties as @var{overlay}. However, the marker +endpoints and properties as @var{overlay}. However, the text insertion type for the start of the overlay and for the end of the -overlay are set to their default values (@pxref{Marker Insertion -Types}). +overlay are set to their default values. @end defun Here are some examples: @example +@group ;; @r{Create an overlay.} (setq foo (make-overlay 1 10)) @result{} # +@end group +@group (overlay-start foo) @result{} 1 +@end group +@group (overlay-end foo) @result{} 10 (overlay-buffer foo) @@ -1595,6 +1599,8 @@ Managing Overlays ;; @r{Verify the property is present.} (overlay-get foo 'happy) @result{} t +@end group +@group ;; @r{Move the overlay.} (move-overlay foo 5 20) @result{} # @@ -1602,6 +1608,8 @@ Managing Overlays @result{} 5 (overlay-end foo) @result{} 20 +@end group +@group ;; @r{Delete the overlay.} (delete-overlay foo) @result{} nil @@ -1615,6 +1623,8 @@ Managing Overlays @result{} nil (overlay-buffer foo) @result{} nil +@end group +@group ;; @r{Undelete the overlay.} (move-overlay foo 1 20) @result{} # @@ -1625,26 +1635,14 @@ Managing Overlays @result{} 20 (overlay-buffer foo) @result{} # +@end group +@group ;; @r{Moving and deleting the overlay does not change its properties.} (overlay-get foo 'happy) @result{} t +@end group @end example - Emacs stores the overlays of each buffer in two lists, divided -around an arbitrary center position. One list extends backwards -through the buffer from that center position, and the other extends -forwards from that center position. The center position can be anywhere -in the buffer. - -@defun overlay-recenter pos -This function recenters the overlays of the current buffer around -position @var{pos}. That makes overlay lookup faster for positions -near @var{pos}, but slower for positions far away from @var{pos}. -@end defun - - A loop that scans the buffer forwards, creating overlays, can run -faster if you do @code{(overlay-recenter (point-max))} first. - @node Overlay Properties @subsection Overlay Properties @cindex overlay properties @@ -1701,15 +1699,15 @@ Overlay Properties (or zero), or a positive integer. Any other value has undefined behavior. The priority matters when two or more overlays cover the same -character and both specify the same property; the one whose -@code{priority} value is larger overrides the other. (For the -@code{face} property, the higher priority overlay's value does not -completely override the other value; instead, its face attributes -override the face attributes of the lower priority @code{face} -property.) If two overlays have the same priority value, and one is -nested in the other, then the inner one will prevail over the outer -one. If neither is nested in the other then you should not make -assumptions about which overlay will prevail. +character and both specify the same property with different values; +the one whose @code{priority} value is larger overrides the other. +(For the @code{face} property, the higher priority overlay's value +does not completely override the other value; instead, its face +attributes override the face attributes of the @code{face} property +whose priority is lower.) If two overlays have the same priority +value, and one is nested in the other, then the inner one will prevail +over the outer one. If neither is nested in the other then you should +not make assumptions about which overlay will prevail. Currently, all overlays take priority over text properties. @@ -1770,7 +1768,7 @@ Overlay Properties This property is used instead of @code{face} when the mouse is within the range of the overlay. However, Emacs ignores all face attributes from this property that alter the text size (e.g., @code{:height}, -@code{:weight}, and @code{:slant}). Those attributes are always the +@code{:weight}, and @code{:slant}); those attributes are always the same as in the unhighlighted text. @item display @@ -1783,9 +1781,8 @@ Overlay Properties @item help-echo @kindex help-echo @r{(overlay property)} If an overlay has a @code{help-echo} property, then when you move the -mouse onto the text in the overlay, Emacs displays a help string in the -echo area, or in the tooltip window. For details see @ref{Text -help-echo}. +mouse onto the text in the overlay, Emacs displays a help string in +the echo area, or as a tooltip. For details see @ref{Text help-echo}. @item field @kindex field @r{(overlay property)} @@ -1852,7 +1849,8 @@ Overlay Properties Properties}, for details. @item isearch-open-invisible -This property tells incremental search how to make an invisible overlay +This property tells incremental search (@pxref{Incremental Search,,, +emacs, The GNU Emacs Manual}) how to make an invisible overlay visible, permanently, if the final match overlaps it. @xref{Invisible Text}. @@ -1864,13 +1862,15 @@ Overlay Properties @kindex before-string @r{(overlay property)} This property's value is a string to add to the display at the beginning of the overlay. The string does not appear in the buffer in any -sense---only on the screen. +sense---only on the screen. Note that if the text at the beginning of +the overlay is made invisible, the string will not be displayed. @item after-string @kindex after-string @r{(overlay property)} This property's value is a string to add to the display at the end of the overlay. The string does not appear in the buffer in any -sense---only on the screen. +sense---only on the screen. Note that if the text at the end of the +overlay is made invisible, the string will not be displayed. @item line-prefix This property specifies a display spec to prepend to each diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index c4e724d761c..3174056ed83 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -2423,19 +2423,6 @@ Buffer Internals as those created by @code{with-temp-buffer} (@pxref{Definition of with-temp-buffer,, Current Buffer}). -@item overlay_center -This field holds the current overlay center position. @xref{Managing -Overlays}. - -@item overlays_before -@itemx overlays_after -These fields hold, respectively, a list of overlays that end at or -before the current overlay center, and a list of overlays that end -after the current overlay center. @xref{Managing Overlays}. -@code{overlays_before} is sorted in order of decreasing end position, -and @code{overlays_after} is sorted in order of increasing beginning -position. - @item name A Lisp string that names the buffer. It is guaranteed to be unique. @xref{Buffer Names}. This and the following fields have their names @@ -2562,6 +2549,9 @@ Buffer Internals variable names have underscores replaced with dashes. For instance, @code{mode_line_format} stores the value of @code{mode-line-format}. +@item overlays +The inveral tree containing this buffer's overlays. + @item last_selected_window This is the last window that was selected with this buffer in it, or @code{nil} if that window no longer displays this buffer. diff --git a/etc/NEWS b/etc/NEWS index 6cb531cd0f1..662c3125e07 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -105,16 +105,6 @@ configuration on X is known to have problems, such as undesirable frame positioning and various issues with keyboard input of sequences such as 'C-;' and 'C-S-u'. ---- -** The implementation of overlays has changed. -Emacs now uses an implementation of overlays that is much more -efficient than the original one, and should speed up all the -operations that involve overlays, especially when there are lots of -them in a buffer. However, no changes in behavior of overlays should -be visible on the Lisp or user level, with the exception of better -performance and the order of overlays returned by functions that don't -promise any particular order. - --- ** The docstrings of preloaded files are not in "etc/DOC" any more. Instead, they're fetched as needed from the corresponding ".elc" file, @@ -3081,6 +3071,35 @@ which-func. * Incompatible Lisp Changes in Emacs 29.1 ++++ +** The implementation of overlays has changed. +Emacs now uses an implementation of overlays that is much more +efficient than the original one, and should speed up all the +operations that involve overlays, especially when there are lots of +them in a buffer. + +As result of this, some minor incompatibilities in behavior could be +observed, as described below. Except those minor incompatibilities, +no other changes in behavior of overlays should be visible on the Lisp +or user level, with the exception of better performance and the order +of overlays returned by functions that don't promise any particular +order. + +*** The function 'overlay-recenter' is now a no-op. +This function does nothing, and in particular has no effect on the +value returned by 'overlay-lists'. The purpose of 'overlay-recenter' +was to allow more efficient lookup of overlays around certain buffer +position; however with the new implementation the lookup of overlays +is efficient regardless of their position, and there's no longer any +need to "optimize" the lookup, nor any notion of "center" of the +overlays. + +*** The function 'overlay-lists' returns one unified list of overlays. +This function used to return a cons of two lists, one with overlays +before the "center" position, the other after that "center". It now +returns a list whose 'car' is the list of all the buffer overlays, and +whose 'cdr' is always nil. + +++ ** 'format-prompt' now uses 'substitute-command-keys'. This means that both the prompt and 'minibuffer-default-prompt-format' diff --git a/lisp/subr.el b/lisp/subr.el index 21f43092d42..e142eaa8104 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -3855,7 +3855,7 @@ copy-overlay (let ((o1 (if (overlay-buffer o) (make-overlay (overlay-start o) (overlay-end o) ;; FIXME: there's no easy way to find the - ;; insertion-type of the two markers. + ;; insertion-type of overlay's start and end. (overlay-buffer o)) (let ((o1 (make-overlay (point-min) (point-min)))) (delete-overlay o1) diff --git a/src/buffer.c b/src/buffer.c index 69f27c9f476..9a30faa0e1a 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -3898,11 +3898,11 @@ DEFUN ("previous-overlay-change", Fprevious_overlay_change, /* These functions are for debugging overlays. */ DEFUN ("overlay-lists", Foverlay_lists, Soverlay_lists, 0, 0, 0, - doc: /* Return a pair of lists giving all the overlays of the current buffer. -The car has all the overlays before the overlay center; -the cdr has all the overlays after the overlay center. -Recentering overlays moves overlays between these lists. -The lists you get are copies, so that changing them has no effect. + doc: /* Return a list giving all the overlays of the current buffer. + +For backward compatibility, the value is actually a list that +holds another list; the overlays are in the inner list. +The list you get is a copy, so that changing it has no effect. However, the overlays you get are the real objects that the buffer uses. */) (void) { @@ -3918,7 +3918,12 @@ DEFUN ("overlay-lists", Foverlay_lists, Soverlay_lists, 0, 0, 0, DEFUN ("overlay-recenter", Foverlay_recenter, Soverlay_recenter, 1, 1, 0, doc: /* Recenter the overlays of the current buffer around position POS. That makes overlay lookup faster for positions near POS (but perhaps slower -for positions far away from POS). */) +for positions far away from POS). + +Since Emacs 29.1, this function is a no-op, because the implementation +of overlays changed and their lookup is now fast regardless of their +position in the buffer. In particular, this function no longer affects +the value returned by `overlay-lists'. */) (Lisp_Object pos) { CHECK_FIXNUM_COERCE_MARKER (pos); commit d51b66ed5407c63b5a07c5ca26d233678b709ad6 Author: Eli Zaretskii Date: Wed Dec 14 17:46:16 2022 +0200 ; Improve description of scoping and let-bindings * doc/lispref/variables.texi (Local Variables, Variable Scoping): Explain the move to lexical-binding and elaborate on 'let*'. Suggested by Michael Heerdegen . (Bug#60027) diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi index 7206f2acd20..750aeabf65a 100644 --- a/doc/lispref/variables.texi +++ b/doc/lispref/variables.texi @@ -188,15 +188,18 @@ Local Variables and it is the binding acted on by @code{setq}. For most purposes, you can think of the current binding as the -innermost local binding, or the global binding if there is no -local binding. To be more precise, a rule called the @dfn{scoping -rule} determines where in a program a local binding takes effect. The +innermost local binding, or the global binding if there is no local +binding. To be more precise, a rule called the @dfn{scoping rule} +determines where in a program a local binding takes effect. The default scoping rule in Emacs Lisp is called @dfn{dynamic scoping}, which simply states that the current binding at any given point in the execution of a program is the most recently-created binding for that variable that still exists. For details about dynamic scoping, and an alternative scoping rule called @dfn{lexical scoping}, @pxref{Variable -Scoping}. +Scoping}. Lately Emacs is moving towards using lexical binding in +more and more places, with the goal of eventually making lexical +binding the default. In particular, all Emacs Lisp source files and +the @file{*scratch*} buffer use lexical scoping. The special forms @code{let} and @code{let*} exist to create local bindings: @@ -266,6 +269,17 @@ Local Variables @result{} (1 1) @end group @end example + +@noindent +Basically, the @code{let*} binding of @code{x} and @code{y} in the +previous example is equivalent to using nested @code{let} bindings: + +@example +(let ((y 1)) + (let ((z y)) + (list y z))) +@end example + @end defspec @defspec letrec (bindings@dots{}) forms@dots{} @@ -974,6 +988,11 @@ Variable Scoping binding can live on even after the binding construct has finished executing, by means of special objects called @dfn{closures}. + The dynamic binding was (and still is) the default in Emacs for many +years, but lately Emacs is moving towards using lexical binding in +more and more places, with the goal of eventually making that the +default. + The following subsections describe dynamic binding and lexical binding in greater detail, and how to enable lexical binding in Emacs Lisp programs. commit 752f9dde63199d56c4b7dec0e9fd2c0c0ad182a8 Author: Eli Zaretskii Date: Wed Dec 14 17:08:46 2022 +0200 ; Fix a typo in window.el * lisp/window.el (switch-to-prev-buffer-skip-p): Fix typo. Patch by Shuguang Sun . (Bug#59985) diff --git a/lisp/window.el b/lisp/window.el index a11293d372a..7d8ee48635a 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -4636,7 +4636,7 @@ switch-to-prev-buffer-skip-p (catch 'found (dolist (regexp switch-to-prev-buffer-skip-regexp) (when (string-match-p regexp (buffer-name buffer)) - (throw 'tag t))))))))) + (throw 'found t))))))))) (defun switch-to-prev-buffer (&optional window bury-or-kill) "In WINDOW switch to previous buffer. commit 102a3e3b445d96e5a74a3ec32b2a2b701b80819e Author: F. Jason Park Date: Mon Dec 12 23:58:03 2022 -0800 Don't send erc-sasl-user as USER command argument * lisp/erc/erc-sasl.el (erc-sasl--send-cap-ls): Add internal switch for sending an opening "CAP LS". The rationale for not enabling this by default is twofold: one, it more strongly implies that ERC supports IRCv3 client capability negotiation, which is somewhat disingenuous; and, two, We'd still be "faking it" by firing and forgetting, and more balls in the air makes things less predictable. (erc--register-connection): Possibly send a "CAP LS" before anything depending on the value of `erc-sasl--send-cap-ls'. Also, don't attempt to send `erc-session-username' when it holds an SASL username because the latter may contain protocol-defying characters. * test/lisp/erc/resources/base/local-modules/fourth.eld: change user parameter of "USER" command to reflect nick when `erc-sasl-user' is set to `:user'. (Bug#59976.) diff --git a/lisp/erc/erc-sasl.el b/lisp/erc/erc-sasl.el index 280910111d5..78d02a46381 100644 --- a/lisp/erc/erc-sasl.el +++ b/lisp/erc/erc-sasl.el @@ -414,17 +414,30 @@ erc-sasl--destroy " ")) (erc-sasl--destroy proc)) +(defvar erc-sasl--send-cap-ls nil + "Whether to send an opening \"CAP LS\" command. +This is an escape hatch for picky servers. If you need it turned +into a user option, please let ERC know via \\[erc-bug]. +Otherwise, expect it to disappear in subsequent versions.") + (cl-defmethod erc--register-connection (&context (erc-sasl-mode (eql t))) - "Send speculative/pipelined CAP and AUTHENTICATE and hope for the best." + "Send speculative CAP and pipelined AUTHENTICATE and hope for the best." (if-let* ((c (erc-sasl--state-client erc-sasl--state)) (m (sasl-mechanism-name (sasl-client-mechanism c)))) (progn - (erc-server-send "CAP REQ :sasl") - (if (and erc-session-password - (eq :password (alist-get 'password erc-sasl--options))) - (let (erc-session-password) - (erc-login)) + (erc-server-send (if erc-sasl--send-cap-ls "CAP LS" "CAP REQ :sasl")) + (let ((erc-session-password + (and erc-session-password + (not (eq :password (alist-get 'password erc-sasl--options))) + erc-session-password)) + (erc-session-username + ;; The username may contain a colon or a space + (if (eq :user (alist-get 'user erc-sasl--options)) + (erc-current-nick) + erc-session-username))) (erc-login)) + (when erc-sasl--send-cap-ls + (erc-server-send "CAP REQ :sasl")) (erc-server-send (format "AUTHENTICATE %s" m))) (erc-sasl--destroy erc-server-process))) diff --git a/test/lisp/erc/resources/base/local-modules/fourth.eld b/test/lisp/erc/resources/base/local-modules/fourth.eld index fd6d62b6cc2..4ac5dcbd38b 100644 --- a/test/lisp/erc/resources/base/local-modules/fourth.eld +++ b/test/lisp/erc/resources/base/local-modules/fourth.eld @@ -1,7 +1,7 @@ ;; -*- mode: lisp-data; -*- ((cap 10 "CAP REQ :sasl")) ((nick 10 "NICK tester`")) -((user 10 "USER tester 0 * :tester")) +((user 10 "USER tester` 0 * :tester")) ((authenticate 10 "AUTHENTICATE PLAIN") (0.0 ":irc.foonet.org CAP * ACK sasl") commit f0c908887815a9cc668a5a03cbc1b7d6eaf8c91d Author: F. Jason Park Date: Mon Dec 12 23:58:03 2022 -0800 Set erc-network to a "given" ID instead of failing * lisp/erc/erc-networks.el (erc-networks--determine): Return the so-called "given" ID from a non-nil `:id' keyword arg passed to `erc' or `erc-tls'. (erc-networks--allow-unknown-network): Add internal variable to allow IRC session to continue despite the network being unknown. (erc-networks--set-name): Tell the user about falling back to a given ID when the network can't be determined. When that's so, end the session by destroying the connection unless `erc-networks--allow-unknown-network' is enabled. (Bug#59976.) (erc-networks--ensure-announced): Include the fallback announced server name in the error message. * test/lisp/erc/erc-networks-tests.el (erc-networks--set-name): Add dummy server process and don't expect an error to be signaled. * test/lisp/erc/erc-scenarios-misc.el (erc-scenarios-networks-announced-missing): Don't expect an error to be signaled. * test/lisp/erc/resources/networks/announced-missing/foonet.eld: Remove "mode" match pattern. diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 19a7ab86437..fd8bed470ad 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -60,6 +60,7 @@ erc-session-server (declare-function erc-buffer-filter "erc" (predicate &optional proc)) (declare-function erc-current-nick "erc" nil) (declare-function erc-display-error-notice "erc" (parsed string)) +(declare-function erc-display-message "erc" (parsed type buffer msg &rest args)) (declare-function erc-error "erc" (&rest args)) (declare-function erc-get-buffer "erc" (target &optional proc)) (declare-function erc-server-buffer "erc" nil) @@ -1260,24 +1261,45 @@ erc-networks--determine return name) (and-let* ((vanity (erc--get-isupport-entry 'NETWORK 'single)) ((intern vanity)))) + (erc-networks--id-given erc-networks--id) erc-networks--name-missing-sentinel)) -(defun erc-networks--set-name (_proc parsed) +(defvar erc-networks--allow-unknown-network nil + "Whether to ignore a failure in identifying the network. +If you need this as a user option, please say so via \\[erc-bug]. +Otherwise, expect it to vanish at any time.") ; Bug#59976 + +(defun erc-networks--set-name (proc parsed) "Set `erc-network' to the value returned by `erc-networks--determine'. -Signal an error when the network cannot be determined." +Print an error message when the network cannot be determined before +shutting down the connection." ;; Always update (possibly clobber) current value, if any. - (let ((name (erc-networks--determine))) - (when (eq name erc-networks--name-missing-sentinel) - ;; This can happen theoretically, e.g., if you're editing some - ;; settings interactively on a proxy service that impersonates IRC - ;; but aren't being proxied through to a real network. The + (pcase (setq erc-network (erc-networks--determine)) + ((and (pred (eq (erc-networks--id-given erc-networks--id))) + (let m (format "Couldn't determine network. Using given ID `%s'." + erc-network))) + (erc-display-message parsed 'notice nil m) + nil) + ((and + (guard (eq erc-network erc-networks--name-missing-sentinel)) + ;; This can happen theoretically, e.g., when adjusting settings + ;; on a proxy service that partially impersonates IRC but isn't + ;; currently conveying anything through to a real network. The ;; service may send a 422 but no NETWORK param (or *any* 005s). - (let ((m (concat "Failed to determine network. Please set entry for " - erc-server-announced-name " in `erc-networks-alist'."))) - (erc-display-error-notice parsed m) - (erc-error "Failed to determine network"))) ; beep - (setq erc-network name)) - nil) + (let m (concat "Failed to determine network. Please set entry for \"" + erc-server-announced-name "\" in `erc-networks-alist'" + " or consider calling `erc-tls' with the keyword `:id'." + " See Info:\"(erc) Network Identifier\" for more."))) + (require 'info) + (erc-display-error-notice parsed m) + (if erc-networks--allow-unknown-network + (progn + (erc-display-error-notice + parsed (format "Continuing anyway with network set to `%s'." + erc-network)) + nil) + (delete-process proc) + 'error)))) ;; This lives here in this file because all the other "on connect" ;; MOTD stuff ended up here (but perhaps that needs to change). @@ -1287,11 +1309,12 @@ erc-networks--ensure-announced Copy source (prefix) from MOTD-ish message as a last resort." ;; The 004 handler never ran; see 2004-03-10 Diane Murray in change log (unless erc-server-announced-name - (erc-display-error-notice parsed "Failed to determine server name.") + (setq erc-server-announced-name (erc-response.sender parsed)) (erc-display-error-notice - parsed (concat "If this was unexpected, consider reporting it via " - (substitute-command-keys "\\[erc-bug]") ".")) - (setq erc-server-announced-name (erc-response.sender parsed))) + parsed (concat "Failed to determine server name. Using \"" + erc-server-announced-name "\" instead." + " If this was unexpected, consider reporting it via " + (substitute-command-keys "\\[erc-bug]") "."))) nil) (defun erc-unset-network-name (_nick _ip _reason) diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networks-tests.el index fc12bf7ce37..e883174e28a 100644 --- a/test/lisp/erc/erc-networks-tests.el +++ b/test/lisp/erc/erc-networks-tests.el @@ -1171,6 +1171,8 @@ erc-networks--set-name (let (erc-server-announced-name (erc--isupport-params (make-hash-table)) erc-network + erc-quit-hook + (erc-server-process (erc-networks-tests--create-live-proc)) calls) (erc-mode) @@ -1183,10 +1185,7 @@ erc-networks--set-name (ert-info ("Signals when table empty and NETWORK param unset") (setq erc-server-announced-name "irc.fake.gnu.org") - (let ((err (should-error (erc-networks--set-name - nil (make-erc-response))))) - (should (string-match-p "failed" (cadr err))) - (should (eq (car err) 'error))) + (should (eq 'error (erc-networks--set-name nil (make-erc-response)))) (should (string-match-p (rx "*** Failed") (car (pop calls))))))) (erc-networks-tests--clean-bufs))) diff --git a/test/lisp/erc/erc-scenarios-misc.el b/test/lisp/erc/erc-scenarios-misc.el index 3fa05ee8a60..f1696088a48 100644 --- a/test/lisp/erc/erc-scenarios-misc.el +++ b/test/lisp/erc/erc-scenarios-misc.el @@ -98,11 +98,10 @@ erc-scenarios-networks-announced-missing :nick "tester" :full-name "tester") (should (string= (buffer-name) (format "127.0.0.1:%d" port))) - (let ((err (should-error (sleep-for 1)))) - (should (string-match-p "Failed to determine" (cadr err)))) (funcall expect 1 "Failed to determine") (funcall expect 1 "Failed to determine") - (should-not erc-network) + (funcall expect 1 "Connection failed") + (should (string-prefix-p "Unknown" (erc-network-name))) (should (string= erc-server-announced-name "irc.foonet.org")))))) ;; Targets that are host/server masks like $*, $$*, and #* are routed diff --git a/test/lisp/erc/resources/networks/announced-missing/foonet.eld b/test/lisp/erc/resources/networks/announced-missing/foonet.eld index 79b0fb462a8..4481f27663d 100644 --- a/test/lisp/erc/resources/networks/announced-missing/foonet.eld +++ b/test/lisp/erc/resources/networks/announced-missing/foonet.eld @@ -3,6 +3,3 @@ ((user 1 "USER user 0 * :tester") (0 ":irc.foonet.org 001 tester :Welcome to the FooNet Internet Relay Chat Network tester") (0 ":irc.foonet.org 422 tester :MOTD File is missing")) - -((mode-user 1.2 "MODE tester +i") - (0 ":tester MODE tester :+Zi")) commit 09c0c6b2ba36c6b87e8e495710a580e909bbaf26 Author: F. Jason Park Date: Sun Dec 11 19:41:43 2022 -0800 Limit casemapping to appropriate ranges in ERC * lisp/erc/erc-common.el (erc-downcase): Use case table for `erc-downcase' so that case conversions are limited to the ASCII interval. * lisp/erc/erc.el (erc-casemapping--rfc1459-strict, erc--casemapping-rfc1459): Make these case tables instead of translation tables. The functions in case-table.el modify the standard syntax table, but that doesn't seem to make sense here, right? * test/lisp/erc/erc-tests.el (erc-downcase): Add cases showing mappings outside of the ASCII range. (Bug#59976.) diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el index a4046ba9b39..e662c06daa4 100644 --- a/lisp/erc/erc-common.el +++ b/lisp/erc/erc-common.el @@ -301,17 +301,11 @@ erc-log (defun erc-downcase (string) "Return a downcased copy of STRING with properties. Use the CASEMAPPING ISUPPORT parameter to determine the style." - (let* ((mapping (erc--get-isupport-entry 'CASEMAPPING 'single)) - (inhibit-read-only t)) - (if (equal mapping "ascii") - (downcase string) - (with-temp-buffer - (insert string) - (translate-region (point-min) (point-max) - (if (equal mapping "rfc1459-strict") - erc--casemapping-rfc1459-strict - erc--casemapping-rfc1459)) - (buffer-string))))) + (with-case-table (pcase (erc--get-isupport-entry 'CASEMAPPING 'single) + ("ascii" ascii-case-table) + ("rfc1459-strict" erc--casemapping-rfc1459-strict) + (_ erc--casemapping-rfc1459)) + (downcase string))) (define-inline erc-get-channel-user (nick) "Find NICK in the current buffer's `erc-channel-users' hash table." diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 9d811617d2e..5e78096da56 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -407,15 +407,27 @@ erc-server-users "Hash table of users on the current server. It associates nicknames with `erc-server-user' struct instances.") -(defconst erc--casemapping-rfc1459 - (make-translation-table - '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|) (?~ . ?^)) - (mapcar (lambda (c) (cons c (+ c 32))) "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))) - (defconst erc--casemapping-rfc1459-strict - (make-translation-table - '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|)) - (mapcar (lambda (c) (cons c (+ c 32))) "ABCDEFGHIJKLMNOPQRSTUVWXYZ"))) + (let ((tbl (copy-sequence ascii-case-table)) + (cup (copy-sequence (char-table-extra-slot ascii-case-table 0)))) + (set-char-table-extra-slot tbl 0 cup) + (set-char-table-extra-slot tbl 1 nil) + (set-char-table-extra-slot tbl 2 nil) + (pcase-dolist (`(,uc . ,lc) '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|))) + (aset tbl uc lc) + (aset tbl lc lc) + (aset cup uc uc)) + tbl)) + +(defconst erc--casemapping-rfc1459 + (let ((tbl (copy-sequence erc--casemapping-rfc1459-strict)) + (cup (copy-sequence (char-table-extra-slot + erc--casemapping-rfc1459-strict 0)))) + (set-char-table-extra-slot tbl 0 cup) + (aset tbl ?~ ?^) + (aset tbl ?^ ?^) + (aset cup ?~ ?~) + tbl)) (defun erc-add-server-user (nick user) "This function is for internal use only. diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 4d0d69cd7b6..51c562f5255 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -428,18 +428,21 @@ erc-downcase (ert-info ("ascii") (puthash 'CASEMAPPING '("ascii") erc--isupport-params) + (should (equal (erc-downcase "ABC 123 ΔΞΩΣ") "abc 123 ΔΞΩΣ")) (should (equal (erc-downcase "Bob[m]`") "bob[m]`")) (should (equal (erc-downcase "Tilde~") "tilde~" )) (should (equal (erc-downcase "\\O/") "\\o/" ))) (ert-info ("rfc1459") (puthash 'CASEMAPPING '("rfc1459") erc--isupport-params) + (should (equal (erc-downcase "ABC 123 ΔΞΩΣ") "abc 123 ΔΞΩΣ")) (should (equal (erc-downcase "Bob[m]`") "bob{m}`" )) (should (equal (erc-downcase "Tilde~") "tilde^" )) (should (equal (erc-downcase "\\O/") "|o/" ))) (ert-info ("rfc1459-strict") (puthash 'CASEMAPPING '("rfc1459-strict") erc--isupport-params) + (should (equal (erc-downcase "ABC 123 ΔΞΩΣ") "abc 123 ΔΞΩΣ")) (should (equal (erc-downcase "Bob[m]`") "bob{m}`")) (should (equal (erc-downcase "Tilde~") "tilde~" )) (should (equal (erc-downcase "\\O/") "|o/" ))))) commit 44b04c0ac1caef2283076d0784e0407940c14287 Author: F. Jason Park Date: Sun Dec 11 19:41:43 2022 -0800 Actually accept non-symbols as IDs in erc-open * lisp/erc/erc.el (erc-generate-new-buffer-name): Despite what it says in the documentation, only symbols were being accepted as valid `:id' entry-point arguments. This uses the interned `princ' representation of the argument instead. * test/lisp/erc/erc-scenarios-base-netid-samenet.el (erc-scenarios-common--base-network-id-same-network): Randomly specify a string for the ID param instead of a non-nil symbol when opening a new connection. * test/lisp/erc/resources/erc-scenarios-common.el (erc-scenarios-common-assert-initial-buf-name): Adjust helper to allow for non-symbol IDs. (Bug#59976.) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 7e7e142b854..9d811617d2e 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1607,11 +1607,12 @@ erc-generate-new-buffer-name (if (and (with-suppressed-warnings ((obsolete erc-reuse-buffers)) erc-reuse-buffers) id) - (progn - (when-let* ((buf (get-buffer (symbol-name id))) + (let ((string (symbol-name (erc-networks--id-symbol + (erc-networks--id-create id))))) + (when-let* ((buf (get-buffer string)) ((erc-server-process-alive buf))) - (user-error "Session with ID %S already exists" id)) - (symbol-name id)) + (user-error "Session with ID %S already exists" string)) + string) (generate-new-buffer-name (if (and server port) (if (with-suppressed-warnings ((obsolete erc-reuse-buffers)) diff --git a/test/lisp/erc/erc-scenarios-base-netid-samenet.el b/test/lisp/erc/erc-scenarios-base-netid-samenet.el index 3cd8b7dfa14..14367122510 100644 --- a/test/lisp/erc/erc-scenarios-base-netid-samenet.el +++ b/test/lisp/erc/erc-scenarios-base-netid-samenet.el @@ -40,6 +40,9 @@ erc-scenarios-common--base-network-id-same-network (erc-server-flood-margin 30) erc-serv-buf-a erc-serv-buf-b) + (when (and id-a (zerop (random 2))) (setq id-a (symbol-name id-a))) + (when (and id-b (zerop (random 2))) (setq id-b (symbol-name id-b))) + (ert-info ("Connect to foonet with nick tester") (with-current-buffer (setq erc-serv-buf-a (erc :server "127.0.0.1" diff --git a/test/lisp/erc/resources/erc-scenarios-common.el b/test/lisp/erc/resources/erc-scenarios-common.el index d77b32984b7..57d4658e75a 100644 --- a/test/lisp/erc/resources/erc-scenarios-common.el +++ b/test/lisp/erc/resources/erc-scenarios-common.el @@ -185,7 +185,7 @@ erc-scenarios-common-with-cleanup (defun erc-scenarios-common-assert-initial-buf-name (id port) ;; Assert no limbo period when explicit ID given (should (string= (if id - (symbol-name id) + (format "%s" id) (format "127.0.0.1:%d" port)) (buffer-name)))) commit 75f26646d4a569cfb485de4baddcda66ff44b2c3 Author: F. Jason Park Date: Sun Dec 11 19:16:07 2022 -0800 ; Be nicer when updating browse-url var in erc-compat * lisp/erc/erc-compat.el: Be more cautious about modifying `browse-url-default-handlers' when loading erc-compat on Emacs 28. A user may have already added an entry for irc:// URLs before loading `erc-compat'. diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el index bd932547586..77625398abd 100644 --- a/lisp/erc/erc-compat.el +++ b/lisp/erc/erc-compat.el @@ -391,8 +391,11 @@ erc-compat--29-browse-url-irc (cond ((fboundp 'browse-url-irc)) ; 29 ((boundp 'browse-url-default-handlers) ; 28 - (cl-pushnew '("\\`irc6?s?://" . erc-compat--29-browse-url-irc) - browse-url-default-handlers)) + (setf (alist-get "\\`irc6?s?://" browse-url-default-handlers + nil nil (lambda (a _) + (and (stringp a) + (string-match-p a "irc://localhost")))) + #'erc-compat--29-browse-url-irc)) ((boundp 'browse-url-browser-function) ; 27 (require 'browse-url) (let ((existing browse-url-browser-function)) commit 0155fc67be393239e5a2956d5dfaf6a0f74b517e Author: F. Jason Park Date: Fri Dec 2 23:11:24 2022 -0800 Respect a nil erc-session-password when reconnecting * lisp/erc/erc.el (erc-open): Simplify `old-vars' expression. (erc--compute-server-password): Only compute a server password when first connecting. For compatibility, this respects third-party code that expects session passwords in target buffers when initially non-nil. * test/lisp/erc/erc-scenarios-services-misc.el (erc-scenarios-services-auth-source-reconnect): Add new test. * test/lisp/erc/resources/services/auth-source/recon.eld: Add new test data file. (Bug#59858.) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 3b0cde41558..7e7e142b854 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1970,7 +1970,7 @@ erc-open (let* ((target (and channel (erc--target-from-string channel))) (buffer (erc-get-buffer-create server port nil target id)) (old-buffer (current-buffer)) - (old-vars (and (not connect) (buffer-local-variables))) + (old-vars (and target (buffer-local-variables))) (old-recon-count erc-server-reconnect-count) (old-point nil) (delayed-modules nil) @@ -6451,6 +6451,8 @@ erc--compute-server-password When `erc-auth-source-server-function' is non-nil, call it with NICK for the user field and use whatever it returns as the server password." (or password (and erc-auth-source-server-function + (not erc--server-reconnecting) + (not erc--target) (funcall erc-auth-source-server-function :user nick)))) (defun erc-compute-full-name (&optional full-name) diff --git a/test/lisp/erc/erc-scenarios-services-misc.el b/test/lisp/erc/erc-scenarios-services-misc.el index 680750d2d71..44e04e51509 100644 --- a/test/lisp/erc/erc-scenarios-services-misc.el +++ b/test/lisp/erc/erc-scenarios-services-misc.el @@ -84,4 +84,63 @@ erc-scenarios-services-prompt (should-not (memq 'services erc-modules)))) +;; A user with `services' enabled connects, quits, and reconnects. An +;; entry in their netrc matches the network ID, which isn't known when +;; `erc-auth-source-server-function' runs -- initially *or* on +;; reconnect. It's only seen by `erc-auth-source-services-function'. + +(ert-deftest erc-scenarios-services-auth-source-reconnect () + :tags '(:expensive-test) + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "services/auth-source") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'recon 'recon)) + (port (process-contact dumb-server :service)) + (netrc-file (make-temp-file + "auth-source-test" nil nil + "machine FooNet login tester password changeme\n")) + (auth-sources (list netrc-file)) + (auth-source-do-cache nil) + (erc-modules (cons 'services erc-modules)) + (erc-use-auth-source-for-nickserv-password t) ; do consult + (erc-prompt-for-nickserv-password nil) ; don't prompt + (erc-nickserv-alist + (cons '(FooNet + "NickServ!NickServ@services.int" + "This nickname is registered. Please choose" + "NickServ" "IDENTIFY" nil nil "You are now identified for ") + erc-nickserv-alist)) + (expect (erc-d-t-make-expecter)) + (erc-scenarios-common-extra-teardown (lambda () + (delete-file netrc-file)))) + + (ert-info ("Server password omitted from initial connection") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :user "tester" + :full-name "tester") + (should (string= (buffer-name) (format "127.0.0.1:%d" port))) + (ert-info ("Services module authenticates") + (funcall expect 10 "This nickname is registered.") + (funcall expect 3 "You are now identified")) + (erc-cmd-JOIN "#chan") + (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan")) + (funcall expect 10 "the gallants desire it")) + (erc-cmd-QUIT "") + (funcall expect 3 "finished"))) + + (ert-info ("Server password withheld on reconnect") + (with-current-buffer "#chan" + (erc-cmd-RECONNECT)) + (with-current-buffer "FooNet" + (funcall expect 10 "This nickname is registered.") + (funcall expect 3 "You are now identified") + (with-current-buffer "#chan" ; autojoined + (funcall expect 10 "the gallants desire it")) + (erc-cmd-QUIT "") + (funcall expect 3 "finished"))) + + (erc-services-mode -1))) + ;;; erc-scenarios-services-misc.el ends here diff --git a/test/lisp/erc/resources/services/auth-source/recon.eld b/test/lisp/erc/resources/services/auth-source/recon.eld new file mode 100644 index 00000000000..40ea3c9157d --- /dev/null +++ b/test/lisp/erc/resources/services/auth-source/recon.eld @@ -0,0 +1,48 @@ +;; -*- mode: lisp-data; -*- +((nick 10 "NICK tester")) +((user 5 "USER tester 0 * :tester") + (0.00 ":irc.foonet.net NOTICE * :*** Looking up your hostname...") + (0.04 ":irc.foonet.net NOTICE tester :*** Could not resolve your hostname: Domain not found; using your IP address (10.0.2.100) instead.") + (0.06 ":irc.foonet.net 001 tester :Welcome to the FooNet IRC Network tester!tester@10.0.2.100") + (0.01 ":irc.foonet.net 002 tester :Your host is irc.foonet.net, running version InspIRCd-3") + (0.01 ":irc.foonet.net 003 tester :This server was created 08:32:24 Dec 05 2022") + (0.01 ":irc.foonet.net 004 tester irc.foonet.net InspIRCd-3 BIRcgikorsw ACHIKMORTXabcefghijklmnopqrstvz :HIXabefghjkloqv") + (0.01 ":irc.foonet.net 005 tester ACCEPT=30 AWAYLEN=200 BOT=B CALLERID=g CASEMAPPING=ascii CHANLIMIT=#:20 CHANMODES=IXbeg,k,Hfjl,ACKMORTcimnprstz CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU ESILENCE=CcdiNnPpTtx EXCEPTS=e :are supported by this server") + (0.01 ":irc.foonet.net 005 tester EXTBAN=,ACORTUacjrwz HOSTLEN=64 INVEX=I KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=I:100,X:100,b:100,e:100,g:100 MAXTARGETS=20 MODES=20 MONITOR=30 NAMELEN=128 NAMESX NETWORK=FooNet :are supported by this server") + (0.01 ":irc.foonet.net 005 tester NICKLEN=30 PREFIX=(qaohv)~&@%+ SAFELIST SILENCE=32 STATUSMSG=~&@%+ TOPICLEN=307 UHNAMES USERIP USERLEN=10 USERMODES=,,s,BIRcgikorw WHOX :are supported by this server") + (0.01 ":irc.foonet.net 251 tester :There are 2 users and 0 invisible on 2 servers") + (0.00 ":irc.foonet.net 253 tester 1 :unknown connections") + (0.00 ":irc.foonet.net 254 tester 1 :channels formed") + (0.00 ":irc.foonet.net 255 tester :I have 2 clients and 1 servers") + (0.00 ":irc.foonet.net 265 tester :Current local users: 2 Max: 3") + (0.00 ":irc.foonet.net 266 tester :Current global users: 2 Max: 3") + (0.00 ":irc.foonet.net 375 tester :irc.foonet.net message of the day") + (0.00 ":irc.foonet.net 372 tester :Have fun!") + (0.00 ":irc.foonet.net 376 tester :End of message of the day.")) + +((mode-a 10 "MODE tester +i") + (0.00 ":irc.foonet.net 501 tester x :is not a recognised user mode.") + (0.04 ":tester!tester@10.0.2.100 MODE tester :+i") + (0.00 ":NickServ!NickServ@services.int NOTICE tester :This nickname is registered. Please choose a different nickname, or identify via \2/msg NickServ identify \2.")) + +((~privmsg 10 "PRIVMSG NickServ :IDENTIFY changeme") + (0.00 ":NickServ!NickServ@services.int NOTICE tester :You are now identified for \2tester\2.") + (0.01 ":irc.foonet.net 900 tester tester!tester@10.0.2.100 tester :You are now logged in as tester")) + +((~join 10 "JOIN #chan") + (0.00 ":tester!tester@10.0.2.100 JOIN :#chan") + (0.04 ":irc.foonet.net 353 tester = #chan :@alice bob tester") + (0.00 ":irc.foonet.net 366 tester #chan :End of /NAMES list.")) + +((mode-b 10 "MODE #chan") + (0.03 ":irc.foonet.net 324 tester #chan :+nt") + (0.01 ":irc.foonet.net 329 tester #chan :1670229160") + (0.00 ":alice!alice@0::1 PRIVMSG #chan :tester, welcome!") + (0.00 ":bob!bob@0::1 PRIVMSG #chan :tester, welcome!") + (0.05 ":alice!alice@0::1 PRIVMSG #chan :bob: Thou art the cap of all the fools alive.") + (0.06 ":bob!bob@0::1 PRIVMSG #chan :alice: What, man! 'tis a night of revels; the gallants desire it.")) + +((quit 10 "QUIT :\2ERC\2") + (0.1 ":tester!tester@10.0.2.100 QUIT :Client Quit")) + +((drop 1 DROP)) commit 9ac80e8a6e4969cfe88d5233dc4152bbfa46c848 Author: F. Jason Park Date: Wed Nov 30 23:10:58 2022 -0800 Add dedicated auth-source section in ERC manual * doc/misc/erc.texi: Move auth-source description from the Password subheading of the Advanced chapter's Connecting section to the new Integrations section as a new node, Auth-Source, and give it a bit more structure. Fix various misuses of xref vs. pxref. Convert URL subheading to subsection and add anchor. Prefer "backend" as a single word, based on usage in other manuals. Also replace loud "warning" in SASL troubleshooting section. * etc/ERC-NEWS: Re-link auth-source mention. * lisp/erc/erc-sasl.el (erc-sasl-auth-source-function): Update info node in doc string. * lisp/erc/erc-services.el (erc-auth-source-services-function): Re-link auth-source info node in doc string. * lisp/erc/erc.el (erc-password, erc-auth-source-server-function, erc-auth-source-join-function): Re-link auth-source info node in doc strings. diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 5ad739a77e1..2ab2e908940 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -570,10 +570,20 @@ Advanced Usage @menu * Connecting:: Ways of connecting to an IRC server. -* SASL:: Authenticating via SASL +* SASL:: Authenticating via SASL. * Sample Configuration:: An example configuration file. * Integrations:: Integrations available for ERC. * Options:: Options that are available for ERC. + +@detailmenu +--- Detailed Node Listing --- + +Integrations + +* URL:: Opening IRC URLs in ERC. +* auth-source:: Retrieving auth-source entries with ERC. + +@end detailmenu @end menu @node Connecting @@ -643,7 +653,7 @@ Connecting parameters, and some, like @code{client-certificate}, will just be @code{nil}. -@anchor{ERC client-certificate} +@anchor{client-certificate} To use a certificate with @code{erc-tls}, specify the optional @var{client-certificate} keyword argument, whose value should be as described in the documentation of @code{open-network-stream}: if @@ -687,6 +697,8 @@ Connecting @xref{Help for users,,,auth, Emacs auth-source Library}, for more on the @file{.authinfo}/@file{.netrc} backend of @code{auth-source}. +For other uses of auth-source throughout ERC, @pxref{auth-source, +ERC's auth-source integration}. @end defun @subheading Server @@ -778,9 +790,9 @@ Connecting You can manually set another nickname with the /NICK command. @end defopt -@anchor{ERC username} +@anchor{username parameter} @subheading User -@cindex user +@cindex username parameter @defun erc-compute-user &optional user Determine a suitable value to send as the first argument of the @@ -803,8 +815,27 @@ Connecting a string abiding by the rules of the network. @end defopt +@anchor{password parameter} +@anchor{server password} +@cindex password, server @subheading Password -@cindex password + +This parameter was traditionally meant to specify a @dfn{server +password} to be sent along with the IRC @samp{PASS} command. However, +such passwords aren't widely used. Instead, networks typically expect +them, when present, to convey other authentication information. In +the case of account-services (a.k.a., ``NickServ'') credentials, this +typically involves a special syntax, such as @samp{myuser:mypass}. +IRC bouncers often do something similar but include a pre-configured +network-ID component, for example, @samp{bncuser/mynet:bncpass}. + +In general, if you have @emph{not} been asked by your network or +bouncer to specify a repurposed server password, you should instead +consider setting up @samp{services} or, preferably, @samp{sasl}, both +ERC modules (@pxref{Modules}). In addition to performing +network-account authentication, these obviate the need for this +parameter completely, although both can optionally borrow it for their +own purposes. (@xref{SASL, SASL in ERC}.) @defopt erc-prompt-for-password If non-@code{nil} (the default), @kbd{M-x erc} and @kbd{M-x erc-tls} @@ -814,109 +845,9 @@ Connecting @noindent If you prefer, you can set this option to @code{nil} and use the -@code{auth-source} mechanism to store your password. For instance, if -the option @code{auth-sources} contains @file{~/.authinfo}, put -something like the following in that file: - -@example -machine irc.example.net login mynick password sEcReT -@end example - -@noindent -For server passwords, that is, passwords sent for the IRC @samp{PASS} -command, the @samp{host} field (@w{@code{machine irc.example.net}} in -the above example) -corresponds to the @var{server} parameter used by @code{erc} and -@code{erc-tls}. Unfortunately, specifying a network, like -@samp{Libera.Chat}, or a specific network server, like -@samp{platinum.libera.chat}, won't normally work for looking up a server -password because such information isn't available during opening -introductions. (Actually, ERC @emph{can} find entries with arbitrary -@samp{host} values for any context, including server passwords, but -that requires customizing the more advanced options below.) - -If ERC can't find a suitable server password, it will just skip the IRC -@samp{PASS} command altogether, something users may want when using -CertFP or engaging NickServ via ERC's ``services'' module. If that is -what you'd like to do, you can also customize the option -@code{erc-auth-source-server-function} to @code{nil} to skip -server-password lookup for all servers. Note that some networks and -IRCds may accept account-services authentication via server password -using the nonstandard @samp{mynick:sEcReT} convention. - -As just mentioned, you can also use @code{auth-source} to authenticate -to account services the traditional way, through a bot called -@samp{NickServ}. To tell ERC to do that, set -@code{erc-use-auth-source-for-nickserv-password} to @code{t}. For -these and most other queries, entries featuring custom identifiers and -networks are matched first, followed by network-specific servers and -dialed endpoints (typically, the @var{server} argument passed to -@code{erc}). The following netrc-style entries appear in order of -precedence: - -@example -machine Libera/cellphone login MyNick password sEcReT -machine Libera.Chat login MyNick password sEcReT -machine zirconium.libera.chat login MyNick password sEcReT -machine irc.libera.chat login MyNick password sEcReT -@end example - -@noindent -Remember that field labels vary per backend, so @samp{machine} (in -netrc's case) maps to auth-source's generalized notion of a host, -hence the @samp{:host} keyword property. Also, be sure to mind the -syntax of your chosen backend medium. For example, always quote -channel names in a netrc file. - -If this all seems overly nuanced or just plain doesn't appeal to you, -see options @code{erc-auth-source-services-function} and friends, described -below. These let you query auth-source your way. Most users can -simply ignore the passed-in arguments and get by with something like -the following: - -@lisp -(defun my-fancy-auth-source-func (&rest _) - (let* ((host (read-string "host: " nil nil "default")) - (pass (auth-source-pick-first-password :host host))) - (if (and pass (string-search "libera" host)) - (concat "MyNick:" pass) - pass))) -@end lisp - -Lastly, ERC also consults @code{auth-source} to find ``keys'' that may -be required by certain channels you join. When modifying a -traditional @code{auth-source} entry for this purpose, put the channel -name in the @samp{user} field (for example, @samp{login "#fsf"}, in -netrc's case). The actual key goes in the @samp{password} (or -@samp{secret}) field. - -@noindent -For details, @pxref{Top,,auth-source, auth, Emacs auth-source Library}. - -@anchor{ERC auth-source functions} -@defopt erc-auth-source-server-function -@end defopt -@defopt erc-auth-source-services-function -@end defopt -@defopt erc-auth-source-join-function - -ERC calls these functions with keyword arguments recognized by -@code{auth-source-search}, namely, those deemed most relevant to the -current context, if any. For example, with NickServ queries, -@code{:user} is the ``desired'' nickname rather than the current one. -Generalized names, like @code{:user} and @code{:host}, are always used -over back-end specific ones, like @code{:login} or @code{:machine}. -ERC expects a string to use as the secret or @code{nil}, if the search -fails. - -@findex erc-auth-source-search -The default value for all three options is the function -@code{erc-auth-source-search}. It tries to merge relevant contextual -parameters with those provided or discovered from the logical connection -or the underlying transport. Some auth-source back ends may not be -compatible; netrc, plstore, json, secrets, and pass are currently -supported. -@end defopt +auth-source facility to retrieve a server password, although hitting +@kbd{RET} at the prompt may achieve the same effect. +@xref{auth-source, ERC's auth-source integration}, for more. @subheading Full name @@ -946,8 +877,8 @@ Connecting @end defopt -@subheading ID @anchor{Network Identifier} +@subheading ID ERC uses an abstract designation, called @dfn{network context identifier}, for referring to a connection internally. While normally @@ -1002,7 +933,7 @@ SASL uppercase with colon seps (@samp{DE:AD:BE:EF}). These days, there's usually a @samp{CERT ADD} command offered by NickServ that can register you automatically if you issue it while connected with a -client cert. (@pxref{ERC client-certificate}). +client cert. @xref{client-certificate}. Additional considerations: @enumerate @@ -1038,30 +969,32 @@ SASL This should be your network account username, typically the same one registered with nickname services. Specify this when your NickServ login differs from the @code{:user} you're connecting with. -(@pxref{ERC username}) +@xref{username parameter}. @end defopt @defopt erc-sasl-password -As noted elsewhere, the @code{:password} parameter for @code{erc-tls} -was originally intended for traditional ``server passwords,'' but these -aren't really used any more. As such, this option defaults to -borrowing that parameter for its own uses, thus allowing you to call -@code{erc-tls} with @code{:password} set to your NickServ password. +As noted elsewhere, the entry-point @code{:password} param was +originally intended for traditional ``server passwords,'' but these +aren't really used any more (@pxref{password parameter}). As such, +this option defaults to borrowing that parameter for its own uses, +thus allowing you to call @code{erc-tls} with @code{:password} set to +your NickServ password. You can also set this to a nonemtpy string, and ERC will send that when needed, no questions asked. Or, if you'd rather use auth-source, set @code{erc-sasl-auth-source-function} to a function, and ERC will -perform an auth-source query instead. As last resort in all cases, -ERC will prompt you for input. +perform an auth-source query instead. In all cases, ERC will prompt +you for input as a last resort. Lastly, if your mechanism is @code{ecdsa-nist256p-challenge}, this option should instead hold the file name of your key. @end defopt +@anchor{SASL auth-source function} @defopt erc-sasl-auth-source-function This is nearly identical to the other ERC @samp{auth-source} function -options (@pxref{ERC auth-source functions}) except that the default -value here is @code{nil}, meaning you have to set it to something like +options (@pxref{auth-source functions}) except that the default value +here is @code{nil}, meaning you have to set it to something like @code{erc-auth-source-search} for queries to be performed. For convenience, this module provides the following as a possible value: @@ -1163,9 +1096,9 @@ SASL @subheading Troubleshooting -@strong{Warning:} ERC's SASL offering is currently limited by a lack -of support for proper IRCv3 capability negotiation. In most cases, -this shouldn't affect your ability to authenticate. +First and foremost, please know that ERC's SASL offering is currently +limited by a lack of support for proper IRCv3 capability negotiation. +In most cases, this shouldn't affect your ability to authenticate. If you're struggling, remember that your SASL password is almost always your NickServ password. When in doubt, try restoring all SASL @@ -1260,12 +1193,19 @@ Integrations @section Integrations @cindex integrations -@subheading URL +@menu +* auth-source:: Retrieving auth-source entries with ERC. +@end menu + +@anchor{URL} +@subsection URL +@cindex URL + For anything to work, you'll want to set @code{url-irc-function} to @code{url-irc-erc}. As a rule of thumb, libraries relying directly on @code{url-retrieve} should be fine out the box from Emacs 29.1 onward. On older versions of Emacs, you may need to @code{(require 'erc)} -beforehand. @pxref{Retrieving URLs,,, url, URL}. +beforehand. @xref{Retrieving URLs,,, url, URL}. For other apps and libraries, such as those relying on the higher-level @code{browse-url}, you'll oftentimes be asked to specify @@ -1282,6 +1222,160 @@ Integrations @noindent Users on Emacs 28 and below may need to use @code{browse-url} instead. +@node auth-source +@subsection auth-source +@cindex auth-source + +You can configure ERC to use the built-in auth-source library for +looking up passwords. @xref{Top,,auth-source, auth, Emacs auth-source +Library}, for general info on setting up various backends, but keep in +mind that some of these may not be compatible. Those currently +supported are netrc, plstore, json, secrets, and pass. To get started +with the default backend, netrc, put a line like the following in your +@file{~/.authinfo.gpg} (or any file named in the option +@code{auth-sources}): + +@example +machine irc.example.net login mynick password sEcReT +@end example + +@subsubheading Server Passwords +When retrieving passwords to accompany the IRC @samp{PASS} command +(@pxref{password parameter}), ERC asks auth-source to match the +@var{server} parameter of @code{erc-tls} against each entry's +@samp{host} field (@w{@code{machine irc.example.net}} in the above +example). Unfortunately, specifying a network, like +@samp{Libera.Chat}, or a specific network server, like +@samp{platinum.libera.chat}, won't normally work for looking up a +server password because that information isn't available during +opening introductions. (Actually, ERC @emph{can} find entries with +arbitrary @samp{host} values for any context, including server +passwords, but that requires customizing the more advanced options +below.) + +If ERC can't find a suitable server password, it will just skip the +IRC @samp{PASS} command altogether, something users may want when +using CertFP or engaging NickServ via ERC's @code{services} module. +If that appeals to you, consider customizing the option +@code{erc-auth-source-server-function} to @code{nil} to skip +server-password lookup for all servers. Note that some networks and +IRCds may accept account-services authentication via server password. +Also, some ERC modules may commandeer the @code{erc-tls} +@var{password} parameter for their own ends, which likely don't +involve a server password. + +@subsubheading The @samp{services} module +You can use auth-source to authenticate to account services the +traditional way through a bot called @samp{NickServ}. To do so, add +@code{services} to @code{erc-modules} and set the option +@code{erc-use-auth-source-for-nickserv-password} to @code{t}. After +that, expect the @samp{user} parameter in relevant auth-source queries +to be your current nickname. + +Most of the time, a query's precise contextual details (such as +whether a nick was granted or forcibly assigned) shouldn't affect how +you define entries in your backend. However, if something isn't quite +working, you may want to investigate the interplay between the option +@code{erc-nickserv-identify-mode} and account services. In +particular, if you find yourself facing nicks suffixed with an +@code{erc-nick-uniquifier} (the infamous @samp{`}), check that the +network's entry in @code{erc-nickserv-alist} is up to date, and do let +us know if something's off (@pxref{Getting Help and Reporting Bugs}). +Of course, if you've had your fill of fiddling with this module, +consider switching to SASL for what's likely a more consistent +auth-source experience. (@xref{SASL}.) + +@subsubheading Default query behavior +When preparing entries for your backend, it may help to get a feel for +how ERC and its modules conduct searches, especially when exploring a +new context, such as channel keys. (Hint: in such situations, try +temporarily setting the variable @code{auth-source-debug} to @code{t} +and checking @samp{*Messages*} periodically for insights into how +auth-source is operating.) Overall, though, ERC tries to be +consistent in performing queries across various authentication +contexts. Here's what to expect with respect to the @samp{host} +field, which, by default, most heavily influences the fate of a query: + +@enumerate +@item +entries featuring custom identifiers and networks are matched first +(@pxref{Network Identifier}) +@item +followed by network-specific servers +@item +and, finally, dialed endpoints (typically the @var{server} argument +passed to @code{erc-tls}) +@end enumerate + +@noindent +The following netrc-style entries appear in order of precedence: + +@example +machine Libera/cellphone login MyNick password sEcReT +machine Libera.Chat login MyNick password sEcReT +machine zirconium.libera.chat login MyNick password sEcReT +machine irc.libera.chat login MyNick password sEcReT +@end example + +@noindent +Remember that field labels vary per backend, so @samp{machine} (in +netrc's case) maps to auth-source's generalized notion of a host, +hence the @samp{:host} keyword parameter to @code{auth-source-search}. +Also, be sure to mind the syntax of your chosen backend medium. For +example, always quote channel names in a netrc file. + +Lastly, if this all seems overly nuanced or just plain doesn't appeal +to you, please see options @code{erc-auth-source-services-function} +and friends, described just below. + +@subsubheading Custom query functions +These let you query auth-source your way. Most users can +simply ignore the passed-in arguments and get by with something like +the following: + +@lisp +(defun my-fancy-auth-source-func (&rest _) + (let* ((host (read-string "host: " nil nil "default")) + (pass (auth-source-pick-first-password :host host))) + (if (and pass (string-search "libera" host)) + (concat "MyNick:" pass) + pass))) +@end lisp + +@anchor{auth-source functions} +@defopt erc-auth-source-server-function +@end defopt +@defopt erc-auth-source-services-function +@end defopt +@defopt erc-auth-source-join-function + +ERC calls these functions with keyword arguments recognized by +@code{auth-source-search}, namely, those deemed most relevant to the +current context, if any. For example, when identifying to services, +@code{:user} contains your current nickname. Generalized parameter +names, like @code{:user} and @code{:host}, are always preferred over +backend specific ones, like @code{:login} or @code{:machine}. In +return, ERC expects a string if the search succeeds or @code{nil} if +it fails. + +@findex erc-auth-source-search +The default value for all three options is the function +@code{erc-auth-source-search}. It tries to merge relevant contextual +parameters with those provided or discovered from the logical +connection or the underlying transport. + +For using auth-source along with SASL, @pxref{SASL auth-source +function}. +@end defopt + +@subsubheading Channel keys +ERC also consults @code{auth-source} to find ``keys'' that may be +required by certain channels you join. When modifying a traditional +@code{auth-source} entry for this purpose, put the channel name in the +@samp{user} field (for example, @samp{login "#fsf"}, in netrc's case). +The actual key goes in the @samp{password} (or @samp{secret}) field. + + @node Options @section Options @cindex options diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index d0d84d0a987..76439f1d068 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -45,8 +45,8 @@ With the overhaul of the services module temporarily shelved and the transition to SASL-based authentication still underway, users may feel left in the lurch to endure yet another release cycle of backtick hell. For some, auth-source may provide a workaround in the form of -nonstandard server passwords. See the "Connection" node in the manual -under the subheading "Password". +nonstandard server passwords. See the section titled "auth-source" in +the Integrations chapter of ERC's manual. ** Rudimentary SASL support has arrived. A new module, 'erc-sasl', now ships with ERC 5.5. See the SASL diff --git a/lisp/erc/erc-sasl.el b/lisp/erc/erc-sasl.el index 5b2c93988af..280910111d5 100644 --- a/lisp/erc/erc-sasl.el +++ b/lisp/erc/erc-sasl.el @@ -102,7 +102,7 @@ erc-sasl-auth-source-function `erc-sasl-password', to their values from entry-point invocation. In return, ERC expects a string to send as the SASL password, or nil, in which case, ERC will prompt the for input. See info -node `(erc) Connecting' for details on ERC's auth-source +node `(erc) auth-source' for details on ERC's auth-source integration." :type '(choice (function-item erc-sasl-auth-source-password-as-host) (function-item erc-auth-source-search) diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el index 48953288d17..c2d91ca9d65 100644 --- a/lisp/erc/erc-services.el +++ b/lisp/erc/erc-services.el @@ -180,7 +180,7 @@ erc-auth-source-services-function `auth-source-search' and relevant to authenticating to nickname services. In return, ERC expects a string to send as the password, or nil, to fall through to the next method, such as -prompting. See info node `(erc) Connecting' for details." +prompting. See info node `(erc) auth-source' for details." :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA :type '(choice (const erc-auth-source-search) (const nil) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 6bb2e013c3b..3b0cde41558 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -219,7 +219,7 @@ erc-password This variable only exists for legacy reasons. It's not customizable and is limited to a single server password. Users looking for similar functionality should consider auth-source instead. See info -node `(auth) Top' and info node `(erc) Connecting'.") +node `(auth) Top' and info node `(erc) auth-source'.") (make-obsolete-variable 'erc-password "use auth-source instead" "29.1") @@ -3208,7 +3208,7 @@ erc-auth-source-server-function password, or nil, to skip the \"PASS\" command completely. An explicit `:password' argument to entry-point commands `erc' and `erc-tls' also inhibits lookup, as does setting this option to -nil. See info node `(erc) Connecting' for details." +nil. See info node `(erc) auth-source' for details." :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA :group 'erc :type '(choice (const erc-auth-source-search) @@ -3223,7 +3223,7 @@ erc-auth-source-join-function \"key\", or nil to just join the channel normally. Setting the option itself to nil tells ERC to always forgo consulting auth-source for channel keys. For more information, see info -node `(erc) Connecting'." +node `(erc) auth-source'." :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA :group 'erc :type '(choice (const erc-auth-source-search) commit 2d96a18cd09be1c53b1242be1e0671cfc5b7fa8c Author: Mattias Engdegård Date: Wed Dec 14 14:06:46 2022 +0100 ; * lisp/emacs-lisp/shortdoc.el: fix mistakes in previous commit diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 034513005ec..6704db3cc57 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -627,7 +627,7 @@ list (nconc :eval (nconc (list 1) (list 2 3 4))) (delq - :eval (delq 'a (list a b c d))) + :eval (delq 'a (list 'a 'b 'c 'd))) (delete :eval (delete 2 (list 1 2 3 4)) :eval (delete "a" (list "a" "b" "c" "d"))) @@ -676,7 +676,7 @@ list :eval (member 2 '(1 2 3)) :eval (member "b" '("a" "b" "c"))) (remq - :eval (remq b '(a b c))) + :eval (remq 'b '(a b c))) (member-ignore-case :eval (member-ignore-case "foo" '("bar" "Foo" "zot"))) "Association Lists" @@ -733,9 +733,9 @@ symbol :eval (eq 'abc 'abc) :eval (eq 'abc 'abd)) (eql - :eval (eq 'abc 'abc)) + :eval (eql 'abc 'abc)) (equal - :eval (eq 'abc 'abc)) + :eval (equal 'abc 'abc)) "Name" (symbol-name :eval (symbol-name 'abc))) commit 1d3cbba7dfa26fc74df4d09d40a3cd7ba07279b4 Author: Mattias Engdegård Date: Wed Dec 14 12:25:49 2022 +0100 ; * lisp/progmodes/cmake-ts-mode.el (auto-mode-alist): $ -> \' diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el index 15934a290b7..fc25d2ba5fd 100644 --- a/lisp/progmodes/cmake-ts-mode.el +++ b/lisp/progmodes/cmake-ts-mode.el @@ -196,7 +196,7 @@ cmake-ts-mode--imenu-1 ;;;###autoload (add-to-list 'auto-mode-alist - '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)$" . cmake-ts-mode)) + '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode)) ;;;###autoload (define-derived-mode cmake-ts-mode prog-mode "CMake" commit 0cc199f1a61c91528eb899eab6ae51c626be6927 Author: Mattias Engdegård Date: Wed Dec 14 12:20:46 2022 +0100 Better shortdoc examples * lisp/emacs-lisp/shortdoc.el (symbol, comparison): New. (string, list, number): Remove or change examples that do not have well-defined results, such as `eq` on strings or floats. Edit other examples for better illustrating each respective operation. diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index c6925791d08..034513005ec 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -251,18 +251,17 @@ string :eval (string-glyph-decompose "Å")) "Predicates for Strings" (string-equal - :eval (string-equal "foo" "foo")) + :eval (string-equal "abc" "abc") + :eval (string-equal "abc" "ABC")) (string-equal-ignore-case :eval (string-equal-ignore-case "foo" "FOO")) - (eq - :eval (eq "foo" "foo")) - (eql - :eval (eql "foo" "foo")) (equal :eval (equal "foo" "foo")) (cl-equalp :eval (cl-equalp "Foo" "foo")) (stringp + :eval (stringp "a") + :eval (stringp 'a) :eval "(stringp ?a)") (string-empty-p :no-manual t @@ -271,16 +270,16 @@ string :no-manual t :eval (string-blank-p " \n")) (string-lessp - :eval (string-lessp "foo" "bar") + :eval (string-lessp "abc" "def") :eval (string-lessp "pic4.png" "pic32.png") - :eval (string-lessp "1.1" "1 2")) + :eval (string-lessp "1.1" "1.2")) (string-greaterp :eval (string-greaterp "foo" "bar")) (string-version-lessp :eval (string-version-lessp "pic4.png" "pic32.png") - :eval (string-version-lessp "1.1" "1 2")) + :eval (string-version-lessp "1.9.3" "1.10.2")) (string-collate-lessp - :eval (string-collate-lessp "1.1" "1 2")) + :eval (string-collate-lessp "abc" "abd")) (string-prefix-p :eval (string-prefix-p "foo" "foobar")) (string-suffix-p @@ -297,7 +296,8 @@ string "Converting Strings" (string-to-number :eval (string-to-number "42") - :eval (string-to-number "deadbeef" 16)) + :eval (string-to-number "deadbeef" 16) + :eval (string-to-number "2.5e+03")) (number-to-string :eval (number-to-string 42)) "Data About Strings" @@ -627,8 +627,7 @@ list (nconc :eval (nconc (list 1) (list 2 3 4))) (delq - :eval (delq 2 (list 1 2 3 4)) - :eval (delq "a" (list "a" "b" "c" "d"))) + :eval (delq 'a (list a b c d))) (delete :eval (delete 2 (list 1 2 3 4)) :eval (delete "a" (list "a" "b" "c" "d"))) @@ -670,29 +669,25 @@ list :eval (nlistp '(1 . 2))) "Finding Elements" (memq - :eval (memq 2 '(1 2 3)) - :eval (memq 2.0 '(1.0 2.0 3.0)) - :eval (memq "b" '("a" "b" "c"))) + :eval (memq 'b '(a b c))) + (memql + :eval (memql 2.0 '(1.0 2.0 3.0))) (member :eval (member 2 '(1 2 3)) :eval (member "b" '("a" "b" "c"))) (remq - :eval (remq 2 '(1 2 3 2 4 2)) - :eval (remq "b" '("a" "b" "c"))) - (memql - :eval (memql 2.0 '(1.0 2.0 3.0))) + :eval (remq b '(a b c))) (member-ignore-case :eval (member-ignore-case "foo" '("bar" "Foo" "zot"))) "Association Lists" (assoc - :eval (assoc 'b '((a 1) (b 2)))) + :eval (assoc "b" '(("a" . 1) ("b" . 2)))) (rassoc - :eval (rassoc '2 '((a . 1) (b . 2)))) + :eval (rassoc "b" '((1 . "a") (2 . "b")))) (assq - :eval (assq 'b '((a 1) (b 2))) - :eval (assq "a" '(("a" 1) ("b" 2)))) + :eval (assq 'b '((a . 1) (b . 2)))) (rassq - :eval (rassq '2 '((a . 1) (b . 2)))) + :eval (rassq 'b '((1 . a) (2 . b)))) (assoc-string :eval (assoc-string "foo" '(("a" 1) (foo 2)))) (alist-get @@ -725,6 +720,88 @@ list (safe-length :eval (safe-length '(a b c)))) +(define-short-documentation-group symbol + "Making symbols" + (intern + :eval (intern "abc")) + (intern-soft + :eval (intern-soft "Phooey!")) + (make-symbol + :eval (make-symbol "abc")) + "Comparing symbols" + (eq + :eval (eq 'abc 'abc) + :eval (eq 'abc 'abd)) + (eql + :eval (eq 'abc 'abc)) + (equal + :eval (eq 'abc 'abc)) + "Name" + (symbol-name + :eval (symbol-name 'abc))) + +(define-short-documentation-group comparison + "General-purpose" + (eq + :eval (eq 'a 'a) + :eval "(eq ?A ?A)" + :eval (let ((x (list 'a "b" '(c) 4 5.0))) + (eq x x))) + (eql + :eval (eql 2 2) + :eval (eql 2.0 2.0) + :eval (eql 2.0 2)) + (equal + :eval (equal "abc" "abc") + :eval (equal 2.0 2.0) + :eval (equal 2.0 2) + :eval (equal '(a "b" (c) 4.0) '(a "b" (c) 4.0))) + (cl-equalp + :eval (cl-equalp 2 2.0) + :eval (cl-equalp "ABC" "abc")) + "Numeric" + (= + :args (number &rest numbers) + :eval (= 2 2) + :eval (= 2.0 2.0) + :eval (= 2.0 2) + :eval (= 4 4 4 4)) + (/= + :eval (/= 4 4)) + (< + :args (number &rest numbers) + :eval (< 4 4) + :eval (< 1 2 3)) + (<= + :args (number &rest numbers) + :eval (<= 4 4) + :eval (<= 1 2 2 3)) + (> + :args (number &rest numbers) + :eval (> 4 4) + :eval (> 3 2 1)) + (>= + :args (number &rest numbers) + :eval (>= 4 4) + :eval (>= 3 2 2 1)) + "String" + (string-equal + :eval (string-equal "abc" "abc") + :eval (string-equal "abc" "ABC")) + (string-equal-ignore-case + :eval (string-equal-ignore-case "abc" "ABC")) + (string-lessp + :eval (string-lessp "abc" "abd") + :eval (string-lessp "abc" "abc") + :eval (string-lessp "pic4.png" "pic32.png")) + (string-greaterp + :eval (string-greaterp "abd" "abc") + :eval (string-greaterp "abc" "abc")) + (string-version-lessp + :eval (string-version-lessp "pic4.png" "pic32.png") + :eval (string-version-lessp "1.9.3" "1.10.2")) + (string-collate-lessp + :eval (string-collate-lessp "abc" "abd"))) (define-short-documentation-group vector "Making Vectors" @@ -1131,13 +1208,10 @@ number :args (number &rest numbers) :eval (= 4 4) :eval (= 4.0 4.0) - :eval (= 4 5 6 7)) - (eq - :eval (eq 4 4) - :eval (eq 4.0 4.0)) + :eval (= 4 4.0) + :eval (= 4 4 4 4)) (eql :eval (eql 4 4) - :eval (eql 4 "4") :eval (eql 4.0 4.0)) (/= :eval (/= 4 4)) @@ -1148,15 +1222,15 @@ number (<= :args (number &rest numbers) :eval (<= 4 4) - :eval (<= 1 2 3)) + :eval (<= 1 2 2 3)) (> :args (number &rest numbers) :eval (> 4 4) - :eval (> 1 2 3)) + :eval (> 3 2 1)) (>= :args (number &rest numbers) :eval (>= 4 4) - :eval (>= 1 2 3)) + :eval (>= 3 2 2 1)) (zerop :eval (zerop 0)) (cl-plusp commit 931d97bf56328d8b030f52eef3b9737b46ab7551 Author: Mattias Engdegård Date: Wed Dec 14 12:16:28 2022 +0100 Shortdoc: read and evaluate strings after :eval * lisp/emacs-lisp/shortdoc.el (shortdoc--display-function): If the parameter of :eval is a string then read, evaluate and print the result. This was always the intention and is documented behaviour. diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 83283247150..c6925791d08 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -1440,14 +1440,16 @@ shortdoc--display-function do (cl-case type (:eval + (insert " ") (if (stringp value) - (insert " " value "\n") - (insert " ") - (prin1 value (current-buffer)) - (insert "\n") - (insert " " double-arrow " ") - (prin1 (eval value) (current-buffer)) - (insert "\n"))) + (insert value) + (prin1 value (current-buffer))) + (insert "\n " double-arrow " ") + (let ((expr (if (stringp value) + (car (read-from-string value)) + value))) + (prin1 (eval expr) (current-buffer))) + (insert "\n")) (:no-eval* (if (stringp value) (insert " " value "\n") commit be165f7533271b04fddb814c190a2e632f637dc4 Author: Michael Albinus Date: Wed Dec 14 10:52:04 2022 +0100 Fix Tramp tests in eglot-tests, prefix tests uniquely * test/lisp/progmodes/eglot-tests.el (eglot--call-with-fixture): Use `make-nearby-temp-file'. (eglot--call-with-tramp-test): Set `tramp-verbose' and `default-directory'. The latter is needed for `make-nearby-temp-file'. (eglot-test-tramp-test, eglot-test-tramp-test-2): Tag them as :expensive-test. (all): Prefix all tests with `eglot-test-' uniquely. diff --git a/test/lisp/progmodes/eglot-tests.el b/test/lisp/progmodes/eglot-tests.el index f6b53fd0c6f..d8c9560f5bd 100644 --- a/test/lisp/progmodes/eglot-tests.el +++ b/test/lisp/progmodes/eglot-tests.el @@ -88,7 +88,7 @@ eglot--make-file-or-dir (defun eglot--call-with-fixture (fixture fn) "Helper for `eglot--with-fixture'. Run FN under FIXTURE." - (let* ((fixture-directory (make-temp-file "eglot--fixture" t)) + (let* ((fixture-directory (make-nearby-temp-file "eglot--fixture" t)) (default-directory fixture-directory) file-specs created-files syms-to-restore @@ -311,7 +311,7 @@ eglot--simulate-key-event ;;; Unit tests -(ert-deftest eclipse-connect () +(ert-deftest eglot-test-eclipse-connect () "Connect to eclipse.jdt.ls server." (skip-unless (executable-find "jdtls")) (eglot--with-fixture @@ -343,12 +343,12 @@ eglot-tests--auto-detect-running-server-1 (eglot--find-file-noselect "anotherproject/cena.c") (should-error (eglot--current-server-or-lose)))))) -(ert-deftest auto-detect-running-server () +(ert-deftest eglot-test-auto-detect-running-server () "Visit a file and \\[eglot], then visit a neighbor." (skip-unless (executable-find "clangd")) (eglot-tests--auto-detect-running-server-1)) -(ert-deftest auto-shutdown () +(ert-deftest eglot-test-auto-shutdown () "Visit a file and \\[eglot], then kill buffer." (skip-unless (executable-find "clangd")) (let (server @@ -367,7 +367,7 @@ auto-shutdown (let ((eglot-autoshutdown t)) (kill-buffer buffer)) (should (not (jsonrpc-running-p server))))))) -(ert-deftest auto-reconnect () +(ert-deftest eglot-test-auto-reconnect () "Start a server. Kill it. Watch it reconnect." (skip-unless (executable-find "clangd")) (let (server (eglot-autoreconnect 1)) @@ -390,7 +390,7 @@ auto-reconnect (while (process-live-p proc) (accept-process-output nil 0.5))) (should (not (eglot-current-server))))))) -(ert-deftest rust-analyzer-watches-files () +(ert-deftest eglot-test-rust-analyzer-watches-files () "Start rust-analyzer. Notify it when a critical file changes." (skip-unless (executable-find "rust-analyzer")) (skip-unless (executable-find "cargo")) @@ -425,7 +425,7 @@ rust-analyzer-watches-files (and (string= (eglot--path-to-uri "Cargo.toml") uri) (= type 3)))))))))) -(ert-deftest basic-diagnostics () +(ert-deftest eglot-test-basic-diagnostics () "Test basic diagnostics." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -443,7 +443,7 @@ basic-diagnostics (flymake-goto-next-error 1 '() t) (should (eq 'flymake-error (face-at-point))))))) -(ert-deftest diagnostic-tags-unnecessary-code () +(ert-deftest eglot-test-diagnostic-tags-unnecessary-code () "Test rendering of diagnostics tagged \"unnecessary\"." (skip-unless (executable-find "rust-analyzer")) (skip-unless (executable-find "cargo")) @@ -486,7 +486,7 @@ eglot--tests-force-full-eldoc do (sit-for 0.5) finally (error "eglot--tests-force-full-eldoc didn't deliver"))) -(ert-deftest rust-analyzer-hover-after-edit () +(ert-deftest eglot-test-rust-analyzer-hover-after-edit () "Hover and highlightChanges." (skip-unless (executable-find "rust-analyzer")) (skip-unless (executable-find "cargo")) @@ -519,7 +519,7 @@ rust-analyzer-hover-after-edit (&key id &allow-other-keys) (eq id pending-id))))))) -(ert-deftest rename-a-symbol () +(ert-deftest eglot-test-rename-a-symbol () "Test basic symbol renaming." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -534,7 +534,7 @@ rename-a-symbol (should (equal (buffer-string) "int bar() {return 42;} int main() {return bar();}"))))) -(ert-deftest basic-completions () +(ert-deftest eglot-test-basic-completions () "Test basic autocompletion in a python LSP." (skip-unless (executable-find "pylsp")) (eglot--with-fixture @@ -546,7 +546,7 @@ basic-completions (completion-at-point) (should (looking-back "sys.exit"))))) -(ert-deftest non-unique-completions () +(ert-deftest eglot-test-non-unique-completions () "Test completion resulting in 'Complete, but not unique'." (skip-unless (executable-find "pylsp")) (eglot--with-fixture @@ -563,7 +563,7 @@ non-unique-completions (forward-line -1) (should (looking-at "Complete, but not unique")))))) -(ert-deftest basic-xref () +(ert-deftest eglot-test-basic-xref () "Test basic xref functionality in a python LSP." (skip-unless (executable-find "pylsp")) (eglot--with-fixture @@ -583,7 +583,7 @@ eglot--test-python-buffer (declare-function yas-minor-mode nil) -(ert-deftest snippet-completions () +(ert-deftest eglot-test-snippet-completions () "Test simple snippet completion in a python LSP." (skip-unless (and (executable-find "pylsp") (functionp 'yas-minor-mode))) @@ -605,7 +605,7 @@ company-candidates (declare-function company-mode nil) (declare-function company-complete nil) -(ert-deftest snippet-completions-with-company () +(ert-deftest eglot-test-snippet-completions-with-company () "Test simple snippet completion in a python LSP." (skip-unless (and (executable-find "pylsp") (functionp 'yas-minor-mode) @@ -628,7 +628,7 @@ snippet-completions-with-company ;; pylsp will change the representation of this candidate (should (member "foobazquuz(d, e, f)" company-candidates))))) -(ert-deftest eglot-eldoc-after-completions () +(ert-deftest eglot-test-eldoc-after-completions () "Test documentation echo in a python LSP." (skip-unless (executable-find "pylsp")) (eglot--with-fixture @@ -641,7 +641,7 @@ eglot-eldoc-after-completions (should (looking-back "sys.exit")) (should (string-match "^exit" (eglot--tests-force-full-eldoc)))))) -(ert-deftest eglot-multiline-eldoc () +(ert-deftest eglot-test-multiline-eldoc () "Test if suitable amount of lines of hover info are shown." (skip-unless (executable-find "pylsp")) (eglot--with-fixture @@ -656,7 +656,7 @@ eglot-multiline-eldoc (should (string-match "datetim" captured-message)) (should (cl-find ?\n captured-message)))))) -(ert-deftest eglot-single-line-eldoc () +(ert-deftest eglot-test-single-line-eldoc () "Test if suitable amount of lines of hover info are shown." (skip-unless (executable-find "pylsp")) (eglot--with-fixture @@ -671,7 +671,7 @@ eglot-single-line-eldoc (should (string-match "datetim" captured-message)) (should (not (cl-find ?\n eldoc-last-message))))))) -(ert-deftest python-autopep-formatting () +(ert-deftest eglot-test-python-autopep-formatting () "Test formatting in the pylsp python LSP. pylsp prefers autopep over yafp, despite its README stating the contrary." ;; Beware, default autopep rules can change over time, which may @@ -696,7 +696,7 @@ python-autopep-formatting (should (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n"))))) -(ert-deftest python-yapf-formatting () +(ert-deftest eglot-test-python-yapf-formatting () "Test formatting in the pylsp python LSP." (skip-unless (and (executable-find "pylsp") (not (executable-find "autopep8")) @@ -718,7 +718,7 @@ python-yapf-formatting (should (string= (buffer-string) "def a():\n pass\n\n\ndef b():\n pass\n"))))) -(ert-deftest rust-on-type-formatting () +(ert-deftest eglot-test-rust-on-type-formatting () "Test textDocument/onTypeFormatting against rust-analyzer." (skip-unless (executable-find "rust-analyzer")) (skip-unless (executable-find "cargo")) @@ -738,7 +738,7 @@ rust-on-type-formatting (eglot--simulate-key-event ?.) (should (looking-back "^ \\.")))))) -(ert-deftest javascript-basic () +(ert-deftest eglot-test-javascript-basic () "Test basic autocompletion in a JavaScript LSP." (skip-unless (and (executable-find "typescript-language-server") (executable-find "tsserver"))) @@ -768,7 +768,7 @@ javascript-basic (= severity 1)) diagnostics))))))))) -(ert-deftest project-wide-diagnostics-typescript () +(ert-deftest eglot-test-project-wide-diagnostics-typescript () "Test diagnostics through multiple files in a TypeScript LSP." (skip-unless (and (executable-find "typescript-language-server") (executable-find "tsserver"))) @@ -797,7 +797,7 @@ project-wide-diagnostics-typescript (string= method "textDocument/publishDiagnostics")) (should (= 4 (length (flymake--project-diagnostics)))))))))) -(ert-deftest project-wide-diagnostics-rust-analyzer () +(ert-deftest eglot-test-project-wide-diagnostics-rust-analyzer () "Test diagnostics through multiple files in a TypeScript LSP." (skip-unless (executable-find "rust-analyzer")) (skip-unless (executable-find "cargo")) @@ -826,7 +826,7 @@ project-wide-diagnostics-rust-analyzer "main.rs" (flymake-diagnostic-buffer (car diags)))))))))) -(ert-deftest json-basic () +(ert-deftest eglot-test-json-basic () "Test basic autocompletion in vscode-json-languageserver." (skip-unless (executable-find "vscode-json-languageserver")) (eglot--with-fixture @@ -870,12 +870,12 @@ eglot-tests--lsp-abiding-column-1 (funcall eglot-move-to-column-function 71) (should (looking-at "p"))))))) -(ert-deftest eglot-tests-lsp-abiding-column () +(ert-deftest eglot-test-lsp-abiding-column () "Test basic `eglot-lsp-abiding-column' and `eglot-move-to-lsp-abiding-column'." (skip-unless (executable-find "clangd")) (eglot-tests--lsp-abiding-column-1)) -(ert-deftest eglot-ensure () +(ert-deftest eglot-test-ensure () "Test basic `eglot-ensure' functionality." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -897,7 +897,7 @@ eglot-ensure '(find-file "project/bar.c")) (should (eq server (eglot-current-server))))))) -(ert-deftest slow-sync-connection-wait () +(ert-deftest eglot-test-slow-sync-connection-wait () "Connect with `eglot-sync-connect' set to t." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -909,7 +909,7 @@ slow-sync-connection-wait `((c-mode . ("sh" "-c" "sleep 1 && clangd"))))) (should (eglot--tests-connect 3)))))) -(ert-deftest slow-sync-connection-intime () +(ert-deftest eglot-test-slow-sync-connection-intime () "Connect synchronously with `eglot-sync-connect' set to 2." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -921,7 +921,7 @@ slow-sync-connection-intime `((c-mode . ("sh" "-c" "sleep 1 && clangd"))))) (should (eglot--tests-connect 3)))))) -(ert-deftest slow-async-connection () +(ert-deftest eglot-test-slow-async-connection () "Connect asynchronously with `eglot-sync-connect' set to 2." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -937,7 +937,7 @@ slow-async-connection (accept-process-output nil 0.2)) (should (eglot-current-server))))))) -(ert-deftest slow-sync-timeout () +(ert-deftest eglot-test-slow-sync-timeout () "Failed attempt at connection synchronously." (skip-unless (executable-find "clangd")) (eglot--with-fixture @@ -950,7 +950,7 @@ slow-sync-timeout `((c-mode . ("sh" "-c" "sleep 2 && clangd"))))) (should-error (apply #'eglot--connect (eglot--guess-contact))))))) -(ert-deftest eglot-capabilities () +(ert-deftest eglot-test-capabilities () "Unit test for `eglot--server-capable'." (cl-letf (((symbol-function 'eglot--capabilities) (lambda (_dummy) @@ -976,7 +976,7 @@ eglot--without-interface-warnings (let ((eglot-strict-mode nil)) (macroexpand-all (macroexp-progn body) macroexpand-all-environment))) -(ert-deftest eglot-strict-interfaces () +(ert-deftest eglot-test-strict-interfaces () (let ((eglot--lsp-interface-alist `((FooObject . ((:foo :bar) (:baz)))))) (eglot--without-interface-warnings @@ -1018,7 +1018,7 @@ eglot-strict-interfaces (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :baz bargh) (cons foo bar))))))) -(ert-deftest eglot-dcase () +(ert-deftest eglot-test-dcase () (eglot--without-interface-warnings (let ((eglot--lsp-interface-alist `((FooObject . ((:foo :bar) (:baz))) @@ -1049,7 +1049,7 @@ eglot-dcase (((CodeAction) _title _edit _command) (ert-fail "Shouldn't have destructured this object as a CodeAction")))))))) -(ert-deftest eglot-dcase-issue-452 () +(ert-deftest eglot-test-dcase-issue-452 () (let ((eglot--lsp-interface-alist `((FooObject . ((:foo :bar) (:baz))) (CodeAction (:title) (:kind :diagnostics :edit :command)) @@ -1100,7 +1100,7 @@ eglot--guessing-contact (eglot--guess-contact ,i-sym) ,@body)))))) -(ert-deftest eglot-server-programs-simple-executable () +(ert-deftest eglot-test-server-programs-simple-executable () (let ((eglot-server-programs '((foo-mode "some-executable"))) (major-mode 'foo-mode)) (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact) @@ -1108,7 +1108,7 @@ eglot-server-programs-simple-executable (should (equal guessed-class 'eglot-lsp-server)) (should (equal guessed-contact '("some-executable")))))) -(ert-deftest eglot-server-programs-simple-missing-executable () +(ert-deftest eglot-test-server-programs-simple-missing-executable () (let ((eglot-server-programs '((foo-mode "a-missing-executable.exe"))) (major-mode 'foo-mode)) (eglot--guessing-contact (interactive-p prompt-args guessed-class guessed-contact) @@ -1117,7 +1117,7 @@ eglot-server-programs-simple-missing-executable (should (or prompt-args (equal guessed-contact '("a-missing-executable.exe"))))))) -(ert-deftest eglot-server-programs-executable-multiple-major-modes () +(ert-deftest eglot-test-server-programs-executable-multiple-major-modes () (let ((eglot-server-programs '(((bar-mode foo-mode) "some-executable"))) (major-mode 'foo-mode)) (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact) @@ -1125,7 +1125,7 @@ eglot-server-programs-executable-multiple-major-modes (should (equal guessed-class 'eglot-lsp-server)) (should (equal guessed-contact '("some-executable")))))) -(ert-deftest eglot-server-programs-executable-with-arg () +(ert-deftest eglot-test-server-programs-executable-with-arg () (let ((eglot-server-programs '((foo-mode "some-executable" "arg1"))) (major-mode 'foo-mode)) (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact) @@ -1133,7 +1133,7 @@ eglot-server-programs-executable-with-arg (should (equal guessed-class 'eglot-lsp-server)) (should (equal guessed-contact '("some-executable" "arg1")))))) -(ert-deftest eglot-server-programs-executable-with-args-and-autoport () +(ert-deftest eglot-test-server-programs-executable-with-args-and-autoport () (let ((eglot-server-programs '((foo-mode "some-executable" "arg1" :autoport "arg2"))) (major-mode 'foo-mode)) @@ -1143,7 +1143,7 @@ eglot-server-programs-executable-with-args-and-autoport (should (equal guessed-contact '("some-executable" "arg1" :autoport "arg2")))))) -(ert-deftest eglot-server-programs-host-and-port () +(ert-deftest eglot-test-server-programs-host-and-port () (let ((eglot-server-programs '((foo-mode "somehost.example.com" 7777))) (major-mode 'foo-mode)) (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact) @@ -1151,7 +1151,7 @@ eglot-server-programs-host-and-port (should (equal guessed-class 'eglot-lsp-server)) (should (equal guessed-contact '("somehost.example.com" 7777)))))) -(ert-deftest eglot-server-programs-host-and-port-and-tcp-args () +(ert-deftest eglot-test-server-programs-host-and-port-and-tcp-args () (let ((eglot-server-programs '((foo-mode "somehost.example.com" 7777 :type network))) (major-mode 'foo-mode)) @@ -1161,7 +1161,7 @@ eglot-server-programs-host-and-port-and-tcp-args (should (equal guessed-contact '("somehost.example.com" 7777 :type network)))))) -(ert-deftest eglot-server-programs-class-name-and-plist () +(ert-deftest eglot-test-server-programs-class-name-and-plist () (let ((eglot-server-programs '((foo-mode bar-class :init-key init-val))) (major-mode 'foo-mode)) (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact) @@ -1169,7 +1169,7 @@ eglot-server-programs-class-name-and-plist (should (equal guessed-class 'bar-class)) (should (equal guessed-contact '(:init-key init-val)))))) -(ert-deftest eglot-server-programs-class-name-and-contact-spec () +(ert-deftest eglot-test-server-programs-class-name-and-contact-spec () (let ((eglot-server-programs '((foo-mode bar-class "some-executable" "arg1" :autoport "arg2"))) (major-mode 'foo-mode)) @@ -1179,7 +1179,7 @@ eglot-server-programs-class-name-and-contact-spec (should (equal guessed-contact '("some-executable" "arg1" :autoport "arg2")))))) -(ert-deftest eglot-server-programs-function () +(ert-deftest eglot-test-server-programs-function () (let ((eglot-server-programs '((foo-mode . (lambda (&optional _) '("some-executable"))))) (major-mode 'foo-mode)) @@ -1188,7 +1188,7 @@ eglot-server-programs-function (should (equal guessed-class 'eglot-lsp-server)) (should (equal guessed-contact '("some-executable")))))) -(ert-deftest eglot-server-programs-guess-lang () +(ert-deftest eglot-test-server-programs-guess-lang () (let ((major-mode 'foo-mode)) (let ((eglot-server-programs '((foo-mode . ("prog-executable"))))) (eglot--guessing-contact (_ nil _ _ guessed-lang) @@ -1205,7 +1205,7 @@ eglot-server-programs-guess-lang (defun eglot--glob-match (glob str) (funcall (eglot--glob-compile glob t t) str)) -(ert-deftest eglot--glob-test () +(ert-deftest eglot-test-glob-test () (should (eglot--glob-match "foo/**/baz" "foo/bar/baz")) (should (eglot--glob-match "foo/**/baz" "foo/baz")) (should-not (eglot--glob-match "foo/**/baz" "foo/bar")) @@ -1260,31 +1260,34 @@ tramp-histfile-override (defun eglot--call-with-tramp-test (fn) ;; Set up a Tramp method that’s just a shell so the remote host is ;; really just the local host. - (let ((tramp-remote-path (cons 'tramp-own-remote-path tramp-remote-path)) - (tramp-histfile-override t) - (temporary-file-directory ert-remote-temporary-file-directory)) + (let* ((tramp-remote-path (cons 'tramp-own-remote-path tramp-remote-path)) + (tramp-histfile-override t) + (tramp-verbose 1) + (temporary-file-directory ert-remote-temporary-file-directory) + (default-directory temporary-file-directory)) ;; We must check the remote LSP server. So far, just "clangd" is used. - (let ((default-directory temporary-file-directory)) - (unless (executable-find "clangd" 'remote) - (ert-skip "Remote clangd not found"))) + (unless (executable-find "clangd" 'remote) + (ert-skip "Remote clangd not found")) (funcall fn))) -(ert-deftest eglot--tramp-test () +(ert-deftest eglot-test-tramp-test () "Ensure LSP servers can be used over TRAMP." + :tags '(:expensive-test) (eglot--call-with-tramp-test #'eglot-tests--auto-detect-running-server-1)) -(ert-deftest eglot--tramp-test-2 () +(ert-deftest eglot-test-tramp-test-2 () "Ensure LSP servers can be used over TRAMP." + :tags '(:expensive-test) (eglot--call-with-tramp-test #'eglot-tests--lsp-abiding-column-1)) -(ert-deftest eglot--path-to-uri-windows () +(ert-deftest eglot-test-path-to-uri-windows () (skip-unless (eq system-type 'windows-nt)) (should (string-prefix-p "file:///" (eglot--path-to-uri "c:/Users/Foo/bar.lisp"))) (should (string-suffix-p "c%3A/Users/Foo/bar.lisp" (eglot--path-to-uri "c:/Users/Foo/bar.lisp")))) -(ert-deftest eglot--same-server-multi-mode () +(ert-deftest eglot-test-same-server-multi-mode () "Check single LSP instance manages multiple modes in same project." (skip-unless (executable-find "clangd")) (let (server) commit 8c30cb90ba9fc1a7b60c25f43697687c587bb9ad Author: Juri Linkov Date: Wed Dec 14 10:05:55 2022 +0200 * lisp/vc/vc-git.el (vc-git-checkin): Use make-nearby-temp-file (bug#60011) diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 38e9d5f9c91..b5959d535c0 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -1041,7 +1041,7 @@ vc-git-checkin (string-replace file-diff "" vc-git-patch-string)) (user-error "Index not empty")) (setq pos (point)))))) - (let ((patch-file (make-temp-file "git-patch"))) + (let ((patch-file (make-nearby-temp-file "git-patch"))) (with-temp-file patch-file (insert vc-git-patch-string)) (unwind-protect commit 3efe4df1d20b1b2d823613f0945a2d37b76004a9 Author: Stefan Kangas Date: Wed Dec 14 08:21:34 2022 +0100 Delete temp files after icalendar tests * test/lisp/calendar/icalendar-tests.el (icalendar-tests--get-error-string-for-export): Make sure we clean up temporary files after test. diff --git a/test/lisp/calendar/icalendar-tests.el b/test/lisp/calendar/icalendar-tests.el index fa55eea95e2..baf4846c8f5 100644 --- a/test/lisp/calendar/icalendar-tests.el +++ b/test/lisp/calendar/icalendar-tests.el @@ -63,7 +63,8 @@ icalendar-tests--get-file-contents (defun icalendar-tests--get-error-string-for-export (diary-string) "Call icalendar-export for DIARY-STRING and return resulting error-string." - (let ((file (make-temp-file "export.ics"))) + (ert-with-temp-file file + :suffix "-export.ics" (with-temp-buffer (insert diary-string) (icalendar-export-region (point-min) (point-max) file)) commit 33e0a104649dd90e347701723fa52af52a8a57c7 Author: Stefan Kangas Date: Wed Dec 14 06:38:14 2022 +0100 ; * lisp/keymap.el (keymap-substitute): Doc fix. (Bug#60059) (cherry picked from commit 1568123196cd8b57ed64e284b7deb058026be713) diff --git a/lisp/keymap.el b/lisp/keymap.el index eaeba966444..b355f68aa2f 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -147,7 +147,7 @@ keymap-substitute If you don't specify OLDMAP, you can usually get the same results in a cleaner way with command remapping, like this: (define-key KEYMAP [remap OLDDEF] NEWDEF) -\n(fn OLDDEF NEWDEF KEYMAP &optional OLDMAP)" +\n(fn KEYMAP OLDDEF NEWDEF &optional OLDMAP)" ;; Don't document PREFIX in the doc string because we don't want to ;; advertise it. It's meant for recursive calls only. Here's its ;; meaning commit fafcf02c856ef8fd712ff75e8999dfb0f6d97f07 Author: Kai Ma Date: Sun Dec 4 06:15:42 2022 +0800 Fix syntax tables of tree-sitter modes (bug#59807) Tree-sitter modes should use the same syntax table as the non-tree-sitter ones. * lisp/progmodes/js.el (js-mode-syntax-table) (js-ts-mode) * lisp/progmodes/python.el (python-ts-mode) * lisp/progmodes/sh-script.el (bash-ts-mode) Copyright-paperwork-exempt: yes xx diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 1de0f3442f0..02990813ef4 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -686,7 +686,7 @@ js-mode-syntax-table (modify-syntax-entry ?$ "_" table) (modify-syntax-entry ?` "\"" table) table) - "Syntax table for `js-mode'.") + "Syntax table for `js-mode' and `js-ts-mode'.") (defvar-local js--quick-match-re nil "Autogenerated regexp used by `js-mode' to match buffer constructs.") @@ -3843,6 +3843,7 @@ js-ts-mode \\" :group 'js + :syntax-table js-mode-syntax-table (when (treesit-ready-p 'javascript) ;; Borrowed from `js-mode'. (setq-local prettify-symbols-alist js--prettify-symbols-alist) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 0e0898ffe28..ee05862550d 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -6619,6 +6619,7 @@ python-ts-mode "Major mode for editing Python files, using tree-sitter library. \\{python-ts-mode-map}" + :syntax-table python-mode-syntax-table (when (treesit-ready-p 'python) (treesit-parser-create 'python) (setq-local treesit-font-lock-feature-list diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index e170d18afeb..76e8d5b0748 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el @@ -1611,6 +1611,7 @@ bash-ts-mode "Major mode for editing Bash shell scripts. This mode automatically falls back to `sh-mode' if the buffer is not written in Bash or sh." + :syntax-table sh-mode-syntax-table (when (treesit-ready-p 'bash) (setq-local treesit-font-lock-feature-list '(( comment function) commit 91b8d9b7db47f242cf33f0e99d787c235d761d4b Author: Yuan Fu Date: Tue Dec 13 16:24:38 2022 -0800 ; * admin/notes/tree-sitter/build-module/build.sh: Minor name change. diff --git a/admin/notes/tree-sitter/build-module/build.sh b/admin/notes/tree-sitter/build-module/build.sh index d020ee92c39..4195ea58c3c 100755 --- a/admin/notes/tree-sitter/build-module/build.sh +++ b/admin/notes/tree-sitter/build-module/build.sh @@ -14,17 +14,17 @@ topdir= ### Retrieve sources -namespace="tree-sitter" +org="tree-sitter" repo="tree-sitter-${lang}" sourcedir="tree-sitter-${lang}/src" grammardir="tree-sitter-${lang}" case "${lang}" in "dockerfile") - namespace="camdencheek" + org="camdencheek" ;; "cmake") - namespace="uyha" + org="uyha" ;; "typescript") sourcedir="tree-sitter-typescript/typescript/src" @@ -37,7 +37,7 @@ grammardir= ;; esac -git clone "https://github.com/${namespace}/${repo}.git" \ +git clone "https://github.com/${org}/${repo}.git" \ --depth 1 --quiet cp "${grammardir}"/grammar.js "${sourcedir}" # We have to go into the source directory to compile, because some commit 1b0e282a7f82d3110bec32aff6d6363910491b69 Author: Yuan Fu Date: Tue Dec 13 15:59:29 2022 -0800 ; Comment and stylistic change in treesit.el * lisp/treesit.el (treesit-defun-skipper): Docstring change. (treesit--navigate-defun): Comment and stylistic change. diff --git a/lisp/treesit.el b/lisp/treesit.el index 9b33bc8e765..58b85ddba39 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -1584,9 +1584,12 @@ treesit-defun-tactic (defvar-local treesit-defun-skipper #'treesit-default-defun-skipper "A function called after tree-sitter navigation moved a step. + It is called with no arguments. By default, this function tries to move to the beginning of a line, either by moving to the empty -newline after a defun, or the beginning of a defun.") +newline after a defun, or the beginning of a defun. + +If the value is nil, no skipping is performed.") (defvar-local treesit-defun-prefer-top-level nil "When non-nil, Emacs prefers top-level defun. @@ -1760,6 +1763,33 @@ treesit--top-level-defun do (setq node cursor)) node)) +;; The basic idea for nested defun navigation is that we first try to +;; move across sibling defuns in the same level, if no more siblings +;; exist, we move to parents's beg/end, rinse and repeat. We never +;; move into a defun, only outwards. +;; +;; Let me describe roughly what does this function do: there are four +;; possible operations: prev-beg, next-end, prev-end, next-beg, and +;; each of (prev-sibling next-sibling and parent) could exist or not +;; exist. So there are 4 times 8 = 32 situations. +;; +;; I'll only describe the situation when we go backward (prev-beg & +;; prev-end), and consider only prev-sibling & parent. Deriving the +;; reverse situations is left as an exercise for the reader. +;; +;; prev-beg (easy case): +;; 1. prev-sibling or parent exists +;; -> go the prev-sibling/parent's beg +;; +;; prev-end (tricky): +;; 1. prev-sibling exists +;; -> If you think about it, we are already at prev-sibling's end! +;; So we need to go one step further, either to +;; prev-prev-sibling's end, or parent's prev-sibling's end, etc. +;; 2. prev-sibling is nil but parent exists +;; -> Obviously we don't want to go to parent's end, instead, we +;; want to go to parent's prev-sibling's end. Again, we recurse +;; in the function to do that. (defun treesit--navigate-defun (pos arg side &optional recursing) "Navigate defun ARG steps from POS. @@ -1793,9 +1823,9 @@ treesit--navigate-defun (pcase-let ((`(,prev ,next ,parent) (treesit--defuns-around pos regexp pred))) - ;; When PARENT is nil, nested and top-level are the same, - ;; there there is a PARENT, make PARENT to be the top-level - ;; parent and pretend there is no nested PREV and NEXT. + ;; When PARENT is nil, nested and top-level are the same, if + ;; there is a PARENT, make PARENT to be the top-level parent + ;; and pretend there is no nested PREV and NEXT. (when (and (eq treesit-defun-tactic 'top-level) parent) (setq parent (treesit--top-level-defun @@ -1811,19 +1841,18 @@ treesit--navigate-defun (parent t) ; [2] (t nil))) ;; Special case: go to next beg-of-defun. Set POS - ;; to the end of next/parent defun, and run one more - ;; step. If there is a next defun, step over it, so - ;; we only need to recurse once, so we don't need to - ;; recurse if we are already recursing [1]. If there - ;; is no next but a parent, keep stepping out + ;; to the end of next-sib/parent defun, and run one + ;; more step. If there is a next-sib defun, we only + ;; need to recurse once, so we don't need to recurse + ;; if we are already recursing [1]. If there is no + ;; next-sib but a parent, keep stepping out ;; (recursing) until we got out of the parents until ;; (1) there is a next sibling defun, or (2) no more ;; parents [2]. - (setq pos - (or (treesit--navigate-defun - (treesit-node-end (or next parent)) - 1 'beg t) - (throw 'term nil))) + (setq pos (or (treesit--navigate-defun + (treesit-node-end (or next parent)) + 1 'beg t) + (throw 'term nil))) ;; Normal case. (setq pos (funcall advance (or next parent)))) ;; ...backward. @@ -1832,19 +1861,16 @@ treesit--navigate-defun (parent t) (t nil))) ;; Special case: go to prev end-of-defun. - (setq pos - (or (treesit--navigate-defun - (treesit-node-start (or prev parent)) - -1 'end t) - (throw 'term nil))) + (setq pos (or (treesit--navigate-defun + (treesit-node-start (or prev parent)) + -1 'end t) + (throw 'term nil))) ;; Normal case. (setq pos (funcall advance (or prev parent))))) ;; A successful step! Decrement counter. (cl-decf counter)))) ;; Counter equal to 0 means we successfully stepped ARG steps. - (if (eq counter 0) - pos - nil))) + (if (eq counter 0) pos nil))) ;;; Activating tree-sitter commit 489b02d03cf3838bfb2a45c55ff52e5d962f1c74 Author: Stefan Kangas Date: Wed Dec 14 00:36:30 2022 +0100 * doc/misc/Makefile.in (need_emacsver): Add use-package. diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in index 49cd8e13b03..60b14172c37 100644 --- a/doc/misc/Makefile.in +++ b/doc/misc/Makefile.in @@ -186,7 +186,8 @@ info.info: ## Extra dependencies. ## FIXME Updating this list manually is unreliable. -need_emacsver = calc cl dired-x efaq efaq-w32 erc forms ido newsticker reftex remember woman +need_emacsver = calc cl dired-x efaq efaq-w32 erc forms ido \ + newsticker reftex remember use-package woman need_emacsver_prefix = $(addprefix ${buildinfodir}/,${need_emacsver}) $(need_emacsver_prefix:=.info) $(need_emacsver:=.dvi) $(need_emacsver:=.pdf) $(need_emacsver:=.html) : ${emacsdir}/emacsver.texi