commit b5b6159d036fd167c6cab21532c2fdd587051d28 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Tue Jan 3 15:12:39 2023 +0800 Fix potential crash with fast mouse position enabled * src/xterm.c (x_free_frame_resources): Clear last_mouse_motion_frame and last_mouse_frame if required. diff --git a/src/xterm.c b/src/xterm.c index 8d8b0a0c0aa..028bb7582c4 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -28841,6 +28841,13 @@ x_free_frame_resources (struct frame *f) if (f == hlinfo->mouse_face_mouse_frame) reset_mouse_highlight (hlinfo); + /* These two need to be freed now that they are used to compute the + mouse position, I think. */ + if (f == dpyinfo->last_mouse_motion_frame) + dpyinfo->last_mouse_motion_frame = NULL; + if (f == dpyinfo->last_mouse_frame) + dpyinfo->last_mouse_frame = NULL; + #ifdef HAVE_XINPUT2 /* Consider a frame being unfocused with no following FocusIn event while an older focus from another seat exists. The client commit 55e41707ea727ea4b5c4d3c85f68b62e32dcdfb5 Merge: 2ee6012b3fa 6dd3e352f44 Author: Stefan Kangas Date: Tue Jan 3 06:30:17 2023 +0100 Merge from origin/emacs-29 6dd3e352f44 Extract common code into ruby-base-mode to derive from 94e330243e1 ruby-ts-mode: Indentation fixes 9b24417dda8 ruby-ts--font-lock-settings: Use more standard faces 9e6536e4d96 ruby-ts-mode: Standardize the string literal highlights 1a9a1fdebf6 Improve fontification in java-ts-mode (bug#60492) dfdf9c21cbe Fontification improvements in typescript-ts-mode (bug#60500) 68e68dfeefe Improve fontification consistency in js-ts-mode (bug#60503) aef869e74f4 ; Update tree-sitter manual 4ef12cfb1fc ; Fix tree-sitter manual title case aab8ddca5e1 ; nt/INSTALL: Update for Emacs 29. 809fbb0e8c4 ; Update copyright notice in tramp-sh.el f8f5202487c (typescript/tsx-ts-mode): Split font-lock feature list in... a86a213e1ac js-ts-mode: Move 'string-interpolation' to font-lock level 3 d26b523886e Fix shrinking of the tab-bar 3f7ea621b90 ; Fix typos in ruby-ts-mode.el 9599b054316 ; Skip ruby-ts tests if grammar is not available ff35ac9dfab Fix default-port regression in erc-select-read-args b7ad0b40148 ; Clarify doc strings of 'call-process' and 'call-process... commit 6dd3e352f44eb402c9b76c8f6e5bef032317cc55 Author: Dmitry Gutov Date: Tue Jan 3 03:10:49 2023 +0200 Extract common code into ruby-base-mode to derive from * lisp/progmodes/ruby-mode.el (ruby-base-mode): New major base mode, to set up common vars and hooks. (ruby-mode-variables): Delete. Move most code to ruby-base-mode. And some -- to ruby-mode body. (ruby-mode): Derive from ruby-base-mode. Also move some setup to there. * lisp/progmodes/ruby-ts-mode.el (ruby-ts-mode): Derive from ruby-base-mode. Remove duplicating settings. diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 14cdf0a1a26..2e8d335f151 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -899,24 +899,6 @@ ruby-accurate-end-of-block (while (and (setq state (apply #'ruby-parse-partial end state)) (>= (nth 2 state) 0) (< (point) end)))))) -(defun ruby-mode-variables () - "Set up initial buffer-local variables for Ruby mode." - (setq indent-tabs-mode ruby-indent-tabs-mode) - (smie-setup ruby-smie-grammar #'ruby-smie-rules - :forward-token #'ruby-smie--forward-token - :backward-token #'ruby-smie--backward-token) - (unless ruby-use-smie - (setq-local indent-line-function #'ruby-indent-line)) - (setq-local comment-start "# ") - (setq-local comment-end "") - (setq-local comment-column ruby-comment-column) - (setq-local comment-start-skip "#+ *") - (setq-local parse-sexp-ignore-comments t) - (setq-local parse-sexp-lookup-properties t) - (setq-local paragraph-start (concat "$\\|" page-delimiter)) - (setq-local paragraph-separate paragraph-start) - (setq-local paragraph-ignore-fill-prefix t)) - (defun ruby--insert-coding-comment (encoding) "Insert a magic coding comment for ENCODING. The style of the comment is controlled by `ruby-encoding-magic-comment-style'." @@ -2629,29 +2611,54 @@ ruby--prettify-symbols-alist "Value for `prettify-symbols-alist' in `ruby-mode'.") ;;;###autoload -(define-derived-mode ruby-mode prog-mode "Ruby" - "Major mode for editing Ruby code." - (ruby-mode-variables) +(define-derived-mode ruby-base-mode prog-mode "Ruby" + "Generic major mode for editing Ruby. - (setq-local imenu-create-index-function #'ruby-imenu-create-index) - (setq-local add-log-current-defun-function #'ruby-add-log-current-method) - (setq-local beginning-of-defun-function #'ruby-beginning-of-defun) - (setq-local end-of-defun-function #'ruby-end-of-defun) +This mode is intended to be inherited by concrete major modes. +Currently there are `ruby-mode' and `ruby-ts-mode'." + (setq indent-tabs-mode ruby-indent-tabs-mode) + + (setq-local comment-start "# ") + (setq-local comment-end "") + (setq-local comment-column ruby-comment-column) + (setq-local comment-start-skip "#+ *") + + (setq-local parse-sexp-ignore-comments t) + (setq-local parse-sexp-lookup-properties t) + + (setq-local paragraph-start (concat "$\\|" page-delimiter)) + (setq-local paragraph-separate paragraph-start) + (setq-local paragraph-ignore-fill-prefix t) ;; `outline-regexp' contains the first part of `ruby-indent-beg-re' (setq-local outline-regexp (concat "^\\s *" (regexp-opt '("class" "module" "def")) "\\_>")) (setq-local outline-level (lambda () (1+ (/ (current-indentation) - ruby-indent-level)))) + ruby-indent-level)))) (add-hook 'after-save-hook #'ruby-mode-set-encoding nil 'local) (add-hook 'electric-indent-functions #'ruby--electric-indent-p nil 'local) (add-hook 'flymake-diagnostic-functions #'ruby-flymake-auto nil 'local) + (setq-local prettify-symbols-alist ruby--prettify-symbols-alist)) + +;;;###autoload +(define-derived-mode ruby-mode ruby-base-mode "Ruby" + "Major mode for editing Ruby code." + (smie-setup ruby-smie-grammar #'ruby-smie-rules + :forward-token #'ruby-smie--forward-token + :backward-token #'ruby-smie--backward-token) + (unless ruby-use-smie + (setq-local indent-line-function #'ruby-indent-line)) + + (setq-local imenu-create-index-function #'ruby-imenu-create-index) + (setq-local add-log-current-defun-function #'ruby-add-log-current-method) + (setq-local beginning-of-defun-function #'ruby-beginning-of-defun) + (setq-local end-of-defun-function #'ruby-end-of-defun) + (setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil ((?_ . "w")))) - (setq-local prettify-symbols-alist ruby--prettify-symbols-alist) (setq-local syntax-propertize-function #'ruby-syntax-propertize)) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 6fb6f71991c..c086214a11d 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -898,21 +898,11 @@ ruby-ts-mode-map "C-c C-f" #'ruby-find-library-file) ;;;###autoload -(define-derived-mode ruby-ts-mode prog-mode "Ruby" +(define-derived-mode ruby-ts-mode ruby-base-mode "Ruby" "Major mode for editing Ruby, powered by tree-sitter." :group 'ruby :syntax-table ruby-mode-syntax-table - (setq indent-tabs-mode ruby-indent-tabs-mode) - - (setq-local paragraph-start (concat "$\\|" page-delimiter)) - (setq-local paragraph-separate paragraph-start) - (setq-local paragraph-ignore-fill-prefix t) - - (setq-local comment-start "# ") - (setq-local comment-end "") - (setq-local comment-start-skip "#+ *") - (unless (treesit-ready-p 'ruby) (error "Tree-sitter for Ruby isn't available")) commit 94e330243e14200ba6b45e696e6a80c611438dec Author: Dmitry Gutov Date: Tue Jan 3 02:26:00 2023 +0200 ruby-ts-mode: Indentation fixes * lisp/progmodes/ruby-ts-mode.el (ruby-ts--align-keywords): Fix for 'def' (which was misread as 'method' in the check). (ruby-ts--indent-rules): Indent the curly block closer the same way as the 'do ... end' closer. diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 96596cb5daf..6fb6f71991c 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -355,8 +355,11 @@ ruby-ts--align-keywords (lambda (node parent bol &rest rest) (let* ((pred-node (funcall pred node parent bol rest)) (temp (treesit-node-start pred-node)) - (keyword (treesit-node-type pred-node)) - (bol (ruby-smie--indent-to-stmt-p keyword))) + (type (treesit-node-type pred-node)) + (bol (ruby-smie--indent-to-stmt-p + (if (equal type "method") + "def" + type)))) (when temp (if bol (save-excursion @@ -736,7 +739,7 @@ ruby-ts--indent-rules ((match "end" "do_block") parent-bol 0) ((n-p-gp "block_body" "block" nil) parent-bol ruby-indent-level) ((n-p-gp nil "block_body" "block") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) - ((match "}" "block") (ruby-ts--bol ruby-ts--grand-parent-node) 0) + ((match "}" "block") parent-bol 0) ;; Chained strings ((match "string" "chained_string") first-sibling 0) commit 9b24417dda83087edb5b8bb5d2daf158c70b4193 Author: Dmitry Gutov Date: Tue Jan 3 00:41:25 2023 +0200 ruby-ts--font-lock-settings: Use more standard faces * lisp/progmodes/ruby-ts-mode.el (ruby-ts--font-lock-settings): Use more standard faces for regexp literals and string interpolation delimiters (following js-ts-mode). diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 92c8f93a799..96596cb5daf 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -237,8 +237,10 @@ ruby-ts--font-lock-settings ;; Also before 'operator because % and / are operators :language language :feature 'regexp - '((regex "/" @font-lock-regexp-grouping-construct) - (regex _ (string_content) @font-lock-regexp-grouping-backslash)) + ;; TODO: We probably need a separate face for regexps everywhere. + ;; Maybe another one for regexp delimiters as well. + '((regex "/" @font-lock-string-face) + (regex _ (string_content) @font-lock-string-face)) :language language :feature 'operator @@ -267,8 +269,8 @@ ruby-ts--font-lock-settings :language language :feature 'interpolation - '((interpolation "#{" @font-lock-doc-face) - (interpolation "}" @font-lock-doc-face)) + '((interpolation "#{" @font-lock-delimiter-face) + (interpolation "}" @font-lock-delimiter-face)) :language language :feature 'type commit 9e6536e4d96e2280b8ed76e9e83369659a347e02 Author: Dmitry Gutov Date: Mon Jan 2 23:26:39 2023 +0200 ruby-ts-mode: Standardize the string literal highlights * lisp/progmodes/ruby-ts-mode.el (ruby-ts--font-lock-settings): Use font-lock-string-face for %w() and `...`. Use font-lock-constant-face (just like we do for symbol literals) for symbol array literals, %i(). Combine the matchers for string content and heredocs. diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 26d0fc49260..92c8f93a799 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -253,16 +253,17 @@ ruby-ts--font-lock-settings :feature 'string '((delimited_symbol [ ":\"" "\"" ] @font-lock-string-face) (string "\"" @font-lock-string-face) - (string_array [ "%w(" ")" ] @font-lock-delimiter-face) - (subshell "`" @font-lock-delimiter-face) - (symbol_array [ "%i(" ")"] @font-lock-delimiter-face)) + (string_array ["%w(" ")"] @font-lock-string-face) + (subshell "`" @font-lock-string-face) + (symbol_array ["%i(" ")"] @font-lock-constant-face)) :language language :feature 'string - '((string_content) @font-lock-string-face - (heredoc_beginning) @font-lock-string-face - (heredoc_content) @font-lock-string-face - (heredoc_end) @font-lock-string-face) + '([(string_content) + (heredoc_beginning) + (heredoc_content) + (heredoc_end)] + @font-lock-string-face) :language language :feature 'interpolation commit 1a9a1fdebf648cc1f614089f385d2a9c6cbabc5b Author: Theodor Thornhill Date: Mon Jan 2 13:46:25 2023 +0100 Improve fontification in java-ts-mode (bug#60492) * lisp/progmodes/java-ts-mode.el (java-ts-mode--font-lock-settings): Add expression_statement with only identifier support. diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el index 8d6b244c135..96d8045bd61 100644 --- a/lisp/progmodes/java-ts-mode.el +++ b/lisp/progmodes/java-ts-mode.el @@ -240,7 +240,9 @@ java-ts-mode--font-lock-settings (method_invocation name: (identifier) @font-lock-function-name-face) - (argument_list (identifier) @font-lock-variable-name-face)) + (argument_list (identifier) @font-lock-variable-name-face) + + (expression_statement (identifier) @font-lock-variable-name-face)) :language 'java :feature 'bracket commit dfdf9c21cbe7896d03da011773e636fc287d97db Author: Jostein Kjønigsen Date: Mon Jan 2 20:56:41 2023 +0100 Fontification improvements in typescript-ts-mode (bug#60500) - highlight method-definitins in interfaces. - only highlight variable-declarations, not variables everywhere (consistency with other modes). - move highlighting of method invocations to level 4 * lisp/progmodes/typescript-ts-mode.el: (typescript-ts-mode--font-lock-settings): Update rules. (typescript-ts-mode, tsx-ts-mode): Update feature list. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index a0ba425b3e9..e0583f4b05c 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -167,6 +167,8 @@ typescript-ts-mode--font-lock-settings (method_definition name: (property_identifier) @font-lock-function-name-face) + (method_signature + name: (property_identifier) @font-lock-function-name-face) (required_parameter (identifier) @font-lock-variable-name-face) (optional_parameter (identifier) @font-lock-variable-name-face) @@ -211,10 +213,8 @@ typescript-ts-mode--font-lock-settings (enum_assignment name: (property_identifier) @font-lock-type-face) - (assignment_expression - left: [(identifier) @font-lock-variable-name-face - (member_expression - property: (property_identifier) @font-lock-variable-name-face)]) + (variable_declarator + name: (identifier) @font-lock-variable-name-face) (for_in_statement left: (identifier) @font-lock-variable-name-face) @@ -242,10 +242,6 @@ typescript-ts-mode--font-lock-settings 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) @@ -263,9 +259,11 @@ typescript-ts-mode--font-lock-settings left: [(identifier) @font-lock-function-name-face (member_expression property: (property_identifier) @font-lock-function-name-face)] - right: [(function) (arrow_function)]) + right: [(function) (arrow_function)])) - (call_expression + :language language + :feature 'function + '((call_expression function: [(identifier) @font-lock-function-name-face (member_expression @@ -377,7 +375,7 @@ typescript-ts-mode '((comment declaration) (keyword string escape-sequence) (constant expression identifier number pattern property) - (bracket delimiter))) + (function bracket delimiter))) (treesit-major-mode-setup))) @@ -412,7 +410,7 @@ tsx-ts-mode '((comment declaration) (keyword string escape-sequence) (constant expression identifier jsx number pattern property) - (bracket delimiter))) + (function bracket delimiter))) (treesit-major-mode-setup))) commit 68e68dfeefe0ac64d4ec6c31d046ae5957741109 Author: Jostein Kjønigsen Date: Mon Jan 2 21:26:36 2023 +0100 Improve fontification consistency in js-ts-mode (bug#60503) * lisp/progmodes/js.el (js--treesit-font-lock-settings): Highlight declared parameters in functions, methods and arrow-expressions as variables. diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index c5fdecae71b..050472002bb 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3521,6 +3521,15 @@ js--treesit-font-lock-settings (method_definition name: (property_identifier) @font-lock-function-name-face) + (method_definition + parameters: (formal_parameters (identifier) @font-lock-variable-name-face)) + + (arrow_function + parameters: (formal_parameters (identifier) @font-lock-variable-name-face)) + + (function_declaration + parameters: (formal_parameters (identifier) @font-lock-variable-name-face)) + (variable_declarator name: (identifier) @font-lock-variable-name-face) commit aef869e74f47bbe00c8cf0cb02cea20aa0c33a6d Author: Yuan Fu Date: Mon Jan 2 14:15:36 2023 -0800 ; Update tree-sitter manual * doc/lispref/positions.texi (List Motion): Replace treesit-defun-prefer-top-level with treesit-defun-tactic. diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi index 68e948bacd8..f47720184a3 100644 --- a/doc/lispref/positions.texi +++ b/doc/lispref/positions.texi @@ -848,25 +848,14 @@ List Motion nodes. (For ``node'' and ``node type'', @pxref{Parsing Program Source}.) For example, @code{python-mode} sets this variable to a regexp that -matches either @code{function_definition} or @code{class_definition}. +matches either @code{"function_definition"} or @code{"class_definition"}. @end defvar -@defvar treesit-defun-prefer-top-level -If this variable is non-@code{nil}, Emacs skips nested defuns, when it -looks for beginning and end of a defun, and prefers to go to the -top-level defun instead. - -In some languages, a defun could be nested in another one. By default, -Emacs stops at the first defun it encounters. But if this variable's -value is @code{t}, whenever Emacs finds a defun node, it tries to go -up the parse tree until it finds the top-level defun. - -This variable can also be a list of cons cells of the form -@w{@code{(@var{from} . @var{to}))}}, where @var{from} and @var{to} are -regexps matching tree-sitter node types. When Emacs finds a defun -node whose type matches any of the @var{from} regexps in the list, it -then tries to go up the parse tree until it finds a higher-level node -matching the corresponding @var{to} regexp. +@defvar treesit-defun-tactic +This variable determines how does Emacs treat nested defuns. If the +value is @code{top-level}, navigation functions only move across +top-level defuns, if the value is @code{nested}, navigation functions +recognize nested defuns. @end defvar @node Skipping Characters commit 4ef12cfb1fc3f08fc17f0ed622ddfcb1d26cefc8 Author: Yuan Fu Date: Mon Jan 2 14:15:05 2023 -0800 ; Fix tree-sitter manual title case * doc/lispref/elisp.texi: * doc/lispref/modes.texi: * doc/lispref/parsing.texi: Change to title case. diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index fd06409fd59..c7dc330441f 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -1370,7 +1370,7 @@ Top * Accessing Node Information:: Accessing node information. * Pattern Matching:: Pattern matching with query patterns. * Multiple Languages:: Parse text written in multiple languages. -* Tree-sitter major modes:: Develop major modes using tree-sitter. +* Tree-sitter Major Modes:: Develop major modes using tree-sitter. * Tree-sitter C API:: Compare the C API and the ELisp API. Syntax Descriptors diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi index 9cd20532de6..dffd6653369 100644 --- a/doc/lispref/modes.texi +++ b/doc/lispref/modes.texi @@ -2863,10 +2863,10 @@ Imenu @var{name-fn} should be either @var{nil} or a function that takes a defun node and returns the name of that defun, e.g., the function name for a function definition. If @var{name-fn} is @var{nil}, -@code{treesit-defun-name} (@pxref{Tree-sitter major modes}) is used +@code{treesit-defun-name} (@pxref{Tree-sitter Major Modes}) is used instead. -@code{treesit-major-mode-setup} (@pxref{Tree-sitter major modes}) +@code{treesit-major-mode-setup} (@pxref{Tree-sitter Major Modes}) automatically sets up Imenu if this variable is non-@code{nil}. @end defvar diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 1ed59526a61..19a22c121de 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -45,7 +45,7 @@ Parsing Program Source * Accessing Node Information:: Accessing node information. * Pattern Matching:: Pattern matching with query patterns. * Multiple Languages:: Parse text written in multiple languages. -* Tree-sitter major modes:: Develop major modes using tree-sitter. +* Tree-sitter Major Modes:: Develop major modes using tree-sitter. * Tree-sitter C API:: Compare the C API and the ELisp API. @end menu @@ -1675,7 +1675,7 @@ Multiple Languages @code{treesit-language-at}. @end defvar -@node Tree-sitter major modes +@node Tree-sitter Major Modes @section Developing major modes with tree-sitter @cindex major mode, developing with tree-sitter commit 2ee6012b3faaf12710ec63626795148caeef0f6a Author: Paul Eggert Date: Mon Jan 2 10:00:41 2023 -0800 Improve interactive file-saving performance * src/fileio.c (init_fileio): No longer any need to set write-region-inhibit-fsync here. (syms_of_fileio): Default write-region-inhibit-fsync to t (Bug#60474). diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi index 6d666831612..6a9103d3a09 100644 --- a/doc/emacs/files.texi +++ b/doc/emacs/files.texi @@ -801,22 +801,21 @@ Customize Save @vindex write-region-inhibit-fsync Normally, when a program writes a file, the operating system briefly caches the file's data in main memory before committing the data to -disk. This can greatly improve performance; for example, when running -on laptops, it can avoid a disk spin-up each time a file is written. -However, it risks data loss if the operating system crashes before -committing the cache to disk. +secondary storage. Although this can greatly improve performance, it +risks data loss if the system loses power before committing the cache, +and on some platforms other processes might not immediately notice the +file's change. To lessen this risk, Emacs can invoke the @code{fsync} system call after saving a file. Using @code{fsync} does not eliminate the risk -of data loss, partly because many systems do not implement +of data loss or slow notification, partly because many systems do not support @code{fsync} properly, and partly because Emacs's file-saving procedure typically relies also on directory updates that might not survive a crash even if @code{fsync} works properly. The @code{write-region-inhibit-fsync} variable controls whether Emacs invokes @code{fsync} after saving a file. The variable's -default value is @code{nil} when Emacs is interactive, and @code{t} -when Emacs runs in batch mode (@pxref{Initial Options, Batch Mode}). +default value is @code{t}. Emacs never uses @code{fsync} when writing auto-save files, as these files might lose data anyway. diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 707af6ee64c..91643530f7f 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -692,11 +692,9 @@ Writing to Files @defvar write-region-inhibit-fsync If this variable's value is @code{nil}, @code{write-region} uses the -@code{fsync} system call after writing a file. Although this slows -Emacs down, it lessens the risk of data loss after power failure. If -the value is @code{t}, Emacs does not use @code{fsync}. The default -value is @code{nil} when Emacs is interactive, and @code{t} when Emacs -runs in batch mode. @xref{Files and Storage}. +@code{fsync} system call after writing a file. If the value is +@code{t}, Emacs does not use @code{fsync}. The default value is +@code{t}. @xref{Files and Storage}. @end defvar @defmac with-temp-file file body@dots{} @@ -2038,17 +2036,28 @@ Files and Storage the other is later modified; this will lose both files if the only copy on secondary storage is lost due to media failure. Second, the operating system might not write data to secondary storage -immediately, which will lose the data if power is lost. +immediately, which will lose the data if power is lost +or if there is a media failure. @findex write-region Although both sorts of failures can largely be avoided by a suitably -configured file system, such systems are typically more expensive or -less efficient. In more-typical systems, to survive media failure you +configured system, such systems are typically more expensive or +less efficient. In lower-end systems, to survive media failure you can copy the file to a different device, and to survive a power -failure you can use the @code{write-region} function with the +failure (or be immediately notified of a media failure) you can use +the @code{write-region} function with the @code{write-region-inhibit-fsync} variable set to @code{nil}. +Although this variable is ordinarily @code{t} because that can +significantly improve performance, it may make sense to temporarily +bind it to @code{nil} if using Emacs to implement database-like +transactions that survive power failure on lower-end systems. @xref{Writing to Files}. +On some platforms when Emacs changes a file other processes might not +be notified of the change immediately. Setting +@code{write-region-inhibit-fsync} to @code{nil} may improve +notification speed in this case, though there are no guarantees. + @node File Names @section File Names @cindex file names diff --git a/etc/NEWS b/etc/NEWS index eb68ce434b3..1ab6822da3f 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -41,6 +41,10 @@ compositing manager, Emacs will now redisplay such a frame even though 'frame-visible-' returns nil or 'icon' for it. This can happen, for example, as part of preview for iconified frames. ++++ +** 'write-region-inhibit-fsync' now defaults to t in interactive mode, +as it has in batch mode since Emacs 24. + * Editing Changes in Emacs 30.1 diff --git a/src/fileio.c b/src/fileio.c index 7fb7f5ddc5e..c672e0f7baf 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -6334,24 +6334,6 @@ init_fileio (void) umask (realmask); valid_timestamp_file_system = 0; - - /* fsync can be a significant performance hit. Often it doesn't - suffice to make the file-save operation survive a crash. For - batch scripts, which are typically part of larger shell commands - that don't fsync other files, its effect on performance can be - significant so its utility is particularly questionable. - Hence, for now by default fsync is used only when interactive. - - For more on why fsync often fails to work on today's hardware, see: - Zheng M et al. Understanding the robustness of SSDs under power fault. - 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84 - https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf - - For more on why fsync does not suffice even if it works properly, see: - Roche X. Necessary step(s) to synchronize filename operations on disk. - Austin Group Defect 672, 2013-03-19 - https://austingroupbugs.net/view.php?id=672 */ - write_region_inhibit_fsync = noninteractive; } void @@ -6609,9 +6591,22 @@ do (file-exists-p FILENAME) and FILENAME is handled by HANDLER, then DEFVAR_BOOL ("write-region-inhibit-fsync", write_region_inhibit_fsync, doc: /* Non-nil means don't call fsync in `write-region'. This variable affects calls to `write-region' as well as save commands. -Setting this to nil may avoid data loss if the system loses power or -the operating system crashes. By default, it is non-nil in batch mode. */); - write_region_inhibit_fsync = 0; /* See also `init_fileio' above. */ +By default, it is non-nil. + +Although setting this to nil may avoid data loss if the system loses power, +it can be a significant performance hit in the usual case, and it doesn't +necessarily cause file-save operations to actually survive a crash. */); + + /* For more on why fsync often fails to work on today's hardware, see: + Zheng M et al. Understanding the robustness of SSDs under power fault. + 11th USENIX Conf. on File and Storage Technologies, 2013 (FAST '13), 271-84 + https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf + + For more on why fsync does not suffice even if it works properly, see: + Roche X. Necessary step(s) to synchronize filename operations on disk. + Austin Group Defect 672, 2013-03-19 + https://austingroupbugs.net/view.php?id=672 */ + write_region_inhibit_fsync = true; DEFVAR_BOOL ("delete-by-moving-to-trash", delete_by_moving_to_trash, doc: /* Specifies whether to use the system's trash can. commit aab8ddca5e1bbbca0ab3d2241c34ccde7ebd6e1e Author: Eli Zaretskii Date: Mon Jan 2 20:56:52 2023 +0200 ; nt/INSTALL: Update for Emacs 29. diff --git a/nt/INSTALL b/nt/INSTALL index 2d973816e37..3b465ba494c 100644 --- a/nt/INSTALL +++ b/nt/INSTALL @@ -7,7 +7,7 @@ The MSYS/MinGW build described here is supported on versions of Windows starting with Windows XP and newer. Building on Windows 2000 and Windows 9X is not supported (but the Emacs binary produced by this -build will run on Windows 9X and newer systems). +build should run on Windows 9X and newer systems). Do not use this recipe with Cygwin. For building on Cygwin, use the normal installation instructions, ../INSTALL. @@ -87,7 +87,7 @@ build will run on Windows 9X and newer systems). Git for Windows is available from this download page: - https://github.com/git-for-windows/git/releases + https://gitforwindows.org/ That page offers both 32-bit and 64-bit installations; pick the one suitable for your OS. In general, we recommend to install a 64-bit @@ -139,7 +139,7 @@ build will run on Windows 9X and newer systems). like to mess with manual installations. You can download it from here: - https://sourceforge.net/projects/mingw/files/Installer/mingw-get/ + https://osdn.net/projects/mingw/releases (This installer only supports packages downloaded from the MinGW site; for the rest you will still need the manual method.) @@ -203,13 +203,13 @@ build will run on Windows 9X and newer systems). MinGW runtime and Windows API distributions, to compile Emacs. You can find these on the MinGW download/Base page: - https://sourceforge.net/projects/mingw/files/MinGW/Base/ + https://osdn.net/projects/mingw/releases In general, install the latest stable versions of the following MinGW packages from that page: gcc, binutils, mingw-rt, w32api. You only need the 'bin' and the 'dll' tarballs of each of the above. - MinGW packages are distributed as .tar.lzma compressed archives. To + MinGW packages are distributed as .tar.xz compressed archives. To install the packages manually, we recommend to use the Windows port of the 'bsdtar' program to unpack the tarballs. 'bsdtar' is available as part of the 'libarchive' package from here: @@ -598,8 +598,7 @@ build will run on Windows 9X and newer systems). * Optional image library support In addition to its "native" image formats (pbm and xbm), Emacs can - handle other image types: xpm, tiff, gif, png, jpeg, webp and - experimental support for svg. + handle other image types: xpm, tiff, gif, png, jpeg, webp and svg. To build Emacs with support for them, the corresponding headers must be in the include path and libraries should be where the linker @@ -846,6 +845,20 @@ build will run on Windows 9X and newer systems). from the MSYS2 project. If HarfBuzz is not available, Emacs will use the Uniscribe shaping engine that is part of MS-Windows. +* Optional support for accessing SQLite databases + + Emacs can support built-in access to SQLite databases, if compiled + with the sqlite3 library. Prebuilt 32-bit binaries of that library + are available from the ezwinports site. + +* Optional support for tree-sitter + + Emacs can be built with the tree-sitter incremental parsing library, + which enables editing of program sources written in various + programming languages based on the tree-sitter parsers. Prebuilt + 32-bit binaries of the tree-sitter library DLL and of several + language grammar libraries are available from the ezwinports site. + This file is part of GNU Emacs. commit 809fbb0e8c419d670b045f506e90614ad00fda55 Author: Michael Albinus Date: Mon Jan 2 19:50:07 2023 +0100 ; Update copyright notice in tramp-sh.el * lisp/net/tramp-sh.el (tramp-perl-encode, tramp-perl-decode): Remove copyright notice, Tramp is copyrighted by FSF anyway. diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el index 97867bf9999..ec8437176db 100644 --- a/lisp/net/tramp-sh.el +++ b/lisp/net/tramp-sh.el @@ -838,7 +838,6 @@ tramp-perl-decode-with-module (defconst tramp-perl-encode "%p -e ' # This script contributed by Juanma Barranquero . -# Copyright (C) 2002-2022 Free Software Foundation, Inc. use strict; my %%trans = do { @@ -877,7 +876,6 @@ tramp-perl-encode (defconst tramp-perl-decode "%p -e ' # This script contributed by Juanma Barranquero . -# Copyright (C) 2002-2022 Free Software Foundation, Inc. use strict; my %%trans = do { commit f8f5202487c0909a253228e63a64ba17d9c459da Author: Dmitry Gutov Date: Mon Jan 2 20:42:52 2023 +0200 (typescript/tsx-ts-mode): Split font-lock feature list into 4 values * lisp/progmodes/typescript-ts-mode.el (typescript-ts-mode) (tsx-ts-mode): Split font-lock feature list into 4 values. diff --git a/lisp/progmodes/typescript-ts-mode.el b/lisp/progmodes/typescript-ts-mode.el index d3266134500..a0ba425b3e9 100644 --- a/lisp/progmodes/typescript-ts-mode.el +++ b/lisp/progmodes/typescript-ts-mode.el @@ -374,7 +374,8 @@ typescript-ts-mode (setq-local treesit-font-lock-settings (typescript-ts-mode--font-lock-settings 'typescript)) (setq-local treesit-font-lock-feature-list - '((comment declaration keyword string escape-sequence) + '((comment declaration) + (keyword string escape-sequence) (constant expression identifier number pattern property) (bracket delimiter))) @@ -408,7 +409,8 @@ tsx-ts-mode (setq-local treesit-font-lock-settings (typescript-ts-mode--font-lock-settings 'tsx)) (setq-local treesit-font-lock-feature-list - '((comment declaration keyword string escape-sequence) + '((comment declaration) + (keyword string escape-sequence) (constant expression identifier jsx number pattern property) (bracket delimiter))) commit a86a213e1ac6439557703ab6a3a1294160ffcdc2 Author: Dmitry Gutov Date: Mon Jan 2 19:59:50 2023 +0200 js-ts-mode: Move 'string-interpolation' to font-lock level 3 * lisp/progmodes/js.el (js-ts-mode): Move 'string-interpolation' to font-lock level 3. diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el index 501c0599e89..c5fdecae71b 100644 --- a/lisp/progmodes/js.el +++ b/lisp/progmodes/js.el @@ -3817,9 +3817,8 @@ js-ts-mode '(( comment definition) ( keyword string) ( assignment constant escape-sequence jsx number - pattern) - ( bracket delimiter function operator property - string-interpolation))) + pattern string-interpolation) + ( bracket delimiter function operator property))) ;; Imenu (setq-local treesit-simple-imenu-settings `(("Function" "\\`function_declaration\\'" nil nil) commit d26b523886ee52548648ca660fc2933eadf49a55 Author: Eli Zaretskii Date: Mon Jan 2 17:02:05 2023 +0200 Fix shrinking of the tab-bar * src/haikufns.c (haiku_change_tab_bar_height): * src/pgtkfns.c (pgtk_change_tab_bar_height): * src/nsfns.m (ns_change_tab_bar_height): * src/w32fns.c (w32_change_tab_bar_height): * src/xfns.c (x_change_tab_bar_height): Don't let the number of tab-bar lines degenerate to zero due to integer division. (Bug#60210) diff --git a/src/haikufns.c b/src/haikufns.c index 59332346dab..b591c143900 100644 --- a/src/haikufns.c +++ b/src/haikufns.c @@ -175,19 +175,17 @@ haiku_change_tool_bar_height (struct frame *f, int height) void haiku_change_tab_bar_height (struct frame *f, int height) { - int unit, old_height, lines; - Lisp_Object fullscreen; - - unit = FRAME_LINE_HEIGHT (f); - old_height = FRAME_TAB_BAR_HEIGHT (f); - fullscreen = get_frame_param (f, Qfullscreen); + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TAB_BAR_HEIGHT (f); /* This differs from the tool bar code in that the tab bar height is not rounded up. Otherwise, if redisplay_tab_bar decides to grow the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, leading to the tab bar height being incorrectly set upon the next call to x_set_font. (bug#59285) */ - lines = height / unit; + int lines = height / unit; + if (lines == 0 && height != 0) + lines = 1; /* Make sure we redisplay all windows in this frame. */ fset_redisplay (f); @@ -208,6 +206,8 @@ haiku_change_tab_bar_height (struct frame *f, int height) if (!f->tab_bar_resized) { + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + /* As long as tab_bar_resized is false, effectively try to change F's native height. */ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) diff --git a/src/nsfns.m b/src/nsfns.m index 8c78657db50..8804a7df7cf 100644 --- a/src/nsfns.m +++ b/src/nsfns.m @@ -632,19 +632,17 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. void ns_change_tab_bar_height (struct frame *f, int height) { - int unit, old_height, lines; - Lisp_Object fullscreen; - - unit = FRAME_LINE_HEIGHT (f); - old_height = FRAME_TAB_BAR_HEIGHT (f); - fullscreen = get_frame_param (f, Qfullscreen); + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TAB_BAR_HEIGHT (f); /* This differs from the tool bar code in that the tab bar height is not rounded up. Otherwise, if redisplay_tab_bar decides to grow the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, leading to the tab bar height being incorrectly set upon the next call to x_set_font. (bug#59285) */ - lines = height / unit; + int lines = height / unit; + if (lines == 0 && height != 0) + lines = 1; /* Make sure we redisplay all windows in this frame. */ fset_redisplay (f); @@ -665,6 +663,8 @@ Turn the input menu (an NSMenu) into a lisp list for tracking on lisp side. if (!f->tab_bar_resized) { + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + /* As long as tab_bar_resized is false, effectively try to change F's native height. */ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) diff --git a/src/pgtkfns.c b/src/pgtkfns.c index 57591d2693c..6b3a0459d36 100644 --- a/src/pgtkfns.c +++ b/src/pgtkfns.c @@ -473,19 +473,17 @@ pgtk_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) void pgtk_change_tab_bar_height (struct frame *f, int height) { - int unit, old_height, lines; - Lisp_Object fullscreen; - - unit = FRAME_LINE_HEIGHT (f); - old_height = FRAME_TAB_BAR_HEIGHT (f); - fullscreen = get_frame_param (f, Qfullscreen); + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TAB_BAR_HEIGHT (f); /* This differs from the tool bar code in that the tab bar height is not rounded up. Otherwise, if redisplay_tab_bar decides to grow the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, leading to the tab bar height being incorrectly set upon the next call to x_set_font. (bug#59285) */ - lines = height / unit; + int lines = height / unit; + if (lines == 0 && height != 0) + lines = 1; /* Make sure we redisplay all windows in this frame. */ fset_redisplay (f); @@ -506,6 +504,8 @@ pgtk_change_tab_bar_height (struct frame *f, int height) if (!f->tab_bar_resized) { + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + /* As long as tab_bar_resized is false, effectively try to change F's native height. */ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) diff --git a/src/w32fns.c b/src/w32fns.c index 9d02e680fe8..192d3ddf27a 100644 --- a/src/w32fns.c +++ b/src/w32fns.c @@ -1717,19 +1717,17 @@ w32_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) void w32_change_tab_bar_height (struct frame *f, int height) { - int unit, old_height, lines; - Lisp_Object fullscreen; - - unit = FRAME_LINE_HEIGHT (f); - old_height = FRAME_TAB_BAR_HEIGHT (f); - fullscreen = get_frame_param (f, Qfullscreen); + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TAB_BAR_HEIGHT (f); /* This differs from the tool bar code in that the tab bar height is not rounded up. Otherwise, if redisplay_tab_bar decides to grow the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, leading to the tab bar height being incorrectly set upon the next call to x_set_font. (bug#59285) */ - lines = height / unit; + int lines = height / unit; + if (lines == 0 && height != 0) + lines = 1; /* Make sure we redisplay all windows in this frame. */ fset_redisplay (f); @@ -1758,6 +1756,8 @@ w32_change_tab_bar_height (struct frame *f, int height) if (!f->tab_bar_resized) { + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + /* As long as tab_bar_resized is false, effectively try to change F's native height. */ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) diff --git a/src/xfns.c b/src/xfns.c index a1984f9e8f8..528ae61ca32 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -1758,19 +1758,17 @@ x_set_tab_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval) void x_change_tab_bar_height (struct frame *f, int height) { - int unit, old_height, lines; - Lisp_Object fullscreen; - - unit = FRAME_LINE_HEIGHT (f); - old_height = FRAME_TAB_BAR_HEIGHT (f); - fullscreen = get_frame_param (f, Qfullscreen); + int unit = FRAME_LINE_HEIGHT (f); + int old_height = FRAME_TAB_BAR_HEIGHT (f); /* This differs from the tool bar code in that the tab bar height is not rounded up. Otherwise, if redisplay_tab_bar decides to grow the tab bar by even 1 pixel, FRAME_TAB_BAR_LINES will be changed, leading to the tab bar height being incorrectly set upon the next call to x_set_font. (bug#59285) */ - lines = height / unit; + int lines = height / unit; + if (lines == 0 && height != 0) + lines = 1; /* Make sure we redisplay all windows in this frame. */ fset_redisplay (f); @@ -1791,6 +1789,8 @@ x_change_tab_bar_height (struct frame *f, int height) if (!f->tab_bar_resized) { + Lisp_Object fullscreen = get_frame_param (f, Qfullscreen); + /* As long as tab_bar_resized is false, effectively try to change F's native height. */ if (NILP (fullscreen) || EQ (fullscreen, Qfullwidth)) commit 3f7ea621b9008bc507048ee23466f3259b6b620d Author: Stefan Kangas Date: Mon Jan 2 15:17:59 2023 +0100 ; Fix typos in ruby-ts-mode.el diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 5c9a25c1fde..26d0fc49260 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -23,7 +23,7 @@ ;;; Commentary: -;; This file defines ruby-ts-mode which is a major mode for editting +;; This file defines ruby-ts-mode which is a major mode for editing ;; Ruby files that uses Tree Sitter to parse the language. More ;; information about Tree Sitter can be found in the ELisp Info pages ;; as well as this website: https://tree-sitter.github.io/tree-sitter/ @@ -150,7 +150,7 @@ ruby-ts--statement-container-regexp "parenthesized_statements" "interpolation") string-end) - "Regular expression of the nodes that can constain statements.") + "Regular expression of the nodes that can contain statements.") (defun ruby-ts--lineno (node) "Return line number of NODE's start." @@ -178,7 +178,7 @@ ruby-ts--comment-font-lock Applies `font-lock-comment-delimiter-face' and `font-lock-comment-face' See `treesit-fontify-with-override' for values of OVERRIDE" - ;; Emperically it appears as if (treesit-node-start node) will be + ;; Empirically it appears as if (treesit-node-start node) will be ;; where the # character is at and (treesit-node-end node) will be ;; the end of the line (let* ((node-start (treesit-node-start node)) @@ -717,7 +717,7 @@ ruby-ts--indent-rules ((n-p-gp ,ruby-ts--method-regex "body_statement" ,ruby-ts--class-or-module-regex) (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) - ;; Match the end of a class / modlue + ;; Match the end of a class / module ((match "end" ,ruby-ts--class-or-module-regex) parent 0) ;; A "do_block" has a "body_statement" child which has the commit 9599b054316db2e727e505fd9770f5a9faf173be Author: Stefan Kangas Date: Mon Jan 2 14:58:37 2023 +0100 ; Skip ruby-ts tests if grammar is not available * test/lisp/progmodes/ruby-ts-mode-tests.el: Properly skip tests if there is no grammar for ruby. diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el b/test/lisp/progmodes/ruby-ts-mode-tests.el index f48d0bf6330..aa1ab1e2605 100644 --- a/test/lisp/progmodes/ruby-ts-mode-tests.el +++ b/test/lisp/progmodes/ruby-ts-mode-tests.el @@ -44,7 +44,7 @@ ruby-ts-test-string (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) (ert-deftest ruby-ts-indent-simple () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-should-indent-buffer "if foo | bar @@ -58,7 +58,7 @@ ruby-ts-indent-simple |")) (ert-deftest ruby-ts-align-to-stmt-keywords-t () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (let ((ruby-align-to-stmt-keywords t)) (ruby-ts-should-indent-buffer "foo = if bar? @@ -94,7 +94,7 @@ ruby-ts-align-to-stmt-keywords-t )) (ert-deftest ruby-ts-align-to-stmt-keywords-case () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (let ((ruby-align-to-stmt-keywords '(case))) (ruby-ts-should-indent-buffer "b = case a @@ -111,7 +111,7 @@ ruby-ts-align-to-stmt-keywords-case | end"))) (ert-deftest ruby-ts-add-log-current-method-examples () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (let ((pairs '(("foo" . "#foo") ("C.foo" . ".foo") ("self.foo" . ".foo") @@ -134,7 +134,7 @@ ruby-ts-add-log-current-method-examples (format "M::C%s" value)))))))) (ert-deftest ruby-ts-add-log-current-method-outside-of-method () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "module M | class C @@ -147,7 +147,7 @@ ruby-ts-add-log-current-method-outside-of-method (should (string= (ruby-ts-add-log-current-function) "M::C")))) (ert-deftest ruby-ts-add-log-current-method-in-singleton-class () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "class C | class << self @@ -160,7 +160,7 @@ ruby-ts-add-log-current-method-in-singleton-class (should (string= (ruby-ts-add-log-current-function) "C.foo")))) (ert-deftest ruby-ts-add-log-current-method-namespace-shorthand () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "class C::D | def foo @@ -171,7 +171,7 @@ ruby-ts-add-log-current-method-namespace-shorthand (should (string= (ruby-ts-add-log-current-function) "C::D#foo")))) (ert-deftest ruby-ts-add-log-current-method-after-inner-class () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "module M | class C @@ -186,7 +186,7 @@ ruby-ts-add-log-current-method-after-inner-class (should (string= (ruby-ts-add-log-current-function) "M::C#foo")))) (ert-deftest ruby-ts-add-log-current-method-after-inner-class-outside-methods () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "module M | class C @@ -201,7 +201,7 @@ ruby-ts-add-log-current-method-after-inner-class-outside-methods (should (string= (ruby-ts-add-log-current-function) "M::C")))) (ert-deftest ruby-ts-add-log-current-method-after-inner-class-outside-methods-with-text () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "module M | class C @@ -215,7 +215,7 @@ ruby-ts-add-log-current-method-after-inner-class-outside-methods-with-text (should (string= (ruby-ts-add-log-current-function) "M::C")))) (ert-deftest ruby-ts-add-log-current-method-after-endless-method () - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (ruby-ts-with-temp-buffer (ruby-ts-test-string "module M | class C @@ -237,7 +237,7 @@ ruby-ts-resource-file (defmacro ruby-ts-deftest-indent (file) `(ert-deftest ,(intern (format "ruby-ts-indent-test/%s" file)) () ;; :tags '(:expensive-test) - (skip-unless (treesit-available-p)) + (skip-unless (treesit-ready-p 'ruby t)) (let ((buf (find-file-noselect (ruby-ts-resource-file ,file)))) (unwind-protect (with-current-buffer buf commit ff35ac9dfabf7ac33199c42bc56c8bb0f53eebc4 Author: F. Jason Park Date: Thu Dec 29 06:43:19 2022 -0800 Fix default-port regression in erc-select-read-args * lisp/erc/erc.el (erc--warn-unencrypted): New function, likely temporary, to warn new users connecting interactively to the default server, "irc.libara.chat", via the default non-TLS port, 6667. (erc-select-read-args): Remove stray code from incomplete feature introduced by bug#56514. Ensure connecting always works with default port, which is non-TLS. Respect `erc-prompt-for-password' when user pastes URL containing password component into "server" prompt. Maybe add `erc--warn-unencrypted' as one-off hook for impending connection. * test/lisp/erc/erc-tests.el (erc-select-read-args): Always expect password prompt and sometimes a non-TLS port when `erc' called interactively. (Bug#60428.) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index fe1201dd3a8..6315d5aa482 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2161,6 +2161,23 @@ erc--ensure-url (setq input (concat "irc://" input))) input) +;; A temporary means of addressing the problem of ERC's namesake entry +;; point defaulting to a non-TLS connection with its default server +;; (bug#60428). +(defun erc--warn-unencrypted () + ;; Remove unconditionally to avoid wrong context due to races from + ;; simultaneous dialing or aborting (e.g., via `keybaord-quit'). + (remove-hook 'erc--server-post-connect-hook #'erc--warn-unencrypted) + (when (and (process-contact erc-server-process :nowait) + (equal erc-session-server erc-default-server) + (eql erc-session-port erc-default-port)) + ;; FIXME use the autoloaded `info' instead of `Info-goto-node' in + ;; `erc-button-alist'. + (require 'info nil t) + (erc-display-error-notice + nil (concat "This connection is unencrypted. Please use `erc-tls'" + " from now on. See Info:\"(erc) connecting\" for more.")))) + ;;;###autoload (defun erc-select-read-args () "Prompt the user for values of nick, server, port, and password." @@ -2171,10 +2188,7 @@ erc-select-read-args ;; For legacy reasons, also accept a URL without a scheme. (url (url-generic-parse-url (erc--ensure-url input))) (server (url-host url)) - (sp (and (or (string-suffix-p "s" (url-type url)) - (and (equal server erc-default-server) - (not (string-prefix-p "irc://" input)))) - 'ircs-u)) + (sp (and (string-suffix-p "s" (url-type url)) erc-default-port-tls)) (port (or (url-portspec url) (erc-compute-port (let ((d (erc-compute-port sp))) ; may be a string @@ -2187,13 +2201,19 @@ erc-select-read-args (let ((d (erc-compute-nick))) (read-string (format "Nickname (default is %S): " d) nil 'erc-nick-history-list d)))) - (passwd (or (url-password url) - (if erc-prompt-for-password - (read-passwd "Server password (optional): ") - (with-suppressed-warnings ((obsolete erc-password)) - erc-password))))) + (passwd (let* ((p (with-suppressed-warnings ((obsolete erc-password)) + (or (url-password url) erc-password))) + (m (if p + (format "Server password (default is %S): " p) + "Server password (optional): "))) + (if erc-prompt-for-password (read-passwd m nil p) p)))) (when (and passwd (string= "" passwd)) (setq passwd nil)) + (when (and (equal server erc-default-server) + (eql port erc-default-port) + (not (eql port erc-default-port-tls)) ; not `erc-tls' + (not (string-prefix-p "irc://" input))) ; not yanked URL + (add-hook 'erc--server-post-connect-hook #'erc--warn-unencrypted)) (list :server server :port port :nick nick :password passwd))) ;;;###autoload diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el index 6807b24bfc6..85506c3d27e 100644 --- a/test/lisp/erc/erc-tests.el +++ b/test/lisp/erc/erc-tests.el @@ -1001,11 +1001,11 @@ erc--server-connect-dumb-ipv6-regexp (ert-deftest erc-select-read-args () - (ert-info ("Defaults to TLS") + (ert-info ("Does not default to TLS") (should (equal (ert-simulate-keys "\r\r\r\r" (erc-select-read-args)) (list :server "irc.libera.chat" - :port 6697 + :port 6667 :nick (user-login-name) :password nil)))) @@ -1036,7 +1036,7 @@ erc-select-read-args :password nil)))) (ert-info ("Address includes nick and password") - (should (equal (ert-simulate-keys "nick:sesame@localhost:6667\r" + (should (equal (ert-simulate-keys "nick:sesame@localhost:6667\r\r" (erc-select-read-args)) (list :server "localhost" :port 6667 commit b7ad0b40148bd5905497a4c05fced4e0b9099812 Author: Eli Zaretskii Date: Mon Jan 2 13:52:25 2023 +0200 ; Clarify doc strings of 'call-process' and 'call-process-region' * src/callproc.c (Fcall_process, Fcall_process_region): Document that the destination buffer can be specified by its name. (Bug#60477) diff --git a/src/callproc.c b/src/callproc.c index 7208ceb5d2f..5e1e1a8cc0a 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -259,8 +259,8 @@ DEFUN ("call-process", Fcall_process, Scall_process, 1, MANY, 0, Third argument DESTINATION specifies how to handle program's output. (\"Output\" here means both standard output and standard error output.) -If DESTINATION is a buffer, or t that stands for the current buffer, - it means insert output in that buffer before point. +If DESTINATION is a buffer or the name of a buffer, or t (which stands for +the current buffer), it means insert output in that buffer before point. If DESTINATION is nil, it means discard output; 0 means discard and don't wait for the program to terminate. If DESTINATION is `(:file FILE)', where FILE is a file name string, @@ -1055,6 +1055,7 @@ DEFUN ("call-process-region", Fcall_process_region, Scall_process_region, BUFFER means discard it; 0 means discard and don't wait; and `(:file FILE)', where FILE is a file name string, means that it should be written to that file (if the file already exists it is overwritten). +BUFFER can be a string which is the name of a buffer. BUFFER can also have the form (REAL-BUFFER STDERR-FILE); in that case, REAL-BUFFER says what to do with standard output, as above, while STDERR-FILE says what to do with standard error in the child. commit c209802f7b3721a1b95113290934a23fee88f678 Merge: 9377a3c889a 4520f09dd8b Author: Stefan Kangas Date: Mon Jan 2 12:06:37 2023 +0100 Merge from origin/emacs-29 4520f09dd8b ; * admin/git-bisect-start: Update failing commits 2569ede9c49 Update to Org 9.6-81-g563a43 d9ed736f0a7 ruby-ts-mode: Remove some currently unused functions 45618447203 ruby-ts-mode: Highlight singleton method definitions and ... 0562006da3b Add ruby-ts-mode 84e7c2fbc85 Fix fontification of C++ reference return types (bug#60441) 1864b65af60 ; Minor fix for treesit--install-language-grammar-1 (bug#... 8994f87ad40 Adjust function-call fontification in csharp-ts-mode (bug... 411647a3f65 ; Fix NEWS. 7b0b17df67e Rewrite Antinews in ELisp manual for Emacs 29 f12f72b0e09 ; * lisp/simple.el (primitive-undo): Clarify error messag... 7fd822e7f52 Update Antinews in the user manual for Emacs 29 da77d70deeb ; * test/lisp/emacs-lisp/copyright-tests.el: Fix and futu... 2baf9e107c1 Fix shortdoc-tests failure with respect to regexp-opt-cha... 5aeb8de32ee ; Fix copyright years in 2 more files. # Conflicts: # etc/NEWS commit 4520f09dd8bc9a0014d6afd0f76c2c77dcb2e5a0 Author: Gregory Heytings Date: Mon Jan 2 09:58:23 2023 +0000 ; * admin/git-bisect-start: Update failing commits diff --git a/admin/git-bisect-start b/admin/git-bisect-start index 6015b6b2917..a439ee7fe15 100755 --- a/admin/git-bisect-start +++ b/admin/git-bisect-start @@ -82,7 +82,7 @@ done # SKIP-BRANCH 58cc931e92ece70c3e64131ee12a799d65409100 ## The list below is the exhaustive list of all commits between Dec 1 -## 2016 and Nov 30 2022 on which building Emacs with the default +## 2016 and Dec 31 2022 on which building Emacs with the default ## options, on a GNU/Linux computer and with GCC, fails. It is ## possible (though unlikely) that building Emacs with non-default ## options, with other compilers, or on other platforms, would succeed @@ -1637,3 +1637,40 @@ $REAL_GIT bisect skip $(cat $0 | grep '^# SKIP-SINGLE ' | sed 's/^# SKIP-SINGLE # SKIP-SINGLE 4552b01d8c8052f607dca2fcddcf7b2e270f1db6 # SKIP-SINGLE b6568c1389128d47538b646d940427949ddf58d0 # SKIP-SINGLE 6d5b34d9de7b2f1b346d9aff123ad20c942166dc +# SKIP-SINGLE d9d90666f545dc25be63c1b16c030ce1aa96510e +# SKIP-SINGLE e645bcc26d468ab6b8e16b6160c203c5db70ec6b +# SKIP-SINGLE 0aea1cf8190aa804a0d11a67b4a3cb4b715ae82d +# SKIP-SINGLE 7e6d1d1c47196bf1bb5254f5c9014e25bdaf9833 +# SKIP-SINGLE 784e509bded0fe41dd9908022a92c54ac8c21a2c +# SKIP-SINGLE bc4cbbcc57a56a23c64576c8c23ecf6afb1c747b +# SKIP-SINGLE 523261b454058d0b28df2c3de1eab55fe378aa69 +# SKIP-SINGLE 29d23b7fa00ed8263baa060d487b526d51fa6986 +# SKIP-SINGLE 9371d488be62a37788b499a7e44b1f5db158e212 +# SKIP-SINGLE 60418e6f09c67924e3e05eb4948e109d8f7c4073 +# SKIP-SINGLE 9153cf8158489d387a6a0d9d0ede9a2528c35f0a +# SKIP-SINGLE d11e34ce76aac8680337f247419657e042e4cf34 +# SKIP-SINGLE 2541bec21bf3cf090071e434dac170d52394594e +# SKIP-SINGLE 007e66bccb2cb8382158e5e24727fd1b4478cd69 +# SKIP-SINGLE 753b7a1cff6b8ce2367a94d27b615ac31f1067ba +# SKIP-SINGLE 7c63b632e4e2241a28f08015cc981a72e18d7867 +# SKIP-SINGLE 91ae9f3d12885373d38c3e8d693f7dc210f9d471 +# SKIP-SINGLE 314cbef84944145e2160736ce32812403ed99cd9 +# SKIP-SINGLE 1a88a28ace24c8b4fb1e4780948b50dd37ada539 +# SKIP-SINGLE 98327e371938033f7ccefd1c5226cd102cb29ad1 +# SKIP-SINGLE 9d814bea4600ac28dcdbf9caf386467551d7d9be +# SKIP-SINGLE 73769dc2b872441eb0b8565e1090e97fc0b5d521 +# SKIP-SINGLE 283043621756fd004906ecdd5ba829a47cb3fc57 +# SKIP-SINGLE 05ece1eb8b7ce28d366d02df89449d453be8d37e +# SKIP-SINGLE 248c13dcfe1b9618811a6fe67e967b25b1a8f139 +# SKIP-SINGLE 38c35bf0f6a938001dfecbe439addf8fb62897c6 +# SKIP-SINGLE 9065d745151e1995b80a1f4d5a04e2af111ad928 +# SKIP-SINGLE e78e69b33189c653d1588b810283969ac3cca137 +# SKIP-SINGLE 909091d7578b7225601b202fb9257dedae879e9a +# SKIP-SINGLE 706ed85285515e7047e16608815c1d02d4907b07 +# SKIP-SINGLE 7013b0179cbe5cce19e114d7673770d1425d3005 +# SKIP-SINGLE 2de25accaf31aef643557ec476041c770fc7ac15 +# SKIP-SINGLE 2b1fdbffcb595bcd72fa9aa3db674c6985042bcb +# SKIP-SINGLE 1480865e641b06d570f5ab56011f8e3e5481da7d +# SKIP-SINGLE 8c13e8497821881b5197a1717e9e53b9991859d0 +# SKIP-SINGLE a6db8464e150c49724c71c5969b97f205ee2dec5 +# SKIP-SINGLE cfbfd393b450d4eb7ac0b7922b44208688553c9e commit 2569ede9c496bb060e0b88428cb541088aaba1f9 Author: Kyle Meyer Date: Sun Jan 1 22:24:28 2023 -0500 Update to Org 9.6-81-g563a43 diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS index 62c918564d2..d610a63b09d 100644 --- a/etc/ORG-NEWS +++ b/etc/ORG-NEWS @@ -24,7 +24,7 @@ the time being. It will be removed in the next release. See https://orgmode.org/list/87r0yk7bx8.fsf@localhost for more details. -*** Element cache is enabled by default and work for headings +*** Element cache is enabled by default and works for headings The old element cache code has been refactored. Emacs does not hang anymore when the cache is enabled. diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el index dacf420bd1c..9bb77f7920b 100644 --- a/lisp/org/ob-core.el +++ b/lisp/org/ob-core.el @@ -2461,13 +2461,18 @@ org-babel-insert-result (insert (org-trim (org-list-to-org + ;; We arbitrarily choose to format non-strings + ;; as %S. (cons 'unordered (mapcar (lambda (e) (cond ((stringp e) (list e)) ((listp e) - (mapcar (lambda (x) (format "%S" x)) e)) + (mapcar + (lambda (x) + (if (stringp x) x (format "%S" x))) + e)) (t (list (format "%S" e))))) (if (listp result) result (split-string result "\n" t)))) diff --git a/lisp/org/org-agenda.el b/lisp/org/org-agenda.el index 3376dbc1140..66b08adf535 100644 --- a/lisp/org/org-agenda.el +++ b/lisp/org/org-agenda.el @@ -3477,14 +3477,14 @@ org-fix-agenda-info (setq props (plist-put props 'tags (mapconcat #'identity tmp ":")))) (when (setq tmp (plist-get props 'date)) (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) - (let ((calendar-date-display-form '(year "-" month "-" day))) - '((format "%4d, %9s %2s, %4s" dayname monthname day year)) - + (let ((calendar-date-display-form + '(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left)))) (setq tmp (calendar-date-string tmp))) (setq props (plist-put props 'date tmp))) (when (setq tmp (plist-get props 'day)) (when (integerp tmp) (setq tmp (calendar-gregorian-from-absolute tmp))) - (let ((calendar-date-display-form '(year "-" month "-" day))) + (let ((calendar-date-display-form + '(year "-" (string-pad month 2 ?0 'left) "-" (string-pad day 2 ?0 'left)))) (setq tmp (calendar-date-string tmp))) (setq props (plist-put props 'day tmp)) (setq props (plist-put props 'agenda-day tmp))) @@ -4678,7 +4678,7 @@ org-search-view (org-agenda-text-search-extra-files org-agenda-text-search-extra-files) regexp rtn rtnall files file pos inherited-tags marker category level tags c neg re boolean - ee txt beg end words regexps+ regexps- hdl-only buffer beg1 str) + ee txt beg end last-search-end words regexps+ regexps- hdl-only buffer beg1 str) (unless (and (not edit-at) (stringp string) (string-match "\\S-" string)) @@ -4817,6 +4817,7 @@ org-search-view (throw 'nextfile t)) (goto-char (max (point-min) (1- (point)))) (while (re-search-forward regexp nil t) + (setq last-search-end (point)) (org-back-to-heading t) (while (and (not (zerop org-agenda-search-view-max-outline-level)) (> (org-reduced-level (org-outline-level)) @@ -4878,7 +4879,7 @@ org-search-view 'priority 1000 'type "search") (push txt ee) - (goto-char (1- end)))))))))) + (goto-char (max (1- end) last-search-end)))))))))) (setq rtn (nreverse ee)) (setq rtnall (append rtnall rtn))) (org-agenda--insert-overriding-header diff --git a/lisp/org/org-cycle.el b/lisp/org/org-cycle.el index f4d84f5058f..828c84cd0ac 100644 --- a/lisp/org/org-cycle.el +++ b/lisp/org/org-cycle.el @@ -1,6 +1,6 @@ ;;; org-cycle.el --- Visibility cycling of Org entries -*- lexical-binding: t; -*- ;; -;; Copyright (C) 2020, 2023-2020 Free Software Foundation, Inc. +;; Copyright (C) 2020-2023 Free Software Foundation, Inc. ;; ;; Maintainer: Ihor Radchenko ;; Keywords: folding, visibility cycling, invisible text diff --git a/lisp/org/org-fold-core.el b/lisp/org/org-fold-core.el index 4f737af4ef5..0855e6f39ce 100644 --- a/lisp/org/org-fold-core.el +++ b/lisp/org/org-fold-core.el @@ -1,6 +1,6 @@ ;;; org-fold-core.el --- Folding buffer text -*- lexical-binding: t; -*- ;; -;; Copyright (C) 2020, 2023-2020 Free Software Foundation, Inc. +;; Copyright (C) 2020-2023 Free Software Foundation, Inc. ;; ;; Author: Ihor Radchenko ;; Keywords: folding, invisible text diff --git a/lisp/org/org-fold.el b/lisp/org/org-fold.el index 93429bb3025..1b7ca22b044 100644 --- a/lisp/org/org-fold.el +++ b/lisp/org/org-fold.el @@ -1,6 +1,6 @@ ;;; org-fold.el --- Folding of Org entries -*- lexical-binding: t; -*- ;; -;; Copyright (C) 2020, 2023-2020 Free Software Foundation, Inc. +;; Copyright (C) 2020-2023 Free Software Foundation, Inc. ;; ;; Author: Ihor Radchenko ;; Keywords: folding, invisible text diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el index b09be05b7c3..72929cdd26c 100644 --- a/lisp/org/org-macs.el +++ b/lisp/org/org-macs.el @@ -74,11 +74,15 @@ org-assert-version loading of the newer Org version. It is recommended to put - (straight-use-package 'org) + + %s + early in the config. Ideally, right after the straight.el bootstrap. Moving `use-package' :straight declaration may not be sufficient if the corresponding `use-package' statement is - deferring the loading.") + deferring the loading." + ;; Avoid `warn' replacing "'" with "’" (see `format-message'). + "(straight-use-package 'org)") (error "Org version mismatch. Make sure that correct `load-path' is set early in init.el"))) ;; We rely on org-macs when generating Org version. Checking Org diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el index 8acf678d427..c3650c167e2 100644 --- a/lisp/org/org-persist.el +++ b/lisp/org/org-persist.el @@ -161,7 +161,7 @@ (declare-function org-at-heading-p "org" (&optional invisible-not-ok)) -(defconst org-persist--storage-version "2.7" +(defconst org-persist--storage-version "3.1" "Persistent storage layout version.") (defgroup org-persist nil @@ -431,25 +431,27 @@ org-persist--remove-from-index (when key (remhash (cons cont (list :key key)) org-persist--index-hash)))) (setq org-persist--index (delq existing org-persist--index))))) -(defun org-persist--get-collection (container &optional associated &rest misc) +(defun org-persist--get-collection (container &optional associated misc) "Return or create collection used to store CONTAINER for ASSOCIATED. When ASSOCIATED is nil, it is a global CONTAINER. ASSOCIATED can also be a (:buffer buffer) or buffer, (:file file-path) or file-path, (:inode inode), (:hash hash), or or (:key key). -MISC, if non-nil will be appended to the collection." +MISC, if non-nil will be appended to the collection. It must be a plist." (unless (and (listp container) (listp (car container))) (setq container (list container))) (setq associated (org-persist--normalize-associated associated)) - (unless (equal misc '(nil)) - (setq associated (append associated misc))) + (when (and misc (or (not (listp misc)) (= 1 (% (length misc) 2)))) + (error "org-persist: Not a plist: %S" misc)) (or (org-persist--find-index `( :container ,(org-persist--normalize-container container) :associated ,associated)) (org-persist--add-to-index - (list :container (org-persist--normalize-container container) - :persist-file - (replace-regexp-in-string "^.." "\\&/" (org-id-uuid)) - :associated associated)))) + (nconc + (list :container (org-persist--normalize-container container) + :persist-file + (replace-regexp-in-string "^.." "\\&/" (org-id-uuid)) + :associated associated) + misc)))) ;;;; Reading container data. @@ -650,9 +652,10 @@ org-persist-write:file (file-copy (org-file-name-concat org-persist-directory (format "%s-%s.%s" persist-file (md5 path) ext)))) - (unless (file-exists-p (file-name-directory file-copy)) - (make-directory (file-name-directory file-copy) t)) - (copy-file path file-copy 'overwrite) + (unless (file-exists-p file-copy) + (unless (file-exists-p (file-name-directory file-copy)) + (make-directory (file-name-directory file-copy) t)) + (copy-file path file-copy 'overwrite)) (format "%s-%s.%s" persist-file (md5 path) ext))))) (defun org-persist-write:url (c collection) @@ -719,7 +722,8 @@ org-persist-register EXPIRY key has no effect when INHERIT is non-nil. Optional key WRITE-IMMEDIATELY controls whether to save the container data immediately. -MISC will be appended to CONTAINER. +MISC will be appended to the collection. It must be alternating :KEY +VALUE pairs. When WRITE-IMMEDIATELY is non-nil, the return value will be the same with `org-persist-write'." (unless org-persist--index (org-persist--load-index)) diff --git a/lisp/org/org-src.el b/lisp/org/org-src.el index fd0adadb7a9..9e439281118 100644 --- a/lisp/org/org-src.el +++ b/lisp/org/org-src.el @@ -629,83 +629,83 @@ org-src-font-lock-fontify-block "Fontify code block between START and END using LANG's syntax. This function is called by Emacs' automatic fontification, as long as `org-src-fontify-natively' is non-nil." - (let ((lang-mode (org-src-get-lang-mode lang))) - (when (fboundp lang-mode) - (let ((string (buffer-substring-no-properties start end)) - (modified (buffer-modified-p)) - (org-buffer (current-buffer))) - (remove-text-properties start end '(face nil)) - (with-current-buffer - (get-buffer-create - (format " *org-src-fontification:%s*" lang-mode)) - (let ((inhibit-modification-hooks nil)) - (erase-buffer) - ;; Add string and a final space to ensure property change. - (insert string " ")) - (unless (eq major-mode lang-mode) (funcall lang-mode)) - (font-lock-ensure) - (let ((pos (point-min)) next) - (while (setq next (next-property-change pos)) - ;; Handle additional properties from font-lock, so as to - ;; preserve, e.g., composition. - ;; FIXME: We copy 'font-lock-face property explicitly because - ;; `font-lock-mode' is not enabled in the buffers starting from - ;; space and the remapping between 'font-lock-face and 'face - ;; text properties may thus not be set. See commit - ;; 453d634bc. - (dolist (prop (append '(font-lock-face face) font-lock-extra-managed-props)) - (let ((new-prop (get-text-property pos prop))) - (when new-prop - (if (not (eq prop 'invisible)) - (put-text-property - (+ start (1- pos)) (1- (+ start next)) prop new-prop - org-buffer) - ;; Special case. `invisible' text property may - ;; clash with Org folding. Do not assign - ;; `invisible' text property directly. Use - ;; property alias instead. - (let ((invisibility-spec - (or - ;; ATOM spec. - (and (memq new-prop buffer-invisibility-spec) - new-prop) - ;; (ATOM . ELLIPSIS) spec. - (assq new-prop buffer-invisibility-spec)))) - (with-current-buffer org-buffer - ;; Add new property alias. - (unless (memq 'org-src-invisible - (cdr (assq 'invisible char-property-alias-alist))) - (setq-local - char-property-alias-alist - (cons (cons 'invisible - (nconc (cdr (assq 'invisible char-property-alias-alist)) - '(org-src-invisible))) - (remove (assq 'invisible char-property-alias-alist) - char-property-alias-alist)))) - ;; Carry over the invisibility spec, unless - ;; already present. Note that there might - ;; be conflicting invisibility specs from - ;; different major modes. We cannot do much - ;; about this then. - (when invisibility-spec - (add-to-invisibility-spec invisibility-spec)) - (put-text-property - (+ start (1- pos)) (1- (+ start next)) - 'org-src-invisible new-prop - org-buffer))))))) - (setq pos next))) - (set-buffer-modified-p nil)) - ;; Add Org faces. - (let ((src-face (nth 1 (assoc-string lang org-src-block-faces t)))) - (when (or (facep src-face) (listp src-face)) - (font-lock-append-text-property start end 'face src-face)) - (font-lock-append-text-property start end 'face 'org-block)) - ;; Clear abbreviated link folding. - (org-fold-region start end nil 'org-link) - (add-text-properties - start end - '(font-lock-fontified t fontified t font-lock-multiline t)) - (set-buffer-modified-p modified))))) + (let ((modified (buffer-modified-p))) + (remove-text-properties start end '(face nil)) + (let ((lang-mode (org-src-get-lang-mode lang))) + (when (fboundp lang-mode) + (let ((string (buffer-substring-no-properties start end)) + (org-buffer (current-buffer))) + (with-current-buffer + (get-buffer-create + (format " *org-src-fontification:%s*" lang-mode)) + (let ((inhibit-modification-hooks nil)) + (erase-buffer) + ;; Add string and a final space to ensure property change. + (insert string " ")) + (unless (eq major-mode lang-mode) (funcall lang-mode)) + (font-lock-ensure) + (let ((pos (point-min)) next) + (while (setq next (next-property-change pos)) + ;; Handle additional properties from font-lock, so as to + ;; preserve, e.g., composition. + ;; FIXME: We copy 'font-lock-face property explicitly because + ;; `font-lock-mode' is not enabled in the buffers starting from + ;; space and the remapping between 'font-lock-face and 'face + ;; text properties may thus not be set. See commit + ;; 453d634bc. + (dolist (prop (append '(font-lock-face face) font-lock-extra-managed-props)) + (let ((new-prop (get-text-property pos prop))) + (when new-prop + (if (not (eq prop 'invisible)) + (put-text-property + (+ start (1- pos)) (1- (+ start next)) prop new-prop + org-buffer) + ;; Special case. `invisible' text property may + ;; clash with Org folding. Do not assign + ;; `invisible' text property directly. Use + ;; property alias instead. + (let ((invisibility-spec + (or + ;; ATOM spec. + (and (memq new-prop buffer-invisibility-spec) + new-prop) + ;; (ATOM . ELLIPSIS) spec. + (assq new-prop buffer-invisibility-spec)))) + (with-current-buffer org-buffer + ;; Add new property alias. + (unless (memq 'org-src-invisible + (cdr (assq 'invisible char-property-alias-alist))) + (setq-local + char-property-alias-alist + (cons (cons 'invisible + (nconc (cdr (assq 'invisible char-property-alias-alist)) + '(org-src-invisible))) + (remove (assq 'invisible char-property-alias-alist) + char-property-alias-alist)))) + ;; Carry over the invisibility spec, unless + ;; already present. Note that there might + ;; be conflicting invisibility specs from + ;; different major modes. We cannot do much + ;; about this then. + (when invisibility-spec + (add-to-invisibility-spec invisibility-spec)) + (put-text-property + (+ start (1- pos)) (1- (+ start next)) + 'org-src-invisible new-prop + org-buffer))))))) + (setq pos next))) + (set-buffer-modified-p nil))))) + ;; Add Org faces. + (let ((src-face (nth 1 (assoc-string lang org-src-block-faces t)))) + (when (or (facep src-face) (listp src-face)) + (font-lock-append-text-property start end 'face src-face)) + (font-lock-append-text-property start end 'face 'org-block)) + ;; Clear abbreviated link folding. + (org-fold-region start end nil 'org-link) + (add-text-properties + start end + '(font-lock-fontified t fontified t font-lock-multiline t)) + (set-buffer-modified-p modified))) (defun org-fontify-inline-src-blocks (limit) "Try to apply `org-fontify-inline-src-blocks-1'." diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el index a0016265f02..dd6d92d8e58 100644 --- a/lisp/org/org-version.el +++ b/lisp/org/org-version.el @@ -11,7 +11,7 @@ org-release (defun org-git-version () "The Git version of Org mode. Inserted by installing Org or when a release is made." - (let ((org-git-version "release_9.6-61-g63e073f")) + (let ((org-git-version "release_9.6-81-g563a43")) org-git-version)) (provide 'org-version) commit d9ed736f0a724693929c0712b0c443d77a9707f1 Author: Dmitry Gutov Date: Mon Jan 2 03:51:11 2023 +0200 ruby-ts-mode: Remove some currently unused functions * lisp/progmodes/ruby-ts-mode.el (ruby-ts--grand-parent-is) (ruby-ts--ancestor-start, ruby-ts--ancestor-is): Remove some currently unused functions. diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index ac016caccdc..5c9a25c1fde 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -374,25 +374,10 @@ ruby-ts--bol (back-to-indentation) (point))))) -(defun ruby-ts--grand-parent-is (type) - "Check grand parent's type matches regexp TYPE." - (lambda (_n parent &rest _) - (string-match-p type (treesit-node-type (treesit-node-parent parent))))) - (defun ruby-ts--grand-parent-node (_n parent &rest _) "Return parent of PARENT node." (treesit-node-parent parent)) -(defun ruby-ts--ancestor-start (type) - "Return start of closest ancestor matching regexp TYPE." - (lambda (node &rest _) - (treesit-node-start (treesit-parent-until node (ruby-ts--type-pred type))))) - -(defun ruby-ts--ancestor-is (type) - "Check that ancestor's type matches regexp TYPE." - (lambda (node &rest _) - (treesit-parent-until node (ruby-ts--type-pred type)))) - (defun ruby-ts--align-chain-p (&rest _) "Return value of `ruby-align-chained-calls'." ruby-align-chained-calls) @@ -475,9 +460,6 @@ ruby-ts--same-line-hash-array-p (first-child (ruby-ts--first-non-comment-child parent))) (= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child)))) -(defalias 'ancestor-node #'ruby-ts--ancestor-is - "Return ancestor node whose type matches regexp TYPE.") - (defun ruby-ts--assignment-ancestor (node &rest _) "Return the assignment ancestor of NODE if any." (treesit-parent-until node (ruby-ts--type-pred "\\`assignment\\'"))) commit 45618447203a1332125106bf2d7a61f2c53e3939 Author: Dmitry Gutov Date: Mon Jan 2 03:29:15 2023 +0200 ruby-ts-mode: Highlight singleton method definitions and setters * lisp/progmodes/ruby-ts-mode.el (ruby-ts--font-lock-settings): Highlight singleton method definitions and setters. diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el index 2654f08fe85..ac016caccdc 100644 --- a/lisp/progmodes/ruby-ts-mode.el +++ b/lisp/progmodes/ruby-ts-mode.el @@ -284,7 +284,11 @@ ruby-ts--font-lock-settings :language language :feature 'method-definition '((method - name: (identifier) @font-lock-function-name-face)) + name: (identifier) @font-lock-function-name-face) + (singleton_method + name: (identifier) @font-lock-function-name-face) + (method + name: (setter) @font-lock-function-name-face)) ;; Yuan recommends also putting method definitions into the ;; 'function' category (thus keeping it in both). I've opted to commit 0562006da3b6f0147069a9aea75c08a9a0a4e6d8 Author: Perry Smith Date: Mon Jan 2 02:57:38 2023 +0200 Add ruby-ts-mode * etc/NEWS: Mention the new mode. * lisp/progmodes/ruby-ts-mode.el: New file. * test/lisp/progmodes/ruby-ts-mode-tests.el: New file. * lisp/progmodes/eglot.el (eglot-server-programs): Add ruby-ts-mode to the Ruby entry. Co-authored-by: Dmitry Gutov diff --git a/etc/NEWS b/etc/NEWS index 36044d26244..355ba6ba8aa 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3261,6 +3261,11 @@ written in YAML. It is auto-enabled for files with the ".yaml" or A major mode based on the tree-sitter library for editing programs in the Rust language. It is auto-enabled for files with the ".rs" extension. +--- +*** New major mode 'ruby-ts-mode'. +An optional major mode based on the tree-sitter library for editing +programs in the Ruby language. + * Incompatible Lisp Changes in Emacs 29.1 diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 791108001d2..6d192d9b333 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -205,7 +205,7 @@ eglot-server-programs (((caml-mode :language-id "ocaml") (tuareg-mode :language-id "ocaml") reason-mode) . ("ocamllsp")) - (ruby-mode + ((ruby-mode ruby-ts-mode) . ("solargraph" "socket" "--port" :autoport)) (haskell-mode . ("haskell-language-server-wrapper" "--lsp")) diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el new file mode 100644 index 00000000000..2654f08fe85 --- /dev/null +++ b/lisp/progmodes/ruby-ts-mode.el @@ -0,0 +1,958 @@ +;;; ruby-ts-mode.el --- Major mode for editing Ruby files using tree-sitter -*- lexical-binding: t; -*- + +;; Copyright (C) 2022-2023 Free Software Foundation, Inc. + +;; Author: Perry Smith +;; Created: December 2022 +;; Keywords: ruby 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: + +;; This file defines ruby-ts-mode which is a major mode for editting +;; Ruby files that uses Tree Sitter to parse the language. More +;; information about Tree Sitter can be found in the ELisp Info pages +;; as well as this website: https://tree-sitter.github.io/tree-sitter/ + +;; For this major mode to work, Emacs has to be compiled with +;; tree-sitter support, and the Ruby grammar has to be compiled and +;; put somewhere Emacs can find it. See the docstring of +;; `treesit-extra-load-path'. + +;; This mode doesn't associate itself with .rb files automatically. +;; You can do that either by prepending to the value of +;; `auto-mode-alist', or using `major-mode-remap-alist'. + +;; Tree Sitter brings a lot of power and versitility which can be +;; broken into these features. + +;; * Font Lock + +;; The ability to color the source code is not new but what is new is +;; the versatility to enable and disable particular font lock rules. +;; I suggest reviewing variable treesit-font-lock-level and function +;; treesit-font-lock-recompute-features to get a better understanding +;; of the following. + +;; Currently tree treesit-font-lock-feature-list is set with the +;; following levels: +;; 1: comment method-definition +;; 2: keyword regexp string type +;; 3: builtin constant delimiter escape-sequence +;; global instance +;; interpolation literal symbol variable +;; 4: bracket error function operator punctuation + +;; Thus if treesit-font-lock-level is set to level 3 which is its +;; default, all the features listed in levels 1 through 3 above will +;; be enabled. i.e. those features will font lock or colorize the +;; code accordingly. Individual features can be added and removed via +;; treesit-font-lock-recompute-features. + +;; describe-face can be used to view how a face looks. + +;; * Indent + +;; ruby-ts-mode tries to adhere to the indentation related user +;; options from ruby-mode, such as ruby-indent-level, +;; ruby-indent-tabs-mode, and so on. + +;; * IMenu +;; * Navigation +;; * Which-func + +;;; Code: + +(require 'treesit) +(require 'ruby-mode) + +(declare-function treesit-parser-create "treesit.c") + +(defgroup ruby-ts nil + "Major mode for editing Ruby code." + :prefix "ruby-ts-" + :group 'languages) + +(defcustom ruby-ts-highlight-predefined-constants t + "When non-nil, the pre-defined constants are highlighted. +They will be highlighted the same way as the pre-defined variables." + :type 'boolean) + +(defvar ruby-ts--operators + '("+" "-" "*" "/" "%" "**" + "==" "!=" ">" "<" ">=" "<=" "<=>" "===" + "=" "+=" "-=" "*=" "/=" "%=" "**=" + "&" "|" "^" "~" "<<" ">>" + "!" "&&" "and" "not" "or" "||" + "?" ":" + ".." "..." + "defined?" + "." "::") + "Ruby operators for tree-sitter font-locking.") + +(defvar ruby-ts--delimiters '("," ";") + "Ruby's punctuation characters.") + +(defvar ruby-ts--predefined-constants + (rx (or "ARGF" "ARGV" "DATA" "ENV" "RUBY_COPYRIGHT" + "RUBY_DESCRIPTION" "RUBY_ENGINE" "RUBY_ENGINE_VERSION" + "RUBY_PATCHLEVEL" "RUBY_PLATFORM" "RUBY_RELEASE_DATE" + "RUBY_REVISION" "RUBY_VERSION" "STDERR" "STDIN" "STDOUT" + "TOPLEVEL_BINDING")) + "Ruby predefined global constants. +These are currently unused") + +(defvar ruby-ts--predefined-variables + (rx (or "$!" "$@" "$~" "$&" "$‘" "$‘" "$+" "$=" "$/" "$\\" "$," "$;" + "$." "$<" "$>" "$_" "$*" "$$" "$?" "$:" "$LOAD_PATH" + "$LOADED_FEATURES" "$DEBUG" "$FILENAME" "$stderr" "$stdin" + "$stdout" "$VERBOSE" "$-a" "$-i" "$-l" "$-p" + (seq "$" (+ digit)))) + "Ruby global variables (but not global constants.") + +(defconst ruby-ts--class-or-module-regex + (rx string-start + (or "class" "module" "singleton_class") + string-end) + "Regular expression that matches a class or module's node type.") + +(defconst ruby-ts--method-regex + (rx string-start + (or "method" "singleton_method") + string-end) + "Regular expression matching methods and singleton methods.") + +(defconst ruby-ts--statement-container-regexp + (rx string-start + (or "program" + "block_body" + "begin_block" + "end_block" + "do" + "else" + "then" + "ensure" + "body_statement" + "parenthesized_statements" + "interpolation") + string-end) + "Regular expression of the nodes that can constain statements.") + +(defun ruby-ts--lineno (node) + "Return line number of NODE's start." + (line-number-at-pos (treesit-node-start node))) + +;; doc/keywords.rdoc in the Ruby git repository considers these to be +;; reserved keywords. If these keywords are added to the list, it +;; causes the font-lock to stop working. +;; +;; "__ENCODING__" "__FILE__" "__LINE__" "false" "self" "super" "true" +;; +;; "nil" (which does not exhibit this issue) is also considered a +;; keyword but I removed it and added it as a constant. +;; +(defvar ruby-ts--keywords + '("BEGIN" "END" "alias" "and" "begin" "break" "case" "class" + "def" "defined?" "do" "else" "elsif" "end" "ensure" "for" + "if" "in" "module" "next" "not" "or" "redo" "rescue" + "retry" "return" "then" "undef" "unless" "until" "when" + "while" "yield") + "Ruby keywords for tree-sitter font-locking.") + +(defun ruby-ts--comment-font-lock (node override start end &rest _) + "Apply font lock to comment NODE within START and END. +Applies `font-lock-comment-delimiter-face' and +`font-lock-comment-face' See `treesit-fontify-with-override' for +values of OVERRIDE" + ;; Emperically it appears as if (treesit-node-start node) will be + ;; where the # character is at and (treesit-node-end node) will be + ;; the end of the line + (let* ((node-start (treesit-node-start node)) + (plus-1 (1+ node-start)) + (node-end (treesit-node-end node)) + (text (treesit-node-text node t))) + (if (and (>= node-start start) + (<= plus-1 end) + (string-match-p "\\`#" text)) + (treesit-fontify-with-override node-start plus-1 + font-lock-comment-delimiter-face override)) + (treesit-fontify-with-override (max plus-1 start) (min node-end end) + font-lock-comment-face override))) + +(defun ruby-ts--font-lock-settings (language) + "Tree-sitter font-lock settings for Ruby." + (treesit-font-lock-rules + :language language + :feature 'comment + '((comment) @ruby-ts--comment-font-lock) + + :language language + :feature 'builtin + `(((global_variable) @var (:match ,ruby-ts--predefined-variables @var)) @font-lock-builtin-face + ,@(when ruby-ts-highlight-predefined-constants + `(((constant) @var (:match ,ruby-ts--predefined-constants @var)) @font-lock-builtin-face))) + + :language language + :feature 'keyword + `([,@ruby-ts--keywords] @font-lock-keyword-face) + + :language language + :feature 'constant + '((true) @font-lock-doc-markup-face + (false) @font-lock-doc-markup-face + (nil) @font-lock-doc-markup-face + (self) @font-lock-doc-markup-face + (super) @font-lock-doc-markup-face) + + :language language + :feature 'symbol + '((bare_symbol) @font-lock-constant-face + (delimited_symbol (string_content) @font-lock-constant-face) + (hash_key_symbol) @font-lock-constant-face + (simple_symbol) @font-lock-constant-face) + + ;; Before 'operator so (unary) works. + :language language + :feature 'literal + '((unary ["+" "-"] [(integer) (rational) (float) (complex)]) @font-lock-number-face + (integer) @font-lock-number-face + (float) @font-lock-number-face + (complex) @font-lock-number-face + (rational) @font-lock-number-face) + + ;; Also before 'operator because % and / are operators + :language language + :feature 'regexp + '((regex "/" @font-lock-regexp-grouping-construct) + (regex _ (string_content) @font-lock-regexp-grouping-backslash)) + + :language language + :feature 'operator + `("!" @font-lock-negation-char-face + [,@ruby-ts--operators] @font-lock-operator-face) + + ;; TODO: Consider using a different face for string delimiters. + ;; font-lock-delimiter-face is not a good choice, though, because it + ;; looks like 'default' in the default theme, and its documented purpose + ;; is characters like commas, semicolons, etc. + :language language + :feature 'string + '((delimited_symbol [ ":\"" "\"" ] @font-lock-string-face) + (string "\"" @font-lock-string-face) + (string_array [ "%w(" ")" ] @font-lock-delimiter-face) + (subshell "`" @font-lock-delimiter-face) + (symbol_array [ "%i(" ")"] @font-lock-delimiter-face)) + + :language language + :feature 'string + '((string_content) @font-lock-string-face + (heredoc_beginning) @font-lock-string-face + (heredoc_content) @font-lock-string-face + (heredoc_end) @font-lock-string-face) + + :language language + :feature 'interpolation + '((interpolation "#{" @font-lock-doc-face) + (interpolation "}" @font-lock-doc-face)) + + :language language + :feature 'type + '((constant) @font-lock-type-face) + + :language language + :feature 'global + '((global_variable) @font-lock-variable-name-face) + + :language language + :feature 'instance + '((instance_variable) @font-lock-variable-name-face) + + :language language + :feature 'method-definition + '((method + name: (identifier) @font-lock-function-name-face)) + + ;; Yuan recommends also putting method definitions into the + ;; 'function' category (thus keeping it in both). I've opted to + ;; just use separate categories for them -- dgutov. + :language language + :feature 'function + '((call + method: (identifier) @font-lock-function-name-face)) + + :language language + :feature 'error + '((ERROR) @font-lock-warning-face) + + :feature 'escape-sequence + :language language + :override t + '((escape_sequence) @font-lock-escape-face) + + :language language + :feature 'bracket + '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face) + + :language language + :feature 'punctuation + `(([,@ruby-ts--delimiters] @font-lock-delimiter-face)))) + +(defun ruby-ts--first-non-comment-child (node) + "Return the first named child of NODE that is not a comment." + (let ((child (treesit-node-child node 0 t))) + (while (and child + (equal "comment" (treesit-node-type child))) + (setq child (treesit-node-next-sibling child t))) + child)) + +;; +;; These routines would be better added to treesit.el They are +;; intended to be used with indent rules +;; +;; I think this is over simplified but basically +;; treesit--simple-indent-eval calls the result with node, parent, and +;; bol. Thus all of these functions return a lambda that accepts three +;; arguments. Somewhere something explains that &rest should always +;; be used in case extra arguments are added in the future. +;; + +(defun ruby-ts--type-pred (regexp) + "Return predicate taking a node returning non-nil if REGEXP matches type of node." + (lambda (node) + (string-match-p regexp (treesit-node-type node)))) + +(defun ruby-ts--parent-node (_n parent &rest _) + "Return the PARENT node matching ident rule." + parent) + +(defun ruby-ts--align-keywords (pred) + "Return either start or bol of PRED. +PRED should specify a node that is listed in +`ruby-alignable-keywords'. If PRED is listed in user option +`ruby-align-to-stmt-keywords', then return the BOL of PRED. +Otherwise return start of PRED." + (lambda (node parent bol &rest rest) + (let* ((pred-node (funcall pred node parent bol rest)) + (temp (treesit-node-start pred-node)) + (keyword (treesit-node-type pred-node)) + (bol (ruby-smie--indent-to-stmt-p keyword))) + (when temp + (if bol + (save-excursion + (goto-char temp) + (back-to-indentation) + (point)) + temp))))) + +(defun ruby-ts--bol (pred) + "Return bol of PRED. +PRED should take (node parent bol &rest rest) and return a node. +Returns bol of the current line if PRED returns nil." + (lambda (node parent bol &rest rest) + (save-excursion + (let ((temp (treesit-node-start (funcall pred node parent bol rest)))) + (if temp + (goto-char temp)) + (back-to-indentation) + (point))))) + +(defun ruby-ts--grand-parent-is (type) + "Check grand parent's type matches regexp TYPE." + (lambda (_n parent &rest _) + (string-match-p type (treesit-node-type (treesit-node-parent parent))))) + +(defun ruby-ts--grand-parent-node (_n parent &rest _) + "Return parent of PARENT node." + (treesit-node-parent parent)) + +(defun ruby-ts--ancestor-start (type) + "Return start of closest ancestor matching regexp TYPE." + (lambda (node &rest _) + (treesit-node-start (treesit-parent-until node (ruby-ts--type-pred type))))) + +(defun ruby-ts--ancestor-is (type) + "Check that ancestor's type matches regexp TYPE." + (lambda (node &rest _) + (treesit-parent-until node (ruby-ts--type-pred type)))) + +(defun ruby-ts--align-chain-p (&rest _) + "Return value of `ruby-align-chained-calls'." + ruby-align-chained-calls) + +(defun ruby-ts--parenless-call-arguments-indent-p (&rest _) + "Return value of `ruby-parenless-call-arguments-indent'." + ruby-parenless-call-arguments-indent) + +(defun ruby-ts--align-chain (_n parent &rest _) + "Align chained method call. +Align NODE which will be the dot (.) to the dot of the +first (outermost) call in the chain. See +`ruby-align-chained-calls' for details. PARENT will be the +\"call\" node. Called only when `ruby-align-chained-calls' is +non-nil." + (let* (first-call ) + (while (and parent + (setq first-call (treesit-node-parent parent)) + (string-match-p "call" (treesit-node-type first-call))) + (setq parent first-call)) + (treesit-node-start (treesit-search-subtree parent "\\." nil t)))) + +(defun ruby-ts--same-line-args-p (_n parent &rest _) + "Return non-nil when first argument is on the same line as the method. +PARENT will be argument_list. NODE can be the close paren." + (let* ((method (treesit-node-parent parent)) + (first-param (ruby-ts--first-non-comment-child parent))) + (= (ruby-ts--lineno method) (ruby-ts--lineno first-param)))) + +(defun ruby-ts--same-line-params-p (_n parent &rest _) + "Return non-nil when first parameter is on the same line as the method. +PARENT will be method_parameters. NODE can be the close paren." + (let* ((method (treesit-node-parent parent)) + (first-param (ruby-ts--first-non-comment-child parent))) + (= (ruby-ts--lineno method) (ruby-ts--lineno first-param)))) + +(defun ruby-ts--param-indent (_n parent &rest _) + "Indent parameters that start on next line. +Given: NODE is the parameter. PARENT is +method_parameters. `ruby-ts--same-line-params-p' is nil. +Indent according to `ruby-method-params-indent'. + +If `ruby-method-params-indent' is 0 +def foo( + param1, + param2 +) + +Params start on next line, `ruby-method-params-indent' is t +def foo( + param1, + param2 + )" + (let ((method (treesit-node-parent parent))) + (if (eq t ruby-method-params-indent) + ;; For methods, the "name" is the name of the method but for + ;; singleton methods, we need to find "object" + (let* ((singleton (equal "singleton_method" (treesit-node-type method))) + (name-node (treesit-node-child-by-field-name + method + (if singleton "object" "name")))) + ;; (message "name-node: %S" name-node) + (treesit-node-start name-node)) + ;; Small Danger: if the method name plus the parent is less than + ;; `ruby-method-params-indent', then the addition will put the + ;; result on the next line and indented incorrectly. There are + ;; plausible ways to fix this but the probability seems rather + ;; remote. + (+ (treesit-node-start method) (or ruby-method-params-indent 0))))) + +(defun ruby-ts--true (&rest _) + "I have no idea why I can't just put t but I can put 0." + t) + +(defun ruby-ts--same-line-hash-array-p (_n parent &rest _) + "Return non-nil if first element and open brace are on the same line. +NODE is the element or closing brace or bracket. PARENT is the +array or hash." + (let* ((open-brace (treesit-node-child parent 0 nil)) + (first-child (ruby-ts--first-non-comment-child parent))) + (= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child)))) + +(defalias 'ancestor-node #'ruby-ts--ancestor-is + "Return ancestor node whose type matches regexp TYPE.") + +(defun ruby-ts--assignment-ancestor (node &rest _) + "Return the assignment ancestor of NODE if any." + (treesit-parent-until node (ruby-ts--type-pred "\\`assignment\\'"))) + +(defun ruby-ts--statement-ancestor (node &rest _) + "Return the statement ancestor of NODE if any. +A statement is defined as a child of a statement container where +a statement container is a node that matches +`ruby-ts--statement-container-regexp'." + (let* ((statement node) + (parent (treesit-node-parent statement))) + (while (and parent + statement + (not (string-match-p ruby-ts--statement-container-regexp + (treesit-node-type parent)))) + (setq statement parent + parent (treesit-node-parent parent))) + statement)) + +(defun ruby-ts--is-in-condition (node &rest _) + "Return the condition node if NODE is within a condition." + (while (and node + (not (equal "condition" (treesit-node-field-name node))) + (not (string-match-p ruby-ts--statement-container-regexp + (treesit-node-type node)))) + (setq node (treesit-node-parent node))) + (and (equal "condition" (treesit-node-field-name node)) node)) + +(defun ruby-ts--endless-method (node &rest _) + "Return the expression node if NODE is in an endless method. +i.e. expr of def foo(args) = expr is returned." + (let* ((method node)) + (while (and method + (not (string-match-p ruby-ts--method-regex (treesit-node-type method)))) + (setq method (treesit-node-parent method))) + (when method + (if (equal "=" (treesit-node-type (treesit-node-child method 3 nil))) + (treesit-node-child method 4 nil))))) + +;; +;; end of functions that can be used for queries +;; + +(defun ruby-ts--indent-rules () + "Indent rules supported by `ruby-ts-mode'." + (let ((common + `( + ;; Slam all top level nodes to the left margin + ((parent-is "program") parent 0) + + ;; Do not indent here docs or the end. Not sure why it + ;; takes the grand-parent but ok fine. + ((n-p-gp nil nil "heredoc_body") no-indent 0) + ((parent-is "heredoc_body") no-indent 0) + ((node-is "heredoc_body") no-indent 0) + ;; Do not indent multiline regexp + ((n-p-gp nil nil "regex") no-indent 0) + ((parent-is "regex") no-indent 0) + + ;; if then else elseif notes: + ;; + ;; 1. The "then" starts at the end of the line that ends + ;; the if condition which can be on a different line + ;; from the "if". + ;; + ;; 2. If there is an "elsif", it is a sibling to the then + ;; BUT the "else" that follows is now a child of the + ;; "elsif". + ;; + ;; 3. The statements within each of these are direct + ;; children. There is no intermediate construct such + ;; as a block_statement. + ;; + ;; I'm using very restrictive patterns hoping to reduce rules + ;; triggering unintentionally. + ((match "else" "if") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((match "elsif" "if") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((match "end" "if") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((n-p-gp nil "then\\|else\\|elsif" "if\\|unless") + (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level) + + ;; case expression: when, in_clause, and else are all + ;; children of case. when and in_clause have pattern and + ;; body as fields. body has "then" and then the statemets. + ;; i.e. the statements are not children of when but then. + ;; But for the statements are children of else. + ((match "when" "case") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((match "in_clause" "case") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((match "else" "case") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((match "end" "case") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((n-p-gp nil "then" "when") grand-parent ruby-indent-level) + ((n-p-gp nil "then" "in_clause") grand-parent ruby-indent-level) + ((n-p-gp nil "else" "case") parent ruby-indent-level) + + ;; The beauty of inconsistency :-) + ;; while / until have only "do" as a child. The "end" is a + ;; child of "do". + ((n-p-gp "end" "do" "while\\|until") + (ruby-ts--align-keywords ruby-ts--grand-parent-node) 0) + ((n-p-gp nil "do" "while\\|until") + (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level) + ;; begin can have rescue, ensure, else, and end. + ;; statements are a child of begin. rescue, ensure, else, + ;; and end are also children of begin. rescue has a then + ;; as a child thus statements will be grand children of + ;; rescue. + ((n-p-gp nil "then" "rescue") + (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level) + ((n-p-gp nil "ensure\\|else" "begin") + (ruby-ts--align-keywords ruby-ts--parent-node) ruby-indent-level) + ((match "rescue\\|ensure\\|else\\|end" "begin") + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((parent-is "begin") ;last + (ruby-ts--align-keywords ruby-ts--parent-node) ruby-indent-level) + + ;; for ... I don't think I have ever used a for loop in + ;; Ruby. The "in" (not an in_clause) and "do" are + ;; children. The statements are children of the "do". + ;; And, of course, the "end" is a child of the "do". + ((n-p-gp "end" "do" "for") + (ruby-ts--align-keywords ruby-ts--grand-parent-node) 0) + ((n-p-gp nil "do" "for") + (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level) + + ;; method has a "body_statement" and the "end" as children. + ;; The body_statement can have rescue, ensure, and else as + ;; well as statements. Note that the first statement of a + ;; body_statement hits the node as "body_statement" and not + ;; as the assignment, etc. + ((match "end" ,ruby-ts--method-regex) + (ruby-ts--align-keywords ruby-ts--parent-node) 0) + ((n-p-gp "\\`\\(rescue\\|ensure\\|else\\)\\'" "body_statement" ,ruby-ts--method-regex) + (ruby-ts--align-keywords ruby-ts--grand-parent-node) 0) + ((n-p-gp nil "rescue\\|ensure\\|else" "body_statement") parent ruby-indent-level) + ((match "body_statement" ,ruby-ts--method-regex) ;first statement + (ruby-ts--align-keywords ruby-ts--parent-node) ruby-indent-level) + ((n-p-gp nil "body_statement" ,ruby-ts--method-regex) ;other statements + (ruby-ts--align-keywords ruby-ts--grand-parent-node) ruby-indent-level) + + ;; Chained calls: + ;; if `ruby-align-chained-calls' is true, the first query + ;; matches and the node is aligned under the first dot (.); + ;; else the second query aligns + ;; `ruby-indent-level' spaces in from the parent. + ((and ruby-ts--align-chain-p (match "\\." "call")) ruby-ts--align-chain 0) + ((match "\\." "call") parent ruby-indent-level) + + ;; ruby-indent-after-block-in-continued-expression + ((match "begin" "assignment") parent ruby-indent-level) + + ;; method parameters -- four styles: + ;; 1) With paren, first arg on same line: + ((and (query "(method_parameters \"(\" _ @indent)") + ruby-ts--same-line-params-p + (node-is ")")) + first-sibling 0) + ((and (query "(method_parameters \"(\" _ @indent)") + ruby-ts--same-line-params-p) + first-sibling 1) + ;; ;; 2) With paren, first arg on next line, ruby-method-params-indent eq t + ;; ;; 3) With paren, first arg on next line, ruby-method-params-indent neq t + ((and (query "(method_parameters \"(\" _ @indent)") (node-is ")")) ruby-ts--param-indent 0) + ((query "(method_parameters \"(\" _ @indent)") ruby-ts--param-indent ruby-indent-level) + ;; 4) No paren: + ((parent-is "method_parameters") first-sibling 0) + + ;; Argument lists: + ;; 1) With paren, 1st arg on same line + ((and (query "(argument_list \"(\" _ @indent)") + ruby-ts--same-line-args-p + (node-is ")")) + first-sibling 0) + ((and (query "(argument_list \"(\" _ @indent)") + ruby-ts--same-line-args-p) + first-sibling 1) + ;; 2) With paren, 1st arg on next line + ((and (query "(argument_list \"(\" _ @indent)") + (node-is ")")) + (ruby-ts--bol ruby-ts--grand-parent-node) 0) + ((query "(argument_list \"(\" _ @indent)") + (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + ;; 3) No paren, ruby-parenless-call-arguments-indent is t + ((and ruby-ts--parenless-call-arguments-indent-p (parent-is "argument_list")) + first-sibling 0) + ;; 4) No paren, ruby-parenless-call-arguments-indent is nil + ((parent-is "argument_list") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + + ;; Old... probably too simple + ((parent-is "block_parameters") first-sibling 1) + + ((and (parent-is "binary") + (or ruby-ts--assignment-ancestor + ruby-ts--is-in-condition + ruby-ts--endless-method)) + first-sibling 0) + + ;; ruby-mode does not touch these... + ((match "bare_string" "string_array") no-indent 0) + + ;; hash and array other than assignments. Note that the + ;; first sibling is the "{" or "[". There is a special + ;; case where the hash is an argument to a method. These + ;; need to be processed first. + + ((and ruby-ts--same-line-hash-array-p (match "}" "hash")) + first-sibling 0) + ((and ruby-ts--same-line-hash-array-p (parent-is "hash")) + (nth-sibling 0 ruby-ts--true) 0) + ((and ruby-ts--same-line-hash-array-p (match "]" "array")) + first-sibling 0) + ((and ruby-ts--same-line-hash-array-p (parent-is "array")) + (nth-sibling 0 ruby-ts--true) 0) + + ;; NOTE to folks trying to understand my insanity... + ;; I having trouble understanding the "logic" of why things + ;; are indented like they are so I am adding special cases + ;; hoping at some point I will be struck by lightning. + ((and (n-p-gp "}" "hash" "pair") + (not ruby-ts--same-line-hash-array-p)) + grand-parent 0) + ((and (n-p-gp "pair" "hash" "pair") + (not ruby-ts--same-line-hash-array-p)) + grand-parent ruby-indent-level) + ((and (n-p-gp "}" "hash" "method") + (not ruby-ts--same-line-hash-array-p)) + grand-parent 0) + ((and (n-p-gp "pair" "hash" "method") + (not ruby-ts--same-line-hash-array-p)) + grand-parent ruby-indent-level) + + ((n-p-gp "}" "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0) + ((n-p-gp nil "hash" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + ((n-p-gp "]" "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) 0) + ((n-p-gp nil "array" "assignment") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + + ((n-p-gp "}" "hash" "argument_list") first-sibling 0) + ((n-p-gp nil "hash" "argument_list") first-sibling ruby-indent-level) + ((n-p-gp "]" "array" "argument_list") first-sibling 0) + ((n-p-gp nil "array" "argument_list") first-sibling ruby-indent-level) + + ((match "}" "hash") first-sibling 0) + ((parent-is "hash") first-sibling ruby-indent-level) + ((match "]" "array") first-sibling 0) + ((parent-is "array") first-sibling ruby-indent-level) + + ;; If the previous method isn't finished yet, this will get + ;; the next method indented properly. + ((n-p-gp ,ruby-ts--method-regex "body_statement" ,ruby-ts--class-or-module-regex) + (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + + ;; Match the end of a class / modlue + ((match "end" ,ruby-ts--class-or-module-regex) parent 0) + + ;; A "do_block" has a "body_statement" child which has the + ;; statements as children within it. The problem is that + ;; the first statement starts at the same point as the + ;; body_statement and so treesit-simple-indent is called + ;; with node set to body_statement on the first statement + ;; but with node set to the statement and parent set to + ;; body_statement for all others. ... Fine. Be that way. + ;; Ditto for "block" and "block_body" + ((node-is "body_statement") parent-bol ruby-indent-level) + ((parent-is "body_statement") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + ((match "end" "do_block") parent-bol 0) + ((n-p-gp "block_body" "block" nil) parent-bol ruby-indent-level) + ((n-p-gp nil "block_body" "block") (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level) + ((match "}" "block") (ruby-ts--bol ruby-ts--grand-parent-node) 0) + + ;; Chained strings + ((match "string" "chained_string") first-sibling 0) + + ;; Try and indent two spaces when all else fails. + (catch-all parent-bol ruby-indent-level)))) + `((ruby . ,common)))) + +(defun ruby-ts--class-or-module-p (node) + "Predicate if NODE is a class or module." + (string-match-p ruby-ts--class-or-module-regex (treesit-node-type node))) + +(defun ruby-ts--get-name (node) + "Return the text of the `name' field of NODE." + (treesit-node-text (treesit-node-child-by-field-name node "name"))) + +(defun ruby-ts--full-name (node) + "Return the fully qualified name of NODE." + (let* ((name (ruby-ts--get-name node)) + (delimiter "#")) + (while (setq node (treesit-parent-until node #'ruby-ts--class-or-module-p)) + (setq name (concat (ruby-ts--get-name node) delimiter name)) + (setq delimiter "::")) + name)) + +(defun ruby-ts--imenu-helper (node) + "Convert a treesit sparse tree NODE in an imenu list. +Helper for `ruby-ts--imenu' which converts a treesit sparse +NODE into a list of imenu ( name . pos ) nodes" + (let* ((ts-node (car node)) + (subtrees (mapcan #'ruby-ts--imenu-helper (cdr node))) + (name (when ts-node + (ruby-ts--full-name ts-node))) + (marker (when ts-node + (set-marker (make-marker) + (treesit-node-start ts-node))))) + (cond + ((or (null ts-node) (null name)) subtrees) + ;; Don't include the anonymous "class" and "module" nodes + ((string-match-p "(\"\\(class\\|module\\)\")" + (treesit-node-string ts-node)) + nil) + (subtrees + `((,name ,(cons name marker) ,@subtrees))) + (t + `((,name . ,marker)))))) + +;; For now, this is going to work like ruby-mode and return a list of +;; class, modules, def (methods), and alias. It is likely that this +;; can be rigged to be easily extended. +(defun ruby-ts--imenu () + "Return Imenu alist for the current buffer." + (let* ((root (treesit-buffer-root-node)) + (nodes (treesit-induce-sparse-tree root "^\\(method\\|alias\\|class\\|module\\)$"))) + (ruby-ts--imenu-helper nodes))) + +(defun ruby-ts--arrow-up-start (arg) + "Move to the start ARG levels up or out." + (interactive "p") + (setq arg (or arg 1)) + (let* ((pnt (point)) + (found (treesit-node-at pnt)) + (pos (treesit-node-start found)) + new-pos) + (while (and found pos (> arg 0)) + (setq found (treesit-node-parent found) + new-pos (treesit-node-start found)) + (when (and new-pos (not (= new-pos pos))) + (setq arg (1- arg) + pos new-pos))) + (if pos + (goto-char pos) + (error "Something didn't work")))) + +(defun ruby-ts--class-name (node) + "Return NODE's name. +Assumes NODE's type is \"class\" or \"method\"" + (list + (treesit-node-text + (treesit-node-child-by-field-name + node + (if (equal "singleton_class" (treesit-node-type node)) "value" "name")) + t))) + +(defun ruby-ts--method-name (node) + "Return the method name of NODE. +Assumes NODE's type is method or singleton_method." + (if (equal "method" (treesit-node-type node)) + (list (treesit-node-text (treesit-node-child-by-field-name node "name") t)) + (let* ((children (treesit-node-children node)) + ;; 0th is "def" + (first (nth 1 children)) + (third (nth 3 children))) + (cond + ((equal "(" (treesit-node-type first)) + (list (treesit-node-text (nth 2 children) t) + (treesit-node-text (nth 5 children) t))) + ;; ((equal "self" (treesit-node-type first)) + ;; (list (treesit-node-text third t))) + (t (mapcar (lambda (n) + (treesit-node-text n t)) + (list first third))))))) + +(defun ruby-ts-add-log-current-function () + "Return the current method name as a string. +The hash (#) is for instance methods only which are methods +\"defined on a class\" -- which is 99% of methods. Otherwise, a +dot (.) is used. Double colon (::) is used between classes. The +leading double colon is not added." + (let* ((node (treesit-node-at (point))) + (method (treesit-parent-until node (ruby-ts--type-pred ruby-ts--method-regex))) + (class (or method node)) + (result nil) + (sep "#") + (method-list nil) + (class-list nil) + (method-name nil)) + + (when method + (setq method-list (ruby-ts--method-name method)) + (unless (= 1 (length method-list)) + (setq sep "."))) + (while (setq class (treesit-parent-until class + (ruby-ts--type-pred + ruby-ts--class-or-module-regex))) + (setq class-list (append (ruby-ts--class-name class) class-list))) + (setq method-name (car (last method-list)) + method-list (butlast method-list)) + (when (equal (car method-list) (car (last class-list))) + (setq method-list (cdr method-list))) + (dolist (ele (append class-list method-list)) + (cond + ((equal "self" ele) + (setq sep ".")) + ((string-match-p "\\`[^A-Z]" ele) ;not a class + (setq sep "." + result (if result + (concat result "::" ele) + ele))) + (t (setq result (if result + (concat result "::" ele) + ele))))) + (if method-name + (concat result sep method-name) + result))) + +(defvar-keymap ruby-ts-mode-map + :doc "Keymap used in Ruby mode" + :parent prog-mode-map + ;; (when ruby-use-smie + ;; (define-key map (kbd "M-C-d") 'smie-down-list)) + ;; (define-key map (kbd "M-C-p") 'ruby-beginning-of-block) + ;; (define-key map (kbd "M-C-n") 'ruby-end-of-block) + "C-c {" #'ruby-toggle-block + "C-c '" #'ruby-toggle-string-quotes + "C-c C-f" #'ruby-find-library-file) + +;;;###autoload +(define-derived-mode ruby-ts-mode prog-mode "Ruby" + "Major mode for editing Ruby, powered by tree-sitter." + :group 'ruby + :syntax-table ruby-mode-syntax-table + + (setq indent-tabs-mode ruby-indent-tabs-mode) + + (setq-local paragraph-start (concat "$\\|" page-delimiter)) + (setq-local paragraph-separate paragraph-start) + (setq-local paragraph-ignore-fill-prefix t) + + (setq-local comment-start "# ") + (setq-local comment-end "") + (setq-local comment-start-skip "#+ *") + + (unless (treesit-ready-p 'ruby) + (error "Tree-sitter for Ruby isn't available")) + + (treesit-parser-create 'ruby) + + (setq-local add-log-current-defun-function #'ruby-ts-add-log-current-function) + + ;; Navigation. + (setq-local treesit-defun-type-regexp ruby-ts--method-regex) + + ;; AFAIK, Ruby can not nest methods + (setq-local treesit-defun-prefer-top-level nil) + + ;; Imenu. + (setq-local imenu-create-index-function #'ruby-ts--imenu) + + (setq-local treesit-simple-indent-rules (ruby-ts--indent-rules)) + + ;; Font-lock. + (setq-local treesit-font-lock-settings (ruby-ts--font-lock-settings 'ruby)) + ;; Level 3 is the default. + (setq-local treesit-font-lock-feature-list + '(( comment method-definition ) + ( keyword regexp string type) + ( builtin constant + delimiter escape-sequence global + instance + interpolation literal symbol variable) + ( bracket error function operator punctuation))) + + (treesit-major-mode-setup)) + +(provide 'ruby-ts-mode) + +;;; ruby-ts-mode.el ends here diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el b/test/lisp/progmodes/ruby-ts-mode-tests.el new file mode 100644 index 00000000000..f48d0bf6330 --- /dev/null +++ b/test/lisp/progmodes/ruby-ts-mode-tests.el @@ -0,0 +1,254 @@ +;;; ruby-mode-tests.el --- Test suite for ruby-mode -*- lexical-binding:t -*- + +;; Copyright (C) 2023 Free Software Foundation, Inc. + +;; 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 'ert) +(require 'ert-x) +(require 'ruby-ts-mode) + +(defmacro ruby-ts-with-temp-buffer (contents &rest body) + (declare (indent 1) (debug t)) + `(with-temp-buffer + (insert ,contents) + (ruby-ts-mode) + ,@body)) + +(defun ruby-ts-should-indent-buffer (expected content) + "Assert that CONTENT turns into EXPECTED after the buffer is re-indented. + +The whitespace before and including \"|\" on each line is removed." + (ruby-ts-with-temp-buffer (ruby-ts-test-string content) + (indent-region (point-min) (point-max)) + (should (string= (ruby-ts-test-string expected) (buffer-string))))) + +(defun ruby-ts-test-string (s &rest args) + (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) + +(ert-deftest ruby-ts-indent-simple () + (skip-unless (treesit-available-p)) + (ruby-ts-should-indent-buffer + "if foo + | bar + |end + |zot + |" + "if foo + |bar + | end + | zot + |")) + +(ert-deftest ruby-ts-align-to-stmt-keywords-t () + (skip-unless (treesit-available-p)) + (let ((ruby-align-to-stmt-keywords t)) + (ruby-ts-should-indent-buffer + "foo = if bar? + | 1 + |else + | 2 + |end + | + |foo || begin + | bar + |end + | + |foo || + | begin + | bar + | end + |" + "foo = if bar? + | 1 + |else + | 2 + | end + | + | foo || begin + | bar + |end + | + | foo || + | begin + |bar + | end + |") + )) + +(ert-deftest ruby-ts-align-to-stmt-keywords-case () + (skip-unless (treesit-available-p)) + (let ((ruby-align-to-stmt-keywords '(case))) + (ruby-ts-should-indent-buffer + "b = case a + |when 13 + | 6 + |else + | 42 + |end" + "b = case a + | when 13 + | 6 + | else + | 42 + | end"))) + +(ert-deftest ruby-ts-add-log-current-method-examples () + (skip-unless (treesit-available-p)) + (let ((pairs '(("foo" . "#foo") + ("C.foo" . ".foo") + ("self.foo" . ".foo") + ("<<" . "#<<")))) + (dolist (pair pairs) + (let ((name (car pair)) + (value (cdr pair))) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "module M + | class C + | def %s + | _ + | end + | end + |end" + name) + (search-backward "_") + (forward-line) + (should (string= (ruby-ts-add-log-current-function) + (format "M::C%s" value)))))))) + +(ert-deftest ruby-ts-add-log-current-method-outside-of-method () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "module M + | class C + | def foo + | end + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-ts-add-log-current-function) "M::C")))) + +(ert-deftest ruby-ts-add-log-current-method-in-singleton-class () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "class C + | class << self + | def foo + | _ + | end + | end + |end") + (search-backward "_") + (should (string= (ruby-ts-add-log-current-function) "C.foo")))) + +(ert-deftest ruby-ts-add-log-current-method-namespace-shorthand () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "class C::D + | def foo + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-ts-add-log-current-function) "C::D#foo")))) + +(ert-deftest ruby-ts-add-log-current-method-after-inner-class () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "module M + | class C + | class D + | end + | def foo + | _ + | end + | end + |end") + (search-backward "_") + (should (string= (ruby-ts-add-log-current-function) "M::C#foo")))) + +(ert-deftest ruby-ts-add-log-current-method-after-inner-class-outside-methods () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "module M + | class C + | class D + | end + | + |_ + | end + |end") + (search-backward "_") + (delete-char 1) + (should (string= (ruby-ts-add-log-current-function) "M::C")))) + +(ert-deftest ruby-ts-add-log-current-method-after-inner-class-outside-methods-with-text () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "module M + | class C + | class D + | end + | + | FOO = 5 + | end + |end") + (search-backward "FOO") + (should (string= (ruby-ts-add-log-current-function) "M::C")))) + +(ert-deftest ruby-ts-add-log-current-method-after-endless-method () + (skip-unless (treesit-available-p)) + (ruby-ts-with-temp-buffer (ruby-ts-test-string + "module M + | class C + | def foo = + | 4_ + | end + |end") + (search-backward "_") + (delete-char 1) + (should (string= (ruby-ts-add-log-current-function) "M::C#foo")))) + +(defmacro ruby-ts-resource-file (file) + `(when-let ((testfile ,(or (macroexp-file-name) + buffer-file-name))) + (let ((default-directory (file-name-directory testfile))) + (file-truename + (expand-file-name (format "ruby-mode-resources/%s" ,file)))))) + +(defmacro ruby-ts-deftest-indent (file) + `(ert-deftest ,(intern (format "ruby-ts-indent-test/%s" file)) () + ;; :tags '(:expensive-test) + (skip-unless (treesit-available-p)) + (let ((buf (find-file-noselect (ruby-ts-resource-file ,file)))) + (unwind-protect + (with-current-buffer buf + (let ((orig (buffer-string))) + ;; Indent and check that we get the original text. + (indent-region (point-min) (point-max)) + (should (equal (buffer-string) orig)))) + (kill-buffer buf))))) + +(ruby-ts-deftest-indent "ruby-method-params-indent.rb") + +(provide 'ruby-ts-mode-tests) + +;;; ruby-ts-mode-tests.el ends here commit 84e7c2fbc85e5b7fbc5f9c225c2d1ba4cba2689b Author: Daniel Martín Date: Sat Dec 31 01:45:27 2022 +0100 Fix fontification of C++ reference return types (bug#60441) * lisp/progmodes/c-ts-mode.el (c-ts-fontify-error): Treat reference_declarator nodes the same as pointer_declarator nodes when calculating the identifier to fontify. diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el index 8325b411816..1f2a195bf64 100644 --- a/lisp/progmodes/c-ts-mode.el +++ b/lisp/progmodes/c-ts-mode.el @@ -425,7 +425,7 @@ c-ts-mode--declarator-identifier ;; Recurse. ((or "attributed_declarator" "parenthesized_declarator") (c-ts-mode--declarator-identifier (treesit-node-child node 0 t))) - ("pointer_declarator" + ((or "pointer_declarator" "reference_declarator") (c-ts-mode--declarator-identifier (treesit-node-child node -1))) ((or "function_declarator" "array_declarator" "init_declarator") (c-ts-mode--declarator-identifier commit 1864b65af6051f7028beba1a19dfe8bd2eed6574 Author: Yuan Fu Date: Sun Jan 1 16:15:02 2023 -0800 ; Minor fix for treesit--install-language-grammar-1 (bug#60465) * lisp/treesit.el (treesit--install-language-grammar-1): Fix. diff --git a/lisp/treesit.el b/lisp/treesit.el index 0b512cf8669..1ca72af5c2d 100644 --- a/lisp/treesit.el +++ b/lisp/treesit.el @@ -2772,6 +2772,8 @@ treesit--install-language-grammar-1 (rx bos (+ anychar) ".o" eos)) "-o" ,lib-name)) ;; Copy out. + (unless (file-exists-p out-dir) + (make-directory out-dir t)) (copy-file lib-name (file-name-as-directory out-dir) t t) (message "Library installed to %s/%s" out-dir lib-name)) (when (file-exists-p workdir) commit 8994f87ad40cabd99a93e0000abfd94777c59f96 Author: Jostein Kjønigsen Date: Sun Jan 1 17:27:06 2023 +0100 Adjust function-call fontification in csharp-ts-mode (bug#60376) - Ensure method-invocations are highlighted only on level 4. - Ensure consistent fontification of variable declarations (don't highlight usage of all variables). - Fix issues with highlighting types in new() expressions. - Fix issues with generic types in variable-declarations not using "var". - Use fewer, more general queries for function-invocations. simplify code. * lisp/progmodes/csharp-mode.el (csharp-ts-mode--font-lock-settings): Change rules. (csharp-ts-mode): Update feature list. diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el index da64daf9848..473e8f49fd3 100644 --- a/lisp/progmodes/csharp-mode.el +++ b/lisp/progmodes/csharp-mode.el @@ -696,7 +696,7 @@ csharp-ts-mode--font-lock-settings :feature 'expression '((conditional_expression (identifier) @font-lock-variable-name-face) (postfix_unary_expression (identifier)* @font-lock-variable-name-face) - (assignment_expression (identifier) @font-lock-variable-name-face)) + (initializer_expression (assignment_expression left: (identifier) @font-lock-variable-name-face))) :language 'c-sharp :feature 'bracket @@ -764,8 +764,12 @@ csharp-ts-mode--font-lock-settings (identifier) @font-lock-type-face) (type_argument_list (identifier) @font-lock-type-face) - (generic_name - (identifier) @font-lock-type-face) + (type_argument_list + (generic_name + (identifier) @font-lock-type-face)) + (base_list + (generic_name + (identifier) @font-lock-type-face)) (array_type (identifier) @font-lock-type-face) (cast_expression (identifier) @font-lock-type-face) @@ -773,7 +777,12 @@ csharp-ts-mode--font-lock-settings (type_parameter_constraints_clause target: (identifier) @font-lock-type-face) (type_of_expression (identifier) @font-lock-type-face) - (object_creation_expression (identifier) @font-lock-type-face)) + (object_creation_expression + type: (identifier) @font-lock-type-face) + (object_creation_expression + type: (generic_name (identifier) @font-lock-type-face)) + (as_expression right: (identifier) @font-lock-type-face) + (as_expression right: (generic_name (identifier) @font-lock-type-face))) :language 'c-sharp :feature 'definition @@ -793,7 +802,6 @@ csharp-ts-mode--font-lock-settings (record_declaration (identifier) @font-lock-type-face) (namespace_declaration (identifier) @font-lock-type-face) (base_list (identifier) @font-lock-type-face) - (property_declaration (generic_name)) (property_declaration type: (nullable_type) @font-lock-type-face name: (identifier) @font-lock-variable-name-face) @@ -807,29 +815,10 @@ csharp-ts-mode--font-lock-settings (constructor_declaration name: (_) @font-lock-type-face) - (method_declaration type: (_) @font-lock-type-face) + (method_declaration type: [(identifier) (void_keyword)] @font-lock-type-face) + (method_declaration type: (generic_name (identifier) @font-lock-type-face)) (method_declaration name: (_) @font-lock-function-name-face) - (invocation_expression - (member_access_expression - (generic_name (identifier) @font-lock-function-name-face))) - (invocation_expression - (member_access_expression - ((identifier) @font-lock-variable-name-face - (identifier) @font-lock-function-name-face))) - (invocation_expression - (identifier) @font-lock-function-name-face) - (invocation_expression - (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)) (catch_declaration @@ -837,13 +826,30 @@ csharp-ts-mode--font-lock-settings (identifier) @font-lock-variable-name-face)) (variable_declaration (identifier) @font-lock-type-face) + (variable_declaration (generic_name (identifier) @font-lock-type-face)) (variable_declarator (identifier) @font-lock-variable-name-face) (parameter type: (identifier) @font-lock-type-face) + (parameter type: (generic_name (identifier) @font-lock-type-face)) (parameter name: (identifier) @font-lock-variable-name-face) - (binary_expression (identifier) @font-lock-variable-name-face) - (argument (identifier) @font-lock-variable-name-face)) + (lambda_expression (identifier) @font-lock-variable-name-face) + + (declaration_expression type: (identifier) @font-lock-type-face) + (declaration_expression name: (identifier) @font-lock-variable-name-face)) + + :language 'c-sharp + :feature 'function + '((invocation_expression + function: (member_access_expression + name: (identifier) @font-lock-function-name-face)) + (invocation_expression + function: (identifier) @font-lock-function-name-face) + (invocation_expression + function: (member_access_expression + name: (generic_name (identifier) @font-lock-function-name-face))) + (invocation_expression + function: (generic_name (identifier) @font-lock-function-name-face))) :language 'c-sharp :feature 'escape-sequence @@ -916,7 +922,7 @@ csharp-ts-mode '(( comment definition) ( keyword string type) ( constant escape-sequence expression literal property) - ( bracket delimiter error))) + ( function bracket delimiter error))) ;; Imenu. (setq-local treesit-simple-imenu-settings commit 411647a3f65c0290eedda165c9469899f6a39445 Author: Eli Zaretskii Date: Sun Jan 1 19:38:24 2023 +0200 ; Fix NEWS. diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index cbc4c378248..fd06409fd59 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -235,7 +235,7 @@ Top Appendices -* Antinews:: Info for users downgrading to Emacs 27. +* Antinews:: Info for users downgrading to Emacs 28. * GNU Free Documentation License:: The license for this documentation. * GPL:: Conditions for copying and changing GNU Emacs. * Tips:: Advice and coding conventions for Emacs Lisp. diff --git a/etc/NEWS b/etc/NEWS index ae3c06c4872..36044d26244 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3812,21 +3812,21 @@ Standard. ** seq +++ -** New function 'seq-split'. +*** New function 'seq-split'. This returns a list of sub-sequences of the specified sequence. +++ -** New function 'seq-remove-at-position'. +*** New function 'seq-remove-at-position'. This function returns a copy of the specified sequence where the element at a given (zero-based) index got removed. +++ -** New function 'seq-positions'. +*** New function 'seq-positions'. This returns a list of the (zero-based) indices of elements matching a given predicate in the specified sequence. +++ -** New function 'seq-keep'. +*** New function 'seq-keep'. This is like 'seq-map', but removes all nil results from the returned list. @@ -4108,7 +4108,7 @@ where 'major-mode' is 'shell-mode' or a combined with a condition like +++ ** New function 'match-buffers'. -Use 'buffer-match-p' to gather a list of buffers that match a +It uses 'buffer-match-p' to gather a list of buffers that match a condition. --- commit 7b0b17df67e9c1fb197219c2434e86e6d648bf07 Author: Eli Zaretskii Date: Sun Jan 1 19:37:22 2023 +0200 Rewrite Antinews in ELisp manual for Emacs 29 * doc/lispref/anti.texi (Antinews): Rewrite for Emacs 29. * doc/lispref/elisp.texi (Top): Update the top-level menu for Antinews. diff --git a/doc/lispref/anti.texi b/doc/lispref/anti.texi index 157a7f8cc81..cddf675d336 100644 --- a/doc/lispref/anti.texi +++ b/doc/lispref/anti.texi @@ -6,179 +6,182 @@ @c This node must have no pointers. @node Antinews -@appendix Emacs 27 Antinews +@appendix Emacs 28 Antinews @c Update the elisp.texi Antinews menu entry with the above version number. For those users who live backwards in time, here is information about -downgrading to Emacs version 27.2. We hope you will enjoy the greater +downgrading to Emacs version 28.2. We hope you will enjoy the greater simplicity that results from the absence of many @w{Emacs @value{EMACSVER}} features. @itemize @bullet @item -The annoying @code{lexical-binding} local variable now heeds the -value of @code{enable-local-variables}: if it's @code{nil}, the -@code{lexical-binding} cookie is ignored. We are working hard on -removing the lexical-binding support in some past Emacs version, and -this small step advances us back to that change. +The implementation of overlays is back to its simple, time-proven +storage in a pair of linear linked lists centered around some buffer +position. No more fancy interval trees and suchlikes. Lisp programs +that use overlays once again need to recenter overlays around the +buffer position of interest, and display-related features should again +make sure they don't use too many overlays in a buffer, lest redisplay +will be too slow. @item -The @code{load-dangerous-libraries} variable is not obsolete, as it -must be used to allow loading Lisp compiled by XEmacs, which will -become more and more important as you move back in time. +Several functions stopped the annoying conversion of quotes and key +sequences by no longer calling @code{substitute-command-keys}. One +prominent example is @code{format-prompt} and all its many callers. +This makes the strings they produce much more predictable, returning +to you, the Lisp programmer, control on which punctuation characters +will appear in the text presented to the users. For similar reasons, +the @code{substitute-quotes} function was deleted. @item -The optional @var{modes} argument of @code{interactive} is not -supported, and every command is deemed applicable to any major mode. -We believe this makes the life of Lisp programmers much simpler, as -there's now no need to tag commands with the modes where they make -sense. +The venerable @code{buffer-modified-p} function again reliably returns +either @code{nil} or @code{t}, not any other confusing values. @item -Shorthands for Lisp symbols have been removed, which makes loading -Lisp files and handling Lisp symbols much simpler and more efficient. -This is important for decent performance on slower CPUs as you move -back in time. +The support for @samp{medium} weight of fonts was dropped. Emacs now +considers @samp{medium} and @samp{regular} weights to be the same. We +believe this will simplify your font setup, since there's no longer a +need to worry about fonts that support @samp{regular} weight, but not +the @samp{medium} one, or vice versa: either one will do! @item To reduce the amount of code in Emacs related to unimportant features, -we've removed the variables @code{global-minor-modes} and -@code{local-minor-modes}. If your Lisp program needs to determine -whether some minor mode is in effect, it will have to test explicitly -for every mode. We don't expect anyone to miss those fancy variables. +we've removed the function @code{compiled-function-p}. Lisp programs +are expected to test explicitly for the relevant types of function +objects: built-in, byte-compiled, and natively-compiled. For the same +reasons we deleted the functions @code{pos-bol}, @code{pos-eol}, +@code{file-attribute-file-identifier}, and quite a few others. We +don't expect anyone to miss those fancy functions. @item -The default preference for servicing sub-processes that produce output -at a high rate, and the associated variable -@code{process-prioritize-lower-fds}, have been removed. Moving back -in time means fewer and fewer programs can produce such high-rate -output, so this features becomes just useless crud. +The timeout used by @code{x-show-tip} can no longer be specified by +Lisp programs; it is hard-coded in the function. This will lead to a +simpler, easier maintained code, and no one should want to control the +timeout after which the tip pops down. @item -The encodings that are variants of EBCDIC were removed. This includes -@code{ibm256}, @code{ibm273}, and others---variants of the EBCDIC -encoding tailored for some Japanese and European locales. You won't -need those where you are going. +The macro @code{setopt} was deleted; use @code{customize-variable} +instead, or invoke the @code{:set} function from Lisp. @item -The ``Bindat type expression'' description language has been removed, -as the existing data layout specifications are perfectly suited for -this job. +We removed the @code{lisp-directory} variable, as the value can be +easily deduced from other similar variables, like +@code{installation-directory} and @code{source-directory}, each one +when it's relevant. @item -To simplify code and reduce complexity, we removed the capability of -specifying the success handler in @code{condition-case} via the -@code{:success} keyword. If you really need this feature (why would -you?), you can always write some simple Lisp that has the same effect. +To simplify code and reduce complexity, we deleted the functions +@code{get-display-property} and @code{add-display-text-property}; use +the generic @code{get-text-property} and @code{put-text-property} +instead. @item -Emacs modules can no longer provide interactive functions, or install -finalizers, nor open channels to existing pipe sub-processes. All -this is extra ballast, especially since we plan on removing modules in -some past Emacs version. The @code{make_unibyte_string} module API -was removed for the same reason. +Support for pinch input events and for modern drag-and-drop +functionality on X was dropped. As you move back in time, these +facilities will become less and less important, and will soon enough +disappear, so there's no reason to keep them in Emacs. @item -To keep Emacs clean and elegant, we've removed the -@code{print-integers-as-characters} option. Recognizing characters by -their decimal codes is a basic requirement for Emacs Lisp programmers, -and with the expected decrease in use of Unicode characters, this will -be soon limited to ASCII only: surely something you all can master! +To keep Emacs clean and elegant, we've removed the @file{textsec.el} +library, with its facilities for checking whether some text is +``suspicious''. We consider our users smart enough to detect +maliciously modified text by just looking at it or by moving the +cursor across it, and the whole idea that someone would wish to +deliberately deceive Emacs users ridiculous and unworthy of +complicating our elegant text-processing and display capabilities. @item -The optional @var{count} argument of the @code{directory-files} -function has been removed. Extracting the first @var{n} members from -the full list is trivial, so this is a significant simplification for -an insignificant cost. +The functions @code{keymap-set}, @code{keymap-global-set}, +@code{keymap-local-set}, @code{keymap-substitute}, +@code{keymap-lookup}, and some others were deleted. We have found the +traditional @code{define-key}, @code{global-set-key}, +@code{local-set-key}, @code{substitute-key-definition}, and +@code{key-binding} more than enough, and their minor inconsistencies +in the syntax of keys they accept a source of endless fun in Emacs +Lisp programming. Why make Emacs programming a dull place? For the +same reasons we deleted @code{key-valid-p}, since we consider the +permissive nature of @code{kbd} more in the spirit of Emacs Lisp. @item -Functions that create sub-processes and network connections no longer -accept the @code{:coding} argument; use -@code{set-process-coding-system} or bind -@code{coding-system-for-read/write} instead: again, a significant -reduction in Emacs complexity for little or no cost. +Yanking of anything but plain text from other applications becomes +more and more an unnecessary feature as you move back in time, so we +dropped support for pasting media like HTML and images via the +clipboard. If you @i{really} need to yank those into an Emacs buffer, +you can go via a disk file. @item -We deleted from the macros @code{define-derived-mode} and -@code{define-minor-mode} the code which allowed using the -@code{:interactive} argument. The possibility of marking a mode -non-interactive makes very little sense, +We removed unnecessary functions @code{string-pixel-width} and +@code{string-glyph-split}, as we consider it inappropriate for Lisp +programs to do display layout calculations, where these functions come +in handy. Display is for the display engine, written in C, and should +stay there! @item -The possibility of having links to man pages in doc strings has been -removed. Use plain text instead, if you need such references. +Various new Xwidget functions, such as +@code{xwidget-perform-lispy-event}, @code{xwidget-webkit-load-html}, +and @code{xwidget-webkit-back-forward-list}, were deleted as part of +our continuing effort to gradually delete the entire Xwidget +functionality in some previous release of Emacs. @item -Temporary buffers are no longer exempt from running any buffer-related -hooks. Programs that don't want such hooks in some buffer can always -disable it locally, whereas making that simpler complicates Emacs for -no good reason. +Setting the @code{:stderr} property of a process in a +@code{make-process} call once again forces the process's connection to +use pipes, not ptys, for all the standard streams --- a considerable +simplification of this complex interface. @item +To keep the amount of Lisp functions from growing out of control, we +deleted @code{string-equal-ignore-case}. Use @code{compare-strings} +instead. + Several features that complicated the byte compiler have been removed: @itemize @minus @item -The checks for missing declarations of dynamic variables. This will -continue making less and less sense as we move away of lexical-binding -support. - -@item -The ability of compiling symlinked @file{*.el} files, which is really -gross: copy the files instead. +The warnings about quoting mistakes in documentation strings. You are +expected to find such mistakes yourself, by eyeballing the resulting +@file{*Help*} buffer display. @item -The warnings about too-wide doc strings---that is just a nuisance, as -the programmers should be trusted to know what they are doing. +The warnings about malformed @code{defcustom} types, like +double-quoting symbols in @code{choice} lists. @end itemize - -@item -We deleted several features of the @code{pcase} macro, in accordance -with our general plan to remove @code{pcase} from Emacs: - -@itemize @minus -@item -The @code{cl-type} pattern. - @item -the @code{pcase-setq} macro. - -@item -The @code{pcase-compile-patterns} function. -@end itemize +The macro @code{with-buffer-unmodified-if-unchanged} was deleted. +Lisp programs that need to leave the buffer unmodified in these cases +can always compare the text before and after the modifications. @item -Some of the keywords used in Edebug specification lists were deemed to -be of little use, and were therefore removed: @code{&interpose}, -@code{&error}, and @code{&name}. The long-term plane is for Emacs to -drop Edebug entirely, leaving only the trusted Lisp debugger, and we -continue working according to that plan. +The functions @code{string-edit} and @code{read-string-from-buffer} +were removed, as we consider the fun of programming them anew every +time an important part of the education of each Emacs Lisp developer. @item -The function @code{object-intervals} was dropped, as a Lisp program -can easily collect the intervals of a buffer or a string by iterating -through them one by one. +We deleted the function @code{readablep} and the related variable +@code{print-unreadable-function}, since no one is supposed to want to +print unreadable Lisp objects. @item -We decided that the @code{require-theme} function is an unnecessary -complication, so we deleted it. Lisp programs can easily search along -@code{custom-theme-load-path} instead. +The facility for storing multisession variables was deleted as an +unnecessary complication. With it are gone @code{multisession-value}, +@code{define-multisession-variable}, and +@code{list-multisession-values}. @item -The convenience functions @code{length<}, @code{length>}, and -@code{length=} were removed, as using @code{length} followed by a -comparison should be good enough for everyone, especially considering -that the typical length of a list keeps going down as you move back -through time. +The support for the @code{cursor-face} text property was dropped. We +consider the rest of the faces adequate for supporting this +functionality. @item -The variable @code{current-minibuffer-command} is no longer available, -as we found little justification for keeping it. +The function @code{tooltip-show} dropped support for optional face +arguments @code{text-face} and @code{default-face} that allow fancy +control of the face of the tip text and top frame colors. We decided +that tooltips should all look the same, to prevent user confusion. @item As part of the ongoing quest for simplicity, many other functions and variables have been eliminated. Other functions and variables, that -were declared obsolete since Emacs 23, have been added back, in -preparation for releasing Emacs 23 in some distant past. +were declared obsolete since Emacs 24, have been added back, in +preparation for releasing Emacs 24 in some distant past. @end itemize commit f12f72b0e09c7a45098955c1304499963a5eb9a7 Author: Eli Zaretskii Date: Sun Jan 1 17:49:10 2023 +0200 ; * lisp/simple.el (primitive-undo): Clarify error message (bug#60467) diff --git a/lisp/simple.el b/lisp/simple.el index 16f23ea3623..63479e9ce0a 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -3590,7 +3590,7 @@ primitive-undo ;; said it would do. (unless (and (= start start-mark) (= (+ delta end) end-mark)) - (error "Changes to be undone by function different from announced")) + (error "Changes undone by function are different from the announced ones")) (set-marker start-mark nil) (set-marker end-mark nil)) (apply fun-args)) commit 7fd822e7f52c253e315cc0366e8c1b7eb3945c17 Author: Eli Zaretskii Date: Sun Jan 1 17:38:23 2023 +0200 Update Antinews in the user manual for Emacs 29 * doc/emacs/anti.texi (Antinews): Rewrite for Emacs 29. * doc/emacs/emacs.texi (Top): Adjust the top-level menu. diff --git a/doc/emacs/anti.texi b/doc/emacs/anti.texi index 58ab06b36d2..c46110a530d 100644 --- a/doc/emacs/anti.texi +++ b/doc/emacs/anti.texi @@ -4,134 +4,154 @@ @c See file emacs.texi for copying conditions. @node Antinews -@appendix Emacs 27 Antinews +@appendix Emacs 28 Antinews @c Update the emacs.texi Antinews menu entry with the above version number. For those users who live backwards in time, here is information -about downgrading to Emacs version 27.2. We hope you will enjoy the +about downgrading to Emacs version 28.2. We hope you will enjoy the greater simplicity that results from the absence of many @w{Emacs @value{EMACSVER}} features. @itemize @bullet @item -Emacs can no longer be built with support of native compilation of -Lisp programs. This means Emacs builds much faster, and the problems -that came with native compilation: the need to have GCC and Binutils -installed, the complications of managing your @file{eln-cache} -directories---all of that is now future history. The simplicity and -elegance of the Emacs byte-compiled code is now restored in all of its -pristine beauty. +Like its newer releases, Emacs 28 can still be built with support of +native compilation of Lisp programs. However, in preparation for +removal of this feature in some previous version, we've deleted the +capability of ahead-of-time native compilation of all the Lisp files +that come with Emacs. This makes the Emacs build process much faster. @item -Emacs no longer builds by default with Cairo, even if it's present. -The warnings about not using HarfBuzz are also gone, in preparation -for complete removal of HarfBuzz support in previous Emacs versions. -Fancy text shaping and display is becoming less important as you move -back in time. The @code{ftx} font backend is again part of Emacs, for -the same reasons. +Emacs can no longer be built with the tree-sitter library, so you no +longer will need to look for and install the grammar libraries for +the languages in which you want to program. Similarly, all the modes +that are based on the tree-sitter library were deleted, leaving you +with just one major mode for every supported programming language: no +more need to decide whether to turn the tree-sitter supported modes on +and try using their parser-based fontification, indentation, and other +features. For some languages and file types, this means no major mode +at all, leaving you with the venerable Fundamental mode as the +natural, high-performance choice. For example, Go, Rust, and CMake +files no longer have any major modes for editing their files --- +another milestone towards a simpler, leaner Emacs. @item -Emacs once again supports versions 5.3 and older OpenBSD systems, -which will be needed as you move back in time. +Built-in support for accessing SQLite databases was removed. You can +now again edit SQLite files as simple binary files, which Emacs is +quite capable to support, as it always did. @item -We've dropped support for Secure Computing filter on GNU/Linux. The -past world is much more secure than the present, so the complexities -related with this stuff, which can only be explained by severe -paranoia, are no longer justified. +As a gesture to users of the Haiku operating system, we've dropped the +code which allowed Emacs to be built on that OS@. We expect Haiku +users to enjoy the much simpler editors they have for editing their +files. @item -Emacs reverted back to supporting Unicode 13.x, since the following -versions of the standards are not yet published where you are going. -The @samp{emoji} script and the support for displaying Emoji sequences -were removed for the same reasons: no one will produce them in the -past. +Support for XInput2 input events on X is gone. We think the +traditional X input events are more than enough, certainly so as you +move back in time, where XInput2 will eventually be removed from X as +well, once the maintainers of the X Windows system realize the utter +futility of supporting fancy input mechanisms. @item -Mode-specific commands and the @kbd{M-S-x} command that invokes them -were removed. As you move back in time, the command set in Emacs -becomes smaller, so any such filtering of applicable commands just -gets in the way. +The ``pure GTK'' (a.k.a.@: @acronym{PGTK}) configuration of Emacs is +no longer supported. This is in anticipation of the complete removal +of the GTK toolkit support from Emacs, and in accordance with our +expectation that GTK will cease to exist as you move back in time. We +plan on removing support for all the other toolkits as well, leaving +only the pure X build with our own widgets as the single supported GUI +configuration on X. @item -We have removed the system for displaying documentation of groups of -related functions, the @kbd{shortdoc-display-group} command to go with -it, and the corresponding ``See also'' button in the @file{*Help*} -buffer. That should make searching for certain functions simpler: -just use the venerable @samp{apropos} commands. +The @option{--init-directory} command-line option was removed, as +initializing Emacs with init files of another user is a preposterous +idea anyway. @item -The @code{context-menu-mode} was removed, and with it the context -menus popped by pressing the right mouse button. This is one small -step towards freeing Emacs (and eventually, the whole world of -computing) from the tyranny of the GUI pointing devices in general, -and moving back to the simplicity of text-mode user interfaces. -Down with mice and other rodents! +In line with simplifying and eventually removing the +native-compilation option, we've deleted the +@code{inhibit-automatic-native-compilation} variable and its support +code. This greatly simplifies how native compilation works and makes +your configure-time decision regarding native compilation in Emacs +clear-cut: either Emacs always compiles Lisp to native code before +using it, or it never does so; no more half measures and special +exceptions. For similar reasons, @code{native-compile-prune-cache} +and @code{startup-redirect-eln-cache} features are no longer part of +Emacs. @item -The commands @kbd{C-x 4 4} and @kbd{C-x 5 5} for displaying the -results in a new window/frame re gone. We are quite certain that -creating a new window/frame before running a command is much simpler, -and doesn't require a complication of a new prefix. +We've deleted the special code and features which allowed Emacs to +present decent performance and responsiveness when editing files with +very long lines. Such files become more and more rare as time goes +back, and so having all this tricky code in Emacs for their benefit +was deemed an unnecessary complication. @item -The behavior of active minibuffers when switching frames is now the -perfect mess it should be: sometimes the minibuffer moves to the new -selected frame, sometimes it doesn't, and sometimes you get an error. -This makes Emacs usage much more fun, as you get to guess the result, -instead of having it boringly consistent. +Emacs dropped support for Eglot and the LSP servers. We decided that +the built-in ways of analyzing source code are more than enough as you +move back in time. @item -Compact mode-line display mode has been removed. The items displayed -on the mode line are now always in the same place, and if there's not -enough space for them, they are not displayed at all, instead of being -confusingly displayed in a different position. You no longer need to -think twice where to find a particular mode-line element on display. +Commands to scale and rotate images are once again bound to single +keys like @kbd{+}, @kbd{-}, and @kbd{r}, which makes them much easier +to type. As for the risk of typing these by mistake, we don't believe +Emacs users make typing mistakes, especially as they move back in +time and become younger and younger. @item -Many commands and options related to tab bars were removed, including -(but not limited to) frame-specific appearance of tab bars, the -@code{tab-bar-format} option, the @kbd{C-x t n}, @kbd{C-x t N}, -@kbd{C-x t M}, and @kbd{C-x t G} commands, and many mouse gestures on -the tab bar. We are going to delete the tab bar support from Emacs in -one of the past versions, and this is a step in that direction. +To simplify typing popular commands, we've rebound the @w{@kbd{C-x 8 . .}} +back to @w{@kbd{C-x 8 .}} and @w{@kbd{C-x 8 = =}} back to @w{@kbd{C-x 8 =}}. +There's no need for fancier, longer key sequences, as moving back in +time means we will have fewer and fewer commands to bind to them in +the first place. @item -The ``transient'' input methods have been removed; use @kbd{C-\} to -turn input methods on and off instead. This is in preparation for -complete removal of input methods from Emacs in version 19, and -consistent with the fact that the number of input methods we support -becomes smaller as you move back in time. +If you inadvertently kill the @file{*scratch*} buffer, Emacs will +recreate it in Fundamental mode, not in Lisp Interaction mode. You +get to turn on the mode you like yourself. Our long-term plans for +past Emacs releases is to remove the recreation of @file{*scratch*} +altogether, and this is the first step in that direction. @item -We disabled @code{show-paren-mode} by default, since we think the -venerable @code{blink-matching-paren} feature is more than enough, and -better fits the simplicity of past Emacs versions. It will definitely -be better when colors are removed from Emacs in the distant past. +Support for @code{rlogin} and @code{rsh} protocols are back, since we +expect them to become more and more important and popular as you move +back in time. -For the same reason, sub-groups in interactive regexp searches are no -longer highlighted in distinct colors. +@item +In preparation for eventual removal of Unicode support from Emacs, +we've downgraded our Unicode support to version 14.0. + +@item +You can no longer change the size of the font globally. Since Emacs +will at some past date remove all support for variable-size fonts, +having such commands is a luxury we are better without. + +@item +On our permanent quest for simplifying Emacs, we've removed the +commands @code{duplicate-line} and @code{duplicate-dwim}; the old-time +friends @kbd{M-w} and @kbd{C-y} (typed one or more times) should +suffice. The command @code{rename-visited-file} is gone for the same +reason. @item -On our permanent quest for simplifying Emacs, we've removed the Ispell -command @code{ispell-comment-or-string-at-point}; the old-time friend -@code{ispell-comments-and-strings} should suffice. +We've deleted many commands related to Emoji, which were bound in the +@kbd{C-x 8 e} prefix keymap. We decided that the ability to type +Emoji sequences using @kbd{C-x 8 @key{RET}} is enough, and actually +serves our users better by requiring them to know the codepoints of +the sequences they want to type. @item -Many Gnus commands and options were deemed to unnecessarily complicate -the use of Gnus (which is too complex to begin with), and thus were -removed. This includes @code{gnus-topic-display-predicate}, -@code{gnus-process-mark-toggle}, @code{gnus-registry-register-all}, -@code{gnus-paging-select-next}, and many others. The @code{nnselect} -backend was deleted for the same reason. +We dropped support for many scripts and input methods, especially old +scripts that no one uses anyway. For similar reasons, Greek and +Ukrainian translations of the Emacs tutorial are not available +anymore. @item -The @file{project.el} package have been redesigned to remove many -unnecessary features, so that just the bare essentials remain. We -plan on removing this package from Emacs in a previous version, but -decided to begin with removing some extra features first. +@file{package.el} can no longer fetch source code of packages from +their VCS repositories. We think command-line tools like Git should +be enough to allow you to clone their repositories. So we deleted +the @code{package-vc-install} command and other similar commands. @item To keep up with decreasing computer memory capacity and disk space, many -other functions and files have been eliminated in Emacs 27.2. +other functions and files have been eliminated in Emacs 28.2. @end itemize diff --git a/doc/emacs/emacs.texi b/doc/emacs/emacs.texi index 83486a23793..b6d149eb3ef 100644 --- a/doc/emacs/emacs.texi +++ b/doc/emacs/emacs.texi @@ -220,7 +220,7 @@ Top * GNU Free Documentation License:: The license for this documentation. * Emacs Invocation:: Hairy startup options. * X Resources:: X resources for customizing Emacs. -* Antinews:: Information about Emacs version 27. +* Antinews:: Information about Emacs version 28. * Mac OS / GNUstep:: Using Emacs under macOS and GNUstep. * Haiku:: Using Emacs on Haiku. * Microsoft Windows:: Using Emacs on Microsoft Windows and MS-DOS. commit da77d70deeb2798693ec4f28a291befeb8e43989 Author: Mattias Engdegård Date: Sun Jan 1 13:18:50 2023 +0100 ; * test/lisp/emacs-lisp/copyright-tests.el: Fix and future-safe. diff --git a/test/lisp/emacs-lisp/copyright-tests.el b/test/lisp/emacs-lisp/copyright-tests.el index ef531174617..5f8b5c67896 100644 --- a/test/lisp/emacs-lisp/copyright-tests.el +++ b/test/lisp/emacs-lisp/copyright-tests.el @@ -59,7 +59,8 @@ test-end-chop "\nCopyright 2006, 2007, 2008 Foo Bar\n\n") (copyright-update) (buffer-substring (- (point-max) 42) (point-max)))) - "Copyright 2006, 2007, 2008, 2022 Foo Bar\n\n"))) + (format "Copyright 2006, 2007, 2008, %s Foo Bar\n\n" + (format-time-string "%Y"))))) (ert-deftest test-correct-notice () (should (equal @@ -70,7 +71,8 @@ test-correct-notice (copyright-query nil)) (copyright-update)) (buffer-string)) - "Copyright 2021 FSF\nCopyright 2021, 2022 FSF\n"))) + (format "Copyright 2021 FSF\nCopyright 2021, %s FSF\n" + (format-time-string "%Y"))))) (defmacro with-copyright-fix-years-test (orig result) `(let ((copyright-year-ranges t)) commit 2baf9e107c1d6f1c71f5804b6bd933d3f5d6a9ea Author: Mattias Engdegård Date: Sun Jan 1 12:52:47 2023 +0100 Fix shortdoc-tests failure with respect to regexp-opt-charset * test/lisp/emacs-lisp/shortdoc-tests.el (regexp-opt): Require. `regexp-opt-charset` is not autoloaded, and whether `regexp-opt` is preloaded is configuration-dependent. diff --git a/test/lisp/emacs-lisp/shortdoc-tests.el b/test/lisp/emacs-lisp/shortdoc-tests.el index 914aee633ee..516d095767f 100644 --- a/test/lisp/emacs-lisp/shortdoc-tests.el +++ b/test/lisp/emacs-lisp/shortdoc-tests.el @@ -22,6 +22,7 @@ (require 'ert) (require 'shortdoc) (require 'subr-x) ; `string-pad' in shortdoc group needed at run time +(require 'regexp-opt) ; `regexp-opt-charset' not autoloaded (defun shortdoc-tests--tree-contains (tree fun) "Whether TREE contains a call to FUN." commit 5aeb8de32ee54baacedfcfc56d951b04145dea5d Author: Eli Zaretskii Date: Sun Jan 1 13:08:15 2023 +0200 ; Fix copyright years in 2 more files. diff --git a/etc/images/gnus/README b/etc/images/gnus/README index 7fe27efc80f..f05cf0f7f10 100644 --- a/etc/images/gnus/README +++ b/etc/images/gnus/README @@ -21,11 +21,11 @@ Files: catchup.pbm catchup.xpm cu-exit.pbm cu-exit.xpm unsubscribe.pbm unsubscribe.xpm uu-decode.pbm uu-decode.xpm uu-post.pbm uu-post.xpm Author: Luis Fernandes -Copyright (C) 2001-2022 Free Software Foundation, Inc. +Copyright (C) 2001-2023 Free Software Foundation, Inc. Files: gnus.png, gnus.svg Author: Francesc Rocher - Copyright (C) 2008-2022 Free Software Foundation, Inc. + Copyright (C) 2008-2023 Free Software Foundation, Inc. * The following icons are from GNOME 2.x. They are not part of Emacs, diff --git a/etc/images/icons/README b/etc/images/icons/README index d6065232e0c..bb455980ca7 100644 --- a/etc/images/icons/README +++ b/etc/images/icons/README @@ -14,7 +14,7 @@ Files: hicolor/16x16/apps/emacs23.png hicolor/24x24/apps/emacs23.png hicolor/128x128/apps/emacs23.png hicolor/scalable/apps/emacs23.svg Author: Kentaro Ohkouchi -Copyright (C) 2007-2022 Free Software Foundation, Inc. +Copyright (C) 2007-2023 Free Software Foundation, Inc. License: GNU General Public License version 3 or later (see COPYING) @@ -22,7 +22,7 @@ Files: hicolor/16x16/apps/emacs22.png hicolor/24x24/apps/emacs22.png hicolor/32x32/apps/emacs22.png hicolor/48x48/apps/emacs22.png Author: Andrew Zhilin -Copyright (C) 2005-2022 Free Software Foundation, Inc. +Copyright (C) 2005-2023 Free Software Foundation, Inc. License: GNU General Public License version 3 or later (see COPYING) Files: allout-widgets-dark-bg/closed.png @@ -71,5 +71,5 @@ Files: allout-widgets-dark-bg/closed.png allout-widgets-light-bg/through-descender.xpm Author: Ken Manheimer -Copyright (C) 2011-2022 Free Software Foundation, Inc. +Copyright (C) 2011-2023 Free Software Foundation, Inc. License: GNU General Public License version 3 or later (see COPYING)