Minor fix. Improve folding.

This commit is contained in:
CismonX 2020-10-26 01:52:13 +08:00
parent 3b34510feb
commit f2a77ff8d1
Signed by: cismonx
GPG Key ID: 3094873E29A482FB
4 changed files with 43 additions and 23 deletions

View File

@ -10,6 +10,9 @@ import DocumentSymbolContext from './document_symbol';
import FoldingRangeContext from './folding_range';
import PreviewContext from './preview';
/**
* Holds all contexts for a Texinfo document.
*/
export default class DocumentContext {
readonly foldingRange = new FoldingRangeContext(this.document);

View File

@ -17,17 +17,17 @@ export default class DocumentSymbolContext {
private document = this.documentContext.document;
private symbols?: vscode.DocumentSymbol[];
private documentSymbols?: vscode.DocumentSymbol[];
private foldingRanges?: readonly FoldingRange[];
get values() {
return this.symbols ??= this.calculcateDocumentSymbols();
return this.documentSymbols ??= this.calculcateDocumentSymbols();
}
clear() {
this.foldingRanges = undefined;
this.symbols = undefined;
this.documentSymbols = undefined;
}
constructor(private readonly documentContext: DocumentContext) {}
@ -39,7 +39,7 @@ export default class DocumentSymbolContext {
const ranges = Array<RangeNode>(this.document.lineCount);
(this.foldingRanges ??= this.documentContext.foldingRange.values)
.forEach(range => range.kind ?? (ranges[range.start] = range));
return this.symbols = foldingRangeToSymbols(ranges, 0, ranges.length);
return this.documentSymbols = foldingRangeToSymbols(ranges, 0, ranges.length);
}
}

View File

@ -13,6 +13,12 @@ import { FoldingRange, Range } from '../utils/types';
*/
export default class FoldingRangeContext {
/**
* Regex for matching subsection/section/chapter (-like) commands.
*/
private static nodeMatcher = new RegExp('^@(?:(subsection|unnumberedsubsec|appendixsubsec|subheading)|' +
'(section|unnumberedsec|appendixsec|heading)|(chapter|unnumbered|appendix|majorheading|chapheading)) (.*)$');
/**
* Get VSCode folding ranges from the context.
*/
@ -58,8 +64,8 @@ export default class FoldingRangeContext {
*/
private calculateFoldingRanges() {
this.foldingRanges = [];
this.headerStart = undefined;
const closingBlocks = <{ name: string, line: number }[]>[];
this.clearTemporaries();
let closingBlocks = <ClosingBlock[]>[];
let lastLine = this.document.lineCount - 1;
let verbatim = false;
for (let idx = lastLine; idx >= 0; --idx) {
@ -70,8 +76,8 @@ export default class FoldingRangeContext {
lastLine = idx;
// Abort anything after `@bye`.
this.foldingRanges = [];
this.commentRange = undefined;
this.headerStart = undefined;
closingBlocks = [];
this.clearTemporaries();
continue;
}
if (this.processComment(line, idx)) continue;
@ -97,7 +103,6 @@ export default class FoldingRangeContext {
}
if (this.commentRange !== undefined) {
this.addRange(this.commentRange.start, this.commentRange.end, { kind: vscode.FoldingRangeKind.Comment });
this.commentRange = undefined;
}
return this.foldingRanges;
}
@ -129,19 +134,23 @@ export default class FoldingRangeContext {
constructor(private readonly document: vscode.TextDocument) {}
private processNode(lineText: string, lineNum: number, lastLineNum: number) {
if (lineText.startsWith('@subsection ')) {
const detail = lineText.substring(12);
this.addRange(lineNum, this.closingSubsection ?? lastLineNum, { name: 'subsection', detail: detail });
const result = lineText.match(FoldingRangeContext.nodeMatcher);
if (result === null) return false;
// Subsection level node.
if (result[1] !== undefined) {
this.addRange(lineNum, this.closingSubsection ?? lastLineNum, { name: result[1], detail: result[4] });
this.closingSubsection = this.getLastTextLine(lineNum - 1);
return true;
} else if (lineText.startsWith('@section ')) {
const detail = lineText.substring(9);
this.addRange(lineNum, this.closingSection ?? lastLineNum, { name: 'section', detail: detail });
}
// Section level node.
if (result[2] !== undefined) {
this.addRange(lineNum, this.closingSection ?? lastLineNum, { name: result[2], detail: result[4] });
this.closingSubsection = this.closingSection = this.getLastTextLine(lineNum - 1);
return true;
} else if (lineText.startsWith('@chapter ')) {
const detail = lineText.substring(9);
this.addRange(lineNum, this.closingChapter ?? lastLineNum, { name: 'chapter', detail: detail });
}
// Chapter level node.
if (result[3] !== undefined) {
this.addRange(lineNum, this.closingChapter ?? lastLineNum, { name: result[3], detail: result[4] });
this.closingSubsection = this.closingSection = this.closingChapter = this.getLastTextLine(lineNum - 1);
return true;
}
@ -165,4 +174,12 @@ export default class FoldingRangeContext {
(this.foldingRanges ??= [])
.push(new FoldingRange(extraArgs.name ?? '', extraArgs.detail ?? '', start, end, extraArgs.kind));
}
private clearTemporaries() {
this.commentRange = undefined;
this.headerStart = undefined;
this.closingSubsection = this.closingSection = this.closingChapter = undefined;
}
}
type ClosingBlock = { name: string, line: number };

View File

@ -30,16 +30,16 @@ export function exec(path: string, args: string[], maxBuffer: number) {
}
/**
* Open a prompt with two buttons, "Confirm" and "Cancel", and wait for user action.
* Open a prompt with a button, and wait for user action.
*
* @param message The message to be displayed on the prompt.
* @param confirm Text to be displayed on the "Confirm" button.
* @param label Text to be displayed on the button.
* @param error Whether the prompt is shown as an error message. Default false.
* @returns Whether the user clicked the "Confirm" button.
* @returns Whether the user clicked the button.
*/
export async function prompt(message: string, confirm: string, error = false) {
export async function prompt(message: string, label: string, error = false) {
const func = error ? vscode.window.showErrorMessage : vscode.window.showInformationMessage;
return confirm === await func(message, confirm, 'Cancel');
return label === await func(message, label);
}
/**