commit 1e9dca9ba2a64e6379883e86a70c1c9d08fe0b33 Author: Juri Linkov Date: Mon Dec 15 09:22:33 2025 +0200 * lisp/vc/vc.el (vc-diff-internal): Reuse the buffer object (bug#80005). Instead of delaying hooks, set the variable 'buffer' to the buffer object returned by 'get-buffer-create'. This allows renaming the diff buffer via 'diff-mode-hook'. diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index b0821de3da5..c65088b994d 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -2731,7 +2731,7 @@ Output goes to the buffer BUFFER, which defaults to *vc-diff*. BUFFER, if non-nil, should be a buffer or a buffer name. Return t if the buffer had changes, nil otherwise." (unless buffer - (setq buffer "*vc-diff*")) + (setq buffer (get-buffer-create "*vc-diff*"))) (let* ((files (cadr vc-fileset)) (messages (cons (format "Finding changes in %s..." (vc-delistify files)) @@ -2799,15 +2799,13 @@ Return t if the buffer had changes, nil otherwise." ;; bindings are nicer for read only buffers. pcl-cvs does the ;; same thing. (setq buffer-read-only t) - (delay-mode-hooks - (diff-mode) - (setq-local diff-vc-backend (car vc-fileset)) - (setq-local diff-vc-revisions (list rev1 rev2)) - (setq-local revert-buffer-function - (lambda (_ignore-auto _noconfirm) - (vc-diff-internal async vc-fileset rev1 rev2 verbose))) - (vc-call-backend (car vc-fileset) 'diff files rev1 rev2 buffer async)) - (run-mode-hooks 'diff-mode-hook) + (diff-mode) + (setq-local diff-vc-backend (car vc-fileset)) + (setq-local diff-vc-revisions (list rev1 rev2)) + (setq-local revert-buffer-function + (lambda (_ignore-auto _noconfirm) + (vc-diff-internal async vc-fileset rev1 rev2 verbose))) + (vc-call-backend (car vc-fileset) 'diff files rev1 rev2 buffer async) (if (and (zerop (buffer-size)) (not (get-buffer-process (current-buffer)))) ;; Treat this case specially so as not to pop the buffer. commit 5fe0b9e6b017d7f6662ee7fcb5aa6d1ce2ede316 Author: Paul Eggert Date: Sun Dec 14 14:45:49 2025 -0800 make-docfile preferring streq * lib-src/make-docfile.c (main, add_global, compare_globals): Prefer streq to strcmp where either will do. diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index f41cf8d136b..ac3c7ccc9d3 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -150,7 +150,7 @@ main (int argc, char **argv) /* If first two args are -o FILE, output to FILE. */ i = 1; - if (argc > i + 1 && !strcmp (argv[i], "-o")) + if (argc > i + 1 && streq (argv[i], "-o")) { if (! freopen (argv[i + 1], "w", stdout)) { @@ -159,7 +159,7 @@ main (int argc, char **argv) } i += 2; } - if (argc > i + 1 && !strcmp (argv[i], "-a")) + if (argc > i + 1 && streq (argv[i], "-a")) { if (! freopen (argv[i + 1], "a", stdout)) { @@ -168,7 +168,7 @@ main (int argc, char **argv) } i += 2; } - if (argc > i + 1 && !strcmp (argv[i], "-d")) + if (argc > i + 1 && streq (argv[i], "-d")) { if (chdir (argv[i + 1]) != 0) { @@ -177,7 +177,7 @@ main (int argc, char **argv) } i += 2; } - if (argc > i && !strcmp (argv[i], "-g")) + if (argc > i && streq (argv[i], "-g")) { generate_globals = true; ++i; @@ -198,7 +198,7 @@ main (int argc, char **argv) int j; /* Don't process one file twice. */ for (j = first_infile; j < i; j++) - if (strcmp (argv[i], argv[j]) == 0) + if (streq (argv[i], argv[j])) break; if (j == i) scan_file (argv[i]); @@ -602,7 +602,7 @@ add_global (enum global_type type, char const *name, int value, char const *svalue) { /* Ignore the one non-symbol that can occur. */ - if (strcmp (name, "...")) + if (!streq (name, "...")) { if (num_globals == num_globals_allocated) { @@ -654,9 +654,9 @@ compare_globals (const void *a, const void *b) int ai = ncommonsym, bi = ncommonsym; for (int i = 0; i < ncommonsym; i++) { - if (ga->name[0] == 'Q' && strcmp (ga->name + 1, commonsym[i]) == 0) + if (ga->name[0] == 'Q' && streq (ga->name + 1, commonsym[i])) ai = i; - if (gb->name[0] == 'Q' && strcmp (gb->name + 1, commonsym[i]) == 0) + if (gb->name[0] == 'Q' && streq (gb->name + 1, commonsym[i])) bi = i; } if (! (ai == ncommonsym && bi == ncommonsym)) @@ -692,7 +692,7 @@ write_globals (void) for (i = 0; i < num_globals; i++) { while (i + 1 < num_globals - && strcmp (globals[i].name, globals[i + 1].name) == 0) + && streq (globals[i].name, globals[i + 1].name)) { if (globals[i].type == FUNCTION && globals[i].v.value != globals[i + 1].v.value) commit 19e5d27dafa84d93cb84469c9f21594c05204bb3 Author: Paul Eggert Date: Sun Dec 14 14:45:49 2025 -0800 Support nested parens in make-docfile args * lib-src/make-docfile.c (scan_c_stream): Allow nested parens. E.g., ‘(Lisp_Object XXX (force))’ for the identifier ‘force’, where XXX is a macro. This is for future changes. diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index 69adcb415af..f41cf8d136b 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -1205,12 +1205,13 @@ scan_c_stream (FILE *infile) c = getc (infile); } /* Copy arguments into ARGBUF. */ - while (true) + for (ptrdiff_t nested = 0; ; ) { *p++ = c; if (argbuf + sizeof argbuf <= p) fatal ("argument buffer exhausted"); - if (c == ')') + nested += (c == '(') - (c == ')'); + if (c == ')' && !nested) break; c = getc (infile); if (c < 0) commit aeab91bc55db67222cb9142476916ad08d32c98f Author: Paul Eggert Date: Sun Dec 14 14:45:49 2025 -0800 Fix make-docfile strncmp typo * lib-src/make-docfile.c (write_c_args): Don’t mishandle the identifiers ‘v’, ‘vo’, and ‘voi’. diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index f59ce7def35..69adcb415af 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -524,7 +524,7 @@ write_c_args (char *buf, int minargs, int maxargs) if (ident_length == 0) continue; - if (strncmp (ident_start, "void", ident_length) == 0) + if (ident_length == 4 && memeq (ident_start, "void", 4)) continue; putchar (' '); commit 1269bbdaa91b4eb9d17117bfd0718de297040271 Author: Paul Eggert Date: Sun Dec 14 14:45:49 2025 -0800 Improve make-docfile.c for C23 * lib-src/make-docfile.c (write_c_args): Don’t diagnose “()”. In C23 it’s equivalent to (void), and it works fine (albeit with less type-checking) in older C. Omit first arg, which is no longer needed. Caller changed. diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index 068b36f1b74..f59ce7def35 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -485,7 +485,7 @@ read_c_string_or_comment (FILE *infile, int printflag, bool comment, MINARGS and MAXARGS are the minimum and maximum number of arguments. */ static void -write_c_args (char *func, char *buf, int minargs, int maxargs) +write_c_args (char *buf, int minargs, int maxargs) { char *p; bool in_ident = false; @@ -522,10 +522,7 @@ write_c_args (char *func, char *buf, int minargs, int maxargs) if (c == ',' || c == ')') { if (ident_length == 0) - { - error ("empty arg list for '%s' should be (void), not ()", func); - continue; - } + continue; if (strncmp (ident_start, "void", ident_length) == 0) continue; @@ -551,6 +548,8 @@ write_c_args (char *func, char *buf, int minargs, int maxargs) c = '-'; putchar (c); } + + ident_length = 0; } } @@ -1220,7 +1219,7 @@ scan_c_stream (FILE *infile) *p = '\0'; /* Output them. */ fputs ("\n\n", stdout); - write_c_args (input_buffer, argbuf, minargs, maxargs); + write_c_args (argbuf, minargs, maxargs); } else if (defunflag && maxargs == -1 && !saw_usage) /* The DOC should provide the usage form. */ commit 51b8a7c7cb4132ce1fc239c86b5858fa7636b488 Author: Paul Eggert Date: Sun Dec 14 14:45:49 2025 -0800 Fix some make-docfile core dumps This bit me when I ran ‘make’ with typos in the Emacs source. * lib-src/make-docfile.c (struct rcsoc_state.buf_lim): New member. (read_c_string_or_comment): Initialize it. (put_char, scan_c_stream): Check for buffer overflow. (scan_c_stream): Output a diagnostic rather than aborting when the buffer overflows. diff --git a/lib-src/make-docfile.c b/lib-src/make-docfile.c index d0ea463f299..068b36f1b74 100644 --- a/lib-src/make-docfile.c +++ b/lib-src/make-docfile.c @@ -261,6 +261,8 @@ struct rcsoc_state /* If non-zero, a buffer into which to copy characters. */ char *buf_ptr; + /* If non-zero, one past the buffer's last byte. */ + char *buf_lim; /* If non-zero, a file into which to copy characters. */ FILE *out_file; @@ -299,7 +301,11 @@ put_char (char ch, struct rcsoc_state *state) if (state->out_file) putc (out_ch, state->out_file); if (state->buf_ptr) - *state->buf_ptr++ = out_ch; + { + *state->buf_ptr++ = out_ch; + if (state->buf_lim <= state->buf_ptr) + fatal ("state buffer exhausted"); + } } while (out_ch != ch); } @@ -397,8 +403,9 @@ read_c_string_or_comment (FILE *infile, int printflag, bool comment, struct rcsoc_state state; state.in_file = infile; - state.buf_ptr = (printflag < 0 ? input_buffer : 0); - state.out_file = (printflag > 0 ? stdout : 0); + state.buf_ptr = printflag < 0 ? input_buffer : NULL; + state.buf_lim = printflag < 0 ? input_buffer + sizeof input_buffer : NULL; + state.out_file = printflag <= 0 ? NULL : stdout; state.pending_spaces = 0; state.pending_newlines = 0; state.keyword = (saw_usage ? "usage:" : 0); @@ -1109,8 +1116,8 @@ scan_c_stream (FILE *infile) goto eof; if (c == ')') break; - if (p - input_buffer > sizeof (input_buffer)) - abort (); + if (input_buffer + sizeof input_buffer <= p) + fatal ("attribute buffer exhausted"); *p++ = c; } *p = 0; @@ -1199,16 +1206,17 @@ scan_c_stream (FILE *infile) c = getc (infile); } /* Copy arguments into ARGBUF. */ - *p++ = c; - do + while (true) { + *p++ = c; + if (argbuf + sizeof argbuf <= p) + fatal ("argument buffer exhausted"); + if (c == ')') + break; c = getc (infile); if (c < 0) goto eof; - *p++ = c; } - while (c != ')'); - *p = '\0'; /* Output them. */ fputs ("\n\n", stdout); commit 2d1e891eea742e16f1ae26763af2a70ef1a95a81 Author: João Távora Date: Sat Dec 13 19:43:43 2025 +0000 Eglot: half-decent pull diagnostics support Implement basic LSP 3.17 pull diagnostics ('textDocument/diagnostic'). Only diagnostics for the current document are requested. This is chiefly because virtually no server has been found to support the 'relatedDocumentSupport' sub-capability which would allow to test this. * etc/EGLOT-NEWS: Announce pull diagnostics support. * lisp/progmodes/eglot.el (eglot-client-capabilities): Announce :diagnostic capability. (eglot--flymake-diag-type): New function. (eglot--flymake-make-diag): New function. (eglot--flymake-push-report-fn): Rename from eglot--current-flymake-report-fn. (eglot-flymake-backend): Check for :diagnosticProvider and dispatch to pull or push path. (eglot--flymake-pull): New function. (eglot--flymake-push): Rename from eglot--report-to-flymake. (eglot-handle-notification textDocument/publishDiagnostics): Use eglot--flymake-make-diag helper. (eglot-ignored-server-capabilities): Add diagnosticProvider diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS index d9999248a31..fbd1a87ec5b 100644 --- a/etc/EGLOT-NEWS +++ b/etc/EGLOT-NEWS @@ -20,6 +20,19 @@ https://github.com/joaotavora/eglot/issues/1234. * Changes to upcoming Eglot +** Support for pull diagnostics (github#1559, github#1290) + +For servers supporting the 'diagnosticProvider' capability, Eglot +requests diagnostics on-demand rather than relying solely on +server-pushed 'publishDiagnostics' notifications. This may provide a +more responsive user experience. The 'ty' server is known to support it +while the 'tsgo' server is known to support is exclusively. However, no +server has been found to support the 'relatedDocumentSupport' +sub-capability, which e.g. introducing a problem in one file to bring +diagnostics for another related file. The traditional push diagnostics, +as supported by some servers, are at the moment still a superior user +experience in this particular regard. + ** Support for semantic tokens (bug#79374) The new minor mode 'eglot-semantic-tokens-mode' provides enhanced syntax diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index b8d29f966fc..2f140ff510a 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -576,7 +576,8 @@ under cursor." (const :tag "Inlay hints" :inlayHintProvider) (const :tag "Semantic tokens" :semanticTokensProvider) (const :tag "Type hierarchies" :typeHierarchyProvider) - (const :tag "Call hierarchies" :callHierarchyProvider))) + (const :tag "Call hierarchies" :callHierarchyProvider) + (const :tag "On-demand \"pull\" diagnostics" :diagnosticProvider))) (defcustom eglot-advertise-cancellation nil "If non-nil, Eglot attempts to inform server of canceled requests. @@ -738,6 +739,7 @@ This can be useful when using docker to run a language server.") :textEdit :additionalTextEdits :commitCharacters :command :data :tags)) (Diagnostic (:range :message) (:severity :code :source :relatedInformation :codeDescription :tags)) + (DocumentDiagnosticReport (:kind :items)) (DocumentHighlight (:range) (:kind)) (ExecuteCommandParams ((:command . string)) (:arguments)) (FileSystemWatcher (:globPattern) (:kind)) @@ -1135,6 +1137,7 @@ object." :inlayHint `(:dynamicRegistration :json-false) :callHierarchy `(:dynamicRegistration :json-false) :typeHierarchy `(:dynamicRegistration :json-false) + :diagnostic `(:dynamicRegistration :json-false) :publishDiagnostics (list :relatedInformation :json-false :versionSupport t ;; TODO: We can support :codeDescription after @@ -2170,7 +2173,7 @@ and just return it. PROMPT shouldn't end with a question mark." (define-key map [remap display-local-help] #'eldoc-doc-buffer) map)) -(defvar-local eglot--current-flymake-report-fn nil +(defvar-local eglot--flymake-push-report-fn nil "Current flymake report function for this buffer.") (defvar-local eglot--saved-bindings nil @@ -2296,9 +2299,9 @@ Use `eglot-managed-p' to determine if current buffer is managed.") (cl-loop for (var . saved-binding) in eglot--saved-bindings do (set (make-local-variable var) saved-binding)) (remove-function (local 'imenu-create-index-function) #'eglot-imenu) - (when eglot--current-flymake-report-fn - (eglot--report-to-flymake nil nil) - (setq eglot--current-flymake-report-fn nil)) + (when eglot--flymake-push-report-fn + (eglot--flymake-push nil nil) + (setq eglot--flymake-push-report-fn nil)) (run-hooks 'eglot-managed-mode-hook) (let ((server eglot--cached-server)) (setq eglot--cached-server nil) @@ -2634,13 +2637,10 @@ still unanswered LSP requests to the server\n")))) (put 'eglot-warning 'flymake-category 'flymake-warning) (put 'eglot-error 'flymake-category 'flymake-error) -(defalias 'eglot--make-diag #'flymake-make-diagnostic) -(defalias 'eglot--diag-data #'flymake-diagnostic-data) - (defun eglot--flymake-diagnostics (beg &optional end) "Like `flymake-diagnostics', but for Eglot-specific diagnostics." (cl-loop for diag in (flymake-diagnostics beg end) - for data = (eglot--diag-data diag) + for data = (flymake-diagnostic-data diag) for lsp-diag = (alist-get 'eglot-lsp-diag data) for version = (alist-get 'eglot--doc-version data) when (and lsp-diag (or (null version) @@ -2648,7 +2648,7 @@ still unanswered LSP requests to the server\n")))) collect diag)) (defun eglot--diag-to-lsp-diag (diag) - (alist-get 'eglot-lsp-diag (eglot--diag-data diag))) + (alist-get 'eglot-lsp-diag (flymake-diagnostic-data diag))) (defvar eglot-diagnostics-map (let ((map (make-sparse-keymap))) @@ -2757,12 +2757,7 @@ expensive cached value of `file-truename'.") &key uri diagnostics version &allow-other-keys) ; FIXME: doesn't respect `eglot-strict-mode' "Handle notification publishDiagnostics." - (cl-flet ((eglot--diag-type (sev) - (cond ((null sev) 'eglot-error) - ((<= sev 1) 'eglot-error) - ((= sev 2) 'eglot-warning) - (t 'eglot-note))) - (find-it (abspath) + (cl-flet ((find-it (abspath) ;; `find-buffer-visiting' would be natural, but calls the ;; potentially slow `file-truename' (bug#70036). (cl-loop for b in (eglot--managed-buffers server) @@ -2783,45 +2778,14 @@ expensive cached value of `file-truename'.") flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics)) for diag-spec across diagnostics - collect (eglot--dbind ((Diagnostic) range code message severity source tags) - diag-spec - (pcase-let - ((`(,beg . ,end) (eglot-range-region range))) - ;; Fallback to `flymake-diag-region' if server - ;; botched the range - (when (= beg end) - (if-let* ((st (plist-get range :start)) - (diag-region - (flymake-diag-region - (current-buffer) (1+ (plist-get st :line)) - (plist-get st :character)))) - (setq beg (car diag-region) end (cdr diag-region)) - (eglot--widening - (goto-char (point-min)) - (setq beg - (eglot--bol - (1+ (plist-get (plist-get range :start) :line)))) - (setq end - (line-end-position - (1+ (plist-get (plist-get range :end) :line))))))) - (eglot--make-diag - (current-buffer) beg end - (eglot--diag-type severity) - (list source code message) - `((eglot-lsp-diag . ,diag-spec) - (eglot--doc-version . ,version)) - (when-let* ((faces - (cl-loop for tag across tags - when (alist-get tag eglot--tag-faces) - collect it))) - `((face . ,faces)))))) + collect (eglot--flymake-make-diag diag-spec version) into diags finally (cond ((and ;; only add to current report if Flymake ;; starts on idle-timer (github#958) (not (null flymake-no-changes-timeout)) - eglot--current-flymake-report-fn) - (eglot--report-to-flymake diags version)) + eglot--flymake-push-report-fn) + (eglot--flymake-push diags version)) (t (setq eglot--diagnostics (cons diags version)))))) (cl-loop @@ -2830,8 +2794,9 @@ expensive cached value of `file-truename'.") (let* ((start (plist-get range :start)) (line (1+ (plist-get start :line))) (char (1+ (plist-get start :character)))) - (eglot--make-diag - path (cons line char) nil (eglot--diag-type severity) + (flymake-make-diagnostic + path (cons line char) nil + (eglot--flymake-diag-type severity) (list source code message)))) into diags finally @@ -3215,6 +3180,48 @@ When called interactively, use the currently active server" :text (buffer-substring-no-properties (point-min) (point-max)) :textDocument (eglot--TextDocumentIdentifier))))) +(defun eglot--flymake-diag-type (severity) + "Convert LSP diagnostic SEVERITY to Eglot/Flymake diagnostic type." + (cond ((null severity) 'eglot-error) + ((<= severity 1) 'eglot-error) + ((= severity 2) 'eglot-warning) + (t 'eglot-note))) + +(defun eglot--flymake-make-diag (diag-spec version) + "Convert LSP diagnostic DIAG-SPEC to Flymake diagnostic. +VERSION is the document version number." + (eglot--dbind ((Diagnostic) range code message severity source tags) + diag-spec + (pcase-let + ((`(,beg . ,end) (eglot-range-region range))) + ;; Fallback to `flymake-diag-region' if server botched the range + (when (= beg end) + (if-let* ((st (plist-get range :start)) + (diag-region + (flymake-diag-region + (current-buffer) (1+ (plist-get st :line)) + (plist-get st :character)))) + (setq beg (car diag-region) end (cdr diag-region)) + (eglot--widening + (goto-char (point-min)) + (setq beg + (eglot--bol + (1+ (plist-get (plist-get range :start) :line)))) + (setq end + (line-end-position + (1+ (plist-get (plist-get range :end) :line))))))) + (flymake-make-diagnostic + (current-buffer) beg end + (eglot--flymake-diag-type severity) + (list source code message) + `((eglot-lsp-diag . ,diag-spec) + (eglot--doc-version . ,version)) + (when-let* ((faces + (cl-loop for tag across tags + when (alist-get tag eglot--tag-faces) + collect it))) + `((face . ,faces))))))) + (defun eglot-flymake-backend (report-fn &rest _more) "A Flymake backend for Eglot. Calls REPORT-FN (or arranges for it to be called) when the server @@ -3222,18 +3229,51 @@ publishes diagnostics. Between calls to this function, REPORT-FN may be called multiple times (respecting the protocol of `flymake-diagnostic-functions')." (cond (eglot--managed-mode - (setq eglot--current-flymake-report-fn report-fn) - (eglot--report-to-flymake (car eglot--diagnostics) - (cdr eglot--diagnostics))) + (cond + ;; Use pull diagnostics if server supports it + ((eglot-server-capable :diagnosticProvider) + (eglot--flymake-pull report-fn)) + ;; Otherwise use traditional push diagnostics + (t + (setq eglot--flymake-push-report-fn report-fn) + (eglot--flymake-push (car eglot--diagnostics) + (cdr eglot--diagnostics))))) (t (funcall report-fn nil)))) -(defun eglot--report-to-flymake (diags version) - "Internal helper for `eglot-flymake-backend'." +(defun eglot--flymake-pull (report-fn) + "Pull diagnostics from server and call REPORT-FN." + (let ((buf (current-buffer)) + (server (eglot--current-server-or-lose)) + (version eglot--docver)) + (eglot--async-request + server + :textDocument/diagnostic + (list :textDocument (eglot--TextDocumentIdentifier)) + :success-fn + (lambda (result) + (eglot--when-live-buffer buf + (eglot--dbind ((DocumentDiagnosticReport) kind items) result + (pcase kind + ("full" + (let ((diags + (cl-loop + for diag-spec across items + collect (eglot--flymake-make-diag diag-spec version)))) + (setq eglot--diagnostics (cons diags version)))) + ("unchanged" + ;; Server says diagnostics haven't changed, report what we have + )) + (funcall report-fn (car eglot--diagnostics) + :region (cons (point-min) (point-max)))))) + :hint :textDocument/diagnostic))) + +(defun eglot--flymake-push (diags version) + "Push previously collected diagnostics to `eglot--flymake-push-report-fn'." (save-restriction (widen) (if (or (null version) (= version eglot--docver)) - (funcall eglot--current-flymake-report-fn diags + (funcall eglot--flymake-push-report-fn diags ;; If the buffer hasn't changed since last ;; call to the report function, flymake won't ;; delete old diagnostics. Using :region @@ -3246,7 +3286,7 @@ may be called multiple times (respecting the protocol of ;; signal we're alive and clear a possible "Wait" state. We ;; hackingly achieve this by reporting an empty list and making ;; sure it pertains to a 0-length region. - (funcall eglot--current-flymake-report-fn nil + (funcall eglot--flymake-push-report-fn nil :region (cons (point-min) (point-min))))) (setq eglot--diagnostics (cons diags version))) commit 9adb6df788fc6e75f24246e8edeab53141c3b894 Author: Christoph Wedler Date: Sun Dec 14 21:47:29 2025 +0100 Add NEWS and auto-load entry for antlr-mode * etc/NEWS (Antlr mode): Mention major changes. * lisp/files.el (auto-mode-alist): Add 'antlr-v4-mode' for extension "g4". diff --git a/etc/NEWS b/etc/NEWS index 27204393f7a..1c53e0789a6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -3163,6 +3163,40 @@ it will begrudgingly use the scratch buffer. Customize the variable 'abbrev-mode' to non-nil to enable Abbrev mode by default in all buffers. +** Antlr mode + +*** Variable 'antlr-tool-version' is no user option anymore. +If becomes buffer-local and has the symbol 'antlr-v2', 'antlr-v3' or +'antlr-v4' as value. The value determines which of the tool-version +dependent customization options are used. For example, the command +'antlr-run-tool' uses the option 'antlr-v3-tool-command' (with default +value "java org.antlr.Tool") when 'antlr-tool-version' has the value +'antlr-v3'. + +*** Command 'antlr-mode' now also works on ANTLR v3 or v4 grammars. +If the variable 'antlr-tool-version' is not set locally, e.g. by the +file’s local variables specs, the command sets its local value to +'antlr-v2' if a keyword "class" or "header" appears at the beginning of +the source, or to 'antlr-v3' otherwise. + +*** New command 'antlr-v4-mode' is a derived mode of 'antlr-mode'. +It sets 'antlr-tool-version' to value 'antlr-v4', and is automatically +used for files with extension "g4". + +*** The variable 'antlr-language' is now used more generally. +The variable has a symbol as value which determines which of the +language-dependent customization options are used. These options +influence font-locking and indentation commands. Its value is usually +set according to the grammar option "language", see the default values +of 'antlr-v2-language-list', 'antlr-v3-language-list' and +'antlr-v4-language-list'. This mode now supports C, Delphi, JavaScript, +ObjC, Python and Ruby, additional to Java and Cpp. + +*** New user option 'antlr-run-tool-on-buffer-file'. +Command 'antlr-run-tool' now usually runs on the file for the current +buffer. Customize this user option to have value ' nil' to get the +previous behavior back. + * New Modes and Packages in Emacs 31.1 diff --git a/lisp/files.el b/lisp/files.el index f9341ab5a90..6949544a9e4 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -3215,6 +3215,7 @@ ARC\\|ZIP\\|LZH\\|LHA\\|ZOO\\|[JEW]AR\\|XPI\\|RAR\\|CBR\\|7Z\\|SQUASHFS\\)\\'" . ("\\.ebrowse\\'" . ebrowse-tree-mode) ("#\\*mail\\*" . mail-mode) ("\\.g\\'" . antlr-mode) + ("\\.g4\\'" . antlr-v4-mode) ("\\.mod\\'" . m2-mode) ("\\.ses\\'" . ses-mode) ("\\.docbook\\'" . sgml-mode) commit ab6382087021152b91d5bc9395fed68aa2d9c32b Merge: dbdae1b9a2c 8447ebb06fd Author: Michael Albinus Date: Sun Dec 14 16:56:06 2025 +0100 Merge branch 'master' of git.sv.gnu.org:/srv/git/emacs commit dbdae1b9a2c068cde49c9b813a8dcfe590f0d367 Author: Michael Albinus Date: Sun Dec 14 16:55:38 2025 +0100 Implement process error buffer in tramp-smb.el * lisp/net/tramp-smb.el (tramp-smb-handle-make-process): Handle error buffer. * test/lisp/net/tramp-tests.el (tramp-test30-make-process): Adapt test. diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el index 8e385913004..3269efadc95 100644 --- a/lisp/net/tramp-smb.el +++ b/lisp/net/tramp-smb.el @@ -1300,13 +1300,29 @@ will be used." (tramp-unquote-file-local-name (if (stringp stderr) stderr (tramp-make-tramp-temp-name v))))) - ;; (remote-tmpstderr - ;; (and tmpstderr (tramp-make-tramp-file-name v tmpstderr))) + (remote-tmpstderr + (and tmpstderr (tramp-make-tramp-file-name v tmpstderr))) (bmp (and (buffer-live-p buffer) (buffer-modified-p buffer))) p) (if tmpstderr (setq command (format "%s 2>//%s%s" command host tmpstderr))) + ;; Handle error buffer. + (when (bufferp stderr) + (make-empty-file remote-tmpstderr) + (with-current-buffer stderr + (setq buffer-read-only nil + default-directory (file-name-directory remote-tmpstderr)) + (setq-local buffer-file-name remote-tmpstderr + auto-revert-notify-exclude-dir-regexp + "nothing-to-be-excluded" + create-lockfiles t) + (set-visited-file-modtime) + (set-buffer-modified-p nil) + (auto-save-mode -1) + (auto-save-visited-mode -1) + (auto-revert-tail-mode 1))) + (with-tramp-saved-connection-properties v '(" process-name" " process-buffer") (unwind-protect @@ -1339,6 +1355,20 @@ will be used." (ignore-errors (set-process-query-on-exit-flag p (null noquery)) (set-marker (process-mark p) (point))) + ;; We must flush them here already; otherwise + ;; `delete-file' will fail. + (tramp-flush-connection-property v " process-name") + (tramp-flush-connection-property v " process-buffer") + ;; Stop auto-revert. Delete stderr file. + (when (bufferp stderr) + (add-function + :after (process-sentinel p) + (lambda (_proc _msg) + (with-current-buffer stderr + (auto-revert-tail-mode -1) + (revert-buffer nil 'noconfirm)) + (ignore-errors + (delete-file remote-tmpstderr))))) ;; Return value. p)) diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el index c01766b9653..96e4e28de46 100644 --- a/test/lisp/net/tramp-tests.el +++ b/test/lisp/net/tramp-tests.el @@ -5840,9 +5840,7 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." ;; Process with stderr buffer. "telnet" does not cooperate with ;; three processes. - ;; FIXME: tramp-smb.el should implement this. - (unless (or (tramp--test-telnet-p) (tramp--test-smb-p) - (tramp-direct-async-process-p)) + (unless (or (tramp--test-telnet-p) (tramp-direct-async-process-p)) (let ((stderr (generate-new-buffer "*stderr*"))) (unwind-protect (with-temp-buffer @@ -5860,13 +5858,19 @@ If UNSTABLE is non-nil, the test is tagged as `:unstable'." (with-current-buffer stderr (with-timeout (10 (tramp--test-timeout-handler)) (while (not (string-match-p - "No such file or directory" (buffer-string))) - (while (accept-process-output - (get-buffer-process stderr) 0 nil t)))) + (rx (| "No such file or directory" + "Cannot find path")) + (buffer-string))) + (if (processp (get-buffer-process stderr)) + (while (accept-process-output + (get-buffer-process stderr) 0 nil t)) + (revert-buffer nil 'noconfirm)))) (delete-process proc) (should (string-match-p - (rx "cat:" (* nonl) " No such file or directory") + (rx (| (: "cat:" (* nonl) "No such file or directory") + ;; MS Windows. + (: "cat : Cannot find path"))) (buffer-string))))) ;; Cleanup. commit 8447ebb06fdf0a282622dd65efb5b6b8a142e896 Author: Philip Kaludercic Date: Sun Dec 14 16:50:49 2025 +0100 Load 'byte-recompile-file' to process User Lisp directory * lisp/startup.el (byte-recompile-file): Declare 'byte-recompile-file'. (prepare-user-lisp): Load bytecomp if necessary. (Bug#79997) diff --git a/lisp/startup.el b/lisp/startup.el index c455eb73814..7804ab42c8c 100644 --- a/lisp/startup.el +++ b/lisp/startup.el @@ -1236,6 +1236,9 @@ directories that do not contain Lisp files." :type '(choice (repeat (string :tag "Directory name"))) :version "31.1") +(declare-function byte-recompile-file "bytecomp" + (filename &optional force arg load)) + (defun prepare-user-lisp (&optional just-activate autoload-file force) "Byte-compile, scrape autoloads and prepare files in `user-lisp-directory'. Write the autoload file to AUTOLOAD-FILE. If JUST-ACTIVATE is non-nil, @@ -1246,6 +1249,7 @@ If FORCE is non-nil, or if invoked interactively with a prefix argument, re-create the entire autoload file and byte-compile everything unconditionally." (interactive (list nil nil current-prefix-arg)) + (unless just-activate (require 'bytecomp)) (unless (file-directory-p user-lisp-directory) (error "No such directory: %S" user-lisp-directory)) (unless autoload-file commit 699fb56b4e26aa2cffeec3292bf01c4ac5b11c44 Author: Sean Whitton Date: Sun Dec 14 10:51:08 2025 +0000 * lisp/vc/vc.el (vc-diff-internal): Use delay-mode-hooks. diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index f210d440b69..b0821de3da5 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -2799,13 +2799,15 @@ Return t if the buffer had changes, nil otherwise." ;; bindings are nicer for read only buffers. pcl-cvs does the ;; same thing. (setq buffer-read-only t) - (diff-mode) - (setq-local diff-vc-backend (car vc-fileset)) - (setq-local diff-vc-revisions (list rev1 rev2)) - (setq-local revert-buffer-function - (lambda (_ignore-auto _noconfirm) - (vc-diff-internal async vc-fileset rev1 rev2 verbose))) - (vc-call-backend (car vc-fileset) 'diff files rev1 rev2 buffer async) + (delay-mode-hooks + (diff-mode) + (setq-local diff-vc-backend (car vc-fileset)) + (setq-local diff-vc-revisions (list rev1 rev2)) + (setq-local revert-buffer-function + (lambda (_ignore-auto _noconfirm) + (vc-diff-internal async vc-fileset rev1 rev2 verbose))) + (vc-call-backend (car vc-fileset) 'diff files rev1 rev2 buffer async)) + (run-mode-hooks 'diff-mode-hook) (if (and (zerop (buffer-size)) (not (get-buffer-process (current-buffer)))) ;; Treat this case specially so as not to pop the buffer. commit d481b9efdc65bb066e2c765ae76ab5aa93dc9541 Author: Eli Zaretskii Date: Sun Dec 14 10:18:34 2025 +0200 Fix a bug in 'kill-visual-line' that caused it signal an error * lisp/simple.el (kill-visual-line): Don't assume 'posn-at-point' always returns a non-nil value. (Bug#80004) diff --git a/lisp/simple.el b/lisp/simple.el index 118fcb77502..6222608bbd0 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -8609,7 +8609,8 @@ even beep.)" ;; like display or overlay strings, intangible text, etc.: ;; otherwise, we don't want to kill a character that's ;; unrelated to the place where the visual line wraps. - (and (= (cdr (nth 6 (posn-at-point))) orig-vlnum) + (and (numberp (nth 6 (posn-at-point))) + (= (cdr (nth 6 (posn-at-point))) orig-vlnum) ;; Make sure we delete the character where the line wraps ;; under visual-line-mode, be it whitespace or a ;; character whose category set permits wrapping at it.