Skip to content

Commit 8f0d559

Browse files
committed
feat: add decorator
2 parents 567f39a + dcf862d commit 8f0d559

File tree

1 file changed

+151
-0
lines changed

1 file changed

+151
-0
lines changed

src/decorator.ts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import * as vscode from "vscode";
2+
import { genMarkdownString, getColorTokenValue } from "./utils";
3+
4+
export default function setupChangeEvent(
5+
context: vscode.ExtensionContext,
6+
fullToken: any
7+
) {
8+
let timeout: NodeJS.Timer | undefined = undefined;
9+
let activeEditor = vscode.window.activeTextEditor;
10+
const fullTokenKeys = Object.keys(fullToken);
11+
const fileDecorationMap = new Map<
12+
string,
13+
vscode.TextEditorDecorationType[]
14+
>();
15+
const openedFileNameSet = new Set<string>();
16+
17+
if (activeEditor) {
18+
const isOpened = checkOpenedFile(activeEditor.document.fileName);
19+
20+
if (!isOpened) {
21+
triggerUpdateDecorations();
22+
}
23+
}
24+
25+
vscode.workspace.onDidChangeTextDocument(
26+
(event) => {
27+
if (event.contentChanges.length === 0) {
28+
return;
29+
}
30+
31+
if (activeEditor && event.document === activeEditor.document) {
32+
/**
33+
* As undo (reason === 1) or redo (reason === 2) are very fast, do it very fast too.
34+
*/
35+
triggerUpdateDecorations(true);
36+
}
37+
},
38+
null,
39+
context.subscriptions
40+
);
41+
42+
vscode.window.onDidChangeActiveTextEditor(
43+
(editor) => {
44+
activeEditor = editor;
45+
if (editor) {
46+
const isOpened = checkOpenedFile(editor.document.fileName);
47+
48+
if (!isOpened) {
49+
triggerUpdateDecorations();
50+
}
51+
}
52+
},
53+
null,
54+
context.subscriptions
55+
);
56+
57+
function triggerUpdateDecorations(throttle = false) {
58+
if (timeout) {
59+
clearTimeout(timeout);
60+
timeout = undefined;
61+
}
62+
if (throttle) {
63+
timeout = setTimeout(() => {
64+
updateDecorations();
65+
}, 500);
66+
} else {
67+
updateDecorations();
68+
}
69+
}
70+
71+
function updateDecorations() {
72+
if (activeEditor) {
73+
const text = activeEditor.document.getText();
74+
const fileName = activeEditor.document.fileName;
75+
let currentFileDecorations = fileDecorationMap.get(fileName) || [];
76+
77+
/**
78+
* Dispose the line decoration between start and end
79+
*/
80+
if (currentFileDecorations.length) {
81+
currentFileDecorations.forEach((item) => {
82+
item.dispose();
83+
});
84+
currentFileDecorations = [];
85+
}
86+
87+
fullTokenKeys.forEach((key: string) => {
88+
if (!activeEditor) {
89+
return;
90+
}
91+
92+
const regEx = new RegExp(`\\b(${key})\\b(?!-)`, "g");
93+
94+
let match;
95+
while ((match = regEx.exec(text))) {
96+
const valueDecorations: vscode.DecorationOptions[] = [];
97+
let decorationType: vscode.TextEditorDecorationType;
98+
99+
/**
100+
* TIPS:
101+
* Actually, they are always at the same line.
102+
*/
103+
const startPos = activeEditor.document.positionAt(match.index);
104+
const endPos = activeEditor.document.positionAt(
105+
match.index + match[0].length
106+
);
107+
const currentLine = startPos.line;
108+
109+
const value = String(fullToken[key]);
110+
const colorSpan = genMarkdownString(value);
111+
const markDownString = new vscode.MarkdownString(
112+
`<h3>antd design token: ${match[0]}</h3>${colorSpan}<code>${value}</code><br></br>`
113+
);
114+
markDownString.supportHtml = true;
115+
markDownString.isTrusted = true;
116+
117+
const decoration = {
118+
range: new vscode.Range(startPos, endPos),
119+
hoverMessage: markDownString,
120+
};
121+
122+
const colorValue = getColorTokenValue(fullToken[key]);
123+
valueDecorations.push(decoration);
124+
125+
decorationType = vscode.window.createTextEditorDecorationType({
126+
after: {
127+
contentText: colorValue ? `**` : `(${String(fullToken[key])})`,
128+
backgroundColor: colorValue || "",
129+
margin: "0 0 0 4px;",
130+
color: colorValue || "#1890ff",
131+
fontWeight: "bolder",
132+
},
133+
});
134+
135+
currentFileDecorations.push(decorationType);
136+
activeEditor.setDecorations(decorationType, valueDecorations);
137+
}
138+
});
139+
fileDecorationMap.set(fileName, currentFileDecorations);
140+
}
141+
}
142+
143+
function checkOpenedFile(fileName: string): boolean {
144+
if (openedFileNameSet.has(fileName)) {
145+
return true;
146+
} else {
147+
openedFileNameSet.add(fileName);
148+
return false;
149+
}
150+
}
151+
}

0 commit comments

Comments
 (0)