diff --git a/src/completions.ts b/src/completions.ts index 343b131..bbd55a5 100644 --- a/src/completions.ts +++ b/src/completions.ts @@ -1,7 +1,7 @@ import * as vscode from "vscode"; import * as fs from "fs"; import { _context } from "./extension"; -import { labels } from "./extension"; +// import { labels } from "./extension"; import { elementChildren } from "./constants"; function readJsonFile(relativePath: string): any { @@ -225,51 +225,53 @@ async function elementCompletions( return elementCompletionItems; } -async function refCompletions( - document: vscode.TextDocument, - position: vscode.Position, - token: vscode.CancellationToken, - context: vscode.CompletionContext -) { - // const refs = readJsonFile("snippets/pretext-attributes.json"); - const linePrefix = document - .lineAt(position.line) - .text.slice(0, position.character); - let completionItems: vscode.CompletionItem[] = []; - if (linePrefix.match(/ { - // labels = await utils.updateReferences(document, labels); - // }); + ///////////////// Commands ////////////////////// context.subscriptions.push( diff --git a/src/lsp-server/completions/get-completions.ts b/src/lsp-server/completions/get-completions.ts index 1356052..15982fb 100644 --- a/src/lsp-server/completions/get-completions.ts +++ b/src/lsp-server/completions/get-completions.ts @@ -17,6 +17,7 @@ import { import { ATTRIBUTES, ELEMENTS } from "./constants"; import { Position, Range, TextDocument } from "vscode-languageserver-textdocument"; import { elementChildren } from "../../constants"; +import { references } from "../main"; const LINK_CONTENT_NODES = new Set(["xsl", "source", "publication"]); @@ -83,9 +84,16 @@ export async function getCompletions( })]; console.log("completionItems", completionItems); } else if (completionType === "ref") { - // Form completions for references. - // return await refCompletions(params); - return null; + for (let [reference, parent] of references) { + const refCompletion: CompletionItem = { + label: reference, + kind: CompletionItemKind.Reference + };; + refCompletion.documentation = "(a " + parent + ")"; + refCompletion.detail = "(reference to " + parent + ")"; + refCompletion.sortText = "0" + reference; + completionItems.push(refCompletion); + } } else { // Completions for attributes and elements: // First, stop completions if the previous character (or the one before it in case a trigger character is used) is not a space. diff --git a/src/lsp-server/completions/utils.ts b/src/lsp-server/completions/utils.ts index 4d74427..cf7f40c 100644 --- a/src/lsp-server/completions/utils.ts +++ b/src/lsp-server/completions/utils.ts @@ -11,6 +11,8 @@ import { } from "vscode-languageserver/node"; import { documents } from "../state"; import { TextDocument } from "vscode-languageserver-textdocument"; +import path from "path"; +import { URI, Utils } from "vscode-uri"; export async function readJsonFile(relativePath: string): Promise { try { @@ -200,3 +202,115 @@ export async function getSnippetCompletionItems( } return completionItems; } + + + +function getMainFile() { + let dir = "./"; + // Set default main file to main.ptx + let mainFile = path.join(dir, "source", "main.ptx"); + // Check if project.ptx exists and if so, use that to find main file + let project = path.join(dir, "project.ptx"); + if (fs.existsSync(project)) { + console.log("Found project.ptx"); + const text = fs.readFileSync(project).toString(); + // Determine whether v1 or v2: + let regexVersion = /(.*?)<\/source>/; + let targetSourceMatch = regexTarget.exec(text); + if (targetSourceMatch) { + mainFile = path.join(dir, targetSourceMatch[1]); + } + } + } + console.log("Checking for main source file: ", mainFile); + if (fs.existsSync(mainFile)) { + console.log("Found main source file", mainFile); + return mainFile; + } else { + console.log("main source file not found"); + return ""; + } +} + + +// define a type for the array of labels: +type LabelArray = [string, string, string][]; + +/** + * Search through a project to find all xml:id's. Start with main.ptx and include any fine that is xi:included up to a depth of 5. + */ +export function getReferences(): LabelArray { + // Look through all files in project directory and collect all labels contained as xml:id attributes. + let baseFile = getMainFile(); + let references: LabelArray = []; + let files = [baseFile]; + let depth = 0; + // const uri = vscode.Uri.file(sourceDir); + // let files = await vscode.workspace.fs.readDirectory(uri); + while (depth < 5 && files.length > 0) { + let newFiles: string[] = []; + for (const file of files) { + if (fs.existsSync(file)) { + let text = fs.readFileSync(file).toString(); + let regex = / path.join(file, "..", match[1])) + ); + regex = /<(\w*?)\s(.*?)xml:id="([^"]+?)"/g; + matches = [...text.matchAll(regex)]; + const posixFile = file.replace(/\\/g, "/"); + references = references.concat( + matches.map((match) => [match[3], match[1], posixFile]) + ); + } + } + files = newFiles; + depth++; + } + console.log("Finished collecting references, reached depth of ", depth); + return references; +} + +export function updateReferences( + document: TextDocument, + references: LabelArray = [] +) { + console.log("Updating references"); + // Look through the specified file collect all labels contained as xml:id attributes. + // This can then be used to update the current list of references every time a file is saved. + let fileContents = document.getText(); + let regex = /<(\w*?)\s(.*?)xml:id="([^"]+)"/g; + let matches = [...fileContents.matchAll(regex)]; + const rootDir = fs.realpathSync("."); + console.log("Root directory: ", rootDir); + const currentFile = document.uri; + console.log("Current file: ", currentFile); + const posixFile = path.posix.relative(rootDir, currentFile); + console.log("Current file: ", posixFile); + // Remove all (old) labels from the current file: + references = references.filter((label) => label[2] !== posixFile); + // Add all (new) labels from the current file: + references = references.concat( + matches.map((match) => [match[3], match[1], posixFile]) + ); + console.log("Done updating labels"); + return references; +} \ No newline at end of file diff --git a/src/lsp-server/main.ts b/src/lsp-server/main.ts index 695fe50..cd3808d 100644 --- a/src/lsp-server/main.ts +++ b/src/lsp-server/main.ts @@ -29,12 +29,25 @@ import { getCompletionDetails, } from "./completions/get-completions"; import { formatDocument } from "./formatter"; +import { getReferences, updateReferences } from "./completions/utils"; let hasConfigurationCapability = false; let hasWorkspaceFolderCapability = false; export let hasDiagnosticRelatedInformationCapability = false; -connection.onInitialize((params: InitializeParams) => { + +type LabelArray = [string, string, string][]; +export let references: LabelArray = []; + + + + + + // vscode.workspace.onDidSaveTextDocument(async (document) => { + // labels = await utils.updateReferences(document, labels); + // }); + +connection.onInitialize( (params: InitializeParams) => { const capabilities = params.capabilities; // Does the client support the `workspace/configuration` request? @@ -92,6 +105,14 @@ connection.onInitialized(() => { connection.console.log("Workspace folder change event received."); }); } + + ///////////////// Completion Items ////////////////////// + references = []; + try { + references = getReferences(); + } catch { + console.log("Error getting references"); + } }); connection.onDidChangeConfiguration((change) => { @@ -128,6 +149,12 @@ documents.onDidChangeContent(async (change) => { } }); +documents.onDidSave((e) => { + // update references for the saved document + // TODO: this should just update references instead of finding all of them again. + references = getReferences(); +}); + connection.onDidChangeWatchedFiles((_change) => { // Monitored files have change in VSCode connection.console.log("We received a file change event"); diff --git a/src/utils.ts b/src/utils.ts index 28c68a6..95a1b45 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,6 +4,7 @@ import * as path from "path"; import * as vscode from "vscode"; import * as fs from "fs"; import { SpellCheckScope } from "./types"; +import { TextDocument } from "vscode-languageserver-textdocument"; export { getDir, @@ -49,49 +50,7 @@ function getDir(myPath: string = "") { } } -async function getMainFile() { - let dir = getDir(); - // Set default main file to main.ptx - let mainFile = path.join(dir, "source", "main.ptx"); - // Check if project.ptx exists and if so, use that to find main file - let project = path.join(dir, "project.ptx"); - if (fs.existsSync(project)) { - console.log("Found project.ptx"); - const text = fs.readFileSync(project).toString(); - // Determine whether v1 or v2: - let regexVersion = /(.*?)<\/source>/; - let targetSourceMatch = regexTarget.exec(text); - if (targetSourceMatch) { - mainFile = path.join(dir, targetSourceMatch[1]); - } - } - } - console.log("Checking for main source file: ", mainFile); - if (fs.existsSync(mainFile)) { - console.log("Found main source file"); - return mainFile; - } else { - console.log("main source file not found"); - return ""; - } -} + async function installPretext(progress: vscode.Progress<{}>) { // Here we will attempt to pip install pretext, upgraded to the most recent version. This will happen if pretext is not found, or if a user requests it through a command. @@ -432,63 +391,7 @@ function setupTerminal(terminal: vscode.Terminal): vscode.Terminal { return terminal; } -// define a type for the array of labels: -type LabelArray = [string, string, string][]; -/** - * Search through a project to find all xml:id's. Start with main.ptx and include any fine that is xi:included up to a depth of 5. - */ -export async function getReferences(): Promise { - // Look through all files in project directory and collect all labels contained as xml:id attributes. - let baseFile = await getMainFile(); - let labels: LabelArray = []; - let files = [baseFile]; - let depth = 0; - // const uri = vscode.Uri.file(sourceDir); - // let files = await vscode.workspace.fs.readDirectory(uri); - while (depth < 5 && files.length > 0) { - let newFiles: string[] = []; - for (const file of files) { - if (fs.existsSync(file)) { - let text = fs.readFileSync(file).toString(); - let regex = / path.join(file, "..", match[1])) - ); - regex = /<(\w*?)\s(.*?)xml:id="([^"]+?)"/g; - matches = [...text.matchAll(regex)]; - labels = labels.concat( - matches.map((match) => [match[3], match[1], file]) - ); - } - } - files = newFiles; - depth++; - } - console.log("Finished collecting labels, reached depth of ", depth); - return labels; -} - -export function updateReferences( - document: vscode.TextDocument, - labels: LabelArray = [] -) { - console.log("Updating references"); - // Look through the specified file collect all labels contained as xml:id attributes. - // This can then be used to update the current list of references every time a file is saved. - let fileContents = document.getText(); - let regex = /<(\w*?)\s(.*?)xml:id="([^"]+)"/g; - let matches = [...fileContents.matchAll(regex)]; - // Remove all (old) labels from the current file: - labels = labels.filter((label) => label[2] !== document.fileName); - // Add all (new) labels from the current file: - labels = labels.concat( - matches.map((match) => [match[3], match[1], document.fileName]) - ); - console.log("Done updating labels"); - return labels; -} function stripColorCodes(input: string): string { // ANSI color code regex