]> gitweb.factorcode.org Git - factor.git/blob - extra/gemini/cli/cli.factor
gemini.cli: cleanup using command-line.loop.
[factor.git] / extra / gemini / cli / cli.factor
1 ! Copyright (C) 2021 John Benediktsson
2 ! See http://factorcode.org/license.txt for BSD license
3
4 USING: accessors arrays combinators.short-circuit
5 command-line.loop formatting gemini gemini.private io
6 io.directories io.encodings.string io.encodings.utf8 io.files
7 io.files.temp io.launcher kernel math math.parser namespaces
8 present sequences splitting system urls webbrowser ;
9
10 IN: gemini.cli
11
12 CONSTANT: DEFAULT-URL "gemini://gemini.circumlunar.space"
13
14 CONSTANT: HISTORY V{ }
15 CONSTANT: LINKS V{ }
16 CONSTANT: STACK V{ }
17 CONSTANT: URL V{ }
18
19 : add-stack ( args -- )
20     URL ?first STACK index [
21         1 + dup STACK ?nth pick = [
22             2drop
23         ] [
24             STACK [ length ] [ delete-slice ] bi
25             STACK push
26             STACK length 10 > [
27                 0 STACK remove-nth! drop
28             ] when
29         ] if
30     ] [
31         STACK push
32     ] if* ;
33
34 : add-history ( args -- )
35     HISTORY dup length 10 > [
36         0 swap remove-nth!
37     ] when dupd remove! push ;
38
39 : gemini-history ( -- )
40     HISTORY [ 1 + swap "[%s] %s\n" printf ] each-index
41     LINKS delete-all HISTORY LINKS push-all ;
42
43 : gemini-print ( url body meta -- )
44     f pre [
45         LINKS delete-all
46         gemini-charset decode string-lines [
47             { [ pre get not ] [ "=>" ?head ] } 0&& [
48                 swap gemini-link present LINKS push
49                 LINKS length swap "[%s] %s\n" printf
50             ] [
51                 gemini-line.
52             ] if
53         ] with each
54     ] with-variable ;
55
56 : gemini-get ( args -- )
57     dup 0 URL set-nth
58     >url dup gemini [ drop ] 2dip swap "text/" ?head [
59         "gemini.txt" temp-file
60         [ utf8 [ gemini-print ] with-file-writer ]
61         [ utf8 file-contents print ] bi
62     ] [
63         "ERROR: Cannot display '" "'" surround print 2drop
64     ] if ;
65
66 : gemini-go ( args -- )
67     [ DEFAULT-URL ] when-empty
68     { [ "://" over subseq? ] [ "gemini://" head? ] } 1||
69     [ "gemini://" prepend ] unless
70     dup "gemini://" head? [
71         [ add-history ] [ add-stack ] [ gemini-get ] tri
72     ] [ open-url ] if ;
73
74 : gemini-reload ( -- )
75     HISTORY ?last gemini-go ;
76
77 : gemini-back ( -- )
78     URL ?first STACK index [
79         1 - STACK ?nth [ gemini-get ] when*
80     ] when* ;
81
82 : gemini-forward ( -- )
83     URL ?first STACK index [
84         1 + STACK ?nth [ gemini-get ] when*
85     ] when* ;
86
87 : gemini-up ( -- )
88     URL ?first [
89         >url f >>query f >>anchor
90         [ "/" ?tail drop "/" split1-last drop "/" append ] change-path
91         present gemini-go
92     ] when* ;
93
94 : gemini-less ( -- )
95     "less" "gemini.txt" temp-file 2array try-process ;
96
97 : gemini-quit ( -- )
98     "gemini.txt" temp-file ?delete-file 0 exit ;
99
100 CONSTANT: COMMANDS {
101     T{ command
102         { name "back" }
103         { quot [ drop gemini-back ] }
104         { help "Go back to the previous Gemini URL." }
105         { abbrevs { "b" } } }
106     T{ command
107         { name "forward" }
108         { quot [ drop gemini-forward ] }
109         { help "Go forward to the next Gemini URL." }
110         { abbrevs { "f" } } }
111     T{ command
112         { name "history" }
113         { quot [ drop gemini-history ] }
114         { help "Display recently viewed Gemini URLs." }
115         { abbrevs { "h" "hist" } } }
116     T{ command
117         { name "less" }
118         { quot [ drop gemini-less ] }
119         { help "View the most recent Gemini URL in a pager." }
120         { abbrevs { "l" } } }
121     T{ command
122         { name "go" }
123         { quot [ gemini-go ] }
124         { help "Go to a Gemini URL" }
125         { abbrevs { "g" } } }
126     T{ command
127         { name "up" }
128         { quot [ drop gemini-up ] }
129         { help "Go up one directory from the recent Gemini URL." }
130         { abbrevs { "u" } } }
131     T{ command
132         { name "reload" }
133         { quot [ drop gemini-reload ] }
134         { help "Reload the most recent Gemini URL." }
135         { abbrevs { "r" } } }
136     T{ command
137         { name "quit" }
138         { quot [ drop gemini-quit ] }
139         { help "Quit the program." }
140         { abbrevs { "q" } } }
141 }
142
143 TUPLE: gemini-command-loop < command-loop ;
144
145 M: gemini-command-loop missing-command
146     over string>number [ 1 - LINKS ?nth ] [ f ] if* [
147         gemini-go 3drop
148     ] [
149         call-next-method
150     ] if* ;
151
152 : gemini-main ( -- )
153     "Welcome to Project Gemini!" "GEMINI>"
154     gemini-command-loop new-command-loop
155     COMMANDS [ over add-command ] each
156     run-command-loop ;
157
158 MAIN: gemini-main