diff --git a/src/asciidocParser.ts b/src/asciidocParser.ts index fe043769..673ba28b 100644 --- a/src/asciidocParser.ts +++ b/src/asciidocParser.ts @@ -2,6 +2,8 @@ import * as vscode from 'vscode' import * as path from 'path' import { AsciidoctorWebViewConverter } from './asciidoctorWebViewConverter' import { Asciidoctor } from '@asciidoctor/core' +import { SkinnyTextDocument } from './util/document' +import { IncludeItems } from './asciidoctorFindIncludeProcessor' const asciidoctorFindIncludeProcessor = require('./asciidoctorFindIncludeProcessor') @@ -14,7 +16,6 @@ const highlightjsAdapter = require('./highlightjs-adapter') export class AsciidocParser { private stylesdir: string - public baseDocumentIncludeItems = null constructor (extensionUri: vscode.Uri, private errorCollection: vscode.DiagnosticCollection = null) { // Asciidoctor.js in the browser environment works with URIs however for desktop clients @@ -26,16 +27,35 @@ export class AsciidocParser { } } - public getMediaDir (text) { - return text.match(/^\\s*:mediadir:/) + // Load + + public load (textDocument: SkinnyTextDocument): { document: Asciidoctor.Document, baseDocumentIncludeItems: IncludeItems } { + const memoryLogger = processor.MemoryLogger.create() + processor.LoggerManager.setLogger(memoryLogger) + const registry = processor.Extensions.create() + asciidoctorFindIncludeProcessor.register(registry) + asciidoctorFindIncludeProcessor.resetIncludes() + const baseDir = this.getBaseDir(textDocument.fileName) + const document = processor.load(textDocument.getText(), { + attributes: { + 'env-vscode': '', + }, + extension_registry: registry, + sourcemap: true, + safe: 'unsafe', + ...(baseDir && { base_dir: baseDir }), + }) + // QUESTION: should we report error? + return { document, baseDocumentIncludeItems: asciidoctorFindIncludeProcessor.getBaseDocIncludes() } } + // Convert (preview) + public convertUsingJavascript ( text: string, doc: vscode.TextDocument, forHTMLSave: boolean, backend: string, - getDocumentInformation: boolean, context?: vscode.ExtensionContext, editor?: vscode.WebviewPanel ): {html: string, document: Asciidoctor.Document} { @@ -54,8 +74,6 @@ export class AsciidocParser { processor.LoggerManager.setLogger(memoryLogger) const registry = processor.Extensions.create() - // registry for processing document differently to find AST/metadata otherwise not available - const registryForDocumentInfo = processor.Extensions.create() const asciidoctorWebViewConverter = new AsciidoctorWebViewConverter() processor.ConverterFactory.register(asciidoctorWebViewConverter, ['webview-html5']) @@ -65,12 +83,6 @@ export class AsciidocParser { kroki.register(registry) } - // the include processor is only run to identify includes, not to process them - if (getDocumentInformation) { - asciidoctorFindIncludeProcessor.register(registryForDocumentInfo) - asciidoctorFindIncludeProcessor.resetIncludes() - } - if (context && editor) { highlightjsAdapter.register(highlightjsBuiltInSyntaxHighlighter, context, editor) } else { @@ -136,7 +148,7 @@ export class AsciidocParser { const options: { [key: string]: any } = { attributes: attributes, backend: backend, - extension_registry: getDocumentInformation ? registryForDocumentInfo : registry, + extension_registry: registry, header_footer: true, safe: 'unsafe', sourcemap: true, @@ -145,9 +157,6 @@ export class AsciidocParser { try { const document = processor.load(text, options) - if (getDocumentInformation) { - this.baseDocumentIncludeItems = asciidoctorFindIncludeProcessor.getBaseDocIncludes() - } const blocksWithLineNumber = document.findBy(function (b) { return typeof b.getLineNumber() !== 'undefined' }) @@ -173,7 +182,7 @@ export class AsciidocParser { context?: vscode.ExtensionContext, editor?: vscode.WebviewPanel ): Promise<{ html: string, document?: Asciidoctor.Document }> { - return this.convertUsingJavascript(text, doc, forHTMLSave, backend, false, context, editor) + return this.convertUsingJavascript(text, doc, forHTMLSave, backend, context, editor) } private reportErrors (memoryLogger: Asciidoctor.MemoryLogger, textDocument: vscode.TextDocument) { diff --git a/src/asciidoctorFindIncludeProcessor.ts b/src/asciidoctorFindIncludeProcessor.ts index 7b60a1e5..db918b54 100644 --- a/src/asciidoctorFindIncludeProcessor.ts +++ b/src/asciidoctorFindIncludeProcessor.ts @@ -5,7 +5,7 @@ interface IncludeEntry { length: string, } -interface IncludeItems extends Array{} +export interface IncludeItems extends Array{} let baseDocIncludes: IncludeItems = [] let includeIndex = 0 diff --git a/src/features/documentLinkProvider.ts b/src/features/documentLinkProvider.ts index 533b016d..7a31a874 100644 --- a/src/features/documentLinkProvider.ts +++ b/src/features/documentLinkProvider.ts @@ -48,15 +48,12 @@ export default class LinkProvider implements vscode.DocumentLinkProvider { this.engine = engine } - public provideDocumentLinks ( - textDocument: vscode.TextDocument, - _token: vscode.CancellationToken - ): vscode.DocumentLink[] { + public provideDocumentLinks (textDocument: vscode.TextDocument, _token: vscode.CancellationToken): vscode.DocumentLink[] { const asciidocParser = this.engine.getEngine() - const { document } = asciidocParser.convertUsingJavascript(textDocument.getText(), textDocument, false, 'webview-html5', true) + const { document, baseDocumentIncludeItems } = asciidocParser.load(textDocument) // includes from the reader are resolved correctly but the line numbers may be offset and not exactly match the document - let baseDocumentProcessorIncludes = asciidocParser.baseDocumentIncludeItems + let baseDocumentProcessorIncludes = baseDocumentIncludeItems const includeDirective = /^(\\)?include::([^[][^[]*)\[([^\n]+)?\]$/ // get includes from document text. These may be inside ifeval or ifdef but the line numbers are correct. const baseDocumentRegexIncludes = new Map() diff --git a/src/features/documentSymbolProvider.ts b/src/features/documentSymbolProvider.ts index 09fedc36..e4c6654f 100644 --- a/src/features/documentSymbolProvider.ts +++ b/src/features/documentSymbolProvider.ts @@ -4,7 +4,8 @@ import * as vscode from 'vscode' import { AsciidocEngine } from '../asciidocEngine' -import { TableOfContentsProvider, SkinnyTextDocument, TocEntry } from '../tableOfContentsProvider' +import { TableOfContentsProvider, TocEntry } from '../tableOfContentsProvider' +import { SkinnyTextDocument } from '../util/document' interface AsciidocSymbol { readonly level: number; diff --git a/src/features/workspaceSymbolProvider.ts b/src/features/workspaceSymbolProvider.ts index cdf2c0d5..653263c0 100644 --- a/src/features/workspaceSymbolProvider.ts +++ b/src/features/workspaceSymbolProvider.ts @@ -7,7 +7,7 @@ import { disposeAll } from '../util/dispose' import { isAsciidocFile } from '../util/file' import { Lazy, lazy } from '../util/lazy' import AdocDocumentSymbolProvider from './documentSymbolProvider' -import { SkinnyTextDocument } from '../tableOfContentsProvider' +import { SkinnyTextDocument } from '../util/document' export interface WorkspaceAsciidocDocumentProvider { getAllAsciidocDocuments(): Promise>; diff --git a/src/tableOfContentsProvider.ts b/src/tableOfContentsProvider.ts index f3883f94..8a950571 100644 --- a/src/tableOfContentsProvider.ts +++ b/src/tableOfContentsProvider.ts @@ -5,6 +5,7 @@ import * as vscode from 'vscode' import { AsciidocEngine } from './asciidocEngine' import { githubSlugifier, Slug } from './slugify' +import { SkinnyTextDocument } from './util/document' export interface TocEntry { readonly slug: Slug; @@ -14,15 +15,6 @@ export interface TocEntry { readonly location: vscode.Location; } -export interface SkinnyTextDocument { - readonly uri: vscode.Uri; - readonly lineCount: number; - - getText(): string; - - lineAt(line: number): vscode.TextLine; -} - export class TableOfContentsProvider { private toc?: TocEntry[] diff --git a/src/util/document.ts b/src/util/document.ts new file mode 100644 index 00000000..c7ed2d96 --- /dev/null +++ b/src/util/document.ts @@ -0,0 +1,42 @@ +import { TextLine, Uri } from 'vscode' + +export interface SkinnyTextDocument { + /** + * The associated uri for this document. + * + * *Note* that most documents use the `file`-scheme, which means they are files on disk. However, **not** all documents are + * saved on disk and therefore the `scheme` must be checked before trying to access the underlying file or siblings on disk. + * + * @see {@link FileSystemProvider} + * @see {@link TextDocumentContentProvider} + */ + readonly uri: Uri; + + /** + * The file system path of the associated resource. Shorthand + * notation for {@link TextDocument.uri TextDocument.uri.fsPath}. Independent of the uri scheme. + */ + readonly fileName: string; + + /** + * The number of lines in this document. + */ + readonly lineCount: number; + + /** + * Get the text of this document. + * + * @return The entire text. + */ + getText(): string; + + /** + * Returns a text line denoted by the line number. Note + * that the returned object is *not* live and changes to the + * document are not reflected. + * + * @param line A line number in [0, lineCount). + * @return A {@link TextLine line}. + */ + lineAt(line: number): TextLine; +}