commit 723b0973512c0e6e9fb0f07678124347ccd44b54 (HEAD, refs/remotes/origin/master) Author: Jim Porter Date: Thu Jan 25 20:58:34 2024 -0800 Add support for running commands via Eshell's "env" command * (eshell-handle-local-variables): Move most of the code to... (eshell-parse-local-variables): ... here. (eshell/env): Call 'eshell-parse-local-variables'. * test/lisp/eshell/esh-var-tests.el (esh-var-test/local-variables/env): New test. * doc/misc/eshell.texi (Built-ins): Describe the new behavior. * etc/NEWS: Announce this change. diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi index fb9a563b696..da5e1ef1d03 100644 --- a/doc/misc/eshell.texi +++ b/doc/misc/eshell.texi @@ -624,9 +624,11 @@ each argument as a string, separated by a space. @item env @cmindex env -Prints the current environment variables. Unlike in Bash, this -command does not yet support running commands with a modified -environment. +With no arguments, print the current environment variables. If you +pass arguments to this command, then @command{env} will execute the +arguments as a command. If you pass any initial arguments of the form +@samp{@var{var}=@var{value}}, @command{env} will first set @var{var} +to @var{value} before running the command. @item eshell-debug @cmindex eshell-debug diff --git a/etc/NEWS b/etc/NEWS index 0d7d7d5ab60..37264f2f1f1 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -656,6 +656,13 @@ appropriate, but still allow piping the output elsewhere if desired. For more information, see the "(eshell) Built-ins" node in the Eshell manual. ++++ +*** Eshell's 'env' command now supports running commands. +Like in many other shells, Eshell's 'env' command now lets you run a +command passed as arguments to 'env'. If you pass any initial +arguments of the form 'VAR=VALUE', 'env' will first set 'VAR' to +'VALUE' before running the command. + +++ *** New special reference type '#'. This special reference type returns a marker at 'POSITION' in diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index 1d90fbdd8ee..627cbb17797 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -304,27 +304,36 @@ This is set to t in `eshell-local-variable-bindings' (which see).") (add-hook 'pcomplete-try-first-hook #'eshell-complete-variable-assignment nil t))) -(defun eshell-handle-local-variables () - "Allow for the syntax `VAR=val '." +(defun eshell-parse-local-variables (args) + "Parse a list of ARGS, looking for variable assignments. +Variable assignments are of the form \"VAR=value\". If ARGS +begins with any such assignments, throw `eshell-replace-command' +with a form that will temporarily set those variables. +Otherwise, return nil." ;; Handle local variable settings by let-binding the entries in ;; `eshell-local-variable-bindings' and calling `eshell-set-variable' ;; for each variable before the command is invoked. (let ((setvar "\\`\\([A-Za-z_][A-Za-z0-9_]*\\)=\\(.*\\)\\'") - (command eshell-last-command-name) - (args eshell-last-arguments)) - (when (and (stringp command) (string-match setvar command)) + (head (car args)) + (rest (cdr args))) + (when (and (stringp head) (string-match setvar head)) (throw 'eshell-replace-command `(let ,eshell-local-variable-bindings ,@(let (locals) - (while (and (stringp command) - (string-match setvar command)) + (while (and (stringp head) + (string-match setvar head)) (push `(eshell-set-variable - ,(match-string 1 command) - ,(match-string 2 command)) + ,(match-string 1 head) + ,(match-string 2 head)) locals) - (setq command (pop args))) + (setq head (pop rest))) (nreverse locals)) - (eshell-named-command ,command ,(list 'quote args))))))) + (eshell-named-command ,head ',rest)))))) + +(defun eshell-handle-local-variables () + "Allow for the syntax `VAR=val '." + (eshell-parse-local-variables (cons eshell-last-command-name + eshell-last-arguments))) (defun eshell-interpolate-variable () "Parse a variable interpolation. @@ -414,19 +423,22 @@ the values of nil for each." obarray #'boundp)) (pcomplete-here)))) -;; FIXME the real "env" command does more than this, it runs a program -;; in a modified environment. (defun eshell/env (&rest args) "Implementation of `env' in Lisp." - (eshell-init-print-buffer) (eshell-eval-using-options "env" args - '((?h "help" nil nil "show this usage screen") + '(;; FIXME: Support more "env" options, like "--unset". + (?h "help" nil nil "show this usage screen") :external "env" - :usage "") - (dolist (setting (sort (eshell-environment-variables) 'string-lessp)) - (eshell-buffered-print setting "\n")) - (eshell-flush))) + :parse-leading-options-only + :usage "[NAME=VALUE]... [COMMAND [ARG]...]") + (if args + (or (eshell-parse-local-variables args) + (eshell-named-command (car args) (cdr args))) + (eshell-init-print-buffer) + (dolist (setting (sort (eshell-environment-variables) 'string-lessp)) + (eshell-buffered-print setting "\n")) + (eshell-flush)))) (defun eshell-insert-envvar (envvar-name) "Insert ENVVAR-NAME into the current buffer at point." diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index bb3d18abf6d..b94e8a276d7 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -661,6 +661,13 @@ nil, use FUNCTION instead." (eshell-insert-command "VAR=hello cd ..") (should (equal default-directory parent-directory))))) +(ert-deftest esh-var-test/local-variables/env () + "Test that \"env VAR=value command\" temporarily sets variables." + (with-temp-eshell + (push "VAR=value" process-environment) + (eshell-match-command-output "env VAR=hello env" "VAR=hello\n") + (should (equal (getenv "VAR") "value")))) + ;; Variable aliases commit f897b82ab16ac92e7fd800f75b00e55762b0df31 Author: Jim Porter Date: Thu Jan 25 20:54:48 2024 -0800 ; * etc/NEWS: Fix thinko in Eshell entry. diff --git a/etc/NEWS b/etc/NEWS index a1874313502..0d7d7d5ab60 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -660,9 +660,10 @@ manual. *** New special reference type '#'. This special reference type returns a marker at 'POSITION' in 'BUFFER'. You can insert it by typing or using the new interactive -command 'eshell-insert-marker'. You can also insert markers of any -type with the new command 'eshell-insert-special-reference'. See the -"(eshell) Arguments" node in the Eshell manual for more details. +command 'eshell-insert-marker'. You can also insert special +references of any type using the new interactive command +'eshell-insert-special-reference'. See the "(eshell) Arguments" node +in the Eshell manual for more details. +++ *** New splice operator for Eshell dollar expansions. commit 16831e290ed29f5f70dfe144ec63c583527485e8 Author: Po Lu Date: Fri Jan 26 11:24:51 2024 +0800 Avert race condition between window attachment and buffer swap * java/org/gnu/emacs/EmacsView.java (swapBuffers): Synchronize such that code cannot execute between the bitmap's being loaded and being transferred to surfaceView. (onDetachedFromWindow): Recycle bitmap after the surface view is reset. * java/org/gnu/emacs/EmacsWindow.java (recreateActivity): * src/android.c (android_init_emacs_window) (android_recreate_activity): * src/androidfns.c (Fandroid_recreate_activity) (syms_of_androidfns): New functions for debugging window attachment. * src/androidgui.h: Update prototypes. diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java index 136d8abc713..8398e4b784c 100644 --- a/java/org/gnu/emacs/EmacsView.java +++ b/java/org/gnu/emacs/EmacsView.java @@ -456,7 +456,6 @@ else if (child.getVisibility () != GONE) { Canvas canvas; Rect damageRect; - Bitmap bitmap; /* Make sure this function is called only from the Emacs thread. */ @@ -474,11 +473,12 @@ else if (child.getVisibility () != GONE) damageRect = damageRegion.getBounds (); damageRegion.setEmpty (); - bitmap = getBitmap (); - - /* Transfer the bitmap to the surface view, then invalidate - it. */ - surfaceView.setBitmap (bitmap, damageRect); + synchronized (this) + { + /* Transfer the bitmap to the surface view, then invalidate + it. */ + surfaceView.setBitmap (bitmap, damageRect); + } } @Override @@ -724,17 +724,20 @@ else if (child.getVisibility () != GONE) public synchronized void onDetachedFromWindow () { - isAttachedToWindow = false; - - /* Recycle the bitmap and call GC. */ - - if (bitmap != null) - bitmap.recycle (); + Bitmap savedBitmap; + savedBitmap = bitmap; + isAttachedToWindow = false; bitmap = null; canvas = null; + surfaceView.setBitmap (null, null); + /* Recycle the bitmap and call GC. */ + + if (savedBitmap != null) + savedBitmap.recycle (); + /* Collect the bitmap storage; it could be large. */ Runtime.getRuntime ().gc (); diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java index 207bd22c538..304304a328b 100644 --- a/java/org/gnu/emacs/EmacsWindow.java +++ b/java/org/gnu/emacs/EmacsWindow.java @@ -1784,4 +1784,32 @@ else if (type.equals (ClipDescription.MIMETYPE_TEXT_URILIST)) return true; } + + + + /* Miscellaneous functions for debugging graphics code. */ + + /* Recreate the activity to which this window is attached, if any. + This is nonfunctional on Android 2.3.7 and earlier. */ + + public void + recreateActivity () + { + final EmacsWindowAttachmentManager.WindowConsumer attached; + + attached = this.attached; + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) + return; + + view.post (new Runnable () { + @Override + public void + run () + { + if (attached instanceof EmacsActivity) + ((EmacsActivity) attached).recreate (); + } + }); + } }; diff --git a/src/android.c b/src/android.c index 509f30a759b..51eb85a97e8 100644 --- a/src/android.c +++ b/src/android.c @@ -111,6 +111,7 @@ struct android_emacs_window jmethodID set_dont_focus_on_map; jmethodID define_cursor; jmethodID damage_rect; + jmethodID recreate_activity; }; struct android_emacs_cursor @@ -1802,12 +1803,12 @@ android_init_emacs_window (void) FIND_METHOD (set_dont_accept_focus, "setDontAcceptFocus", "(Z)V"); FIND_METHOD (define_cursor, "defineCursor", "(Lorg/gnu/emacs/EmacsCursor;)V"); - /* In spite of the declaration of this function being located within EmacsDrawable, the ID of the `damage_rect' method is retrieved from EmacsWindow, which avoids virtual function dispatch within android_damage_window. */ FIND_METHOD (damage_rect, "damageRect", "(IIII)V"); + FIND_METHOD (recreate_activity, "recreateActivity", "()V"); #undef FIND_METHOD } @@ -6638,6 +6639,24 @@ android_request_storage_access (void) android_exception_check (); } +/* Recreate the activity to which WINDOW is attached to debug graphics + code executed in response to window attachment. */ + +void +android_recreate_activity (android_window window) +{ + jobject object; + jmethodID method; + + object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW); + method = window_class.recreate_activity; + + (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, object, + window_class.class, + method); + android_exception_check (); +} + /* The thread from which a query against a thread is currently being diff --git a/src/androidfns.c b/src/androidfns.c index 34f1f533684..eaecb78338b 100644 --- a/src/androidfns.c +++ b/src/androidfns.c @@ -3164,6 +3164,24 @@ android_set_preeditarea (struct window *w, int x, int y) y + w->phys_cursor_height); } + + +/* Debugging. */ + +DEFUN ("android-recreate-activity", Fandroid_recreate_activity, + Sandroid_recreate_activity, 0, 0, "", + doc: /* Recreate the activity attached to the current frame. +This function exists for debugging purposes and is of no interest to +users. */) + (void) +{ + struct frame *f; + + f = decode_window_system_frame (Qnil); + android_recreate_activity (FRAME_ANDROID_WINDOW (f)); + return Qnil; +} + #endif /* !ANDROID_STUBIFY */ @@ -3550,6 +3568,7 @@ language to be US English if LANGUAGE is empty. */); defsubr (&Sandroid_request_directory_access); defsubr (&Sandroid_external_storage_available_p); defsubr (&Sandroid_request_storage_access); + defsubr (&Sandroid_recreate_activity); tip_timer = Qnil; staticpro (&tip_timer); diff --git a/src/androidgui.h b/src/androidgui.h index 69efd393d55..89317581191 100644 --- a/src/androidgui.h +++ b/src/androidgui.h @@ -708,6 +708,7 @@ extern void android_translate_coordinates (android_window, int, extern int android_wc_lookup_string (android_key_pressed_event *, wchar_t *, int, int *, enum android_lookup_status *); +extern void android_recreate_activity (android_window); extern void android_update_ic (android_window, ptrdiff_t, ptrdiff_t, ptrdiff_t, ptrdiff_t); extern void android_reset_ic (android_window, enum android_ic_mode); commit 65829b27ca4898ff0905a8124980243977a1382f Author: Jim Porter Date: Thu Jan 25 17:54:13 2024 -0800 Improve handling of local variable settings in Eshell This ensures that these commands work the same as normal commands, aside from making environment variable settings local to that command. Among other things, this means that "VAR=value cd dir/" now changes the directory correctly. * lisp/eshell/esh-var.el (eshell-in-local-scope-p) (eshell-local-variable-bindings): New variables. (eshell-var-initialize, eshell-set-variable): Use 'eshell-local-variable-bindings'. (eshell-handle-local-variables): Don't use 'eshell-as-subcommand'. * test/lisp/eshell/esh-var-tests.el (esh-var-test/local-variables/cd): New test. diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index ae0b18cd13a..1d90fbdd8ee 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -255,6 +255,20 @@ copied (a.k.a. \"exported\") to the environment of created subprocesses." (defvar-keymap eshell-var-mode-map "C-c M-v" #'eshell-insert-envvar) +;;; Internal Variables: + +(defvar eshell-in-local-scope-p nil + "Non-nil if the current command has a local variable scope. +This is set to t in `eshell-local-variable-bindings' (which see).") + +(defvar eshell-local-variable-bindings + '((eshell-in-local-scope-p t) + (process-environment (eshell-copy-environment)) + (eshell-variable-aliases-list eshell-variable-aliases-list) + (eshell-path-env-list eshell-path-env-list) + (comint-pager comint-pager)) + "A list of `let' bindings for local variable (and subcommand) environments.") + ;;; Functions: (define-minor-mode eshell-var-mode @@ -271,12 +285,8 @@ copied (a.k.a. \"exported\") to the environment of created subprocesses." (setq-local process-environment (eshell-copy-environment))) (make-local-variable 'comint-pager) (setq-local eshell-subcommand-bindings - (append - '((process-environment (eshell-copy-environment)) - (eshell-variable-aliases-list eshell-variable-aliases-list) - (eshell-path-env-list eshell-path-env-list) - (comint-pager comint-pager)) - eshell-subcommand-bindings)) + (append eshell-local-variable-bindings + eshell-subcommand-bindings)) (setq-local eshell-special-chars-inside-quoting (append eshell-special-chars-inside-quoting '(?$))) @@ -296,30 +306,25 @@ copied (a.k.a. \"exported\") to the environment of created subprocesses." (defun eshell-handle-local-variables () "Allow for the syntax `VAR=val '." - ;; Eshell handles local variable settings (e.g. 'CFLAGS=-O2 make') - ;; by making the whole command into a subcommand, and calling - ;; `eshell-set-variable' immediately before the command is invoked. - ;; This means that 'FOO=x cd bar' won't work exactly as expected, - ;; but that is by no means a typical use of local environment - ;; variables. + ;; Handle local variable settings by let-binding the entries in + ;; `eshell-local-variable-bindings' and calling `eshell-set-variable' + ;; for each variable before the command is invoked. (let ((setvar "\\`\\([A-Za-z_][A-Za-z0-9_]*\\)=\\(.*\\)\\'") (command eshell-last-command-name) (args eshell-last-arguments)) (when (and (stringp command) (string-match setvar command)) (throw 'eshell-replace-command - `(eshell-as-subcommand - (progn - ,@(let (locals) - (while (and (stringp command) - (string-match setvar command)) - (push `(eshell-set-variable - ,(match-string 1 command) - ,(match-string 2 command)) - locals) - (setq command (pop args))) - (nreverse locals)) - (eshell-named-command ,command ,(list 'quote args))) - ))))) + `(let ,eshell-local-variable-bindings + ,@(let (locals) + (while (and (stringp command) + (string-match setvar command)) + (push `(eshell-set-variable + ,(match-string 1 command) + ,(match-string 2 command)) + locals) + (setq command (pop args))) + (nreverse locals)) + (eshell-named-command ,command ,(list 'quote args))))))) (defun eshell-interpolate-variable () "Parse a variable interpolation. @@ -709,7 +714,7 @@ to a Lisp variable)." ((functionp target) (funcall target nil value)) ((null target) - (unless eshell-in-subcommand-p + (unless eshell-in-local-scope-p (error "Variable `%s' is not settable" (eshell-stringify name))) (push `(,name ,(lambda () value) t t) eshell-variable-aliases-list) diff --git a/test/lisp/eshell/esh-var-tests.el b/test/lisp/eshell/esh-var-tests.el index 39c278a6277..bb3d18abf6d 100644 --- a/test/lisp/eshell/esh-var-tests.el +++ b/test/lisp/eshell/esh-var-tests.el @@ -653,6 +653,14 @@ nil, use FUNCTION instead." "VAR=hello\n") (should (equal (getenv "VAR") "value")))) +(ert-deftest esh-var-test/local-variables/cd () + "Test that \"VAR=value cd DIR\" properly changes the directory." + (let ((parent-directory (file-name-directory + (directory-file-name default-directory)))) + (with-temp-eshell + (eshell-insert-command "VAR=hello cd ..") + (should (equal default-directory parent-directory))))) + ;; Variable aliases commit 4834be0949e13a728b69ab97ac9c8a0dbec65f3a Author: Jim Porter Date: Thu Jan 25 17:12:28 2024 -0800 ; For compatibility, eshell/make should print to Eshell unless backgrounded * lisp/eshell/em-unix.el (eshell/make): Pass 'plain' to eshell-compile when in the foreground (bug#68724). diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el index 75afaf1c104..b066e9eeb8e 100644 --- a/lisp/eshell/em-unix.el +++ b/lisp/eshell/em-unix.el @@ -741,7 +741,7 @@ Fallback to standard make when called synchronously." (eshell-compile "make" args ;; Use plain output unless we're executing in the ;; background. - (not eshell-current-subjob-p))) + (unless eshell-current-subjob-p 'plain))) (put 'eshell/make 'eshell-no-numeric-conversions t) commit 737d46e04d73dbad84bf0225cebb1c936ff89365 Author: Dmitry Gutov Date: Fri Jan 26 03:00:04 2024 +0200 python--treesit-syntax-propertize: Fix edits in the middle * lisp/progmodes/python.el (python--treesit-syntax-propertize): Process the beginning and the end of the triple-quoted string's delimiters separately. Among other things, that still works when the beginning is outside of the propertized region (bug#68445). diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index e2f614f52c2..41f612c8b1c 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1359,15 +1359,15 @@ For NODE, OVERRIDE, START, END, and ARGS, see (save-excursion (goto-char start) (while (re-search-forward (rx (or "\"\"\"" "'''")) end t) - (let ((node (treesit-node-at (point)))) - ;; The triple quotes surround a non-empty string. - (when (equal (treesit-node-type node) "string_content") - (let ((start (treesit-node-start node)) - (end (treesit-node-end node))) - (put-text-property (1- start) start - 'syntax-table (string-to-syntax "|")) - (put-text-property end (min (1+ end) (point-max)) - 'syntax-table (string-to-syntax "|")))))))) + (let ((node (treesit-node-at (- (point) 3)))) + ;; Handle triple-quoted strings. + (pcase (treesit-node-type node) + ("string_start" + (put-text-property (1- (point)) (point) + 'syntax-table (string-to-syntax "|"))) + ("string_end" + (put-text-property (- (point) 3) (- (point) 2) + 'syntax-table (string-to-syntax "|")))))))) ;;; Indentation commit 22a58fccb763da6ec52f4bea98f91647b71ee1f0 Author: Dmitry Gutov Date: Fri Jan 26 02:52:35 2024 +0200 project--read-project-list: Handle corrupted file contents * lisp/progmodes/project.el (project--read-project-list): Handle the 'end-of-file' error (bug#68546). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index ab4504fa027..da782ad5537 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1707,7 +1707,10 @@ With some possible metadata (to be decided).") (let ((name (car elem))) (list (if (file-remote-p name) name (abbreviate-file-name name))))) - (read (current-buffer)))))) + (condition-case nil + (read (current-buffer)) + (end-of-file + (warn "Failed to read the projects list file due to unexpected EOF"))))))) (unless (seq-every-p (lambda (elt) (stringp (car-safe elt))) project--list) commit 4e260bfc47e5b507df1db218f49729fbae91900c Author: Stefan Monnier Date: Thu Jan 25 14:24:20 2024 -0500 * lisp/emacs-lisp/cl-generic.el (cl--generic-compiler): Clarify the test Use `compiled-function-p`. diff --git a/lisp/emacs-lisp/cl-generic.el b/lisp/emacs-lisp/cl-generic.el index 48f5c06e390..bdccdcc48ce 100644 --- a/lisp/emacs-lisp/cl-generic.el +++ b/lisp/emacs-lisp/cl-generic.el @@ -672,7 +672,7 @@ The set of acceptable TYPEs (also called \"specializers\") is defined ;; compiled. Otherwise the byte-compiler and all the code on ;; which it depends needs to be usable before cl-generic is loaded, ;; which imposes a significant burden on the bootstrap. - (if (consp (lambda (x) (+ x 1))) + (if (not (compiled-function-p (lambda (x) (+ x 1)))) (lambda (exp) (eval exp t)) ;; But do byte-compile the dispatchers once bootstrap is passed: ;; the performance difference is substantial (like a 5x speedup on commit d22a3e5afe75c9f4a18926cce16c1a13fa912df2 Author: Juri Linkov Date: Thu Jan 25 19:52:08 2024 +0200 * lisp/simple.el (next-line-completion): Better handing of group lines. Simplify to not compare the result of 'move-to-column' with the value 'column'. Such comparison prevented from moving over lines without completion candidates such as group lines (bug#68688). * test/lisp/minibuffer-tests.el (completions-group-navigation-test): Add more group candidates to create more columns and to test moving over group lines and over columns without candidates. diff --git a/lisp/simple.el b/lisp/simple.el index 1157bd578fd..8246b9cab81 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10062,7 +10062,7 @@ Also see the `completion-auto-wrap' variable." (while (and (not found) (eq (forward-line 1) 0) (not (eobp)) - (eq (move-to-column column) column)) + (move-to-column column)) (when (get-text-property (point) 'mouse-face) (setq found t))) (when (not found) @@ -10086,7 +10086,7 @@ Also see the `completion-auto-wrap' variable." (completion--move-to-candidate-start) (while (and (not found) (eq (forward-line -1) 0) - (eq (move-to-column column) column)) + (move-to-column column)) (when (get-text-property (point) 'mouse-face) (setq found t))) (when (not found) diff --git a/test/lisp/minibuffer-tests.el b/test/lisp/minibuffer-tests.el index d104858b0d0..07c4dbc3197 100644 --- a/test/lisp/minibuffer-tests.el +++ b/test/lisp/minibuffer-tests.el @@ -565,35 +565,63 @@ (if transform name (pcase name - (`"aa" "Group 1") - (`"ab" "Group 2") - (`"ac" "Group 3"))))) + (`"aa1" "Group 1") + (`"aa2" "Group 1") + (`"aa3" "Group 1") + (`"aa4" "Group 1") + (`"ab1" "Group 2") + (`"ac1" "Group 3") + (`"ac2" "Group 3"))))) (category . unicode-name)) - (complete-with-action action '("aa" "ab" "ac") string pred))) + (complete-with-action action '("aa1" "aa2" "aa3" "aa4" "ab1" "ac1" "ac2") + string pred))) (insert "a") (minibuffer-completion-help) (switch-to-completions) - (should (equal "aa" (get-text-property (point) 'completion--string))) + (should (equal "aa1" (get-text-property (point) 'completion--string))) (let ((completion-auto-wrap t)) - (next-completion 3)) - (should (equal "aa" (get-text-property (point) 'completion--string))) + (next-completion 7)) + (should (equal "aa1" (get-text-property (point) 'completion--string))) (let ((completion-auto-wrap nil)) - (next-completion 3)) - (should (equal "ac" (get-text-property (point) 'completion--string))) + (next-completion 7)) + (should (equal "ac2" (get-text-property (point) 'completion--string))) - (first-completion) (let ((completion-auto-wrap t)) + ;; First column + (first-completion) (next-line-completion 1) - (should (equal "ab" (get-text-property (point) 'completion--string))) - (next-line-completion 2) - (should (equal "aa" (get-text-property (point) 'completion--string))) + (should (equal "aa4" (get-text-property (point) 'completion--string))) + (next-line-completion 3) + (should (equal "aa1" (get-text-property (point) 'completion--string))) (previous-line-completion 2) - (should (equal "ab" (get-text-property (point) 'completion--string)))) + (should (equal "ab1" (get-text-property (point) 'completion--string))) + + ;; Second column + (first-completion) + (next-completion 1) + (should (equal "aa2" (get-text-property (point) 'completion--string))) + (next-line-completion 1) + (should (equal "ac2" (get-text-property (point) 'completion--string))) + (next-line-completion 1) + (should (equal "aa2" (get-text-property (point) 'completion--string))) + (previous-line-completion 1) + (should (equal "ac2" (get-text-property (point) 'completion--string))) + (previous-line-completion 1) + (should (equal "aa2" (get-text-property (point) 'completion--string))) + + ;; Third column + (first-completion) + (next-completion 2) + (should (equal "aa3" (get-text-property (point) 'completion--string))) + (next-line-completion 1) + (should (equal "aa3" (get-text-property (point) 'completion--string)))) + (let ((completion-auto-wrap nil)) - (next-line-completion 3) - (should (equal "ac" (get-text-property (point) 'completion--string))) - (previous-line-completion 3) - (should (equal "aa" (get-text-property (point) 'completion--string)))))) + (first-completion) + (next-line-completion 7) + (should (equal "ac2" (get-text-property (point) 'completion--string))) + (previous-line-completion 7) + (should (equal "aa1" (get-text-property (point) 'completion--string)))))) (provide 'minibuffer-tests) ;;; minibuffer-tests.el ends here commit b07265f8eed74dda792e13062baae94319484b4b Author: Juri Linkov Date: Thu Jan 25 19:38:03 2024 +0200 * lisp/dired.el (dired--move-to-next-line): Improve to avoid an infinite loop. An infinite loop is possible in a directory without files and subdirectories, where even lines with . and .. are omitted, so 'dired-between-files' is true for all Dired lines. For the case of dired-movement-style=cycle a guard is triggered when the loop wraps twice while the value 'arg' is not changing. And for the case of dired-movement-style=bounded a guard is triggered when point doesn't move while trying to go back to the last non-empty line. diff --git a/lisp/dired.el b/lisp/dired.el index 69fa15dde73..cef93ab757c 100644 --- a/lisp/dired.el +++ b/lisp/dired.el @@ -2817,7 +2817,9 @@ is controlled by `dired-movement-style'." (dired--trivial-next-line arg))) (defun dired--move-to-next-line (arg jumpfun) - (let ((old-position (progn + (let ((wrapped nil) + (old-arg arg) + (old-position (progn ;; It's always true that we should move ;; to the filename when possible. (dired-move-to-filename) @@ -2832,16 +2834,27 @@ is controlled by `dired-movement-style'." (when (= old-position (point)) ;; Now point is at beginning/end of movable area, ;; but it still wants to move farther. - (if (eq dired-movement-style 'cycle) - ;; `cycle': go to the other end. + (cond + ;; `cycle': go to the other end. + ((eq dired-movement-style 'cycle) + ;; Argument not changing on the second wrap + ;; means infinite loop with no files found. + (if (and wrapped (eq old-arg arg)) + (setq arg 0) (goto-char (if (cl-plusp moving-down) (point-min) - (point-max))) - ;; `bounded': go back to the last non-empty line. - (while (dired-between-files) - (funcall jumpfun (- moving-down))) + (point-max)))) + (setq wrapped t)) + ;; `bounded': go back to the last non-empty line. + ((eq dired-movement-style 'bounded) + (while (and (dired-between-files) (not (zerop arg))) + (funcall jumpfun (- moving-down)) + ;; Point not moving means infinite loop. + (if (= old-position (point)) + (setq arg 0) + (setq old-position (point)))) ;; Encountered a boundary, so let's stop movement. - (setq arg moving-down))) + (setq arg (if (dired-between-files) 0 moving-down))))) (unless (dired-between-files) ;; Has moved to a non-empty line. This movement does ;; make sense. commit a8cfe3bda8b8008071818d6ac5e5103002ed6c08 Author: Basil L. Contovounesios Date: Thu Jan 25 15:57:54 2024 +0100 ; Update 'struct charset' hash for CHECK_STRUCTS This follows commit 33b8d5b6c5 of 2024-01-23 "(struct charset): Remove dependency on hash-table internals". diff --git a/src/pdumper.c b/src/pdumper.c index 8907d25cc13..f42d1777371 100644 --- a/src/pdumper.c +++ b/src/pdumper.c @@ -3213,7 +3213,7 @@ dump_object_for_offset (struct dump_context *ctx, Lisp_Object object) static dump_off dump_charset (struct dump_context *ctx, int cs_i) { -#if CHECK_STRUCTS && !defined (HASH_charset_317C49E291) +#if CHECK_STRUCTS && !defined (HASH_charset_E31F4B5D96) # error "charset changed. See CHECK_STRUCTS comment in config.h." #endif dump_align_output (ctx, alignof (struct charset)); commit e13653ae5cb86c26e5b9ae0c3bb5753ebb7bc98c Author: Basil L. Contovounesios Date: Wed Jan 24 10:50:46 2024 +0100 ; * .mailmap: Change own email address. diff --git a/.mailmap b/.mailmap index 5d80e4aa082..18e55b0d1e7 100644 --- a/.mailmap +++ b/.mailmap @@ -28,6 +28,7 @@ Arash Esbati Arash Esbati Artur Malabarba Artur Malabarba Artur Malabarba +Basil L. Contovounesios Bastien Guerry Bastien Guerry Bastien Guerry @@ -163,8 +164,8 @@ Ronnie Schnell Ryan C. Thompson Sam Steingold Simen Heggestøyl -Simen Heggestøyl Simen Heggestøyl +Simen Heggestøyl Simon Josefsson Stefan Kangas Stefan Monnier commit 5d91cbf9a57d519968a6fb3ad6edfbf9709574a5 Author: Andrea Corallo Date: Thu Jan 25 14:37:17 2024 +0100 * Make comp tests robust against sxhash-equal internal changes * test/src/comp-tests.el (cl-seq): Require. (comp-tests--types-equal): New function. (comp-tests-check-ret-type-spec): Make use of. diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el index 0aa9e76fa2d..4e7ca88d197 100644 --- a/test/src/comp-tests.el +++ b/test/src/comp-tests.el @@ -28,6 +28,7 @@ (require 'ert) (require 'ert-x) (require 'cl-lib) +(require 'cl-seq) (require 'comp) (require 'comp-cstr) @@ -903,14 +904,26 @@ Return a list of results." (should (subr-native-elisp-p (symbol-function 'comp-tests-fw-prop-1-f))) (should (= (comp-tests-fw-prop-1-f) 6)))) +(defun comp-tests--types-equal (t1 t2) + "Whether the types T1 and T2 are equal." + (or (equal t1 t2) ; optimisation for the common case + (and (consp t1) (consp t2) + (eq (car t1) (car t2)) + (if (memq (car t1) '(and or member)) + (null (cl-set-exclusive-or (cdr t1) (cdr t2) + :test #'comp-tests--types-equal)) + (and (= (length t1) (length t2)) + (cl-every #'comp-tests--types-equal (cdr t1) (cdr t2))))))) + (defun comp-tests-check-ret-type-spec (func-form ret-type) (let ((lexical-binding t) (native-comp-speed 2) (f-name (cl-second func-form))) (eval func-form t) (native-compile f-name) - (should (equal (cl-third (subr-type (symbol-function f-name))) - ret-type)))) + (should (comp-tests--types-equal + (cl-third (subr-type (symbol-function f-name))) + ret-type)))) (cl-eval-when (compile eval load) (cl-defstruct comp-foo a b) commit b014bca833a17f5b2258e88115f03cffa983d0bd Author: João Távora Date: Thu Jan 25 12:18:58 2024 +0000 Eglot: bump to 1.17 * etc/EGLOT-NEWS: Update. * lisp/progmodes/eglot.el (Version): Bump to 1.17 (Package-Requires): Bump jsonrpc depedency to 1.24 diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS index 1f913f81236..12e7d3f6b9b 100644 --- a/etc/EGLOT-NEWS +++ b/etc/EGLOT-NEWS @@ -20,6 +20,19 @@ https://github.com/joaotavora/eglot/issues/1234. * Changes in upcoming Eglot + +* Changes in Eglot 1.17 (25/1/2024) + +** Fixes to completion (github#847, github#1349) + +** Fix code-action gathering for some servers (github#847) + +** Experimental support for Eglot-only subprojects + +Until project.el's support for subprojects improves, github#1337 +describes a reasonably sane way to configure nested sub-projects +within a larger one just for Eglot purposes. + * Changes in Eglot 1.16 (27/12/2023) diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index f8d96051606..40837074573 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2,12 +2,12 @@ ;; Copyright (C) 2018-2024 Free Software Foundation, Inc. -;; Version: 1.16 +;; Version: 1.17 ;; Author: João Távora ;; Maintainer: João Távora ;; URL: https://github.com/joaotavora/eglot ;; Keywords: convenience, languages -;; Package-Requires: ((emacs "26.3") (jsonrpc "1.0.23") (flymake "1.2.1") (project "0.9.8") (xref "1.6.2") (eldoc "1.14.0") (seq "2.23") (external-completion "0.1")) +;; Package-Requires: ((emacs "26.3") (jsonrpc "1.0.24") (flymake "1.2.1") (project "0.9.8") (xref "1.6.2") (eldoc "1.14.0") (seq "2.23") (external-completion "0.1")) ;; This is a GNU ELPA :core package. Avoid adding functionality ;; that is not available in the version of Emacs recorded above or any commit 5d88c98e7c101ebad68b562334020b8c082c2ca5 Author: João Távora Date: Thu Jan 25 12:10:40 2024 +0000 Eglot: fix bug introduced when "fixing" middle-of-symbol completions Culprit: commit a6ef458e3831001b0acad57cf8fa75b77a4aff3f Author: João Távora Date: Tue Dec 26 00:31:29 2023 +0000 Eglot: partial fix for middle-of-symbol completions The decision to restore the buffer state to when the last LSP completion set was invoked is rock-solid (because that the state those completions' edits apply to). However, when caching the LSP completions across multiple eglot-completion-at-point calls, we must make sure to also restore the values of the local values, such as 'bounds-string'. This allows us to do that restoration. * lisp/progmodes/eglot.el (eglot-completion-at-point): Also restore bounds-string from capf session cache. Github-reference: https://github.com/joaotavora/eglot/issues/1349 diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index c5fbf5eb9d5..f8d96051606 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -3125,7 +3125,8 @@ for which LSP on-type-formatting should be requested." items))) ;; (trace-values "Requested" (length proxies) cachep bounds) (setq eglot--capf-session - (if cachep (list bounds retval resolved orig-pos) :none)) + (if cachep (list bounds retval resolved orig-pos + bounds-string) :none)) (setq local-cache retval))))) (resolve-maybe ;; Maybe completion/resolve JSON object `lsp-comp' into @@ -3145,7 +3146,8 @@ for which LSP on-type-formatting should be requested." (>= (cdr bounds) (cdr (nth 0 eglot--capf-session)))) (setq local-cache (nth 1 eglot--capf-session) resolved (nth 2 eglot--capf-session) - orig-pos (nth 3 eglot--capf-session)) + orig-pos (nth 3 eglot--capf-session) + bounds-string (nth 4 eglot--capf-session)) ;; (trace-values "Recalling cache" (length local-cache) bounds orig-pos) ) (list