2 USING: kernel namespaces xmode.rules xmode.tokens
3 xmode.marker.state xmode.marker.context xmode.utilities
4 xmode.catalog sequences math assocs combinators
5 strings regexp splitting parser-combinators ascii unicode.case
6 combinators.short-circuit accessors ;
8 ! Based on org.gjt.sp.jedit.syntax.TokenMarker
10 : current-keyword ( -- string )
11 last-offset get position get line get subseq ;
13 : keyword-number? ( keyword -- ? )
15 [ current-rule-set highlight-digits?>> ]
16 [ dup [ digit? ] contains? ]
19 current-rule-set digit-re>>
20 dup [ dupd matches? ] [ drop f ] if
25 : mark-number ( keyword -- id )
26 keyword-number? DIGIT and ;
28 : mark-keyword ( keyword -- id )
29 current-rule-set keywords>> at ;
31 : add-remaining-token ( -- )
32 current-rule-set default>> prev-token, ;
36 dup mark-number [ ] [ mark-keyword ] ?if
37 [ prev-token, ] when* ;
39 : current-char ( -- char )
40 position get line get nth ;
42 GENERIC: match-position ( rule -- n )
44 M: mark-previous-rule match-position drop last-offset get ;
46 M: rule match-position drop position get ;
48 : can-match-here? ( matcher rule -- ? )
51 [ over at-line-start?>> over zero? implies ]
52 [ over at-whitespace-end?>> over whitespace-end get = implies ]
53 [ over at-word-start?>> over last-offset get = implies ]
56 : rest-of-line ( -- str )
57 line get position get tail-slice ;
59 GENERIC: text-matches? ( string text -- match-count/f )
64 M: string-matcher text-matches?
66 [ string>> ] [ ignore-case?>> ] bi string-head?
67 ] keep string>> length and ;
69 M: regexp text-matches?
70 >r >string r> match-head ;
72 : rule-start-matches? ( rule -- match-count/f )
73 dup start>> tuck swap can-match-here? [
74 rest-of-line swap text>> text-matches?
79 : rule-end-matches? ( rule -- match-count/f )
80 dup mark-following-rule? [
81 dup start>> swap can-match-here? 0 and
83 dup end>> tuck swap can-match-here? [
85 swap text>> context get end>> or
94 : get-always-rules ( vector/f ruleset -- vector/f )
95 f swap rules>> at ?push-all ;
97 : get-char-rules ( vector/f char ruleset -- vector/f )
98 >r ch>upper r> rules>> at ?push-all ;
100 : get-rules ( char ruleset -- seq )
101 f -rot [ get-char-rules ] keep get-always-rules ;
103 GENERIC: handle-rule-start ( match-count rule -- )
105 GENERIC: handle-rule-end ( match-count rule -- )
107 : find-escape-rule ( -- rule )
109 in-rule-set>> escape-rule>> [ ] [
110 parent>> in-rule-set>>
111 dup [ escape-rule>> ] when
114 : check-escape-rule ( rule -- ? )
116 find-escape-rule dup [
117 dup rule-start-matches? dup [
118 swap handle-rule-start
119 delegate-end-escaped? [ not ] change
127 : check-every-rule ( -- ? )
128 current-char current-rule-set get-rules
129 [ rule-start-matches? ] map-find
130 dup [ handle-rule-start t ] [ 2drop f ] if ;
134 dup rule-end-matches?
135 dup [ swap handle-rule-end ] [ 2drop ] if
138 : rule-match-token* ( rule -- id )
140 { f [ dup body-token>> ] }
141 { t [ current-rule-set default>> ] }
145 M: escape-rule handle-rule-start
148 process-escape? get [
149 escaped? [ not ] change
150 position [ + ] change
153 M: seq-rule handle-rule-start
157 tuck body-token>> next-token,
158 delegate>> [ push-context ] when* ;
160 UNION: abstract-span-rule span-rule eol-span-rule ;
162 M: abstract-span-rule handle-rule-start
166 tuck rule-match-token* next-token,
168 dup context get (>>in-rule)
169 delegate>> push-context ;
171 M: span-rule handle-rule-end
174 M: mark-following-rule handle-rule-start
176 mark-token add-remaining-token
177 tuck rule-match-token* next-token,
178 f context get (>>end)
179 context get (>>in-rule) ;
181 M: mark-following-rule handle-rule-end
182 nip rule-match-token* prev-token,
183 f context get (>>in-rule) ;
185 M: mark-previous-rule handle-rule-start
188 dup body-token>> prev-token,
189 rule-match-token* next-token, ;
197 : check-end-delegate ( -- ? )
198 context get parent>> [
200 dup rule-end-matches? dup [
206 ] keep context get parent>> in-rule>>
207 rule-match-token* next-token,
209 seen-whitespace-end? on t
210 ] [ drop check-escape-rule ] if
214 : handle-no-word-break ( -- )
215 context get parent>> [
217 dup no-word-break?>> [
218 rule-match-token* prev-token,
228 add-remaining-token ;
230 : (check-word-break) ( -- )
233 1 current-rule-set default>> next-token, ;
235 : rule-set-empty? ( ruleset -- ? )
236 [ rules>> ] [ keywords>> ] bi
237 [ assoc-empty? ] bi@ and ;
239 : check-word-break ( -- ? )
240 current-char dup blank? [
243 seen-whitespace-end? get [
244 position get 1+ whitespace-end set
250 ! Micro-optimization with incorrect semantics; we keep
251 ! it here because jEdit mode files depend on it now...
252 current-rule-set rule-set-empty? [
258 current-rule-set rule-set-no-word-sep* member? [
264 seen-whitespace-end? on
267 delegate-end-escaped? off t ;
270 : mark-token-loop ( -- )
271 position get line get length < [
273 [ check-end-delegate ]
282 : mark-remaining ( -- )
283 line get length position set
286 : unwind-no-line-break ( -- )
287 context get parent>> [
296 : tokenize-line ( line-context line rules -- line-context' seq )