| @@ -2263,12 +2263,6 @@ use for the buffer. It defaults to \"*recetf-show*\"." | |||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; git walktree | ;; git walktree | ||||
| ;; TODO: Fix variable names | |||||
| ;; commit-sha1 for commit sha1 (allow abbreviated) | |||||
| ;; commit-full-sha1 for commit sha1 in 40 chars | |||||
| ;; object-full-sha1 for object sha1 in 40 chars | |||||
| ;; Do not use something like "-id" in name | |||||
| (defgroup git-walktree nil | (defgroup git-walktree nil | ||||
| "Git Walktree." | "Git Walktree." | ||||
| :tag "GitWalktree" | :tag "GitWalktree" | ||||
| @@ -2288,9 +2282,8 @@ This path is always relative to repository root.") | |||||
| "Psudo filename of current buffer.") | "Psudo filename of current buffer.") | ||||
| (make-variable-buffer-local 'git-walktree-buffer-file-name) | (make-variable-buffer-local 'git-walktree-buffer-file-name) | ||||
| ;; TODO: -> object-full-sha1 | |||||
| (defvar git-walktree-object-full-sha1 nil | (defvar git-walktree-object-full-sha1 nil | ||||
| "Object id of current buffer.") | |||||
| "Object name in full sha1 format of current buffer.") | |||||
| (make-variable-buffer-local 'git-walktree-object-full-sha1) | (make-variable-buffer-local 'git-walktree-object-full-sha1) | ||||
| (defvar git-walktree-repository-root nil | (defvar git-walktree-repository-root nil | ||||
| @@ -2325,7 +2318,7 @@ TYPE is target object type." | |||||
| (string= type "tree")) | (string= type "tree")) | ||||
| (with-current-buffer (or git-walktree-tree-buffer-for-reuse | (with-current-buffer (or git-walktree-tree-buffer-for-reuse | ||||
| (setq git-walktree-tree-buffer-for-reuse | (setq git-walktree-tree-buffer-for-reuse | ||||
| (get-buffer-create "*gitwalktree*"))) | |||||
| (generate-new-buffer "gitwalktreebuf"))) | |||||
| (setq git-walktree-repository-root root) | (setq git-walktree-repository-root root) | ||||
| (rename-buffer name t) | (rename-buffer name t) | ||||
| (current-buffer)) | (current-buffer)) | ||||
| @@ -2349,6 +2342,7 @@ It also copy text overlays." | |||||
| (with-current-buffer target | (with-current-buffer target | ||||
| (replace-buffer-contents src))) | (replace-buffer-contents src))) | ||||
| ;; Copy color overlays | |||||
| (let ((overlays (overlays-in (point-min) (point-max)))) | (let ((overlays (overlays-in (point-min) (point-max)))) | ||||
| (dolist (o overlays) | (dolist (o overlays) | ||||
| (let ((beg (overlay-start o)) | (let ((beg (overlay-start o)) | ||||
| @@ -2360,7 +2354,9 @@ It also copy text overlays." | |||||
| (require 'ansi-color) | (require 'ansi-color) | ||||
| (defun git-walktree--open-treeish (committish path treeish) | (defun git-walktree--open-treeish (committish path treeish) | ||||
| "Open git tree buffer of TREEISH." | |||||
| "Open git tree buffer of COMMITISH:PATH. | |||||
| TREEISH should be a tree-ish object full-sha1 of COMMITISH:PATH." | |||||
| (cl-assert path) | (cl-assert path) | ||||
| (cl-assert treeish) | (cl-assert treeish) | ||||
| (let* (point-tree-start | (let* (point-tree-start | ||||
| @@ -2374,10 +2370,10 @@ It also copy text overlays." | |||||
| (with-current-buffer buf | (with-current-buffer buf | ||||
| (unless (and (string= treeish | (unless (and (string= treeish | ||||
| git-walktree-object-full-sha1) | git-walktree-object-full-sha1) | ||||
| (or (string= committish | |||||
| git-walktree-current-committish) | |||||
| (eq committish | |||||
| git-walktree-current-committish))) | |||||
| (or (eq committish | |||||
| git-walktree-current-committish) | |||||
| (string= committish | |||||
| git-walktree-current-committish))) | |||||
| (buffer-disable-undo) | (buffer-disable-undo) | ||||
| ;; For running git command go back to repository root | ;; For running git command go back to repository root | ||||
| (cd git-walktree-repository-root) | (cd git-walktree-repository-root) | ||||
| @@ -2425,7 +2421,7 @@ It also copy text overlays." | |||||
| (cd dir))) | (cd dir))) | ||||
| (when (= (point) (point-min)) | (when (= (point) (point-min)) | ||||
| (goto-char point-tree-start) | (goto-char point-tree-start) | ||||
| (git-walktree-mode--goto-file) | |||||
| (git-walktree-mode--move-to-file) | |||||
| ) | ) | ||||
| )) | )) | ||||
| buf)) | buf)) | ||||
| @@ -2446,7 +2442,8 @@ Result will be inserted into current buffer." | |||||
| args)))) | args)))) | ||||
| ?w | ?w | ||||
| (defun git-walktree--open-blob (committish path blob) | (defun git-walktree--open-blob (committish path blob) | ||||
| "Open BLOB object." | |||||
| "Open blob object of COMMITISH:PATH. | |||||
| BLOB should be a object full sha1 of COMMITISH:PATH." | |||||
| (cl-assert committish) | (cl-assert committish) | ||||
| (cl-assert path) | (cl-assert path) | ||||
| (cl-assert blob) | (cl-assert blob) | ||||
| @@ -2505,8 +2502,8 @@ When PATH is omitted or nil, it is calculated from current file or directory." | |||||
| (git-walktree--path-in-repository (or buffer-file-name | (git-walktree--path-in-repository (or buffer-file-name | ||||
| default-directory)))) | default-directory)))) | ||||
| ;; PATH must not start with and end with slashes | ;; PATH must not start with and end with slashes | ||||
| (cl-assert (not (string-match "\\`/" path))) | |||||
| (cl-assert (not (string-match "/\\'" path))) | |||||
| (cl-assert (not (string-match-p "\\`/" path))) | |||||
| (cl-assert (not (string-match-p "/\\'" path))) | |||||
| (let ((obj (git-walktree--resolve-object committish path))) | (let ((obj (git-walktree--resolve-object committish path))) | ||||
| (while (not obj) | (while (not obj) | ||||
| @@ -2520,9 +2517,9 @@ When PATH is omitted or nil, it is calculated from current file or directory." | |||||
| ;; TODO: Store view history | ;; TODO: Store view history | ||||
| (defun git-walktree--open-noselect (committish path object) | (defun git-walktree--open-noselect (committish path object) | ||||
| "Open git tree buffer of COMMITTISH. | |||||
| "Open buffer to view git object of COMMITTISH:PATH. | |||||
| When PATH was given and non-nil open that, otherwise open root tree. | When PATH was given and non-nil open that, otherwise open root tree. | ||||
| When OBJECT was given and non-nil, assume that is the full sha1 object id of | |||||
| When OBJECT was given and non-nil, assume that is the object full sha1 of | |||||
| COMMITTISH:PATH without checking it." | COMMITTISH:PATH without checking it." | ||||
| (cl-assert committish) | (cl-assert committish) | ||||
| (let ((type (git-walktree--git-plumbing "cat-file" | (let ((type (git-walktree--git-plumbing "cat-file" | ||||
| @@ -2533,8 +2530,8 @@ COMMITTISH:PATH without checking it." | |||||
| (setq path (or path | (setq path (or path | ||||
| ".")) | ".")) | ||||
| ;; PATH must not start with and end with slashes | ;; PATH must not start with and end with slashes | ||||
| (cl-assert (not (string-match "\\`/" path))) | |||||
| (cl-assert (not (string-match "/\\'" path))) | |||||
| (cl-assert (not (string-match-p "\\`/" path))) | |||||
| (cl-assert (not (string-match-p "/\\'" path))) | |||||
| (setq object (or object | (setq object (or object | ||||
| (git-walktree--resolve-object committish path))) | (git-walktree--resolve-object committish path))) | ||||
| @@ -2554,11 +2551,13 @@ COMMITTISH:PATH without checking it." | |||||
| (error "Type cannot handle: %s" type))))) | (error "Type cannot handle: %s" type))))) | ||||
| (defun git-walktree--resolve-object (committish path) | (defun git-walktree--resolve-object (committish path) | ||||
| "Return object id of COMMITISIH:PATH. | |||||
| If path is equal to \".\" return COMMITTISH's tree object | |||||
| "Return object full sha1 name of COMMITISIH:PATH. | |||||
| If path is equal to \".\" return COMMITTISH's root tree object. | |||||
| PATH will be always treated as relative to repository root." | PATH will be always treated as relative to repository root." | ||||
| (cl-assert committish) | (cl-assert committish) | ||||
| (cl-assert path) | (cl-assert path) | ||||
| (cl-assert (not (string-match-p "\\`/" path))) | |||||
| (cl-assert (not (string-match-p "/\\'" path))) | |||||
| (if (string= path ".") | (if (string= path ".") | ||||
| (git-walktree--git-plumbing "show" | (git-walktree--git-plumbing "show" | ||||
| "--no-patch" | "--no-patch" | ||||
| @@ -2570,13 +2569,12 @@ PATH will be always treated as relative to repository root." | |||||
| path)))) | path)))) | ||||
| (plist-get info :object)))) | (plist-get info :object)))) | ||||
| (defun git-walktree-open (committish &optional path object) | |||||
| (defun git-walktree-open (committish &optional path) | |||||
| "Open git tree buffer of COMMITTISH. | "Open git tree buffer of COMMITTISH. | ||||
| When PATH was given and non-nil open that, otherwise open root tree. | |||||
| When OBJECT was given and non-nil, assume that is the object of COMMITTISH:PATH without | |||||
| checking it." | |||||
| When PATH was given and non-nil open that, otherwise try to open current path. | |||||
| If target path is not found in COMMITISH tree, go up path and try again until found." | |||||
| (interactive (list (magit-read-branch-or-commit "Revision: "))) | (interactive (list (magit-read-branch-or-commit "Revision: "))) | ||||
| (switch-to-buffer (git-walktree--open-noselect committish path object))) | |||||
| (switch-to-buffer (git-walktree--open-noselect-safe-path committish path))) | |||||
| (defalias 'git-walktree 'git-walktree-open) | (defalias 'git-walktree 'git-walktree-open) | ||||
| (defun git-walktree--path-in-repository (path) | (defun git-walktree--path-in-repository (path) | ||||
| @@ -2596,7 +2594,7 @@ checking it." | |||||
| (defcustom git-walktree-try-cd t | (defcustom git-walktree-try-cd t | ||||
| "Try to cd if directory exists in current working directory if non-nil. | "Try to cd if directory exists in current working directory if non-nil. | ||||
| Otherwise buffer's `default-directory' is always repository root." | |||||
| Otherwise use repository root for gitwalktree buffer's `default-directory'." | |||||
| :type 'boolean | :type 'boolean | ||||
| :group 'git-walktree) | :group 'git-walktree) | ||||
| @@ -2605,10 +2603,8 @@ Otherwise buffer's `default-directory' is always repository root." | |||||
| :type 'boolean | :type 'boolean | ||||
| :group 'git-walktree) | :group 'git-walktree) | ||||
| (defcustom git-walktree-tree-buffer-for-reuse nil | |||||
| "Buffer to use when `git-walktree-reuse-tree-buffer' is non-nil." | |||||
| :type 'string | |||||
| :group 'git-walktree) | |||||
| (defvar git-walktree-tree-buffer-for-reuse nil | |||||
| "Buffer to use when `git-walktree-reuse-tree-buffer' is non-nil.") | |||||
| (defun git-walktree--git-plumbing (&rest args) | (defun git-walktree--git-plumbing (&rest args) | ||||
| "Run git plubming command with ARGS. | "Run git plubming command with ARGS. | ||||
| @@ -2630,6 +2626,7 @@ Returns first line of output without newline." | |||||
| (progn | (progn | ||||
| (goto-char (point-min)) | (goto-char (point-min)) | ||||
| (point-at-eol)))))) | (point-at-eol)))))) | ||||
| (defconst git-walktree-ls-tree-line-regexp | (defconst git-walktree-ls-tree-line-regexp | ||||
| "^\\([0-9]\\{6\\}\\) \\(\\w+\\) \\([0-9a-f]+\\)\t\\(.*\\)$" | "^\\([0-9]\\{6\\}\\) \\(\\w+\\) \\([0-9a-f]+\\)\t\\(.*\\)$" | ||||
| "Regexp for one line of output of git ls-tree.") | "Regexp for one line of output of git ls-tree.") | ||||
| @@ -2661,7 +2658,7 @@ Returns property list like (:mode MODE :type TYPE :object OBJECT :file FILE)." | |||||
| :file (match-string 4))))))) | :file (match-string 4))))))) | ||||
| (defun git-walktree-mode-open-this () | (defun git-walktree-mode-open-this () | ||||
| "Open current object." | |||||
| "Open git object of current line." | |||||
| (interactive) | (interactive) | ||||
| (let ((info (git-walktree--parse-lstree-line (buffer-substring-no-properties (point-at-bol) | (let ((info (git-walktree--parse-lstree-line (buffer-substring-no-properties (point-at-bol) | ||||
| (point-at-eol))))) | (point-at-eol))))) | ||||
| @@ -2721,8 +2718,7 @@ If not given, value of current buffer will be used." | |||||
| nil)) | nil)) | ||||
| (message "Cannot find parent directory for current tree.")))) | (message "Cannot find parent directory for current tree.")))) | ||||
| ;; TODO: -> -move-to | |||||
| (defun git-walktree-mode--goto-file () | |||||
| (defun git-walktree-mode--move-to-file () | |||||
| "Move point to file field of ls-tree output in current line. | "Move point to file field of ls-tree output in current line. | ||||
| This function do nothing when current line is not ls-tree output." | This function do nothing when current line is not ls-tree output." | ||||
| @@ -2739,7 +2735,7 @@ This function do nothing when current line is not ls-tree output." | |||||
| (interactive "^p\np") | (interactive "^p\np") | ||||
| (or arg (setq arg 1)) | (or arg (setq arg 1)) | ||||
| (line-move arg nil nil try-vscroll) | (line-move arg nil nil try-vscroll) | ||||
| (git-walktree-mode--goto-file) | |||||
| (git-walktree-mode--move-to-file) | |||||
| ) | ) | ||||
| (defun git-walktree-mode-previous-line (&optional arg try-vscroll) | (defun git-walktree-mode-previous-line (&optional arg try-vscroll) | ||||
| @@ -2747,7 +2743,7 @@ This function do nothing when current line is not ls-tree output." | |||||
| (interactive "^p\np") | (interactive "^p\np") | ||||
| (or arg (setq arg 1)) | (or arg (setq arg 1)) | ||||
| (line-move (- arg) nil nil try-vscroll) | (line-move (- arg) nil nil try-vscroll) | ||||
| (git-walktree-mode--goto-file) | |||||
| (git-walktree-mode--move-to-file) | |||||
| ) | ) | ||||
| (defgroup git-walktree-faces nil | (defgroup git-walktree-faces nil | ||||
| @@ -2767,11 +2763,12 @@ This function do nothing when current line is not ls-tree output." | |||||
| :group 'git-walktree-faces) | :group 'git-walktree-faces) | ||||
| (defvar git-walktree-known-child-revisions (make-hash-table :test 'equal) | (defvar git-walktree-known-child-revisions (make-hash-table :test 'equal) | ||||
| "Hash of already known pair of commitid -> list of child commitid.") | |||||
| "Hash of already known pair of commitid -> list of child commitid. | |||||
| Both values should be object full sha1 names.") | |||||
| (defun git-walktree--put-child (parent child) | (defun git-walktree--put-child (parent child) | ||||
| "Register PARENT and CHILD relationship. | "Register PARENT and CHILD relationship. | ||||
| PARENT should be a full SHA-1 object name." | |||||
| PARENT should be a full sha1 object name." | |||||
| ;; Any way to check if PARENT is a full SHA-1 object name? | ;; Any way to check if PARENT is a full SHA-1 object name? | ||||
| (let ((current (gethash parent git-walktree-known-child-revisions))) | (let ((current (gethash parent git-walktree-known-child-revisions))) | ||||
| (unless (member child current) | (unless (member child current) | ||||
| @@ -2781,12 +2778,12 @@ PARENT should be a full SHA-1 object name." | |||||
| git-walktree-known-child-revisions)))) | git-walktree-known-child-revisions)))) | ||||
| ;; TODO: Add aggressive search mode | ;; TODO: Add aggressive search mode | ||||
| ;; https://stackoverflow.com/a/9870218 | |||||
| ;; git log --reverse --pretty=format:%H -n 1 --ancestry-path <PARENT>..HEAD | |||||
| (defun git-walktree--get-children (parent) | (defun git-walktree--get-children (parent) | ||||
| "Get known children list of PARENT commit. | "Get known children list of PARENT commit. | ||||
| PARENT should be a full SHA-1 object name." | |||||
| PARENT should be a full sha1 object name." | |||||
| (gethash parent git-walktree-known-child-revisions)) | (gethash parent git-walktree-known-child-revisions)) | ||||
| ;; https://stackoverflow.com/a/9870218 | |||||
| ;; git log --reverse --pretty=format:%H -n 1 --ancestry-path <PARENT>..HEAD | |||||
| (defun git-walktree--choose-committish (prompt-format collection) | (defun git-walktree--choose-committish (prompt-format collection) | ||||
| "Emit PROMPT-FORMAT and ask user to which committish of COLLECTION to use. | "Emit PROMPT-FORMAT and ask user to which committish of COLLECTION to use. | ||||
| @@ -2807,12 +2804,12 @@ When collection has just one element, return the first element without asking." | |||||
| If current path was not found in the parent revision try to go up path." | If current path was not found in the parent revision try to go up path." | ||||
| (interactive) | (interactive) | ||||
| (cl-assert git-walktree-current-committish) | (cl-assert git-walktree-current-committish) | ||||
| (let* ((commitid (git-walktree--git-plumbing "rev-parse" | |||||
| git-walktree-current-committish)) | |||||
| (parents (git-walktree--parent-commitid commitid))) | |||||
| (let* ((commit-full-sha1 (git-walktree--git-plumbing "rev-parse" | |||||
| git-walktree-current-committish)) | |||||
| (parents (git-walktree--parent-full-sha1 commit-full-sha1))) | |||||
| (dolist (parent parents) | (dolist (parent parents) | ||||
| (git-walktree--put-child parent | (git-walktree--put-child parent | ||||
| commitid)) | |||||
| commit-full-sha1)) | |||||
| (if (< (length parents) | (if (< (length parents) | ||||
| 1) | 1) | ||||
| (message "This revision has no parent revision") | (message "This revision has no parent revision") | ||||
| @@ -2823,7 +2820,7 @@ If current path was not found in the parent revision try to go up path." | |||||
| (switch-to-buffer (git-walktree--open-noselect-safe-path parent | (switch-to-buffer (git-walktree--open-noselect-safe-path parent | ||||
| path)))))) | path)))))) | ||||
| (defun git-walktree--parent-commitid (committish) | |||||
| (defun git-walktree--parent-full-sha1 (committish) | |||||
| "Return list of parent commits of COMMITTISH in sha1 string." | "Return list of parent commits of COMMITTISH in sha1 string." | ||||
| (let ((type (git-walktree--git-plumbing "cat-file" | (let ((type (git-walktree--git-plumbing "cat-file" | ||||
| "-t" | "-t" | ||||
| @@ -2834,15 +2831,13 @@ If current path was not found in the parent revision try to go up path." | |||||
| "--pretty=format:%P" | "--pretty=format:%P" | ||||
| committish))) | committish))) | ||||
| (split-string parents))) | (split-string parents))) | ||||
| ;; (git-walktree--parent-sha1 "HEAD") | |||||
| ;; (git-walktree--parent-sha1 "ae4b80f") | |||||
| (defun git-walktree-known-child-revision () | (defun git-walktree-known-child-revision () | ||||
| "Open known revision of current path." | "Open known revision of current path." | ||||
| (interactive) | (interactive) | ||||
| (let* ((commitid (git-walktree--git-plumbing "rev-parse" | |||||
| git-walktree-current-committish)) | |||||
| (children (git-walktree--get-children commitid))) | |||||
| (let* ((commit-full-sha1 (git-walktree--git-plumbing "rev-parse" | |||||
| git-walktree-current-committish)) | |||||
| (children (git-walktree--get-children commit-full-sha1))) | |||||
| (if (< (length children) | (if (< (length children) | ||||
| 1) | 1) | ||||
| (message "There are no known child revision") | (message "There are no known child revision") | ||||