! Copyright (C) 2006, 2008 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: arrays assocs combinators continuations documents ui.tools.workspace hashtables io io.styles kernel math math.vectors models namespaces parser prettyprint quotations sequences sequences.lib strings threads listener tuples ui.commands ui.gadgets ui.gadgets.editors ui.gadgets.presentations ui.gadgets.worlds ui.gestures definitions boxes calendar ; IN: ui.tools.interactor TUPLE: interactor history output thread quot help ; : interactor-continuation ( interactor -- continuation ) interactor-thread box-value thread-continuation box-value ; : interactor-busy? ( interactor -- ? ) interactor-thread box-full? not ; : interactor-use ( interactor -- seq ) dup interactor-busy? [ drop f ] [ use swap interactor-continuation continuation-name assoc-stack ] if ; : init-caret-help ( interactor -- ) dup editor-caret 1/3 seconds swap set-interactor-help ; : init-interactor-history ( interactor -- ) V{ } clone swap set-interactor-history ; : ( output -- gadget ) interactor construct-editor tuck set-interactor-output over set-interactor-thread dup init-interactor-history dup init-caret-help ; M: interactor graft* dup delegate graft* dup interactor-help add-connection ; : word-at-loc ( loc interactor -- word ) over [ [ gadget-model T{ one-word-elt } elt-string ] keep interactor-use assoc-stack ] [ 2drop f ] if ; M: interactor model-changed 2dup interactor-help eq? [ swap model-value over word-at-loc swap show-summary ] [ delegate model-changed ] if ; : write-input ( string input -- ) presented associate [ H{ { font-style bold } } format ] with-nesting ; : interactor-input. ( string interactor -- ) interactor-output [ dup string? [ dup write-input nl ] [ short. ] if ] with-stream* ; : add-interactor-history ( str interactor -- ) over empty? [ 2drop ] [ interactor-history push-new ] if ; : interactor-continue ( obj interactor -- ) interactor-thread box> resume-with ; : clear-input ( interactor -- ) gadget-model clear-doc ; : interactor-finish ( interactor -- ) #! The spawn is a kludge to make it infer. Stupid. [ editor-string ] keep [ interactor-input. ] 2keep [ add-interactor-history ] keep [ clear-input ] curry "Clearing input" spawn drop ; : interactor-eof ( interactor -- ) dup interactor-busy? [ f over interactor-continue ] unless drop ; : evaluate-input ( interactor -- ) dup interactor-busy? [ dup control-value over interactor-continue ] unless drop ; : interactor-yield ( interactor -- obj ) [ interactor-thread >box ] curry "input" suspend ; M: interactor stream-readln [ interactor-yield ] keep interactor-finish ?first ; : interactor-call ( quot interactor -- ) dup interactor-busy? [ 2dup interactor-input. 2dup interactor-continue ] unless 2drop ; M: interactor stream-read swap dup zero? [ 2drop "" ] [ >r stream-readln dup length r> min head ] if ; M: interactor stream-read-partial stream-read ; : go-to-error ( interactor error -- ) dup parse-error-line 1- swap parse-error-col 2array over set-caret mark>caret ; : handle-parse-error ( interactor error -- ) dup parse-error? [ 2dup go-to-error delegate ] when swap find-workspace debugger-popup ; : try-parse ( lines interactor -- quot/error/f ) [ drop parse-lines-interactive ] [ 2nip dup delegate unexpected-eof? [ drop f ] when ] recover ; : handle-interactive ( lines interactor -- quot/f ? ) tuck try-parse { { [ dup quotation? ] [ nip t ] } { [ dup not ] [ drop "\n" swap user-input f f ] } { [ t ] [ handle-parse-error f f ] } } cond ; M: interactor stream-read-quot [ interactor-yield ] keep { { [ over not ] [ drop ] } { [ over callable? ] [ drop ] } { [ t ] [ [ handle-interactive ] keep swap [ interactor-finish ] [ nip stream-read-quot ] if ] } } cond ; M: interactor pref-dim* 0 over line-height 4 * 2array swap delegate pref-dim* vmax ; interactor "interactor" f { { T{ key-down f f "RET" } evaluate-input } { T{ key-down f { C+ } "k" } clear-input } } define-command-map