mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-06 01:25:38 -05:00
SQL Operations Studio Public Preview 1 (0.23) release source code
This commit is contained in:
94
extensions/markdown/src/tableOfContentsProvider.ts
Normal file
94
extensions/markdown/src/tableOfContentsProvider.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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*\1*$/, (_, word) => `${word.trim()}`);
|
||||
}
|
||||
|
||||
public static slugify(header: string): string {
|
||||
return encodeURI(header.trim()
|
||||
.toLowerCase()
|
||||
.replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~\`]/g, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/^\-+/, '')
|
||||
.replace(/\-+$/, ''));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user