diff --git a/README.md b/README.md index 9edd08dbe..3aeb02392 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,8 @@ To streamline maintenance and enhance security measures, I removed some features - Magic comment support - Creating temporary directory to build - Formatting LaTeX documents +- R Sweave and Weave.jl supports +- old-style Docker supports - Counting words ## Feature requests diff --git a/package.json b/package.json index 994a8a756..791c0583c 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,7 @@ }, "categories": [ "Programming Languages", - "Snippets", - "Linters", - "Formatters" + "Linters" ], "keywords": [ "latex", @@ -108,32 +106,6 @@ "LaTeX-Expl3" ], "configuration": "./syntax/latex3-language-configuration.json" - }, - { - "id": "jlweave", - "aliases": [ - "Weave.jl" - ], - "extensions": [ - ".jnw", - ".jtexw" - ], - "configuration": "./syntax/latex-language-configuration.json" - }, - { - "id": "rsweave", - "aliases": [ - "R Sweave" - ], - "extensions": [ - ".rnw", - ".Rnw", - ".Rtex", - ".rtex", - ".snw", - ".Snw" - ], - "configuration": "./syntax/latex-language-configuration.json" } ], "grammars": [ @@ -185,22 +157,6 @@ "language": "latex-expl3", "scopeName": "text.tex.latex.expl3", "path": "./syntax/LaTeX-Expl3.tmLanguage.json" - }, - { - "language": "jlweave", - "scopeName": "text.tex.latex.jlweave", - "path": "./syntax/JLweave.tmLanguage.json", - "embeddedLanguages": { - "source.julia": "julia" - } - }, - { - "language": "rsweave", - "scopeName": "text.tex.latex.rsweave", - "path": "./syntax/RSweave.tmLanguage.json", - "embeddedLanguages": { - "source.r": "r" - } } ], "commands": [ @@ -351,19 +307,19 @@ "key": "ctrl+l alt+m", "mac": "cmd+l alt+m", "command": "latex-toybox.toggleMathPreviewPanel", - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && config.latex-toybox.bind.altKeymap.enabled" + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && config.latex-toybox.bind.altKeymap.enabled" }, { "key": "ctrl+l alt+b", "mac": "cmd+l alt+b", "command": "latex-toybox.build", - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" }, { "key": "ctrl+l alt+v", "mac": "cmd+l alt+v", "command": "latex-toybox.view", - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" }, { "key": "ctrl+l alt+j", @@ -375,19 +331,19 @@ "key": "ctrl+alt+m", "mac": "cmd+alt+m", "command": "latex-toybox.toggleMathPreviewPanel", - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !config.latex-toybox.bind.altKeymap.enabled" + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && !config.latex-toybox.bind.altKeymap.enabled" }, { "key": "ctrl+alt+b", "mac": "cmd+alt+b", "command": "latex-toybox.build", - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && !config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" }, { "key": "ctrl+alt+v", "mac": "cmd+alt+v", "command": "latex-toybox.view", - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && !config.latex-toybox.bind.altKeymap.enabled && !virtualWorkspace" }, { "key": "ctrl+alt+j", @@ -398,12 +354,12 @@ { "key": "enter", "command": "latex-toybox.onEnterKey", - "when": "config.latex-toybox.bind.enter.key && editorTextFocus && (acceptSuggestionOnEnter && !suggestWidgetVisible || !acceptSuggestionOnEnter) && !editorReadonly && editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && (vim.active && vim.mode == 'Insert' || !vim.active)" + "when": "config.latex-toybox.bind.enter.key && editorTextFocus && (acceptSuggestionOnEnter && !suggestWidgetVisible || !acceptSuggestionOnEnter) && !editorReadonly && editorLangId =~ /^latex$|^latex-expl3$/ && (vim.active && vim.mode == 'Insert' || !vim.active)" }, { "key": "alt+enter", "command": "latex-toybox.onAltEnterKey", - "when": "config.latex-toybox.bind.enter.key && editorTextFocus && (acceptSuggestionOnEnter && !suggestWidgetVisible || !acceptSuggestionOnEnter) && !editorReadonly && editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/" + "when": "config.latex-toybox.bind.enter.key && editorTextFocus && (acceptSuggestionOnEnter && !suggestWidgetVisible || !acceptSuggestionOnEnter) && !editorReadonly && editorLangId =~ /^latex$|^latex-expl3$/" } ], "configurationDefaults": { @@ -472,20 +428,6 @@ "pdflatex" ] }, - { - "name": "Compile Rnw files", - "tools": [ - "rnw2tex", - "latexmk" - ] - }, - { - "name": "Compile Jnw files", - "tools": [ - "jnw2tex", - "latexmk" - ] - }, { "name": "tectonic", "tools": [ @@ -596,33 +538,6 @@ ], "env": {} }, - { - "name": "rnw2tex", - "command": "Rscript", - "args": [ - "-e", - "knitr::opts_knit$set(concordance = TRUE); knitr::knit('%DOCFILE_EXT%')" - ], - "env": {} - }, - { - "name": "jnw2tex", - "command": "julia", - "args": [ - "-e", - "using Weave; weave(\"%DOC_EXT%\", doctype=\"tex\")" - ], - "env": {} - }, - { - "name": "jnw2texmintex", - "command": "julia", - "args": [ - "-e", - "using Weave; weave(\"%DOC_EXT%\", doctype=\"texminted\")" - ], - "env": {} - }, { "name": "tectonic", "command": "tectonic", @@ -707,9 +622,7 @@ "type": "string" }, "default": [ - "**/*.tex", - "**/*.rnw", - "**/*.Rnw" + "**/*.tex" ], "markdownDescription": "Patterns of files to consider for the root detection mechanism. Relative paths are computed from the workspace folder. To detect the root file and the tex file tree, we parse all the `.tex` listed here. If you want to specify all `.tex` files inside directory, say `foo`, and all its subdirectories recursively, you need to use `**/foo/**/*.tex`. If you only want to match `.tex` files at the top level of the workspace, use `*.tex`. For more details, see https://github.com/James-Yu/LaTeX-Workshop/wiki/Compile#multi-file-projects" }, @@ -1713,24 +1626,24 @@ "menus": { "editor/context": [ { - "when": "config.latex-toybox.showContextMenu && editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !virtualWorkspace", + "when": "config.latex-toybox.showContextMenu && editorLangId =~ /^latex$|^latex-expl3$/ && !virtualWorkspace", "command": "latex-toybox.build", "group": "navigation@100" }, { - "when": "config.latex-toybox.showContextMenu && editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !virtualWorkspace", + "when": "config.latex-toybox.showContextMenu && editorLangId =~ /^latex$|^latex-expl3$/ && !virtualWorkspace", "command": "latex-toybox.synctex", "group": "navigation@101" } ], "editor/title": [ { - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !virtualWorkspace", + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && !virtualWorkspace", "command": "latex-toybox.view", "group": "navigation@2" }, { - "when": "editorLangId =~ /^latex$|^latex-expl3$|^rsweave$|^jlweave$/ && !virtualWorkspace", + "when": "editorLangId =~ /^latex$|^latex-expl3$/ && !virtualWorkspace", "command": "latex-toybox.build", "group": "navigation@1" } diff --git a/src/components/builder.ts b/src/components/builder.ts index 6dad1aff4..e022240ef 100644 --- a/src/components/builder.ts +++ b/src/components/builder.ts @@ -345,13 +345,7 @@ export class Builder { } else if (defaultRecipeName === 'lastUsed' && this.previouslyUsedRecipe) { recipe = this.previouslyUsedRecipe } else if (defaultRecipeName === 'first' || defaultRecipeName === 'lastUsed' && !this.previouslyUsedRecipe) { - let candidates: Recipe[] = recipes - if (languageId === 'rsweave') { - candidates = recipes.filter(candidate => candidate.name.toLowerCase().match('rnw|rsweave')) - } else if (languageId === 'jlweave') { - candidates = recipes.filter(candidate => candidate.name.toLowerCase().match('jnw|jlweave|weave.jl')) - } - recipe = candidates[0] + recipe = recipes[0] } if (recipe === undefined) { this.extension.logger.error(`Failed to resolve build recipe: ${[recipeName, defaultRecipeName]}`) diff --git a/src/components/completionupdater.ts b/src/components/completionupdater.ts index 1d80c2384..bd30b43e9 100644 --- a/src/components/completionupdater.ts +++ b/src/components/completionupdater.ts @@ -1,4 +1,3 @@ -import * as utils from '../utils/utils' import {latexParser} from 'latex-utensils' import * as vscode from 'vscode' import {CommandUpdater} from './completionupdaterlib/commandupdater' @@ -66,13 +65,6 @@ export class CompletionUpdater { this.commandUpdater.update(file, nodes) } else { this.extension.logger.info(`Cannot parse a TeX file: ${file}`) - this.extension.logger.info('Fall back to regex-based completion.') - // Do the update with old style. - const contentNoComment = utils.stripCommentsAndVerbatim(content) - this.referenceUpdater.update(file, undefined, undefined, contentNoComment) - this.glossaryUpdater.update(file, undefined, contentNoComment) - this.environmentUpdater.update(file, undefined, undefined, contentNoComment) - this.commandUpdater.update(file, undefined, contentNoComment) } if (cache) { if (isContentOnDisk) { diff --git a/src/components/completionupdaterlib/commandupdater.ts b/src/components/completionupdaterlib/commandupdater.ts index 473a664af..673995687 100644 --- a/src/components/completionupdaterlib/commandupdater.ts +++ b/src/components/completionupdaterlib/commandupdater.ts @@ -22,15 +22,12 @@ export class CommandUpdater { /** * Updates the Manager cache for commands used in `file` with `nodes`. - * If `nodes` is `undefined`, `content` is parsed with regular expressions, - * and the result is used to update the cache. * @param file The path of a LaTeX file. * @param nodes AST of a LaTeX file. - * @param content The content of a LaTeX file. */ - update(file: string, nodes?: latexParser.Node[], content?: string) { + update(file: string, nodes: latexParser.Node[]) { // First, we must update the package list - this.updatePkg(file, nodes, content) + this.updatePkgWithNodeArray(file, nodes) // Remove newcommand cmds, because they will be re-insert in the next step this.definedCmds.forEach((entry,cmd) => { if (entry.file === file) { @@ -41,43 +38,7 @@ export class CommandUpdater { if (cache === undefined) { return } - if (nodes !== undefined) { - cache.element.command = this.commandFinder.getCmdFromNodeArray(file, nodes, new CommandNameDuplicationDetector()) - } else if (content !== undefined) { - cache.element.command = this.commandFinder.getCmdFromContent(file, content) - } - } - - /** - * Updates the Manager cache for packages used in `file` with `nodes`. - * If `nodes` is `undefined`, `content` is parsed with regular expressions, - * and the result is used to update the cache. - * - * @param file The path of a LaTeX file. - * @param nodes AST of a LaTeX file. - * @param content The content of a LaTeX file. - */ - private updatePkg(file: string, nodes?: latexParser.Node[], content?: string) { - if (nodes !== undefined) { - this.updatePkgWithNodeArray(file, nodes) - } else if (content !== undefined) { - const pkgReg = /\\usepackage(?:\[[^[\]{}]*\])?{(.*)}/g - - while (true) { - const result = pkgReg.exec(content) - if (result === null) { - break - } - result[1].split(',').forEach(pkg => { - pkg = pkg.trim() - if (pkg === '') { - return - } - const cache = this.extension.manager.getCachedContent(file) - cache?.element.package.add(pkg) - }) - } - } + cache.element.command = this.commandFinder.getCmdFromNodeArray(file, nodes, new CommandNameDuplicationDetector()) } private updatePkgWithNodeArray(file: string, nodes: latexParser.Node[]) { diff --git a/src/components/completionupdaterlib/commandupdaterlib/commandfinder.ts b/src/components/completionupdaterlib/commandupdaterlib/commandfinder.ts index 35633bec8..ec321fa56 100644 --- a/src/components/completionupdaterlib/commandupdaterlib/commandfinder.ts +++ b/src/components/completionupdaterlib/commandupdaterlib/commandfinder.ts @@ -142,117 +142,6 @@ export class CommandFinder { return this.getArgsHelperFromNode(node, (_: number) => { return '' }) } - - getCmdFromContent(file: string, content: string): CmdEnvSuggestion[] { - const cmdReg = /\\([a-zA-Z@_]+(?::[a-zA-Z]*)?\*?)({[^{}]*})?({[^{}]*})?({[^{}]*})?/g - const cmds: CmdEnvSuggestion[] = [] - const commandNameDuplicationDetector = new CommandNameDuplicationDetector() - let explSyntaxOn: boolean = false - while (true) { - const result = cmdReg.exec(content) - if (result === null) { - break - } - if (result[1] === 'ExplSyntaxOn') { - explSyntaxOn = true - continue - } else if (result[1] === 'ExplSyntaxOff') { - explSyntaxOn = false - continue - } - - - if (!explSyntaxOn) { - const len = result[1].search(/[_:]/) - if (len > -1) { - result[1] = result[1].slice(0, len) - } - } - if (commandNameDuplicationDetector.has(result[1])) { - continue - } - - const documentation = '`' + result[1] + '`' - const insertText = new vscode.SnippetString(result[1] + this.getTabStopsFromRegResult(result)) - const filterText = result[1] - let command: vscode.Command | undefined - if (isTriggerSuggestNeeded(result[1])) { - command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' } - } - const cmd = new CmdEnvSuggestion( - `\\${result[1]}`, - this.whichPackageProvidesCommand(result[1]), - { name: result[1], args: this.getArgsFromRegResult(result) }, - vscode.CompletionItemKind.Function, - { documentation, insertText, filterText, command} - ) - cmds.push(cmd) - commandNameDuplicationDetector.add(result[1]) - } - - const newCommandReg = /\\(?:(?:(?:re|provide)?(?:new)?command)|(?:DeclarePairedDelimiter(?:X|XPP)?)|DeclareMathOperator)\*?{?\\(\w+)}?(?:\[([1-9])\])?/g - while (true) { - const result = newCommandReg.exec(content) - if (result === null) { - break - } - if (commandNameDuplicationDetector.has(result[1])) { - continue - } - - let tabStops = '' - let args = '' - if (result[2]) { - const numArgs = parseInt(result[2]) - for (let i = 1; i <= numArgs; ++i) { - tabStops += '{${' + i + '}}' - args += '{}' - } - } - - const documentation = '`' + result[1] + '`' - const insertText = new vscode.SnippetString(result[1] + tabStops) - const filterText = result[1] - const cmd = new CmdEnvSuggestion( - `\\${result[1]}`, - 'user-defined', - {name: result[1], args}, - vscode.CompletionItemKind.Function, - { documentation, insertText, filterText } - ) - cmds.push(cmd) - commandNameDuplicationDetector.add(result[1]) - - this.definedCmds.set(result[1], { - file, - location: new vscode.Location( - vscode.Uri.file(file), - new vscode.Position(content.substring(0, result.index).split('\n').length - 1, 0)) - }) - } - - return cmds - } - - private getTabStopsFromRegResult(result: RegExpExecArray): string { - let text = '' - - if (result[2]) { - text += '{${1}}' - } - if (result[3]) { - text += '{${2}}' - } - if (result[4]) { - text += '{${3}}' - } - return text - } - - private getArgsFromRegResult(result: RegExpExecArray): string { - return '{}'.repeat(result.length - 1) - } - /** * Return the name of the package providing cmdName among all the packages * included in the rootFile. If no package matches, return '' diff --git a/src/components/completionupdaterlib/environmentupdater.ts b/src/components/completionupdaterlib/environmentupdater.ts index ae9f0cbba..85cfbec59 100644 --- a/src/components/completionupdaterlib/environmentupdater.ts +++ b/src/components/completionupdaterlib/environmentupdater.ts @@ -12,22 +12,15 @@ export class EnvironmentUpdater { /** * Updates the Manager cache for environments used in `file` with `nodes`. - * If `nodes` is `undefined`, `content` is parsed with regular expressions, - * and the result is used to update the cache. * @param file The path of a LaTeX file. * @param nodes AST of a LaTeX file. - * @param content The content of a LaTeX file. */ - update(file: string, nodes?: latexParser.Node[], lines?: string[], content?: string) { + update(file: string, nodes: latexParser.Node[], lines: string[]) { const cache = this.extension.manager.getCachedContent(file) if (cache === undefined) { return } - if (nodes !== undefined && lines !== undefined) { - cache.element.environment = this.getEnvFromNodeArray(nodes, lines) - } else if (content !== undefined) { - cache.element.environment = this.getEnvFromContent(content) - } + cache.element.environment = this.getEnvFromNodeArray(nodes, lines) } // This function will return all environments in a node array, including sub-nodes @@ -61,31 +54,4 @@ export class EnvironmentUpdater { return envs } - private getEnvFromContent(content: string): CmdEnvSuggestion[] { - const envReg = /\\begin\s?{([^{}]*)}/g - const envs: CmdEnvSuggestion[] = [] - const envList: string[] = [] - while (true) { - const result = envReg.exec(content) - if (result === null) { - break - } - if (envList.includes(result[1])) { - continue - } - const documentation = '`' + result[1] + '`' - const filterText = result[1] - const env = new CmdEnvSuggestion( - `${result[1]}`, - '', - { name: result[1], args: '' }, - vscode.CompletionItemKind.Module, - { documentation, filterText } - ) - envs.push(env) - envList.push(result[1]) - } - return envs - } - } diff --git a/src/components/completionupdaterlib/glossaryupdater.ts b/src/components/completionupdaterlib/glossaryupdater.ts index 55edb72e0..860c5e24f 100644 --- a/src/components/completionupdaterlib/glossaryupdater.ts +++ b/src/components/completionupdaterlib/glossaryupdater.ts @@ -143,74 +143,15 @@ export class GlossaryUpdater { /** * Update the Manager cache for references defined in `file` with `nodes`. - * If `nodes` is `undefined`, `content` is parsed with regular expressions, - * and the result is used to update the cache. * @param file The path of a LaTeX file. * @param nodes AST of a LaTeX file. - * @param content The content of a LaTeX file. */ - update(file: string, nodes?: latexParser.Node[], content?: string) { + update(file: string, nodes: latexParser.Node[]) { const cache = this.extension.manager.getCachedContent(file) if (cache === undefined) { return } - if (nodes !== undefined) { - cache.element.glossary = this.getGlossaryFromNodeArray(nodes, file) - } else if (content !== undefined) { - cache.element.glossary = this.getGlossaryFromContent(content, file) - } + cache.element.glossary = this.getGlossaryFromNodeArray(nodes, file) } - private getGlossaryFromContent(content: string, file: string): GlossarySuggestion[] { - const glossaries: GlossarySuggestion[] = [] - const glossaryList: string[] = [] - - // We assume that the label is always result[1] and use getDescription(result) for the description - const regexes: { - [key: string]: { - regex: RegExp, - type: GlossaryType, - getDescription: (result: RegExpMatchArray) => string - } - } = { - 'glossary': { - regex: /\\(?:provide|new)glossaryentry{([^{}]*)}\s*{(?:(?!description).)*description=(?:([^{},]*)|{([^{}]*))[,}]/gms, - type: GlossaryType.glossary, - getDescription: (result) => { return result[2] ? result[2] : result[3] } - }, - 'longGlossary': { - regex: /\\long(?:provide|new)glossaryentry{([^{}]*)}\s*{[^{}]*}\s*{([^{}]*)}/gms, - type: GlossaryType.glossary, - getDescription: (result) => { return result[2] } - }, - 'acronym': { - regex: /\\newacronym(?:\[[^[\]]*\])?{([^{}]*)}{[^{}]*}{([^{}]*)}/gm, - type: GlossaryType.acronym, - getDescription: (result) => { return result[2] } - } - } - - for(const key in regexes){ - while(true) { - const result = regexes[key].regex.exec(content) - if (result === null) { - break - } - const positionContent = content.substring(0, result.index).split('\n') - if (glossaryList.includes(result[1])) { - continue - } - glossaries.push({ - type: regexes[key].type, - file, - position: new vscode.Position(positionContent.length - 1, positionContent[positionContent.length - 1].length), - label: result[1], - detail: regexes[key].getDescription(result), - kind: vscode.CompletionItemKind.Reference - }) - } - } - - return glossaries - } } diff --git a/src/components/completionupdaterlib/labeldefinitionupdater.ts b/src/components/completionupdaterlib/labeldefinitionupdater.ts index 5fd3b4365..26ec60adc 100644 --- a/src/components/completionupdaterlib/labeldefinitionupdater.ts +++ b/src/components/completionupdaterlib/labeldefinitionupdater.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' import {latexParser} from 'latex-utensils' -import {stripEnvironments, isNewCommand} from '../../utils/utils' +import {isNewCommand} from '../../utils/utils' import { LabelDefinitionElement } from '../../providers/completer/labeldefinition' import { toVscodeRange } from '../../utils/utensils' @@ -16,23 +16,16 @@ export class LabelDefinitionUpdater { /** * Updates the Manager cache for references defined in `file` with `nodes`. - * If `nodes` is `undefined`, `content` is parsed with regular expressions, - * and the result is used to update the cache. * @param file The path of a LaTeX file. * @param nodes AST of a LaTeX file. * @param lines The lines of the content. They are used to generate the documentation of completion items. - * @param content The content of a LaTeX file. */ - update(file: string, nodes?: latexParser.Node[], lines?: string[], content?: string) { + update(file: string, nodes: latexParser.Node[], lines: string[]) { const cache = this.extension.manager.getCachedContent(file) if (cache === undefined) { return } - if (nodes !== undefined && lines !== undefined) { - cache.element.labelDefinition = this.getRefFromNodeArray(nodes, lines) - } else if (content !== undefined) { - cache.element.labelDefinition = this.getRefFromContent(content) - } + cache.element.labelDefinition = this.getRefFromNodeArray(nodes, lines) } // This function will return all references in a node array, including sub-nodes @@ -102,32 +95,4 @@ export class LabelDefinitionUpdater { return refs } - private getRefFromContent(content: string): LabelDefinitionElement[] { - const refReg = /(?:\\label(?:\[[^[\]{}]*\])?|(?:^|[,\s])label=){([^#\\}]*)}/gm - const refs: LabelDefinitionElement[] = [] - const refList: string[] = [] - content = stripEnvironments(content, this.envsToSkip) - while (true) { - const result = refReg.exec(content) - if (result === null) { - break - } - if (refList.includes(result[1])) { - continue - } - const prevContent = content.substring(0, content.substring(0, result.index).lastIndexOf('\n') - 1) - const followLength = content.substring(result.index, content.length).split('\n', 4).join('\n').length - const positionContent = content.substring(0, result.index).split('\n') - - refs.push({ - label: result[1], - documentation: content.substring(prevContent.lastIndexOf('\n') + 1, result.index + followLength), - range: new vscode.Range(positionContent.length - 1, positionContent[positionContent.length - 1].length, - positionContent.length - 1, positionContent[positionContent.length - 1].length) - }) - refList.push(result[1]) - } - return refs - } - } diff --git a/src/components/manager.ts b/src/components/manager.ts index f4841bc85..d35308011 100644 --- a/src/components/manager.ts +++ b/src/components/manager.ts @@ -21,7 +21,7 @@ import { LwFileWatcher } from './managerlib/lwfilewatcher' import { getTeXChildren } from './managerlib/gettexchildren' import { findWorkspace, isExcluded } from './managerlib/utils' import { getDirtyContent } from '../utils/getdirtycontent' -import { inferLanguageId, isTexOrWeaveFile } from '../utils/hastexid' +import { inferLanguageId, isTexFile } from '../utils/hastexid' import type { Logger } from './logger' import type { Viewer } from './viewer' import type { Completer } from '../providers/completion' @@ -693,6 +693,7 @@ export class Manager { cacheEntry.bibs.cache.clear() cacheEntry.bibs.mtime = 0 } + // TODO const bibReg = /(?:\\(?:bibliography|addbibresource)(?:\[[^[\]{}]*\])?){(.+?)}|(?:\\putbib)\[(.+?)\]/g while (true) { const result = bibReg.exec(content) @@ -744,7 +745,7 @@ export class Manager { if (inputFile === rootFile || this.isWatched(inputFile)) { continue } - if (isTexOrWeaveFile(vscode.Uri.file(inputFile))) { + if (isTexFile(vscode.Uri.file(inputFile))) { // Parse tex files as imported subfiles. this.gracefulCachedContent(rootFile).children.cache.add(inputFile) await this.parseFileAndSubs(inputFile, rootFile, new Set()) @@ -809,13 +810,13 @@ export class Manager { private async onWatchingNewFile(fileUri: vscode.Uri) { this.extension.logger.info(`Added to file watcher: ${fileUri}`) - if (isTexOrWeaveFile(fileUri)) { + if (isTexFile(fileUri)) { await this.updateContentEntry(fileUri) } } private async onWatchedFileChanged(fileUri: vscode.Uri) { - if (isTexOrWeaveFile(fileUri)) { + if (isTexFile(fileUri)) { await this.updateContentEntry(fileUri) } await this.buildOnFileChanged(fileUri) diff --git a/src/components/mathpreviewlib/newcommandfinder.ts b/src/components/mathpreviewlib/newcommandfinder.ts index 27cff1a7f..3d8ddfd5a 100644 --- a/src/components/mathpreviewlib/newcommandfinder.ts +++ b/src/components/mathpreviewlib/newcommandfinder.ts @@ -1,6 +1,6 @@ import * as vscode from 'vscode' import {latexParser} from 'latex-utensils' -import {stripCommentsAndVerbatim, isNewCommand, NewCommand} from '../../utils/utils' +import {isNewCommand, NewCommand} from '../../utils/utils' import * as path from 'path' import { readFilePathGracefully } from '../../lib/lwfs/lwfs' @@ -87,7 +87,7 @@ export class NewCommandFinder { } async findNewCommand(content: string): Promise { - let commands: string[] = [] + const commands: string[] = [] try { const ast = await this.extension.utensilsParser.parseLatexPreamble(content) for (const node of ast.content) { @@ -103,23 +103,10 @@ export class NewCommandFinder { commands.push(s) } } + return commands } catch (e) { - commands = [] - const regex = /(\\(?:(?:(?:(?:re)?new|provide)command|DeclareMathOperator)(\*)?{\\[a-zA-Z]+}(?:\[[^[\]{}]*\])*{.*})|\\(?:def\\[a-zA-Z]+(?:#[0-9])*{.*})|\\DeclarePairedDelimiter{\\[a-zA-Z]+}{[^{}]*}{[^{}]*})/gm - const noCommentContent = stripCommentsAndVerbatim(content) - let result: RegExpExecArray | null - do { - result = regex.exec(noCommentContent) - if (result) { - let command = result[1] - if (result[2]) { - command = command.replace(/\*/, '') - } - commands.push(command) - } - } while (result) + return [] } - return commands } } diff --git a/src/components/structurelib/sectionnodeprovider.ts b/src/components/structurelib/sectionnodeprovider.ts index 21b153144..82de76601 100644 --- a/src/components/structurelib/sectionnodeprovider.ts +++ b/src/components/structurelib/sectionnodeprovider.ts @@ -5,7 +5,6 @@ import { Section, SectionKind } from '../structure' import { resolveFile } from '../../utils/utils' import { buildLaTeXHierarchy } from './sectionnodeproviderlib/structure' import { setLastLineOfEachSection } from './sectionnodeproviderlib/utils' -import { parseRnwChildCommand } from './sectionnodeproviderlib/rnw' import { captionify, findEnvCaption } from './sectionnodeproviderlib/caption' import { getDirtyContent } from '../../utils/getdirtycontent' import type { Logger } from '../logger' @@ -155,21 +154,10 @@ export class SectionNodeProvider implements vscode.TreeDataProvider
{ return [] } - // Get a list of rnw child chunks - const rnwChildren = subFile ? await parseRnwChildCommand(content, file, this.extension.manager.rootFile || '') : [] - let rnwChild = rnwChildren.shift() - // Parse each base-level node. If the node has contents, that function // will be called recursively. let sections: Section[] = [] for (const node of ast.content) { - while (rnwChild && node.location && rnwChild.line <= node.location.start.line) { - sections = [ - ...sections, - ...await this.buildLaTeXSectionFromFile(rnwChild.subFile, subFile, filesBuilt) - ] - rnwChild = rnwChildren.shift() - } sections = [ ...sections, ...await this.parseLaTeXNode(node, file, subFile, filesBuilt) @@ -294,7 +282,7 @@ export class SectionNodeProvider implements vscode.TreeDataProvider
{ cmdArgs.push(argString.slice(1, argString.length - 1)) }) - const texDirs = vscode.workspace.getConfiguration('latex-toybox').get('latex.texDirs') as string[] + const texDirs = vscode.workspace.getConfiguration('latex-toybox').get('latex.texDirs', []) as string[] let candidate: string | undefined // \input{sub.tex} @@ -302,27 +290,32 @@ export class SectionNodeProvider implements vscode.TreeDataProvider
{ 'subfile', 'loadglsentries'].includes(node.name.replace(/\*$/, '')) && cmdArgs.length > 0) { candidate = await resolveFile( - [path.dirname(file), - path.dirname(this.extension.manager.rootFile || ''), - ...texDirs], - cmdArgs[0]) + [ + path.dirname(file), + path.dirname(this.extension.manager.rootFile || ''), + ...texDirs + ], + cmdArgs[0] + ) } // \import{sections/}{section1.tex} if (['import', 'inputfrom', 'includefrom'].includes(node.name.replace(/\*$/, '')) && cmdArgs.length > 1) { candidate = await resolveFile( - [cmdArgs[0], - path.join( - path.dirname(this.extension.manager.rootFile || ''), - cmdArgs[0])], - cmdArgs[1]) + [ + cmdArgs[0], + path.join(path.dirname(this.extension.manager.rootFile || ''), cmdArgs[0]) + ], + cmdArgs[1] + ) } // \subimport{01-IntroDir/}{01-Intro.tex} if (['subimport', 'subinputfrom', 'subincludefrom'].includes(node.name.replace(/\*$/, '')) && cmdArgs.length > 1) { candidate = await resolveFile( [path.dirname(file)], - path.join(cmdArgs[0], cmdArgs[1])) + path.join(cmdArgs[0], cmdArgs[1]) + ) } return candidate ? this.buildLaTeXSectionFromFile(candidate, subFile, filesBuilt) : [] diff --git a/src/components/structurelib/sectionnodeproviderlib/rnw.ts b/src/components/structurelib/sectionnodeproviderlib/rnw.ts deleted file mode 100644 index 0a5cc3cad..000000000 --- a/src/components/structurelib/sectionnodeproviderlib/rnw.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { InputFileRegExp } from '../../../utils/inputfilepath' - - -export async function parseRnwChildCommand(content: string, file: string, rootFile: string) { - const children: {subFile: string, line: number}[] = [] - const childRegExp = new InputFileRegExp() - while(true) { - const result = await childRegExp.execChild(content, file, rootFile) - if (!result) { - break - } - const line = (content.slice(0, result.match.index).match(/\n/g) || []).length - children.push({subFile: result.path, line}) - } - return children -} diff --git a/src/providers/folding.ts b/src/providers/folding.ts index cfb5b3543..964c71f08 100644 --- a/src/providers/folding.ts +++ b/src/providers/folding.ts @@ -9,11 +9,7 @@ export class FoldingProvider implements vscode.FoldingRangeProvider { this.sectionRegex = sections.map(section => RegExp(`\\\\(?:${section})(?:\\*)?(?:\\[[^\\[\\]\\{\\}]*\\])?{(.*)}`, 'm')) } - public provideFoldingRanges( - document: vscode.TextDocument, - _context: vscode.FoldingContext, - _token: vscode.CancellationToken - ): vscode.ProviderResult { + public provideFoldingRanges(document: vscode.TextDocument): vscode.FoldingRange[] { return [...this.getSectionFoldingRanges(document), ...this.getEnvironmentFoldingRanges(document)] } @@ -126,44 +122,3 @@ export class FoldingProvider implements vscode.FoldingRangeProvider { } } } - -export class WeaveFoldingProvider implements vscode.FoldingRangeProvider { - - public provideFoldingRanges( - document: vscode.TextDocument, - _context: vscode.FoldingContext, - _token: vscode.CancellationToken - ): vscode.ProviderResult { - const ranges: vscode.FoldingRange[] = [] - const opStack: { keyword: string, index: number }[] = [] - const text: string = document.getText() - const envRegex = /^([\t ]*<<.*>>=)\s*$|[\t ]*(@)\s*$/gm - while (true) { - const match = envRegex.exec(text) - if (match === null) { - return ranges - } - let keyword: string = '' - if (match[1]) { - keyword = 'begin' - } else if (match[2]) { - keyword = 'end' - } - const item = { - keyword, - index: match.index - } - const lastItem = opStack[opStack.length - 1] - - if (keyword === 'end' && lastItem && lastItem.keyword === 'begin') { // match 'end' with its 'begin' - opStack.pop() - ranges.push(new vscode.FoldingRange( - document.positionAt(lastItem.index).line, - document.positionAt(item.index).line - 1 - )) - } else { - opStack.push(item) - } - } - } -} diff --git a/src/providersmanager.ts b/src/providersmanager.ts index 9b7976c00..1210725b7 100644 --- a/src/providersmanager.ts +++ b/src/providersmanager.ts @@ -9,7 +9,7 @@ import { DefinitionProvider } from './providers/definition' import { ReferenceProvider } from './providers/reference' import { RenameProvider } from './providers/rename' import { BibtexCompleter } from './providers/bibtexcompletion' -import { FoldingProvider, WeaveFoldingProvider } from './providers/folding' +import { FoldingProvider } from './providers/folding' import { BibtexFormatterProvider } from './providers/bibtexformatter' import type { Extension } from './main' import { MathPreviewPanelSerializer } from './components/mathpreviewpanel' @@ -57,7 +57,7 @@ export class ProvidersManager { constructor(extension: Extension){ this.registerProviders(extension, extension.extensionContext) - const latexDoctexSelector = selectDocumentsWithId(['latex', 'latex-expl3', 'jlweave', 'rsweave', 'doctex']) + const latexDoctexSelector = selectDocumentsWithId(['latex', 'latex-expl3', 'doctex']) const selectionRangeProvider = new SelectionRangeProvider(extension) const ltInlayHintsProvider = new LtInlayHintsProvider(extension) const fileDecorationProvider = new FileDecorationProvider(extension) @@ -137,8 +137,7 @@ export class ProvidersManager { } private registerProviders(extension: Extension, context: vscode.ExtensionContext) { - const latexSelector = selectDocumentsWithId(['latex', 'latex-expl3', 'jlweave', 'rsweave']) - const weaveSelector = selectDocumentsWithId(['jlweave', 'rsweave']) + const latexSelector = selectDocumentsWithId(['latex', 'latex-expl3']) const bibtexFormatter = new BibtexFormatterProvider(extension) context.subscriptions.push( @@ -169,7 +168,6 @@ export class ProvidersManager { context.subscriptions.push( vscode.languages.registerFoldingRangeProvider(latexSelector, new FoldingProvider()), - vscode.languages.registerFoldingRangeProvider(weaveSelector, new WeaveFoldingProvider()) ) context.subscriptions.push( diff --git a/src/utils/hastexid.ts b/src/utils/hastexid.ts index 2b9367f16..b9a9ef025 100644 --- a/src/utils/hastexid.ts +++ b/src/utils/hastexid.ts @@ -8,7 +8,7 @@ import * as path from 'path' * @param id The language identifier */ export function hasTexId(id: string) { - return ['tex', 'latex', 'latex-expl3', 'doctex', 'jlweave', 'rsweave'].includes(id) + return ['tex', 'latex', 'latex-expl3', 'doctex'].includes(id) } /** @@ -20,18 +20,10 @@ export function hasBibtexId(id: string) { return id === 'bibtex' } -const rsweaveExt = ['.rnw', '.Rnw', '.rtex', '.Rtex', '.snw', '.Snw'] -const jlweaveExt = ['.jnw', '.jtexw'] -const weaveExt = jlweaveExt.concat(rsweaveExt) - export function inferLanguageId(filename: string): string | undefined { const ext = path.extname(filename).toLocaleLowerCase() if (ext === '.tex') { return 'latex' - } else if (jlweaveExt.includes(ext)) { - return 'jlweave' - } else if (rsweaveExt.includes(ext)) { - return 'rsweave' } else if (ext === '.dtx') { return 'doctex' } else { @@ -39,6 +31,6 @@ export function inferLanguageId(filename: string): string | undefined { } } -export function isTexOrWeaveFile(fileUri: vscode.Uri) { - return ['.tex', ...weaveExt].find(suffix => fileUri.path.toLocaleLowerCase().endsWith(suffix)) +export function isTexFile(fileUri: vscode.Uri) { + return ['.tex'].find(suffix => fileUri.path.toLocaleLowerCase().endsWith(suffix)) } diff --git a/src/utils/inputfilepath.ts b/src/utils/inputfilepath.ts index ad234cdf4..5b100ba68 100644 --- a/src/utils/inputfilepath.ts +++ b/src/utils/inputfilepath.ts @@ -3,22 +3,17 @@ import * as path from 'path' import { resolveFile } from './utils' -enum MatchType { - Input, - Child -} interface MatchPath { - readonly type: MatchType, readonly path: string, - readonly directory: string, + readonly directory: string | undefined, readonly matchedString: string, readonly index: number } export class InputFileRegExp { + // TODO private readonly inputReg = /\\(?:input|InputIfFileExists|include|SweaveInput|subfile|loadglsentries|(?:(?:sub)?(?:import|inputfrom|includefrom)\*?{([^}]*)}))(?:\[[^[\]{}]*\])?{([^}]*)}/g - private readonly childReg = /<<(?:[^,]*,)*\s*child='([^']*)'\s*(?:,[^,]*)*>>=/g /** * Return the matched input path. If there is no match, return undefined @@ -31,7 +26,6 @@ export class InputFileRegExp { const result = this.inputReg.exec(content) if (result) { const match = { - type: MatchType.Input, path: result[2], directory: result[1], matchedString: result[0], @@ -43,29 +37,6 @@ export class InputFileRegExp { return undefined } - /** - * Return the matched child path. If there is no match, return undefined - * - * @param content the string to match the regex on - * @param currentFile is the name of file in which the regex is executed - * @param rootFile - */ - async execChild(content: string, currentFile: string, rootFile: string) { - const result = this.childReg.exec(content) - if (result) { - const match = { - type: MatchType.Child, - path: result[1], - directory: '', - matchedString: result[0], - index: result.index - } - const filePath = await this.parseInputFilePath(match, currentFile, rootFile) - return filePath ? {path: filePath, match} : undefined - } - return undefined - } - /** * Return the matched input or child path. If there is no match, return * undefined @@ -75,8 +46,7 @@ export class InputFileRegExp { * @param rootFile */ async exec(content: string, currentFile: string, rootFile: string) { - return await this.execInput(content, currentFile, rootFile) - || await this.execChild(content, currentFile, rootFile) + return this.execInput(content, currentFile, rootFile) } /** @@ -88,21 +58,18 @@ export class InputFileRegExp { */ private parseInputFilePath(match: MatchPath, currentFile: string, rootFile: string) { const texDirs = vscode.workspace.getConfiguration('latex-toybox').get('latex.texDirs') as string[] - /* match of this.childReg */ - if (match.type === MatchType.Child) { - return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], match.path) - } - /* match of this.inputReg */ - if (match.type === MatchType.Input) { - if (match.matchedString.startsWith('\\subimport') || match.matchedString.startsWith('\\subinputfrom') || match.matchedString.startsWith('\\subincludefrom')) { + if (match.matchedString.startsWith('\\subimport') || match.matchedString.startsWith('\\subinputfrom') || match.matchedString.startsWith('\\subincludefrom')) { + if (match.directory) { return resolveFile([path.dirname(currentFile)], path.join(match.directory, match.path)) - } else if (match.matchedString.startsWith('\\import') || match.matchedString.startsWith('\\inputfrom') || match.matchedString.startsWith('\\includefrom')) { + } + } else if (match.matchedString.startsWith('\\import') || match.matchedString.startsWith('\\inputfrom') || match.matchedString.startsWith('\\includefrom')) { + if (match.directory) { return resolveFile([match.directory, path.join(path.dirname(rootFile), match.directory)], match.path) - } else { - return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], match.path) } + } else { + return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], match.path) } - return undefined + return } } diff --git a/syntax/JLweave.tmLanguage.json b/syntax/JLweave.tmLanguage.json deleted file mode 100644 index 61a9c15ca..000000000 --- a/syntax/JLweave.tmLanguage.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "jlweave", - "scopeName": "text.tex.latex.jlweave", - "patterns": [ - { - "include": "text.tex.latex" - }, - { - "name": "text.tex.latex.jlweave.codeblock", - "begin": "^(\\s*?)(<<)(.*?)(>>=)\\s*(.+)?\\s*\\n", - "end": "^\\1(@)\\s*(.+)?\\s*\\n", - "endCaptures": { - "1": { - "name": "meta.tag.jlweave" - }, - "2": { - "name": "invalid.illegal.jlweave" - } - }, - "beginCaptures": { - "2": { - "name": "meta.tag.jlweave" - }, - "4": { - "name": "meta.tag.jlweave" - }, - "5": { - "name": "invalid.illegal.jlweave" - }, - "3": { - "patterns": [ - { - "include": "source.julia" - } - ] - } - }, - "contentName": "source.julia", - "patterns": [ - { - "include": "source.julia" - } - ] - } - ] -} diff --git a/syntax/RSweave.tmLanguage.json b/syntax/RSweave.tmLanguage.json deleted file mode 100644 index bbbaa3fb0..000000000 --- a/syntax/RSweave.tmLanguage.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "name": "RSweave", - "scopeName": "text.tex.latex.rsweave", - "fileTypes": [ - "rnw", - "Rnw", - "rtex", - "Rtex", - "snw", - "Snw" - ], - "patterns": [ - { - "captures": { - "1": { - "name": "support.function.verb.latex" - }, - "2": { - "name": "punctuation.definition.function.latex" - }, - "3": { - "name": "punctuation.definition.arguments.begin.latex" - }, - "4": { - "patterns": [ - { - "include": "source.r" - } - ] - }, - "5": { - "name": "punctuation.definition.arguments.end.latex" - } - }, - "match": "((\\\\)Sexpr)(\\{)([^\\{\\}]*)(\\})", - "name": "meta.function.verb.latex" - }, - { - "include": "text.tex.latex" - }, - { - "name": "text.tex.latex.rsweave.codeblock", - "begin": "^(\\s*?)(<<)(.*?)(>>=)\\s*(.+)?\\s*\\n", - "end": "^\\1(@)\\s*(.+)?\\s*\\n", - "endCaptures": { - "1": { - "name": "meta.tag.rsweave" - }, - "2": { - "name": "invalid.illegal.rsweave" - } - }, - "beginCaptures": { - "2": { - "name": "meta.tag.rsweave" - }, - "4": { - "name": "meta.tag.rsweave" - }, - "5": { - "name": "invalid.illegal.rsweave" - }, - "3": { - "patterns": [ - { - "include": "source.r#function-parameters" - } - ] - } - }, - "contentName": "source.r", - "patterns": [ - { - "include": "source.r" - } - ] - } - ] -}