Skip to content

Commit a90c54a

Browse files
committed
Initial LineNumberer Class
1 parent e0ce881 commit a90c54a

1 file changed

Lines changed: 230 additions & 0 deletions

File tree

src/util/lineNumberer.ts

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
/* ---------------------------------------------------------------------------------------------
2+
* Copyright (c) Applied Eng & Design All rights reserved.
3+
* Licensed under the MIT License. See License.md in the project root for license information.
4+
* -------------------------------------------------------------------------------------------- */
5+
'use strict';
6+
7+
import { Progress, ProgressLocation, Range, TextEditor, window } from 'vscode';
8+
9+
export enum LineNumberFrequency {
10+
EveryLine,
11+
AtToolChanges,
12+
}
13+
14+
type LineNumbererOptions = {
15+
addSpaceAfter?: boolean;
16+
frequency?: LineNumberFrequency;
17+
ignoreComments?: boolean;
18+
ignoreBlank?: boolean;
19+
ignoreProgramNumbers?: boolean;
20+
};
21+
22+
type ProgressInfo = {
23+
message?: string | undefined;
24+
increment?: number | undefined;
25+
};
26+
27+
export class LineNumberer {
28+
private _editor: TextEditor | undefined;
29+
private _beforeText: string = '';
30+
31+
constructor() {
32+
this._editor = window.activeTextEditor;
33+
}
34+
35+
async addNumbers(
36+
start: number,
37+
increment: number,
38+
showProgress: boolean,
39+
options?: LineNumbererOptions,
40+
): Promise<boolean> {
41+
if (this._editor && this._editor.document) {
42+
this._beforeText = this._editor.document.getText();
43+
}
44+
// Remove any numbers first
45+
const newtext = this._removeNumbers(this._beforeText);
46+
if (showProgress) {
47+
await window.withProgress(
48+
{
49+
location: ProgressLocation.Notification,
50+
title: 'Adding Line Numbers',
51+
cancellable: true,
52+
},
53+
(progress, token) => {
54+
token.onCancellationRequested(() => {
55+
return this._updateTextEditor(this._beforeText);
56+
});
57+
58+
progress.report({ increment: 0, message: 'Adding Line Numbers...' });
59+
return this._addNumbers(newtext, start, increment, progress, options).then(replace => {
60+
progress.report({ increment: 100, message: 'Updating Text.' });
61+
return Promise.resolve(this._updateTextEditor(replace));
62+
});
63+
},
64+
);
65+
} else {
66+
return this._addNumbers(newtext, start, increment, undefined, options).then(replace => {
67+
return Promise.resolve(this._updateTextEditor(replace));
68+
});
69+
}
70+
71+
return false;
72+
}
73+
74+
private async _addNumbers(
75+
text: string,
76+
start: number,
77+
increment: number,
78+
progress?: Progress<ProgressInfo>,
79+
options?: LineNumbererOptions,
80+
): Promise<string> {
81+
let replace = '';
82+
let curNum = start;
83+
const space = options?.addSpaceAfter ?? true ? ' ' : '';
84+
const lines = text.match(/.*(?:\r\n|\r|\n)/g) || [];
85+
86+
for (let i = 0; i < lines.length; ++i) {
87+
lines[i] = lines[i].replace(/\r?\n|\r/g, '');
88+
const line = lines[i].trim();
89+
90+
if ((options?.frequency ?? LineNumberFrequency.EveryLine) === LineNumberFrequency.EveryLine) {
91+
if (line.length === 0) {
92+
if (options?.ignoreBlank ?? true) {
93+
replace += `${line}${i + 1 === lines.length ? '' : '\n'}`;
94+
if (progress) {
95+
progress.report({ increment: Math.floor(i / lines.length) });
96+
}
97+
continue;
98+
} else {
99+
replace += `N${curNum}${space}`;
100+
curNum += increment;
101+
if (progress) {
102+
progress.report({ increment: Math.floor(i / lines.length) });
103+
}
104+
continue;
105+
}
106+
}
107+
108+
const re = /\(|\)/;
109+
if (re.test(line)) {
110+
if (options?.ignoreComments ?? true) {
111+
replace += `${line}${i + 1 === lines.length ? '' : '\n'}`;
112+
if (progress) {
113+
progress.report({ increment: Math.floor(i / lines.length) });
114+
}
115+
continue;
116+
} else {
117+
replace += `N${curNum}${space}${line}${i + 1 === lines.length ? '' : '\n'}`;
118+
curNum += increment;
119+
if (progress) {
120+
progress.report({ increment: Math.floor(i / lines.length) });
121+
}
122+
continue;
123+
}
124+
}
125+
126+
const re1 = /(^[oO])(\d+)/;
127+
if (re1.test(line)) {
128+
if (options?.ignoreProgramNumbers ?? true) {
129+
replace += `${line}${i + 1 === lines.length ? '' : '\n'}`;
130+
if (progress) {
131+
progress.report({ increment: Math.floor(i / lines.length) });
132+
}
133+
continue;
134+
} else {
135+
replace += `N${curNum}${space}${line}${i + 1 === lines.length ? '' : '\n'}`;
136+
curNum += increment;
137+
if (progress) {
138+
progress.report({ increment: Math.floor(i / lines.length) });
139+
}
140+
continue;
141+
}
142+
}
143+
144+
replace += `N${curNum}${space}${line}${i + 1 === lines.length ? '' : '\n'}`;
145+
curNum += increment;
146+
if (progress) {
147+
progress.report({ increment: Math.floor(i / lines.length) });
148+
}
149+
} else {
150+
const re = /(M0?6)/;
151+
152+
if (re.test(line)) {
153+
replace += `N${curNum}${space}${line}${i + 1 === lines.length ? '' : '\n'}`;
154+
curNum += increment;
155+
if (progress) {
156+
progress.report({ increment: Math.floor(i / lines.length) });
157+
}
158+
continue;
159+
} else {
160+
replace += `${line}${i + 1 === lines.length ? '' : '\n'}`;
161+
curNum += increment;
162+
if (progress) {
163+
progress.report({ increment: Math.floor(i / lines.length) });
164+
}
165+
continue;
166+
}
167+
}
168+
}
169+
170+
return Promise.resolve(replace);
171+
}
172+
173+
async removeNumbers(showProgress: boolean = false): Promise<boolean> {
174+
if (this._editor && this._editor.document) {
175+
this._beforeText = this._editor.document.getText();
176+
}
177+
if (showProgress) {
178+
await window.withProgress(
179+
{
180+
location: ProgressLocation.Notification,
181+
title: 'Removing Line Numbers',
182+
cancellable: true,
183+
},
184+
(progress, token) => {
185+
token.onCancellationRequested(() => {
186+
return this._updateTextEditor(this._beforeText);
187+
});
188+
189+
progress.report({ increment: 0, message: 'Removing Line Numbers...' });
190+
191+
const replace = this._removeNumbers(this._beforeText);
192+
progress.report({ increment: 100, message: 'Updating Text.' });
193+
194+
return this._updateTextEditor(replace);
195+
},
196+
);
197+
} else {
198+
const replace = this._removeNumbers(this._beforeText);
199+
return this._updateTextEditor(replace);
200+
}
201+
202+
return false;
203+
}
204+
205+
private _removeNumbers(replace: string): string {
206+
return replace.replace(new RegExp(/(^[nN])(\d+)/gim), '');
207+
}
208+
209+
private async _updateTextEditor(text: string): Promise<boolean> {
210+
const len = this._beforeText.length;
211+
212+
if (this._editor && this._editor.document) {
213+
return Promise.resolve(
214+
this._editor.edit(editBuilder => {
215+
if (this._editor && this._editor.document) {
216+
editBuilder.replace(
217+
new Range(this._editor.document.positionAt(0), this._editor.document.positionAt(len - 1)),
218+
text,
219+
);
220+
221+
this._beforeText = '';
222+
}
223+
}),
224+
);
225+
} else {
226+
this._beforeText = '';
227+
return false;
228+
}
229+
}
230+
}

0 commit comments

Comments
 (0)