aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Tromey2017-02-13 18:09:36 -0700
committerTom Tromey2017-02-14 14:07:53 -0700
commit3fb9f5452fbd0458f90115b0a95151b8e7a482a1 (patch)
tree0821ca2fdd6fe0a65b36a35eb2f30a0a4938393b
parent71b90192dab8de9825904faaabbaf9548d3db2ab (diff)
downloademacs-3fb9f5452fbd0458f90115b0a95151b8e7a482a1.tar.gz
emacs-3fb9f5452fbd0458f90115b0a95151b8e7a482a1.zip
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.
-rw-r--r--lisp/vc/vc-git.el179
1 files changed, 110 insertions, 69 deletions
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 24dabb6f9f3..0f58892eb4e 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -401,11 +401,30 @@ or an empty string if none."
401 (vc-git-file-type-as-string old-perm new-perm) 401 (vc-git-file-type-as-string old-perm new-perm)
402 (vc-git-rename-as-string state extra)))) 402 (vc-git-rename-as-string state extra))))
403 403
404(defun vc-git-after-dir-status-stage (stage files update-function) 404(cl-defstruct (vc-git-dir-status-state
405 (:copier nil)
406 (:conc-name vc-git-dir-status-state->))
407 ;; Current stage.
408 stage
409 ;; List of files still to be processed.
410 files
411 ;; Update function to be called at the end.
412 update-function
413 ;; Hash table of entries for files we've computed so far.
414 (hash (make-hash-table :test 'equal)))
415
416(defsubst vc-git-dir-status-update-file (state filename file-state file-info)
417 (puthash filename (list file-state file-info)
418 (vc-git-dir-status-state->hash state))
419 (setf (vc-git-dir-status-state->files state)
420 (delete filename (vc-git-dir-status-state->files state))))
421
422(defun vc-git-after-dir-status-stage (git-state)
405 "Process sentinel for the various dir-status stages." 423 "Process sentinel for the various dir-status stages."
406 (let (next-stage result) 424 (let (next-stage
425 (files (vc-git-dir-status-state->files git-state)))
407 (goto-char (point-min)) 426 (goto-char (point-min))
408 (pcase stage 427 (pcase (vc-git-dir-status-state->stage git-state)
409 (`update-index 428 (`update-index
410 (setq next-stage (if (vc-git--empty-db-p) 'ls-files-added 'diff-index))) 429 (setq next-stage (if (vc-git--empty-db-p) 'ls-files-added 'diff-index)))
411 (`ls-files-added 430 (`ls-files-added
@@ -413,29 +432,40 @@ or an empty string if none."
413 (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) 432 (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t)
414 (let ((new-perm (string-to-number (match-string 1) 8)) 433 (let ((new-perm (string-to-number (match-string 1) 8))
415 (name (match-string 2))) 434 (name (match-string 2)))
416 (push (list name 'added (vc-git-create-extra-fileinfo 0 new-perm)) 435 (vc-git-dir-status-update-file
417 result)))) 436 git-state name 'added
437 (vc-git-create-extra-fileinfo 0 new-perm)))))
418 (`ls-files-up-to-date 438 (`ls-files-up-to-date
419 (setq next-stage 'ls-files-unknown) 439 (setq next-stage 'ls-files-unknown)
420 (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 0\t\\([^\0]+\\)\0" nil t) 440 (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} \\([0-3]\\)\t\\([^\0]+\\)\0" nil t)
441 (let ((perm (string-to-number (match-string 1) 8))
442 (state (match-string 2))
443 (name (match-string 3)))
444 (vc-git-dir-status-update-file
445 git-state name (if (equal state "0")
446 'up-to-date
447 'conflict)
448 (vc-git-create-extra-fileinfo perm perm)))))
449 (`ls-files-conflict
450 (setq next-stage 'ls-files-unknown)
451 ;; It's enough to look for "3" to notice a conflict.
452 (while (re-search-forward "\\([0-7]\\{6\\}\\) [0-9a-f]\\{40\\} 3\t\\([^\0]+\\)\0" nil t)
421 (let ((perm (string-to-number (match-string 1) 8)) 453 (let ((perm (string-to-number (match-string 1) 8))
422 (name (match-string 2))) 454 (name (match-string 2)))
423 (push (list name 'up-to-date 455 (vc-git-dir-status-update-file
424 (vc-git-create-extra-fileinfo perm perm)) 456 git-state name 'conflict
425 result)))) 457 (vc-git-create-extra-fileinfo perm perm)))))
426 (`ls-files-unknown 458 (`ls-files-unknown
427 (when files (setq next-stage 'ls-files-ignored)) 459 (when files (setq next-stage 'ls-files-ignored))
428 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) 460 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
429 (push (list (match-string 1) 'unregistered 461 (vc-git-dir-status-update-file git-state (match-string 1) 'unregistered
430 (vc-git-create-extra-fileinfo 0 0)) 462 (vc-git-create-extra-fileinfo 0 0))))
431 result)))
432 (`ls-files-ignored 463 (`ls-files-ignored
433 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1) 464 (while (re-search-forward "\\([^\0]*?\\)\0" nil t 1)
434 (push (list (match-string 1) 'ignored 465 (vc-git-dir-status-update-file git-state (match-string 1) 'ignored
435 (vc-git-create-extra-fileinfo 0 0)) 466 (vc-git-create-extra-fileinfo 0 0))))
436 result)))
437 (`diff-index 467 (`diff-index
438 (setq next-stage (if files 'ls-files-up-to-date 'ls-files-unknown)) 468 (setq next-stage (if files 'ls-files-up-to-date 'ls-files-conflict))
439 (while (re-search-forward 469 (while (re-search-forward
440 ":\\([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" 470 ":\\([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"
441 nil t 1) 471 nil t 1)
@@ -446,30 +476,34 @@ or an empty string if none."
446 (new-name (match-string 8))) 476 (new-name (match-string 8)))
447 (if new-name ; Copy or rename. 477 (if new-name ; Copy or rename.
448 (if (eq ?C (string-to-char state)) 478 (if (eq ?C (string-to-char state))
449 (push (list new-name 'added 479 (vc-git-dir-status-update-file
450 (vc-git-create-extra-fileinfo old-perm new-perm 480 git-state new-name 'added
451 'copy name)) 481 (vc-git-create-extra-fileinfo old-perm new-perm
452 result) 482 'copy name))
453 (push (list name 'removed 483 (vc-git-dir-status-update-file
454 (vc-git-create-extra-fileinfo 0 0 484 git-state name 'removed
455 'rename new-name)) 485 (vc-git-create-extra-fileinfo 0 0 'rename new-name))
456 result) 486 (vc-git-dir-status-update-file
457 (push (list new-name 'added 487 git-state new-name 'added
458 (vc-git-create-extra-fileinfo old-perm new-perm 488 (vc-git-create-extra-fileinfo old-perm new-perm
459 'rename name)) 489 'rename name)))
460 result)) 490 (vc-git-dir-status-update-file
461 (push (list name (vc-git--state-code state) 491 git-state name (vc-git--state-code state)
462 (vc-git-create-extra-fileinfo old-perm new-perm)) 492 (vc-git-create-extra-fileinfo old-perm new-perm)))))))
463 result)))))) 493 ;; If we had files but now we don't, it's time to stop.
464 (when result 494 (when (and files (not (vc-git-dir-status-state->files git-state)))
465 (setq result (nreverse result)) 495 (setq next-stage nil))
466 (when files 496 (setf (vc-git-dir-status-state->stage git-state) next-stage)
467 (dolist (entry result) (setq files (delete (car entry) files))) 497 (setf (vc-git-dir-status-state->files git-state) files)
468 (unless files (setq next-stage nil)))) 498 (if next-stage
469 (when (or result (not next-stage)) 499 (vc-git-dir-status-goto-stage git-state)
470 (funcall update-function result next-stage)) 500 (funcall (vc-git-dir-status-state->update-function git-state)
471 (when next-stage 501 (let ((result nil))
472 (vc-git-dir-status-goto-stage next-stage files update-function)))) 502 (maphash (lambda (key value)
503 (push (cons key value) result))
504 (vc-git-dir-status-state->hash git-state))
505 result)
506 nil))))
473 507
474;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command 508;; Follows vc-git-command (or vc-do-async-command), which uses vc-do-command
475;; from vc-dispatcher. 509;; from vc-dispatcher.
@@ -477,41 +511,48 @@ or an empty string if none."
477;; Follows vc-exec-after. 511;; Follows vc-exec-after.
478(declare-function vc-set-async-update "vc-dispatcher" (process-buffer)) 512(declare-function vc-set-async-update "vc-dispatcher" (process-buffer))
479 513
480(defun vc-git-dir-status-goto-stage (stage files update-function) 514(defun vc-git-dir-status-goto-stage (git-state)
481 (erase-buffer) 515 (let ((files (vc-git-dir-status-state->files git-state)))
482 (pcase stage 516 (erase-buffer)
483 (`update-index 517 (pcase (vc-git-dir-status-state->stage git-state)
484 (if files 518 (`update-index
485 (vc-git-command (current-buffer) 'async files "add" "--refresh" "--") 519 (if files
486 (vc-git-command (current-buffer) 'async nil 520 (vc-git-command (current-buffer) 'async files "add" "--refresh" "--")
487 "update-index" "--refresh"))) 521 (vc-git-command (current-buffer) 'async nil
488 (`ls-files-added 522 "update-index" "--refresh")))
489 (vc-git-command (current-buffer) 'async files 523 (`ls-files-added
490 "ls-files" "-z" "-c" "-s" "--")) 524 (vc-git-command (current-buffer) 'async files
491 (`ls-files-up-to-date 525 "ls-files" "-z" "-c" "-s" "--"))
492 (vc-git-command (current-buffer) 'async files 526 (`ls-files-up-to-date
493 "ls-files" "-z" "-c" "-s" "--")) 527 (vc-git-command (current-buffer) 'async files
494 (`ls-files-unknown 528 "ls-files" "-z" "-c" "-s" "--"))
495 (vc-git-command (current-buffer) 'async files 529 (`ls-files-conflict
496 "ls-files" "-z" "-o" "--directory" 530 (vc-git-command (current-buffer) 'async files
497 "--no-empty-directory" "--exclude-standard" "--")) 531 "ls-files" "-z" "-c" "-s" "--"))
498 (`ls-files-ignored 532 (`ls-files-unknown
499 (vc-git-command (current-buffer) 'async files 533 (vc-git-command (current-buffer) 'async files
500 "ls-files" "-z" "-o" "-i" "--directory" 534 "ls-files" "-z" "-o" "--directory"
501 "--no-empty-directory" "--exclude-standard" "--")) 535 "--no-empty-directory" "--exclude-standard" "--"))
502 ;; --relative added in Git 1.5.5. 536 (`ls-files-ignored
503 (`diff-index 537 (vc-git-command (current-buffer) 'async files
504 (vc-git-command (current-buffer) 'async files 538 "ls-files" "-z" "-o" "-i" "--directory"
505 "diff-index" "--relative" "-z" "-M" "HEAD" "--"))) 539 "--no-empty-directory" "--exclude-standard" "--"))
506 (vc-run-delayed 540 ;; --relative added in Git 1.5.5.
507 (vc-git-after-dir-status-stage stage files update-function))) 541 (`diff-index
542 (vc-git-command (current-buffer) 'async files
543 "diff-index" "--relative" "-z" "-M" "HEAD" "--")))
544 (vc-run-delayed
545 (vc-git-after-dir-status-stage git-state))))
508 546
509(defun vc-git-dir-status-files (_dir files update-function) 547(defun vc-git-dir-status-files (_dir files update-function)
510 "Return a list of (FILE STATE EXTRA) entries for DIR." 548 "Return a list of (FILE STATE EXTRA) entries for DIR."
511 ;; Further things that would have to be fixed later: 549 ;; Further things that would have to be fixed later:
512 ;; - how to handle unregistered directories 550 ;; - how to handle unregistered directories
513 ;; - how to support vc-dir on a subdir of the project tree 551 ;; - how to support vc-dir on a subdir of the project tree
514 (vc-git-dir-status-goto-stage 'update-index files update-function)) 552 (vc-git-dir-status-goto-stage
553 (make-vc-git-dir-status-state :stage 'update-index
554 :files files
555 :update-function update-function)))
515 556
516(defvar vc-git-stash-map 557(defvar vc-git-stash-map
517 (let ((map (make-sparse-keymap))) 558 (let ((map (make-sparse-keymap)))