diff --git a/package.json b/package.json index 5842af25..5defc850 100644 --- a/package.json +++ b/package.json @@ -556,6 +556,16 @@ "type": "boolean", "default": false, "markdownDescription": "%asciidoc.antora.enableAntoraSupport.desc%" + }, + "asciidoc.antora.search.antoraConfig": { + "type": "array", + "default": ["**/antora.yml"], + "markdownDescription": "%asciidoc.antora.search.antoraConfig.desc%" + }, + "asciidoc.antora.search.exclude": { + "type": "array", + "default": [], + "markdownDescription": "%asciidoc.antora.search.exclude.desc%" } } } diff --git a/package.nls.de.json b/package.nls.de.json index cf9cbc93..e3167f8b 100644 --- a/package.nls.de.json +++ b/package.nls.de.json @@ -69,5 +69,7 @@ "asciidoc.use_kroki.desc": "**Veraltet:** Aktiviert die Kroki-Integration zur Generierung von Diagrammen.", "asciidoc.use_kroki.deprecationMessage": "Diese Einstellung wurde durch `#asciidoc.extensions.enableKroki#` ersetzt und hat keine Auswirkungen mehr.", "asciidoc.antora.title": "Antora", - "asciidoc.antora.enableAntoraSupport.desc": "Aktiviere [Antora](https://antora.org/) Unterstützung." + "asciidoc.antora.enableAntoraSupport.desc": "Aktiviere [Antora](https://antora.org/) Unterstützung.", + "asciidoc.antora.search.antoraConfig.desc": "Antora config globs", + "asciidoc.antora.search.exclude.desc": "Globs to exclude from antora file search" } \ No newline at end of file diff --git a/package.nls.fr.json b/package.nls.fr.json index f4e82903..5ff44828 100644 --- a/package.nls.fr.json +++ b/package.nls.fr.json @@ -69,5 +69,7 @@ "asciidoc.use_kroki.desc": "**Obsolète:** Active l'extension Kroki afin de générer des diagrammes.", "asciidoc.use_kroki.deprecationMessage": "Ce paramètre a été remplacé par `#asciidoc.extensions.enableKroki#` et n'a plus aucun effet.", "asciidoc.antora.title": "Antora", - "asciidoc.antora.enableAntoraSupport.desc": "Active le support [Antora](https://antora.org/)." + "asciidoc.antora.enableAntoraSupport.desc": "Active le support [Antora](https://antora.org/).", + "asciidoc.antora.search.antoraConfig.desc": "Antora config globs", + "asciidoc.antora.search.exclude.desc": "Globs to exclude from antora file search" } \ No newline at end of file diff --git a/package.nls.ja.json b/package.nls.ja.json index 4393c7ed..e2398015 100644 --- a/package.nls.ja.json +++ b/package.nls.ja.json @@ -69,5 +69,7 @@ "asciidoc.use_kroki.desc": "**非推奨:** ダイアグラム生成Krokiを使用します。", "asciidoc.use_kroki.deprecationMessage": "本設定は、`#asciidoc.extensions.enableKroki#`に置き換えられ、動作しません。", "asciidoc.antora.title": "Antora", - "asciidoc.antora.enableAntoraSupport.desc": "[Antora](https://antora.org/)サポートを有効にします。" + "asciidoc.antora.enableAntoraSupport.desc": "[Antora](https://antora.org/)サポートを有効にします。", + "asciidoc.antora.search.antoraConfig.desc": "Antora config globs", + "asciidoc.antora.search.exclude.desc": "Globs to exclude from antora file search" } \ No newline at end of file diff --git a/package.nls.json b/package.nls.json index b47e00f7..c3b3e8a5 100644 --- a/package.nls.json +++ b/package.nls.json @@ -78,5 +78,7 @@ "asciidoc.use_kroki.deprecationMessage": "This setting has been replaced by `#asciidoc.extensions.enableKroki#` and no longer has any effect.", "asciidoc.antora.title": "Antora", - "asciidoc.antora.enableAntoraSupport.desc": "Enable [Antora](https://antora.org/) support." + "asciidoc.antora.enableAntoraSupport.desc": "Enable [Antora](https://antora.org/) support.", + "asciidoc.antora.search.antoraConfig.desc": "Antora config globs", + "asciidoc.antora.search.exclude.desc": "Globs to exclude from antora file search" } diff --git a/src/features/antora/antoraConfigs.ts b/src/features/antora/antoraConfigs.ts new file mode 100644 index 00000000..9d4e15a0 --- /dev/null +++ b/src/features/antora/antoraConfigs.ts @@ -0,0 +1,99 @@ +import vscode, { CancellationTokenSource, FileType } from 'vscode' +import { findAntoraFiles } from './findAntoraFiles' +import yaml from 'js-yaml' +import ospath from 'path' + +export class AntoraConfig { + public contentSourceRootPath: string + public contentSourceRootFsPath: string + + private static versionMap = new Map() + + constructor (public uri: vscode.Uri, public config: { [key: string]: any }) { + const path = uri.path + this.contentSourceRootPath = path.slice(0, path.lastIndexOf('/')) + this.contentSourceRootFsPath = ospath.dirname(uri.fsPath) + if (config.version === true || config.version === undefined) { + config.version = this.getVersionForPath(path) + } + } + + public getVersionForPath (path: string): string { + const version = AntoraConfig.versionMap.get(path) + if (version) return `V-${version}` + + const nextVersion = AntoraConfig.versionMap.size + 1 + AntoraConfig.versionMap.set(path, nextVersion) + return `V-${nextVersion}` + } +} + +const cache = { + antoraConfigs: [] as AntoraConfig[], + antoraConfigUris: [] as vscode.Uri[], +} + +let ongoingRefreshPromise : Promise | undefined + +async function refreshAntoraConfigs (token?: vscode.CancellationToken) { + if (!ongoingRefreshPromise) { + ongoingRefreshPromise = asyncTriggerRefresh(token).then(() => { + ongoingRefreshPromise = undefined + }) + } + await ongoingRefreshPromise + + async function asyncTriggerRefresh (token: vscode.CancellationToken): Promise { + const antoraConfigArray = vscode.workspace.getConfiguration('asciidoc.antora.search', null).get('antoraConfig') + const glob = '{' + antoraConfigArray.join(',') + '}' + const antoraConfigUris = await findAntoraFiles(glob, token) + + const cancellationToken = new CancellationTokenSource() + cancellationToken.token.onCancellationRequested((e) => { + console.log('Cancellation requested, cause: ' + e) + }) + // check for Antora configuration + const antoraConfigs = (await Promise.all(antoraConfigUris.map(async (antoraConfigUri) => { + let config = {} + const parentPath = antoraConfigUri.path.slice(0, antoraConfigUri.path.lastIndexOf('/')) + const parentDirectoryStat = await vscode.workspace.fs.stat(antoraConfigUri.with({ path: parentPath })) + if (parentDirectoryStat.type === (FileType.Directory | FileType.SymbolicLink) || parentDirectoryStat.type === FileType.SymbolicLink) { + // ignore! + return undefined + } + try { + config = yaml.load(await vscode.workspace.fs.readFile(antoraConfigUri)) || {} + } catch (err) { + console.log(`Unable to parse ${antoraConfigUri}, cause:` + err.toString()) + } + return new AntoraConfig(antoraConfigUri, config) + }))).filter((c) => c) // filter undefined + + cache.antoraConfigs = antoraConfigs + cache.antoraConfigUris = antoraConfigUris + } +} + +export async function getAntoraConfigs (token?: vscode.CancellationToken) { + if (!cache.antoraConfigs.length) { + await refreshAntoraConfigs(token) + } + return cache.antoraConfigs +} + +export async function getAntoraConfigUris (token?: vscode.CancellationToken) { + if (!cache.antoraConfigUris.length) { + await refreshAntoraConfigs(token) + } + return cache.antoraConfigUris +} + +// initial refresh of antora configs +refreshAntoraConfigs() + +// Update the configs when an antora.yml file changes +vscode.workspace.onDidChangeTextDocument(async (event) => { + if (event.document.uri.path.endsWith('antora.yml')) { + await refreshAntoraConfigs() + } +}) diff --git a/src/features/antora/antoraSupport.ts b/src/features/antora/antoraSupport.ts index 41668f5b..e544fec0 100644 --- a/src/features/antora/antoraSupport.ts +++ b/src/features/antora/antoraSupport.ts @@ -1,4 +1,4 @@ -import vscode, { CancellationTokenSource, FileType, Memento, Uri } from 'vscode' +import vscode, { CancellationTokenSource, Memento, Uri } from 'vscode' import fs from 'fs' import yaml from 'js-yaml' import ospath, { posix as posixpath } from 'path' @@ -9,6 +9,9 @@ import ContentCatalog from '@antora/content-classifier/content-catalog' import { getWorkspaceFolder } from '../../util/workspace' import { dir, exists } from '../../util/file' import * as contentClassifier from '@antora/content-classifier' +import { AntoraConfig, getAntoraConfigs, getAntoraConfigUris } from './antoraConfigs' +import { findAntoraFiles } from './findAntoraFiles' + const classifyContent = contentClassifier.default || contentClassifier const MAX_DEPTH_SEARCH_ANTORA_CONFIG = 100 @@ -19,32 +22,6 @@ export interface AntoraResourceContext { version: string; module: string; } - -export class AntoraConfig { - public contentSourceRootPath: string - public contentSourceRootFsPath: string - - private static versionMap = new Map() - - constructor (public uri: vscode.Uri, public config: { [key: string]: any }) { - const path = uri.path - this.contentSourceRootPath = path.slice(0, path.lastIndexOf('/')) - this.contentSourceRootFsPath = ospath.dirname(uri.fsPath) - if (config.version === true || config.version === undefined) { - config.version = this.getVersionForPath(path) - } - } - - public getVersionForPath (path: string): string { - const version = AntoraConfig.versionMap.get(path) - if (version) return `V-${version}` - - const nextVersion = AntoraConfig.versionMap.size + 1 - AntoraConfig.versionMap.set(path, nextVersion) - return `V-${nextVersion}` - } -} - export class AntoraDocumentContext { private PERMITTED_FAMILIES = ['attachment', 'example', 'image', 'page', 'partial'] @@ -192,8 +169,8 @@ export async function findAntoraConfigFile (textDocumentUri: Uri): Promise { console.log('Cancellation requested, cause: ' + e) }) - const antoraConfigUris = await vscode.workspace.findFiles('**/antora.yml', undefined, 100, cancellationToken.token) - // check for Antora configuration + const antoraConfigUris = await getAntoraConfigUris(cancellationToken.token) + for (const antoraConfigUri of antoraConfigUris) { const antoraConfigParentDirPath = antoraConfigUri.path.slice(0, antoraConfigUri.path.lastIndexOf('/')) const modulesDirPath = posixpath.normalize(`${antoraConfigParentDirPath}/modules`) @@ -233,31 +210,6 @@ export async function antoraConfigFileExists (textDocumentUri: Uri): Promise { - const cancellationToken = new CancellationTokenSource() - cancellationToken.token.onCancellationRequested((e) => { - console.log('Cancellation requested, cause: ' + e) - }) - const antoraConfigUris = await vscode.workspace.findFiles('**/antora.yml', undefined, 100, cancellationToken.token) - // check for Antora configuration - const antoraConfigs = await Promise.all(antoraConfigUris.map(async (antoraConfigUri) => { - let config = {} - const parentPath = antoraConfigUri.path.slice(0, antoraConfigUri.path.lastIndexOf('/')) - const parentDirectoryStat = await vscode.workspace.fs.stat(antoraConfigUri.with({ path: parentPath })) - if (parentDirectoryStat.type === (FileType.Directory | FileType.SymbolicLink) || parentDirectoryStat.type === FileType.SymbolicLink) { - // ignore! - return undefined - } - try { - config = yaml.load(await vscode.workspace.fs.readFile(antoraConfigUri)) || {} - } catch (err) { - console.log(`Unable to parse ${antoraConfigUri}, cause:` + err.toString()) - } - return new AntoraConfig(antoraConfigUri, config) - })) - return antoraConfigs.filter((c) => c) // filter undefined -} - export async function getAntoraConfig (textDocumentUri: Uri): Promise { const antoraConfigUri = await findAntoraConfigFile(textDocumentUri) if (antoraConfigUri === undefined) { @@ -293,7 +245,8 @@ export async function getAntoraDocumentContext (textDocumentUri: Uri, workspaceS const workspaceFolder = getWorkspaceFolder(antoraConfig.uri) const workspaceRelative = posixpath.relative(workspaceFolder.uri.path, antoraConfig.contentSourceRootPath) const globPattern = 'modules/*/{attachments,examples,images,pages,partials,assets}/**' - const files = await Promise.all((await vscode.workspace.findFiles(`${workspaceRelative ? `${workspaceRelative}/` : ''}${globPattern}`)).map(async (file) => { + // const files = await Promise.all((await vscode.workspace.findFiles(`${workspaceRelative ? `${workspaceRelative}/` : ''}${globPattern}`)).map(async (file) => { + const files = await Promise.all((await findAntoraFiles(`${workspaceRelative ? `${workspaceRelative}/` : ''}${globPattern}`)).map(async (file) => { const contentSourceRootPath = antoraConfig.contentSourceRootPath return { base: contentSourceRootPath, diff --git a/src/features/antora/findAntoraFiles.ts b/src/features/antora/findAntoraFiles.ts new file mode 100644 index 00000000..c2f0b603 --- /dev/null +++ b/src/features/antora/findAntoraFiles.ts @@ -0,0 +1,7 @@ +import vscode from 'vscode' + +export async function findAntoraFiles (glob: string, token?: vscode.CancellationToken) { + const excludeArray = vscode.workspace.getConfiguration('asciidoc.antora.search', null).get('exclude') + const excludeString = '{' + excludeArray.join(',') + '}' + return vscode.workspace.findFiles(glob, excludeString, 100, token) +}