diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi index 3f2c8d4afdf..77c4e09c826 100644 --- a/doc/emacs/dired.texi +++ b/doc/emacs/dired.texi @@ -715,6 +715,10 @@ Otherwise, the command operates on the current file only. Certain other Dired commands, such as @kbd{!} and the @samp{%} commands, use the same conventions to decide which files to work on. + In addition to Dired commands described here, you can also invoke +Version Control (VC) commands on one or more files shown in a Dired +buffer. @xref{Version Control}. + @vindex dired-dwim-target @cindex two directories (in Dired) Commands which ask for a destination directory, such as those which diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi index 5191bb2918d..f5bbc4d65c0 100644 --- a/doc/emacs/maintaining.texi +++ b/doc/emacs/maintaining.texi @@ -94,6 +94,20 @@ is useful when you perform version control commands outside Emacs different version control system, or remove it from version control entirely. +@cindex VC commands, in Dired buffers +@cindex filesets, VC, in Dired buffers + VC is also enabled automatically in Dired buffers (@pxref{Dired}) +showing directories whose files are controlled by a VCS@. All VC +commands described in this section can be invoked from any Dired +buffer showing a directory with VC-controlled files; any files that +are marked in a Dired buffer (@pxref{Marks vs Flags}) are considered +to belong to the current fileset, and VC commands operate on the files +in this fileset. This allows you to construct VC filesets including +any files you want, regardless of their VC state. (If no files are +marked when a VC command is invoked from a Dired buffer, the file +shown on the current line in the buffer is considered the only file in +the fileset.) + @menu * Introduction to VC:: How version control works in general. * VC Mode Line:: How the mode line shows version control status. @@ -471,7 +485,10 @@ collection of one or more files that a VC operation acts on. When you type VC commands in a buffer visiting a version-controlled file, the VC fileset is simply that one file. When you type them in a VC Directory buffer, and some files in it are marked, the VC fileset -consists of the marked files (@pxref{VC Directory Mode}). +consists of the marked files (@pxref{VC Directory Mode}). Likewise, +when you invoke a VC command from a Dired buffer, the VC fileset +consists of the marked files (@pxref{Marks vs Flags}), defaulting to +the file shown on the current line if no files are marked. On modern changeset-based version control systems (@pxref{VCS Changesets}), VC commands handle multi-file VC filesets as a group. @@ -495,7 +512,9 @@ action on the current VC fileset: either registering it with a version control system, or committing it, or unlocking it, or merging changes into it. The precise actions are described in detail in the following subsections. You can use @kbd{C-x v v} either in a file-visiting -buffer, in a Dired buffer, or in a VC Directory buffer. +buffer, in a Dired buffer, or in a VC Directory buffer; in the latter +two cases the command operates on the fileset consisting of the marked +files. Note that VC filesets are distinct from the named filesets used for viewing and visiting files in functional groups @@ -840,7 +859,7 @@ details. If you invoke @kbd{C-x v =} or @kbd{C-u C-x v =} from a Dired buffer (@pxref{Dired}), the file listed on the current line is treated as the -current VC fileset. +current VC fileset. The VC fileset can also include several marked files. @ifnottex @findex vc-ediff @@ -1000,16 +1019,25 @@ Search the change history for a specified pattern. @findex vc-print-log @kbd{C-x v l} (@code{vc-print-log}) displays a buffer named @file{*vc-change-log*}, showing the history of changes made to the -current file, including who made the changes, the dates, and the log -entry for each change (these are the same log entries you would enter -via the @file{*vc-log*} buffer; @pxref{Log Buffer}). Point is -centered at the revision of the file currently being visited. With a -prefix argument, the command prompts for the revision to center on, -and the maximum number of revisions to display. +current fileset in the long form, including who made the changes, the +dates, and the log entry for each change (these are the same log +entries you would enter via the @file{*vc-log*} buffer; @pxref{Log +Buffer}). When invoked from a buffer visiting a file, the current +fileset consists of that single file, and point in the displayed +@file{*vc-change-log*} buffer is centered at the revision of that +file. When invoked from a VC Directory buffer (@pxref{VC Directory +Mode}) or from a Dired buffer (@pxref{Dired}), the fileset consists of +all the marked files, defaulting to the file shown on the current line +in the directory buffer if no file is marked. - If you call @kbd{C-x v l} from a VC Directory buffer (@pxref{VC -Directory Mode}) or a Dired buffer (@pxref{Dired}), it applies to the -file listed on the current line. + If the fileset includes one or more directories, the resulting +@file{*vc-change-log*} buffer shows a short log of changes (one line +for each change), if the VC backend supports that; otherwise it shows +the log in the long form. + + With a prefix argument, the command prompts for the revision to +center on in the @file{*vc-change-log*} buffer and for the maximum +number of revisions to display. @kindex C-x v L @findex vc-print-root-log @@ -1215,6 +1243,11 @@ called PCL-CVS which is specialized for CVS@. @xref{Top, , About PCL-CVS, pcl-cvs, PCL-CVS---The Emacs Front-End to CVS}. @end ifnottex + You can also invoke VC commands from Dired buffers (@pxref{Dired}). +In that case, any VC command you invoke considers the marked files as +the current fileset (@pxref{Basic VC Editing}), defaulting to the file +on the current line if no files are marked. + @menu * Buffer: VC Directory Buffer. What the buffer looks like and means. * Commands: VC Directory Commands. Commands to use in a VC directory buffer. diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 70785c8100f..b15f2ab4d29 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -1988,7 +1988,11 @@ all. @defun file-modes-number-to-symbolic modes This function converts a numeric file mode specification in -@var{modes} into the equivalent symbolic form. +@var{modes} into the equivalent string form. The string which this +function returns is in the same format produced by the shell command +@kbd{ls -l} and by @code{file-attributes}, @emph{not} the symbolic +form accepted by @code{file-modes-symbolic-to-number} and the +@command{chmod} shell command. @end defun @defun set-file-times filename &optional time flag diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi index 38c6adaf131..eed9744b9f0 100644 --- a/doc/misc/eglot.texi +++ b/doc/misc/eglot.texi @@ -883,14 +883,6 @@ this map. For example: (define-key eglot-mode-map (kbd "") 'xref-find-definitions) @end lisp -@item eglot-lazy-inlay-hints -This variable controls the operation and performance of LSP Inlay -Hints (@pxref{Eglot Features}). If non-@code{nil}, it specifies how -much time to wait after a window is displayed or scrolled before -requesting hints for that visible portion of a given buffer. If -@code{nil}, inlay hints are always requested for the whole buffer, -even for parts of it not currently visible. - @end vtable Additional variables, which are relevant for customizing the server diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el index 6cb097f6bb3..96ac9da4508 100644 --- a/lisp/dired-aux.el +++ b/lisp/dired-aux.el @@ -3741,12 +3741,21 @@ of the target of the link instead." ;;;###autoload (defun dired-vc-next-action (verbose) - "Do the next version control operation on marked files/directories. -When only files are marked then call `vc-next-action' with the -same value of the VERBOSE argument. -When also directories are marked then call `vc-dir' and mark -the same files/directories in the VC-Dir buffer that were marked -in the Dired buffer." + "Do the next logical version control operation on marked files/directories. +The VC control operation will operate on a fileset which includes +the marked files/directories. If no files/directories are marked, the +fileset will include the single file/directory shown on the current line. + +If only regular files are in the fileset, call `vc-next-action' with +the same value of the VERBOSE argument (interactively, the prefix +argument). + +If one or more directories are in the fileset, start `vc-dir' in the root +directory of the repository that includes the current directory, with +the same files/directories marked in the VC-Directory buffer that were +marked in the original Dired buffer. If the current directory doesn't +belong to a VCS repository, prompt for a repository directory. In this +case, the VERBOSE argument is ignored." (interactive "P") (let* ((marked-files (dired-get-marked-files nil nil nil nil t)) diff --git a/lisp/files.el b/lisp/files.el index 5b989902bc3..387a3b5dc66 100644 --- a/lisp/files.el +++ b/lisp/files.el @@ -8406,11 +8406,14 @@ as in \"og+rX-w\"." num-rights)) (defun file-modes-number-to-symbolic (mode &optional filetype) - "Return a string describing a file's MODE. + "Return a description of a file's MODE as a string of 10 letters and dashes. +The returned string is like the mode description produced by \"ls -l\". For instance, if MODE is #o700, then it produces `-rwx------'. -FILETYPE if provided should be a character denoting the type of file, -such as `?d' for a directory, or `?l' for a symbolic link and will override -the leading `-' char." +Note that this is NOT the same as the \"chmod\" style symbolic description +accepted by `file-modes-symbolic-to-number'. +FILETYPE, if provided, should be a character denoting the type of file, +such as `?d' for a directory, or `?l' for a symbolic link, and will override +the leading `-' character." (string (or filetype (pcase (ash mode -12) diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el index 8262e6261d4..72df65a2287 100644 --- a/lisp/progmodes/c-ts-common.el +++ b/lisp/progmodes/c-ts-common.el @@ -268,7 +268,7 @@ particular major mode. This cannot be nil for `c-ts-common' statement indent functions to work.") (defvar c-ts-common-indent-type-regexp-alist nil - "An alist of of node type regexps. + "An alist of node type regexps. Each key in the alist is one of `if', `else', `do', `while', `for', `block', `close-bracket'. Each value in the alist diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index b569c03e8c2..4a09da65e53 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -2824,16 +2824,20 @@ for which LSP on-type-formatting should be requested." (mapcar (jsonrpc-lambda (&rest item &key label insertText insertTextFormat - &allow-other-keys) + textEdit &allow-other-keys) (let ((proxy - (cond ((and (eql insertTextFormat 2) - (eglot--snippet-expansion-fn)) + ;; Snippet or textEdit, it's safe to + ;; display/insert the label since + ;; it'll be adjusted. If no usable + ;; insertText at all, label is best, + ;; too. + (cond ((or (and (eql insertTextFormat 2) + (eglot--snippet-expansion-fn)) + textEdit + (null insertText) + (string-empty-p insertText)) (string-trim-left label)) - ((and insertText - (not (string-empty-p insertText))) - insertText) - (t - (string-trim-left label))))) + (t insertText)))) (unless (zerop (length proxy)) (put-text-property 0 1 'eglot--lsp-item item proxy)) proxy)) @@ -3485,32 +3489,39 @@ If NOERROR, return predicate, else erroring function." (defface eglot-parameter-hint-face '((t (:inherit eglot-inlay-hint-face))) "Face used for parameter inlay hint overlays.") -(defcustom eglot-lazy-inlay-hints 0.3 - "If non-nil, restrict LSP inlay hints to visible portion of buffer. +(defvar-local eglot--outstanding-inlay-hints-region (cons nil nil) + "Jit-lock-calculated (FROM . TO) region with potentially outdated hints") -Value is number specifying how many seconds to wait after a -window has been (re)scrolled before requesting new inlay hints -for the visible region of the window being manipulated. +(defvar-local eglot--outstanding-inlay-regions-timer nil + "Helper timer for `eglot--update-hints'") -If nil, then inlay hints are requested for the entire buffer. - -This value is only meaningful if the minor mode -`eglot-inlay-hints-mode' is true. -" - :type 'number - :version "29.1") - -(defun eglot--inlay-hints-fully () - (eglot--widening (eglot--update-hints-1 (point-min) (point-max)))) - -(cl-defun eglot--inlay-hints-lazily (&optional (buffer (current-buffer))) - (eglot--when-live-buffer buffer - (when eglot--managed-mode - (dolist (window (get-buffer-window-list nil nil 'visible)) - (eglot--update-hints-1 (window-start window) (window-end window)))))) +(defun eglot--update-hints (from to) + "Jit-lock function for Eglot inlay hints." + (cl-symbol-macrolet ((region eglot--outstanding-inlay-hints-region) + (timer eglot--outstanding-inlay-regions-timer)) + (setcar region (min (or (car region) (point-max)) from)) + (setcdr region (max (or (cdr region) (point-min)) to)) + ;; HACK: We're relying on knowledge of jit-lock internals here. The + ;; condition comparing `jit-lock-context-unfontify-pos' to + ;; `point-max' is a heuristic for telling whether this call to + ;; `jit-lock-functions' happens after `jit-lock-context-timer' has + ;; just run. Only after this delay should we start the smoothing + ;; timer that will eventually call `eglot--update-hints-1' with the + ;; coalesced region. I wish we didn't need the timer, but sometimes + ;; a lot of "non-contextual" calls come in all at once and do verify + ;; the condition. Notice it is a 0 second timer though, so we're + ;; not introducing any more delay over jit-lock's timers. + (when (= jit-lock-context-unfontify-pos (point-max)) + (if timer (cancel-timer timer)) + (setq timer (run-at-time + 0 nil + (lambda () + (eglot--update-hints-1 (max (car region) (point-min)) + (min (cdr region) (point-max))) + (setq region (cons nil nil) timer nil))))))) (defun eglot--update-hints-1 (from to) - "Request LSP inlay hints and annotate current buffer from FROM to TO." + "Do most work for `eglot--update-hints', including LSP request." (let* ((buf (current-buffer)) (paint-hint (eglot--lambda ((InlayHint) position kind label paddingLeft paddingRight) @@ -3541,60 +3552,16 @@ This value is only meaningful if the minor mode (mapc paint-hint hints)))) :deferred 'eglot--update-hints-1))) -(defun eglot--inlay-hints-after-scroll (window display-start) - (cl-macrolet ((wsetq (sym val) `(set-window-parameter window ',sym ,val)) - (wgetq (sym) `(window-parameter window ',sym))) - (let ((buf (window-buffer window)) - (timer (wgetq eglot--inlay-hints-timer)) - (last-display-start (wgetq eglot--last-inlay-hint-display-start))) - (when (and eglot-lazy-inlay-hints - ;; FIXME: If `window' is _not_ the selected window, - ;; then for some unknown reason probably related to - ;; the overlays added later to the buffer, the scroll - ;; function will be called indefinitely. Not sure if - ;; an Emacs bug, but prevent useless duplicate calls - ;; by saving and examining `display-start' fixes it. - (not (eql last-display-start display-start))) - (when timer (cancel-timer timer)) - (wsetq eglot--last-inlay-hint-display-start - display-start) - (wsetq eglot--inlay-hints-timer - (run-at-time - eglot-lazy-inlay-hints - nil (lambda () - (eglot--when-live-buffer buf - (when (eq buf (window-buffer window)) - (eglot--update-hints-1 (window-start window) - (window-end window)) - (wsetq eglot--inlay-hints-timer nil)))))))))) - (define-minor-mode eglot-inlay-hints-mode - "Minor mode annotating buffer with LSP inlay hints." + "Minor mode for annotating buffers with LSP server's inlay hints." :global nil (cond (eglot-inlay-hints-mode - (cond - ((not (eglot--server-capable :inlayHintProvider)) + (if (eglot--server-capable :inlayHintProvider) + (jit-lock-register #'eglot--update-hints 'contextual) (eglot--warn - "No :inlayHintProvider support. Inlay hints will not work.")) - (eglot-lazy-inlay-hints - (add-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-lazily t t) - (add-hook 'window-scroll-functions - #'eglot--inlay-hints-after-scroll nil t) - ;; Maybe there isn't a window yet for current buffer, - ;; so `run-at-time' ensures this runs after redisplay. - (run-at-time 0 nil #'eglot--inlay-hints-lazily)) - (t - (add-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-fully nil t) - (eglot--inlay-hints-fully)))) + "No :inlayHintProvider support. Inlay hints will not work."))) (t - (remove-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-lazily t) - (remove-hook 'eglot--document-changed-hook - #'eglot--inlay-hints-fully t) - (remove-hook 'window-scroll-functions - #'eglot--inlay-hints-after-scroll t) + (jit-lock-unregister #'eglot--update-hints) (remove-overlays nil nil 'eglot--inlay-hint t)))) diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 00a887f6ce7..90905edb887 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -1239,7 +1239,11 @@ For old-style locking-based version control systems, like RCS: When using this command to register a new file (or files), it will automatically deduce which VC repository to register it -with, using the most specific one." +with, using the most specific one. + +If VERBOSE is non-nil (interactively, the prefix argument), +you can specify a VC backend or (for centralized VCS only) +the revision ID or branch ID." (interactive "P") (let* ((vc-fileset (vc-deduce-fileset nil t 'state-model-only-files)) (backend (car vc-fileset)) @@ -2696,7 +2700,16 @@ earlier revisions. Show up to LIMIT entries (non-nil means unlimited)." is-start-revision limit type))))) (defvar vc-log-view-type nil - "Set this to differentiate the different types of logs.") + "Set this to record the type of VC log shown in the current buffer. +Supported values are: + + `short' -- short log form, one line for each commit + `long' -- long log form, including full log message and author + `with-diff' -- log including diffs + `log-outgoing' -- log of changes to be pushed to upstream + `log-incoming' -- log of changes to be brought by pulling from upstream + `log-search' -- log entries matching a pattern; shown in long format + `mergebase' -- log created by `vc-log-mergebase'.") (put 'vc-log-view-type 'permanent-local t) (defvar vc-sentinel-movepoint) @@ -2753,13 +2766,20 @@ Each function runs in the log output buffer without args.") ;;;###autoload (defun vc-print-log (&optional working-revision limit) - "List the change log of the current fileset in a window. -If WORKING-REVISION is non-nil, leave point at that revision. + "Show in another window the VC change history of the current fileset. +If WORKING-REVISION is non-nil, it should be a revision ID; position +point in the change history buffer at that revision. If LIMIT is non-nil, it should be a number specifying the maximum number of revisions to show; the default is `vc-log-show-limit'. When called interactively with a prefix argument, prompt for -WORKING-REVISION and LIMIT." +WORKING-REVISION and LIMIT. + +This shows a short log (one line for each commit) if the current +fileset includes directories and the VC backend supports that; +otherwise it shows the detailed log of each commit, which includes +the full log message and the author. Additional control of the +shown log style is available via `vc-log-short-style'." (interactive (cond (current-prefix-arg @@ -2784,14 +2804,14 @@ WORKING-REVISION and LIMIT." ;;;###autoload (defun vc-print-root-log (&optional limit revision) - "List the revision history for the current VC controlled tree in a window. + "Show in another window VC change history of the current VC controlled tree. If LIMIT is non-nil, it should be a number specifying the maximum number of revisions to show; the default is `vc-log-show-limit'. -When called interactively with a prefix argument, prompt for LIMIT. -When the prefix argument is a number, use it as LIMIT. +When called interactively with a prefix argument, prompt for LIMIT, but +if the prefix argument is a number, use it as LIMIT. A special case is when the prefix argument is 1: in this case -the command asks for the ID of a revision, and shows that revision -with its diffs (if the underlying VCS supports that)." +the command prompts for the ID of a revision, and shows that revision +with its diffs (if the underlying VCS backend supports that)." (interactive (cond ((eq current-prefix-arg 1) @@ -2875,15 +2895,17 @@ In some version control systems REMOTE-LOCATION can be a remote branch name." ;;;###autoload (defun vc-log-search (pattern) - "Search the log of changes for PATTERN. + "Search the VC log of changes for PATTERN and show log of matching changes. PATTERN is usually interpreted as a regular expression. However, its exact semantics is up to the backend's log search command; some can only match fixed strings. -Display all entries that match log messages in long format. -With a prefix argument, ask for a command to run that will output -log entries." +This command displays in long format all the changes whose log messages +match PATTERN. + +With a prefix argument, the command asks for a shell command to run that +will output log entries, and displays those log entries instead." (interactive (list (unless current-prefix-arg (read-regexp "Search log with pattern: ")))) (let ((backend (vc-deduce-backend))) @@ -2894,8 +2916,8 @@ log entries." ;;;###autoload (defun vc-log-mergebase (_files rev1 rev2) - "Show a log of changes between the merge base of REV1 and REV2 revisions. -The merge base is a common ancestor between REV1 and REV2 revisions." + "Show a log of changes between the merge base of revisions REV1 and REV2. +The merge base is a common ancestor of revisions REV1 and REV2." (interactive (vc-diff-build-argument-list-internal (or (ignore-errors (vc-deduce-fileset t))