Package: emacs;
Reported by: Tom Tromey <tom <at> tromey.com>
Date: Fri, 10 Feb 2017 22:17:02 UTC
Severity: minor
Found in version 25.1.91
Done: Tom Tromey <tom <at> tromey.com>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 25683 in the body.
You can then email your comments to 25683 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Fri, 10 Feb 2017 22:17:02 GMT) Full text and rfc822 format available.Tom Tromey <tom <at> tromey.com>
:bug-gnu-emacs <at> gnu.org
.
(Fri, 10 Feb 2017 22:17:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: bug-gnu-emacs <at> gnu.org Subject: 25.1.91; vc-dir shows conflicted files as "edited" Date: Fri, 10 Feb 2017 15:15:35 -0700
I was doing a "git rebase" and it had some conflicts. If I "git status" in the shell I can see conflicts like: both modified: gdb/minidebug.c However, if I use vc-dir, I just see: edited gdb/minidebug.c This isn't any different from a file that is touched by this change but not in conflict. I think it would be nicer if vc-dir showed me which files had conflicts and which were merely "edited". Tom In GNU Emacs 25.1.91.2 (x86_64-unknown-linux-gnu, GTK+ Version 3.22.7) of 2017-02-02 built on bapiya Repository revision: 7e02a477bbcabb4e65aeecade79b67357c0b9dae Windowing system distributor 'Fedora Project', version 11.0.11901000 System Description: Fedora release 25 (Twenty Five) Configured using: 'configure --prefix=/home/tromey/Emacs/install/ --with-modules' Configured features: XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND GPM DBUS GCONF GSETTINGS NOTIFY LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 MODULES Important settings: value of $LANG: en_US.utf8 value of $XMODIFIERS: @im=ibus locale-coding-system: utf-8-unix Major mode: VC dir Minor modes in effect: vc-parent-buffer: *vc-dir*<binutils-gdb> shell-dirtrack-mode: t diff-auto-refine-mode: t which-function-mode: t erc-services-mode: t erc-list-mode: t erc-menu-mode: t erc-autojoin-mode: t erc-ring-mode: t erc-networks-mode: t erc-pcomplete-mode: t erc-track-mode: t erc-match-mode: t erc-netsplit-mode: t erc-hl-nicks-mode: t erc-button-mode: t erc-fill-mode: t erc-stamp-mode: t erc-irccontrols-mode: t erc-noncommands-mode: t erc-move-to-prompt-mode: t erc-readonly-mode: t savehist-mode: t tooltip-mode: t global-eldoc-mode: t electric-indent-mode: t mouse-wheel-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t buffer-read-only: t column-number-mode: t line-number-mode: t transient-mark-mode: t Recent messages: Delete excess backup versions of /home/tromey/gdb/binutils-gdb/.git/COMMIT_EDITMSG? (y or n) y Wrote /home/tromey/gdb/binutils-gdb/.git/COMMIT_EDITMSG There are unresolved conflicts in /home/tromey/gdb/binutils-gdb/gdb/ui-out.h Making completion list... Mark saved where search started Mark set Mark saved where search started C-x C-g is undefined (No files need saving) Hiding up-to-date and ignored items Load-path shadows: /home/tromey/.emacs.d/elpa/bubbles-0.5/bubbles hides /home/tromey/Emacs/install/share/emacs/25.1.91/lisp/play/bubbles Features: (shadow emacsbug conf-mode two-column iso-transl perl-mode sh-script executable cal-move nnregistry python tramp-sh tramp tramp-compat tramp-loaddefs trampver ucs-normalize make-mode etags cursor-sensor mhtml-mode org-bullets org-element org-rmail org-mhe org-irc org-info org-gnus org-docview doc-view image-mode org-bibtex bibtex org-bbdb org-w3m org org-macro org-footnote org-pcomplete org-list org-faces org-entities org-version ob-emacs-lisp ob ob-tangle ob-ref ob-lob ob-table ob-exp org-src ob-keys ob-comint ob-core ob-eval org-compat org-macs org-loaddefs gnus-fun gnus-draft noutline outline ido skeleton css-mode smie eww url-queue trace find-dired descr-text gdb-shell lisp-mnt url-handlers url-http url-gw url-auth lex edebug debug m4-mode bbdb-sc supercite regi xref project log-edit js json map sgml-mode flow-fill gnus-html xml url-cache mm-url url url-proxy url-privacy url-expand url-methods url-history url-cookie url-domsuf eieio-opt speedbar sb-image ezimage dframe find-func whitespace tcl log-view pcvs-util vc-annotate term/xterm xterm smerge-mode goto-addr shell find-file idutils derived bug-reference cc-mode cc-fonts cc-guess cc-menus cc-cmds jka-compr mailalias mail-hist nnir sort gnus-cite smiley shr-color url-util url-parse url-vars shr dom subr-x browse-url mm-archive gnus-async gnus-bcklg qp gnus-ml disp-table gnus-topic nndraft nnmh nnfolder utf-7 bbdb-gnus bbdb-mua bbdb-com crm network-stream nsm starttls gnus-agent gnus-srvr gnus-score score-mode nnvirtual gnus-msg nntp gnus-cache gnus-registry registry eieio-compat eieio-base gnus-art mm-uu mml2015 mm-view mml-smime smime dig mailcap gnus-sum gnus-group gnus-undo smtpmail gnus-start gnus-cloud nnimap nnmail mail-source tls gnutls utf7 netrc nnoo parse-time gnus-spec gnus-int gnus-range gnus-win gnus gnus-ems nnheader bbdb-message sendmail mail-extr message idna dired rfc822 mml mml-sec epg mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 ietf-drums mailabbrev mail-utils gmm-utils mailheader gud dwarf-mode copyright dabbrev misearch multi-isearch vc-mtn vc-hg vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs add-log rx vc-git diff-mode easy-mmode rust-mode flyspell ispell diminish edmacro kmacro projectile grep compile ibuf-ext ibuffer dash appt diary-lib diary-loaddefs cal-menu calendar cal-loaddefs which-func imenu minimap autorevert filenotify cus-start cus-load status erc-services erc-list erc-menu erc-join erc-ring erc-networks erc-pcomplete pcomplete erc-track erc-match erc-netsplit erc-hl-nicks color erc-button erc-fill erc-stamp wid-edit erc-goodies erc erc-backend erc-compat format-spec auth-source eieio gnus-util mm-util help-fns mail-prsvr password-cache thingatpt pp warnings advice vc-dir ewoc vc vc-dispatcher cc-styles cc-align cc-engine cc-vars cc-defs bbdb bbdb-site timezone ange-ftp comint ansi-color ring server savehist finder-inf dwarf-mode-autoloads gdb-shell-autoloads eieio-core lisppaste-autoloads pydoc-info-autoloads info-look cl-seq cl-macs cl weblogger-autoloads info package epg-config seq byte-opt gv bytecomp byte-compile cl-extra help-mode easymenu cconv cl-loaddefs pcase cl-lib bbdb-loaddefs time-date mule-util tooltip eldoc electric uniquify ediff-hook vc-hooks lisp-float-type mwheel x-win term/common-win x-dnd tool-bar dnd fontset image regexp-opt fringe tabulated-list newcomment elisp-mode lisp-mode prog-mode register page menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock syntax facemenu font-core frame cl-generic cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese charscript case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer cl-preloaded nadvice loaddefs button faces cus-face macroexp files text-properties overlay sha1 md5 base64 format env code-pages mule custom widget hashtable-print-readable backquote dbusbind inotify dynamic-setting system-font-setting font-render-setting move-toolbar gtk x-toolkit x multi-tty make-network-process emacs) Memory information: ((conses 16 1841388 223499) (symbols 48 137600 13) (miscs 40 30171 9433) (strings 32 518292 186214) (string-bytes 1 14434760) (vectors 16 128453) (vector-slots 8 2744148 100168) (floats 8 924 1207) (intervals 56 168057 715) (buffers 976 269))
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Sat, 11 Feb 2017 20:46:02 GMT) Full text and rfc822 format available.Message #8 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: 25683 <at> debbugs.gnu.org Subject: semi-working patch Date: Sat, 11 Feb 2017 13:45:06 -0700
This patch kind of works. That is, it correctly notices files that have a conflict. However, when typing "g" in vc-dir, such a file briefly appears as "edited", then switches to "conflict". This happens because a file is first noticed in the diff-index phase, then later its state is corrected in the new ls-files-conflict stage. Ideally it would be possible to get the conflict state directly from git diff-index, but I couldn't see a way to do that :(. The manual says: 8. sha1 for "dst"; 0{40} if creation, unmerged or "look at work tree". ... but this just means the value can be all-0 for either the edited or conflict states. One fix for this might be to pass maintain more state here and only call the update-function when all the passes are done. Another idea for a fix would be to notice files with an all-0 sha in diff-index, then push these names on "files"; then let the new ls-files-conflict stage determine the result. Tom diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 24dabb6..db19eb0 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -417,10 +417,22 @@ vc-git-after-dir-status-stage result)))) (`ls-files-up-to-date (setq next-stage 'ls-files-unknown) - (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) + (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} \\([0-3]\\)\t\\([^\0]+\\)\0" nil t) + (let ((perm (string-to-number (match-string 1) 8)) + (state (match-string 2)) + (name (match-string 3))) + (push (list name (if (equal state "0") + 'up-to-date + 'conflict) + (vc-git-create-extra-fileinfo perm perm)) + result)))) + (`ls-files-conflict + (setq next-stage 'ls-files-unknown) + ;; It's enough to look for "3" to notice a conflict. + (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 3\t\\([^\0]+\\)\0" nil t) (let ((perm (string-to-number (match-string 1) 8)) (name (match-string 2))) - (push (list name 'up-to-date + (push (list name 'conflict (vc-git-create-extra-fileinfo perm perm)) result)))) (`ls-files-unknown @@ -435,7 +447,7 @@ vc-git-after-dir-status-stage (vc-git-create-extra-fileinfo 0 0)) result))) (`diff-index - (setq next-stage (if files 'ls-files-up-to-date 'ls-files-unknown)) + (setq next-stage (if files 'ls-files-up-to-date 'ls-files-conflict)) (while (re-search-forward ":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMUT]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0" nil t 1) @@ -491,6 +503,9 @@ vc-git-dir-status-goto-stage (`ls-files-up-to-date (vc-git-command (current-buffer) 'async files "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-conflict + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) (`ls-files-unknown (vc-git-command (current-buffer) 'async files "ls-files" "-z" "-o" "--directory"
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Sat, 11 Feb 2017 21:41:01 GMT) Full text and rfc822 format available.Message #11 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: semi-working patch Date: Sat, 11 Feb 2017 14:40:05 -0700
Tom> One fix for this might be to pass maintain more state here and only call Tom> the update-function when all the passes are done. I've implemented this idea. Let me know what you think. Tom diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index 24dabb6..de07ea2 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -401,11 +401,30 @@ vc-git-dir-printer (vc-git-file-type-as-string old-perm new-perm) (vc-git-rename-as-string state extra)))) -(defun vc-git-after-dir-status-stage (stage files update-function) +(cl-defstruct (vc-git-dir-status-state + (:copier nil) + (:conc-name vc-git-dir-status-state->)) + ;; Current stage. + stage + ;; List of files still to be processed. + files + ;; Update function to be called at the end. + update-function + ;; Hash table of entries for files we've computed so far. + (hash (make-hash-table :test 'equal))) + +(defsubst vc-git-dir-status-update-file (state filename file-state file-info) + (puthash filename (list file-state file-info) + (vc-git-dir-status-state->hash state)) + (setf (vc-git-dir-status-state->files state) + (delete filename (vc-git-dir-status-state->files state)))) + +(defun vc-git-after-dir-status-stage (git-state) "Process sentinel for the various dir-status stages." - (let (next-stage result) + (let (next-stage + (files (vc-git-dir-status-state->files git-state))) (goto-char (point-min)) - (pcase stage + (pcase (vc-git-dir-status-state->stage git-state) (`update-index (setq next-stage (if (vc-git--empty-db-p) 'ls-files-added 'diff-index))) (`ls-files-added @@ -413,29 +432,40 @@ vc-git-after-dir-status-stage (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) (let ((new-perm (string-to-number (match-string 1) 8)) (name (match-string 2))) - (push (list name 'added (vc-git-create-extra-fileinfo 0 new-perm)) - result)))) + (vc-git-dir-status-update-file + git-state name 'added + (vc-git-create-extra-fileinfo 0 new-perm))))) (`ls-files-up-to-date (setq next-stage 'ls-files-unknown) - (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) + (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} \\([0-3]\\)\t\\([^\0]+\\)\0" nil t) + (let ((perm (string-to-number (match-string 1) 8)) + (state (match-string 2)) + (name (match-string 3))) + (vc-git-dir-status-update-file + git-state name (if (equal state "0") + 'up-to-date + 'conflict) + (vc-git-create-extra-fileinfo perm perm))))) + (`ls-files-conflict + (setq next-stage 'ls-files-unknown) + ;; It's enough to look for "3" to notice a conflict. + (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 3\t\\([^\0]+\\)\0" nil t) (let ((perm (string-to-number (match-string 1) 8)) (name (match-string 2))) - (push (list name 'up-to-date - (vc-git-create-extra-fileinfo perm perm)) - result)))) + (vc-git-dir-status-update-file + git-state name 'conflict + (vc-git-create-extra-fileinfo perm perm))))) (`ls-files-unknown (when files (setq next-stage 'ls-files-ignored)) (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) - (push (list (match-string 1) 'unregistered - (vc-git-create-extra-fileinfo 0 0)) - result))) + (vc-git-create-extra-fileinfo git-state (match-string 1) 'unregistered + (vc-git-create-extra-fileinfo 0 0)))) (`ls-files-ignored (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) - (push (list (match-string 1) 'ignored - (vc-git-create-extra-fileinfo 0 0)) - result))) + (vc-git-dir-status-update-file git-state (match-string 1) 'ignored + (vc-git-create-extra-fileinfo 0 0)))) (`diff-index - (setq next-stage (if files 'ls-files-up-to-date 'ls-files-unknown)) + (setq next-stage (if files 'ls-files-up-to-date 'ls-files-conflict)) (while (re-search-forward ":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMUT]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0" nil t 1) @@ -446,30 +476,34 @@ vc-git-after-dir-status-stage (new-name (match-string 8))) (if new-name ; Copy or rename. (if (eq ?C (string-to-char state)) - (push (list new-name 'added - (vc-git-create-extra-fileinfo old-perm new-perm - 'copy name)) - result) - (push (list name 'removed - (vc-git-create-extra-fileinfo 0 0 - 'rename new-name)) - result) - (push (list new-name 'added - (vc-git-create-extra-fileinfo old-perm new-perm - 'rename name)) - result)) - (push (list name (vc-git--state-code state) - (vc-git-create-extra-fileinfo old-perm new-perm)) - result)))))) - (when result - (setq result (nreverse result)) - (when files - (dolist (entry result) (setq files (delete (car entry) files))) - (unless files (setq next-stage nil)))) - (when (or result (not next-stage)) - (funcall update-function result next-stage)) - (when next-stage - (vc-git-dir-status-goto-stage next-stage files update-function)))) + (vc-git-dir-status-update-file + git-state new-name 'added + (vc-git-create-extra-fileinfo old-perm new-perm + 'copy name)) + (vc-git-dir-status-update-file + git-state name 'removed + (vc-git-create-extra-fileinfo 0 0 'rename new-name)) + (vc-git-dir-status-update-file + git-state new-name 'added + (vc-git-create-extra-fileinfo old-perm new-perm + 'rename name))) + (vc-git-dir-status-update-file + git-state name (vc-git--state-code state) + (vc-git-create-extra-fileinfo old-perm new-perm))))))) + ;; If we had files but now we don't, it's time to stop. + (when (and files (not (vc-git-dir-status-state->files git-state))) + (setq next-stage nil)) + (setf (vc-git-dir-status-state->stage git-state) next-stage) + (setf (vc-git-dir-status-state->files git-state) files) + (if next-stage + (vc-git-dir-status-goto-stage git-state) + (funcall (vc-git-dir-status-state->update-function git-state) + (let ((result nil)) + (maphash (lambda (key value) + (push (cons key value) result)) + (vc-git-dir-status-state->hash git-state)) + result) + nil)))) ;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command ;; from vc-dispatcher. @@ -477,41 +511,48 @@ vc-git-after-dir-status-stage ;; Follows vc-exec-after. (declare-function vc-set-async-update "vc-dispatcher" (process-buffer)) -(defun vc-git-dir-status-goto-stage (stage files update-function) - (erase-buffer) - (pcase stage - (`update-index - (if files - (vc-git-command (current-buffer) 'async files "add" "--refresh" "--") - (vc-git-command (current-buffer) 'async nil - "update-index" "--refresh"))) - (`ls-files-added - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-c" "-s" "--")) - (`ls-files-up-to-date - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-c" "-s" "--")) - (`ls-files-unknown - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-o" "--directory" - "--no-empty-directory" "--exclude-standard" "--")) - (`ls-files-ignored - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-o" "-i" "--directory" - "--no-empty-directory" "--exclude-standard" "--")) - ;; --relative added in Git 1.5.5. - (`diff-index - (vc-git-command (current-buffer) 'async files - "diff-index" "--relative" "-z" "-M" "HEAD" "--"))) - (vc-run-delayed - (vc-git-after-dir-status-stage stage files update-function))) +(defun vc-git-dir-status-goto-stage (git-state) + (let ((files (vc-git-dir-status-state->files git-state))) + (erase-buffer) + (pcase (vc-git-dir-status-state->stage git-state) + (`update-index + (if files + (vc-git-command (current-buffer) 'async files "add" "--refresh" "--") + (vc-git-command (current-buffer) 'async nil + "update-index" "--refresh"))) + (`ls-files-added + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-up-to-date + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-conflict + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-unknown + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-o" "--directory" + "--no-empty-directory" "--exclude-standard" "--")) + (`ls-files-ignored + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-o" "-i" "--directory" + "--no-empty-directory" "--exclude-standard" "--")) + ;; --relative added in Git 1.5.5. + (`diff-index + (vc-git-command (current-buffer) 'async files + "diff-index" "--relative" "-z" "-M" "HEAD" "--"))) + (vc-run-delayed + (vc-git-after-dir-status-stage git-state)))) (defun vc-git-dir-status-files (_dir files update-function) "Return a list of (FILE STATE EXTRA) entries for DIR." ;; Further things that would have to be fixed later: ;; - how to handle unregistered directories ;; - how to support vc-dir on a subdir of the project tree - (vc-git-dir-status-goto-stage 'update-index files update-function)) + (vc-git-dir-status-goto-stage + (make-vc-git-dir-status-state :stage 'update-index + :files files + :update-function update-function))) (defvar vc-git-stash-map (let ((map (make-sparse-keymap)))
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Sun, 12 Feb 2017 06:18:02 GMT) Full text and rfc822 format available.Message #14 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: semi-working patch Date: Sat, 11 Feb 2017 23:17:08 -0700
Tom> I've implemented this idea. Tom> Let me know what you think. It seems that this patch regresses the case where a new file is created and not registered. So, there's more debugging to be done. I'd still appreciate comments on the direction. Tom
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Tue, 14 Feb 2017 01:13:02 GMT) Full text and rfc822 format available.Message #17 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: semi-working patch Date: Mon, 13 Feb 2017 18:12:32 -0700
Tom> It seems that this patch regresses the case where a new file is created Tom> and not registered. So, there's more debugging to be done. Tom> I'd still appreciate comments on the direction. It was just a spot where I didn't properly update a call. This version works. Tom commit 4921bfdbbd7009749e371a6ec2b76b78679e4a3d Author: Tom Tromey <tom <at> tromey.com> Date: Mon Feb 13 18:09:36 2017 -0700 Make vc-git detect conflict state for vc-dir * lisp/vc/vc-git.el (vc-git-dir-status-state): New struct. (vc-git-dir-status-update-file): New function. (vc-git-after-dir-status-stage, vc-git-dir-status-goto-stage): Use vc-git-dir-status-state; add 'ls-files-conflict state. (vc-git-dir-status-files): Create a vc-git-dir-status-state. diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el index d985cb3..713965e 100644 --- a/lisp/vc/vc-git.el +++ b/lisp/vc/vc-git.el @@ -401,11 +401,30 @@ vc-git-dir-printer (vc-git-file-type-as-string old-perm new-perm) (vc-git-rename-as-string state extra)))) -(defun vc-git-after-dir-status-stage (stage files update-function) +(cl-defstruct (vc-git-dir-status-state + (:copier nil) + (:conc-name vc-git-dir-status-state->)) + ;; Current stage. + stage + ;; List of files still to be processed. + files + ;; Update function to be called at the end. + update-function + ;; Hash table of entries for files we've computed so far. + (hash (make-hash-table :test 'equal))) + +(defsubst vc-git-dir-status-update-file (state filename file-state file-info) + (puthash filename (list file-state file-info) + (vc-git-dir-status-state->hash state)) + (setf (vc-git-dir-status-state->files state) + (delete filename (vc-git-dir-status-state->files state)))) + +(defun vc-git-after-dir-status-stage (git-state) "Process sentinel for the various dir-status stages." - (let (next-stage result) + (let (next-stage + (files (vc-git-dir-status-state->files git-state))) (goto-char (point-min)) - (pcase stage + (pcase (vc-git-dir-status-state->stage git-state) (`update-index (setq next-stage (if (vc-git--empty-db-p) 'ls-files-added 'diff-index))) (`ls-files-added @@ -413,29 +432,40 @@ vc-git-after-dir-status-stage (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) (let ((new-perm (string-to-number (match-string 1) 8)) (name (match-string 2))) - (push (list name 'added (vc-git-create-extra-fileinfo 0 new-perm)) - result)))) + (vc-git-dir-status-update-file + git-state name 'added + (vc-git-create-extra-fileinfo 0 new-perm))))) (`ls-files-up-to-date (setq next-stage 'ls-files-unknown) - (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) + (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} \\([0-3]\\)\t\\([^\0]+\\)\0" nil t) + (let ((perm (string-to-number (match-string 1) 8)) + (state (match-string 2)) + (name (match-string 3))) + (vc-git-dir-status-update-file + git-state name (if (equal state "0") + 'up-to-date + 'conflict) + (vc-git-create-extra-fileinfo perm perm))))) + (`ls-files-conflict + (setq next-stage 'ls-files-unknown) + ;; It's enough to look for "3" to notice a conflict. + (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 3\t\\([^\0]+\\)\0" nil t) (let ((perm (string-to-number (match-string 1) 8)) (name (match-string 2))) - (push (list name 'up-to-date - (vc-git-create-extra-fileinfo perm perm)) - result)))) + (vc-git-dir-status-update-file + git-state name 'conflict + (vc-git-create-extra-fileinfo perm perm))))) (`ls-files-unknown (when files (setq next-stage 'ls-files-ignored)) (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) - (push (list (match-string 1) 'unregistered - (vc-git-create-extra-fileinfo 0 0)) - result))) + (vc-git-dir-status-update-file git-state (match-string 1) 'unregistered + (vc-git-create-extra-fileinfo 0 0)))) (`ls-files-ignored (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) - (push (list (match-string 1) 'ignored - (vc-git-create-extra-fileinfo 0 0)) - result))) + (vc-git-dir-status-update-file git-state (match-string 1) 'ignored + (vc-git-create-extra-fileinfo 0 0)))) (`diff-index - (setq next-stage (if files 'ls-files-up-to-date 'ls-files-unknown)) + (setq next-stage (if files 'ls-files-up-to-date 'ls-files-conflict)) (while (re-search-forward ":\\([0-7]\\{6\\}\\) \\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} [0-9a-f]\\{40\\} \\(\\([ADMUT]\\)\0\\([^\0]+\\)\\|\\([CR]\\)[0-9]*\0\\([^\0]+\\)\0\\([^\0]+\\)\\)\0" nil t 1) @@ -446,30 +476,34 @@ vc-git-after-dir-status-stage (new-name (match-string 8))) (if new-name ; Copy or rename. (if (eq ?C (string-to-char state)) - (push (list new-name 'added - (vc-git-create-extra-fileinfo old-perm new-perm - 'copy name)) - result) - (push (list name 'removed - (vc-git-create-extra-fileinfo 0 0 - 'rename new-name)) - result) - (push (list new-name 'added - (vc-git-create-extra-fileinfo old-perm new-perm - 'rename name)) - result)) - (push (list name (vc-git--state-code state) - (vc-git-create-extra-fileinfo old-perm new-perm)) - result)))))) - (when result - (setq result (nreverse result)) - (when files - (dolist (entry result) (setq files (delete (car entry) files))) - (unless files (setq next-stage nil)))) - (when (or result (not next-stage)) - (funcall update-function result next-stage)) - (when next-stage - (vc-git-dir-status-goto-stage next-stage files update-function)))) + (vc-git-dir-status-update-file + git-state new-name 'added + (vc-git-create-extra-fileinfo old-perm new-perm + 'copy name)) + (vc-git-dir-status-update-file + git-state name 'removed + (vc-git-create-extra-fileinfo 0 0 'rename new-name)) + (vc-git-dir-status-update-file + git-state new-name 'added + (vc-git-create-extra-fileinfo old-perm new-perm + 'rename name))) + (vc-git-dir-status-update-file + git-state name (vc-git--state-code state) + (vc-git-create-extra-fileinfo old-perm new-perm))))))) + ;; If we had files but now we don't, it's time to stop. + (when (and files (not (vc-git-dir-status-state->files git-state))) + (setq next-stage nil)) + (setf (vc-git-dir-status-state->stage git-state) next-stage) + (setf (vc-git-dir-status-state->files git-state) files) + (if next-stage + (vc-git-dir-status-goto-stage git-state) + (funcall (vc-git-dir-status-state->update-function git-state) + (let ((result nil)) + (maphash (lambda (key value) + (push (cons key value) result)) + (vc-git-dir-status-state->hash git-state)) + result) + nil)))) ;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command ;; from vc-dispatcher. @@ -477,41 +511,48 @@ vc-git-after-dir-status-stage ;; Follows vc-exec-after. (declare-function vc-set-async-update "vc-dispatcher" (process-buffer)) -(defun vc-git-dir-status-goto-stage (stage files update-function) - (erase-buffer) - (pcase stage - (`update-index - (if files - (vc-git-command (current-buffer) 'async files "add" "--refresh" "--") - (vc-git-command (current-buffer) 'async nil - "update-index" "--refresh"))) - (`ls-files-added - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-c" "-s" "--")) - (`ls-files-up-to-date - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-c" "-s" "--")) - (`ls-files-unknown - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-o" "--directory" - "--no-empty-directory" "--exclude-standard" "--")) - (`ls-files-ignored - (vc-git-command (current-buffer) 'async files - "ls-files" "-z" "-o" "-i" "--directory" - "--no-empty-directory" "--exclude-standard" "--")) - ;; --relative added in Git 1.5.5. - (`diff-index - (vc-git-command (current-buffer) 'async files - "diff-index" "--relative" "-z" "-M" "HEAD" "--"))) - (vc-run-delayed - (vc-git-after-dir-status-stage stage files update-function))) +(defun vc-git-dir-status-goto-stage (git-state) + (let ((files (vc-git-dir-status-state->files git-state))) + (erase-buffer) + (pcase (vc-git-dir-status-state->stage git-state) + (`update-index + (if files + (vc-git-command (current-buffer) 'async files "add" "--refresh" "--") + (vc-git-command (current-buffer) 'async nil + "update-index" "--refresh"))) + (`ls-files-added + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-up-to-date + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-conflict + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-c" "-s" "--")) + (`ls-files-unknown + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-o" "--directory" + "--no-empty-directory" "--exclude-standard" "--")) + (`ls-files-ignored + (vc-git-command (current-buffer) 'async files + "ls-files" "-z" "-o" "-i" "--directory" + "--no-empty-directory" "--exclude-standard" "--")) + ;; --relative added in Git 1.5.5. + (`diff-index + (vc-git-command (current-buffer) 'async files + "diff-index" "--relative" "-z" "-M" "HEAD" "--"))) + (vc-run-delayed + (vc-git-after-dir-status-stage git-state)))) (defun vc-git-dir-status-files (_dir files update-function) "Return a list of (FILE STATE EXTRA) entries for DIR." ;; Further things that would have to be fixed later: ;; - how to handle unregistered directories ;; - how to support vc-dir on a subdir of the project tree - (vc-git-dir-status-goto-stage 'update-index files update-function)) + (vc-git-dir-status-goto-stage + (make-vc-git-dir-status-state :stage 'update-index + :files files + :update-function update-function))) (defvar vc-git-stash-map (let ((map (make-sparse-keymap)))
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Tue, 14 Feb 2017 14:04:02 GMT) Full text and rfc822 format available.Message #20 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Dmitry Gutov <dgutov <at> yandex.ru> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: bug#25683: semi-working patch Date: Tue, 14 Feb 2017 16:03:01 +0200
Hey Tom, On 14.02.2017 03:12, Tom Tromey wrote: > It was just a spot where I didn't properly update a call. > This version works. This is looking good (working, too). Please feel free to install. However, if you were looking for a more fundamental solution, switching to parsing the output of 'git status --porcelain' should be faster and ultimately less complex. See vc-git-conflicted-files for the first example of its usage, and https://debbugs.gnu.org/19343 for a related discussion.
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Tue, 14 Feb 2017 21:06:02 GMT) Full text and rfc822 format available.Message #23 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: Dmitry Gutov <dgutov <at> yandex.ru> Cc: Tom Tromey <tom <at> tromey.com>, 25683 <at> debbugs.gnu.org Subject: Re: bug#25683: semi-working patch Date: Tue, 14 Feb 2017 14:05:17 -0700
>>>>> "Dmitry" == Dmitry Gutov <dgutov <at> yandex.ru> writes: Dmitry> This is looking good (working, too). Please feel free to install. Thanks! Dmitry> However, if you were looking for a more fundamental solution, Dmitry> switching to parsing the output of 'git status --porcelain' should be Dmitry> faster and ultimately less complex. I had looked at this a bit but I didn't see how get the permissions info out of git status --porcelain; and then I found the bug you refer to and it seemed like it was being dealt with by someone else already; and/or maybe waiting until --porcelain was considered "old enough"? Tom
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Wed, 15 Feb 2017 00:08:02 GMT) Full text and rfc822 format available.Message #26 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Dmitry Gutov <dgutov <at> yandex.ru> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: bug#25683: semi-working patch Date: Wed, 15 Feb 2017 02:07:43 +0200
On 14.02.2017 23:05, Tom Tromey wrote: > I had looked at this a bit but I didn't see how get the permissions info > out of git status --porcelain; Good objection, and I don't know (this info might be in the porcelain=v2 format, but it was only added in Git 2.12 last year). If we could fetch that data using just one extra call, that would be great, though. > and then I found the bug you refer to and > it seemed like it was being dealt with by someone else already; Someone else is yours truly, so not sure when that happens. > and/or > maybe waiting until --porcelain was considered "old enough"? No, --porcelain is old enough, aside from the problem you mentioned. We discussed the --ignored flag which still is "too new", but that's a minor problem, only tangentially related. Anyway, thanks for the fix! --porcelain can wait some more.
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Wed, 15 Feb 2017 04:19:01 GMT) Full text and rfc822 format available.Message #29 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: Dmitry Gutov <dgutov <at> yandex.ru> Cc: Tom Tromey <tom <at> tromey.com>, 25683 <at> debbugs.gnu.org Subject: Re: bug#25683: semi-working patch Date: Tue, 14 Feb 2017 21:17:49 -0700
Dmitry> Someone else is yours truly, so not sure when that happens. Oops, sorry about that. I didn't read the bug very closely it seems... Dmitry> Anyway, thanks for the fix! --porcelain can wait some more. It's on my wish-list, but after a bunch of other things. I think I look at the per-file state very rarely if at all; whereas vc-dir is one of my main views when working on a project. Tom
Tom Tromey <tom <at> tromey.com>
:Tom Tromey <tom <at> tromey.com>
:Message #34 received at 25683-done <at> debbugs.gnu.org (full text, mbox):
From: Tom Tromey <tom <at> tromey.com> To: 25683-done <at> debbugs.gnu.org Subject: done Date: Tue, 14 Feb 2017 21:18:20 -0700
Fix checked in. Tom
bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Wed, 15 Feb 2017 13:43:02 GMT) Full text and rfc822 format available.Message #37 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Dmitry Gutov <dgutov <at> yandex.ru> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: bug#25683: semi-working patch Date: Wed, 15 Feb 2017 15:42:46 +0200
On 15.02.2017 06:17, Tom Tromey wrote: > It's on my wish-list, but after a bunch of other things. Thanks. > I think I look at the per-file state very rarely if at all; > whereas vc-dir is one of my main views when working on a project. Per-file state also affects the vc-dir view as well (that is the exact situation in bug#19343). But I was only suggesting you reimplement vc-git-dir-status-files based on 'git status --porcelain'. The fact that reusing the resulting code in vc-git-status would be very easy is just the icing. ;) Anyway, the file permissions question complicates the issue.
Debbugs Internal Request <help-debbugs <at> gnu.org>
to internal_control <at> debbugs.gnu.org
.
(Thu, 16 Mar 2017 11:24:04 GMT) Full text and rfc822 format available.Dmitry Gutov <dgutov <at> yandex.ru>
to control <at> debbugs.gnu.org
.
(Mon, 01 May 2017 14:26:01 GMT) Full text and rfc822 format available.bug-gnu-emacs <at> gnu.org
:bug#25683
; Package emacs
.
(Mon, 01 May 2017 14:34:02 GMT) Full text and rfc822 format available.Message #44 received at 25683 <at> debbugs.gnu.org (full text, mbox):
From: Dmitry Gutov <dgutov <at> yandex.ru> To: Tom Tromey <tom <at> tromey.com> Cc: 25683 <at> debbugs.gnu.org Subject: Re: bug#25683: semi-working patch Date: Mon, 1 May 2017 17:33:30 +0300
Hey Tom, On 15.02.2017 6:17, Tom Tromey wrote: > Dmitry> Anyway, thanks for the fix! --porcelain can wait some more. > > It's on my wish-list, but after a bunch of other things. > I think I look at the per-file state very rarely if at all; > whereas vc-dir is one of my main views when working on a project. 'git status --porcelain' for vc-git-state is now in. Did you have any new ideas about getting the file permissions? I have recently noticed that your patch makes vc-dir-status-files slower. E.g., in Emacs's own repository checkout, a refresh took a fraction of a second before 3fb9f5452fbd0458f90115b0a95151b8e7a482a1, and about 3 seconds now.
Debbugs Internal Request <help-debbugs <at> gnu.org>
to internal_control <at> debbugs.gnu.org
.
(Tue, 30 May 2017 11:24:05 GMT) Full text and rfc822 format available.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.