2 USING: accessors combinators.cleave combinators.short-circuit
3 concurrency.combinators destructors fry io io.directories
4 io.encodings io.encodings.utf8 io.launcher io.monitors
5 io.pathnames io.pipes io.ports kernel locals math namespaces
6 sequences splitting strings threads ui ui.gadgets
7 ui.gadgets.buttons ui.gadgets.editors ui.gadgets.labels
8 ui.gadgets.packs ui.gadgets.tracks ;
12 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
14 : head** ( seq obj -- seq/f ) dup number? [ head ] [ dupd find drop head ] if ;
16 : tail** ( seq obj -- seq/f )
19 [ dupd find drop [ tail ] [ drop f ] if* ]
22 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
24 :: <process-stdout-stderr-reader> ( DESC -- process stream stream )
26 [let | STDOUT-PIPE [ (pipe) |dispose ]
27 STDERR-PIPE [ (pipe) |dispose ] |
29 [let | PROCESS [ DESC >process ] |
32 [ STDOUT-PIPE out>> or ] change-stdout
33 [ STDERR-PIPE out>> or ] change-stderr
36 STDOUT-PIPE out>> dispose
37 STDERR-PIPE out>> dispose
39 STDOUT-PIPE in>> <input-port> utf8 <decoder>
40 STDERR-PIPE in>> <input-port> utf8 <decoder> ] ]
44 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
46 : run-process/result ( desc -- process )
47 <process-stdout-stderr-reader>
49 [ contents [ string-lines ] [ f ] if* ]
50 [ contents [ string-lines ] [ f ] if* ]
53 [ >>stdout ] [ >>stderr ] bi*
54 dup wait-for-process >>status ;
56 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
57 ! process popup windows
58 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
60 : popup-window ( title contents -- )
61 dup string? [ ] [ "\n" join ] if
62 <editor> tuck set-editor-string swap open-window ;
64 : popup-process-window ( process -- )
65 [ stdout>> [ "output" swap popup-window ] when* ]
66 [ stderr>> [ "error" swap popup-window ] when* ]
68 [ stdout>> ] [ stderr>> ] bi or not
69 [ "Process" "NO OUTPUT" popup-window ]
74 : popup-if-error ( process -- )
75 { [ status>> 0 = not ] [ popup-process-window t ] } 1&& drop ;
77 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
79 :: git-process ( REPO DESC -- process )
80 REPO [ DESC run-process/result ] with-directory ;
82 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
84 : git-status-section ( lines section -- lines/f )
87 [ "#\t" head? ] tail**
88 [ "#\t" head? not ] head**
94 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
96 : colon ( -- ch ) CHAR: : ;
97 : space ( -- ch ) 32 ;
99 : git-status-line-file ( line -- file )
100 { [ colon = ] 1 [ space = not ] } [ tail** ] each ;
102 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
113 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
115 : check-empty ( seq -- seq/f ) dup empty? [ drop f ] when ;
117 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
119 :: refresh-git-status ( STATUS -- STATUS )
121 [let | LINES [ STATUS repository>> { "git" "status" } git-process stdout>> ] |
125 LINES "# Changes to be committed:" git-status-section
126 [ "new file:" head? ] filter
127 [ git-status-line-file ] map
131 LINES "# Changes to be committed:" git-status-section
132 [ "modified:" head? ] filter
133 [ git-status-line-file ] map
137 LINES "# Changes to be committed:" git-status-section
138 [ "deleted:" head? ] filter
139 [ git-status-line-file ] map
143 LINES "# Changed but not updated:" git-status-section
144 [ "modified:" head? ] filter
145 [ git-status-line-file ] map
149 LINES "# Changed but not updated:" git-status-section
150 [ "deleted:" head? ] filter
151 [ git-status-line-file ] map
155 LINES "# Untracked files:" git-status-section >>untracked ] ;
157 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
159 :: git-status ( REPO -- <git-status> )
161 <git-status> new REPO >>repository refresh-git-status ;
163 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
165 :: factor-git-status ( -- <git-status> ) "resource:" git-status ;
167 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
169 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
171 : to-commit ( <git-status> -- seq )
172 { to-commit-new>> to-commit-modified>> to-commit-deleted>> } 1arr concat ;
174 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
176 :: refresh-status-pile ( STATUS PILE -- )
178 STATUS refresh-git-status drop
186 [wlet | add-commit-path-button [| TEXT PATH |
190 TEXT <label> 2/8 track-add
191 PATH <label> 6/8 track-add
198 { "git" "reset" "HEAD" PATH }
202 STATUS PILE refresh-status-pile
204 <bevel-button> f track-add
210 "Changes to be committed" <label> reverse-video-theme add-gadget
212 STATUS to-commit-new>>
213 [| PATH | "new file: " PATH add-commit-path-button ]
216 STATUS to-commit-modified>>
217 [| PATH | "modified: " PATH add-commit-path-button ]
220 STATUS to-commit-deleted>>
221 [| PATH | "deleted: " PATH add-commit-path-button ]
226 [let | EDITOR [ <editor> "COMMIT MESSAGE" over set-editor-string ] |
233 [let | MSG [ EDITOR editor-string ] |
236 { "git" "commit" "-m" MSG } git-process
238 STATUS PILE refresh-status-pile
252 "Modified but not updated" <label> reverse-video-theme add-gadget
259 PATH <label> add-gadget
264 STATUS repository>> { "git" "add" PATH } git-process popup-if-error
265 STATUS PILE refresh-status-pile
267 <bevel-button> add-gadget
272 STATUS repository>> { "git" "diff" PATH } git-process
275 <bevel-button> add-gadget
289 "Untracked files" <label> reverse-video-theme add-gadget
296 PATH <label> f track-add
301 STATUS repository>> { "git" "add" PATH } git-process popup-if-error
302 STATUS PILE refresh-status-pile
304 <bevel-button> f track-add
316 "Refresh" [ drop STATUS PILE refresh-status-pile ] <bevel-button> add-gadget
320 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
322 :: git-remote-branches ( REPO NAME -- seq )
323 REPO { "git" "remote" "show" NAME } git-process stdout>>
324 " Tracked remote branches" over index 1 + tail first " " split
325 [ empty? not ] filter ;
327 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
329 :: refresh-remotes-pile ( REPO PILE -- )
335 "Remotes" <label> reverse-video-theme add-gadget
337 REPO { "git" "remote" } git-process stdout>> [ empty? not ] filter
341 [let | BRANCH! [ "master" ] |
345 NAME <label> 1 track-add
347 [let | BRANCH-BUTTON [ "master" [ drop ] <bevel-button> ] |
357 REPO NAME git-remote-branches
365 OTHER-BRANCH BRANCH-BUTTON gadget-child set-label-string
373 "Select a branch" open-window
380 [ drop REPO { "git" "fetch" NAME } git-process popup-process-window ]
387 [let | ARG [ { ".." NAME "/" BRANCH } concat ] |
388 REPO { "git" "log" ARG } git-process popup-process-window ]
396 [let | ARG [ { NAME "/" BRANCH } concat ] |
397 REPO { "git" "merge" ARG } git-process popup-process-window ]
405 [let | ARG [ { NAME "/" BRANCH ".." } concat ] |
406 REPO { "git" "log" ARG } git-process popup-process-window ]
414 REPO { "git" "push" NAME "master" } git-process popup-process-window
426 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
428 :: git-tool ( REPO -- )
432 "Repository: " REPO [ current-directory get ] with-directory append
436 [let | STATUS [ REPO git-status ]
437 PILE [ <pile> 1 >>fill ] |
441 [let | MONITOR [ REPO t <monitor> ] |
443 [let | PATH [ MONITOR next-change drop ] |
444 ".git" PATH subseq? ! Ignore git internal operations
446 [ STATUS PILE refresh-status-pile ]
457 STATUS PILE refresh-status-pile
461 REPO <pile> 1 >>fill tuck refresh-remotes-pile add-gadget
465 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
467 : factor-git-tool ( -- ) "resource:" git-tool ;
469 ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!