mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-21 17:22:55 -05:00
* Initial port of release/0.24 source code * Fix additional headers * Fix a typo in launch.json
95 lines
2.4 KiB
TypeScript
95 lines
2.4 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
'use strict';
|
|
|
|
import * as vscode from 'vscode';
|
|
|
|
import { MarkdownEngine } from './markdownEngine';
|
|
|
|
export interface TocEntry {
|
|
slug: string;
|
|
text: string;
|
|
level: number;
|
|
line: number;
|
|
location: vscode.Location;
|
|
}
|
|
|
|
export class TableOfContentsProvider {
|
|
private toc: TocEntry[];
|
|
|
|
public constructor(
|
|
private engine: MarkdownEngine,
|
|
private document: vscode.TextDocument
|
|
) { }
|
|
|
|
public async getToc(): Promise<TocEntry[]> {
|
|
if (!this.toc) {
|
|
try {
|
|
this.toc = await this.buildToc(this.document);
|
|
} catch (e) {
|
|
this.toc = [];
|
|
}
|
|
}
|
|
return this.toc;
|
|
}
|
|
|
|
public async lookup(fragment: string): Promise<number> {
|
|
const slug = TableOfContentsProvider.slugify(fragment);
|
|
for (const entry of await this.getToc()) {
|
|
if (entry.slug === slug) {
|
|
return entry.line;
|
|
}
|
|
}
|
|
return NaN;
|
|
}
|
|
|
|
private async buildToc(document: vscode.TextDocument): Promise<TocEntry[]> {
|
|
const toc: TocEntry[] = [];
|
|
const tokens = await this.engine.parse(document.uri, document.getText());
|
|
|
|
for (const heading of tokens.filter(token => token.type === 'heading_open')) {
|
|
const lineNumber = heading.map[0];
|
|
const line = document.lineAt(lineNumber);
|
|
const href = TableOfContentsProvider.slugify(line.text);
|
|
const level = TableOfContentsProvider.getHeaderLevel(heading.markup);
|
|
if (href) {
|
|
toc.push({
|
|
slug: href,
|
|
text: TableOfContentsProvider.getHeaderText(line.text),
|
|
level: level,
|
|
line: lineNumber,
|
|
location: new vscode.Location(document.uri, line.range)
|
|
});
|
|
}
|
|
}
|
|
return toc;
|
|
}
|
|
|
|
private static getHeaderLevel(markup: string): number {
|
|
if (markup === '=') {
|
|
return 1;
|
|
} else if (markup === '-') {
|
|
return 2;
|
|
} else { // '#', '##', ...
|
|
return markup.length;
|
|
}
|
|
}
|
|
|
|
private static getHeaderText(header: string): string {
|
|
return header.replace(/^\s*#+\s*(.*?)\s*#*$/, (_, word) => word.trim());
|
|
}
|
|
|
|
public static slugify(header: string): string {
|
|
return encodeURI(header.trim()
|
|
.toLowerCase()
|
|
.replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~\`]/g, '')
|
|
.replace(/\s+/g, '-')
|
|
.replace(/^\-+/, '')
|
|
.replace(/\-+$/, ''));
|
|
}
|
|
}
|
|
|