11import * as vscode from "vscode" ;
22import { genMarkdownString , getColorTokenValue } from "./utils" ;
33
4+ interface DecorationItem {
5+ line : number ;
6+ disposable : vscode . TextEditorDecorationType ;
7+ }
8+
49export default function setupChangeEvent (
510 context : vscode . ExtensionContext ,
611 fullToken : any
712) {
813 let timeout : NodeJS . Timer | undefined = undefined ;
914 let activeEditor = vscode . window . activeTextEditor ;
1015 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 ;
1219
1320 if ( activeEditor ) {
14- triggerUpdateDecorations ( ) ;
21+ lineCount = activeEditor . document . lineCount ;
22+ const isOpened = checkOpenedFile ( activeEditor . document . fileName ) ;
23+
24+ if ( ! isOpened ) {
25+ triggerUpdateDecorations ( ) ;
26+ }
1527 }
1628
1729 vscode . workspace . onDidChangeTextDocument (
1830 ( 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+
1938 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 ) ;
2148 }
2249 } ,
2350 null ,
@@ -28,78 +55,156 @@ export default function setupChangeEvent(
2855 ( editor ) => {
2956 activeEditor = editor ;
3057 if ( editor ) {
31- triggerUpdateDecorations ( ) ;
58+ lineCount = editor . document . lineCount ;
59+ const isOpened = checkOpenedFile ( editor . document . fileName ) ;
60+
61+ if ( ! isOpened ) {
62+ triggerUpdateDecorations ( ) ;
63+ }
3264 }
3365 } ,
3466 null ,
3567 context . subscriptions
3668 ) ;
3769
38- function triggerUpdateDecorations ( throttle = false ) {
70+ function triggerUpdateDecorations (
71+ throttle = false ,
72+ isEdit = false ,
73+ startLine ?: number ,
74+ endLine ?: number
75+ ) {
3976 if ( timeout ) {
4077 clearTimeout ( timeout ) ;
4178 timeout = undefined ;
4279 }
4380 if ( throttle ) {
44- timeout = setTimeout ( updateDecorations , 500 ) ;
81+ timeout = setTimeout ( ( ) => {
82+ updateDecorations ( isEdit , startLine , endLine ) ;
83+ } , 500 ) ;
4584 } else {
46- updateDecorations ( ) ;
85+ updateDecorations ( isEdit , startLine , endLine ) ;
4786 }
4887 }
4988
50- function updateDecorations ( ) {
89+ function updateDecorations (
90+ isEdit : boolean ,
91+ startLine ?: number ,
92+ endLine ?: number
93+ ) {
5194 if ( activeEditor ) {
95+ console . log ( "!!!!!!update!!!!" , startLine , endLine ) ;
5296 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+ // }
56132
57133 fullTokenKeys . forEach ( ( key : string ) => {
58134 if ( ! activeEditor ) {
59135 return ;
60136 }
137+
61138 const regEx = new RegExp ( `\\b(${ key } )\\b(?!-)` , "g" ) ;
62139
63140 let match ;
64141 while ( ( match = regEx . exec ( text ) ) ) {
65142 const valueDecorations : vscode . DecorationOptions [ ] = [ ] ;
66143 let decorationType : vscode . TextEditorDecorationType ;
67144
145+ /**
146+ * TIPS:
147+ * Actually, they are always at the same line.
148+ */
68149 const startPos = activeEditor . document . positionAt ( match . index ) ;
69150 const endPos = activeEditor . document . positionAt (
70151 match . index + match [ 0 ] . length
71152 ) ;
153+ const currentLine = startPos . line ;
72154
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+ }
101196 }
102197 } ) ;
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 ;
103208 }
104209 }
105210}
0 commit comments