commit 70d064dab74ac7928eeacb61c03605b99de995a9 (HEAD, refs/remotes/origin/master) Author: Dmitry Gutov Date: Tue Oct 8 02:47:15 2024 +0300 poject--vc-list-files: Check that the current Emacs is 31+ * lisp/progmodes/project.el (project--vc-list-files): Check that the current Emacs is 31+, to avoid breakage on remote hosts with older Git (bug#73320). diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index b2f18da8925..18613e9ec33 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -674,7 +674,8 @@ See `project-vc-extra-root-markers' for the marker value format.") (submodules (project--git-submodules)) files) (setq args (append args - (and (version<= "2.35" (vc-git--program-version)) + (and (<= 31 emacs-major-version) + (version<= "2.35" (vc-git--program-version)) '("--sparse")) (and include-untracked '("-o")))) (when extra-ignores commit 7cd8108098c08de47078db4e17291e5a529e0ae0 Author: Dmitry Gutov Date: Tue Oct 8 02:42:39 2024 +0300 Detect Git version on remote hosts separately from the local one * lisp/vc/vc-git.el (vc-git--program-version): Detect Git version on remote hosts separately from the local one (buf#73320). (vc-git-connection-default-profile): Set up collection-local profile. And use it for the 'vc-git' :application. (vc-git--program-version): Operate on the connection-local value of 'vc-git--program-version'. diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 05400523048..5a7ffeffc9d 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -315,11 +315,21 @@ Good example of file name that needs this: \"test[56].xx\".") (defvar vc-git--program-version nil) +(connection-local-set-profile-variables + 'vc-git-connection-default-profile + '((vc-git--program-version . nil))) + +(connection-local-set-profiles + '(:application vc-git) + 'vc-git-connection-default-profile) + (defun vc-git--program-version () - (or vc-git--program-version - (let ((version-string - (vc-git--run-command-string nil "version"))) - (setq vc-git--program-version + (with-connection-local-application-variables 'vc-git + (or vc-git--program-version + (let ((version-string + (vc-git--run-command-string nil "version"))) + (setq-connection-local + vc-git--program-version (if (and version-string ;; Some Git versions append additional strings ;; to the numerical version string. E.g., Git @@ -329,7 +339,7 @@ Good example of file name that needs this: \"test[56].xx\".") (string-match "git version \\([0-9][0-9.]+\\)" version-string)) (string-trim-right (match-string 1 version-string) "\\.") - "0"))))) + "0")))))) (defun vc-git--git-path (&optional path) "Resolve .git/PATH for the current working tree. commit 2d139141a6c249691a50ade9c8d08dc35fcdf456 Author: Dmitry Gutov Date: Tue Oct 8 02:25:14 2024 +0300 Support file creation and deletion in diff-apply-hunk * lisp/vc/diff-mode.el (diff-find-file-name): Allow entering non-existing file name when the corresponding hunk is of type "create file" (bug#62731). Default to file name with deleted prefix if diff-buffer-type is Git or Hg. Make sure not to add such input to diff-remembered-files-alist, it would be hard to change otherwise in case of typo. (diff-setup-buffer-type): Match against the diff header common to 'hg diff' output. (diff-find-source-location): Look at the other source when the buffer is applied in reverse. (diff-apply-hunk): Delect file deletion and pass a different argument to 'diff-find-source-location' in such case. Bind diff-vc-backend to nil to avoid older revision buffer being returned. In the end, offer to delete the file if the hunk was of corresponding type and matched the existing contents. * etc/NEWS: Mention the new capability. diff --git a/etc/NEWS b/etc/NEWS index b5104145878..d5f48ae4391 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -424,6 +424,8 @@ useful to prepare a *vc-diff* buffer for committing a single hunk. When the region is active, it deletes all hunks that the region does not overlap. +*** 'diff-apply-hunk' now supports creating and deleting files. + ** php-ts-mode --- diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index d085c721bc8..cfa90d380ad 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -1091,13 +1091,24 @@ PREFIX is only used internally: don't use it." (diff-find-file-name old noprompt (match-string 1))) ;; if all else fails, ask the user (unless noprompt - (let ((file (expand-file-name (or (car fs) "")))) + (let ((file (or (car fs) "")) + (creation (equal null-device + (car (diff-hunk-file-names (not old)))))) + (when (and (memq diff-buffer-type '(git hg)) + (string-match "/" file)) + ;; Strip the dst prefix (like b/) if diff is from Git/Hg. + (setq file (substring file (match-end 0)))) + (setq file (expand-file-name file)) (setq file (read-file-name (format "Use file %s: " file) - (file-name-directory file) file t + (file-name-directory file) file + ;; Allow non-matching for creation. + (not creation) (file-name-nondirectory file))) - (setq-local diff-remembered-files-alist - (cons (cons fs file) diff-remembered-files-alist)) + (when (or (not creation) (file-exists-p file)) + ;; Only remember files that exist. User might have mistyped. + (setq-local diff-remembered-files-alist + (cons (cons fs file) diff-remembered-files-alist))) file))))))) @@ -1647,7 +1658,9 @@ modified lines of the diff." (setq-local diff-buffer-type (if (re-search-forward "^diff --git" nil t) 'git - nil))) + (if (re-search-forward "^diff -r.*-r" nil t) + 'hg + nil)))) (when (eq diff-buffer-type 'git) (setq diff-outline-regexp (concat "\\(^diff --git.*\\|" diff-hunk-header-re "\\)"))) @@ -1957,7 +1970,7 @@ SWITCHED is non-nil if the patch is already applied." diff-context-mid-hunk-header-re nil t) (error "Can't find the hunk separator")) (match-string 1))))) - (file (or (diff-find-file-name other noprompt) + (file (or (diff-find-file-name (xor other reverse) noprompt) (error "Can't find the file"))) (revision (and other diff-vc-backend (if reverse (nth 1 diff-vc-revisions) @@ -2020,7 +2033,11 @@ the value of this variable when given an appropriate prefix argument). With a prefix argument, REVERSE the hunk." (interactive "P") (diff-beginning-of-hunk t) - (pcase-let ((`(,buf ,line-offset ,pos ,old ,new ,switched) + (pcase-let* (;; Do not accept BUFFER.REV buffers as source location. + (diff-vc-backend nil) + ;; When we detect deletion, we will use the old file name. + (deletion (equal null-device (car (diff-hunk-file-names reverse)))) + (`(,buf ,line-offset ,pos ,old ,new ,switched) ;; Sometimes we'd like to have the following behavior: if ;; REVERSE go to the new file, otherwise go to the old. ;; But that means that by default we use the old file, which is @@ -2030,7 +2047,7 @@ With a prefix argument, REVERSE the hunk." ;; TODO: make it possible to ask explicitly for this behavior. ;; ;; This is duplicated in diff-test-hunk. - (diff-find-source-location nil reverse))) + (diff-find-source-location deletion reverse))) (cond ((null line-offset) (user-error "Can't find the text to patch")) @@ -2056,6 +2073,10 @@ With a prefix argument, REVERSE the hunk." "Hunk hasn't been applied yet; apply it now? " "Hunk has already been applied; undo it? "))))) (message "(Nothing done)")) + ((and deletion (not switched)) + (when (y-or-n-p (format-message "Delete file `%s'?" (buffer-file-name buf))) + (delete-file (buffer-file-name buf) delete-by-moving-to-trash) + (kill-buffer buf))) (t ;; Apply the hunk (with-current-buffer buf commit 9904376c797665de47ff760bcf8c2fe33d7ae625 Author: Dmitry Gutov Date: Tue Oct 8 02:03:04 2024 +0300 Support calling 'project-current' with custom prompt * lisp/progmodes/project.el (project-current): Treat being passed a string in the MAYBE-CURRENT argument specially (bug#70833). (project-prompt-project-dir, project-prompt-project-name): Handle it. * etc/NEWS: Mention that change. diff --git a/etc/NEWS b/etc/NEWS index b532d7c6555..b5104145878 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -124,6 +124,12 @@ This hook allows you to control which tab-bar tabs are auto-resized. *** New command 'project-root-find-file'. It is equivalent to running ‘project-any-command’ with ‘find-file’. +--- +*** The MAYBE-PROMPT argument of 'project-current' can be a string. +When such value is used, the 'project-prompt' values are called with it +as the first argument. This is a way for the callers to indicate, for +example, the reason or the context why the project is asked for. + ** Registers *** New functions 'buffer-to-register' and 'file-to-register'. diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 599a350e5ce..b2f18da8925 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -218,7 +218,8 @@ else prompt the user for the project to use. To prompt for a project, call the function specified by `project-prompter', which returns the directory in which to look for the project. If no project is found in that directory, return a \"transient\" -project instance. +project instance. When MAYBE-PROMPT is a string, it's passed to the +prompter function as an argument. The \"transient\" project instance is a special kind of value which denotes a project rooted in that directory and includes all @@ -235,7 +236,9 @@ of the project instance object." (pr) ((unless project-current-directory-override maybe-prompt) - (setq directory (funcall project-prompter) + (setq directory (if (stringp maybe-prompt) + (funcall project-prompter maybe-prompt) + (funcall project-prompter)) pr (project--find-in-directory directory)))) (when maybe-prompt (if pr @@ -1880,11 +1883,12 @@ the project list." (defvar project--dir-history) -(defun project-prompt-project-dir () +(defun project-prompt-project-dir (&optional prompt) "Prompt the user for a directory that is one of the known project roots. The project is chosen among projects known from the project list, see `project-list-file'. -It's also possible to enter an arbitrary directory not in the list." +It's also possible to enter an arbitrary directory not in the list. +When PROMPT is non-nil, use it as the prompt string." (project--ensure-read-project-list) (let* ((dir-choice "... (choose a dir)") (choices @@ -1898,18 +1902,23 @@ It's also possible to enter an arbitrary directory not in the list." ;; If the user simply pressed RET, do this again until they don't. (setq pr-dir (let (history-add-new-input) - (completing-read "Select project: " choices nil t nil 'project--dir-history)))) + (completing-read (if prompt + ;; TODO: Use `format-prompt' (Emacs 28.1+) + (format "%s: " (substitute-command-keys prompt)) + "Select project: ") + choices nil t nil 'project--dir-history)))) (if (equal pr-dir dir-choice) (read-directory-name "Select directory: " default-directory nil t) pr-dir))) (defvar project--name-history) -(defun project-prompt-project-name () +(defun project-prompt-project-name (&optional prompt) "Prompt the user for a project, by name, that is one of the known project roots. The project is chosen among projects known from the project list, see `project-list-file'. -It's also possible to enter an arbitrary directory not in the list." +It's also possible to enter an arbitrary directory not in the list. +When PROMPT is non-nil, use it as the prompt string." (let* ((dir-choice "... (choose a dir)") project--name-history (choices @@ -1933,7 +1942,10 @@ It's also possible to enter an arbitrary directory not in the list." ;; If the user simply pressed RET, do this again until they don't. (setq pr-name (let (history-add-new-input) - (completing-read "Select project: " table nil t nil 'project--name-history)))) + (completing-read (if prompt + (format "%s: " prompt) + "Select project: ") + table nil t nil 'project--name-history)))) (if (equal pr-name dir-choice) (read-directory-name "Select directory: " default-directory nil t) (let ((proj (assoc pr-name choices))) commit ff4de9eff30ade164655354f71e7cbca48135858 Author: Eli Zaretskii Date: Mon Oct 7 21:06:34 2024 +0300 * lib-src/etags.c (C_entries): Fix assertion violation. diff --git a/lib-src/etags.c b/lib-src/etags.c index 7f652790261..4c9b954c9a3 100644 --- a/lib-src/etags.c +++ b/lib-src/etags.c @@ -4266,7 +4266,10 @@ C_entries (int c_ext, /* extension of C */ /* Only if typdef == tinbody is typdefbracelev significant. */ if (typdef == tinbody && bracelev <= typdefbracelev) { - assert (bracelev == typdefbracelev); + /* If we forcibly reset bracelevel to zero above, let's + not shoot ourself in the foot and assert that we didn't. */ + if (!(!ignoreindent && lp == newlb.buffer + 1)) + assert (bracelev == typdefbracelev); typdef = tend; } break; commit 49325e13560daa768e6f455ade8c9284b7369a26 Author: Jim Porter Date: Sun Oct 6 15:19:13 2024 -0700 ; Fix completion of variables in Eshell immediately after "$" * lisp/eshell/esh-var.el (eshell-complete-variable-reference): Match group 1 even when there's nothing after "$". diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el index 5d7ea1c3664..d53ae997cdf 100644 --- a/lisp/eshell/esh-var.el +++ b/lisp/eshell/esh-var.el @@ -840,10 +840,10 @@ START and END." (let ((arg (pcomplete-actual-arg))) (when (string-match (rx "$" (? (or "#" "@")) - (? (or (group-n 1 (regexp eshell-variable-name-regexp) - string-end) - (seq (group-n 2 (or "'" "\"")) - (group-n 1 (+ anychar)))))) + (or (group-n 1 (? (regexp eshell-variable-name-regexp)) + string-end) + (seq (group-n 2 (or "'" "\"")) + (group-n 1 (+ anychar))))) arg) (setq pcomplete-stub (substring arg (match-beginning 1))) (let ((delimiter (match-string 2 arg)))