Skip to content

Commit 6e7cf50

Browse files
Adjust context help alignment for consistent indentation
1 parent 8db4fb5 commit 6e7cf50

File tree

2 files changed

+42
-130
lines changed

2 files changed

+42
-130
lines changed

package-lock.json

Lines changed: 15 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ccs/commands/contextHelp.ts

Lines changed: 27 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,10 @@ export async function resolveContextExpression(): Promise<void> {
1414
}
1515

1616
const { document, selection } = editor;
17-
const contextExpression = selection.isEmpty
18-
? document.lineAt(selection.active.line).text.trim()
19-
: document.getText(selection).trim();
17+
const contextInfo = getContextExpressionInfo(document, selection);
18+
const contextExpression = contextInfo.text;
2019

21-
if (!contextExpression) {
20+
if (!contextExpression.trim()) {
2221
void vscode.window.showErrorMessage("Context expression is empty.");
2322
return;
2423
}
@@ -41,35 +40,16 @@ export async function resolveContextExpression(): Promise<void> {
4140
}
4241

4342
const textExpression = normalizedTextExpression.replace(/\r?\n/g, eol);
44-
let formattedTextExpression = textExpression;
43+
const formattedTextExpression = textExpression;
4544

4645
let rangeToReplace: vscode.Range;
4746
if (selection.isEmpty) {
4847
const fallbackLine = document.lineAt(selection.active.line);
49-
const fallbackRange = fallbackLine.range;
50-
51-
rangeToReplace = getRangeToReplaceForLine(document, selection.active.line, contextExpression) ?? fallbackRange;
52-
53-
const preservedPrefix = document.getText(new vscode.Range(fallbackLine.range.start, rangeToReplace.start));
54-
55-
formattedTextExpression = normalizeInsertionWithPrefix(formattedTextExpression, preservedPrefix, eol);
48+
rangeToReplace = fallbackLine.range;
5649
} else {
57-
// Multi-line or partial selection
58-
const firstSelLine = document.lineAt(selection.start.line);
59-
const preservedPrefix = document.getText(new vscode.Range(firstSelLine.range.start, selection.start));
60-
const leadingWS = firstSelLine.text.match(/^[\t ]*/)?.[0] ?? "";
61-
62-
// 1) Normalize snippet to avoid duplicating "."/";" according to the prefix that will remain in the file
63-
formattedTextExpression = normalizeInsertionWithPrefix(formattedTextExpression, preservedPrefix, eol);
64-
65-
// 2) Only prefix indentation if the selection started at column 0 (i.e., NO preserved prefix)
66-
formattedTextExpression = maybePrefixFirstLineIndent(
67-
formattedTextExpression,
68-
preservedPrefix.length === 0 ? leadingWS : "",
69-
eol
70-
);
71-
72-
rangeToReplace = new vscode.Range(selection.start, selection.end);
50+
const start = document.lineAt(selection.start.line).range.start;
51+
const replacementEnd = contextInfo.replacementEnd ?? document.lineAt(selection.end.line).range.end;
52+
rangeToReplace = new vscode.Range(start, replacementEnd);
7353
}
7454

7555
await editor.edit((editBuilder) => {
@@ -92,112 +72,32 @@ export async function resolveContextExpression(): Promise<void> {
9272
}
9373
}
9474

95-
function getRangeToReplaceForLine(
96-
document: vscode.TextDocument,
97-
lineNumber: number,
98-
contextExpression: string
99-
): vscode.Range | undefined {
100-
if (!contextExpression) {
101-
return undefined;
102-
}
75+
type ContextExpressionInfo = {
76+
text: string;
77+
replacementEnd?: vscode.Position;
78+
};
10379

104-
const line = document.lineAt(lineNumber);
105-
const expressionIndex = line.text.indexOf(contextExpression);
106-
if (expressionIndex === -1) {
107-
return undefined;
80+
function getContextExpressionInfo(document: vscode.TextDocument, selection: vscode.Selection): ContextExpressionInfo {
81+
if (selection.isEmpty) {
82+
return {
83+
text: document.lineAt(selection.active.line).text,
84+
};
10885
}
10986

110-
const prefixLength = getPrefixLengthToPreserve(contextExpression);
111-
const startCharacter = expressionIndex + prefixLength;
112-
const endCharacter = expressionIndex + contextExpression.length;
113-
114-
const start = line.range.start.translate(0, startCharacter);
115-
const end = line.range.start.translate(0, endCharacter);
116-
return new vscode.Range(start, end);
117-
}
118-
119-
/**
120-
* Based on the preserved line prefix, remove from the BEGINNING of the snippet's first line:
121-
* - if the prefix ends with ";": remove ^[\t ]*(?:\.\s*)*;\s*
122-
* - otherwise, if it ends with dots: remove ^[\t ]*(?:\.\s*)+
123-
* - neutral case: try to remove comment; otherwise remove dots
124-
*/
125-
function normalizeInsertionWithPrefix(text: string, preservedPrefix: string, eol: string): string {
126-
const lines = text.split(/\r?\n/);
127-
if (lines.length === 0) return text;
128-
129-
const preservedEnd = preservedPrefix.replace(/\s+$/g, "");
130-
131-
const endsWithSemicolon = /(?:\.\s*)*;\s*$/.test(preservedEnd);
132-
const endsWithDotsOnly = !endsWithSemicolon && /(?:\.\s*)+$/.test(preservedEnd);
87+
const startLine = selection.start.line;
88+
const start = document.lineAt(startLine).range.start;
13389

134-
if (endsWithSemicolon) {
135-
lines[0] = lines[0].replace(/^[\t ]*(?:\.\s*)*;\s*/, "");
136-
} else if (endsWithDotsOnly) {
137-
lines[0] = lines[0].replace(/^[\t ]*(?:\.\s*)+/, "");
138-
} else {
139-
const removedComment = lines[0].replace(/^[\t ]*(?:\.\s*)?;\s*/, "");
140-
if (removedComment !== lines[0]) {
141-
lines[0] = removedComment;
142-
} else {
143-
lines[0] = lines[0].replace(/^[\t ]*(?:\.\s*)+/, "");
144-
}
90+
let lastLine = selection.end.line;
91+
if (selection.end.character === 0 && selection.end.line > selection.start.line) {
92+
lastLine = selection.end.line - 1;
14593
}
14694

147-
return lines.join(eol);
148-
}
149-
150-
/**
151-
* Prefix indentation (tabs/spaces) ONLY if provided.
152-
* Useful when the selection started at column 0 (no preserved prefix).
153-
*/
154-
function maybePrefixFirstLineIndent(text: string, leadingWS: string, eol: string): string {
155-
if (!text || !leadingWS) return text;
156-
const lines = text.split(/\r?\n/);
157-
if (lines.length === 0) return text;
158-
159-
// Do not force replacement if there is already some whitespace; just prefix it.
160-
lines[0] = leadingWS + lines[0];
161-
return lines.join(eol);
162-
}
163-
164-
/**
165-
* Keep: preserve level dots / indentation and, if present, '; ' before the typed content.
166-
* Returns how many characters of the contextExpression belong to that prefix.
167-
*/
168-
function getPrefixLengthToPreserve(contextExpression: string): number {
169-
let index = 0;
170-
171-
while (index < contextExpression.length) {
172-
const char = contextExpression[index];
173-
174-
if (char === ".") {
175-
index++;
176-
while (index < contextExpression.length && contextExpression[index] === " ") {
177-
index++;
178-
}
179-
continue;
180-
}
181-
182-
if (char === " " || char === "\t") {
183-
index++;
184-
continue;
185-
}
186-
187-
break;
188-
}
189-
190-
if (index < contextExpression.length && contextExpression[index] === ";") {
191-
index++;
192-
while (
193-
index < contextExpression.length &&
194-
(contextExpression[index] === " " || contextExpression[index] === "\t")
195-
) {
196-
index++;
197-
}
198-
}
95+
const end = document.lineAt(lastLine).range.end;
19996

200-
return index;
97+
return {
98+
text: document.getText(new vscode.Range(start, end)),
99+
replacementEnd: end,
100+
};
201101
}
202102

203103
function extractGifUri(text: string): {

0 commit comments

Comments
 (0)