Skip to content
138 changes: 76 additions & 62 deletions contrib/stgit.el
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
;;; stgit.el --- major mode for StGit interaction
;;; stgit.el --- major mode for StGit interaction -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2007-2013 David Kågedal
;;
Expand Down Expand Up @@ -58,6 +58,32 @@
(require 'ewoc)
(require 'easymenu)
(require 'format-spec)
(require 'vc)

(defvar log-edit-parent-buffer)

(defvar-local stgit-marked-patches nil
"List of marked patches.")

(defvar-local stgit-index-node nil)
(defvar-local stgit-worktree-node nil)
(defvar-local stgit-expanded-patches '(:work :index))
(defvar-local stgit-svn-find-rev-hash nil)
(defvar-local stgit-committed-count)
(defvar-local stgit-show-committed)
(defvar-local stgit-show-ignored)
(defvar-local stgit-show-patch-names)
(defvar-local stgit-show-svn)
(defvar-local stgit-show-unknown)
(defvar-local stgit-show-worktree)
(defvar-local stgit-ewoc)
(defvar-local stgit-edit-patchsym)
(defvar-local stgit-refresh-after-new)
(defvar-local stgit-refresh-after-new)
(defvar-local stgit-sink-to)
(defvar-local stgit-patchsyms)
(defvar-local old-process-sentinel)
(defvar-local stgit-buffer)

(defun stgit-set-default (symbol value)
"Set default value of SYMBOL to VALUE using `set-default' and
Expand Down Expand Up @@ -308,6 +334,15 @@ format characters are recognized:
"StGit mode face used for modified file status."
:group 'stgit-faces)

(defconst stgit-patch-status-face-alist
'((applied . stgit-applied-patch-face)
(top . stgit-top-patch-face)
(unapplied . stgit-unapplied-patch-face)
(committed . stgit-committed-patch-face)
(index . stgit-index-work-tree-title-face)
(work . stgit-index-work-tree-title-face))
"Alist of face to use for a given patch status.")

(defun stgit (dir)
"Manage StGit patches for the tree in DIR.

Expand Down Expand Up @@ -425,8 +460,8 @@ Argument DIR is the repository path."
(with-current-buffer buf
(setq default-directory dir)
(stgit-mode)
(set (make-local-variable 'stgit-ewoc)
(ewoc-create #'stgit-patch-pp "Branch:\n\n" "--\n" t))
(setq stgit-ewoc
(ewoc-create #'stgit-patch-pp "Branch:\n\n" "--\n" t))
(setq buffer-read-only t))
buf))

Expand Down Expand Up @@ -543,20 +578,18 @@ been advised to update the stgit status when necessary.")
(ewoc-invalidate (car stgit-worktree-node) (cdr stgit-worktree-node))))

(defun stgit-run-series-insert-index (ewoc)
;; TODO: non-lexical stuff happening here (`index-node' and `worktree-node').
;; Fix this before enabling lexical binding.
(setq index-node (cons ewoc (ewoc-enter-last ewoc
(make-stgit-patch
:status 'index
:name :index
:desc nil
:empty nil)))
worktree-node (cons ewoc (ewoc-enter-last ewoc
(make-stgit-patch
:status 'work
:name :work
:desc nil
:empty nil)))))
(setq stgit-index-node (cons ewoc (ewoc-enter-last ewoc
(make-stgit-patch
:status 'index
:name :index
:desc nil
:empty nil)))
stgit-worktree-node (cons ewoc (ewoc-enter-last ewoc
(make-stgit-patch
:status 'work
:name :work
:desc nil
:empty nil)))))

(defun stgit-get-position (&optional position)
"Return `stgit-mode' position information at POSITION (point by
Expand Down Expand Up @@ -672,6 +705,7 @@ using (make-hash-table :test \='equal)."
(commit-abbrev (when (string-match "%-\\([0-9]+\\)n" fmt)
(string-to-number (match-string 1 fmt))))
(exit-status (stgit-run-git-silent "--no-pager" "log"
"--no-color"
"--reverse"
"--pretty=oneline"
nentries
Expand Down Expand Up @@ -707,9 +741,7 @@ using (make-hash-table :test \='equal)."
:desc desc
:empty empty)))
(forward-line 1)))))))
(let ((inserted-index (not stgit-show-worktree))
index-node
worktree-node)
(let ((inserted-index (not stgit-show-worktree)))
(with-temp-buffer
(let* ((standard-output (current-buffer))
(exit-status (stgit-run-silent "series"
Expand All @@ -726,7 +758,7 @@ using (make-hash-table :test \='equal)."
(match-string 0))))
(while (not (eobp))
(unless (looking-at
"\\([*0 ]\\)\\([>+-]\\)\\( \\)\\([^ ]+\\) *[|#] \\(.*\\)")
"\\([*0 ]\\)\\([>+-]\\)\\( \\)\\([^ ]+\\) *[|#] ?\\(.*\\)")
(error "Syntax error in output from stg series"))
(let* ((state-str (match-string 2))
(state (cond ((string= state-str ">") 'top)
Expand All @@ -751,9 +783,7 @@ using (make-hash-table :test \='equal)."
(forward-line 1)))))
(unless inserted-index
(stgit-run-series-insert-index ewoc))
(setq stgit-index-node index-node
stgit-worktree-node worktree-node
stgit-marked-patches (cl-intersection stgit-marked-patches
(setq stgit-marked-patches (cl-intersection stgit-marked-patches
all-patchsyms)))))

(defun stgit-current-branch ()
Expand Down Expand Up @@ -802,15 +832,6 @@ during the operation."
(ignore "Ignored" stgit-ignored-file-face)))
"Alist of code symbols to description strings.")

(defconst stgit-patch-status-face-alist
'((applied . stgit-applied-patch-face)
(top . stgit-top-patch-face)
(unapplied . stgit-unapplied-patch-face)
(committed . stgit-committed-patch-face)
(index . stgit-index-work-tree-title-face)
(work . stgit-index-work-tree-title-face))
"Alist of face to use for a given patch status.")

(defun stgit-file-status-code-as-string (file)
"Return stgit status code for FILE as a string."
(let* ((code (assq (stgit-file->status file)
Expand Down Expand Up @@ -1007,7 +1028,7 @@ If NO-QUOTES is non-nil, do not enclose the result in double quotes."
(insert ":0 0 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 " file-flag "\0")
(forward-char name-len)))))

(defun stgit-process-files (callback)
(defun stgit-process-files (patch callback)
(goto-char (point-min))
(when (looking-at "[0-9A-Fa-f]\\{40\\}\0")
(goto-char (match-end 0)))
Expand All @@ -1018,7 +1039,6 @@ If NO-QUOTES is non-nil, do not enclose the result in double quotes."
(let ((file
(cond ((looking-at
"\\([CR]\\)\\([0-9]*\\)\0\\([^\0]*\\)\0\\([^\0]*\\)\0")
;; TODO: Where does `patch' come from?
(let* ((patch-status (stgit-patch->status patch))
(file-subexp (if (eq patch-status 'unapplied)
3
Expand Down Expand Up @@ -1082,7 +1102,7 @@ at point."
(sort-regexp-fields nil ":[^\0]*\0\\([^\0]*\\)\0" "\\1"
(point-min) (point-max)))

(stgit-process-files (lambda (file) (ewoc-enter-last ewoc file)))
(stgit-process-files patch (lambda (file) (ewoc-enter-last ewoc file)))

(unless (ewoc-nth ewoc 0)
(ewoc-set-hf ewoc ""
Expand Down Expand Up @@ -1110,7 +1130,7 @@ at point."
'switch-to-buffer-other-window
'switch-to-buffer)
(find-file-noselect filename))
(set (make-local-variable 'vc-parent-buffer) filename)))
(setq vc-parent-buffer filename)))

(defun stgit-find-file (&optional other-window this-rev)
(let* ((file (or (stgit-patched-file-at-point)
Expand Down Expand Up @@ -1192,7 +1212,8 @@ See also `stgit-expand'."
"--no-empty-directory" "--"
filename)
"X")
(stgit-process-files (lambda (f)
(stgit-process-files patch
(lambda (f)
(setq node (ewoc-enter-after ewoc node f))))))

(move-to-column (stgit-goal-column))
Expand Down Expand Up @@ -1683,21 +1704,16 @@ See also \\[customize-group] for the \"stgit\" group."
major-mode 'stgit-mode
goal-column 2)
(use-local-map stgit-mode-map)
(mapc (lambda (x) (set (make-local-variable (car x)) (cdr x)))
`((list-buffers-directory . ,default-directory)
(parse-sexp-lookup-properties . t)
(stgit-expanded-patches . (:work :index))
(stgit-index-node . nil)
(stgit-worktree-node . nil)
(stgit-marked-patches . nil)
(stgit-svn-find-rev-hash . ,(make-hash-table :test 'equal))
(stgit-committed-count . ,stgit-default-committed-count)
(stgit-show-committed . ,stgit-default-show-committed)
(stgit-show-ignored . ,stgit-default-show-ignored)
(stgit-show-patch-names . ,stgit-default-show-patch-names)
(stgit-show-svn . ,stgit-default-show-svn)
(stgit-show-unknown . ,stgit-default-show-unknown)
(stgit-show-worktree . ,stgit-default-show-worktree)))
(setq list-buffers-directory default-directory)
(setq-local parse-sexp-lookup-properties t)
(setq stgit-svn-find-rev-hash (make-hash-table :test 'equal))
(setq stgit-committed-count stgit-default-committed-count)
(setq stgit-show-committed stgit-default-show-committed)
(setq stgit-show-ignored stgit-default-show-ignored)
(setq stgit-show-patch-names stgit-default-show-patch-names)
(setq stgit-show-svn stgit-default-show-svn)
(setq stgit-show-unknown stgit-default-show-unknown)
(setq stgit-show-worktree stgit-default-show-worktree)
(set-variable 'truncate-lines 't)
(add-hook 'after-save-hook 'stgit-update-stgit-for-buffer)
(unless stgit-did-advise
Expand Down Expand Up @@ -2427,7 +2443,7 @@ which stage to diff against in the case of unmerged files."
(if (eq patch-id :index)
'("--cached")
(list unmerged-stage))))
(let ((args (append '("show" "-O" "--patch-with-stat")
(let ((args (append '("show" "--color=never" "-O" "--patch-with-stat")
`("-O" ,(stgit-find-copies-harder-diff-arg))
(and space-arg (list "-O" space-arg))
(list (stgit-patch-name-at-point)))))
Expand Down Expand Up @@ -2604,7 +2620,7 @@ file ended up. You can then jump to the file with \
(edit-buf (get-buffer-create "*StGit edit*"))
(dir default-directory))
(log-edit 'stgit-confirm-edit t nil edit-buf)
(set (make-local-variable 'stgit-edit-patchsym) patchsym)
(setq stgit-edit-patchsym patchsym)
(setq default-directory dir)
(let ((standard-output edit-buf))
(save-excursion
Expand Down Expand Up @@ -2660,8 +2676,8 @@ that name (a symbol)."
(dir default-directory))
(log-edit 'stgit-confirm-new t nil edit-buf)
(setq default-directory dir)
(set (make-local-variable 'stgit-refresh-after-new) refresh)
(set (make-local-variable 'stgit-sink-to) sink-to)
(setq stgit-refresh-after-new refresh)
(setq stgit-sink-to sink-to)
(when add-sign
(save-excursion
(let ((standard-output (current-buffer)))
Expand Down Expand Up @@ -2835,7 +2851,7 @@ deepest patch had before the squash."
(dir default-directory)
(sorted-patchsyms (stgit-sort-patches patchsyms)))
(log-edit 'stgit-confirm-squash t nil edit-buf)
(set (make-local-variable 'stgit-patchsyms) sorted-patchsyms)
(setq stgit-patchsyms sorted-patchsyms)
(setq default-directory dir)
(let ((result (let ((standard-output edit-buf))
(save-excursion
Expand Down Expand Up @@ -2939,10 +2955,8 @@ When the command has finished, reload the stgit buffer."
(let ((old-buffer (current-buffer)))
(with-current-buffer buffer
(let ((process (get-buffer-process buffer)))
(set (make-local-variable 'old-process-sentinel)
(process-sentinel process))
(set (make-local-variable 'stgit-buffer)
old-buffer)
(setq old-process-sentinel (process-sentinel process))
(setq stgit-buffer old-buffer)
(set-process-filter process 'stgit-execute-process-filter)
(set-process-sentinel process 'stgit-execute-process-sentinel))))
(with-current-buffer buffer
Expand Down
Loading