/ resources / test-diff-git.output
test-diff-git.output
  1  diff --git a/README.org b/README.org
  2  new file mode 100644
  3  index 0000000000..41babfe10a
  4  --- /dev/null
  5  +++ b/README.org
  6  @@ -1,0 +1,32 @@
  7  +#+title: Areas to work on
  8  +
  9  +* Status
 10  +** A/M/D file overview
 11  +** Diffs
 12  +*** Side-By-Side Diff
 13  +**** split based on git and then reconstitute with overlays
 14  +**** investigate overlays or how magit did it
 15  +*** Segments
 16  +**** within the same file the different segments
 17  +*** squash action acting only on currently selected segment/file
 18  +** Shortlog equivalent
 19  +*** make configurable
 20  +** Overview (Two liner)
 21  +*** conflict marker missing
 22  +* Log
 23  +** Operation Log
 24  +** Obslog
 25  +** Commit Log
 26  +* Actions
 27  +** Squash -i
 28  +*** figure out how to call emacs after jj prepares temporary directory
 29  +**** uses ui.diff-editor even for squash
 30  +**** by default everything is selected for squash, revert needed
 31  +** Diff
 32  +***
 33  +* Minibuffer integration
 34  +** parent change > change > description
 35  +** also show change id after each save?
 36  +* Multiple workflow
 37  +** Squash workflow
 38  +** Split workflow
 39  diff --git a/jujutsu.el b/jujutsu.el
 40  index 5b32d77748...1aa38bdebf 100644
 41  --- a/jujutsu.el
 42  +++ b/jujutsu.el
 43  @@ -26,6 +26,11 @@
 44     "Face used for Jujutsu commit descriptions."
 45     :group 'jujutsu)
 46  
 47  +(defcustom jujutsu-log-revset-fallback "@ | ancestors(immutable_heads().., 2) | trunk()"
 48  +  "Default value when no revset is specified."
 49  +  :group 'jujutsu
 50  +  :type 'string)
 51  +
 52   (defun jj--find-project-root ()
 53     "Find the root directory of the Jujutsu project."
 54     (locate-dominating-file default-directory ".jj"))
 55  @@ -56,15 +61,17 @@
 56                               rev)))
 57       (jj--run-command formatted)))
 58  
 59  -(defun jj--log-w/template (template)
 60  -    "Run `jj log' command with a custom TEMPLATE.
 61  +(defun jj--log-w/template (template &optional revset)
 62  +  "Run `jj log' command with a custom TEMPLATE and optional REVSET.
 63  
 64   TEMPLATE is a string containing the custom template for the `jj log' command.
 65  
 66   This function constructs and executes a `jj log' command with the given
 67   template, disabling graph output and adding newlines between entries. It returns
 68   the command's output as a string, with each log entry separated by newlines."
 69  -  (let* ((formatted (format "log --no-graph --template \"%s ++ \\\"\\n\\n\\\"\""
 70  +  (let* ((revset (or revset jujutsu-log-revset-fallback))
 71  +         (formatted (format "log --revisions \"%s\" --no-graph --template \"%s ++ \\\"\\n\\n\\\"\""
 72  +                            revset
 73                               template)))
 74       (jj--run-command formatted)))
 75  
 76  @@ -75,7 +82,7 @@
 77          (s-split "\n" it t)))
 78  
 79   (defun jj--map-to-escaped-string (map)
 80  -  "Convert MAP (hash-table) to an escaped string."
 81  +  "Convert MAP (hash-table) to an escaped string for use as a jj template."
 82     (->> map
 83          (ht-map (lambda (key value)
 84                    (format "\\\"%s \\\" ++ %s ++ \\\"\\\\n\\\""
 85  @@ -83,14 +90,14 @@
 86          (s-join " ++ ")))
 87  
 88   (defun jj--parse-file-change (line)
 89  -  "Parse a file change LINE into a cons of (type . filename)."
 90  +  "Parse a file change LINE into a hash-table."
 91     (-let* [(regex (rx bos (group (any "AMD")) " " (group (+ not-newline)) eos) line)
 92             ((res m1 m2) (s-match regex line))]
 93       (when res
 94         (ht (m1 m2)))))
 95  
 96   (defun jj--parse-key-value (line)
 97  -  "Parse a KEY-VALUE LINE into a cons of (key . value)."
 98  +  "Parse a KEY-VALUE LINE into a hash-table."
 99     (unless (s-matches? (rx bos (any "AMD") " ") line)
100       (-when-let* [(regex (rx bos
101                               (group (+ (not (any " ")))) ; key
102  @@ -101,7 +108,7 @@
103         (ht ((intern m1) m2)))))
104  
105   (defun jj--parse-and-group-file-changes (file-changes)
106  -  "Parse and group FILE-CHANGES by their change type."
107  +  "Parse and group FILE-CHANGES by their change type into a hash-table."
108     (let ((grouped-changes (ht ('files-added nil)
109                                ('files-modified nil)
110                                ('files-deleted nil))))
111  @@ -115,7 +122,7 @@
112       grouped-changes))
113  
114   (defun jj--parse-string-to-map (input-string)
115  -  "Parse INPUT-STRING into a map and an organized list of file change."
116  +  "Parse INPUT-STRING into a hash-table and an organized list of file change."
117     (let* ((lines (s-split "\n" input-string t))
118            (file-change-lines (-filter #'jj--parse-file-change lines))
119            (grouped-file-changes (jj--parse-and-group-file-changes file-change-lines))
120  @@ -139,11 +146,34 @@
121                         ('commit-id-shortest "commit_id.shortest()")
122                         ('empty "empty")
123                         ('branches "branches")
124  +                      ('git-head "git_head")
125                         ('description "description"))))
126       (-> (jj--map-to-escaped-string template)
127           (jj--show-w/template rev)
128           jj--parse-string-to-map)))
129  
130  +(defun jj--get-log-data (&optional revset)
131  +  "Get status data for the given REVSET."
132  +  (let ((revset (or revset jujutsu-log-revset-fallback))
133  +        (template (ht ('change-id-short "change_id.short(8)")
134  +                      ('change-id-shortest "change_id.shortest()")
135  +                      ('commit-id-short "commit_id.short(8)")
136  +                      ('commit-id-shortest "commit_id.shortest()")
137  +                      ('empty "empty")
138  +                      ('branches "branches")
139  +                      ('hidden "hidden")
140  +                      ('author-email "author.email()")
141  +                      ('timestamp "author.timestamp().format(\\\"%Y-%m-%d %H:%M:%S\\\")")
142  +                      ('current-working-copy "current_working_copy")
143  +                      ('remote-branches "remote_branches")
144  +                      ('git-head "git_head")
145  +                      ('root "root")
146  +                      ('description "description"))))
147  +    (--> (jj--map-to-escaped-string template)
148  +        (jj--log-w/template it revset)
149  +        (jj--split-string-on-empty-lines it)
150  +        (-map #'jj--parse-string-to-map it))))
151  +
152   (defun jj--format-id (id-short id-shortest)
153     "Format ID-SHORT with ID-SHORTEST distinguished."
154     (let* ((shortest-length (length id-shortest))
155  @@ -177,6 +207,88 @@
156                     (propertize "(no description set)" 'face 'warning)))]
157       (format "%s %s %s%s%s" change-id commit-id branches empty desc)))
158  
159  +(defun jj--format-log-line (data)
160  +  "Format a status line using DATA with fontification."
161  +  (-let* [((&hash 'change-id-short chids 'change-id-shortest chidss
162  +                  'commit-id-short coids 'commit-id-shortest coidss
163  +                  'branches branches 'empty empty 'description desc
164  +                  'root root 'author-email author-email
165  +                  'timestamp timestamp
166  +                  'current-working-copy cwc)
167  +           data)
168  +          (cwc (if (s-equals? cwc "true") "@" "◉"))
169  +          (author-email (if author-email
170  +                            (propertize author-email 'face 'warning)
171  +                          ""))
172  +          (root (if (s-equals? root "true") t nil))
173  +          (empty (if (s-equals? empty "true")
174  +                     (propertize "(empty) " 'face 'warning)
175  +                   ""))
176  +          (timestamp (if timestamp (propertize timestamp 'face 'magit-log-date)
177  +                       ""))
178  +          (branches (if branches
179  +                        (s-concat (propertize branches 'face 'magit-branch-local) " ")
180  +                      ""))
181  +          (change-id (jj--format-id chids chidss))
182  +          (commit-id (jj--format-id coids coidss))
183  +          (desc (if desc
184  +                    (propertize desc 'face 'jujutsu-description-face)
185  +                  (propertize "(no description set)" 'face 'warning)))]
186  +    (if root
187  +        (list (format "%s  %s %s %s\n"
188  +                      cwc
189  +                      change-id
190  +                      (propertize "root()" 'face 'magit-keyword)
191  +                      commit-id) )
192  +      (list
193  +       (format "%s  %s %s %s %s%s\n" cwc change-id author-email timestamp branches commit-id)
194  +       (format "│  %s%s\n" empty desc)))))
195  +
196  +(defun jj--foobar (revset)
197  +  "Fooofoofofofo REVSET fooo."
198  +  (let* ((log-data (jj--get-log-data revset))
199  +         (includes-root? (-some (lambda (m) (string= (ht-get m 'root) "true")) log-data)))
200  +    (-concat (-map #'jj--format-log-line log-data) (when (not includes-root?) (list "~")))))
201  +
202  +(defun jj--parse-git-diff (diff-output)
203  +  "Parse GIT-DIFF-OUTPUT into a hash-table with 'a' and 'b' keys and metadata."
204  +  (let ((result (ht ('a '()) ('b '()) ('metadata (ht))))
205  +        (lines (s-split "\n" diff-output))
206  +        (current-section nil))
207  +    (dolist (line lines)
208  +      (cond
209  +       ;; Metadata
210  +       ((s-starts-with? "diff --git " line)
211  +        (ht-set! (ht-get result 'metadata) 'diff-git line))
212  +       ((s-starts-with? "index " line)
213  +        (ht-set! (ht-get result 'metadata) 'index line))
214  +       ((s-starts-with? "--- " line)
215  +        (ht-set! (ht-get result 'metadata) 'file-a (s-chop-prefix "--- " line))
216  +        (setq current-section 'a))
217  +       ((s-starts-with? "+++ " line)
218  +        (ht-set! (ht-get result 'metadata) 'file-b (s-chop-prefix "+++ " line))
219  +        (setq current-section 'b))
220  +       ;; Diff content
221  +       ((s-starts-with? "-" line)
222  +        (ht-set! result 'a (cons line (ht-get result 'a))))
223  +       ((s-starts-with? "+" line)
224  +        (ht-set! result 'b (cons line (ht-get result 'b))))
225  +       (t
226  +        ;; Lines that don't start with special characters
227  +        (ht-set! result 'a (cons line (ht-get result 'a)))
228  +        (ht-set! result 'b (cons line (ht-get result 'b))))))
229  +    (ht-set! result 'a (reverse (ht-get result 'a)))
230  +    (ht-set! result 'b (reverse (ht-get result 'b)))
231  +    result))
232  +
233  +(comment
234  + (jj--parse-git-diff foobar)
235  + (-> foobar
236  +     jj--parse-git-diff
237  +     parseedn-print-str)
238  + )
239  +
240  +
241   (defun jujutsu-status ()
242     "Display a summary of the current Jujutsu working copy status."
243     (interactive)
244  @@ -200,7 +312,7 @@
245                  "\n"
246                  (if (> (length all-files) 0)
247                      (propertize "Working copy changes:\n" 'face 'font-lock-keyword-face)
248  -                 (propertize "The working copy is clean" 'face 'font-lock-keyword-face))
249  +                 (propertize "The working copy is clean\n" 'face 'font-lock-keyword-face))
250                  (-map (lambda (added-file) (propertize (format "A %s\n" added-file)
251                                                    'face
252                                                    'magit-diffstat-added))
253  @@ -212,7 +324,11 @@
254                  (-map (lambda (deleted-file) (propertize (format "D %s\n" deleted-file)
255                                                      'face
256                                                      'magit-diffstat-removed))
257  -                     files-deleted))
258  +                     files-deleted)
259  +               "\n"
260  +               (propertize "Log:\n" 'face 'font-lock-keyword-face)
261  +               (jj--foobar jujutsu-log-revset-fallback)
262  +               )
263            -flatten
264            (apply #'s-concat)
265            insert))