*** empty log message ***
original commit: b1f68dd797b20271c7cd243e7bcf0303458a510e
This commit is contained in:
parent
6759e693a6
commit
1a28cda103
|
@ -56,9 +56,9 @@
|
|||
;; Some other tool wants to take over coloring the buffer, so the
|
||||
;; colorer shouldn't color anything.
|
||||
(define frozen? #f)
|
||||
;; true iff the colorer should recolor from scratch when the freeze
|
||||
;; true iff the colorer must recolor from scratch when the freeze
|
||||
;; is over.
|
||||
(define restart-after-freeze #f)
|
||||
(define force-recolor-after-freeze #f)
|
||||
|
||||
;; ---------------------- Lexing state ------------------------------
|
||||
|
||||
|
@ -83,6 +83,7 @@
|
|||
|
||||
;; ---------------------- Parnethesis matching ----------------------
|
||||
|
||||
;; The pairs of matching parens
|
||||
(define pairs '())
|
||||
(define parens (new paren-tree% (matches pairs)))
|
||||
|
||||
|
@ -92,11 +93,14 @@
|
|||
(define start-pos 0)
|
||||
(define end-pos 'end)
|
||||
|
||||
;; Set the region of the text that is tokenized to start at start and
|
||||
;; end at end.
|
||||
(define/public (reset-region start end)
|
||||
(set! start-pos start)
|
||||
(set! end-pos end)
|
||||
(reset-tokens))
|
||||
|
||||
;; Modify the end of the region.
|
||||
(define/public (update-region-end end)
|
||||
(set! end-pos end))
|
||||
|
||||
|
@ -116,27 +120,32 @@
|
|||
(inherit change-style begin-edit-sequence end-edit-sequence highlight-range
|
||||
get-style-list in-edit-sequence? get-start-position get-end-position
|
||||
local-edit-sequence? get-styles-fixed has-focus?)
|
||||
(define/public (reset-tokens)
|
||||
|
||||
(define (reset-tokens)
|
||||
(send tokens reset-tree)
|
||||
(send invalid-tokens reset-tree)
|
||||
(set! invalid-tokens-start +inf.0)
|
||||
(set! up-to-date? #t)
|
||||
(set! restart-callback #f)
|
||||
(set! force-recolor-after-freeze #f)
|
||||
(set! parens (new paren-tree% (matches pairs)))
|
||||
(set! current-pos start-pos)
|
||||
(set! colors null)
|
||||
(modify))
|
||||
|
||||
;; Let the background thread know the text has been modified.
|
||||
(define (modify)
|
||||
(when background-thread
|
||||
(break-thread background-thread)))
|
||||
|
||||
;; Actually color the buffer.
|
||||
(define (color)
|
||||
(unless (null? colors)
|
||||
((car colors))
|
||||
(set! colors (cdr colors))
|
||||
(color)))
|
||||
|
||||
;; Discard extra tokens at the first of invalie-tokens
|
||||
(define (sync-invalid)
|
||||
(when (and (not (send invalid-tokens is-empty?))
|
||||
(< invalid-tokens-start current-pos))
|
||||
|
@ -146,9 +155,9 @@
|
|||
(set! invalid-tokens-start (+ invalid-tokens-start length)))
|
||||
(sync-invalid)))
|
||||
|
||||
;; re-tokenize should be called with breaks enabled and exit with breaks disabled
|
||||
;; re-tokenize should be called when lock is not held. When it exits, the lock
|
||||
;; will be held.
|
||||
;; re-tokenize should be called with breaks enabled and exit with
|
||||
;; breaks disabled re-tokenize should be called when lock is not
|
||||
;; held. When it exits, the lock will be held.
|
||||
(define (re-tokenize in in-start-pos)
|
||||
(let-values (((type data new-token-start new-token-end) (get-token in)))
|
||||
;; breaks must be disabled before the semaphore wait so we can't be
|
||||
|
@ -171,13 +180,14 @@
|
|||
(lambda ()
|
||||
(change-style color sp ep #f)))
|
||||
colors)))
|
||||
(insert-last! tokens (new token-tree% (length len) (data data)))
|
||||
(insert-last! tokens (new token-tree% (length len) (data type)))
|
||||
(send parens add-token data len)
|
||||
(cond
|
||||
((and (not (send invalid-tokens is-empty?))
|
||||
(= invalid-tokens-start current-pos))
|
||||
(send invalid-tokens search-max!)
|
||||
(send parens merge-tree (send invalid-tokens get-root-end-position))
|
||||
(send parens merge-tree
|
||||
(send invalid-tokens get-root-end-position))
|
||||
(insert-last! tokens invalid-tokens)
|
||||
(set! invalid-tokens-start +inf.0))
|
||||
(else
|
||||
|
@ -187,16 +197,15 @@
|
|||
|
||||
(define (do-insert/delete edit-start-pos change-length)
|
||||
(unless (or stopped? force-stop?)
|
||||
(when frozen?
|
||||
(set! restart-after-freeze #t))
|
||||
(when (> edit-start-pos start-pos)
|
||||
(set! edit-start-pos (sub1 edit-start-pos)))
|
||||
(modify)
|
||||
(cond
|
||||
(up-to-date?
|
||||
(send tokens search! (- edit-start-pos start-pos))
|
||||
(let-values (((orig-token-start orig-token-end valid-tree invalid-tree)
|
||||
(send tokens split)))
|
||||
(let-values
|
||||
(((orig-token-start orig-token-end valid-tree invalid-tree)
|
||||
(send tokens split)))
|
||||
(send parens split-tree orig-token-start)
|
||||
(set! invalid-tokens invalid-tree)
|
||||
(set! tokens valid-tree)
|
||||
|
@ -212,7 +221,8 @@
|
|||
(let-values (((tok-start tok-end valid-tree invalid-tree)
|
||||
(send invalid-tokens split)))
|
||||
(set! invalid-tokens invalid-tree)
|
||||
(set! invalid-tokens-start (+ invalid-tokens-start tok-end change-length))))
|
||||
(set! invalid-tokens-start
|
||||
(+ invalid-tokens-start tok-end change-length))))
|
||||
((>= edit-start-pos current-pos)
|
||||
(set! invalid-tokens-start (+ change-length invalid-tokens-start)))
|
||||
(else
|
||||
|
@ -227,7 +237,7 @@
|
|||
(inherit is-locked?)
|
||||
|
||||
(define (colorer-driver)
|
||||
(unless (or up-to-date? (in-edit-sequence?))
|
||||
(unless up-to-date?
|
||||
(thread-resume background-thread)
|
||||
(sleep .01) ;; This is when the background thread is working.
|
||||
(semaphore-wait mutex-lock)
|
||||
|
@ -242,7 +252,8 @@
|
|||
((is-locked?)
|
||||
(set! restart-callback #t))
|
||||
(else
|
||||
(colorer-driver)
|
||||
(unless (in-edit-sequence?)
|
||||
(colorer-driver))
|
||||
(unless up-to-date?
|
||||
(queue-callback colorer-callback #f)))))
|
||||
|
||||
|
@ -266,7 +277,8 @@
|
|||
(printf "colorer thread: ~s\n" exn)
|
||||
(break-enabled #f)
|
||||
(semaphore-wait mutex-lock))))
|
||||
(re-tokenize (open-input-text-editor this current-pos end-pos (lambda (x) (values #f 1)))
|
||||
(re-tokenize (open-input-text-editor this current-pos end-pos
|
||||
(lambda (x) (values #f 1)))
|
||||
current-pos))
|
||||
;; Breaks should be disabled from exit of re-tokenize
|
||||
;; lock will be held
|
||||
|
@ -275,8 +287,7 @@
|
|||
(thread-suspend (current-thread))))
|
||||
(background-colorer))
|
||||
|
||||
;; Must not be called when the editor is locked or in an edit
|
||||
;; sequence
|
||||
;; Must not be called when the editor is locked
|
||||
(define (finish-now)
|
||||
(unless stopped?
|
||||
(let loop ()
|
||||
|
@ -284,6 +295,47 @@
|
|||
(colorer-driver)
|
||||
(loop)))))
|
||||
|
||||
|
||||
;; Starts tokenizing the buffer.
|
||||
;;
|
||||
;; token-sym-style- will be passed the first return symbol from get-token-
|
||||
;; and should return the style-name that the token should be colored.
|
||||
;;
|
||||
;; get-token- takes an input port and returns the next token as 4 values:
|
||||
;; first, a symbol describing the type of the token. This symbol
|
||||
;; is transformed into a style-name via the token-sym->style-
|
||||
;; argument. The symbols 'white-space and 'comment have special
|
||||
;; meaning and should always be returned for white-space and comment
|
||||
;; tokens respectively.
|
||||
;; second, a symbol indicating how the token should be treated by the paren
|
||||
;; matcher. This symbol should be in the pairs- argument.
|
||||
;; third and fourth, the starting and ending position of the token.
|
||||
;; get-token- will usually be implemented with a lexer using the
|
||||
;; (lib "lex.ss" "parser-tools") library.
|
||||
;; get-token- must obey the following invariants:
|
||||
;; 1) Every position in the buffer must be accounted for in exactly one token.
|
||||
;; 2) The token returned by get-token- must rely only on the contents of the
|
||||
;; input port argument. This means that the tokenization of some part
|
||||
;; of the input cannot depend on earlier parts of the input.
|
||||
;; 3) No edit to the buffer can change the tokenization of the buffer
|
||||
;; prior to the token immediately preceeding the edit. In the following
|
||||
;; example this invariant does not hold. If the buffer contains:
|
||||
;; " 1 2 3
|
||||
;; and the tokenizer treats the unmatched " as its own token (a string error token),
|
||||
;; and separately tokenizes the 1 2 and 3, an edit to make the buffer look like:
|
||||
;; " 1 2 3" would result in a single string token modifying previous tokens.
|
||||
;; To handle these situations, get-token- must treat the first line as a single
|
||||
;; token.
|
||||
;; pairs- is a list of different kinds of matching parens. The second value returned
|
||||
;; by get-token- is compared to this list to see how the paren matcher should treat
|
||||
;; the token. An example: Suppose pairs is '((|(| |)|) (|[| |]|) (begin end)).
|
||||
;; This means that there are three kinds of parens. Any token which has 'begin as its
|
||||
;; second return value will act as an open for matching tokens with 'end.
|
||||
;; Similarly any token with '|]| will act as a closing match for tokens with '|[|.
|
||||
;;
|
||||
;; start-colorer: (symbol? -> string?) *
|
||||
;; (input-port? -> symbol? (union false? symbol?) natural-number? natural-number?) *
|
||||
;; (listof (list/p symbol? symbol?)) ->
|
||||
(define/public (start-colorer token-sym->style- get-token- pairs-)
|
||||
(unless force-stop?
|
||||
(set! stopped? #f)
|
||||
|
@ -295,14 +347,16 @@
|
|||
(set! parens (new paren-tree% (matches pairs)))
|
||||
(unless background-thread
|
||||
(break-enabled #f)
|
||||
(set! background-thread (thread (lambda () (background-colorer-entry))))
|
||||
(set! background-thread
|
||||
(thread (lambda () (background-colorer-entry))))
|
||||
(break-enabled #t))
|
||||
(do-insert/delete start-pos 0)))
|
||||
|
||||
;; Stop coloring and paren matching the buffer.
|
||||
(define/public stop-colorer
|
||||
(opt-lambda ((clear-colors #t))
|
||||
(set! stopped? #t)
|
||||
(when clear-colors
|
||||
(when (and clear-colors (not frozen?))
|
||||
(change-style (send (get-style-list) find-named-style "Standard")
|
||||
start-pos end-pos #f))
|
||||
(match-parens #t)
|
||||
|
@ -311,41 +365,64 @@
|
|||
(set! token-sym->style #f)
|
||||
(set! get-token #f)))
|
||||
|
||||
;; Keep the buffer tokenized and paren matched, but stop altering the colors.
|
||||
(define/public (freeze-colorer)
|
||||
(when (is-locked?)
|
||||
(error 'freeze-colorer "called on a locked color:text<%>."))
|
||||
#|
|
||||
(when (in-edit-sequence?)
|
||||
(error 'freeze-colorer "called on a color:text<%> while in an edit sequence."))
|
||||
|#
|
||||
(unless frozen?
|
||||
(finish-now)
|
||||
(set! frozen? #t)))
|
||||
|
||||
(define/public (thaw-colorer)
|
||||
(when frozen?
|
||||
(set! frozen? #f)
|
||||
(when restart-after-freeze
|
||||
(let ((tn token-sym->style)
|
||||
(gt get-token)
|
||||
(p pairs))
|
||||
(stop-colorer (not should-color?))
|
||||
(start-colorer tn gt p)))))
|
||||
|
||||
;; Start coloring the buffer again. If recolor? is #t, the buffer is re-colored. If it is #f
|
||||
;; the buffer is not recolored. When recolor? is #t, retokenize? controls how the buffer
|
||||
;; is recolored. #f causes the buffer to be entirely recolored before thaw returns using
|
||||
;; the existing tokenization. #t causes the entire buffer to be retokenized and recolored
|
||||
;; from scratch. This will happen in the background after the call to that-colorer returns.
|
||||
(define/public thaw-colorer
|
||||
(opt-lambda ((recolor? #t)
|
||||
(retokenize? #f))
|
||||
(when frozen?
|
||||
(set! frozen? #f)
|
||||
(cond
|
||||
(stopped?
|
||||
(stop-colorer))
|
||||
((or force-recolor-after-freeze recolor?)
|
||||
(cond
|
||||
(retokenize?
|
||||
(let ((tn token-sym->style)
|
||||
(gt get-token)
|
||||
(p pairs))
|
||||
(stop-colorer (not should-color?))
|
||||
(start-colorer tn gt p)))
|
||||
(else
|
||||
(begin-edit-sequence #f #f)
|
||||
(finish-now)
|
||||
(send tokens for-each
|
||||
(lambda (start len type)
|
||||
(when (and should-color? (not (eq? 'white-space type)))
|
||||
(let ((color (send (get-style-list) find-named-style
|
||||
(token-sym->style type)))
|
||||
(sp (+ start-pos start))
|
||||
(ep (+ start-pos (+ start len))))
|
||||
(change-style color sp ep #f)))))
|
||||
(end-edit-sequence))))))))
|
||||
|
||||
|
||||
(define/private (toggle-color on?)
|
||||
(cond
|
||||
((and frozen? (not (equal? on? should-color?)))
|
||||
(set! restart-after-freeze #t))
|
||||
(set! should-color? on?)
|
||||
(set! force-recolor-after-freeze #t))
|
||||
((and (not should-color?) on?)
|
||||
(set! should-color? #t)
|
||||
(set! should-color? on?)
|
||||
(reset-tokens)
|
||||
(do-insert/delete start-pos 0))
|
||||
((and should-color? (not on?))
|
||||
(set! should-color? #f)
|
||||
(set! should-color? on?)
|
||||
(change-style (send (get-style-list) find-named-style "Standard")
|
||||
start-pos end-pos #f))))
|
||||
|
||||
|
||||
;; Causes the entire tokenizing system to become inactive.
|
||||
(define/public (force-stop-colorer x)
|
||||
(set! force-stop? x)
|
||||
(when x
|
||||
|
@ -366,7 +443,8 @@
|
|||
(define (highlight start end caret-pos error?)
|
||||
(let ([off (highlight-range (+ start-pos start) (+ start-pos end)
|
||||
(if error? mismatch-color (get-match-color))
|
||||
(and (send (icon:get-paren-highlight-bitmap) ok?)
|
||||
(and (send (icon:get-paren-highlight-bitmap)
|
||||
ok?)
|
||||
(icon:get-paren-highlight-bitmap))
|
||||
(= caret-pos (+ start-pos start)))])
|
||||
(set! clear-old-locations
|
||||
|
@ -377,6 +455,10 @@
|
|||
|
||||
(define in-match-parens? #f)
|
||||
|
||||
;; the forward matcher signaled an error because not enough of the
|
||||
;; tree has been built.
|
||||
(define (f-match-false-error start end error)
|
||||
(and error (<= (+ start-pos error) current-pos) (not up-to-date?)))
|
||||
|
||||
;; If there is no match because the buffer isn't lexed yet, this will
|
||||
;; do nothing, but the edit sequence for changing color the colors
|
||||
|
@ -397,16 +479,82 @@
|
|||
(unless just-clear?
|
||||
(let* ((here (get-start-position)))
|
||||
(when (= here (get-end-position))
|
||||
(let-values (((start-f end-f error-f) (send parens match-forward (- here start-pos)))
|
||||
((start-b end-b error-b) (send parens match-backward (- here start-pos))))
|
||||
(when (and start-f end-f
|
||||
(not (and error-f (<= (+ start-pos error-f) current-pos) (not up-to-date?))))
|
||||
(let-values (((start-f end-f error-f)
|
||||
(send parens match-forward (- here start-pos)))
|
||||
((start-b end-b error-b)
|
||||
(send parens match-backward (- here start-pos))))
|
||||
(when (and start-f end-f
|
||||
(not (f-match-false-error start-f end-f error-f)))
|
||||
(highlight start-f end-f here error-f))
|
||||
(when (and start-b end-b)
|
||||
(highlight start-b end-b here error-b)))))))
|
||||
(end-edit-sequence)
|
||||
(set! in-match-parens? #f))))
|
||||
|
||||
|
||||
(define/public (forward-match position cutoff)
|
||||
(do-forward-match position cutoff #f))
|
||||
|
||||
(define (do-forward-match position cutoff skip-whitespace?)
|
||||
(let ((position
|
||||
(if skip-whitespace?
|
||||
(skip-whitespace position 'forward #t)
|
||||
position)))
|
||||
(let-values (((start end error)
|
||||
(send parens match-forward (- position start-pos))))
|
||||
(cond
|
||||
((f-match-false-error start end error)
|
||||
(colorer-driver)
|
||||
(do-forward-match position cutoff #f))
|
||||
((and start end (not error))
|
||||
(let ((match-pos (+ start-pos end)))
|
||||
(cond
|
||||
((<= match-pos cutoff) match-pos)
|
||||
(else #f))))
|
||||
(else #f)))))
|
||||
|
||||
|
||||
(define/public (backward-match position cutoff)
|
||||
(let ((position (skip-whitespace position 'backward #t)))
|
||||
(let-values (((start end error)
|
||||
(send parens match-backward (- position start-pos))))
|
||||
(cond
|
||||
((and start end (not error))
|
||||
(let ((match-pos (+ start-pos end)))
|
||||
(cond
|
||||
((>= match-pos cutoff) match-pos)
|
||||
(else #f))))
|
||||
(else #f)))))
|
||||
|
||||
(define (tokenize-to-pos position)
|
||||
(when (and (not up-to-date?) (<= current-pos position))
|
||||
(colorer-driver)
|
||||
(tokenize-to-pos position)))
|
||||
|
||||
(inherit last-position)
|
||||
|
||||
(define/public (skip-whitespace position direction comments?)
|
||||
(cond
|
||||
((and (eq? direction 'forward)
|
||||
(>= position (if (eq? 'end end-pos) (last-position) end-pos)))
|
||||
position)
|
||||
((and (eq? direction 'backward) (<= position start-pos))
|
||||
position)
|
||||
(else
|
||||
(let ((p (if (eq? direction 'backward) (sub1 position) position)))
|
||||
(tokenize-to-pos p)
|
||||
(send tokens search! (- p start-pos))
|
||||
(cond
|
||||
((or (eq? 'white-space (send tokens get-root-data))
|
||||
(and comments? (eq? 'comment (send tokens get-root-data))))
|
||||
(skip-whitespace (+ start-pos
|
||||
(if (eq? direction 'forward)
|
||||
(send tokens get-root-end-position)
|
||||
(send tokens get-root-start-position)))
|
||||
direction))
|
||||
(else p))))))
|
||||
|
||||
|
||||
;; ------------------------- Callbacks to Override ----------------------
|
||||
|
||||
(rename (super-lock lock))
|
||||
|
@ -483,14 +631,8 @@
|
|||
|
||||
(define text-mode-mixin
|
||||
(mixin (mode:surrogate-text<%>) (-text-mode<%>)
|
||||
;; get-token takes an input port and returns 4 values:
|
||||
;; A symbol in `(keyword string literal comment error identifier default)
|
||||
;; Data to be kept with the token
|
||||
;; The token's starting offset
|
||||
;; The token's ending offset
|
||||
;;
|
||||
;; matches is a list of lists of matching paren types.
|
||||
;; For example, '((|(| |)|) (|[| |]|))
|
||||
;; The arguments here are only used to be passed to start-colorer. Refer to its
|
||||
;; documentation.
|
||||
(init-field (get-token default-lexer)
|
||||
(token-sym->style (lambda (x) "Standard"))
|
||||
(matches null))
|
||||
|
|
Loading…
Reference in New Issue
Block a user