1 ! Copyright (C) 2021 John Benediktsson
2 ! See http://factorcode.org/license.txt for BSD license
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 ;
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 recently viewed 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." }
37 CONSTANT: HISTORY V{ }
42 : add-stack ( args -- )
43 URL ?first STACK index [
44 1 + dup STACK ?nth pick = [
47 STACK [ length ] [ delete-slice ] bi
50 0 STACK remove-nth! drop
57 : add-history ( args -- )
58 HISTORY dup length 10 > [
60 ] when dupd remove! push ;
62 : gemini-history ( -- )
63 HISTORY [ 1 + swap "[%s] %s\n" printf ] each-index
64 LINKS delete-all HISTORY LINKS push-all ;
66 : gemini-print ( url body meta -- )
69 gemini-charset decode string-lines [
70 { [ pre get not ] [ "=>" ?head ] } 0&& [
71 swap gemini-link present LINKS push
72 LINKS length swap "[%s] %s\n" printf
79 : gemini-get ( args -- )
81 >url dup gemini [ drop ] 2dip swap "text/" ?head [
82 "gemini.txt" temp-file
83 [ utf8 [ gemini-print ] with-file-writer ]
84 [ utf8 file-contents print ] bi
86 "ERROR: Cannot display '" "'" surround print 2drop
89 : gemini-go ( args -- )
90 [ "gemini://gemini.circumlunar.space" ] when-empty
91 { [ "://" over subseq? ] [ "gemini://" head? ] } 1||
92 [ "gemini://" prepend ] unless
93 dup "gemini://" head? [
94 [ add-history ] [ add-stack ] [ gemini-get ] tri
97 : gemini-reload ( -- )
98 HISTORY ?last gemini-go ;
101 URL ?first STACK index [
102 1 - STACK ?nth [ gemini-get ] when*
105 : gemini-forward ( -- )
106 URL ?first STACK index [
107 1 + STACK ?nth [ gemini-get ] when*
112 >url f >>query f >>anchor
113 [ "/" ?tail drop "/" split1-last drop "/" append ] change-path
118 "less" "gemini.txt" temp-file 2array try-process ;
121 "gemini.txt" temp-file ?delete-file 0 exit ;
123 : gemini-help ( args -- )
126 [ 6 <groups> ] [ longest length 4 + ] bi
127 '[ [ _ CHAR: \s pad-tail write ] each nl ] each
129 ABBREVS ?at drop COMMANDS ?at [
132 "ERROR: Command '" "' not found" surround print
136 : gemini-cmd ( cmd -- )
137 " " split1 swap >lower ABBREVS ?at drop {
138 { "help" [ gemini-help ] }
139 { "history" [ drop gemini-history ] }
140 { "go" [ gemini-go ] }
141 { "reload" [ drop gemini-reload ] }
142 { "back" [ drop gemini-back ] }
143 { "forward" [ drop gemini-forward ] }
144 { "up" [ drop gemini-up ] }
145 { "less" [ drop gemini-less ] }
146 { "quit" [ drop gemini-quit ] }
149 dup string>number [ 1 - LINKS ?nth ] [ f ] if* [
152 "ERROR: Unknown command '" "'" surround print drop
158 "Welcome to Project Gemini!" print flush [
159 "GEMINI> " write flush readln
160 [ gemini-cmd t ] [ f ] if*