From ddec9899a27e97c4034c4351897c5d7c46faf894 Mon Sep 17 00:00:00 2001 From: James Yu Date: Sat, 7 Dec 2024 22:59:26 +0800 Subject: [PATCH 1/5] Sanitize double quoted input file paths --- src/outline/structure/latex.ts | 12 ++++++------ src/utils/inputfilepath.ts | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/outline/structure/latex.ts b/src/outline/structure/latex.ts index 3fd526f66..ae3fe33f9 100644 --- a/src/outline/structure/latex.ts +++ b/src/outline/structure/latex.ts @@ -4,7 +4,7 @@ import type * as Ast from '@unified-latex/unified-latex-types' import { lw } from '../../lw' import { type TeXElement, TeXElementType } from '../../types' import { resolveFile } from '../../utils/utils' -import { InputFileRegExp } from '../../utils/inputfilepath' +import { InputFileRegExp, sanitizeInputFilePath } from '../../utils/inputfilepath' import { argContentToStr } from '../../utils/parser' @@ -168,7 +168,7 @@ async function parseNode( ...attributes } } else if (node.type === 'macro' && ['input', 'InputIfFileExists', 'include', 'SweaveInput', 'subfile', 'loadglsentries', 'markdownInput'].includes(node.content)) { - const arg0 = argContentToStr(node.args?.[0]?.content || []) + const arg0 = sanitizeInputFilePath(argContentToStr(node.args?.[0]?.content || [])) const subFile = await resolveFile([ path.dirname(filePath), path.dirname(lw.root.file.path || ''), ...config.texDirs ], arg0) if (subFile) { element = { @@ -182,8 +182,8 @@ async function parseNode( } } } else if (node.type === 'macro' && ['import', 'inputfrom', 'includefrom'].includes(node.content)) { - const arg0 = argContentToStr(node.args?.[0]?.content || []) - const arg1 = argContentToStr(node.args?.[1]?.content || []) + const arg0 = sanitizeInputFilePath(argContentToStr(node.args?.[0]?.content || [])) + const arg1 = sanitizeInputFilePath(argContentToStr(node.args?.[1]?.content || [])) const subFile = await resolveFile([ arg0, path.join(path.dirname(lw.root.file.path || ''), arg0 )], arg1) if (subFile) { element = { @@ -197,8 +197,8 @@ async function parseNode( } } } else if (node.type === 'macro' && ['subimport', 'subinputfrom', 'subincludefrom'].includes(node.content)) { - const arg0 = argContentToStr(node.args?.[0]?.content || []) - const arg1 = argContentToStr(node.args?.[1]?.content || []) + const arg0 = sanitizeInputFilePath(argContentToStr(node.args?.[0]?.content || [])) + const arg1 = sanitizeInputFilePath(argContentToStr(node.args?.[1]?.content || [])) const subFile = await resolveFile([ path.dirname(filePath) ], path.join(arg0, arg1)) if (subFile) { element = { diff --git a/src/utils/inputfilepath.ts b/src/utils/inputfilepath.ts index 5909dc8c4..2ac8037e4 100644 --- a/src/utils/inputfilepath.ts +++ b/src/utils/inputfilepath.ts @@ -87,24 +87,33 @@ export class InputFileRegExp { * @param rootFile */ static async parseInputFilePath(match: MatchPath, currentFile: string, rootFile: string): Promise { - const rawTexDirs = vscode.workspace.getConfiguration('latex-workshop').get('latex.texDirs') as string[] const texDirs = rawTexDirs.map((texDir) => {return replaceArgumentPlaceholders('', '')(texDir)}) + + const matchedDir = sanitizeInputFilePath(match.directory) + const matchedPath = sanitizeInputFilePath(match.path) /* match of this.childReg */ if (match.type === MatchType.Child) { - return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], match.path) + return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], matchedPath) } /* match of this.inputReg */ if (match.type === MatchType.Input) { if (match.matchedString.startsWith('\\subimport') || match.matchedString.startsWith('\\subinputfrom') || match.matchedString.startsWith('\\subincludefrom')) { - return resolveFile([path.dirname(currentFile)], path.join(match.directory, match.path)) + return resolveFile([path.dirname(currentFile)], path.join(matchedDir, matchedPath)) } else if (match.matchedString.startsWith('\\import') || match.matchedString.startsWith('\\inputfrom') || match.matchedString.startsWith('\\includefrom')) { - return resolveFile([match.directory, path.join(path.dirname(rootFile), match.directory)], match.path) + return resolveFile([matchedDir, path.join(path.dirname(rootFile), matchedDir)], matchedPath) } else { - return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], match.path) + return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], matchedPath) } } return } } + +export function sanitizeInputFilePath(filePath: string): string { + if (filePath.startsWith('"') && filePath.endsWith('"')) { + return filePath.slice(1, -1) + } + return filePath +} From cf2589c22024665d6bb978268a9f02f08d13aa57 Mon Sep 17 00:00:00 2001 From: James Yu Date: Sat, 7 Dec 2024 23:01:50 +0800 Subject: [PATCH 2/5] Hover click supports double quoted paths --- src/language/definition.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/language/definition.ts b/src/language/definition.ts index 360b3dcb8..70d3b2e05 100644 --- a/src/language/definition.ts +++ b/src/language/definition.ts @@ -4,6 +4,7 @@ import * as path from 'path' import { lw } from '../lw' import { tokenizer } from '../utils/tokenizer' import * as utils from '../utils/utils' +import { sanitizeInputFilePath } from '../utils/inputfilepath' export class DefinitionProvider implements vscode.DefinitionProvider { private async onAFilename(document: vscode.TextDocument, position: vscode.Position, token: string): Promise { @@ -18,7 +19,7 @@ export class DefinitionProvider implements vscode.DefinitionProvider { } if (line.match(regexDocumentclass)) { - return utils.resolveFile([path.dirname(vscode.window.activeTextEditor.document.fileName)], token, '.cls') + return utils.resolveFile([path.dirname(vscode.window.activeTextEditor.document.fileName)], sanitizeInputFilePath(token), '.cls') } let dirs: string[] = [] @@ -31,11 +32,11 @@ export class DefinitionProvider implements vscode.DefinitionProvider { const result = line.match(regexImport) if (result) { - dirs = [path.resolve(path.dirname(vscode.window.activeTextEditor.document.fileName), result[1])] + dirs = [path.resolve(path.dirname(vscode.window.activeTextEditor.document.fileName), sanitizeInputFilePath(result[1]))] } if (dirs.length > 0) { - return utils.resolveFile(dirs, token, '.tex') + return utils.resolveFile(dirs, sanitizeInputFilePath(token), '.tex') } return } From 426360834dc00f107e3edbe74b57a21537bfaa34 Mon Sep 17 00:00:00 2001 From: James Yu Date: Sat, 7 Dec 2024 23:06:38 +0800 Subject: [PATCH 3/5] Prevent same TeX structure element from being multiple numbered --- src/outline/structure/latex.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/outline/structure/latex.ts b/src/outline/structure/latex.ts index ae3fe33f9..bdfece687 100644 --- a/src/outline/structure/latex.ts +++ b/src/outline/structure/latex.ts @@ -248,7 +248,7 @@ function insertSubFile(structs: FileStructureCache, struct?: TeXElement[], trave if (lw.root.file.path === undefined) { return [] } - struct = struct ?? structs[lw.root.file.path] ?? [] + struct = JSON.parse(JSON.stringify(struct ?? structs[lw.root.file.path] ?? [])) as TeXElement[] traversed = traversed ?? [lw.root.file.path] let elements: TeXElement[] = [] for (const element of struct) { From 212e1f170165af84c084d9e67cd1167c308c8ad1 Mon Sep 17 00:00:00 2001 From: James Yu Date: Sat, 7 Dec 2024 23:13:10 +0800 Subject: [PATCH 4/5] It's possible that input/import regex has undefined dir and path elements --- src/utils/inputfilepath.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/inputfilepath.ts b/src/utils/inputfilepath.ts index 2ac8037e4..a733cbd15 100644 --- a/src/utils/inputfilepath.ts +++ b/src/utils/inputfilepath.ts @@ -10,8 +10,8 @@ enum MatchType { interface MatchPath { type: MatchType, - path: string, - directory: string, + path?: string, + directory?: string, matchedString: string, index: number } @@ -90,8 +90,8 @@ export class InputFileRegExp { const rawTexDirs = vscode.workspace.getConfiguration('latex-workshop').get('latex.texDirs') as string[] const texDirs = rawTexDirs.map((texDir) => {return replaceArgumentPlaceholders('', '')(texDir)}) - const matchedDir = sanitizeInputFilePath(match.directory) - const matchedPath = sanitizeInputFilePath(match.path) + const matchedDir = sanitizeInputFilePath(match.directory ?? '') + const matchedPath = sanitizeInputFilePath(match.path ?? '') /* match of this.childReg */ if (match.type === MatchType.Child) { return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], matchedPath) From d59c0e83fa22e2db016842c4371ba4dfb4348445 Mon Sep 17 00:00:00 2001 From: James Yu Date: Sat, 7 Dec 2024 23:19:40 +0800 Subject: [PATCH 5/5] Corrections: path component of input/import cannot be undefined --- src/utils/inputfilepath.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/inputfilepath.ts b/src/utils/inputfilepath.ts index a733cbd15..0e4f6de44 100644 --- a/src/utils/inputfilepath.ts +++ b/src/utils/inputfilepath.ts @@ -10,7 +10,7 @@ enum MatchType { interface MatchPath { type: MatchType, - path?: string, + path: string, directory?: string, matchedString: string, index: number