1
1
import * as vscode from "vscode" ;
2
2
import { genMarkdownString , getColorTokenValue } from "./utils" ;
3
3
4
+ interface DecorationItem {
5
+ line : number ;
6
+ disposable : vscode . TextEditorDecorationType ;
7
+ }
8
+
4
9
export default function setupChangeEvent (
5
10
context : vscode . ExtensionContext ,
6
11
fullToken : any
7
12
) {
8
13
let timeout : NodeJS . Timer | undefined = undefined ;
9
14
let activeEditor = vscode . window . activeTextEditor ;
10
15
const fullTokenKeys = Object . keys ( fullToken ) ;
11
- const decorationSet = new Set < vscode . TextEditorDecorationType > ( ) ;
16
+ const fileDecorationMap = new Map < string , DecorationItem [ ] > ( ) ;
17
+ const openedFileNameSet = new Set < string > ( ) ;
18
+ let lineCount = 0 ;
12
19
13
20
if ( activeEditor ) {
14
- triggerUpdateDecorations ( ) ;
21
+ lineCount = activeEditor . document . lineCount ;
22
+ const isOpened = checkOpenedFile ( activeEditor . document . fileName ) ;
23
+
24
+ if ( ! isOpened ) {
25
+ triggerUpdateDecorations ( ) ;
26
+ }
15
27
}
16
28
17
29
vscode . workspace . onDidChangeTextDocument (
18
30
( event ) => {
31
+ if ( event . contentChanges . length === 0 ) {
32
+ return ;
33
+ }
34
+
35
+ const startLine = event . contentChanges [ 0 ] . range . start . line ;
36
+ let endLine = event . contentChanges [ 0 ] . range . end . line ;
37
+
19
38
if ( activeEditor && event . document === activeEditor . document ) {
20
- triggerUpdateDecorations ( true ) ;
39
+ /**
40
+ * As undo (reason === 1) or redo (reason === 2) are very fast, do it very fast too.
41
+ * Same as `delete` some code
42
+ */
43
+ const throttle =
44
+ event . reason !== undefined
45
+ ? false
46
+ : event . document . lineCount - lineCount >= 0 ;
47
+ triggerUpdateDecorations ( throttle , true , startLine , endLine ) ;
21
48
}
22
49
} ,
23
50
null ,
@@ -28,78 +55,156 @@ export default function setupChangeEvent(
28
55
( editor ) => {
29
56
activeEditor = editor ;
30
57
if ( editor ) {
31
- triggerUpdateDecorations ( ) ;
58
+ lineCount = editor . document . lineCount ;
59
+ const isOpened = checkOpenedFile ( editor . document . fileName ) ;
60
+
61
+ if ( ! isOpened ) {
62
+ triggerUpdateDecorations ( ) ;
63
+ }
32
64
}
33
65
} ,
34
66
null ,
35
67
context . subscriptions
36
68
) ;
37
69
38
- function triggerUpdateDecorations ( throttle = false ) {
70
+ function triggerUpdateDecorations (
71
+ throttle = false ,
72
+ isEdit = false ,
73
+ startLine ?: number ,
74
+ endLine ?: number
75
+ ) {
39
76
if ( timeout ) {
40
77
clearTimeout ( timeout ) ;
41
78
timeout = undefined ;
42
79
}
43
80
if ( throttle ) {
44
- timeout = setTimeout ( updateDecorations , 500 ) ;
81
+ timeout = setTimeout ( ( ) => {
82
+ updateDecorations ( isEdit , startLine , endLine ) ;
83
+ } , 500 ) ;
45
84
} else {
46
- updateDecorations ( ) ;
85
+ updateDecorations ( isEdit , startLine , endLine ) ;
47
86
}
48
87
}
49
88
50
- function updateDecorations ( ) {
89
+ function updateDecorations (
90
+ isEdit : boolean ,
91
+ startLine ?: number ,
92
+ endLine ?: number
93
+ ) {
51
94
if ( activeEditor ) {
95
+ console . log ( "!!!!!!update!!!!" , startLine , endLine ) ;
52
96
const text = activeEditor . document . getText ( ) ;
53
- decorationSet . forEach ( ( value ) => {
54
- value . dispose ( ) ;
55
- } ) ;
97
+ const fileName = activeEditor . document . fileName ;
98
+
99
+ if ( ! fileDecorationMap . has ( fileName ) ) {
100
+ fileDecorationMap . set ( fileName , [ ] ) ;
101
+ }
102
+
103
+ const currentFileDecorations = fileDecorationMap . get ( fileName ) || [ ] ;
104
+ const currentLineCount = activeEditor . document . lineCount ;
105
+ const diffLine = currentLineCount - lineCount ;
106
+ console . log ( "diffLine" , diffLine ) ;
107
+ lineCount = currentLineCount ;
108
+
109
+ /**
110
+ * Dispose the line decoration between start and end
111
+ */
112
+ if (
113
+ startLine &&
114
+ endLine &&
115
+ currentFileDecorations . length &&
116
+ diffLine <= 0
117
+ ) {
118
+ for ( let i = startLine ; i <= endLine ; i ++ ) {
119
+ for ( let j = 0 ; j < currentFileDecorations . length ; j ++ ) {
120
+ if ( currentFileDecorations [ j ] . line === i ) {
121
+ currentFileDecorations [ j ] . disposable . dispose ( ) ;
122
+ console . log ( "dispose" , i ) ;
123
+ currentFileDecorations . splice ( j -- , 1 ) ;
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ // if (diffLine > 0) {
130
+ // return;
131
+ // }
56
132
57
133
fullTokenKeys . forEach ( ( key : string ) => {
58
134
if ( ! activeEditor ) {
59
135
return ;
60
136
}
137
+
61
138
const regEx = new RegExp ( `\\b(${ key } )\\b(?!-)` , "g" ) ;
62
139
63
140
let match ;
64
141
while ( ( match = regEx . exec ( text ) ) ) {
65
142
const valueDecorations : vscode . DecorationOptions [ ] = [ ] ;
66
143
let decorationType : vscode . TextEditorDecorationType ;
67
144
145
+ /**
146
+ * TIPS:
147
+ * Actually, they are always at the same line.
148
+ */
68
149
const startPos = activeEditor . document . positionAt ( match . index ) ;
69
150
const endPos = activeEditor . document . positionAt (
70
151
match . index + match [ 0 ] . length
71
152
) ;
153
+ const currentLine = startPos . line ;
72
154
73
- const value = String ( fullToken [ key ] ) ;
74
- const colorSpan = genMarkdownString ( value ) ;
75
- const markDownString = new vscode . MarkdownString (
76
- `<h3>antd design token: ${ match [ 0 ] } </h3>${ colorSpan } <code>${ value } </code><br></br>`
77
- ) ;
78
- markDownString . supportHtml = true ;
79
- markDownString . isTrusted = true ;
80
-
81
- const decoration = {
82
- range : new vscode . Range ( startPos , endPos ) ,
83
- hoverMessage : markDownString ,
84
- } ;
85
-
86
- const colorValue = getColorTokenValue ( fullToken [ key ] ) ;
87
- valueDecorations . push ( decoration ) ;
88
-
89
- decorationType = vscode . window . createTextEditorDecorationType ( {
90
- after : {
91
- contentText : colorValue ? `**` : `(${ String ( fullToken [ key ] ) } )` ,
92
- backgroundColor : colorValue || "" ,
93
- margin : "0 0 0 4px;" ,
94
- color : colorValue || "#1890ff" ,
95
- fontWeight : "bolder" ,
96
- } ,
97
- } ) ;
98
-
99
- decorationSet . add ( decorationType ) ;
100
- activeEditor . setDecorations ( decorationType , valueDecorations ) ;
155
+ if (
156
+ ! isEdit ||
157
+ // diffLine > 0 ||
158
+ ( startLine &&
159
+ endLine &&
160
+ currentLine >= startLine &&
161
+ currentLine <= endLine )
162
+ ) {
163
+ const value = String ( fullToken [ key ] ) ;
164
+ const colorSpan = genMarkdownString ( value ) ;
165
+ const markDownString = new vscode . MarkdownString (
166
+ `<h3>antd design token: ${ match [ 0 ] } </h3>${ colorSpan } <code>${ value } </code><br></br>`
167
+ ) ;
168
+ markDownString . supportHtml = true ;
169
+ markDownString . isTrusted = true ;
170
+
171
+ const decoration = {
172
+ range : new vscode . Range ( startPos , endPos ) ,
173
+ hoverMessage : markDownString ,
174
+ } ;
175
+
176
+ const colorValue = getColorTokenValue ( fullToken [ key ] ) ;
177
+ valueDecorations . push ( decoration ) ;
178
+
179
+ decorationType = vscode . window . createTextEditorDecorationType ( {
180
+ after : {
181
+ contentText : colorValue ? `**` : `(${ String ( fullToken [ key ] ) } )` ,
182
+ backgroundColor : colorValue || "" ,
183
+ margin : "0 0 0 4px;" ,
184
+ color : colorValue || "#1890ff" ,
185
+ fontWeight : "bolder" ,
186
+ } ,
187
+ } ) ;
188
+
189
+ currentFileDecorations . push ( {
190
+ line : currentLine ,
191
+ disposable : decorationType ,
192
+ } ) ;
193
+ console . log ( "setDecorations" , currentLine ) ;
194
+ activeEditor . setDecorations ( decorationType , valueDecorations ) ;
195
+ }
101
196
}
102
197
} ) ;
198
+ fileDecorationMap . set ( fileName , currentFileDecorations ) ;
199
+ }
200
+ }
201
+
202
+ function checkOpenedFile ( fileName : string ) : boolean {
203
+ if ( openedFileNameSet . has ( fileName ) ) {
204
+ return true ;
205
+ } else {
206
+ openedFileNameSet . add ( fileName ) ;
207
+ return false ;
103
208
}
104
209
}
105
210
}
0 commit comments