]> gitweb.factorcode.org Git - factor.git/blob - extra/gemini/cli/cli.factor
command-line.loop: moving to extra/command-loop for now.
[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 command-loop
5 formatting gemini gemini.private io io.directories
6 io.encodings.string io.encodings.utf8 io.files io.files.temp
7 io.launcher kernel math math.parser namespaces present sequences
8 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     "gemini.txt" temp-file dup exists? [
96         "less" swap 2array try-process
97     ] [ drop ] if ;
98
99 : gemini-quit ( -- )
100     "gemini.txt" temp-file ?delete-file 0 exit ;
101
102 CONSTANT: COMMANDS {
103     T{ command
104         { name "back" }
105         { quot [ drop gemini-back ] }
106         { help "Go back to the previous Gemini URL." }
107         { abbrevs { "b" } } }
108     T{ command
109         { name "forward" }
110         { quot [ drop gemini-forward ] }
111         { help "Go forward to the next Gemini URL." }
112         { abbrevs { "f" } } }
113     T{ command
114         { name "history" }
115         { quot [ drop gemini-history ] }
116         { help "Display recently viewed Gemini URLs." }
117         { abbrevs { "h" "hist" } } }
118     T{ command
119         { name "less" }
120         { quot [ drop gemini-less ] }
121         { help "View the most recent Gemini URL in a pager." }
122         { abbrevs { "l" } } }
123     T{ command
124         { name "go" }
125         { quot [ gemini-go ] }
126         { help "Go to a Gemini URL" }
127         { abbrevs { "g" } } }
128     T{ command
129         { name "up" }
130         { quot [ drop gemini-up ] }
131         { help "Go up one directory from the recent Gemini URL." }
132         { abbrevs { "u" } } }
133     T{ command
134         { name "reload" }
135         { quot [ drop gemini-reload ] }
136         { help "Reload the most recent Gemini URL." }
137         { abbrevs { "r" } } }
138     T{ command
139         { name "quit" }
140         { quot [ drop gemini-quit ] }
141         { help "Quit the program." }
142         { abbrevs { "q" } } }
143 }
144
145 TUPLE: gemini-command-loop < command-loop ;
146
147 M: gemini-command-loop missing-command
148     over string>number [ 1 - LINKS ?nth ] [ f ] if* [
149         gemini-go 3drop
150     ] [
151         call-next-method
152     ] if* ;
153
154 : gemini-main ( -- )
155     "Welcome to Project Gemini!" "GEMINI>"
156     gemini-command-loop new-command-loop
157     COMMANDS [ over add-command ] each
158     run-command-loop ;
159
160 MAIN: gemini-main