/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as vscode from 'vscode'; import { MarkdownEngine } from '../markdownEngine'; import { TableOfContentsProvider, SkinnyTextDocument, TocEntry } from '../tableOfContentsProvider'; interface MarkdownSymbol { readonly level: number; readonly parent: MarkdownSymbol | undefined; readonly children: vscode.DocumentSymbol[]; } export default class MDDocumentSymbolProvider implements vscode.DocumentSymbolProvider { constructor( private readonly engine: MarkdownEngine ) { } public async provideDocumentSymbolInformation(document: SkinnyTextDocument): Promise { const toc = await new TableOfContentsProvider(this.engine, document).getToc(); return toc.map(entry => this.toSymbolInformation(entry)); } public async provideDocumentSymbols(document: SkinnyTextDocument): Promise { const toc = await new TableOfContentsProvider(this.engine, document).getToc(); const root: MarkdownSymbol = { level: -Infinity, children: [], parent: undefined }; this.buildTree(root, toc); return root.children; } private buildTree(parent: MarkdownSymbol, entries: TocEntry[]) { if (!entries.length) { return; } const entry = entries[0]; const symbol = this.toDocumentSymbol(entry); symbol.children = []; while (parent && entry.level <= parent.level) { parent = parent.parent!; } parent.children.push(symbol); this.buildTree({ level: entry.level, children: symbol.children, parent }, entries.slice(1)); } private toSymbolInformation(entry: TocEntry): vscode.SymbolInformation { return new vscode.SymbolInformation( this.getSymbolName(entry), vscode.SymbolKind.String, '', entry.location); } private toDocumentSymbol(entry: TocEntry) { return new vscode.DocumentSymbol( this.getSymbolName(entry), '', vscode.SymbolKind.String, entry.location.range, entry.location.range); } private getSymbolName(entry: TocEntry): string { return '#'.repeat(entry.level) + ' ' + entry.text; } }