irongit

A Regex file extension that makes it way easier to edit large regex.

starting new version

huncholanehuncholaneauthored
parent 46e3386commit 51f134bec03e247016d7ad9b5299e410fab0425cBrowse files

16 files changed, +529 -278

+2-2package.json
@@ -2,10 +2,10 @@
22 "name": "regex-file",
33 "displayName": "Regex File",
44 "icon": "images/icon.png",
5- "description": "Made a file type for regex that highlights a second file and adds flags to the status bar.",
5+ "description": "Regex File extension for Visual Studio Code.",
66 "version": "0.0.1",
77 "repository": "git@github.com:huncholane/regex-file.git",
8- "publisher": "Ghost Systems",
8+ "publisher": "Hygo",
99 "engines": {
1010 "vscode": "^1.79.0"
1111 },
+281-0src/backup/backup_extension.ts
@@ -0,0 +1,281 @@
1+import * as vscode from "vscode";
2+
3+/* GLOBAL CONSTANTS */
4+const timeout = vscode.workspace
5+ .getConfiguration("yourExtension")
6+ .get("timeout", 1000);
7+const maxMatches = vscode.workspace
8+ .getConfiguration("yourExtension")
9+ .get("maxMatches", 10000);
10+const baseEditorStyle = vscode.window.createTextEditorDecorationType({
11+ backgroundColor: "yellow",
12+ color: "black",
13+});
14+
15+/* GLOBAL VARIABLES */
16+let textDecorations = [baseEditorStyle];
17+let outputChannel: vscode.OutputChannel;
18+let lastRegex = "";
19+let lastText = "";
20+let decorationType: vscode.TextEditorDecorationType | undefined;
21+const flagButtons: { [key: string]: InnerMapValue } = {};
22+
23+/* TYPES */
24+type GroupMatches = {
25+ style: vscode.TextEditorDecorationType;
26+ matches: vscode.Range[];
27+};
28+type GroupMatchMap = {
29+ [key: string]: GroupMatches;
30+};
31+interface InnerMapValue {
32+ state: "on" | "off";
33+ button: vscode.StatusBarItem;
34+}
35+const states: Record<"on" | "off", string> = {
36+ on: "$(check)",
37+ off: "$(x)",
38+};
39+
40+function getConfigFlags(): string {
41+ const config = vscode.workspace.getConfiguration("regex-file");
42+ return config.get("flags") as string;
43+}
44+
45+function getRandomColor() {
46+ // Generate a random hex color
47+ const letters = "0123456789ABCDEF";
48+ let color = "#";
49+ for (let i = 0; i < 6; i++) {
50+ color += letters[Math.floor(Math.random() * 16)];
51+ }
52+ return color;
53+}
54+
55+function getReEditor(): vscode.TextEditor | undefined {
56+ const editors = vscode.window.visibleTextEditors;
57+
58+ for (const editor of editors) {
59+ const fileName = editor.document.fileName;
60+ if (fileName.endsWith(".re")) {
61+ return editor;
62+ }
63+ }
64+ console.log("No regex document.");
65+}
66+
67+function getTextEditor(): vscode.TextEditor | undefined {
68+ const editors = vscode.window.visibleTextEditors;
69+
70+ for (const editor of editors) {
71+ const fileName = editor.document.fileName;
72+ if (!fileName.endsWith(".re")) {
73+ return editor;
74+ }
75+ }
76+ console.log("No search document.");
77+}
78+
79+export function activate(context: vscode.ExtensionContext) {
80+ outputChannel = vscode.window.createOutputChannel("regex-file");
81+ createFlagButtons(context);
82+ highlightMatches();
83+ vscode.window.onDidChangeVisibleTextEditors(highlightMatches);
84+ vscode.workspace.onDidChangeTextDocument(highlightMatches);
85+}
86+
87+function createFlagButtons(context: vscode.ExtensionContext): void {
88+ ["g", "i", "m", "s", "u", "y", "x"].forEach((flag) => {
89+ const button = vscode.window.createStatusBarItem(
90+ vscode.StatusBarAlignment.Left
91+ );
92+ let state: "on" | "off" = "off";
93+ if (getConfigFlags().includes(flag)) {
94+ state = "on";
95+ }
96+ button.text = `${states[state]} ${flag.toUpperCase()}`;
97+ button.tooltip = `Toggle ${flag} flag`;
98+ button.command = `regex.toggleFlag${flag.toUpperCase()}`;
99+ button.show();
100+ flagButtons[flag] = {
101+ state,
102+ button,
103+ };
104+ let disposable = vscode.commands.registerCommand(
105+ `regex.toggleFlag${flag.toUpperCase()}`,
106+ () => {
107+ toggleFlag(flag);
108+ }
109+ );
110+ context.subscriptions.push(button);
111+ context.subscriptions.push(disposable);
112+ });
113+}
114+
115+function getRegexFlags(): [string, boolean] {
116+ let flags = "";
117+ let hasX = false;
118+ Object.entries(flagButtons).forEach(([flag, info]) => {
119+ if (info.state === "on") {
120+ if (flag === "x") {
121+ hasX = true;
122+ } else {
123+ flags += flag;
124+ }
125+ }
126+ });
127+ return [flags, hasX];
128+}
129+
130+function applyGroupMatchDecorations(
131+ editor: vscode.TextEditor,
132+ groupMatches: GroupMatchMap
133+) {
134+ for (const groupName of Object.keys(groupMatches)) {
135+ const { style, matches } = groupMatches[groupName];
136+ textDecorations.push(style);
137+
138+ const decorations: vscode.DecorationOptions[] = matches.map(
139+ (range) => ({
140+ range,
141+ hoverMessage: `Group: ${groupName}`,
142+ })
143+ );
144+
145+ editor.setDecorations(style, decorations);
146+ }
147+}
148+
149+function updateGroupMatches(
150+ textEditor: vscode.TextEditor,
151+ groupMatches: GroupMatchMap,
152+ match: RegExpExecArray
153+) {
154+ for (const groupName in match.groups) {
155+ const groupMatch = match.groups[groupName];
156+
157+ if (groupMatch) {
158+ const startInd = match[0].indexOf(groupMatch);
159+ const startPos = textEditor.document.positionAt(
160+ match.index + startInd
161+ );
162+ const endInd = startInd + groupMatch.length;
163+ const endPos = textEditor.document.positionAt(match.index + endInd);
164+ const matchRange = new vscode.Range(startPos, endPos);
165+
166+ if (!groupMatches[groupName]) {
167+ // Generate a random color for the group
168+ const randomColor = getRandomColor();
169+
170+ // Define a new TextEditorDecorationType for the group with the random color
171+ groupMatches[groupName] = {
172+ style: vscode.window.createTextEditorDecorationType({
173+ backgroundColor: randomColor,
174+ color: "black", // You can customize the text color
175+ }),
176+ matches: [matchRange],
177+ };
178+ } else {
179+ groupMatches[groupName].matches.push(matchRange);
180+ }
181+ }
182+ }
183+}
184+
185+function highlightMatches(): void {
186+ const reEditor = getReEditor();
187+ const textEditor = getTextEditor();
188+ if (!reEditor || !textEditor) {
189+ outputChannel.appendLine(
190+ "Abort highlighting. Missing reEditor or textEditor."
191+ );
192+ return;
193+ }
194+ let reText = reEditor.document.getText();
195+ if (!reText) {
196+ outputChannel.appendLine(
197+ "Abort highlighting. No text in the regex file."
198+ );
199+ }
200+ let searchText = textEditor.document.getText();
201+ if (searchText === lastText && reText === lastRegex) {
202+ return;
203+ }
204+ lastText = searchText;
205+ lastRegex = reText;
206+ outputChannel.appendLine("Ready to begin highlighting.");
207+
208+ // Clear all previous text decorations
209+ for (const decoration of textDecorations) {
210+ textEditor.setDecorations(decoration, []);
211+ textDecorations = [baseEditorStyle];
212+ }
213+
214+ // Perform your matching and highlighting logic here
215+ const matches: vscode.Range[] = [];
216+ let [flags, hasX] = getRegexFlags();
217+ if (hasX) {
218+ reText = reText.replace(/\s/g, "");
219+ }
220+ let pattern;
221+ try {
222+ pattern = new RegExp(reText, flags);
223+ } catch {
224+ console.log("invalid pattern");
225+ return;
226+ }
227+ const groupMatches: GroupMatchMap = {};
228+ let match: RegExpExecArray | null;
229+ let i = 0;
230+ const startTime = new Date().getTime();
231+ while ((match = pattern.exec(searchText))) {
232+ if (i > maxMatches) {
233+ console.log(`Max matches of ${maxMatches} reached.`);
234+ outputChannel.appendLine(`Max matches of ${maxMatches} reached.`);
235+ break;
236+ }
237+ if (new Date().getTime() > startTime + 1000) {
238+ console.log(`Timeout of ${timeout} reached.`);
239+ outputChannel.appendLine(`Timeout of ${timeout} reached.`);
240+ break;
241+ }
242+ updateGroupMatches(textEditor, groupMatches, match);
243+ const startPos = textEditor.document.positionAt(match.index);
244+ const endPos = textEditor.document.positionAt(
245+ match.index + match[0].length
246+ );
247+ const range = new vscode.Range(startPos, endPos);
248+ matches.push(range);
249+ i++;
250+ }
251+
252+ // Apply base decorations
253+ textEditor.setDecorations(baseEditorStyle, matches);
254+
255+ // Apply decorations to the groups
256+ applyGroupMatchDecorations(textEditor, groupMatches);
257+}
258+
259+function toggleFlag(flag: string): void {
260+ const button = flagButtons[flag].button;
261+ const currentState = flagButtons[flag].state;
262+ const newState = currentState === "on" ? "off" : "on";
263+
264+ flagButtons[flag].state = newState;
265+ button.text = `${states[newState]} ${flag.toUpperCase()}`;
266+}
267+
268+export function deactivate() {
269+ disposeFlagButtons();
270+}
271+
272+function disposeFlagButtons(): void {
273+ for (const key in flagButtons) {
274+ if (flagButtons.hasOwnProperty(key)) {
275+ const innerMapValue = flagButtons[key];
276+ innerMapValue.button.dispose();
277+ }
278+ }
279+ // Clear the flagButtons dictionary
280+ Object.keys(flagButtons).forEach((key) => delete flagButtons[key]);
281+}
+1-0src/backup/extension.js.map
@@ -0,0 +1 @@
1+{"version":3,"file":"extension.js","sourceRoot":"","sources":["extension.ts"],"names":[],"mappings":"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"}
+22-0src/backup/test/runTest.js
@@ -0,0 +1,22 @@
1+"use strict";
2+Object.defineProperty(exports, "__esModule", { value: true });
3+const path = require("path");
4+const test_electron_1 = require("@vscode/test-electron");
5+async function main() {
6+ try {
7+ // The folder containing the Extension Manifest package.json
8+ // Passed to `--extensionDevelopmentPath`
9+ const extensionDevelopmentPath = path.resolve(__dirname, '../../');
10+ // The path to test runner
11+ // Passed to --extensionTestsPath
12+ const extensionTestsPath = path.resolve(__dirname, './suite/index');
13+ // Download VS Code, unzip it and run the integration test
14+ await (0, test_electron_1.runTests)({ extensionDevelopmentPath, extensionTestsPath });
15+ }
16+ catch (err) {
17+ console.error('Failed to run tests', err);
18+ process.exit(1);
19+ }
20+}
21+main();
22+//# sourceMappingURL=runTest.js.map
+1-0src/backup/test/runTest.js.map
@@ -0,0 +1 @@
1+{"version":3,"file":"runTest.js","sourceRoot":"","sources":["runTest.ts"],"names":[],"mappings":";;AAAA,6BAA6B;AAE7B,yDAAiD;AAEjD,KAAK,UAAU,IAAI;IAClB,IAAI;QACH,4DAA4D;QAC5D,yCAAyC;QACzC,MAAM,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEnE,0BAA0B;QAC1B,iCAAiC;QACjC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAEpE,0DAA0D;QAC1D,MAAM,IAAA,wBAAQ,EAAC,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,CAAC,CAAC;KACjE;IAAC,OAAO,GAAG,EAAE;QACb,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KAChB;AACF,CAAC;AAED,IAAI,EAAE,CAAC"}
+23-0src/backup/test/runTest.ts
@@ -0,0 +1,23 @@
1+import * as path from 'path';
2+
3+import { runTests } from '@vscode/test-electron';
4+
5+async function main() {
6+ try {
7+ // The folder containing the Extension Manifest package.json
8+ // Passed to `--extensionDevelopmentPath`
9+ const extensionDevelopmentPath = path.resolve(__dirname, '../../');
10+
11+ // The path to test runner
12+ // Passed to --extensionTestsPath
13+ const extensionTestsPath = path.resolve(__dirname, './suite/index');
14+
15+ // Download VS Code, unzip it and run the integration test
16+ await runTests({ extensionDevelopmentPath, extensionTestsPath });
17+ } catch (err) {
18+ console.error('Failed to run tests', err);
19+ process.exit(1);
20+ }
21+}
22+
23+main();
+15-0src/backup/test/suite/extension.test.js
@@ -0,0 +1,15 @@
1+"use strict";
2+Object.defineProperty(exports, "__esModule", { value: true });
3+const assert = require("assert");
4+// You can import and use all API from the 'vscode' module
5+// as well as import your extension to test it
6+const vscode = require("vscode");
7+// import * as myExtension from '../../extension';
8+suite('Extension Test Suite', () => {
9+ vscode.window.showInformationMessage('Start all tests.');
10+ test('Sample test', () => {
11+ assert.strictEqual(-1, [1, 2, 3].indexOf(5));
12+ assert.strictEqual(-1, [1, 2, 3].indexOf(0));
13+ });
14+});
15+//# sourceMappingURL=extension.test.js.map
+1-0src/backup/test/suite/extension.test.js.map
@@ -0,0 +1 @@
1+{"version":3,"file":"extension.test.js","sourceRoot":"","sources":["extension.test.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AAEjC,0DAA0D;AAC1D,8CAA8C;AAC9C,iCAAiC;AACjC,kDAAkD;AAElD,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE;IAClC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE;QACxB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
+15-0src/backup/test/suite/extension.test.ts
@@ -0,0 +1,15 @@
1+import * as assert from 'assert';
2+
3+// You can import and use all API from the 'vscode' module
4+// as well as import your extension to test it
5+import * as vscode from 'vscode';
6+// import * as myExtension from '../../extension';
7+
8+suite('Extension Test Suite', () => {
9+ vscode.window.showInformationMessage('Start all tests.');
10+
11+ test('Sample test', () => {
12+ assert.strictEqual(-1, [1, 2, 3].indexOf(5));
13+ assert.strictEqual(-1, [1, 2, 3].indexOf(0));
14+ });
15+});
+40-0src/backup/test/suite/index.js
@@ -0,0 +1,40 @@
1+"use strict";
2+Object.defineProperty(exports, "__esModule", { value: true });
3+exports.run = void 0;
4+const path = require("path");
5+const Mocha = require("mocha");
6+const glob = require("glob");
7+function run() {
8+ // Create the mocha test
9+ const mocha = new Mocha({
10+ ui: 'tdd',
11+ color: true
12+ });
13+ const testsRoot = path.resolve(__dirname, '..');
14+ return new Promise((c, e) => {
15+ glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
16+ if (err) {
17+ return e(err);
18+ }
19+ // Add files to the test suite
20+ files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
21+ try {
22+ // Run the mocha test
23+ mocha.run(failures => {
24+ if (failures > 0) {
25+ e(new Error(`${failures} tests failed.`));
26+ }
27+ else {
28+ c();
29+ }
30+ });
31+ }
32+ catch (err) {
33+ console.error(err);
34+ e(err);
35+ }
36+ });
37+ });
38+}
39+exports.run = run;
40+//# sourceMappingURL=index.js.map
+1-0src/backup/test/suite/index.js.map
@@ -0,0 +1 @@
1+{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,+BAA+B;AAC/B,6BAA6B;AAE7B,SAAgB,GAAG;IAClB,wBAAwB;IACxB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACvB,EAAE,EAAE,KAAK;QACT,KAAK,EAAE,IAAI;KACX,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC3B,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACxD,IAAI,GAAG,EAAE;gBACR,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;aACd;YAED,8BAA8B;YAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9D,IAAI;gBACH,qBAAqB;gBACrB,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;oBACpB,IAAI,QAAQ,GAAG,CAAC,EAAE;wBACjB,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,QAAQ,gBAAgB,CAAC,CAAC,CAAC;qBAC1C;yBAAM;wBACN,CAAC,EAAE,CAAC;qBACJ;gBACF,CAAC,CAAC,CAAC;aACH;YAAC,OAAO,GAAG,EAAE;gBACb,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC,CAAC,GAAG,CAAC,CAAC;aACP;QACF,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC;AAjCD,kBAiCC"}
+38-0src/backup/test/suite/index.ts
@@ -0,0 +1,38 @@
1+import * as path from 'path';
2+import * as Mocha from 'mocha';
3+import * as glob from 'glob';
4+
5+export function run(): Promise<void> {
6+ // Create the mocha test
7+ const mocha = new Mocha({
8+ ui: 'tdd',
9+ color: true
10+ });
11+
12+ const testsRoot = path.resolve(__dirname, '..');
13+
14+ return new Promise((c, e) => {
15+ glob('**/**.test.js', { cwd: testsRoot }, (err, files) => {
16+ if (err) {
17+ return e(err);
18+ }
19+
20+ // Add files to the test suite
21+ files.forEach(f => mocha.addFile(path.resolve(testsRoot, f)));
22+
23+ try {
24+ // Run the mocha test
25+ mocha.run(failures => {
26+ if (failures > 0) {
27+ e(new Error(`${failures} tests failed.`));
28+ } else {
29+ c();
30+ }
31+ });
32+ } catch (err) {
33+ console.error(err);
34+ e(err);
35+ }
36+ });
37+ });
38+}
+4-276src/extension.ts
@@ -1,281 +1,9 @@
11 import * as vscode from "vscode";
2-
3-/* GLOBAL CONSTANTS */
4-const timeout = vscode.workspace
5- .getConfiguration("yourExtension")
6- .get("timeout", 1000);
7-const maxMatches = vscode.workspace
8- .getConfiguration("yourExtension")
9- .get("maxMatches", 10000);
10-const baseEditorStyle = vscode.window.createTextEditorDecorationType({
11- backgroundColor: "yellow",
12- color: "black",
13-});
14-
15-/* GLOBAL VARIABLES */
16-let textDecorations = [baseEditorStyle];
17-let outputChannel: vscode.OutputChannel;
18-let lastRegex = "";
19-let lastText = "";
20-let decorationType: vscode.TextEditorDecorationType | undefined;
21-const flagButtons: { [key: string]: InnerMapValue } = {};
22-
23-/* TYPES */
24-type GroupMatches = {
25- style: vscode.TextEditorDecorationType;
26- matches: vscode.Range[];
27-};
28-type GroupMatchMap = {
29- [key: string]: GroupMatches;
30-};
31-interface InnerMapValue {
32- state: "on" | "off";
33- button: vscode.StatusBarItem;
34-}
35-const states: Record<"on" | "off", string> = {
36- on: "$(check)",
37- off: "$(x)",
38-};
39-
40-function getConfigFlags(): string {
41- const config = vscode.workspace.getConfiguration("regex-file");
42- return config.get("flags") as string;
43-}
44-
45-function getRandomColor() {
46- // Generate a random hex color
47- const letters = "0123456789ABCDEF";
48- let color = "#";
49- for (let i = 0; i < 6; i++) {
50- color += letters[Math.floor(Math.random() * 16)];
51- }
52- return color;
53-}
54-
55-function getReEditor(): vscode.TextEditor | undefined {
56- const editors = vscode.window.visibleTextEditors;
57-
58- for (const editor of editors) {
59- const fileName = editor.document.fileName;
60- if (fileName.endsWith(".re")) {
61- return editor;
62- }
63- }
64- console.log("No regex document.");
65-}
66-
67-function getTextEditor(): vscode.TextEditor | undefined {
68- const editors = vscode.window.visibleTextEditors;
69-
70- for (const editor of editors) {
71- const fileName = editor.document.fileName;
72- if (!fileName.endsWith(".re")) {
73- return editor;
74- }
75- }
76- console.log("No search document.");
77-}
2+import { output } from "./output";
783
794 export function activate(context: vscode.ExtensionContext) {
80- outputChannel = vscode.window.createOutputChannel("regex-file");
81- createFlagButtons(context);
82- highlightMatches();
83- vscode.window.onDidChangeVisibleTextEditors(highlightMatches);
84- vscode.workspace.onDidChangeTextDocument(highlightMatches);
85-}
86-
87-function createFlagButtons(context: vscode.ExtensionContext): void {
88- ["g", "i", "m", "s", "u", "y", "x"].forEach((flag) => {
89- const button = vscode.window.createStatusBarItem(
90- vscode.StatusBarAlignment.Left
91- );
92- let state: "on" | "off" = "off";
93- if (getConfigFlags().includes(flag)) {
94- state = "on";
95- }
96- button.text = `${states[state]} ${flag.toUpperCase()}`;
97- button.tooltip = `Toggle ${flag} flag`;
98- button.command = `regex.toggleFlag${flag.toUpperCase()}`;
99- button.show();
100- flagButtons[flag] = {
101- state,
102- button,
103- };
104- let disposable = vscode.commands.registerCommand(
105- `regex.toggleFlag${flag.toUpperCase()}`,
106- () => {
107- toggleFlag(flag);
108- }
109- );
110- context.subscriptions.push(button);
111- context.subscriptions.push(disposable);
112- });
113-}
114-
115-function getRegexFlags(): [string, boolean] {
116- let flags = "";
117- let hasX = false;
118- Object.entries(flagButtons).forEach(([flag, info]) => {
119- if (info.state === "on") {
120- if (flag === "x") {
121- hasX = true;
122- } else {
123- flags += flag;
124- }
125- }
126- });
127- return [flags, hasX];
5+ output.activate();
6+ output.log("Starting File Regex extension");
1287 }
1298
130-function applyGroupMatchDecorations(
131- editor: vscode.TextEditor,
132- groupMatches: GroupMatchMap
133-) {
134- for (const groupName of Object.keys(groupMatches)) {
135- const { style, matches } = groupMatches[groupName];
136- textDecorations.push(style);
137-
138- const decorations: vscode.DecorationOptions[] = matches.map(
139- (range) => ({
140- range,
141- hoverMessage: `Group: ${groupName}`,
142- })
143- );
144-
145- editor.setDecorations(style, decorations);
146- }
147-}
148-
149-function updateGroupMatches(
150- textEditor: vscode.TextEditor,
151- groupMatches: GroupMatchMap,
152- match: RegExpExecArray
153-) {
154- for (const groupName in match.groups) {
155- const groupMatch = match.groups[groupName];
156-
157- if (groupMatch) {
158- const startInd = match[0].indexOf(groupMatch);
159- const startPos = textEditor.document.positionAt(
160- match.index + startInd
161- );
162- const endInd = startInd + groupMatch.length;
163- const endPos = textEditor.document.positionAt(match.index + endInd);
164- const matchRange = new vscode.Range(startPos, endPos);
165-
166- if (!groupMatches[groupName]) {
167- // Generate a random color for the group
168- const randomColor = getRandomColor();
169-
170- // Define a new TextEditorDecorationType for the group with the random color
171- groupMatches[groupName] = {
172- style: vscode.window.createTextEditorDecorationType({
173- backgroundColor: randomColor,
174- color: "black", // You can customize the text color
175- }),
176- matches: [matchRange],
177- };
178- } else {
179- groupMatches[groupName].matches.push(matchRange);
180- }
181- }
182- }
183-}
184-
185-function highlightMatches(): void {
186- const reEditor = getReEditor();
187- const textEditor = getTextEditor();
188- if (!reEditor || !textEditor) {
189- outputChannel.appendLine(
190- "Abort highlighting. Missing reEditor or textEditor."
191- );
192- return;
193- }
194- let reText = reEditor.document.getText();
195- if (!reText) {
196- outputChannel.appendLine(
197- "Abort highlighting. No text in the regex file."
198- );
199- }
200- let searchText = textEditor.document.getText();
201- if (searchText === lastText && reText === lastRegex) {
202- return;
203- }
204- lastText = searchText;
205- lastRegex = reText;
206- outputChannel.appendLine("Ready to begin highlighting.");
207-
208- // Clear all previous text decorations
209- for (const decoration of textDecorations) {
210- textEditor.setDecorations(decoration, []);
211- textDecorations = [baseEditorStyle];
212- }
213-
214- // Perform your matching and highlighting logic here
215- const matches: vscode.Range[] = [];
216- let [flags, hasX] = getRegexFlags();
217- if (hasX) {
218- reText = reText.replace(/\s/g, "");
219- }
220- let pattern;
221- try {
222- pattern = new RegExp(reText, flags);
223- } catch {
224- console.log("invalid pattern");
225- return;
226- }
227- const groupMatches: GroupMatchMap = {};
228- let match: RegExpExecArray | null;
229- let i = 0;
230- const startTime = new Date().getTime();
231- while ((match = pattern.exec(searchText))) {
232- if (i > maxMatches) {
233- console.log(`Max matches of ${maxMatches} reached.`);
234- outputChannel.appendLine(`Max matches of ${maxMatches} reached.`);
235- break;
236- }
237- if (new Date().getTime() > startTime + 1000) {
238- console.log(`Timeout of ${timeout} reached.`);
239- outputChannel.appendLine(`Timeout of ${timeout} reached.`);
240- break;
241- }
242- updateGroupMatches(textEditor, groupMatches, match);
243- const startPos = textEditor.document.positionAt(match.index);
244- const endPos = textEditor.document.positionAt(
245- match.index + match[0].length
246- );
247- const range = new vscode.Range(startPos, endPos);
248- matches.push(range);
249- i++;
250- }
251-
252- // Apply base decorations
253- textEditor.setDecorations(baseEditorStyle, matches);
254-
255- // Apply decorations to the groups
256- applyGroupMatchDecorations(textEditor, groupMatches);
257-}
258-
259-function toggleFlag(flag: string): void {
260- const button = flagButtons[flag].button;
261- const currentState = flagButtons[flag].state;
262- const newState = currentState === "on" ? "off" : "on";
263-
264- flagButtons[flag].state = newState;
265- button.text = `${states[newState]} ${flag.toUpperCase()}`;
266-}
267-
268-export function deactivate() {
269- disposeFlagButtons();
270-}
271-
272-function disposeFlagButtons(): void {
273- for (const key in flagButtons) {
274- if (flagButtons.hasOwnProperty(key)) {
275- const innerMapValue = flagButtons[key];
276- innerMapValue.button.dispose();
277- }
278- }
279- // Clear the flagButtons dictionary
280- Object.keys(flagButtons).forEach((key) => delete flagButtons[key]);
281-}
9+export function deactivate() {}
+5-0src/global.ts
@@ -0,0 +1,5 @@
1+import * as vscode from "vscode";
2+
3+export function getConfig(): vscode.WorkspaceConfiguration {
4+ return vscode.workspace.getConfiguration("regex-file");
5+}
+33-0src/output.ts
@@ -0,0 +1,33 @@
1+import * as vscode from "vscode";
2+
3+class Output {
4+ outputChannel: vscode.OutputChannel | undefined;
5+
6+ activate() {
7+ this.outputChannel = vscode.window.createOutputChannel("Regex File");
8+ this.show();
9+ }
10+
11+ show() {
12+ this.outputChannel?.show();
13+ }
14+
15+ clear() {
16+ this.outputChannel?.clear();
17+ }
18+
19+ dispose() {
20+ this.outputChannel?.dispose();
21+ }
22+
23+ hide() {
24+ this.outputChannel?.hide();
25+ }
26+
27+ log(message: string) {
28+ this.outputChannel?.appendLine(message);
29+ console.log(message);
30+ }
31+}
32+
33+export const output = new Output();
+47-0src/regexButtons.ts
@@ -0,0 +1,47 @@
1+import * as vscode from "vscode";
2+import { getConfig } from "./global";
3+import { output } from "./output";
4+
5+const FLAG_CHARS = ["g", "i", "m", "s", "u", "y", "x"];
6+
7+class RegexButtons {
8+ flagButtons: {
9+ [key: string]: {
10+ state: "on" | "off";
11+ button: vscode.StatusBarItem;
12+ };
13+ } = {};
14+
15+ constructor() {}
16+
17+ activate(context: vscode.ExtensionContext) {
18+ this.createButtons(context);
19+ this.updateFlagsFromConfig();
20+ }
21+
22+ updateFlagsFromConfig() {
23+ output.log("Updating flags");
24+ }
25+
26+ updateFlagsFromUI() {
27+ output.log("Updating flags from UI");
28+ }
29+
30+ createButton(flag: string) {
31+ output.log(`Creating button for ${flag}`);
32+ }
33+
34+ createButtons(context: vscode.ExtensionContext) {
35+ output.log("Creating buttons");
36+ }
37+
38+ disposeButtons() {
39+ output.log("Disposing buttons");
40+ }
41+
42+ dispose() {
43+ this.disposeButtons();
44+ }
45+}
46+
47+export const regexButtons = new RegexButtons();