--- /dev/null
+! Copyright (C) 2021 John Benediktsson
+! See http://factorcode.org/license.txt for BSD license
+
+USING: accessors ascii assocs combinators
+combinators.short-circuit formatting gemini gemini.private io
+io.encodings.string kernel math math.parser namespaces present
+sequences splitting urls ;
+
+IN: gemini.cli
+
+CONSTANT: ABBREVS H{
+ { "b" "back" }
+ { "f" "forward" }
+ { "g" "go" }
+ { "h" "history" }
+ { "hist" "history" }
+ { "q" "quit" }
+ { "r" "reload" }
+ { "u" "up" }
+}
+
+CONSTANT: HISTORY V{ }
+CONSTANT: LINKS V{ }
+CONSTANT: URL V{ }
+
+: add-history ( args -- )
+ HISTORY dup length 10 > [
+ 0 swap remove-nth!
+ ] when dupd remove! push ;
+
+: gemini-history ( args -- )
+ drop HISTORY [ 1 + swap "[%s] %s\n" printf ] each-index
+ LINKS delete-all HISTORY LINKS push-all ;
+
+: gemini-get ( args -- )
+ dup 0 URL set-nth
+ >url dup gemini [ drop ] 2dip swap "text/" ?head [
+ f pre [
+ LINKS delete-all
+ gemini-charset decode string-lines [
+ { [ pre get not ] [ "=>" ?head ] } 0&& [
+ swap gemini-link present LINKS push
+ LINKS length swap "[%s] %s\n" printf
+ ] [
+ gemini-line.
+ ] if
+ ] with each
+ ] with-variable
+ ] [
+ "ERROR: Cannot display '" "'" surround print 2drop
+ ] if ;
+
+: gemini-go ( args -- )
+ [ "gemini://gemini.circumlunar.space" ] when-empty
+ dup "gemini://" head? [ "gemini://" prepend ] unless
+ dup add-history gemini-get ;
+
+: gemini-reload ( args -- )
+ drop HISTORY ?last gemini-go ;
+
+: gemini-back ( args -- )
+ drop URL ?first HISTORY index [
+ 1 - HISTORY ?nth [ gemini-get ] when*
+ ] when* ;
+
+: gemini-forward ( args -- )
+ drop URL ?first HISTORY index [
+ 1 + HISTORY ?nth [ gemini-get ] when*
+ ] when* ;
+
+: gemini-up ( args -- )
+ drop URL ?first [
+ >url f >>query f >>anchor
+ [ "/" ?tail drop "/" split1-last drop "/" append ] change-path
+ present gemini-go
+ ] when* ;
+
+: gemini-cmd ( cmd -- )
+ " " split1 swap >lower ABBREVS ?at drop {
+ { "history" [ gemini-history ] }
+ { "go" [ gemini-go ] }
+ { "reload" [ gemini-reload ] }
+ { "back" [ gemini-back ] }
+ { "forward" [ gemini-forward ] }
+ { "up" [ gemini-up ] }
+ { "" [ drop ] }
+ [
+ dup string>number [ 1 - LINKS ?nth ] [ f ] if* [
+ 2nip gemini-go
+ ] [
+ "ERROR: Unknown command '" "'" surround print drop
+ ] if*
+ ]
+ } case flush ;
+
+: gemini-main ( -- )
+ "Welcome to Project Gemini!" print flush [
+ "GEMINI> " write flush readln
+ [ gemini-cmd t ] [ f ] if*
+ ] loop ;
+
+MAIN: gemini-main