1 ! Copyright (C) 2006, 2008 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: arrays assocs combinators continuations documents
4 hashtables io io.styles kernel math math.vectors models
5 namespaces parser prettyprint quotations sequences strings
6 threads listener classes.tuple ui.commands ui.gadgets
7 ui.gadgets.editors ui.gadgets.presentations ui.gadgets.worlds
8 ui.gestures definitions calendar concurrency.flags
9 ui.tools.workspace accessors ;
10 IN: ui.tools.interactor
12 ! If waiting is t, we're waiting for user input, and invoking
13 ! evaluate-input resumes the thread.
14 TUPLE: interactor output history flag thread waiting help ;
16 : register-self ( interactor -- )
19 : interactor-continuation ( interactor -- continuation )
20 thread>> continuation>> value>> ;
22 : interactor-busy? ( interactor -- ? )
23 #! We're busy if there's no thread to resume.
25 [ thread>> dup [ thread-registered? ] when ]
28 : interactor-use ( interactor -- seq )
29 dup interactor-busy? [ drop f ] [
31 interactor-continuation name>>
35 : <help-model> ( interactor -- model )
36 editor-caret 1/3 seconds <delay> ;
38 : <interactor> ( output -- gadget )
40 interactor construct-editor
43 dup <help-model> >>help
47 [ delegate graft* ] [ dup help>> add-connection ] bi ;
49 M: interactor ungraft*
50 [ dup help>> remove-connection ] [ delegate ungraft ] bi ;
52 : word-at-loc ( loc interactor -- word )
54 [ gadget-model T{ one-word-elt } elt-string ] keep
55 interactor-use assoc-stack
60 M: interactor model-changed
62 swap model-value over word-at-loc swap show-summary
64 delegate model-changed
67 : write-input ( string input -- )
68 <input> presented associate
69 [ H{ { font-style bold } } format ] with-nesting ;
71 : interactor-input. ( string interactor -- )
73 dup string? [ dup write-input nl ] [ short. ] if
76 : add-interactor-history ( str interactor -- )
77 over empty? [ 2drop ] [ interactor-history push-new ] if ;
79 : interactor-continue ( obj interactor -- )
80 thread>> resume-with ;
82 : clear-input ( interactor -- ) gadget-model clear-doc ;
84 : interactor-finish ( interactor -- )
85 #! The spawn is a kludge to make it infer. Stupid.
86 [ editor-string ] keep
87 [ interactor-input. ] 2keep
88 [ add-interactor-history ] keep
89 [ clear-input ] curry "Clearing input" spawn drop ;
91 : interactor-eof ( interactor -- )
92 dup interactor-busy? [
93 f over interactor-continue
96 : evaluate-input ( interactor -- )
97 dup interactor-busy? [
98 dup control-value over interactor-continue
101 : interactor-yield ( interactor -- obj )
102 dup thread>> self eq? [
104 [ [ flag>> raise-flag ] curry "input" suspend ] keep
109 M: interactor stream-readln
110 [ interactor-yield ] keep interactor-finish
113 : interactor-call ( quot interactor -- )
114 dup interactor-busy? [
115 2dup interactor-input.
116 2dup interactor-continue
119 M: interactor stream-read
123 >r stream-readln dup length r> min head
126 M: interactor stream-read-partial
129 : go-to-error ( interactor error -- )
130 [ line>> 1- ] [ column>> ] bi 2array
134 : handle-parse-error ( interactor error -- )
135 dup parse-error? [ 2dup go-to-error error>> ] when
136 swap find-workspace debugger-popup ;
138 : try-parse ( lines interactor -- quot/error/f )
140 drop parse-lines-interactive
144 dup error>> unexpected-eof? [ drop f ] when
148 : handle-interactive ( lines interactor -- quot/f ? )
150 { [ dup quotation? ] [ nip t ] }
151 { [ dup not ] [ drop "\n" swap user-input f f ] }
152 [ handle-parse-error f f ]
155 M: interactor stream-read-quot
156 [ interactor-yield ] keep {
157 { [ over not ] [ drop ] }
158 { [ over callable? ] [ drop ] }
160 [ handle-interactive ] keep swap
161 [ interactor-finish ] [ nip stream-read-quot ] if
165 M: interactor pref-dim*
166 [ line-height 4 * 0 swap 2array ] [ delegate pref-dim* ] bi
169 interactor "interactor" f {
170 { T{ key-down f f "RET" } evaluate-input }
171 { T{ key-down f { C+ } "k" } clear-input }