Skip to content

Commit d5b7524

Browse files
authored
Improve Resyntax integration (#196)
* Remove doc-walk-text call in doc-expand! * Remove walk-text methods * Make resyntax integration a independent module * Add Resyntax related functions to doc.rkt * Allow doc-code-action also return resyntax's result * Add more resyntax test * Add doc-resyntax-available? function to doc lib * Allow runs resyntax through places * Improve the exception handlers by only capture specific exceptions This allows break exception are handled correctly by outer handlers. * Disable resyntax test when it's not available * format resyntax test file * Make doc-diagnostics also return resyntax results * Clear saved resyntax results after each edit * Update scribble docs * Use a fallback slower version of interval-map-iterate-least/end>? in old Racket versions
1 parent 6133aaf commit d5b7524

File tree

18 files changed

+942
-108
lines changed

18 files changed

+942
-108
lines changed
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
(let ([logging-fail-thunk (λ ()
88
(log-info "symbol '~a' from module '~a' fail to load." 'name mod)
99
(fail-thunk))])
10-
(with-handlers ([exn? (λ (e)
11-
(logging-fail-thunk)
12-
(void))])
10+
(with-handlers ([exn:fail? (λ (_e)
11+
(logging-fail-thunk)
12+
(void))])
1313
(dynamic-require mod 'name logging-fail-thunk)))))
1414

1515
(define-syntax-rule (dynamic-import-mod mod names ... fail-thunk)
@@ -19,4 +19,3 @@
1919
(define-syntax-rule (dynamic-imports (mod names ...) ... fail-thunk)
2020
(begin
2121
(dynamic-import-mod mod names ... fail-thunk) ...))
22-

common/interfaces.rkt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
(provide (json-type-out Pos)
1818
(json-type-out Range)
19+
char-range-intersect?
1920
(json-type-out TextEdit)
2021
(json-type-out WorkspaceEdit)
2122
(json-type-out CodeAction)
@@ -53,7 +54,8 @@
5354
(struct-out SemanticToken)
5455
*semantic-token-types*
5556
*semantic-token-modifiers*
56-
abs-pos->Pos)
57+
abs-pos->Pos
58+
(json-type-out Resyntax-Result))
5759

5860
(define-json-struct Pos
5961
[line exact-nonnegative-integer?]
@@ -63,6 +65,15 @@
6365
[start Pos]
6466
[end Pos])
6567

68+
(define/contract (char-range-intersect? left-start left-end right-start right-end)
69+
(-> exact-nonnegative-integer?
70+
exact-nonnegative-integer?
71+
exact-nonnegative-integer?
72+
exact-nonnegative-integer?
73+
boolean?)
74+
(and (< left-start right-end)
75+
(< right-start left-end)))
76+
6677
(define-json-struct TextEdit
6778
[range Range]
6879
[newText string?])
@@ -275,3 +286,11 @@
275286
(match-define (list line char) (send editor pos->line/char pos))
276287
(Pos #:line line #:char char))
277288

289+
;; Resyntax-Result: result of a resyntax refactoring suggestion
290+
(define-json-struct Resyntax-Result
291+
[start exact-nonnegative-integer?]
292+
[end exact-nonnegative-integer?]
293+
[message string?]
294+
[rule-name symbol?]
295+
[new-text string?])
296+

doclib/autocomplete.rkt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
(define (walk stx)
1616
(append
1717
(set->list (user-defined:walk stx))
18-
(with-handlers ([(λ (_exn) #t) (λ (_) '())])
18+
(with-handlers ([exn:fail? (λ (_) '())])
1919
(set->list (required:walk-module stx)))))
2020

2121
;; Get completions that will be computed for every text change.

doclib/check-syntax.rkt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
[current-namespace ns]
4040
[current-annotations collector])
4141
(define stx
42-
(with-handlers ([(λ _ #t) (λ (exn) exn)])
42+
(with-handlers ([exn:fail? (λ (exn) exn)])
4343
(with-module-reading-parameterization
4444
(λ () (read-syntax path in)))))
4545

@@ -48,7 +48,7 @@
4848
(with-intercepted-logging
4949
(λ (log) (set! expand-logs (cons log expand-logs)))
5050
(λ ()
51-
(with-handlers ([(λ _ #t) (λ (exn) exn)])
51+
(with-handlers ([exn:fail? (λ (exn) exn)])
5252
(parameterize ([current-output-port (open-output-nowhere)])
5353
(if (syntax? stx)
5454
(expand stx)

doclib/doc-trace.rkt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@
5252
(for ([s services])
5353
(send s walk-stx expand-result)))
5454

55-
(define/public (walk-text text)
56-
(for ([s services])
57-
(send s walk-text text)))
58-
5955
(define/public (walk-log text)
6056
(for ([s services])
6157
(send s walk-log text)))

doclib/doc.rkt

Lines changed: 112 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
syntax-color/module-lexer
2323
syntax-color/racket-lexer
2424
"check-syntax.rkt"
25+
"external/resyntax.rkt"
2526
"docs-helpers.rkt"
2627
"documentation-parser.rkt"
2728
drracket/check-syntax
@@ -32,7 +33,8 @@
3233
[text (is-a?/c lsp-editor%)]
3334
[trace (is-a?/c build-trace%)]
3435
[version exact-nonnegative-integer?]
35-
[trace-version (or/c false/c exact-nonnegative-integer?)])
36+
[trace-version (or/c false/c exact-nonnegative-integer?)]
37+
[resyntax-results (listof Resyntax-Result?)])
3638
#:mutable)
3739

3840
(define/contract (make-doc uri text [version 0])
@@ -43,7 +45,57 @@
4345
(send doc-text insert text 0)
4446
;; the init trace should not be #f
4547
(define doc-trace (new build-trace% [src (uri->path uri)] [doc-text doc-text] [indenter #f]))
46-
(Doc uri doc-text doc-trace version #f))
48+
(Doc uri doc-text doc-trace version #f (list)))
49+
50+
(define (invalidate-resyntax-results! doc)
51+
(set-Doc-resyntax-results! doc (list)))
52+
53+
(define/contract (doc-get-resyntax-results doc)
54+
(-> Doc? (listof Resyntax-Result?))
55+
(Doc-resyntax-results doc))
56+
57+
(define/contract (doc-update-resyntax-result! doc results)
58+
(-> Doc? (listof Resyntax-Result?) void?)
59+
(set-Doc-resyntax-results! doc results))
60+
61+
(define/contract (resyntax-result->diag doc res)
62+
(-> Doc? Resyntax-Result? Diagnostic?)
63+
(define range
64+
(Range #:start (doc-abs-pos->pos doc (Resyntax-Result-start res))
65+
#:end (doc-abs-pos->pos doc (Resyntax-Result-end res))))
66+
(Diagnostic #:range range
67+
#:severity DiagnosticSeverity-Information
68+
#:source "Resyntax"
69+
#:message (format "[~a] ~a" (Resyntax-Result-rule-name res) (Resyntax-Result-message res))))
70+
71+
(define/contract (resyntax-result->code-action doc res)
72+
(-> Doc? Resyntax-Result? CodeAction?)
73+
(define diag (resyntax-result->diag doc res))
74+
(define doc-uri (Doc-uri doc))
75+
(define range (Diagnostic-range diag))
76+
(CodeAction
77+
#:title (format "Apply rule [~a]" (Resyntax-Result-rule-name res))
78+
#:kind "quickfix"
79+
#:diagnostics (list diag)
80+
#:isPreferred #f
81+
#:edit (WorkspaceEdit
82+
#:changes
83+
(hasheq (string->symbol doc-uri)
84+
(list (TextEdit #:range range
85+
#:newText (Resyntax-Result-new-text res)))))))
86+
87+
(define/contract (doc-resyntax doc)
88+
(-> Doc? (listof Resyntax-Result?))
89+
(run-resyntax (send (Doc-text doc) get-text) (Doc-uri doc)))
90+
91+
(define/contract (doc-resyntax! doc)
92+
(-> Doc? void?)
93+
(define results (doc-resyntax doc))
94+
(doc-update-resyntax-result! doc results))
95+
96+
(define/contract (doc-resyntax-available?)
97+
(-> boolean?)
98+
(resyntax-available?))
4799

48100
(define/contract (doc-update-version! doc new-ver)
49101
(-> Doc? exact-nonnegative-integer? void?)
@@ -58,6 +110,7 @@
58110
(define doc-text (Doc-text doc))
59111
(define doc-trace (Doc-trace doc))
60112

113+
(invalidate-resyntax-results! doc)
61114
(send doc-text erase)
62115
(send doc-trace reset)
63116
(send doc-text insert new-text 0))
@@ -72,6 +125,7 @@
72125
(define old-len (- end-pos st-pos))
73126
(define new-len (string-length text))
74127

128+
(invalidate-resyntax-results! doc)
75129
;; try reuse old information as the check-syntax can fail
76130
;; and return the old build-trace% object
77131
(cond [(> new-len old-len) (send doc-trace expand end-pos (+ st-pos new-len))]
@@ -121,18 +175,12 @@
121175
(-> Doc? boolean?)
122176
(equal? (Doc-version doc) (Doc-trace-version doc)))
123177

124-
(define/contract (doc-walk-text trace text)
125-
(-> (is-a?/c build-trace%) string? void?)
126-
(send trace walk-text text))
127-
128178
(define/contract (doc-expand! doc)
129179
(-> Doc? boolean?)
130180
(define result (doc-expand (Doc-uri doc) (Doc-text doc)))
131181
(define new-trace (CSResult-trace result))
132182
(cond [(CSResult-succeed? result)
133-
(define text (CSResult-text result))
134183
(doc-update-trace! doc new-trace (Doc-version doc))
135-
(doc-walk-text new-trace text)
136184
#t]
137185
[else #f]))
138186

@@ -163,12 +211,43 @@
163211

164212
(define/contract (doc-diagnostics doc)
165213
(-> Doc? (listof Diagnostic?))
166-
(set->list (send (Doc-trace doc) get-warn-diags)))
214+
(append (set->list (send (Doc-trace doc) get-warn-diags))
215+
(for/list ([res (in-list (doc-get-resyntax-results doc))])
216+
(resyntax-result->diag doc res))))
167217

168218
(define/contract (doc-copy-text-buffer doc)
169219
(-> Doc? (is-a?/c lsp-editor%))
170220
(send (Doc-text doc) copy))
171221

222+
(define (interval-map-iterate-least/end>?/fallback intervals end)
223+
(let loop ([iter (interval-map-iterate-first intervals)])
224+
(cond
225+
[(not iter) #f]
226+
[else
227+
(match-define (cons _ interval-end)
228+
(interval-map-iterate-key intervals iter))
229+
(if (> interval-end end)
230+
iter
231+
(loop (interval-map-iterate-next intervals iter)))])))
232+
233+
(define maybe-interval-map-iterate-least/end>?
234+
(dynamic-require 'data/interval-map
235+
'interval-map-iterate-least/end>?
236+
(lambda () interval-map-iterate-least/end>?/fallback)))
237+
238+
(define (interval-map-overlap-values intervals start end)
239+
(let loop ([iter (maybe-interval-map-iterate-least/end>? intervals start)]
240+
[values (list)])
241+
(cond
242+
[(not iter) (reverse values)]
243+
[else
244+
(match-define (cons interval-start _)
245+
(interval-map-iterate-key intervals iter))
246+
(if (>= interval-start end)
247+
(reverse values)
248+
(loop (interval-map-iterate-next intervals iter)
249+
(cons (interval-map-iterate-value intervals iter) values)))])))
250+
172251
;; TODO: Use lexer/token info here instead of scanning raw characters.
173252
(define/contract (doc-find-containing-paren doc pos)
174253
(-> Doc? exact-nonnegative-integer? (or/c exact-nonnegative-integer? #f))
@@ -459,11 +538,23 @@
459538
(define/contract (doc-code-action doc range)
460539
(-> Doc? Range? (listof CodeAction?))
461540
(define doc-trace (Doc-trace doc))
462-
(define act
463-
(interval-map-ref (send doc-trace get-quickfixs)
464-
(doc-pos->abs-pos doc (Range-start range))
465-
#f))
466-
(if act (list act) (list)))
541+
(define req-start (doc-pos->abs-pos doc (Range-start range)))
542+
(define req-end (doc-pos->abs-pos doc (Range-end range)))
543+
(define trace-actions
544+
(interval-map-overlap-values (send doc-trace get-quickfixs)
545+
req-start
546+
req-end))
547+
548+
(define resyntax-actions
549+
(for/list ([res (in-list (doc-get-resyntax-results doc))]
550+
#:when (char-range-intersect?
551+
req-start
552+
req-end
553+
(Resyntax-Result-start res)
554+
(Resyntax-Result-end res)))
555+
(resyntax-result->code-action doc res)))
556+
557+
(append trace-actions resyntax-actions))
467558

468559
(define/contract (doc-signature-help doc pos)
469560
(-> Doc? Pos? (or/c SignatureHelp? #f))
@@ -671,7 +762,13 @@
671762
doc-update-trace!
672763
doc-trace-latest?
673764
doc-expand!
674-
doc-walk-text
765+
doc-resyntax
766+
doc-resyntax!
767+
doc-resyntax-available?
768+
doc-get-resyntax-results
769+
doc-update-resyntax-result!
770+
resyntax-result->diag
771+
resyntax-result->code-action
675772
doc-hover
676773
doc-code-action
677774
doc-signature-help

doclib/editor.rkt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
;; insert str at start
1919
(define/public (insert str start)
20-
(with-handlers ([exn?
20+
(with-handlers ([exn:fail?
2121
(λ _
2222
(reload!)
2323
;; only retry once
@@ -26,7 +26,7 @@
2626

2727
;; replace text at (range start end) with str
2828
(define/public (replace str start end)
29-
(with-handlers ([exn?
29+
(with-handlers ([exn:fail?
3030
(λ _
3131
(reload!)
3232
;; only retry once
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
#lang racket/base
22

3-
(provide resyntax)
3+
(provide run-resyntax
4+
resyntax-available?)
45

5-
(require racket/set
6-
data/interval-map
7-
"../../common/interfaces.rkt"
8-
"../../common/path-util.rkt"
9-
"dynamic-import.rkt")
6+
(require "../../common/dynamic-import.rkt"
7+
"../../common/interfaces.rkt")
108

119
(define has-resyntax? #t)
1210

11+
(define (resyntax-available?)
12+
has-resyntax?)
13+
1314
(define (disable-resyntax!)
1415
(set! has-resyntax? #f))
1516

@@ -37,12 +38,12 @@
3738
resyntax-analyze)
3839
disable-resyntax!)
3940

41+
(define (run-resyntax text _src)
42+
(if has-resyntax?
43+
(run-resyntax-impl text)
44+
(list)))
4045

41-
(define (resyntax text doc-text src warn-diags quickfixs)
42-
(when has-resyntax?
43-
(resyntax-impl text doc-text src warn-diags quickfixs)))
44-
45-
(define (resyntax-impl text doc-text src warn-diags quickfixs)
46+
(define (run-resyntax-impl text)
4647
(define text-source (string-source text))
4748
(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
4849
(define result-set
@@ -51,34 +52,11 @@
5152
#:suite default-recommendations
5253
#:lines all-lines))
5354

54-
(define (add result)
55+
(for/list ([result (in-list (refactoring-result-set-results result-set))])
5556
(define sr (refactoring-result-string-replacement result))
5657
(define char-start (string-replacement-start sr))
5758
(define char-end (string-replacement-original-end sr))
5859
(define message (refactoring-result-message result))
59-
(define range (Range #:start (abs-pos->Pos doc-text char-start)
60-
#:end (abs-pos->Pos doc-text char-end)))
6160
(define new-text (string-replacement-render sr (source->string text-source)))
62-
6361
(define rule-name (refactoring-result-rule-name result))
64-
(define diag
65-
(Diagnostic #:range range
66-
#:severity DiagnosticSeverity-Information
67-
#:source "Resyntax"
68-
#:message (format "[~a] ~a" rule-name message)))
69-
(define code-action
70-
(CodeAction
71-
#:title (format "Apply rule [~a]" rule-name)
72-
#:kind "quickfix"
73-
#:diagnostics (list diag)
74-
#:isPreferred #f
75-
#:edit (WorkspaceEdit
76-
#:changes
77-
(hasheq (string->symbol (path->uri src))
78-
(list (TextEdit #:range range
79-
#:newText new-text))))))
80-
(set-add! warn-diags diag)
81-
(interval-map-set! quickfixs char-start char-end code-action))
82-
83-
(for-each add (refactoring-result-set-results result-set)))
84-
62+
(Resyntax-Result char-start char-end message rule-name new-text)))

0 commit comments

Comments
 (0)