Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance build for rnw files #2013

Merged
merged 9 commits into from
Apr 3, 2020
Merged
27 changes: 16 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,9 @@
".rnw",
".Rnw",
".Rtex",
".rtex"
".rtex",
".snw",
".Snw"
],
"configuration": "./syntax/syntax-rsweave.json"
}
Expand Down Expand Up @@ -389,19 +391,19 @@
"key": "ctrl+l alt+b",
"mac": "cmd+l alt+b",
"command": "latex-workshop.build",
"when": "editorLangId == 'latex' && config.latex-workshop.bind.altKeymap.enabled"
"when": "editorLangId =~ /latex|rsweave/ && config.latex-workshop.bind.altKeymap.enabled"
},
{
"key": "ctrl+l alt+c",
"mac": "cmd+l alt+c",
"command": "latex-workshop.clean",
"when": "editorLangId == 'latex' && config.latex-workshop.bind.altKeymap.enabled"
"when": "editorLangId =~ /latex|rsweave/ && config.latex-workshop.bind.altKeymap.enabled"
},
{
"key": "ctrl+l alt+v",
"mac": "cmd+l alt+v",
"command": "latex-workshop.view",
"when": "editorLangId == 'latex' && config.latex-workshop.bind.altKeymap.enabled"
"when": "editorLangId =~ /latex|rsweave/ && config.latex-workshop.bind.altKeymap.enabled"
},
{
"key": "ctrl+l alt+j",
Expand All @@ -419,19 +421,19 @@
"key": "ctrl+alt+b",
"mac": "cmd+alt+b",
"command": "latex-workshop.build",
"when": "editorLangId == 'latex' && !config.latex-workshop.bind.altKeymap.enabled"
"when": "editorLangId =~ /latex|rsweave/ && !config.latex-workshop.bind.altKeymap.enabled"
},
{
"key": "ctrl+alt+c",
"mac": "cmd+alt+c",
"command": "latex-workshop.clean",
"when": "editorLangId == 'latex' && !config.latex-workshop.bind.altKeymap.enabled"
"when": "editorLangId =~ /latex|rsweave/ && !config.latex-workshop.bind.altKeymap.enabled"
},
{
"key": "ctrl+alt+v",
"mac": "cmd+alt+v",
"command": "latex-workshop.view",
"when": "editorLangId == 'latex' && !config.latex-workshop.bind.altKeymap.enabled"
"when": "editorLangId =~ /latex|rsweave/ && !config.latex-workshop.bind.altKeymap.enabled"
},
{
"key": "ctrl+alt+j",
Expand Down Expand Up @@ -660,7 +662,8 @@
{
"name": "Compile Rnw files",
"tools": [
"rnw2pdf"
"rnw2tex",
"latexmk"
]
}
],
Expand Down Expand Up @@ -736,11 +739,11 @@
"env": {}
},
{
"name": "rnw2pdf",
"name": "rnw2tex",
"command": "Rscript",
"args": [
"-e",
"knitr::knit2pdf('%DOCFILE%')"
"knitr::opts_knit$set(concordance = TRUE); knitr::knit('%DOCFILE_EXT%')"
],
"env": {}
}
Expand Down Expand Up @@ -815,7 +818,9 @@
"type": "string"
},
"default": [
"**/*.tex"
"**/*.tex",
"**/*.rnw",
"**/*.Rnw"
],
"markdownDescription": "Patterns of files to consider for the root detection mechanism.\nRelative paths are computed from the workspace folder. To detect the root file and the tex file tree, we parse all the `.tex` listed here.\nIf 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 the [wiki](https://github.com/James-Yu/LaTeX-Workshop/wiki/Multi-File-Projects)."
},
Expand Down
11 changes: 6 additions & 5 deletions src/commander.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export class Commander {
.catch(err => this.extension.logger.addLogMessage(`Error reading data: ${err}.`))
}

