-
-
Notifications
You must be signed in to change notification settings - Fork 24
/
highlight.rkt
159 lines (136 loc) · 5.24 KB
/
highlight.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#lang racket/base
(require drracket/check-syntax
syntax/parse
"struct.rkt"
racket/class
racket/set
racket/list
racket/bool
racket/match
"expand.rkt")
(provide collect-semantic-tokens)
;; A temporary structure to hold tokens
;; `tag` is symbol that is a tag associated with this token.
;; An identifier may correspond multiple tokens. They will be merged, then converted into
;; lsp semantic token types and modifiers.
(struct Token
(start end tag))
(define collector%
(class (annotations-mixin object%)
(define styles '())
(super-new)
(define/override (syncheck:find-source-object stx)
#f)
(define/override (syncheck:color-range src start end style)
(when (< start end)
(set! styles (cons (Token start end (string->symbol style)) styles))))
(define/override (syncheck:add-definition-target src start finish id mods)
(when (< start finish)
(set! styles (cons (Token start finish 'definition) styles))))
(define/public (get-styles)
(set->list (list->set styles)))))
; (-> lsp-editor% Path (Listof SemanticToken))
(define (collect-semantic-tokens doc-text path)
(define code-str (send doc-text get-text))
(define in (open-input-string code-str))
(port-count-lines! in)
(define collector (new collector%))
(match-define (list stx expanded) (sync (read-and-expand in path collector)))
(define drracket-styles (convert-drracket-color-styles (send collector get-styles)))
(define token-list
(append drracket-styles
(if (syntax? stx) (walk-stx stx) '())
(if (syntax? expanded) (walk-expanded-stx path expanded) '())))
(let* ([tokens-no-false (filter-not false? token-list)]
[tokens-no-out-bounds (filter (λ (t) (< -1 (Token-start t) (string-length code-str)))
tokens-no-false)]
[tokens-in-order (sort tokens-no-out-bounds < #:key Token-start)]
[same-ident-token-groups (group-by Token-start tokens-in-order)]
[tokens-with-merged-tags
(for/list ([token-group same-ident-token-groups])
(define tok (first token-group))
(list (Token-start tok) (Token-end tok) (map Token-tag token-group)))]
[result-tokens
(for*/list ([t tokens-with-merged-tags]
[type (in-value (select-type (third t)))]
[modifiers (in-value (get-valid-modifiers (third t)))]
#:when (not (false? type)))
(SemanticToken (first t) (second t) type modifiers))])
result-tokens))
(define (convert-drracket-color-styles styles)
(for/list ([s styles])
(match s
[(Token start end 'drracket:check-syntax:lexically-bound)
(Token start end 'variable)]
[(Token start end 'drracket:check-syntax:set!d)
(Token start end 'variable)]
[_ #f])))
;; `tags` might contains multiple valid types.
;; This function selects a proper type based on some rules.
(define (select-type tags)
(define valid-types (filter (λ (t) (memq t *semantic-token-types*)) tags))
(cond [(null? valid-types)
#f]
[(memq 'function valid-types)
'function]
[(memq 'variable valid-types)
'variable]
[else (first valid-types)]))
(define (get-valid-modifiers tags)
(filter (λ (t) (memq t *semantic-token-modifiers*)) tags))
(define (walk-stx stx)
(syntax-parse stx
#:datum-literals (#%module-begin)
[() (list)]
[(any1 any* ...)
(append (walk-stx #'any1)
(walk-stx #'(any* ...)))]
[#(any1 any* ...)
(append (walk-stx #'any1)
(walk-stx #'(any* ...)))]
[#%module-begin
(list)]
[atom (list (tag-of-atom-stx #'atom))]))
(define (walk-expanded-stx src stx)
(syntax-parse stx
#:datum-literals (lambda define-values #%app)
[(lambda (args ...) expr ...)
(walk-expanded-stx src #'(expr ...))]
[(define-values (fs) (lambda _ ...))
(append (list (tag-of-expanded-symbol-stx src #'fs 'function))
(walk-expanded-stx src (drop (syntax-e stx) 2)))]
[(define-values (names ...) expr)
(walk-expanded-stx src #'expr)]
[(#%app proc args ...)
(append (list (tag-of-expanded-symbol-stx src #'proc 'function))
(walk-expanded-stx src #'(args ...)))]
[(any1 any* ...)
(append (walk-expanded-stx src #'any1)
(walk-expanded-stx src #'(any* ...)))]
[_ (list)]))
(define (tag-of-expanded-symbol-stx src stx tag)
(define (in-current-file? stx)
(equal? src (syntax-source stx)))
(if (and (in-current-file? stx)
(symbol? (syntax->datum stx)))
(tag-of-atom-stx stx tag)
#f))
(define (tag-of-atom-stx atom-stx [expect-tag #f])
(define pos+1 (syntax-position atom-stx))
(define len (syntax-span atom-stx))
(if (or (not pos+1) (not len) (= len 0)
(not (syntax-original? atom-stx)))
#f
(let ([pos (sub1 pos+1)])
(Token pos (+ pos len)
(if (false? expect-tag)
(get-atom-tag (syntax-e atom-stx))
expect-tag)))))
(define (get-atom-tag atom)
(match atom
[(? number?) 'number]
[(? symbol?) 'symbol]
[(? string?) 'string]
[(? bytes?) 'string]
[(? regexp?) 'regexp]
[_ 'unknown]))