#lang racket (require (prefix-in net: "net.rkt") (prefix-in gmi: "gmi.rkt")) (require net/url-string) ;; global state variable which will be an input port containing the ;; rendered out gemtext document as it shall be shown to the user (define document-buffer null) ;; global state which will be the document structure, before rendering (define document null) ;; global state for the url of the currently visited document (define current-url null) (define (go-cmd url) (if (non-empty-string? url) (let () (when (not (string-contains? url "://")) (set! url (string-append "gemini://" url))) (let-values ([(status meta c-in) (net:get url)]) (let-values ([(doc) (gmi:parse (port->lines c-in))] [(db-in db-out) (make-pipe #f)]) (set! document doc) (set! document-buffer db-in) (parameterize ([current-output-port db-out]) (gmi:render doc)) (set! current-url url) (let ([remaining (pipe-content-length db-in)]) (printf "document retrieved. ~a bytes\n" remaining)) (next-cmd)))) (displayln "go where?"))) (define (next-cmd) (define (iter depth) (when (and (> depth 0) (> (pipe-content-length document-buffer) 0)) (let () (displayln (read-line document-buffer)) (iter (sub1 depth))))) (iter 10) (newline) (let ([remaining (pipe-content-length document-buffer)]) (printf "~a bytes remaining\n" remaining))) (define (visit-cmd line) (define url (gmi:match-link document (string->number line))) (set! url (url->string (combine-url/relative (string->url current-url) url))) (go-cmd url)) (define (repl) (display "G-300 > ") (let ([matches (regexp-match #px"(\\w+)\\s*(.*)" (read-line))]) (cond ;; next command. also default [(or (not matches) (string=? (cadr matches) "next") (string=? (cadr matches) "n")) (next-cmd)] ;; go command [(or (string=? (cadr matches) "go") (string=? (cadr matches) "g")) (go-cmd (caddr matches))] ;; visit link command [(andmap char-numeric? (string->list (cadr matches))) (visit-cmd (cadr matches))])) (repl))