Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/emmet/src/incrementDecrement.ts
4772 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
/* Based on @sergeche's work in his emmet plugin */
7
8
import * as vscode from 'vscode';
9
10
const reNumber = /[0-9]/;
11
12
/**
13
* Incerement number under caret of given editor
14
*/
15
export function incrementDecrement(delta: number): Thenable<boolean> | undefined {
16
if (!vscode.window.activeTextEditor) {
17
vscode.window.showInformationMessage('No editor is active');
18
return;
19
}
20
const editor = vscode.window.activeTextEditor;
21
22
return editor.edit(editBuilder => {
23
editor.selections.forEach(selection => {
24
const rangeToReplace = locate(editor.document, selection.isReversed ? selection.anchor : selection.active);
25
if (!rangeToReplace) {
26
return;
27
}
28
29
const text = editor.document.getText(rangeToReplace);
30
if (isValidNumber(text)) {
31
editBuilder.replace(rangeToReplace, update(text, delta));
32
}
33
});
34
});
35
}
36
37
/**
38
* Updates given number with `delta` and returns string formatted according
39
* to original string format
40
*/
41
export function update(numString: string, delta: number): string {
42
let m: RegExpMatchArray | null;
43
const decimals = (m = numString.match(/\.(\d+)$/)) ? m[1].length : 1;
44
let output = String((parseFloat(numString) + delta).toFixed(decimals)).replace(/\.0+$/, '');
45
46
if (m = numString.match(/^\-?(0\d+)/)) {
47
// padded number: preserve padding
48
output = output.replace(/^(\-?)(\d+)/, (_, minus, prefix) =>
49
minus + '0'.repeat(Math.max(0, (m ? m[1].length : 0) - prefix.length)) + prefix);
50
}
51
52
if (/^\-?\./.test(numString)) {
53
// omit integer part
54
output = output.replace(/^(\-?)0+/, '$1');
55
}
56
57
return output;
58
}
59
60
/**
61
* Locates number from given position in the document
62
*
63
* @return Range of number or `undefined` if not found
64
*/
65
export function locate(document: vscode.TextDocument, pos: vscode.Position): vscode.Range | undefined {
66
67
const line = document.lineAt(pos.line).text;
68
let start = pos.character;
69
let end = pos.character;
70
let hadDot = false, hadMinus = false;
71
let ch;
72
73
while (start > 0) {
74
ch = line[--start];
75
if (ch === '-') {
76
hadMinus = true;
77
break;
78
} else if (ch === '.' && !hadDot) {
79
hadDot = true;
80
} else if (!reNumber.test(ch)) {
81
start++;
82
break;
83
}
84
}
85
86
if (line[end] === '-' && !hadMinus) {
87
end++;
88
}
89
90
while (end < line.length) {
91
ch = line[end++];
92
if (ch === '.' && !hadDot && reNumber.test(line[end])) {
93
// A dot must be followed by a number. Otherwise stop parsing
94
hadDot = true;
95
} else if (!reNumber.test(ch)) {
96
end--;
97
break;
98
}
99
}
100
101
// ensure that found range contains valid number
102
if (start !== end && isValidNumber(line.slice(start, end))) {
103
return new vscode.Range(pos.line, start, pos.line, end);
104
}
105
106
return;
107
}
108
109
/**
110
* Check if given string contains valid number
111
*/
112
function isValidNumber(str: string): boolean {
113
return str ? !isNaN(parseFloat(str)) : false;
114
}
115
116