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