async build(skipSelection: boolean = false, rootFile: string | undefined = undefined, recipe: string | undefined = undefined) {
async build(skipSelection: boolean = false, rootFile: string | undefined = undefined, languageId: string | undefined = undefined, recipe: string | undefined = undefined) {
this.extension.logger.addLogMessage('BUILD command invoked.')
if (!vscode.window.activeTextEditor) {
return
Expand All @@ -76,13 +76,14 @@ export class Commander {
const externalBuildArgs = configuration.get('latex.external.build.args') as string[]
if (rootFile === undefined && this.extension.manager.hasTexId(vscode.window.activeTextEditor.document.languageId)) {
rootFile = await this.extension.manager.findRoot()
languageId = this.extension.manager.rootFileLanguageId
}
if (externalBuildCommand) {
const pwd = path.dirname(rootFile ? rootFile : vscode.window.activeTextEditor.document.fileName)
await this.extension.builder.buildWithExternalCommand(externalBuildCommand, externalBuildArgs, pwd, rootFile)
return
}
if (rootFile === undefined) {
if (rootFile === undefined || languageId === undefined) {
this.extension.logger.addLogMessage('Cannot find LaTeX root file.')
return
}
Expand All @@ -95,7 +96,7 @@ export class Commander {
}
}
this.extension.logger.addLogMessage(`Building root file: ${pickedRootFile}`)
await this.extension.builder.build(pickedRootFile, recipe)
await this.extension.builder.build(pickedRootFile, languageId, recipe)
}

async revealOutputDir() {
Expand All @@ -120,7 +121,7 @@ export class Commander {
return
}
if (recipe) {
this.build(false, undefined, recipe)
this.build(false, undefined, undefined, recipe)
return
}
vscode.window.showQuickPick(recipes.map(candidate => candidate.name), {
Expand All @@ -129,7 +130,7 @@ export class Commander {
if (!selected) {
return
}
this.build(false, undefined, selected)
this.build(false, undefined, undefined, selected)
})
}

Expand Down
36 changes: 27 additions & 9 deletions src/components/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export class Builder {
waitingForBuildToFinishMutex: Mutex
isMiktex: boolean = false
previouslyUsedRecipe: {name: string, tools: (string | StepCommand)[]} | undefined
previousLanguageId: string | undefined

constructor(extension: Extension) {
this.extension = extension
Expand Down Expand Up @@ -158,16 +159,16 @@ export class Builder {
})
}

buildInitiator(rootFile: string, recipe: string | undefined = undefined, releaseBuildMutex: () => void) {
const steps = this.createSteps(rootFile, recipe)
buildInitiator(rootFile: string, languageId: string, recipe: string | undefined = undefined, releaseBuildMutex: () => void) {
const steps = this.createSteps(rootFile, languageId, recipe)
if (steps === undefined) {
this.extension.logger.addLogMessage('Invalid toolchain.')
return
}
this.buildStep(rootFile, steps, 0, recipe || 'Build', releaseBuildMutex) // use 'Build' as default name
}

async build(rootFile: string, recipe: string | undefined = undefined) {
async build(rootFile: string, languageId: string, recipe: string | undefined = undefined) {
if (this.isWaitingForBuildToFinish()) {
this.extension.logger.addLogMessage('Another LaTeX build processing is already waiting for the current LaTeX build to finish. Exit.')
return
Expand Down Expand Up @@ -215,7 +216,7 @@ export class Builder {
fs.ensureDirSync(path.resolve(outDir, relativePath))
})
}
this.buildInitiator(rootFile, recipe, releaseBuildMutex)
this.buildInitiator(rootFile, languageId, recipe, releaseBuildMutex)
} catch (e) {
this.extension.buildInfo.buildEnded()
releaseBuildMutex()
Expand Down Expand Up @@ -379,7 +380,7 @@ export class Builder {
}
}

createSteps(rootFile: string, recipeName: string | undefined): StepCommand[] | undefined {
createSteps(rootFile: string, languageId: string, recipeName: string | undefined): StepCommand[] | undefined {
let steps: StepCommand[] = []
const configuration = vscode.workspace.getConfiguration('latex-workshop')

Expand All @@ -406,7 +407,10 @@ export class Builder {
return undefined
}
let recipe = recipes[0]
if ((configuration.get('latex.recipe.default') as string === 'lastUsed') && (this.previouslyUsedRecipe !== undefined)) {
if (this.previousLanguageId !== languageId) {
this.previouslyUsedRecipe = undefined
}
if ((configuration.get('latex.recipe.default') as string === 'lastUsed') && (this.previouslyUsedRecipe !== undefined) ) {
recipe = this.previouslyUsedRecipe
}
if (recipeName) {
Expand All @@ -416,7 +420,15 @@ export class Builder {
}
recipe = candidates[0]
}
if (!recipeName && languageId === 'rsweave') {
const candidates = recipes.filter(candidate => candidate.name.toLowerCase().match('rnw|rsweave'))
if (candidates.length < 1) {
this.extension.logger.showErrorMessage(`Failed to resolve build recipe: ${recipeName}`)
}
recipe = candidates[0]
}
this.previouslyUsedRecipe = recipe
this.previousLanguageId = languageId

recipe.tools.forEach(tool => {
if (typeof tool === 'string') {
Expand Down Expand Up @@ -517,13 +529,19 @@ export class Builder {
return (arg: string) => {
const docker = vscode.workspace.getConfiguration('latex-workshop').get('docker.enabled')

const doc = rootFile.replace(/\.tex$/, '').split(path.sep).join('/')
const docfile = path.basename(rootFile, '.tex').split(path.sep).join('/')
const rootFileParsed = path.parse(rootFile)
const docfile = rootFileParsed.name
const docfileExt = rootFileParsed.base
const dir = path.normalize(rootFileParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
const docExt = path.join(dir, docfileExt)
const outDir = this.extension.manager.getOutDir(rootFile)

return arg.replace(/%DOC%/g, docker ? docfile : doc)
.replace(/%DOC_EXT%/g, docker ? docfileExt : docExt)
.replace(/%DOCFILE_EXT%/g, docfileExt)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, path.dirname(rootFile).split(path.sep).join('/'))
.replace(/%DIR%/g, dir)
.replace(/%TMPDIR%/g, tmpDir)
.replace(/%OUTDIR%/g, outDir)
}
Expand Down
8 changes: 6 additions & 2 deletions src/components/locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,13 @@ export class Locator {
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const command = configuration.get('view.pdf.external.synctex.command') as string
let args = configuration.get('view.pdf.external.synctex.args') as string[]
const rootFileParsed = path.parse(rootFile)
const docfile = rootFileParsed.name
const dir = path.normalize(rootFileParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
if (args) {
args = args.map(arg => arg.replace(/%DOC%/g, rootFile.replace(/\.tex$/, '').split(path.sep).join('/'))
.replace(/%DOCFILE%/g, path.basename(rootFile, '.tex').split(path.sep).join('/'))
args = args.map(arg => arg.replace(/%DOC%/g, doc)
.replace(/%DOCFILE%/g, docfile)
.replace(/%PDF%/g, pdfFile)
.replace(/%LINE%/g, line.toString())
.replace(/%TEX%/g, texFile))
Expand Down
41 changes: 32 additions & 9 deletions src/components/manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class Manager {
private pdfsWatched: string[] = []
private bibsWatched: string[] = []
private watcherOptions: chokidar.WatchOptions
private rsweaveExt: string[] = ['.rnw', '.Rnw', '.rtex', '.Rtex', '.snw', '.Snw']
private pdfWatcherOptions: chokidar.WatchOptions

constructor(extension: Extension) {
Expand Down Expand Up @@ -79,14 +80,16 @@ export class Manager {
return './'
}

const doc = texPath.replace(/\.tex$/, '')
const docfile = path.basename(texPath, '.tex')
const texPathParsed = path.parse(texPath)
const docfile = texPathParsed.name
const dir = path.normalize(texPathParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
const configuration = vscode.workspace.getConfiguration('latex-workshop')
const docker = configuration.get('docker.enabled')
const outDir = configuration.get('latex.outDir') as string
const out = outDir.replace(/%DOC%/g, docker ? docfile : doc)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, docker ? './' : path.dirname(texPath))
.replace(/%DIR%/g, docker ? './' : dir)
.replace(/%TMPDIR%/g, this.extension.builder.tmpDir)
return path.normalize(out).split(path.sep).join('/')

Expand Down Expand Up @@ -114,6 +117,25 @@ export class Manager {
this.localRootFiles[this.workspaceRootDir] = localRoot
}

private rootFilesLanguageIds: { [key: string]: string | undefined } = {}
get rootFileLanguageId() {
return this.rootFilesLanguageIds[this.workspaceRootDir]
}
set rootFileLanguageId(id: string | undefined) {
this.rootFilesLanguageIds[this.workspaceRootDir] = id
}

private inferLanguageId(filename: string): string | undefined {
const ext = path.extname(filename)
if (ext === '.tex') {
return 'latex'
} else if (this.rsweaveExt.includes(ext)) {
return 'rsweave'
} else {
return undefined
}
}

tex2pdf(texPath: string, respectOutDir: boolean = true) {
let outDir = './'
if (respectOutDir) {
Expand Down Expand Up @@ -177,6 +199,7 @@ export class Manager {
if (this.rootFile !== rootFile) {
this.extension.logger.addLogMessage(`Root file changed from: ${this.rootFile} to ${rootFile}. Find all dependencies.`)
this.rootFile = rootFile
this.rootFileLanguageId = this.inferLanguageId(rootFile)
this.initiateFileWatcher()
this.initiateBibWatcher()
this.parseFileAndSubs(this.rootFile) // finish the parsing is required for subsequent refreshes.
Expand Down Expand Up @@ -457,7 +480,7 @@ export class Manager {
// Update children of current file
if (this.cachedContent[file] === undefined) {
this.cachedContent[file] = {content, element: {}, bibs: [], children: []}
const inputReg = /(?:\\(?:input|InputIfFileExists|include|subfile|(?:(?:sub)?(?:import|inputfrom|includefrom)\*?{([^}]*)}))(?:\[[^[\]{}]*\])?){([^}]*)}/g
const inputReg = /(?:\\(?:input|InputIfFileExists|include|SweaveInput|subfile|(?:(?:sub)?(?:import|inputfrom|includefrom)\*?{([^}]*)}))(?:\[[^[\]{}]*\])?){([^}]*)}/g
while (true) {
const result = inputReg.exec(content)
if (!result) {
Expand Down Expand Up @@ -491,7 +514,7 @@ export class Manager {
}

private parseInputFiles(content: string, baseFile: string) {
const inputReg = /(?:\\(?:input|InputIfFileExists|include|subfile|(?:(?:sub)?(?:import|inputfrom|includefrom)\*?{([^}]*)}))(?:\[[^[\]{}]*\])?){([^}]*)}/g
const inputReg = /(?:\\(?:input|InputIfFileExists|include|SweaveInput|subfile|(?:(?:sub)?(?:import|inputfrom|includefrom)\*?{([^}]*)}))(?:\[[^[\]{}]*\])?){([^}]*)}/g
while (true) {
const result = inputReg.exec(content)
if (!result) {
Expand Down Expand Up @@ -696,7 +719,7 @@ export class Manager {

private onWatchingNewFile(file: string) {
this.extension.logger.addLogMessage(`Adding ${file} to file watcher.`)
if (['.tex', '.bib', '.rnw', '.Rnw', '.rtex', '.Rtex'].includes(path.extname(file)) &&
if (['.tex', '.bib'].concat(this.rsweaveExt).includes(path.extname(file)) &&
!file.includes('expl3-code.tex')) {
this.updateCompleterOnChange(file)
}
Expand All @@ -705,7 +728,7 @@ export class Manager {
private onWatchedFileChanged(file: string) {
this.extension.logger.addLogMessage(`File watcher: responding to change in ${file}`)
// It is possible for either tex or non-tex files in the watcher.
if (['.tex', '.bib', '.rnw', '.Rnw', '.rtex', '.Rtex'].includes(path.extname(file)) &&
if (['.tex', '.bib'].concat(this.rsweaveExt).includes(path.extname(file)) &&
!file.includes('expl3-code.tex')) {
this.parseFileAndSubs(file, true)
this.updateCompleterOnChange(file)
Expand Down Expand Up @@ -793,9 +816,9 @@ export class Manager {
}
this.extension.logger.addLogMessage(`${file} changed. Auto build project.`)
if (!bibChanged && this.localRootFile && configuration.get('latex.rootFile.useSubFile')) {
this.extension.commander.build(true, this.localRootFile)
this.extension.commander.build(true, this.localRootFile, this.rootFileLanguageId)
} else {
this.extension.commander.build(true, this.rootFile)
this.extension.commander.build(true, this.rootFile, this.rootFileLanguageId)
}
}

Expand Down
8 changes: 5 additions & 3 deletions src/providers/latexformatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,14 +129,16 @@ export class LaTexFormatter {
const temporaryFile = documentDirectory + path.sep + '__latexindent_temp.tex'
fs.writeFileSync(temporaryFile, textToFormat)

const doc = document.fileName.replace(/\.tex$/, '').split(path.sep).join('/')
const docfile = path.basename(document.fileName, '.tex').split(path.sep).join('/')
const fileNameParsed = path.parse(document.fileName)
const docfile = fileNameParsed.name
const dir = path.normalize(fileNameParsed.dir).split(path.sep).join('/')
const doc = path.join(dir, docfile)
// generate command line arguments
const args = this.formatterArgs.map(arg => arg
// taken from ../components/builder.ts
.replace(/%DOC%/g, useDocker ? docfile : doc)
.replace(/%DOCFILE%/g, docfile)
.replace(/%DIR%/g, useDocker ? '.' : path.dirname(document.fileName).split(path.sep).join('/'))
.replace(/%DIR%/g, useDocker ? '.' : dir)
// latexformatter.ts specific tokens
.replace(/%TMPFILE%/g, useDocker ? path.basename(temporaryFile) : temporaryFile.split(path.sep).join('/'))
.replace(/%INDENT%/g, indent))
Expand Down
6 changes: 5 additions & 1 deletion syntax/RSweave.tmLanguage.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@
"scopeName": "text.tex.latex.rsweave",
"fileTypes": [
"rnw",
"Rnw"
"Rnw",
"rtex",
"Rtex",
"snw",
"Snw"
],
"patterns": [
{
Expand Down