2 USING: kernel namespaces xmode.rules xmode.tokens
3 xmode.marker.state xmode.marker.context xmode.utilities
4 xmode.catalog sequences math assocs combinators combinators.lib
5 strings regexp splitting parser-combinators ascii unicode.case ;
7 ! Based on org.gjt.sp.jedit.syntax.TokenMarker
9 : current-keyword ( -- string )
10 last-offset get position get line get subseq ;
12 : keyword-number? ( keyword -- ? )
14 [ current-rule-set rule-set-highlight-digits? ]
15 [ dup [ digit? ] contains? ]
18 current-rule-set rule-set-digit-re
19 dup [ dupd matches? ] [ drop f ] if
24 : mark-number ( keyword -- id )
25 keyword-number? DIGIT and ;
27 : mark-keyword ( keyword -- id )
28 current-rule-set rule-set-keywords at ;
30 : add-remaining-token ( -- )
31 current-rule-set rule-set-default prev-token, ;
35 dup mark-number [ ] [ mark-keyword ] ?if
36 [ prev-token, ] when* ;
38 : current-char ( -- char )
39 position get line get nth ;
41 GENERIC: match-position ( rule -- n )
43 M: mark-previous-rule match-position drop last-offset get ;
45 M: rule match-position drop position get ;
47 : can-match-here? ( matcher rule -- ? )
50 [ over matcher-at-line-start? over zero? implies ]
51 [ over matcher-at-whitespace-end? over whitespace-end get = implies ]
52 [ over matcher-at-word-start? over last-offset get = implies ]
55 : rest-of-line ( -- str )
56 line get position get tail-slice ;
58 GENERIC: text-matches? ( string text -- match-count/f )
63 M: string-matcher text-matches?
65 dup string-matcher-string
66 swap string-matcher-ignore-case?
68 ] keep string-matcher-string length and ;
70 M: regexp text-matches?
71 >r >string r> match-head ;
73 : rule-start-matches? ( rule -- match-count/f )
74 dup rule-start tuck swap can-match-here? [
75 rest-of-line swap matcher-text text-matches?
80 : rule-end-matches? ( rule -- match-count/f )
81 dup mark-following-rule? [
82 dup rule-start swap can-match-here? 0 and
84 dup rule-end tuck swap can-match-here? [
86 swap matcher-text context get line-context-end or
95 : get-always-rules ( vector/f ruleset -- vector/f )
96 f swap rule-set-rules at ?push-all ;
98 : get-char-rules ( vector/f char ruleset -- vector/f )
99 >r ch>upper r> rule-set-rules at ?push-all ;
101 : get-rules ( char ruleset -- seq )
102 f -rot [ get-char-rules ] keep get-always-rules ;
104 GENERIC: handle-rule-start ( match-count rule -- )
106 GENERIC: handle-rule-end ( match-count rule -- )
108 : find-escape-rule ( -- rule )
110 line-context-in-rule-set rule-set-escape-rule [ ] [
111 line-context-parent line-context-in-rule-set
112 dup [ rule-set-escape-rule ] when
115 : check-escape-rule ( rule -- ? )
116 rule-no-escape? [ f ] [
117 find-escape-rule dup [
118 dup rule-start-matches? dup [
119 swap handle-rule-start
120 delegate-end-escaped? [ not ] change
128 : check-every-rule ( -- ? )
129 current-char current-rule-set get-rules
130 [ rule-start-matches? ] map-find
131 dup [ handle-rule-start t ] [ 2drop f ] if ;
135 dup rule-end-matches?
136 dup [ swap handle-rule-end ] [ 2drop ] if
139 : rule-match-token* ( rule -- id )
140 dup rule-match-token {
141 { f [ dup rule-body-token ] }
142 { t [ current-rule-set rule-set-default ] }
146 M: escape-rule handle-rule-start
149 process-escape? get [
150 escaped? [ not ] change
151 position [ + ] change
154 M: seq-rule handle-rule-start
158 tuck rule-body-token next-token,
159 rule-delegate [ push-context ] when* ;
161 UNION: abstract-span-rule span-rule eol-span-rule ;
163 M: abstract-span-rule handle-rule-start
167 tuck rule-match-token* next-token,
169 dup context get set-line-context-in-rule
170 rule-delegate push-context ;
172 M: span-rule handle-rule-end
175 M: mark-following-rule handle-rule-start
177 mark-token add-remaining-token
178 tuck rule-match-token* next-token,
179 f context get set-line-context-end
180 context get set-line-context-in-rule ;
182 M: mark-following-rule handle-rule-end
183 nip rule-match-token* prev-token,
184 f context get set-line-context-in-rule ;
186 M: mark-previous-rule handle-rule-start
189 dup rule-body-token prev-token,
190 rule-match-token* next-token, ;
198 : check-end-delegate ( -- ? )
199 context get line-context-parent [
200 line-context-in-rule [
201 dup rule-end-matches? dup [
207 ] keep context get line-context-parent line-context-in-rule 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 line-context-parent [
216 line-context-in-rule [
217 dup rule-no-word-break? [
218 rule-match-token* prev-token,
228 add-remaining-token ;
230 : (check-word-break) ( -- )
233 1 current-rule-set rule-set-default next-token, ;
235 : rule-set-empty? ( ruleset -- ? )
236 dup rule-set-rules assoc-empty?
237 swap rule-set-keywords assoc-empty? 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 line-context-parent [
288 line-context-in-rule [
289 rule-no-line-break? [
296 : tokenize-line ( line-context line rules -- line-context' seq )