mirror of
https://github.com/James-Yu/LaTeX-Workshop.git
synced 2025-01-07 09:47:04 +03:00
Merge remote-tracking branch 'origin/master' into xr-package
This commit is contained in:
commit
110b39798c
4
.github/workflows/texlive_on_linux.yml
vendored
4
.github/workflows/texlive_on_linux.yml
vendored
@ -67,8 +67,8 @@ jobs:
|
||||
name: latex-workshop
|
||||
path: latex-workshop-*.vsix
|
||||
- name: Archive test logs
|
||||
if: failure()
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-error-log
|
||||
name: test-log
|
||||
path: test/log/*.log
|
4
.github/workflows/texlive_on_mac.yml
vendored
4
.github/workflows/texlive_on_mac.yml
vendored
@ -66,8 +66,8 @@ jobs:
|
||||
name: latex-workshop
|
||||
path: latex-workshop-*.vsix
|
||||
- name: Archive test logs
|
||||
if: failure()
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-error-log
|
||||
name: test-log
|
||||
path: test/log/*.log
|
||||
|
4
.github/workflows/texlive_on_win.yml
vendored
4
.github/workflows/texlive_on_win.yml
vendored
@ -70,8 +70,8 @@ jobs:
|
||||
name: latex-workshop
|
||||
path: latex-workshop-*.vsix
|
||||
- name: Archive test logs
|
||||
if: failure()
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: test-error-log
|
||||
name: test-log
|
||||
path: test/log/*.log
|
||||
|
@ -1,5 +1,13 @@
|
||||
# Change Log
|
||||
|
||||
## [9.4.5] - 2023-01-13
|
||||
|
||||
### Fixed
|
||||
- New command finder now honors argument and optional one list.
|
||||
- Entries in `bibtex-entries.first` should also be sorted.
|
||||
- (#3585) A better description to `latex.watch.files.ignore` config.
|
||||
- (#3640) Resolve a package conflict with `isort` that may prevent command suggestion.
|
||||
|
||||
## [9.4.4] - 2023-01-10
|
||||
|
||||
### Fixed
|
||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "latex-workshop",
|
||||
"version": "9.4.4",
|
||||
"version": "9.4.5",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "latex-workshop",
|
||||
"version": "9.4.4",
|
||||
"version": "9.4.5",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chokidar": "3.5.3",
|
||||
|
@ -3,7 +3,7 @@
|
||||
"displayName": "LaTeX Workshop",
|
||||
"description": "Boost LaTeX typesetting efficiency with preview, compile, autocomplete, colorize, and more.",
|
||||
"icon": "icons/icon.png",
|
||||
"version": "9.4.4",
|
||||
"version": "9.4.5",
|
||||
"publisher": "James-Yu",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/James-Yu/LaTeX-Workshop",
|
||||
|
@ -448,8 +448,8 @@ export async function devParseBib() {
|
||||
return vscode.workspace.openTextDocument({content: JSON.stringify(ast, null, 2), language: 'json'}).then(doc => vscode.window.showTextDocument(doc))
|
||||
}
|
||||
|
||||
export function texdoc(pkg?: string) {
|
||||
lw.texdoc.texdoc(pkg)
|
||||
export function texdoc(packageName?: string) {
|
||||
lw.texdoc.texdoc(packageName)
|
||||
}
|
||||
|
||||
export function texdocUsepackages() {
|
||||
@ -493,17 +493,15 @@ async function quickPickRootFile(rootFile: string, localRootFile: string, verb:
|
||||
matchOnDescription: true
|
||||
}).then( selected => {
|
||||
if (!selected) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
switch (selected.label) {
|
||||
case 'Default root file':
|
||||
return rootFile
|
||||
break
|
||||
case 'Subfiles package root file':
|
||||
return localRootFile
|
||||
break
|
||||
default:
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
})
|
||||
return pickedRootFile
|
||||
|
@ -251,11 +251,8 @@ export class Builder {
|
||||
logger.log(`root: ${step.rootFile}`)
|
||||
|
||||
const env = Object.create(null) as ProcessEnv
|
||||
Object.keys(process.env).forEach(key => env[key] = process.env[key])
|
||||
const toolEnv = step.env
|
||||
if (toolEnv) {
|
||||
Object.keys(toolEnv).forEach(key => env[key] = toolEnv[key])
|
||||
}
|
||||
Object.entries(process.env).forEach(([key, value]) => env[key] = value)
|
||||
Object.entries(step.env ?? {}).forEach(([key, value]) => env[key] = value)
|
||||
env['max_print_line'] = this.MAX_PRINT_LINE
|
||||
|
||||
if (!step.isExternal &&
|
||||
@ -450,7 +447,7 @@ export class Builder {
|
||||
} else {
|
||||
const recipe = this.findRecipe(rootFile, langId, recipeName)
|
||||
if (recipe === undefined) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
logger.log(`Preparing to run recipe: ${recipe.name}.`)
|
||||
this.prevRecipe = recipe
|
||||
@ -471,7 +468,7 @@ export class Builder {
|
||||
})
|
||||
}
|
||||
if (buildTools.length < 1) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
// Use JSON.parse and JSON.stringify for a deep copy.
|
||||
@ -507,21 +504,13 @@ export class Builder {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (tool.args) {
|
||||
tool.args = tool.args.map(replaceArgumentPlaceholders(rootFile, lw.manager.tmpDir))
|
||||
}
|
||||
if (tool.env) {
|
||||
Object.keys(tool.env).forEach( v => {
|
||||
const e = tool.env && tool.env[v]
|
||||
if (tool.env && e) {
|
||||
tool.env[v] = replaceArgumentPlaceholders(rootFile, lw.manager.tmpDir)(e)
|
||||
}
|
||||
})
|
||||
}
|
||||
tool.args = tool.args?.map(replaceArgumentPlaceholders(rootFile, lw.manager.tmpDir))
|
||||
const env = tool.env ?? {}
|
||||
Object.entries(env).forEach(([key, value]) => {
|
||||
env[key] = value && replaceArgumentPlaceholders(rootFile, lw.manager.tmpDir)(value)
|
||||
})
|
||||
if (configuration.get('latex.option.maxPrintLine.enabled')) {
|
||||
if (!tool.args) {
|
||||
tool.args = []
|
||||
}
|
||||
tool.args = tool.args ?? []
|
||||
const isLuaLatex = tool.args.includes('-lualatex') ||
|
||||
tool.args.includes('-pdflua') ||
|
||||
tool.args.includes('-pdflualatex') ||
|
||||
@ -545,7 +534,7 @@ export class Builder {
|
||||
if (recipes.length < 1) {
|
||||
logger.log('No recipes defined.')
|
||||
void logger.showErrorMessage('[Builder] No recipes defined.')
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
if (this.prevLangId !== langId) {
|
||||
this.prevRecipe = undefined
|
||||
|
@ -20,7 +20,7 @@ import { UtensilsParser } from './parser/syntax'
|
||||
|
||||
const logger = getLogger('Cacher')
|
||||
|
||||
export interface Context {
|
||||
export interface Cache {
|
||||
/** Cached content of file. Dirty if opened in vscode, disk otherwise */
|
||||
content: string | undefined,
|
||||
/** Completion items */
|
||||
@ -53,7 +53,7 @@ export interface Context {
|
||||
}
|
||||
|
||||
export class Cacher {
|
||||
private readonly contexts: {[filePath: string]: Context} = {}
|
||||
private readonly caches: {[filePath: string]: Cache} = {}
|
||||
private readonly watcher: Watcher = new Watcher(this)
|
||||
private readonly pdfWatcher: PdfWatcher = new PdfWatcher()
|
||||
private readonly bibWatcher: BibWatcher = new BibWatcher()
|
||||
@ -70,23 +70,23 @@ export class Cacher {
|
||||
}
|
||||
|
||||
remove(filePath: string) {
|
||||
if (!(filePath in this.contexts)) {
|
||||
if (!(filePath in this.caches)) {
|
||||
return
|
||||
}
|
||||
delete this.contexts[filePath]
|
||||
delete this.caches[filePath]
|
||||
logger.log(`Removed ${filePath} .`)
|
||||
}
|
||||
|
||||
has(filePath: string) {
|
||||
return Object.keys(this.contexts).includes(filePath)
|
||||
return Object.keys(this.caches).includes(filePath)
|
||||
}
|
||||
|
||||
get(filePath: string): Context {
|
||||
return this.contexts[filePath]
|
||||
get(filePath: string): Cache | undefined {
|
||||
return this.caches[filePath]
|
||||
}
|
||||
|
||||
get allPaths() {
|
||||
return Object.keys(this.contexts)
|
||||
return Object.keys(this.caches)
|
||||
}
|
||||
|
||||
watched(filePath: string) {
|
||||
@ -103,17 +103,17 @@ export class Cacher {
|
||||
await this.bibWatcher.dispose()
|
||||
}
|
||||
|
||||
async refreshContext(filePath: string, rootPath?: string) {
|
||||
async refreshCache(filePath: string, rootPath?: string) {
|
||||
if (CacherUtils.isExcluded(filePath)) {
|
||||
logger.log(`Ignored ${filePath} .`)
|
||||
return
|
||||
}
|
||||
if (!CacherUtils.canContext(filePath)) {
|
||||
if (!CacherUtils.canCache(filePath)) {
|
||||
return
|
||||
}
|
||||
logger.log(`Caching ${filePath} .`)
|
||||
const content = lw.lwfs.readFileSyncGracefully(filePath)
|
||||
this.contexts[filePath] = {content, elements: {}, children: [], bibfiles: new Set(), external: {}}
|
||||
this.caches[filePath] = {content, elements: {}, children: [], bibfiles: new Set(), external: {}}
|
||||
if (content === undefined) {
|
||||
logger.log(`Cannot read ${filePath} .`)
|
||||
return
|
||||
@ -124,6 +124,7 @@ export class Cacher {
|
||||
await this.updateElements(filePath, content, contentTrimmed)
|
||||
await this.updateBibfiles(filePath, contentTrimmed)
|
||||
logger.log(`Cached ${filePath} .`)
|
||||
void lw.structureViewer.computeTreeStructure()
|
||||
lw.eventBus.fire(eventbus.FileParsed, filePath)
|
||||
}
|
||||
|
||||
@ -146,7 +147,7 @@ export class Cacher {
|
||||
continue
|
||||
}
|
||||
|
||||
this.contexts[rootPath].children.push({
|
||||
this.caches[rootPath].children.push({
|
||||
index: result.match.index,
|
||||
filePath: result.path
|
||||
})
|
||||
@ -156,7 +157,7 @@ export class Cacher {
|
||||
continue
|
||||
}
|
||||
this.add(result.path)
|
||||
void this.refreshContext(result.path, rootPath)
|
||||
void this.refreshCache(result.path, rootPath)
|
||||
}
|
||||
}
|
||||
|
||||
@ -176,7 +177,7 @@ export class Cacher {
|
||||
continue
|
||||
}
|
||||
|
||||
this.contexts[rootPath].external[externalPath] = result[1] || ''
|
||||
this.caches[rootPath].external[externalPath] = result[1] || ''
|
||||
logger.log(`External document ${externalPath} from ${filePath} .` +
|
||||
(result[1] ? ` Prefix is ${result[1]}`: ''))
|
||||
|
||||
@ -184,7 +185,7 @@ export class Cacher {
|
||||
continue
|
||||
}
|
||||
this.add(externalPath)
|
||||
void this.refreshContext(externalPath, externalPath)
|
||||
void this.refreshCache(externalPath, externalPath)
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +230,7 @@ export class Cacher {
|
||||
if (bibPath === undefined) {
|
||||
continue
|
||||
}
|
||||
this.contexts[filePath].bibfiles.add(bibPath)
|
||||
this.caches[filePath].bibfiles.add(bibPath)
|
||||
logger.log(`Bib ${bibPath} from ${filePath} .`)
|
||||
await this.bibWatcher.watchBibFile(bibPath)
|
||||
}
|
||||
@ -273,16 +274,16 @@ export class Cacher {
|
||||
}
|
||||
if (path.extname(inputFile) === '.tex') {
|
||||
if (!this.has(filePath)) {
|
||||
await this.refreshContext(filePath)
|
||||
await this.refreshCache(filePath)
|
||||
}
|
||||
// Parse tex files as imported subfiles.
|
||||
this.contexts[filePath].children.push({
|
||||
this.caches[filePath].children.push({
|
||||
index: Number.MAX_VALUE,
|
||||
filePath: inputFile
|
||||
})
|
||||
this.add(inputFile)
|
||||
logger.log(`Found ${inputFile} from .fls ${flsPath} .`)
|
||||
await this.refreshContext(inputFile, filePath)
|
||||
await this.refreshCache(inputFile, filePath)
|
||||
} else if (!this.watched(inputFile)) {
|
||||
// Watch non-tex files.
|
||||
this.add(inputFile)
|
||||
@ -316,8 +317,8 @@ export class Cacher {
|
||||
continue
|
||||
}
|
||||
const rootFile = lw.manager.rootFile
|
||||
if (rootFile && !this.get(rootFile).bibfiles.has(bibPath)) {
|
||||
this.get(rootFile).bibfiles.add(bibPath)
|
||||
if (rootFile && !this.get(rootFile)?.bibfiles.has(bibPath)) {
|
||||
this.get(rootFile)?.bibfiles.add(bibPath)
|
||||
logger.log(`Found .bib ${bibPath} from .aux ${filePath} .`)
|
||||
}
|
||||
await this.bibWatcher.watchBibFile(bibPath)
|
||||
@ -354,13 +355,15 @@ export class Cacher {
|
||||
}
|
||||
children.push(file)
|
||||
const cache = this.get(file)
|
||||
includedBib.push(...cache.bibfiles)
|
||||
for (const child of cache.children) {
|
||||
if (children.includes(child.filePath)) {
|
||||
// Already parsed
|
||||
continue
|
||||
if (cache) {
|
||||
includedBib.push(...cache.bibfiles)
|
||||
for (const child of cache.children) {
|
||||
if (children.includes(child.filePath)) {
|
||||
// Already parsed
|
||||
continue
|
||||
}
|
||||
this.getIncludedBib(child.filePath, includedBib)
|
||||
}
|
||||
this.getIncludedBib(child.filePath, includedBib)
|
||||
}
|
||||
// Make sure to return an array with unique entries
|
||||
return Array.from(new Set(includedBib))
|
||||
@ -385,12 +388,15 @@ export class Cacher {
|
||||
return []
|
||||
}
|
||||
includedTeX.push(file)
|
||||
for (const child of this.get(file).children) {
|
||||
if (includedTeX.includes(child.filePath)) {
|
||||
// Already included
|
||||
continue
|
||||
const cache = this.get(file)
|
||||
if (cache) {
|
||||
for (const child of cache.children) {
|
||||
if (includedTeX.includes(child.filePath)) {
|
||||
// Already included
|
||||
continue
|
||||
}
|
||||
this.getIncludedTeX(child.filePath, includedTeX)
|
||||
}
|
||||
this.getIncludedTeX(child.filePath, includedTeX)
|
||||
}
|
||||
return includedTeX
|
||||
}
|
||||
@ -404,10 +410,10 @@ export class Cacher {
|
||||
*/
|
||||
async getTeXChildren(file: string, baseFile: string, children: string[]) {
|
||||
if (!this.has(file)) {
|
||||
await this.refreshContext(file, baseFile)
|
||||
await this.refreshCache(file, baseFile)
|
||||
}
|
||||
|
||||
this.get(file).children.forEach(async child => {
|
||||
this.get(file)?.children.forEach(async child => {
|
||||
if (children.includes(child.filePath)) {
|
||||
// Already included
|
||||
return
|
||||
|
@ -5,7 +5,7 @@ import micromatch from 'micromatch'
|
||||
import { JLWEAVE_EXT, PWEAVE_EXT, RSWEAVE_EXT, TEX_EXT } from '../manager'
|
||||
|
||||
export class CacherUtils {
|
||||
static canContext(filePath: string) {
|
||||
static canCache(filePath: string) {
|
||||
return [...TEX_EXT, ...RSWEAVE_EXT, ...JLWEAVE_EXT, ...PWEAVE_EXT].includes(path.extname(filePath))
|
||||
&& !filePath.includes('expl3-code.tex')
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ export class PathUtils {
|
||||
const flsFile = path.resolve(rootDir, path.join(outDir, baseName + '.fls'))
|
||||
if (!fs.existsSync(flsFile)) {
|
||||
logger.log(`Non-existent .fls for ${texFile} .`)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
return flsFile
|
||||
}
|
||||
@ -42,7 +42,7 @@ export class PathUtils {
|
||||
if (kpsewhichReturn.status === 0) {
|
||||
const bibPath = kpsewhichReturn.stdout.toString().replace(/\r?\n/, '')
|
||||
if (bibPath === '') {
|
||||
return undefined
|
||||
return
|
||||
} else {
|
||||
return bibPath
|
||||
}
|
||||
@ -50,7 +50,7 @@ export class PathUtils {
|
||||
} catch(e) {
|
||||
logger.logError(`Calling ${kpsewhich} on ${bib} failed.`, e)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
static resolveBibPath(bib: string, baseDir: string) {
|
||||
@ -71,7 +71,7 @@ export class PathUtils {
|
||||
return PathUtils.kpsewhichBibPath(bib)
|
||||
} else {
|
||||
logger.log(`Cannot resolve ${bib} .`)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
return bibPath
|
||||
|
@ -57,8 +57,8 @@ export class Watcher {
|
||||
}
|
||||
|
||||
private onChange(filePath: string) {
|
||||
if (CacherUtils.canContext(filePath)) {
|
||||
void this.cacher.refreshContext(filePath)
|
||||
if (CacherUtils.canCache(filePath)) {
|
||||
void this.cacher.refreshCache(filePath)
|
||||
}
|
||||
void lw.builder.buildOnFileChanged(filePath)
|
||||
logger.log(`Changed ${filePath} .`)
|
||||
|
@ -58,9 +58,9 @@ export class Configuration {
|
||||
|
||||
private checkDeprecatedConfiguration() {
|
||||
const packageDef = JSON.parse(readFileSync(path.resolve(__dirname, '../../../package.json')).toString()) as {contributes: {configuration: {properties: {[config: string]: {default: any, deprecationMessage?: string}}}}}
|
||||
const configs = Object.keys(packageDef.contributes.configuration.properties)
|
||||
const deprecatedConfigs = configs.filter(config => packageDef.contributes.configuration.properties[config].deprecationMessage)
|
||||
.map(config => config.split('.').slice(1).join('.'))
|
||||
const deprecatedConfigs = Object.entries(packageDef.contributes.configuration.properties)
|
||||
.filter(([_, value]) => value.deprecationMessage)
|
||||
.map(([config, _]) => config.split('.').slice(1).join('.'))
|
||||
const workspaceFolders = vscode.workspace.workspaceFolders || [undefined]
|
||||
for (const workspace of workspaceFolders) {
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop', workspace)
|
||||
|
@ -100,9 +100,7 @@ export class EnvPair {
|
||||
return null
|
||||
}
|
||||
const begins = Object.keys(this.delimiters)
|
||||
const ends = Object.keys(this.delimiters).map((key) => {
|
||||
return this.delimiters[key].end
|
||||
})
|
||||
const ends = Object.values(this.delimiters).map(value => value.end)
|
||||
while (true) {
|
||||
line = utils.stripCommentsAndVerbatim(line)
|
||||
let allMatches = regexpAllMatches(line, patRegexp)
|
||||
|
@ -11,6 +11,7 @@ export const ViewerStatusChanged = 'VIEWER_STATUS_CHANGED'
|
||||
export const FileWatched = 'FILE_WATCHED'
|
||||
export const FileChanged = 'FILE_CHANGED'
|
||||
export const FileRemoved = 'FILE_REMOVED'
|
||||
export const DocumentChanged = 'DOCUMENT_CHANGED'
|
||||
|
||||
type EventArgTypeMap = {
|
||||
[RootFileChanged]: string,
|
||||
@ -30,6 +31,7 @@ export type EventName = typeof BuildDone
|
||||
| typeof FileWatched
|
||||
| typeof FileChanged
|
||||
| typeof FileRemoved
|
||||
| typeof DocumentChanged
|
||||
|
||||
export class EventBus {
|
||||
private readonly eventEmitter = new EventEmitter()
|
||||
@ -44,41 +46,41 @@ export class EventBus {
|
||||
this.eventEmitter.emit(eventName, arg)
|
||||
}
|
||||
|
||||
onDidChangeRootFile(cb: (rootFile: EventArgTypeMap[typeof RootFileChanged]) => void): Disposable {
|
||||
return this.registerListener(RootFileChanged, cb)
|
||||
}
|
||||
// onDidChangeRootFile(cb: (rootFile: EventArgTypeMap[typeof RootFileChanged]) => void): Disposable {
|
||||
// return this.registerListener(RootFileChanged, cb)
|
||||
// }
|
||||
|
||||
onDidEndFindRootFile(cb: () => void): Disposable {
|
||||
return this.registerListener(RootFileSearched, cb)
|
||||
}
|
||||
// onDidEndFindRootFile(cb: () => void): Disposable {
|
||||
// return this.registerListener(RootFileSearched, cb)
|
||||
// }
|
||||
|
||||
onDidFileParsed(cb: () => void): Disposable {
|
||||
return this.registerListener(FileParsed, cb)
|
||||
}
|
||||
// onDidFileParsed(cb: () => void): Disposable {
|
||||
// return this.registerListener(FileParsed, cb)
|
||||
// }
|
||||
|
||||
onDidChangePdfViewerStatus(cb: (status: EventArgTypeMap[typeof ViewerStatusChanged]) => void): Disposable {
|
||||
return this.registerListener(ViewerStatusChanged, cb)
|
||||
}
|
||||
// onDidChangePdfViewerStatus(cb: (status: EventArgTypeMap[typeof ViewerStatusChanged]) => void): Disposable {
|
||||
// return this.registerListener(ViewerStatusChanged, cb)
|
||||
// }
|
||||
|
||||
private registerListener<T extends keyof EventArgTypeMap>(
|
||||
eventName: T,
|
||||
cb: (arg: EventArgTypeMap[T]) => void
|
||||
): Disposable
|
||||
private registerListener<T extends EventName>(
|
||||
eventName: T,
|
||||
cb: () => void
|
||||
): Disposable
|
||||
private registerListener<T extends EventName>(
|
||||
eventName: T,
|
||||
cb: (arg?: any) => void
|
||||
): Disposable
|
||||
{
|
||||
this.eventEmitter.on(eventName, cb)
|
||||
const disposable = {
|
||||
dispose: () => { this.eventEmitter.removeListener(eventName, cb) }
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
// private registerListener<T extends keyof EventArgTypeMap>(
|
||||
// eventName: T,
|
||||
// cb: (arg: EventArgTypeMap[T]) => void
|
||||
// ): Disposable
|
||||
// private registerListener<T extends EventName>(
|
||||
// eventName: T,
|
||||
// cb: () => void
|
||||
// ): Disposable
|
||||
// private registerListener<T extends EventName>(
|
||||
// eventName: T,
|
||||
// cb: (arg?: any) => void
|
||||
// ): Disposable
|
||||
// {
|
||||
// this.eventEmitter.on(eventName, cb)
|
||||
// const disposable = {
|
||||
// dispose: () => { this.eventEmitter.removeListener(eventName, cb) }
|
||||
// }
|
||||
// return disposable
|
||||
// }
|
||||
|
||||
on(eventName: EventName, cb: (arg?: any) => void): Disposable {
|
||||
this.eventEmitter.on(eventName, cb)
|
||||
|
@ -62,7 +62,7 @@ export class ChkTeX implements ILinter {
|
||||
if ('stdout' in err) {
|
||||
stdout = err.stdout as string
|
||||
} else {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ export class ChkTeX implements ILinter {
|
||||
if (fs.existsSync(rcPath)) {
|
||||
return rcPath
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private globalRcPath(): string | undefined {
|
||||
|
@ -49,7 +49,7 @@ export class LaCheck implements ILinter {
|
||||
if ('stdout' in err) {
|
||||
stdout = err.stdout as string
|
||||
} else {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,15 +417,11 @@ export class Locator {
|
||||
}
|
||||
// Only one match or one best match
|
||||
if (values.length >= 1) {
|
||||
return parseInt(Object.keys(columnMatches).reduce((a, b) => {
|
||||
return columnMatches[a] > columnMatches[b] ? a : b
|
||||
}))
|
||||
return parseInt(Object.keys(columnMatches).reduce((a, b) => columnMatches[a] > columnMatches[b] ? a : b))
|
||||
}
|
||||
// No match in current iteration, return first best match from previous run or 0
|
||||
if (Object.keys(previousColumnMatches).length > 0) {
|
||||
return parseInt(Object.keys(previousColumnMatches).reduce((a, b) => {
|
||||
return previousColumnMatches[a] > previousColumnMatches[b] ? a : b
|
||||
}))
|
||||
return parseInt(Object.keys(previousColumnMatches).reduce((a, b) => previousColumnMatches[a] > previousColumnMatches[b] ? a : b))
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ export class SyncTexJs {
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
static syncTexJsForward(line: number, filePath: string, pdfFile: string): SyncTeXRecordForward {
|
||||
|
@ -6,6 +6,17 @@ const STATUS_ITEM = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.
|
||||
const PLACEHOLDERS: {[placeholder: string]: string} = {}
|
||||
|
||||
COMPILER_PANEL.append('Ready')
|
||||
let CACHED_EXTLOG: string[] = []
|
||||
let CACHED_COMPILER: string[] = []
|
||||
|
||||
export function resetCachedLog() {
|
||||
CACHED_EXTLOG = []
|
||||
CACHED_COMPILER = []
|
||||
}
|
||||
|
||||
export function getCachedLog() {
|
||||
return {CACHED_EXTLOG, CACHED_COMPILER}
|
||||
}
|
||||
|
||||
export function getLogger(...tags: string[]) {
|
||||
const tagString = tags.map(tag => `[${tag}]`).join('')
|
||||
@ -44,14 +55,17 @@ function logTagless(message: string) {
|
||||
}
|
||||
const placeholder = `%WS${Object.keys(PLACEHOLDERS).length + 1}%`
|
||||
PLACEHOLDERS[folder.uri.fsPath] = placeholder
|
||||
LOG_PANEL.appendLine(`[${timestamp}][Logger] New log placeholder ${placeholder} registered for ${folder.uri.fsPath} .`)
|
||||
const log = `[${timestamp}][Logger] New log placeholder ${placeholder} registered for ${folder.uri.fsPath} .`
|
||||
LOG_PANEL.appendLine(log)
|
||||
CACHED_EXTLOG.push(log)
|
||||
})
|
||||
LOG_PANEL.appendLine(`[${timestamp}]${applyPlaceholders(message)}`)
|
||||
const log = `[${timestamp}]${applyPlaceholders(message)}`
|
||||
LOG_PANEL.appendLine(log)
|
||||
CACHED_EXTLOG.push(log)
|
||||
}
|
||||
|
||||
function applyPlaceholders(message: string) {
|
||||
Object.keys(PLACEHOLDERS)
|
||||
.forEach(placeholder => message = message.replaceAll(placeholder, PLACEHOLDERS[placeholder]))
|
||||
Object.entries(PLACEHOLDERS).forEach(([path, placeholder]) => message = message.replaceAll(path, placeholder))
|
||||
return message
|
||||
}
|
||||
|
||||
@ -77,6 +91,7 @@ function logErrorTagless(message: string, error: unknown, stderr?: string) {
|
||||
|
||||
function logCompiler(message: string) {
|
||||
COMPILER_PANEL.append(message)
|
||||
CACHED_COMPILER.push(message)
|
||||
}
|
||||
|
||||
function initializeStatusBarItem() {
|
||||
@ -139,9 +154,8 @@ function showErrorMessage(message: string, ...args: string[]): Thenable<string |
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop')
|
||||
if (configuration.get('message.error.show')) {
|
||||
return vscode.window.showErrorMessage(message, ...args)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
function showErrorMessageWithCompilerLogButton(message: string) {
|
||||
|
@ -42,7 +42,7 @@ export class LwFileSystem {
|
||||
const ret = fs.readFileSync(filepath).toString()
|
||||
return ret
|
||||
} catch (err) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import * as tmp from 'tmp'
|
||||
import * as utils from '../utils/utils'
|
||||
import * as lw from '../lw'
|
||||
import * as eventbus from './eventbus'
|
||||
import { FinderUtils } from './managerlib/finderutils'
|
||||
import { getLogger } from './logger'
|
||||
|
||||
const logger = getLogger('Manager')
|
||||
@ -155,7 +154,7 @@ export class Manager {
|
||||
if (rootFileUri) {
|
||||
return vscode.workspace.getWorkspaceFolder(rootFileUri)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private inferLanguageId(filename: string): string | undefined {
|
||||
@ -171,7 +170,7 @@ export class Manager {
|
||||
} else if (ext === '.dtx') {
|
||||
return 'doctex'
|
||||
} else {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,7 +211,7 @@ export class Manager {
|
||||
const firstDir = vscode.workspace.workspaceFolders?.[0]
|
||||
// If no workspace is opened.
|
||||
if (!firstDir) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
// If we don't have an active text editor, we can only make a guess.
|
||||
// Let's guess the first one.
|
||||
@ -238,7 +237,7 @@ export class Manager {
|
||||
logger.log(`Current workspace folders: ${JSON.stringify(wsfolders)}`)
|
||||
this.localRootFile = undefined
|
||||
const findMethods = [
|
||||
() => FinderUtils.findRootFromMagic(),
|
||||
() => this.findRootFromMagic(),
|
||||
() => this.findRootFromActive(),
|
||||
() => this.findRootFromCurrentRoot(),
|
||||
() => this.findRootInWorkspace()
|
||||
@ -259,50 +258,94 @@ export class Manager {
|
||||
lw.duplicateLabels.reset()
|
||||
await lw.cacher.resetWatcher()
|
||||
lw.cacher.add(this.rootFile)
|
||||
await lw.cacher.refreshContext(this.rootFile)
|
||||
// await this.initiateFileWatcher()
|
||||
// await this.parseFileAndSubs(this.rootFile, this.rootFile) // Finishing the parsing is required for subsequent refreshes.
|
||||
await lw.cacher.refreshCache(this.rootFile)
|
||||
// We need to parse the fls to discover file dependencies when defined by TeX macro
|
||||
// It happens a lot with subfiles, https://tex.stackexchange.com/questions/289450/path-of-figures-in-different-directories-with-subfile-latex
|
||||
await lw.cacher.loadFlsFile(this.rootFile)
|
||||
void lw.structureViewer.computeTreeStructure()
|
||||
lw.eventBus.fire(eventbus.RootFileChanged, rootFile)
|
||||
} else {
|
||||
logger.log(`Keep using the same root file: ${this.rootFile}`)
|
||||
void lw.structureViewer.refreshView()
|
||||
}
|
||||
lw.eventBus.fire(eventbus.RootFileSearched)
|
||||
return rootFile
|
||||
}
|
||||
void lw.structureViewer.refreshView()
|
||||
lw.eventBus.fire(eventbus.RootFileSearched)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private findRootFromMagic(): string | undefined {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return
|
||||
}
|
||||
const regex = /^(?:%\s*!\s*T[Ee]X\sroot\s*=\s*(.*\.(?:tex|[jrsRS]nw|[rR]tex|jtexw))$)/m
|
||||
let content: string | undefined = vscode.window.activeTextEditor.document.getText()
|
||||
|
||||
let result = content.match(regex)
|
||||
const fileStack: string[] = []
|
||||
if (result) {
|
||||
let file = path.resolve(path.dirname(vscode.window.activeTextEditor.document.fileName), result[1])
|
||||
content = lw.lwfs.readFileSyncGracefully(file)
|
||||
if (content === undefined) {
|
||||
logger.log(`Non-existent magic root ${file} .`)
|
||||
return
|
||||
}
|
||||
fileStack.push(file)
|
||||
logger.log(`Found magic root ${file} from active.`)
|
||||
|
||||
result = content.match(regex)
|
||||
while (result) {
|
||||
file = path.resolve(path.dirname(file), result[1])
|
||||
if (fileStack.includes(file)) {
|
||||
logger.log(`Found looped magic root ${file} .`)
|
||||
return file
|
||||
} else {
|
||||
fileStack.push(file)
|
||||
logger.log(`Found magic root ${file}`)
|
||||
}
|
||||
|
||||
content = lw.lwfs.readFileSyncGracefully(file)
|
||||
if (content === undefined) {
|
||||
logger.log(`Non-existent magic root ${file} .`)
|
||||
return
|
||||
}
|
||||
result = content.match(regex)
|
||||
}
|
||||
logger.log(`Finalized magic root ${file} .`)
|
||||
return file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
private findRootFromCurrentRoot(): string | undefined {
|
||||
if (!vscode.window.activeTextEditor || this.rootFile === undefined) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
if (lw.lwfs.isVirtualUri(vscode.window.activeTextEditor.document.uri)) {
|
||||
logger.log(`The active document cannot be used as the root file: ${vscode.window.activeTextEditor.document.uri.toString(true)}`)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
if (lw.cacher.getIncludedTeX().includes(vscode.window.activeTextEditor.document.fileName)) {
|
||||
return this.rootFile
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private findRootFromActive(): string | undefined {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
if (lw.lwfs.isVirtualUri(vscode.window.activeTextEditor.document.uri)) {
|
||||
logger.log(`The active document cannot be used as the root file: ${vscode.window.activeTextEditor.document.uri.toString(true)}`)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const regex = /\\begin{document}/m
|
||||
const content = utils.stripCommentsAndVerbatim(vscode.window.activeTextEditor.document.getText())
|
||||
const result = content.match(regex)
|
||||
if (result) {
|
||||
const rootSubFile = FinderUtils.findSubFiles(content)
|
||||
const rootSubFile = this.findSubFiles(content)
|
||||
const file = vscode.window.activeTextEditor.document.fileName
|
||||
if (rootSubFile) {
|
||||
this.localRootFile = file
|
||||
@ -312,7 +355,23 @@ export class Manager {
|
||||
return file
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private findSubFiles(content: string): string | undefined {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return
|
||||
}
|
||||
const regex = /(?:\\documentclass\[(.*)\]{subfiles})/
|
||||
const result = content.match(regex)
|
||||
if (result) {
|
||||
const file = utils.resolveFile([path.dirname(vscode.window.activeTextEditor.document.fileName)], result[1])
|
||||
if (file) {
|
||||
logger.log(`Found subfile root ${file} from active.`)
|
||||
}
|
||||
return file
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
private async findRootInWorkspace(): Promise<string | undefined> {
|
||||
@ -321,7 +380,7 @@ export class Manager {
|
||||
logger.log(`Current workspaceRootDir: ${currentWorkspaceDirUri ? currentWorkspaceDirUri.toString(true) : ''}`)
|
||||
|
||||
if (!currentWorkspaceDirUri) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop', currentWorkspaceDirUri)
|
||||
@ -360,7 +419,7 @@ export class Manager {
|
||||
return candidates[0]
|
||||
}
|
||||
} catch (e) {}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private registerSetEnvVar() {
|
||||
|
@ -1,69 +0,0 @@
|
||||
import * as vscode from 'vscode'
|
||||
import * as path from 'path'
|
||||
import * as lw from '../../lw'
|
||||
import * as utils from '../../utils/utils'
|
||||
import { getLogger } from '../logger'
|
||||
|
||||
const logger = getLogger('Manager', 'Finder')
|
||||
|
||||
export class FinderUtils {
|
||||
static findRootFromMagic(): string | undefined {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return undefined
|
||||
}
|
||||
const regex = /^(?:%\s*!\s*T[Ee]X\sroot\s*=\s*(.*\.(?:tex|[jrsRS]nw|[rR]tex|jtexw))$)/m
|
||||
let content: string | undefined = vscode.window.activeTextEditor.document.getText()
|
||||
|
||||
let result = content.match(regex)
|
||||
const fileStack: string[] = []
|
||||
if (result) {
|
||||
let file = path.resolve(path.dirname(vscode.window.activeTextEditor.document.fileName), result[1])
|
||||
content = lw.lwfs.readFileSyncGracefully(file)
|
||||
if (content === undefined) {
|
||||
logger.log(`Non-existent magic root ${file} .`)
|
||||
return undefined
|
||||
}
|
||||
fileStack.push(file)
|
||||
logger.log(`Found magic root ${file} from active.`)
|
||||
|
||||
result = content.match(regex)
|
||||
while (result) {
|
||||
file = path.resolve(path.dirname(file), result[1])
|
||||
if (fileStack.includes(file)) {
|
||||
logger.log(`Found looped magic root ${file} .`)
|
||||
return file
|
||||
} else {
|
||||
fileStack.push(file)
|
||||
logger.log(`Found magic root ${file}`)
|
||||
}
|
||||
|
||||
content = lw.lwfs.readFileSyncGracefully(file)
|
||||
if (content === undefined) {
|
||||
logger.log(`Non-existent magic root ${file} .`)
|
||||
return undefined
|
||||
}
|
||||
result = content.match(regex)
|
||||
}
|
||||
logger.log(`Finalized magic root ${file} .`)
|
||||
return file
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
static findSubFiles(content: string): string | undefined {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return undefined
|
||||
}
|
||||
const regex = /(?:\\documentclass\[(.*)\]{subfiles})/
|
||||
const result = content.match(regex)
|
||||
if (result) {
|
||||
const file = utils.resolveFile([path.dirname(vscode.window.activeTextEditor.document.fileName)], result[1])
|
||||
if (file) {
|
||||
logger.log(`Found subfile root ${file} from active.`)
|
||||
}
|
||||
return file
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
}
|
@ -112,7 +112,7 @@ export class BibLogParser {
|
||||
return {file, line}
|
||||
} else {
|
||||
logger.log(`Cannot find key ${key}`)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,11 +114,11 @@ export class CompilerLogParser {
|
||||
|
||||
private static getErrorPosition(item: LogEntry): {start: number, end: number} | undefined {
|
||||
if (!item.errorPosText) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const content = lw.cacher.get(item.file).content
|
||||
const content = lw.cacher.get(item.file)?.content
|
||||
if (!content) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
// Try to find the errorPosText in the respective line of the document
|
||||
const lines = content.split('\n')
|
||||
@ -135,7 +135,7 @@ export class CompilerLogParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
static showCompilerDiagnostics(compilerDiagnostics: vscode.DiagnosticCollection, buildLog: LogEntry[], source: string) {
|
||||
|
@ -132,7 +132,7 @@ export class Section {
|
||||
return {level: res[1], pos: new vscode.Position(i, 0)}
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
@ -6,11 +6,11 @@ import { getLogger } from './logger'
|
||||
const logger = getLogger('TeXDoc')
|
||||
|
||||
export class TeXDoc {
|
||||
private runTexdoc(pkg: string) {
|
||||
private runTexdoc(packageName: string) {
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop')
|
||||
const texdocPath = configuration.get('texdoc.path') as string
|
||||
const texdocArgs = Array.from(configuration.get('texdoc.args') as string[])
|
||||
texdocArgs.push(pkg)
|
||||
texdocArgs.push(packageName)
|
||||
logger.logCommand('Run texdoc command', texdocPath, texdocArgs)
|
||||
const proc = cs.spawn(texdocPath, texdocArgs)
|
||||
|
||||
@ -31,15 +31,15 @@ export class TeXDoc {
|
||||
|
||||
proc.on('exit', exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
logger.logError(`Cannot find documentation for ${pkg}.`, exitCode)
|
||||
logger.logError(`Cannot find documentation for ${packageName}.`, exitCode)
|
||||
void logger.showErrorMessage('Texdoc failed. Please refer to LaTeX Workshop Output for details.')
|
||||
} else {
|
||||
const regex = new RegExp(`(no documentation found)|(Documentation for ${pkg} could not be found)`)
|
||||
const regex = new RegExp(`(no documentation found)|(Documentation for ${packageName} could not be found)`)
|
||||
if (stdout.match(regex) || stderr.match(regex)) {
|
||||
logger.log(`Cannot find documentation for ${pkg}.`)
|
||||
void logger.showErrorMessage(`Cannot find documentation for ${pkg}.`)
|
||||
logger.log(`Cannot find documentation for ${packageName}.`)
|
||||
void logger.showErrorMessage(`Cannot find documentation for ${packageName}.`)
|
||||
} else {
|
||||
logger.log(`Opening documentation for ${pkg}.`)
|
||||
logger.log(`Opening documentation for ${packageName}.`)
|
||||
}
|
||||
}
|
||||
logger.log(`texdoc stdout: ${stdout}`)
|
||||
@ -47,9 +47,9 @@ export class TeXDoc {
|
||||
})
|
||||
}
|
||||
|
||||
texdoc(pkg?: string) {
|
||||
if (pkg) {
|
||||
this.runTexdoc(pkg)
|
||||
texdoc(packageName?: string) {
|
||||
if (packageName) {
|
||||
this.runTexdoc(packageName)
|
||||
return
|
||||
}
|
||||
void vscode.window.showInputBox({value: '', prompt: 'Package name'}).then(selectedPkg => {
|
||||
@ -68,12 +68,10 @@ export class TeXDoc {
|
||||
if (!pkgs) {
|
||||
continue
|
||||
}
|
||||
Object.keys(pkgs).forEach(pkg => names.add(pkg))
|
||||
Object.keys(pkgs).forEach(packageName => names.add(packageName))
|
||||
}
|
||||
const packagenames = Array.from(new Set(names))
|
||||
const items: vscode.QuickPickItem[] = packagenames.map( name => {
|
||||
return { label: name }
|
||||
})
|
||||
const packageNames = Array.from(new Set(names))
|
||||
const items: vscode.QuickPickItem[] = packageNames.map(packageName => ({ label: packageName }))
|
||||
void vscode.window.showQuickPick(items).then(selectedPkg => {
|
||||
if (!selectedPkg) {
|
||||
return
|
||||
|
@ -9,15 +9,15 @@ export class PdfViewerHookProvider implements vscode.CustomReadonlyEditorProvide
|
||||
}
|
||||
}
|
||||
|
||||
resolveCustomEditor(document: vscode.CustomDocument, webviewPanel: vscode.WebviewPanel) {
|
||||
webviewPanel.webview.options = {
|
||||
...webviewPanel.webview.options,
|
||||
enableScripts: true
|
||||
}
|
||||
resolveCustomEditor(document: vscode.CustomDocument, webviewPanel?: vscode.WebviewPanel) {
|
||||
if (document.uri === undefined || !document.uri.fsPath.toLocaleLowerCase().endsWith('.pdf')) {
|
||||
return
|
||||
}
|
||||
if (webviewPanel) {
|
||||
webviewPanel.webview.options = {
|
||||
...webviewPanel.webview.options,
|
||||
enableScripts: true
|
||||
}
|
||||
void lw.viewer.openPdfInPanel(document.uri, webviewPanel)
|
||||
} else {
|
||||
void lw.viewer.openPdfInTab(document.uri, 'current', false)
|
||||
|
22
src/main.ts
22
src/main.ts
@ -11,6 +11,7 @@ import { FoldingProvider, WeaveFoldingProvider } from './providers/folding'
|
||||
import { SelectionRangeProvider } from './providers/selection'
|
||||
import { BibtexFormatter, BibtexFormatterProvider } from './providers/bibtexformatter'
|
||||
import { getLogger } from './components/logger'
|
||||
import { DocumentChanged } from './components/eventbus'
|
||||
|
||||
const logger = getLogger('')
|
||||
|
||||
@ -46,6 +47,7 @@ export function activate(extensionContext: vscode.ExtensionContext) {
|
||||
|
||||
let updateCompleter: NodeJS.Timeout
|
||||
lw.registerDisposable(vscode.workspace.onDidChangeTextDocument((e: vscode.TextDocumentChangeEvent) => {
|
||||
lw.eventBus.fire(DocumentChanged)
|
||||
if (lw.lwfs.isVirtualUri(e.document.uri)){
|
||||
return
|
||||
}
|
||||
@ -64,7 +66,7 @@ export function activate(extensionContext: vscode.ExtensionContext) {
|
||||
updateCompleter = setTimeout(async () => {
|
||||
const file = e.document.uri.fsPath
|
||||
// await lw.manager.parseFileAndSubs(file, lw.manager.rootFile)
|
||||
await lw.cacher.refreshContext(file, lw.manager.rootFile)
|
||||
await lw.cacher.refreshCache(file, lw.manager.rootFile)
|
||||
await lw.cacher.loadFlsFile(lw.manager.rootFile ? lw.manager.rootFile : file)
|
||||
}, configuration.get('intellisense.update.delay', 1000))
|
||||
}
|
||||
@ -120,7 +122,7 @@ function registerLatexWorkshopCommands() {
|
||||
vscode.commands.registerCommand('latex-workshop.viewExternal', () => lw.commander.view('external')),
|
||||
vscode.commands.registerCommand('latex-workshop.kill', () => lw.commander.kill()),
|
||||
vscode.commands.registerCommand('latex-workshop.synctex', () => lw.commander.synctex()),
|
||||
vscode.commands.registerCommand('latex-workshop.texdoc', (pkg: string | undefined) => lw.commander.texdoc(pkg)),
|
||||
vscode.commands.registerCommand('latex-workshop.texdoc', (packageName: string | undefined) => lw.commander.texdoc(packageName)),
|
||||
vscode.commands.registerCommand('latex-workshop.texdocUsepackages', () => lw.commander.texdocUsepackages()),
|
||||
vscode.commands.registerCommand('latex-workshop.synctexto', (line: number, filePath: string) => lw.commander.synctexonref(line, filePath)),
|
||||
vscode.commands.registerCommand('latex-workshop.clean', () => lw.commander.clean()),
|
||||
@ -172,9 +174,9 @@ function registerLatexWorkshopCommands() {
|
||||
vscode.commands.registerCommand('latex-workshop.demote-sectioning', () => lw.commander.shiftSectioningLevel('demote')),
|
||||
vscode.commands.registerCommand('latex-workshop.select-section', () => lw.commander.selectSection()),
|
||||
|
||||
vscode.commands.registerCommand('latex-workshop.bibsort', () => BibtexFormatter.bibtexFormat(true, false)),
|
||||
vscode.commands.registerCommand('latex-workshop.bibalign', () => BibtexFormatter.bibtexFormat(false, true)),
|
||||
vscode.commands.registerCommand('latex-workshop.bibalignsort', () => BibtexFormatter.bibtexFormat(true, true)),
|
||||
vscode.commands.registerCommand('latex-workshop.bibsort', () => BibtexFormatter.instance.bibtexFormat(true, false)),
|
||||
vscode.commands.registerCommand('latex-workshop.bibalign', () => BibtexFormatter.instance.bibtexFormat(false, true)),
|
||||
vscode.commands.registerCommand('latex-workshop.bibalignsort', () => BibtexFormatter.instance.bibtexFormat(true, true)),
|
||||
|
||||
vscode.commands.registerCommand('latex-workshop.openMathPreviewPanel', () => lw.commander.openMathPreviewPanel()),
|
||||
vscode.commands.registerCommand('latex-workshop.closeMathPreviewPanel', () => lw.commander.closeMathPreviewPanel()),
|
||||
@ -189,14 +191,12 @@ function registerProviders() {
|
||||
const weaveSelector = selectDocumentsWithId(['pweave', 'jlweave', 'rsweave'])
|
||||
const latexDoctexSelector = selectDocumentsWithId(['latex', 'latex-expl3', 'pweave', 'jlweave', 'rsweave', 'doctex'])
|
||||
const bibtexSelector = selectDocumentsWithId(['bibtex'])
|
||||
const latexFormatter = new LatexFormatterProvider()
|
||||
const bibtexFormatter = new BibtexFormatterProvider()
|
||||
|
||||
lw.registerDisposable(
|
||||
vscode.languages.registerDocumentFormattingEditProvider(latexSelector, latexFormatter),
|
||||
vscode.languages.registerDocumentFormattingEditProvider({ scheme: 'file', language: 'bibtex'}, bibtexFormatter),
|
||||
vscode.languages.registerDocumentRangeFormattingEditProvider(latexSelector, latexFormatter),
|
||||
vscode.languages.registerDocumentRangeFormattingEditProvider({ scheme: 'file', language: 'bibtex'}, bibtexFormatter)
|
||||
vscode.languages.registerDocumentFormattingEditProvider(latexSelector, LatexFormatterProvider.instance),
|
||||
vscode.languages.registerDocumentFormattingEditProvider({ scheme: 'file', language: 'bibtex'}, BibtexFormatterProvider.instance),
|
||||
vscode.languages.registerDocumentRangeFormattingEditProvider(latexSelector, LatexFormatterProvider.instance),
|
||||
vscode.languages.registerDocumentRangeFormattingEditProvider({ scheme: 'file', language: 'bibtex'}, BibtexFormatterProvider.instance)
|
||||
)
|
||||
|
||||
lw.registerDisposable(
|
||||
|
@ -91,8 +91,8 @@ export class BibtexCompleter implements vscode.CompletionItemProvider {
|
||||
}
|
||||
entriesList.push(entry)
|
||||
})
|
||||
Object.keys(optFields).forEach(entry => {
|
||||
this.optFieldItems[entry] = this.fieldsToCompletion(entry, optFields[entry], this.bibtexFormatConfig, maxLengths)
|
||||
Object.entries(optFields).forEach(([field, item]) => {
|
||||
this.optFieldItems[field] = this.fieldsToCompletion(field, item, this.bibtexFormatConfig, maxLengths)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -9,15 +9,19 @@ import { UtensilsParser } from '../components/parser/syntax'
|
||||
const logger = getLogger('Format', 'Bib')
|
||||
|
||||
export class BibtexFormatter {
|
||||
private static duplicatesDiagnostics: vscode.DiagnosticCollection
|
||||
private static diags: vscode.Diagnostic[]
|
||||
private readonly duplicatesDiagnostics: vscode.DiagnosticCollection
|
||||
private diags: vscode.Diagnostic[]
|
||||
|
||||
static initialize() {
|
||||
BibtexFormatter.duplicatesDiagnostics = vscode.languages.createDiagnosticCollection('BibTeX')
|
||||
BibtexFormatter.diags = []
|
||||
private static _instance?: BibtexFormatter
|
||||
static get instance() {
|
||||
return this._instance || (this._instance = new BibtexFormatter())
|
||||
}
|
||||
private constructor() {
|
||||
this.duplicatesDiagnostics = vscode.languages.createDiagnosticCollection('BibTeX')
|
||||
this.diags = []
|
||||
}
|
||||
|
||||
static async bibtexFormat(sort: boolean, align: boolean) {
|
||||
async bibtexFormat(sort: boolean, align: boolean) {
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
logger.log('Exit formatting. The active textEditor is undefined.')
|
||||
return
|
||||
@ -28,9 +32,9 @@ export class BibtexFormatter {
|
||||
}
|
||||
const doc = vscode.window.activeTextEditor.document
|
||||
const t0 = performance.now() // Measure performance
|
||||
BibtexFormatter.duplicatesDiagnostics.clear()
|
||||
this.duplicatesDiagnostics.clear()
|
||||
logger.log('Start bibtex formatting on user request.')
|
||||
const edits = await BibtexFormatter.formatDocument(doc, sort, align)
|
||||
const edits = await this.formatDocument(doc, sort, align)
|
||||
if (edits.length === 0) {
|
||||
return
|
||||
}
|
||||
@ -41,7 +45,7 @@ export class BibtexFormatter {
|
||||
|
||||
void vscode.workspace.applyEdit(edit).then(success => {
|
||||
if (success) {
|
||||
BibtexFormatter.duplicatesDiagnostics.set(doc.uri, BibtexFormatter.diags)
|
||||
this.duplicatesDiagnostics.set(doc.uri, this.diags)
|
||||
const t1 = performance.now()
|
||||
logger.log(`BibTeX action successful. Took ${t1 - t0} ms.`)
|
||||
} else {
|
||||
@ -51,7 +55,7 @@ export class BibtexFormatter {
|
||||
|
||||
}
|
||||
|
||||
static async formatDocument(document: vscode.TextDocument, sort: boolean, align: boolean, range?: vscode.Range): Promise<vscode.TextEdit[]> {
|
||||
async formatDocument(document: vscode.TextDocument, sort: boolean, align: boolean, range?: vscode.Range): Promise<vscode.TextEdit[]> {
|
||||
// Get configuration
|
||||
const formatConfig = new BibtexFormatConfig(document.uri)
|
||||
const config = vscode.workspace.getConfiguration('latex-workshop', document)
|
||||
@ -65,7 +69,7 @@ export class BibtexFormatter {
|
||||
logger.log(error.message)
|
||||
void logger.showErrorMessage('Bibtex parser failed with error: ' + error.message)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
})
|
||||
if (! ast) {
|
||||
return []
|
||||
@ -101,9 +105,9 @@ export class BibtexFormatter {
|
||||
}
|
||||
|
||||
// Successively replace the text in the current location from the sorted location
|
||||
BibtexFormatter.duplicatesDiagnostics.clear()
|
||||
this.duplicatesDiagnostics.clear()
|
||||
const edits: vscode.TextEdit[] = []
|
||||
BibtexFormatter.diags = []
|
||||
this.diags = []
|
||||
let lineDelta = 0
|
||||
let text: string
|
||||
let isDuplicate: boolean
|
||||
@ -126,7 +130,7 @@ export class BibtexFormatter {
|
||||
entryLocations[i].start.line + lineDelta + (sortedEntryLocations[i].end.line - sortedEntryLocations[i].start.line) + lineOffset,
|
||||
entryLocations[i].end.character
|
||||
)
|
||||
BibtexFormatter.diags.push(new vscode.Diagnostic(
|
||||
this.diags.push(new vscode.Diagnostic(
|
||||
highlightRange,
|
||||
`Duplicate entry "${entry.internalKey}".`,
|
||||
vscode.DiagnosticSeverity.Warning
|
||||
@ -152,20 +156,21 @@ export class BibtexFormatter {
|
||||
}
|
||||
|
||||
export class BibtexFormatterProvider implements vscode.DocumentFormattingEditProvider, vscode.DocumentRangeFormattingEditProvider {
|
||||
constructor() {
|
||||
BibtexFormatter.initialize()
|
||||
private static _instance?: BibtexFormatterProvider
|
||||
static get instance() {
|
||||
return this._instance || (this._instance = new BibtexFormatterProvider())
|
||||
}
|
||||
private constructor() {}
|
||||
|
||||
public provideDocumentFormattingEdits(document: vscode.TextDocument, _options: vscode.FormattingOptions, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {
|
||||
const sort = vscode.workspace.getConfiguration('latex-workshop', document).get('bibtex-format.sort.enabled') as boolean
|
||||
logger.log('Start bibtex formatting on behalf of VSCode\'s formatter.')
|
||||
return BibtexFormatter.formatDocument(document, sort, true)
|
||||
return BibtexFormatter.instance.formatDocument(document, sort, true)
|
||||
}
|
||||
|
||||
public provideDocumentRangeFormattingEdits(document: vscode.TextDocument, range: vscode.Range, _options: vscode.FormattingOptions, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {
|
||||
const sort = vscode.workspace.getConfiguration('latex-workshop', document).get('bibtex-format.sort.enabled') as boolean
|
||||
logger.log('Start bibtex selection formatting on behalf of VSCode\'s formatter.')
|
||||
return BibtexFormatter.formatDocument(document, sort, true, range)
|
||||
return BibtexFormatter.instance.formatDocument(document, sort, true, range)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ function getBibtexFormatTab(tab: string): string | undefined {
|
||||
const nSpaces = parseInt(res[1], 10)
|
||||
return ' '.repeat(nSpaces)
|
||||
} else {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -88,42 +88,48 @@ export class BibtexUtils {
|
||||
* @param keys Array of sorting keys
|
||||
*/
|
||||
static bibtexSort(duplicates: Set<bibtexParser.Entry>, config: BibtexFormatConfig): (a: BibtexEntry, b: BibtexEntry) => number {
|
||||
const keys = config.sort
|
||||
return (a, b) => {
|
||||
let r = 0
|
||||
for (const key of keys) {
|
||||
// Select the appropriate sort function
|
||||
switch (key) {
|
||||
case 'key':
|
||||
r = BibtexUtils.bibtexSortByKey(a, b, config)
|
||||
break
|
||||
case 'year-desc':
|
||||
r = -BibtexUtils.bibtexSortByField('year', a, b, config)
|
||||
break
|
||||
case 'type':
|
||||
r = BibtexUtils.bibtexSortByType(a, b, config)
|
||||
break
|
||||
default:
|
||||
r = BibtexUtils.bibtexSortByField(key, a, b, config)
|
||||
}
|
||||
// Compare until different
|
||||
if (r !== 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (r === 0 && bibtexParser.isEntry(a)) {
|
||||
// It seems that items earlier in the list appear as the variable b here, rather than a
|
||||
duplicates.add(a)
|
||||
}
|
||||
return r
|
||||
return (a, b) => this.bibtexSortSwitch(a, b, duplicates, config)
|
||||
}
|
||||
|
||||
private static bibtexSortSwitch(a: BibtexEntry, b: BibtexEntry, duplicates: Set<bibtexParser.Entry>, config: BibtexFormatConfig): number {
|
||||
const firstEntryCompare = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b)
|
||||
if (firstEntryCompare !== 0) {
|
||||
return firstEntryCompare
|
||||
}
|
||||
const keys = config.sort
|
||||
let r = 0
|
||||
for (const key of keys) {
|
||||
// Select the appropriate sort function
|
||||
switch (key) {
|
||||
case 'key':
|
||||
r = BibtexUtils.bibtexSortByKey(a, b)
|
||||
break
|
||||
case 'year-desc':
|
||||
r = -BibtexUtils.bibtexSortByField('year', a, b, config)
|
||||
break
|
||||
case 'type':
|
||||
r = BibtexUtils.bibtexSortByType(a, b)
|
||||
break
|
||||
default:
|
||||
r = BibtexUtils.bibtexSortByField(key, a, b, config)
|
||||
}
|
||||
// Compare until different
|
||||
if (r !== 0) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (r === 0 && bibtexParser.isEntry(a)) {
|
||||
// It seems that items earlier in the list appear as the variable b here, rather than a
|
||||
duplicates.add(a)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
/**
|
||||
* If one of the entries `a` or `b` is in `firstEntries` or `stickyEntries`, return an order.
|
||||
* Otherwise, return undefined
|
||||
*/
|
||||
private static bibtexSortFirstEntries(firstEntries: string[], a: BibtexEntry, b: BibtexEntry): number | undefined {
|
||||
private static bibtexSortFirstEntries(firstEntries: string[], a: BibtexEntry, b: BibtexEntry): number {
|
||||
const aFirst = firstEntries.includes(a.entryType)
|
||||
const bFirst = firstEntries.includes(b.entryType)
|
||||
if (aFirst && !bFirst) {
|
||||
@ -133,13 +139,15 @@ export class BibtexUtils {
|
||||
} else if (aFirst && bFirst) {
|
||||
const aIndex = firstEntries.indexOf(a.entryType)
|
||||
const bIndex = firstEntries.indexOf(b.entryType)
|
||||
if (aIndex <= bIndex) {
|
||||
if (aIndex < bIndex) {
|
||||
return -1
|
||||
} else {
|
||||
} else if (aIndex > bIndex) {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
@ -147,11 +155,6 @@ export class BibtexUtils {
|
||||
* @param fieldName which field name to sort by
|
||||
*/
|
||||
private static bibtexSortByField(fieldName: string, a: BibtexEntry, b: BibtexEntry, config: BibtexFormatConfig): number {
|
||||
const firstEntriesOrder = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b)
|
||||
if (firstEntriesOrder) {
|
||||
return firstEntriesOrder
|
||||
}
|
||||
|
||||
let fieldA: string = ''
|
||||
let fieldB: string = ''
|
||||
|
||||
@ -179,8 +182,7 @@ export class BibtexUtils {
|
||||
return fieldA.localeCompare(fieldB)
|
||||
}
|
||||
|
||||
private static bibtexSortByKey(a: BibtexEntry, b: BibtexEntry, config: BibtexFormatConfig): number {
|
||||
const firstEntriesOrder = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b)
|
||||
private static bibtexSortByKey(a: BibtexEntry, b: BibtexEntry): number {
|
||||
let aKey: string | undefined = undefined
|
||||
let bKey: string | undefined = undefined
|
||||
if (bibtexParser.isEntry(a)) {
|
||||
@ -189,9 +191,6 @@ export class BibtexUtils {
|
||||
if (bibtexParser.isEntry(b)) {
|
||||
bKey = b.internalKey
|
||||
}
|
||||
if (firstEntriesOrder) {
|
||||
return firstEntriesOrder
|
||||
}
|
||||
if (!aKey && !bKey) {
|
||||
return 0
|
||||
} else if (!aKey) {
|
||||
@ -203,11 +202,7 @@ export class BibtexUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static bibtexSortByType(a: BibtexEntry, b: BibtexEntry, config: BibtexFormatConfig): number {
|
||||
const firstEntriesOrder = BibtexUtils.bibtexSortFirstEntries(config.firstEntries, a, b)
|
||||
if (firstEntriesOrder) {
|
||||
return firstEntriesOrder
|
||||
}
|
||||
private static bibtexSortByType(a: BibtexEntry, b: BibtexEntry): number {
|
||||
return a.entryType.localeCompare(b.entryType)
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,7 @@ export class AtSuggestion implements IProvider {
|
||||
private initialize(suggestions: {[key: string]: AtSuggestionItemEntry}) {
|
||||
const suggestionReplacements = vscode.workspace.getConfiguration('latex-workshop').get('intellisense.atSuggestionJSON.replace') as {[key: string]: string}
|
||||
this.suggestions.length = 0
|
||||
Object.keys(suggestionReplacements).forEach(prefix => {
|
||||
const body = suggestionReplacements[prefix]
|
||||
Object.entries(suggestionReplacements).forEach(([prefix, body]) => {
|
||||
if (body === '') {
|
||||
return
|
||||
}
|
||||
@ -45,8 +44,7 @@ export class AtSuggestion implements IProvider {
|
||||
this.suggestions.push(completionItem)
|
||||
})
|
||||
|
||||
Object.keys(suggestions).forEach(key => {
|
||||
const item = suggestions[key]
|
||||
Object.values(suggestions).forEach(item => {
|
||||
if (item.prefix in suggestionReplacements) {
|
||||
return
|
||||
}
|
||||
|
@ -181,9 +181,6 @@ export class Citation implements IProvider {
|
||||
// Only happens when rootFile is undefined
|
||||
return Array.from(this.bibEntries.keys())
|
||||
}
|
||||
if (!lw.cacher.get(file)) {
|
||||
return []
|
||||
}
|
||||
const cache = lw.cacher.get(file)
|
||||
if (cache === undefined) {
|
||||
return []
|
||||
@ -280,6 +277,7 @@ export class Citation implements IProvider {
|
||||
})
|
||||
this.bibEntries.set(fileName, newEntry)
|
||||
logger.log(`Parsed ${newEntry.length} bib entries from ${fileName} .`)
|
||||
void lw.structureViewer.computeTreeStructure()
|
||||
lw.eventBus.fire(eventbus.FileParsed, fileName)
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import * as vscode from 'vscode'
|
||||
import * as fs from 'fs'
|
||||
import {latexParser} from 'latex-utensils'
|
||||
import { latexParser } from 'latex-utensils'
|
||||
import * as lw from '../../lw'
|
||||
import type { IProvider, ICompletionItem, PkgType } from '../completion'
|
||||
import {CommandFinder, isTriggerSuggestNeeded} from './commandlib/commandfinder'
|
||||
import {CmdEnvSuggestion, splitSignatureString, filterNonLetterSuggestions, filterArgumentHint} from './completerutils'
|
||||
import {CommandSignatureDuplicationDetector, CommandNameDuplicationDetector} from './commandlib/commandfinder'
|
||||
import { CommandFinder, isTriggerSuggestNeeded } from './commandlib/commandfinder'
|
||||
import { CmdEnvSuggestion, splitSignatureString, filterNonLetterSuggestions, filterArgumentHint } from './completerutils'
|
||||
import { CommandSignatureDuplicationDetector } from './commandlib/commandfinder'
|
||||
import {SurroundCommand} from './commandlib/surround'
|
||||
import { Environment, EnvSnippetType } from './environment'
|
||||
|
||||
@ -54,31 +54,25 @@ export class Command implements IProvider {
|
||||
|
||||
initialize(environment: Environment) {
|
||||
const cmds = JSON.parse(fs.readFileSync(`${lw.extensionRoot}/data/commands.json`, {encoding: 'utf8'})) as {[key: string]: CmdType}
|
||||
Object.keys(cmds).forEach(cmd => {
|
||||
cmds[cmd].command = cmd
|
||||
cmds[cmd].snippet = cmds[cmd].snippet || cmd
|
||||
})
|
||||
const maths = (JSON.parse(fs.readFileSync(`${lw.extensionRoot}/data/packages/tex.json`, {encoding: 'utf8'})) as PkgType).cmds
|
||||
Object.keys(maths).forEach(cmd => {
|
||||
maths[cmd].command = cmd
|
||||
maths[cmd].snippet = maths[cmd].snippet || cmd
|
||||
Object.assign(maths, cmds)
|
||||
Object.entries(maths).forEach(([key, cmd]) => {
|
||||
cmd.command = key
|
||||
cmd.snippet = cmd.snippet || key
|
||||
})
|
||||
|
||||
Object.assign(maths, cmds)
|
||||
const defaultEnvs = environment.getDefaultEnvs(EnvSnippetType.AsCommand)
|
||||
|
||||
const snippetReplacements = vscode.workspace.getConfiguration('latex-workshop').get('intellisense.commandsJSON.replace') as {[key: string]: string}
|
||||
this.defaultCmds = []
|
||||
|
||||
// Initialize default commands and the ones in `tex.json`
|
||||
Object.keys(maths).forEach(key => {
|
||||
const entry = JSON.parse(JSON.stringify(maths[key])) as CmdType
|
||||
if (key in snippetReplacements) {
|
||||
const action = snippetReplacements[key]
|
||||
if (action === '') {
|
||||
return
|
||||
}
|
||||
entry.snippet = action
|
||||
Object.entries(maths).forEach(([key, cmd]) => {
|
||||
const entry = JSON.parse(JSON.stringify(cmd)) as CmdType
|
||||
if (snippetReplacements[key]) {
|
||||
entry.snippet = snippetReplacements[key]
|
||||
} else if (snippetReplacements[key] === '') {
|
||||
return
|
||||
}
|
||||
this.defaultCmds.push(this.entryCmdToCompletion(key, entry))
|
||||
})
|
||||
@ -94,12 +88,11 @@ export class Command implements IProvider {
|
||||
}
|
||||
|
||||
get defaultSymbols() {
|
||||
if (this._defaultSymbols.length === 0) {
|
||||
const symbols: { [key: string]: CmdType } = JSON.parse(fs.readFileSync(`${lw.extensionRoot}/data/unimathsymbols.json`).toString()) as DataUnimathSymbolsJsonType
|
||||
Object.keys(symbols).forEach(key => {
|
||||
this._defaultSymbols.push(this.entryCmdToCompletion(key, symbols[key]))
|
||||
})
|
||||
if (this._defaultSymbols.length > 0) {
|
||||
return this._defaultSymbols
|
||||
}
|
||||
const symbols: { [key: string]: CmdType } = JSON.parse(fs.readFileSync(`${lw.extensionRoot}/data/unimathsymbols.json`).toString()) as DataUnimathSymbolsJsonType
|
||||
Object.entries(symbols).forEach(([key, symbol]) => this._defaultSymbols.push(this.entryCmdToCompletion(key, symbol)))
|
||||
return this._defaultSymbols
|
||||
}
|
||||
|
||||
@ -153,23 +146,23 @@ export class Command implements IProvider {
|
||||
// Insert commands from packages
|
||||
if ((configuration.get('intellisense.package.enabled'))) {
|
||||
const packages = lw.completer.package.getPackagesIncluded(languageId)
|
||||
Object.keys(packages).forEach(packageName => {
|
||||
this.provideCmdInPkg(packageName, packages[packageName], suggestions, cmdDuplicationDetector)
|
||||
lw.completer.environment.provideEnvsAsCommandInPkg(packageName, packages[packageName], suggestions, cmdDuplicationDetector)
|
||||
Object.entries(packages).forEach(([packageName, options]) => {
|
||||
this.provideCmdInPkg(packageName, options, suggestions, cmdDuplicationDetector)
|
||||
lw.completer.environment.provideEnvsAsCommandInPkg(packageName, options, suggestions, cmdDuplicationDetector)
|
||||
})
|
||||
}
|
||||
|
||||
// Start working on commands in tex. To avoid over populating suggestions, we do not include
|
||||
// user defined commands, whose name matches a default command or one provided by a package
|
||||
const commandNameDuplicationDetector = new CommandNameDuplicationDetector(suggestions)
|
||||
const commandSignatureDuplicationDetector = new CommandSignatureDuplicationDetector(suggestions)
|
||||
lw.cacher.getIncludedTeX().forEach(tex => {
|
||||
const cmds = lw.cacher.get(tex)?.elements.command
|
||||
if (cmds !== undefined) {
|
||||
cmds.forEach(cmd => {
|
||||
if (!commandNameDuplicationDetector.has(cmd)) {
|
||||
if (!commandSignatureDuplicationDetector.has(cmd)) {
|
||||
cmd.range = range
|
||||
suggestions.push(cmd)
|
||||
commandNameDuplicationDetector.add(cmd)
|
||||
commandSignatureDuplicationDetector.add(cmd)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -216,7 +209,7 @@ export class Command implements IProvider {
|
||||
return
|
||||
}
|
||||
if (nodes !== undefined) {
|
||||
cache.elements.command = CommandFinder.getCmdFromNodeArray(file, nodes, new CommandNameDuplicationDetector())
|
||||
cache.elements.command = CommandFinder.getCmdFromNodeArray(file, nodes, new CommandSignatureDuplicationDetector())
|
||||
} else if (content !== undefined) {
|
||||
cache.elements.command = CommandFinder.getCmdFromContent(file, content)
|
||||
}
|
||||
@ -264,13 +257,13 @@ export class Command implements IProvider {
|
||||
|
||||
setPackageCmds(packageName: string, cmds: {[key: string]: CmdType}) {
|
||||
const commands: CmdEnvSuggestion[] = []
|
||||
Object.keys(cmds).forEach(key => {
|
||||
cmds[key].package = packageName
|
||||
if (isCmdWithSnippet(cmds[key])) {
|
||||
commands.push(this.entryCmdToCompletion(key, cmds[key]))
|
||||
Object.entries(cmds).forEach(([key, cmd]) => {
|
||||
cmd.package = packageName
|
||||
if (isCmdWithSnippet(cmd)) {
|
||||
commands.push(this.entryCmdToCompletion(key, cmd))
|
||||
} else {
|
||||
logger.log(`Cannot parse intellisense file for ${packageName}.`)
|
||||
logger.log(`Missing field in entry: "${key}": ${JSON.stringify(cmds[key])}.`)
|
||||
logger.log(`Missing field in entry: "${key}": ${JSON.stringify(cmd)}.`)
|
||||
}
|
||||
})
|
||||
this.packageCmds.set(packageName, commands)
|
||||
|
@ -11,108 +11,127 @@ export function isTriggerSuggestNeeded(name: string): boolean {
|
||||
return reg.test(name)
|
||||
}
|
||||
|
||||
export function resolvePkgFile(name: string, dataDir: string): string | undefined {
|
||||
export function resolvePkgFile(packageName: string, dataDir: string): string | undefined {
|
||||
const dirs = vscode.workspace.getConfiguration('latex-workshop').get('intellisense.package.dirs') as string[]
|
||||
dirs.push(dataDir)
|
||||
for (const dir of dirs) {
|
||||
const f = `${dir}/${name}`
|
||||
const f = `${dir}/${packageName}`
|
||||
if (fs.existsSync(f)) {
|
||||
return f
|
||||
}
|
||||
}
|
||||
// Many package with names like toppackage-config.sty are just wrappers around
|
||||
// the general package toppacke.sty and do not define commands on their own.
|
||||
const indexDash = name.lastIndexOf('-')
|
||||
const indexDash = packageName.lastIndexOf('-')
|
||||
if (indexDash > - 1) {
|
||||
const generalPkg = name.substring(0, indexDash)
|
||||
const generalPkg = packageName.substring(0, indexDash)
|
||||
const f = `${dataDir}/${generalPkg}.json`
|
||||
if (fs.existsSync(f)) {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
export class CommandFinder {
|
||||
static definedCmds = new Map<string, {file: string, location: vscode.Location}>()
|
||||
|
||||
static getCmdFromNodeArray(file: string, nodes: latexParser.Node[], commandNameDuplicationDetector: CommandNameDuplicationDetector): CmdEnvSuggestion[] {
|
||||
static getCmdFromNodeArray(file: string, nodes: latexParser.Node[], commandSignatureDuplicationDetector: CommandSignatureDuplicationDetector): CmdEnvSuggestion[] {
|
||||
let cmds: CmdEnvSuggestion[] = []
|
||||
nodes.forEach(node => {
|
||||
cmds = cmds.concat(CommandFinder.getCmdFromNode(file, node, commandNameDuplicationDetector))
|
||||
nodes.forEach((node, index) => {
|
||||
const prev = nodes[index - 1]
|
||||
const next = nodes[index + 1]
|
||||
cmds = cmds.concat(CommandFinder.getCmdFromNode(file, node, commandSignatureDuplicationDetector, latexParser.isCommand(prev) ? prev : undefined, latexParser.isCommand(next) ? next : undefined))
|
||||
})
|
||||
return cmds
|
||||
}
|
||||
|
||||
private static getCmdFromNode(file: string, node: latexParser.Node, commandNameDuplicationDetector: CommandNameDuplicationDetector): CmdEnvSuggestion[] {
|
||||
private static getCmdFromNode(file: string, node: latexParser.Node, commandSignatureDuplicationDetector: CommandSignatureDuplicationDetector, prev?: latexParser.Command, next?: latexParser.Command): CmdEnvSuggestion[] {
|
||||
const cmds: CmdEnvSuggestion[] = []
|
||||
const newCommandDeclarations = ['newcommand', 'renewcommand', 'providecommand', 'DeclareMathOperator', 'DeclarePairedDelimiter', 'DeclarePairedDelimiterX', 'DeclarePairedDelimiterXPP']
|
||||
if (latexParser.isDefCommand(node)) {
|
||||
const name = node.token.slice(1)
|
||||
if (!commandNameDuplicationDetector.has(name)) {
|
||||
const cmd = new CmdEnvSuggestion(`\\${name}`, '', [], -1, {name, args: CommandFinder.getArgsFromNode(node)}, vscode.CompletionItemKind.Function)
|
||||
cmd.documentation = '`' + name + '`'
|
||||
cmd.insertText = new vscode.SnippetString(name + CommandFinder.getTabStopsFromNode(node))
|
||||
cmd.filterText = name
|
||||
if (isTriggerSuggestNeeded(name)) {
|
||||
cmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
const name = node.token.slice(1)
|
||||
const args = CommandFinder.getArgsFromNode(node)
|
||||
const cmd = new CmdEnvSuggestion(`\\${name}${args}`, '', [], -1, {name, args}, vscode.CompletionItemKind.Function)
|
||||
cmd.documentation = '`' + name + '`'
|
||||
cmd.insertText = new vscode.SnippetString(name + CommandFinder.getTabStopsFromNode(node))
|
||||
cmd.filterText = name
|
||||
if (isTriggerSuggestNeeded(name)) {
|
||||
cmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
if (!commandSignatureDuplicationDetector.has(cmd)) {
|
||||
cmds.push(cmd)
|
||||
commandNameDuplicationDetector.add(name)
|
||||
commandSignatureDuplicationDetector.add(cmd)
|
||||
}
|
||||
} else if (latexParser.isCommand(node)) {
|
||||
if (!commandNameDuplicationDetector.has(node.name)) {
|
||||
const cmd = new CmdEnvSuggestion(`\\${node.name}`,
|
||||
CommandFinder.whichPackageProvidesCommand(node.name),
|
||||
[],
|
||||
-1,
|
||||
{ name: node.name, args: CommandFinder.getArgsFromNode(node) },
|
||||
vscode.CompletionItemKind.Function
|
||||
)
|
||||
|
||||
cmd.documentation = '`' + node.name + '`'
|
||||
cmd.insertText = new vscode.SnippetString(node.name + CommandFinder.getTabStopsFromNode(node))
|
||||
if (isTriggerSuggestNeeded(node.name)) {
|
||||
cmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
cmds.push(cmd)
|
||||
commandNameDuplicationDetector.add(node.name)
|
||||
if (latexParser.isCommand(prev) && newCommandDeclarations.includes(prev.name) && prev.args.length === 0) {
|
||||
return cmds
|
||||
}
|
||||
const args = CommandFinder.getArgsFromNode(node)
|
||||
const cmd = new CmdEnvSuggestion(`\\${node.name}${args}`,
|
||||
CommandFinder.whichPackageProvidesCommand(node.name),
|
||||
[],
|
||||
-1,
|
||||
{ name: node.name, args },
|
||||
vscode.CompletionItemKind.Function
|
||||
)
|
||||
cmd.documentation = '`' + node.name + '`'
|
||||
cmd.insertText = new vscode.SnippetString(node.name + CommandFinder.getTabStopsFromNode(node))
|
||||
if (isTriggerSuggestNeeded(node.name)) {
|
||||
cmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
if (!commandSignatureDuplicationDetector.has(cmd) && !newCommandDeclarations.includes(node.name)) {
|
||||
cmds.push(cmd)
|
||||
commandSignatureDuplicationDetector.add(cmd)
|
||||
}
|
||||
const newCommandDeclarations = ['newcommand', 'renewcommand', 'providecommand', 'DeclareMathOperator', 'DeclarePairedDelimiter', 'DeclarePairedDelimiterX', 'DeclarePairedDelimiterXPP']
|
||||
if (newCommandDeclarations.includes(node.name.replace(/\*$/, '')) &&
|
||||
Array.isArray(node.args) && node.args.length > 0 &&
|
||||
latexParser.isGroup(node.args[0]) && node.args[0].content.length > 0 &&
|
||||
latexParser.isCommand(node.args[0].content[0])) {
|
||||
const label = (node.args[0].content[0] as latexParser.Command).name
|
||||
(node.args.length > 0 &&
|
||||
latexParser.isGroup(node.args[0]) && node.args[0].content.length > 0 &&
|
||||
latexParser.isCommand(node.args[0].content[0])) ||
|
||||
(next && next.args.length > 0)) {
|
||||
const isInsideNewCommand = node.args.length > 0
|
||||
const label = ((isInsideNewCommand ? node.args[0].content[0] : next) as latexParser.Command).name
|
||||
let tabStops = ''
|
||||
let args = ''
|
||||
if (latexParser.isOptionalArg(node.args[1])) {
|
||||
const numArgs = parseInt((node.args[1].content[0] as latexParser.TextString).content)
|
||||
for (let i = 1; i <= numArgs; ++i) {
|
||||
tabStops += '{${' + i + '}}'
|
||||
args += '{}'
|
||||
let newargs = ''
|
||||
const argsNode = isInsideNewCommand ? node.args : next?.args || []
|
||||
const argNumNode = isInsideNewCommand ? argsNode[1] : argsNode[0]
|
||||
if (latexParser.isOptionalArg(argNumNode)) {
|
||||
const numArgs = parseInt((argNumNode.content[0] as latexParser.TextString).content)
|
||||
let index = 1
|
||||
for (let i = (isInsideNewCommand ? 2 : 1); i <= argsNode.length - 1; ++i) {
|
||||
if (!latexParser.isOptionalArg(argsNode[i])) {
|
||||
break
|
||||
}
|
||||
tabStops += '[${' + index + '}]'
|
||||
newargs += '[]'
|
||||
index++
|
||||
}
|
||||
for (; index <= numArgs; ++index) {
|
||||
tabStops += '{${' + index + '}}'
|
||||
newargs += '{}'
|
||||
}
|
||||
}
|
||||
if (!commandNameDuplicationDetector.has(label)) {
|
||||
const cmd = new CmdEnvSuggestion(`\\${label}`, 'user-defined', [], -1, {name: label, args}, vscode.CompletionItemKind.Function)
|
||||
cmd.documentation = '`' + label + '`'
|
||||
cmd.insertText = new vscode.SnippetString(label + tabStops)
|
||||
cmd.filterText = label
|
||||
if (isTriggerSuggestNeeded(label)) {
|
||||
cmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
cmds.push(cmd)
|
||||
CommandFinder.definedCmds.set(label, {
|
||||
const newcmd = new CmdEnvSuggestion(`\\${label}${newargs}`, 'user-defined', [], -1, {name: label, args: newargs}, vscode.CompletionItemKind.Function)
|
||||
newcmd.documentation = '`' + label + '`'
|
||||
newcmd.insertText = new vscode.SnippetString(label + tabStops)
|
||||
newcmd.filterText = label
|
||||
if (isTriggerSuggestNeeded(label)) {
|
||||
newcmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
if (!commandSignatureDuplicationDetector.has(newcmd)) {
|
||||
cmds.push(newcmd)
|
||||
CommandFinder.definedCmds.set(cmd.signatureAsString(), {
|
||||
file,
|
||||
location: new vscode.Location(
|
||||
vscode.Uri.file(file),
|
||||
new vscode.Position(node.location.start.line - 1, node.location.start.column))
|
||||
})
|
||||
commandNameDuplicationDetector.add(label)
|
||||
commandSignatureDuplicationDetector.add(newcmd)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (latexParser.hasContentArray(node)) {
|
||||
return cmds.concat(CommandFinder.getCmdFromNodeArray(file, node.content, commandNameDuplicationDetector))
|
||||
return cmds.concat(CommandFinder.getCmdFromNodeArray(file, node.content, commandSignatureDuplicationDetector))
|
||||
}
|
||||
return cmds
|
||||
}
|
||||
@ -158,7 +177,7 @@ export class CommandFinder {
|
||||
static getCmdFromContent(file: string, content: string): CmdEnvSuggestion[] {
|
||||
const cmdReg = /\\([a-zA-Z@_]+(?::[a-zA-Z]*)?\*?)({[^{}]*})?({[^{}]*})?({[^{}]*})?/g
|
||||
const cmds: CmdEnvSuggestion[] = []
|
||||
const commandNameDuplicationDetector = new CommandNameDuplicationDetector()
|
||||
const commandSignatureDuplicationDetector = new CommandSignatureDuplicationDetector()
|
||||
let explSyntaxOn: boolean = false
|
||||
while (true) {
|
||||
const result = cmdReg.exec(content)
|
||||
@ -180,15 +199,13 @@ export class CommandFinder {
|
||||
result[1] = result[1].slice(0, len)
|
||||
}
|
||||
}
|
||||
if (commandNameDuplicationDetector.has(result[1])) {
|
||||
continue
|
||||
}
|
||||
const args = CommandFinder.getArgsFromRegResult(result)
|
||||
const cmd = new CmdEnvSuggestion(
|
||||
`\\${result[1]}`,
|
||||
`\\${result[1]}${args}`,
|
||||
CommandFinder.whichPackageProvidesCommand(result[1]),
|
||||
[],
|
||||
-1,
|
||||
{ name: result[1], args: CommandFinder.getArgsFromRegResult(result) },
|
||||
{ name: result[1], args },
|
||||
vscode.CompletionItemKind.Function
|
||||
)
|
||||
cmd.documentation = '`' + result[1] + '`'
|
||||
@ -197,8 +214,10 @@ export class CommandFinder {
|
||||
if (isTriggerSuggestNeeded(result[1])) {
|
||||
cmd.command = { title: 'Post-Action', command: 'editor.action.triggerSuggest' }
|
||||
}
|
||||
cmds.push(cmd)
|
||||
commandNameDuplicationDetector.add(result[1])
|
||||
if (!commandSignatureDuplicationDetector.has(cmd)) {
|
||||
cmds.push(cmd)
|
||||
commandSignatureDuplicationDetector.add(cmd)
|
||||
}
|
||||
}
|
||||
|
||||
const newCommandReg = /\\(?:(?:(?:re|provide)?(?:new)?command)|(?:DeclarePairedDelimiter(?:X|XPP)?)|DeclareMathOperator)\*?{?\\(\w+)}?(?:\[([1-9])\])?/g
|
||||
@ -207,9 +226,6 @@ export class CommandFinder {
|
||||
if (result === null) {
|
||||
break
|
||||
}
|
||||
if (commandNameDuplicationDetector.has(result[1])) {
|
||||
continue
|
||||
}
|
||||
|
||||
let tabStops = ''
|
||||
let args = ''
|
||||
@ -221,12 +237,14 @@ export class CommandFinder {
|
||||
}
|
||||
}
|
||||
|
||||
const cmd = new CmdEnvSuggestion(`\\${result[1]}`, 'user-defined', [], -1, {name: result[1], args}, vscode.CompletionItemKind.Function)
|
||||
const cmd = new CmdEnvSuggestion(`\\${result[1]}${args}`, 'user-defined', [], -1, {name: result[1], args}, vscode.CompletionItemKind.Function)
|
||||
cmd.documentation = '`' + result[1] + '`'
|
||||
cmd.insertText = new vscode.SnippetString(result[1] + tabStops)
|
||||
cmd.filterText = result[1]
|
||||
cmds.push(cmd)
|
||||
commandNameDuplicationDetector.add(result[1])
|
||||
if (!commandSignatureDuplicationDetector.has(cmd)) {
|
||||
cmds.push(cmd)
|
||||
commandSignatureDuplicationDetector.add(cmd)
|
||||
}
|
||||
|
||||
CommandFinder.definedCmds.set(result[1], {
|
||||
file,
|
||||
@ -295,6 +313,10 @@ export class CommandFinder {
|
||||
export class CommandSignatureDuplicationDetector {
|
||||
private readonly cmdSignatureList: Set<string> = new Set<string>()
|
||||
|
||||
constructor(suggestions: CmdEnvSuggestion[] = []) {
|
||||
this.cmdSignatureList = new Set<string>(suggestions.map(s => s.signatureAsString()))
|
||||
}
|
||||
|
||||
add(cmd: CmdEnvSuggestion) {
|
||||
this.cmdSignatureList.add(cmd.signatureAsString())
|
||||
}
|
||||
@ -303,37 +325,3 @@ export class CommandSignatureDuplicationDetector {
|
||||
return this.cmdSignatureList.has(cmd.signatureAsString())
|
||||
}
|
||||
}
|
||||
|
||||
export class CommandNameDuplicationDetector {
|
||||
private readonly cmdSignatureList: Set<string> = new Set<string>()
|
||||
|
||||
constructor(suggestions: CmdEnvSuggestion[] = []) {
|
||||
this.cmdSignatureList = new Set<string>(suggestions.map(s => s.name()))
|
||||
}
|
||||
|
||||
add(cmd: CmdEnvSuggestion): void
|
||||
add(cmdName: string): void
|
||||
add(cmd: any): void {
|
||||
if (cmd instanceof CmdEnvSuggestion) {
|
||||
this.cmdSignatureList.add(cmd.name())
|
||||
} else if (typeof(cmd) === 'string') {
|
||||
this.cmdSignatureList.add(cmd)
|
||||
} else {
|
||||
throw new Error('Unaccepted argument type')
|
||||
}
|
||||
}
|
||||
|
||||
has(cmd: CmdEnvSuggestion): boolean
|
||||
has(cmd: string): boolean
|
||||
has(cmd: any): boolean {
|
||||
if (cmd instanceof CmdEnvSuggestion) {
|
||||
return this.cmdSignatureList.has(cmd.name())
|
||||
} else if (typeof(cmd) === 'string') {
|
||||
return this.cmdSignatureList.has(cmd)
|
||||
} else {
|
||||
throw new Error('Unaccepted argument type')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,10 +32,10 @@ export class CmdEnvSuggestion extends vscode.CompletionItem implements ICompleti
|
||||
signature: CmdSignature
|
||||
option?: string
|
||||
|
||||
constructor(label: string, pkg: string, keyvals: string[], keyvalpos: number, signature: CmdSignature, kind: vscode.CompletionItemKind, option?: string) {
|
||||
constructor(label: string, packageName: string, keyvals: string[], keyvalpos: number, signature: CmdSignature, kind: vscode.CompletionItemKind, option?: string) {
|
||||
super(label, kind)
|
||||
this.label = label
|
||||
this.package = pkg
|
||||
this.package = packageName
|
||||
this.keyvals = keyvals
|
||||
this.keyvalpos = keyvalpos
|
||||
this.signature = signature
|
||||
@ -84,7 +84,7 @@ export function computeFilteringRange(document: vscode.TextDocument, position: v
|
||||
if (startPos >= 0) {
|
||||
return new vscode.Range(position.line, startPos + 1, position.line, position.character)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
export function filterArgumentHint(suggestions: vscode.CompletionItem[]) {
|
||||
|
@ -15,8 +15,7 @@ export class DocumentClass implements IProvider {
|
||||
private readonly suggestions: vscode.CompletionItem[] = []
|
||||
|
||||
initialize(classes: {[key: string]: ClassItemEntry}) {
|
||||
Object.keys(classes).forEach(key => {
|
||||
const item = classes[key]
|
||||
Object.values(classes).forEach(item => {
|
||||
const cl = new vscode.CompletionItem(item.command, vscode.CompletionItemKind.Module)
|
||||
cl.detail = item.detail
|
||||
cl.documentation = new vscode.MarkdownString(`[${item.documentation}](${item.documentation})`)
|
||||
|
@ -39,18 +39,18 @@ export class Environment implements IProvider {
|
||||
|
||||
initialize() {
|
||||
const envs = JSON.parse(fs.readFileSync(`${lw.extensionRoot}/data/environments.json`, {encoding: 'utf8'})) as {[key: string]: EnvType}
|
||||
Object.keys(envs).forEach(key => {
|
||||
envs[key].name = envs[key].name || key
|
||||
envs[key].snippet = envs[key].snippet || ''
|
||||
envs[key].detail = key
|
||||
Object.entries(envs).forEach(([key, env]) => {
|
||||
env.name = env.name || key
|
||||
env.snippet = env.snippet || ''
|
||||
env.detail = key
|
||||
})
|
||||
this.defaultEnvsAsCommand = []
|
||||
this.defaultEnvsForBegin = []
|
||||
this.defaultEnvsAsName = []
|
||||
Object.keys(envs).forEach(key => {
|
||||
this.defaultEnvsAsCommand.push(this.entryEnvToCompletion(key, envs[key], EnvSnippetType.AsCommand))
|
||||
this.defaultEnvsForBegin.push(this.entryEnvToCompletion(key, envs[key], EnvSnippetType.ForBegin))
|
||||
this.defaultEnvsAsName.push(this.entryEnvToCompletion(key, envs[key], EnvSnippetType.AsName))
|
||||
Object.entries(envs).forEach(([key, env]) => {
|
||||
this.defaultEnvsAsCommand.push(this.entryEnvToCompletion(key, env, EnvSnippetType.AsCommand))
|
||||
this.defaultEnvsForBegin.push(this.entryEnvToCompletion(key, env, EnvSnippetType.ForBegin))
|
||||
this.defaultEnvsAsName.push(this.entryEnvToCompletion(key, env, EnvSnippetType.AsName))
|
||||
})
|
||||
|
||||
return this
|
||||
@ -116,9 +116,9 @@ export class Environment implements IProvider {
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop')
|
||||
if (configuration.get('intellisense.package.enabled')) {
|
||||
const packages = lw.completer.package.getPackagesIncluded(args.document.languageId)
|
||||
Object.keys(packages).forEach(packageName => {
|
||||
Object.entries(packages).forEach(([packageName, options]) => {
|
||||
this.getEnvFromPkg(packageName, snippetType).forEach(env => {
|
||||
if (env.option && packages[packageName] && !packages[packageName].includes(env.option)) {
|
||||
if (env.option && options && !options.includes(env.option)) {
|
||||
return
|
||||
}
|
||||
if (!envList.includes(env.label)) {
|
||||
@ -156,7 +156,7 @@ export class Environment implements IProvider {
|
||||
* Environments can be inserted using `\envname`.
|
||||
* This function is called by Command.provide to compute these commands for every package in use.
|
||||
*/
|
||||
provideEnvsAsCommandInPkg(pkg: string, options: string[], suggestions: vscode.CompletionItem[], cmdDuplicationDetector: CommandSignatureDuplicationDetector) {
|
||||
provideEnvsAsCommandInPkg(packageName: string, options: string[], suggestions: vscode.CompletionItem[], cmdDuplicationDetector: CommandSignatureDuplicationDetector) {
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop')
|
||||
const useOptionalArgsEntries = configuration.get('intellisense.optionalArgsEntries.enabled')
|
||||
|
||||
@ -165,7 +165,7 @@ export class Environment implements IProvider {
|
||||
}
|
||||
|
||||
// Load environments from the package if not already done
|
||||
const entry = this.getEnvFromPkg(pkg, EnvSnippetType.AsCommand)
|
||||
const entry = this.getEnvFromPkg(packageName, EnvSnippetType.AsCommand)
|
||||
// No environment defined in package
|
||||
if (!entry || entry.length === 0) {
|
||||
return
|
||||
@ -234,16 +234,16 @@ export class Environment implements IProvider {
|
||||
return envs
|
||||
}
|
||||
|
||||
getEnvFromPkg(pkg: string, type: EnvSnippetType): CmdEnvSuggestion[] {
|
||||
getEnvFromPkg(packageName: string, type: EnvSnippetType): CmdEnvSuggestion[] {
|
||||
const packageEnvs = this.getPackageEnvs(type)
|
||||
const entry = packageEnvs.get(pkg)
|
||||
const entry = packageEnvs.get(packageName)
|
||||
if (entry !== undefined) {
|
||||
return entry
|
||||
}
|
||||
|
||||
lw.completer.loadPackageData(pkg)
|
||||
lw.completer.loadPackageData(packageName)
|
||||
// No package command defined
|
||||
const pkgEnvs = this.packageEnvs.get(pkg)
|
||||
const pkgEnvs = this.packageEnvs.get(packageName)
|
||||
if (!pkgEnvs || pkgEnvs.length === 0) {
|
||||
return []
|
||||
}
|
||||
@ -252,7 +252,7 @@ export class Environment implements IProvider {
|
||||
pkgEnvs.forEach(env => {
|
||||
newEntry.push(this.entryEnvToCompletion(env.name, env, type))
|
||||
})
|
||||
packageEnvs.set(pkg, newEntry)
|
||||
packageEnvs.set(packageName, newEntry)
|
||||
return newEntry
|
||||
}
|
||||
|
||||
@ -280,13 +280,13 @@ export class Environment implements IProvider {
|
||||
|
||||
setPackageEnvs(packageName: string, envs: {[key: string]: EnvType}) {
|
||||
const environments: EnvType[] = []
|
||||
Object.keys(envs).forEach(key => {
|
||||
envs[key].package = packageName
|
||||
if (isEnv(envs[key])) {
|
||||
environments.push(envs[key])
|
||||
Object.entries(envs).forEach(([key, env]) => {
|
||||
env.package = packageName
|
||||
if (isEnv(env)) {
|
||||
environments.push(env)
|
||||
} else {
|
||||
logger.log(`Cannot parse intellisense file for ${packageName}`)
|
||||
logger.log(`Missing field in entry: "${key}": ${JSON.stringify(envs[key])}`)
|
||||
logger.log(`Missing field in entry: "${key}": ${JSON.stringify(env)}`)
|
||||
delete envs[key]
|
||||
}
|
||||
})
|
||||
|
@ -18,8 +18,7 @@ export class Package implements IProvider {
|
||||
private readonly packageOptions: {[packageName: string]: string[]} = {}
|
||||
|
||||
initialize(defaultPackages: {[key: string]: PackageItemEntry}) {
|
||||
Object.keys(defaultPackages).forEach(key => {
|
||||
const item = defaultPackages[key]
|
||||
Object.values(defaultPackages).forEach(item => {
|
||||
const pack = new vscode.CompletionItem(item.command, vscode.CompletionItemKind.Module)
|
||||
pack.detail = item.detail
|
||||
pack.documentation = new vscode.MarkdownString(`[${item.documentation}](${item.documentation})`)
|
||||
@ -72,17 +71,17 @@ export class Package implements IProvider {
|
||||
if (included === undefined) {
|
||||
return
|
||||
}
|
||||
Object.keys(included).forEach(packageName => packages[packageName] = included[packageName])
|
||||
Object.entries(included).forEach(([packageName, options]) => packages[packageName] = options)
|
||||
})
|
||||
|
||||
while (true) {
|
||||
let newPackageInserted = false
|
||||
Object.keys(packages).forEach(packageName => Object.keys(this.getPackageDeps(packageName)).forEach(dependName => {
|
||||
const dependOptions = this.getPackageDeps(packageName)[dependName]
|
||||
Object.entries(packages).forEach(([packageName, options]) => Object.keys(this.getPackageDeps(packageName)).forEach(includeName => {
|
||||
const dependOptions = this.getPackageDeps(packageName)[includeName]
|
||||
const hasOption = dependOptions.length === 0
|
||||
|| packages[packageName].filter(option => dependOptions.includes(option)).length > 0
|
||||
if (packages[dependName] === undefined && hasOption) {
|
||||
packages[dependName] = []
|
||||
|| options.filter(option => dependOptions.includes(option)).length > 0
|
||||
if (packages[includeName] === undefined && hasOption) {
|
||||
packages[includeName] = []
|
||||
newPackageInserted = true
|
||||
}
|
||||
}))
|
||||
@ -115,7 +114,7 @@ export class Package implements IProvider {
|
||||
break
|
||||
}
|
||||
const packages = result[2].split(',').map(packageName => packageName.trim())
|
||||
const options = (result[1] || '[]').slice(1,-1).replaceAll(/\s*=\s*/g,'=').split(',').map(option => option.trim())
|
||||
const options = (result[1] || '[]').slice(1,-1).replace(/\s*=\s*/g,'=').split(',').map(option => option.trim())
|
||||
const optionsNoTrue = options.filter(option => option.includes('=true')).map(option => option.replace('=true', ''))
|
||||
packages.forEach(packageName => this.pushUsepackage(file, packageName, [...options, ...optionsNoTrue]))
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import { Reference } from './completer/reference'
|
||||
import { Package } from './completer/package'
|
||||
import { Input, Import, SubImport } from './completer/input'
|
||||
import { Glossary } from './completer/glossary'
|
||||
import type {ReferenceDocType } from './completer/reference'
|
||||
import type { ReferenceDocType } from './completer/reference'
|
||||
import { escapeRegExp } from '../utils/utils'
|
||||
import { resolvePkgFile } from './completer/commandlib/commandfinder'
|
||||
import { getLogger } from '../components/logger'
|
||||
@ -99,22 +99,16 @@ export class Completer implements vscode.CompletionItemProvider {
|
||||
}
|
||||
|
||||
private populatePackageData(packageData: PkgType) {
|
||||
Object.keys(packageData.cmds).forEach(cmd => {
|
||||
packageData.cmds[cmd].command = cmd
|
||||
packageData.cmds[cmd].snippet = packageData.cmds[cmd].snippet || cmd
|
||||
const keyvalindex = packageData.cmds[cmd].keyvalindex
|
||||
if (keyvalindex !== undefined) {
|
||||
packageData.cmds[cmd].keyvals = packageData.keyvals[keyvalindex]
|
||||
}
|
||||
Object.entries(packageData.cmds).forEach(([key, cmd]) => {
|
||||
cmd.command = key
|
||||
cmd.snippet = cmd.snippet || key
|
||||
cmd.keyvals = packageData.keyvals[cmd.keyvalindex ?? -1]
|
||||
})
|
||||
Object.keys(packageData.envs).forEach(env => {
|
||||
packageData.envs[env].detail = env
|
||||
packageData.envs[env].name = packageData.envs[env].name || env
|
||||
packageData.envs[env].snippet = packageData.envs[env].snippet || ''
|
||||
const keyvalindex = packageData.envs[env].keyvalindex
|
||||
if (keyvalindex !== undefined) {
|
||||
packageData.envs[env].keyvals = packageData.keyvals[keyvalindex]
|
||||
}
|
||||
Object.entries(packageData.envs).forEach(([key, env]) => {
|
||||
env.detail = key
|
||||
env.name = env.name || key
|
||||
env.snippet = env.snippet || ''
|
||||
env.keyvals = packageData.keyvals[env.keyvalindex ?? -1]
|
||||
})
|
||||
}
|
||||
|
||||
@ -250,7 +244,7 @@ export class Completer implements vscode.CompletionItemProvider {
|
||||
return []
|
||||
}
|
||||
if (type === 'argument') {
|
||||
line = line.replaceAll(/(?<!\\begin){[^[\]{}]*}/g, '').replaceAll(/\[[^[\]{}]*\]/g, '')
|
||||
line = line.replace(/(?<!\\begin){[^[\]{}]*}/g, '').replace(/\[[^[\]{}]*\]/g, '')
|
||||
}
|
||||
const result = line.match(reg)
|
||||
let suggestions: vscode.CompletionItem[] = []
|
||||
|
@ -14,7 +14,7 @@ export class DefinitionProvider implements vscode.DefinitionProvider {
|
||||
const regexDocumentclass = new RegExp(`\\\\(?:documentclass)(?:\\[[^[]]*\\])?\\{${escapedToken}\\}`)
|
||||
|
||||
if (! vscode.window.activeTextEditor) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
if (line.match(regexDocumentclass)) {
|
||||
@ -37,7 +37,7 @@ export class DefinitionProvider implements vscode.DefinitionProvider {
|
||||
if (dirs.length > 0) {
|
||||
return utils.resolveFile(dirs, token, '.tex')
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
provideDefinition(document: vscode.TextDocument, position: vscode.Position): vscode.Location | undefined {
|
||||
@ -54,7 +54,7 @@ export class DefinitionProvider implements vscode.DefinitionProvider {
|
||||
if (command) {
|
||||
return command.location
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const ref = lw.completer.reference.getRef(token)
|
||||
if (ref) {
|
||||
|
@ -24,19 +24,19 @@ export class HoverProvider implements vscode.HoverProvider {
|
||||
}
|
||||
const token = tokenizer(document, position)
|
||||
if (!token) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
// Test if we are on a command
|
||||
if (token.startsWith('\\')) {
|
||||
if (!hovCommand) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
return this.provideHoverOnCommand(token)
|
||||
}
|
||||
if (onAPackage(document, position, token)) {
|
||||
const pkg = encodeURIComponent(JSON.stringify(token))
|
||||
const packageName = encodeURIComponent(JSON.stringify(token))
|
||||
const md = `Package **${token}** \n\n`
|
||||
const mdLink = new vscode.MarkdownString(`[View documentation](command:latex-workshop.texdoc?${pkg})`)
|
||||
const mdLink = new vscode.MarkdownString(`[View documentation](command:latex-workshop.texdoc?${packageName})`)
|
||||
mdLink.isTrusted = true
|
||||
const ctanUrl = `https://ctan.org/pkg/${token}`
|
||||
const ctanLink = new vscode.MarkdownString(`[${ctanUrl}](${ctanUrl})`)
|
||||
@ -55,12 +55,12 @@ export class HoverProvider implements vscode.HoverProvider {
|
||||
return new vscode.Hover(md, range)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private provideHoverOnCommand(token: string): vscode.Hover | undefined {
|
||||
const signatures: string[] = []
|
||||
const pkgs: string[] = []
|
||||
const packageNames: string[] = []
|
||||
const tokenWithoutSlash = token.substring(1)
|
||||
|
||||
lw.cacher.getIncludedTeX().forEach(cachedFile => {
|
||||
@ -76,8 +76,8 @@ export class HoverProvider implements vscode.HoverProvider {
|
||||
}
|
||||
const doc = cmd.documentation
|
||||
const packageName = cmd.package
|
||||
if (packageName && packageName !== 'user-defined' && (!pkgs.includes(packageName))) {
|
||||
pkgs.push(packageName)
|
||||
if (packageName && packageName !== 'user-defined' && (!packageNames.includes(packageName))) {
|
||||
packageNames.push(packageName)
|
||||
}
|
||||
signatures.push(doc)
|
||||
}
|
||||
@ -85,11 +85,11 @@ export class HoverProvider implements vscode.HoverProvider {
|
||||
})
|
||||
|
||||
let pkgLink = ''
|
||||
if (pkgs.length > 0) {
|
||||
if (packageNames.length > 0) {
|
||||
pkgLink = '\n\nView documentation for package(s) '
|
||||
pkgs.forEach(p => {
|
||||
const pkg = encodeURIComponent(JSON.stringify(p))
|
||||
pkgLink += `[${p}](command:latex-workshop.texdoc?${pkg}),`
|
||||
packageNames.forEach(p => {
|
||||
const packageName = encodeURIComponent(JSON.stringify(p))
|
||||
pkgLink += `[${p}](command:latex-workshop.texdoc?${packageName}),`
|
||||
})
|
||||
pkgLink = pkgLink.substring(0, pkgLink.lastIndexOf(',')) + '.'
|
||||
}
|
||||
@ -99,6 +99,6 @@ export class HoverProvider implements vscode.HoverProvider {
|
||||
mdLink.isTrusted = true
|
||||
return new vscode.Hover(mdLink)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -27,90 +27,94 @@ const windows: OperatingSystem = new OperatingSystem('win32', '.exe', 'where')
|
||||
const linux: OperatingSystem = new OperatingSystem('linux', '.pl', 'which')
|
||||
const mac: OperatingSystem = new OperatingSystem('darwin', '.pl', 'which')
|
||||
|
||||
export class LaTeXFormatter {
|
||||
private static currentOs?: OperatingSystem
|
||||
private static formatter: string = ''
|
||||
private static formatterArgs: string[] = []
|
||||
private static formatting: boolean = false
|
||||
class LaTeXFormatter {
|
||||
private readonly currentOs?: OperatingSystem
|
||||
private formatter: string = ''
|
||||
private formatterArgs: string[] = []
|
||||
private formatting: boolean = false
|
||||
|
||||
static initialize() {
|
||||
private static _instance?: LaTeXFormatter
|
||||
static get instance() {
|
||||
return this._instance || (this._instance = new LaTeXFormatter())
|
||||
}
|
||||
private constructor() {
|
||||
const machineOs = os.platform()
|
||||
if (machineOs === windows.name) {
|
||||
LaTeXFormatter.currentOs = windows
|
||||
this.currentOs = windows
|
||||
} else if (machineOs === linux.name) {
|
||||
LaTeXFormatter.currentOs = linux
|
||||
this.currentOs = linux
|
||||
} else if (machineOs === mac.name) {
|
||||
LaTeXFormatter.currentOs = mac
|
||||
this.currentOs = mac
|
||||
} else {
|
||||
logger.log('LaTexFormatter: Unsupported OS')
|
||||
}
|
||||
|
||||
lw.registerDisposable(vscode.workspace.onDidChangeConfiguration((e: vscode.ConfigurationChangeEvent) => {
|
||||
if (e.affectsConfiguration('latex-workshop.latexindent.path')) {
|
||||
LaTeXFormatter.formatter = ''
|
||||
this.formatter = ''
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
static async formatDocument(document: vscode.TextDocument, range?: vscode.Range): Promise<vscode.TextEdit[]> {
|
||||
if (LaTeXFormatter.formatting) {
|
||||
async formatDocument(document: vscode.TextDocument, range?: vscode.Range): Promise<vscode.TextEdit[]> {
|
||||
if (this.formatting) {
|
||||
logger.log('Formatting in progress. Aborted.')
|
||||
}
|
||||
LaTeXFormatter.formatting = true
|
||||
this.formatting = true
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop', document.uri)
|
||||
const pathMeta = configuration.get('latexindent.path') as string
|
||||
LaTeXFormatter.formatterArgs = configuration.get('latexindent.args') as string[]
|
||||
this.formatterArgs = configuration.get('latexindent.args') as string[]
|
||||
logger.log('Start formatting with latexindent.')
|
||||
try {
|
||||
if (LaTeXFormatter.formatter === '') {
|
||||
LaTeXFormatter.formatter = pathMeta
|
||||
const latexindentPresent = await LaTeXFormatter.checkPath()
|
||||
if (this.formatter === '') {
|
||||
this.formatter = pathMeta
|
||||
const latexindentPresent = await this.checkPath()
|
||||
if (!latexindentPresent) {
|
||||
LaTeXFormatter.formatter = ''
|
||||
logger.log(`Can not find ${LaTeXFormatter.formatter} in PATH: ${process.env.PATH}`)
|
||||
this.formatter = ''
|
||||
logger.log(`Can not find ${this.formatter} in PATH: ${process.env.PATH}`)
|
||||
void logger.showErrorMessage('Can not find latexindent in PATH.')
|
||||
return []
|
||||
}
|
||||
}
|
||||
const edit = await LaTeXFormatter.format(document, range)
|
||||
const edit = await this.format(document, range)
|
||||
return edit
|
||||
} finally {
|
||||
LaTeXFormatter.formatting = false
|
||||
this.formatting = false
|
||||
}
|
||||
}
|
||||
|
||||
private static checkPath(): Thenable<boolean> {
|
||||
private checkPath(): Thenable<boolean> {
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop')
|
||||
const useDocker = configuration.get('docker.enabled') as boolean
|
||||
if (useDocker) {
|
||||
logger.log('Use Docker to invoke the command.')
|
||||
if (process.platform === 'win32') {
|
||||
LaTeXFormatter.formatter = path.resolve(lw.extensionRoot, './scripts/latexindent.bat')
|
||||
this.formatter = path.resolve(lw.extensionRoot, './scripts/latexindent.bat')
|
||||
} else {
|
||||
LaTeXFormatter.formatter = path.resolve(lw.extensionRoot, './scripts/latexindent')
|
||||
fs.chmodSync(LaTeXFormatter.formatter, 0o755)
|
||||
this.formatter = path.resolve(lw.extensionRoot, './scripts/latexindent')
|
||||
fs.chmodSync(this.formatter, 0o755)
|
||||
}
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
|
||||
if (path.isAbsolute(LaTeXFormatter.formatter)) {
|
||||
if (fs.existsSync(LaTeXFormatter.formatter)) {
|
||||
if (path.isAbsolute(this.formatter)) {
|
||||
if (fs.existsSync(this.formatter)) {
|
||||
return Promise.resolve(true)
|
||||
} else {
|
||||
logger.log(`The path of latexindent is absolute and not found: ${LaTeXFormatter.formatter}`)
|
||||
logger.log(`The path of latexindent is absolute and not found: ${this.formatter}`)
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!LaTeXFormatter.currentOs) {
|
||||
if (!this.currentOs) {
|
||||
logger.log('The current platform is undefined.')
|
||||
return Promise.resolve(false)
|
||||
}
|
||||
const checker = LaTeXFormatter.currentOs.checker
|
||||
const fileExt = LaTeXFormatter.currentOs.fileExt
|
||||
const checker = this.currentOs.checker
|
||||
const fileExt = this.currentOs.fileExt
|
||||
|
||||
const checkFormatter = (resolve: (value: boolean) => void, isFirstTry: boolean = true) => {
|
||||
const check = cs.spawn(checker, [LaTeXFormatter.formatter])
|
||||
const check = cs.spawn(checker, [this.formatter])
|
||||
let stdout: string = ''
|
||||
let stderr: string = ''
|
||||
check.stdout.setEncoding('utf8')
|
||||
@ -120,8 +124,8 @@ export class LaTeXFormatter {
|
||||
check.on('close', code => {
|
||||
if (code && isFirstTry) {
|
||||
logger.log(`Error when checking latexindent: ${stderr}`)
|
||||
LaTeXFormatter.formatter += fileExt
|
||||
logger.log(`Checking latexindent: ${checker} ${LaTeXFormatter.formatter}`)
|
||||
this.formatter += fileExt
|
||||
logger.log(`Checking latexindent: ${checker} ${this.formatter}`)
|
||||
checkFormatter(resolve, false)
|
||||
} else if (code) {
|
||||
logger.log(`Error when checking latexindent: ${stderr}`)
|
||||
@ -134,12 +138,12 @@ export class LaTeXFormatter {
|
||||
}
|
||||
|
||||
return new Promise((resolve, _) => {
|
||||
logger.log(`Checking latexindent: ${checker} ${LaTeXFormatter.formatter}`)
|
||||
logger.log(`Checking latexindent: ${checker} ${this.formatter}`)
|
||||
checkFormatter(resolve)
|
||||
})
|
||||
}
|
||||
|
||||
private static format(document: vscode.TextDocument, range?: vscode.Range): Thenable<vscode.TextEdit[]> {
|
||||
private format(document: vscode.TextDocument, range?: vscode.Range): Thenable<vscode.TextEdit[]> {
|
||||
return new Promise((resolve, _reject) => {
|
||||
const configuration = vscode.workspace.getConfiguration('latex-workshop')
|
||||
const useDocker = configuration.get('docker.enabled') as boolean
|
||||
@ -172,14 +176,14 @@ export class LaTeXFormatter {
|
||||
|
||||
// generate command line arguments
|
||||
const rootFile = lw.manager.rootFile || document.fileName
|
||||
const args = LaTeXFormatter.formatterArgs.map(arg => { return replaceArgumentPlaceholders(rootFile, lw.manager.tmpDir)(arg)
|
||||
// latexformatter.ts specific tokens
|
||||
const args = this.formatterArgs.map(arg => { return replaceArgumentPlaceholders(rootFile, lw.manager.tmpDir)(arg)
|
||||
// this.ts specific tokens
|
||||
.replace(/%TMPFILE%/g, useDocker ? path.basename(temporaryFile) : temporaryFile.split(path.sep).join('/'))
|
||||
.replace(/%INDENT%/g, indent)
|
||||
})
|
||||
|
||||
logger.logCommand('Formatting LaTeX.', LaTeXFormatter.formatter, args)
|
||||
const worker = cs.spawn(LaTeXFormatter.formatter, args, { stdio: 'pipe', cwd: documentDirectory })
|
||||
logger.logCommand('Formatting LaTeX.', this.formatter, args)
|
||||
const worker = cs.spawn(this.formatter, args, { stdio: 'pipe', cwd: documentDirectory })
|
||||
// handle stdout/stderr
|
||||
const stdoutBuffer: string[] = []
|
||||
const stderrBuffer: string[] = []
|
||||
@ -214,16 +218,18 @@ export class LaTeXFormatter {
|
||||
}
|
||||
|
||||
export class LatexFormatterProvider implements vscode.DocumentFormattingEditProvider, vscode.DocumentRangeFormattingEditProvider {
|
||||
constructor() {
|
||||
LaTeXFormatter.initialize()
|
||||
private static _instance?: LatexFormatterProvider
|
||||
static get instance() {
|
||||
return this._instance || (this._instance = new LatexFormatterProvider())
|
||||
}
|
||||
private constructor() {}
|
||||
|
||||
public provideDocumentFormattingEdits(document: vscode.TextDocument, _options: vscode.FormattingOptions, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {
|
||||
return LaTeXFormatter.formatDocument(document)
|
||||
return LaTeXFormatter.instance.formatDocument(document)
|
||||
}
|
||||
|
||||
public provideDocumentRangeFormattingEdits(document: vscode.TextDocument, range: vscode.Range, _options: vscode.FormattingOptions, _token: vscode.CancellationToken): vscode.ProviderResult<vscode.TextEdit[]> {
|
||||
return LaTeXFormatter.formatDocument(document, range)
|
||||
return LaTeXFormatter.instance.formatDocument(document, range)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -11,18 +11,18 @@ export class GraphicsPreview {
|
||||
const pat = /\\includegraphics\s*(?:\[(.*?)\])?\s*\{(.*?)\}/
|
||||
const range = document.getWordRangeAtPosition(position, pat)
|
||||
if (!range) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const cmdString = document.getText(range)
|
||||
const execArray = pat.exec(cmdString)
|
||||
const relPath = execArray && execArray[2]
|
||||
const includeGraphicsArgs = execArray && execArray[1]
|
||||
if (!execArray || !relPath) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const filePath = this.findFilePath(relPath, document)
|
||||
if (filePath === undefined) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
let pageNumber = 1
|
||||
if (includeGraphicsArgs) {
|
||||
@ -35,7 +35,7 @@ export class GraphicsPreview {
|
||||
if (md !== undefined) {
|
||||
return new vscode.Hover(md, range)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
async renderGraphicsAsMarkdownString(filePath: string, opts: { height: number, width: number, pageNumber?: number }): Promise<vscode.MarkdownString | undefined> {
|
||||
@ -90,12 +90,12 @@ export class GraphicsPreview {
|
||||
dataUrl = await lw.snippetView.renderPdf(vscode.Uri.file(pdfFilePath), newOpts)
|
||||
if (dataUrl && dataUrl.length >= maxDataUrlLength) {
|
||||
logger.log(`Data URL still too large: ${pdfFilePath}`)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
return dataUrl
|
||||
} catch (e: unknown) {
|
||||
logger.logError(`Failed rendering graphics as data url with ${pdfFilePath}`, e)
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@ export class GraphicsPreview {
|
||||
if (fs.existsSync(relPath)) {
|
||||
return relPath
|
||||
} else {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,13 +123,13 @@ export class GraphicsPreview {
|
||||
|
||||
const rootDir = lw.manager.rootDir
|
||||
if (rootDir === undefined) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const frPath = path.resolve(rootDir, relPath)
|
||||
if (fs.existsSync(frPath)) {
|
||||
return frPath
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ export class MathPreview {
|
||||
const refMessage = `numbered ${refNum} at last compilation`
|
||||
return refMessage
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
async generateSVG(tex: TexMathEnv, newCommandsArg?: string) {
|
||||
|
@ -67,11 +67,7 @@ export class NewCommandFinder {
|
||||
logger.log('Timeout error when parsing preambles in findProjectNewCommand.')
|
||||
throw new Error('Timeout Error in findProjectNewCommand')
|
||||
}
|
||||
const cache = lw.cacher.get(tex)
|
||||
if (cache === undefined) {
|
||||
continue
|
||||
}
|
||||
const content = lw.cacher.get(tex).content
|
||||
const content = lw.cacher.get(tex)?.content
|
||||
if (content === undefined) {
|
||||
continue
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ export class TeXMathEnvFinder {
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
static findMathEnvIncludingPosition(document: ITextDocumentLike, position: vscode.Position): TexMathEnv | undefined {
|
||||
@ -100,7 +100,7 @@ export class TeXMathEnvFinder {
|
||||
}
|
||||
lineNum += 1
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
// \begin{...} \end{...}
|
||||
@ -125,7 +125,7 @@ export class TeXMathEnvFinder {
|
||||
lineNum -= 1
|
||||
i += 1
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
// \begin{...} \end{...}
|
||||
@ -139,7 +139,7 @@ export class TeXMathEnvFinder {
|
||||
const range = new vscode.Range(startPos, endPos)
|
||||
return {texString: document.getText(range), range, envname}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
// \[ \]
|
||||
@ -153,7 +153,7 @@ export class TeXMathEnvFinder {
|
||||
const range = new vscode.Range(startPos, endPos)
|
||||
return {texString: document.getText(range), range, envname}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
private static findHoverOnInline(document: ITextDocumentLike, position: vscode.Position): TexMathEnv | undefined {
|
||||
@ -178,6 +178,6 @@ export class TeXMathEnvFinder {
|
||||
}
|
||||
m = s.match(regex)
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ export class TextDocumentLike implements ITextDocumentLike {
|
||||
|
||||
getWordRangeAtPosition(position: vscode.Position, regex = /(-?\d.\d\w)|([^`~!@#%^&*()\-=+[{\]}|;:'",.<>/?\s]+)/g): vscode.Range | undefined {
|
||||
if (position.line > this.lineCount) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const line = this.#lines[position.line]
|
||||
for (let i = position.character; i >= 0; i--) {
|
||||
@ -83,7 +83,7 @@ export class TextDocumentLike implements ITextDocumentLike {
|
||||
return new vscode.Range(position.line, i, position.line, i + m[0].length)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
lineAt(lineNum: number): TextLineLike
|
||||
|
@ -35,7 +35,7 @@ export class SectionNodeProvider implements vscode.TreeDataProvider<Section> {
|
||||
if (sections.length >0) {
|
||||
return sections[0].fileName
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
@ -664,7 +664,7 @@ export class SectionNodeProvider implements vscode.TreeDataProvider<Section> {
|
||||
|
||||
getParent(element?: Section): Section | undefined {
|
||||
if (lw.manager.rootFile === undefined || !element) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
return element.parent
|
||||
}
|
||||
@ -724,18 +724,6 @@ export class StructureTreeView {
|
||||
void lw.structureViewer.refreshView()
|
||||
}
|
||||
})
|
||||
|
||||
lw.eventBus.onDidFileParsed(() => {
|
||||
void this.computeTreeStructure()
|
||||
})
|
||||
|
||||
lw.eventBus.onDidChangeRootFile(() => {
|
||||
void this.computeTreeStructure()
|
||||
})
|
||||
|
||||
lw.eventBus.onDidEndFindRootFile(() => {
|
||||
void this.refreshView()
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -17,7 +17,7 @@ function commandTokenizer(document: vscode.TextDocument, position: vscode.Positi
|
||||
}
|
||||
const startResult = document.getText(new vscode.Range(new vscode.Position(position.line, 0), position)).match(startRegex)
|
||||
if (startResult === null || startResult.index === undefined || startResult.index < 0) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const firstBracket = document.getText(new vscode.Range(position, new vscode.Position(position.line, 65535))).match(/[{]/)
|
||||
if (firstBracket && firstBracket.index !== undefined && firstBracket.index > 0) {
|
||||
@ -30,7 +30,7 @@ function commandTokenizer(document: vscode.TextDocument, position: vscode.Positi
|
||||
if (wordRange) {
|
||||
return document.getText(wordRange.with(new vscode.Position(position.line, startResult.index))).trim()
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
@ -43,11 +43,11 @@ function commandTokenizer(document: vscode.TextDocument, position: vscode.Positi
|
||||
function argTokenizer(document: vscode.TextDocument, position: vscode.Position): string | undefined {
|
||||
const startResult = document.getText(new vscode.Range(new vscode.Position(position.line, 0), position)).match(/[{,[](?=[^{},[\]]*$)/)
|
||||
if (startResult === null || startResult.index === undefined || startResult.index < 0) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
const endResult = document.getText(new vscode.Range(position, new vscode.Position(position.line, 65535))).match(/[}\],]/)
|
||||
if (endResult === null || endResult.index === undefined || endResult.index < 0) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
return document.getText(new vscode.Range(
|
||||
new vscode.Position(position.line, startResult.index + 1),
|
||||
@ -76,7 +76,7 @@ export function tokenizer(document: vscode.TextDocument, position: vscode.Positi
|
||||
if (argToken) {
|
||||
return argToken
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,5 +32,5 @@ export function convertFilenameEncoding(filePath: string): string | undefined {
|
||||
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export class InputFileRegExp {
|
||||
const filePath = InputFileRegExp.parseInputFilePath(match, currentFile, rootFile)
|
||||
return filePath ? {path: filePath, match} : undefined
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
@ -62,7 +62,7 @@ export class InputFileRegExp {
|
||||
const filePath = InputFileRegExp.parseInputFilePath(match, currentFile, rootFile)
|
||||
return filePath ? {path: filePath, match} : undefined
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
@ -102,6 +102,6 @@ export class InputFileRegExp {
|
||||
return resolveFile([path.dirname(currentFile), path.dirname(rootFile), ...texDirs], match.path)
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ export function getSurroundingCommandRange(command: string, position: vscode.Pos
|
||||
return {range: new vscode.Range(start, end), arg}
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -191,7 +191,7 @@ export function getNthArgument(text: string, nth: number): CommandArgument | und
|
||||
index += offset
|
||||
const start = text.indexOf('{')
|
||||
if (start === -1) {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
text = text.slice(start)
|
||||
index += start
|
||||
@ -225,7 +225,7 @@ export function resolveFile(dirs: string[], inputFile: string, suffix: string =
|
||||
return inputFilePath
|
||||
}
|
||||
}
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -498,7 +498,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:cppcode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:cppcode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:cppcode)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -541,7 +541,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:hscode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:hscode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:hscode)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -584,7 +584,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:luacode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:luacode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:luacode)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -627,7 +627,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:jlcode|jlverbatim|jlblock|jlconcode|jlconsole|jlconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:jlcode|jlverbatim|jlblock|jlconcode|jlconsole|jlconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:jlcode|jlverbatim|jlblock|jlconcode|jlconsole|jlconverbatim)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -670,7 +670,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:juliacode|juliaverbatim|juliablock|juliaconcode|juliaconsole|juliaconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:juliacode|juliaverbatim|juliablock|juliaconcode|juliaconsole|juliaconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:juliacode|juliaverbatim|juliablock|juliaconcode|juliaconsole|juliaconverbatim)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -713,7 +713,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|python|pythonq|pythonrepl)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|python|pythonq|pythonrepl)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:sageblock|sagesilent|sageverbatim|sageexample|sagecommandline|python|pythonq|pythonrepl)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -756,7 +756,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:pycode|pyverbatim|pyblock|pyconcode|pyconsole|pyconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:pycode|pyverbatim|pyblock|pyconcode|pyconsole|pyconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:pycode|pyverbatim|pyblock|pyconcode|pyconsole|pyconverbatim)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -799,7 +799,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:pylabcode|pylabverbatim|pylabblock|pylabconcode|pylabconsole|pylabconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:pylabcode|pylabverbatim|pylabblock|pylabconcode|pylabconsole|pylabconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:pylabcode|pylabverbatim|pylabblock|pylabconcode|pylabconsole|pylabconverbatim)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -842,7 +842,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:sympycode|sympyverbatim|sympyblock|sympyconcode|sympyconsole|sympyconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:sympycode|sympyverbatim|sympyblock|sympyconcode|sympyconsole|sympyconverbatim)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:sympycode|sympyverbatim|sympyblock|sympyconcode|sympyconsole|sympyconverbatim)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -885,7 +885,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:scalacode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:scalacode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:scalacode)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -928,7 +928,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:asy|asycode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:asy|asycode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:asy|asycode)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -971,7 +971,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:dot2tex|dotcode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:dot2tex|dotcode)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:dot2tex|dotcode)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
@ -1014,7 +1014,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"begin": "\\s*\\\\begin\\{(?:gnuplot)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{)",
|
||||
"begin": "\\s*\\\\begin\\{(?:gnuplot)\\*?\\}(?:\\[[a-zA-Z0-9_-]*\\])?(?=\\[|\\{|\\s*$)",
|
||||
"end": "\\s*\\\\end\\{(?:gnuplot)\\*?\\}",
|
||||
"captures": {
|
||||
"0": {
|
||||
|
32
test/fixtures/armory/formatter/bibtex_base.bib
vendored
Normal file
32
test/fixtures/armory/formatter/bibtex_base.bib
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
@article{art1,
|
||||
title = {A fake article},
|
||||
author = {Davis, J. and Jones, M.},
|
||||
journal = {Journal of CI tests},
|
||||
year = {2022},
|
||||
description = {hintFake}
|
||||
}
|
||||
|
||||
@book{lamport1994latex,
|
||||
title = {LATEX: A Document Preparation System : User's Guide and Reference Manual},
|
||||
author = {Lamport, L. and Bibby, D. and Pearson Education},
|
||||
isbn = {9780201529838},
|
||||
lccn = {93039691},
|
||||
series = {Addison-Wesley Series on Tools},
|
||||
url = {https://books.google.ch/books?id=khVUAAAAMAAJ},
|
||||
year = {1994},
|
||||
publisher = {Addison-Wesley},
|
||||
description = {hintLaTex}
|
||||
}
|
||||
|
||||
@book{MR1241645,
|
||||
author = {Rubinstein, Reuven Y. and Shapiro, Alexander},
|
||||
title = {Discrete event systems},
|
||||
series = {Wiley Series in Probability and Mathematical Statistics:
|
||||
Probability and Mathematical Statistics},
|
||||
note = {Sensitivity analysis and stochastic optimization by the score
|
||||
function method},
|
||||
publisher = {John Wiley \& Sons Ltd.},
|
||||
address = {Chichester},
|
||||
year = 1993,
|
||||
description = {hintRubi}
|
||||
}
|
15
test/fixtures/armory/formatter/bibtex_dup.bib
vendored
Normal file
15
test/fixtures/armory/formatter/bibtex_dup.bib
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
@article{art1,
|
||||
title = {A fake article},
|
||||
author = {Davis, J. and Jones, M.},
|
||||
journal = {Journal of CI tests},
|
||||
year = {2022},
|
||||
description = {hintFake}
|
||||
}
|
||||
|
||||
@article{art1,
|
||||
title = {A fake article},
|
||||
author = {Davis, J. and Jones, M.},
|
||||
journal = {Journal of CI tests},
|
||||
year = {2022},
|
||||
description = {hintFake}
|
||||
}
|
7
test/fixtures/armory/formatter/bibtex_sortfield.bib
vendored
Normal file
7
test/fixtures/armory/formatter/bibtex_sortfield.bib
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
@article{art1,
|
||||
title = {A fake article},
|
||||
author = {Davis, J. and Jones, M.},
|
||||
journal = {Journal of CI tests},
|
||||
year = {2022},
|
||||
description = {hintFake}
|
||||
}
|
10
test/fixtures/armory/intellisense/newcommand.tex
vendored
Normal file
10
test/fixtures/armory/intellisense/newcommand.tex
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
\documentclass[10pt]{article}
|
||||
\newcommand\WARNING{\textcolor{red}{WARNING}}
|
||||
\newcommand\FIXME[1]{\textcolor{red}{FIX:}\textcolor{red}{#1}}
|
||||
\newcommand\FIXME[2][]{\textcolor{red}{FIX:}\textcolor{red}{#1}}
|
||||
\newcommand{\fix}[3][]{\chdeleted{#2}\chadded[comment={#1}]{#3}}
|
||||
\begin{document}
|
||||
\fakecommand
|
||||
\fakecommand{arg}
|
||||
\fakecommand[opt]{arg}
|
||||
\end{document}
|
@ -2,7 +2,7 @@ import * as vscode from 'vscode'
|
||||
import * as path from 'path'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, assertBuild, runTest, loadTestFile, waitEvent } from './utils'
|
||||
import * as test from './utils'
|
||||
import { BuildDone } from '../../src/components/eventbus'
|
||||
|
||||
suite('Build TeX files test suite', () => {
|
||||
@ -34,107 +34,106 @@ suite('Build TeX files test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
runTest(suiteName, fixtureName, 'build', async () => {
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
test.run(suiteName, fixtureName, 'build', async () => {
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with subfiles', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'build with subfiles', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'same placeholders multiple times', async () => {
|
||||
test.run(suiteName, fixtureName, 'same placeholders multiple times', async () => {
|
||||
const tools = [{name: 'latexmk', command: 'latexmk', args: ['-synctex=1', '-interaction=nonstopmode', '-file-line-error', '-pdf', '%DOC%', '%DOC%', '%DOC%']}]
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.tools', tools)
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect subfile root and build 1', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto-detect subfile root and build 1', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect subfile root and build 2', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto-detect subfile root and build 2', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'main.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with outDir', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with outDir', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'out/main.pdf')
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'out/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build with spaces in names', async () => {
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main space/main.tex'}])
|
||||
await assertBuild(fixture, 'main space/main.tex', 'main space/main.pdf')
|
||||
test.run(suiteName, fixtureName, 'basic build with spaces in names', async () => {
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main space/main.tex'}])
|
||||
await test.assert.build(fixture, 'main space/main.tex', 'main space/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build with spaces in outdir', async () => {
|
||||
test.run(suiteName, fixtureName, 'basic build with spaces in outdir', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', '%DIR%/out space')
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'out space/main.pdf')
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'out space/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with magic comment', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with magic comment', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.recipes', [])
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.build.forceRecipeUsage', false)
|
||||
await loadTestFile(fixture, [{src: 'magic_program.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await test.load(fixture, [{src: 'magic_program.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with !TEX program and !TEX options', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with !TEX program and !TEX options', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.recipes', [])
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.build.forceRecipeUsage', false)
|
||||
await loadTestFile(fixture, [{src: 'magic_option.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'out/main.pdf')
|
||||
await test.load(fixture, [{src: 'magic_option.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'out/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with !TEX root', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'build with !TEX root', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'input_base.tex', dst: 'main.tex'},
|
||||
{src: 'input_base.tex', dst: 'alt.tex'},
|
||||
{src: 'magic_root.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'main.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with invalid !TEX program', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with invalid !TEX program', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.build.forceRecipeUsage', false)
|
||||
await loadTestFile(fixture, [{src: 'magic_invalid.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', '')
|
||||
await test.load(fixture, [{src: 'magic_invalid.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', '')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with forceRecipeUsage: true', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with forceRecipeUsage: true', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.build.forceRecipeUsage', true)
|
||||
await loadTestFile(fixture, [{src: 'magic_invalid.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await test.load(fixture, [{src: 'magic_invalid.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build a subfile when main.tex opened', async () => {
|
||||
test.run(suiteName, fixtureName, 'build a subfile when main.tex opened', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
@ -144,75 +143,76 @@ suite('Build TeX files test suite', () => {
|
||||
const docSub = await vscode.workspace.openTextDocument(vscode.Uri.file(path.resolve(fixture, 'sub/s.tex')))
|
||||
await vscode.window.showTextDocument(docSub, vscode.ViewColumn.Beside)
|
||||
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
})
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
}, ['linux', 'darwin']) // Skip win for very high false alarm rate
|
||||
|
||||
runTest(suiteName, fixtureName, 'build main.tex with QuickPick', async () => {
|
||||
test.run(suiteName, fixtureName, 'build main.tex with QuickPick', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'main.pdf', async () => {
|
||||
const wait = waitEvent(BuildDone)
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'main.pdf', async () => {
|
||||
const event = test.wait(BuildDone)
|
||||
void vscode.commands.executeCommand('latex-workshop.build')
|
||||
await sleep(1000)
|
||||
await test.sleep(1000)
|
||||
await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem')
|
||||
await wait
|
||||
await event
|
||||
})
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build s.tex with QuickPick', async () => {
|
||||
test.run(suiteName, fixtureName, 'build s.tex with QuickPick', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/s.pdf', async () => {
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/s.pdf', async () => {
|
||||
const event = test.wait(BuildDone)
|
||||
void vscode.commands.executeCommand('latex-workshop.build')
|
||||
await sleep(1000)
|
||||
await test.sleep(1000)
|
||||
await vscode.commands.executeCommand('workbench.action.quickOpenSelectNext')
|
||||
await sleep(500)
|
||||
await test.sleep(500)
|
||||
await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem')
|
||||
await waitEvent(BuildDone)
|
||||
await event
|
||||
})
|
||||
})
|
||||
}, ['linux', 'darwin']) // Skip win for very high false alarm rate
|
||||
|
||||
runTest(suiteName, fixtureName, 'build sub.tex to outdir', async () => {
|
||||
test.run(suiteName, fixtureName, 'build sub.tex to outdir', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_subsub.tex', dst: 'sub/s.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/subsub/infile.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/out/s.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/out/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build with makeindex', async () => {
|
||||
await loadTestFile(fixture, [{src: 'makeindex_base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
test.run(suiteName, fixtureName, 'basic build with makeindex', async () => {
|
||||
await test.load(fixture, [{src: 'makeindex_base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build sub.tex to outdir with makeindex', async () => {
|
||||
test.run(suiteName, fixtureName, 'build sub.tex to outdir with makeindex', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'makeindex_subfile.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/out/s.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/out/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test q/.../ with spaces in outdir on Windows', async () => {
|
||||
test.run(suiteName, fixtureName, 'test q/.../ with spaces in outdir on Windows', async () => {
|
||||
const tools = [{ name: 'latexmk', command: 'latexmk', args: ['-e', '$pdflatex=q/pdflatex %O -synctex=1 -interaction=nonstopmode -file-line-error %S/', '-outdir=%OUTDIR%', '-pdf', '%DOC%'], env: {} }]
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.tools', tools)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', '%DIR%/out space')
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'out space/main.pdf')
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'out space/main.pdf')
|
||||
}, ['win32'])
|
||||
|
||||
runTest(suiteName, fixtureName, 'test q/.../ with copy and remove on Windows', async () => {
|
||||
test.run(suiteName, fixtureName, 'test q/.../ with copy and remove on Windows', async () => {
|
||||
const tools = [
|
||||
{ name: 'latexmk', command: 'latexmk', args: ['-e', '$pdflatex=q/pdflatex %O -synctex=1 -interaction=nonstopmode -file-line-error %S/', '-outdir=%OUTDIR%', '-pdf', '%DOC%'], env: {} },
|
||||
{name: 'copyPDF', command: 'copy', args: ['%OUTDIR_W32%\\%DOCFILE%.pdf', '%OUTDIR_W32%\\copy.pdf'], env: {}},
|
||||
@ -222,8 +222,8 @@ suite('Build TeX files test suite', () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.tools', tools)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.recipes', recipes)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', '%DIR%/out space')
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'out space/copy.pdf')
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'out space/copy.pdf')
|
||||
}, ['win32'])
|
||||
|
||||
})
|
||||
|
@ -2,7 +2,7 @@ import * as vscode from 'vscode'
|
||||
import * as path from 'path'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, assertAutoBuild, assertBuild, runTest, loadTestFile, waitEvent } from './utils'
|
||||
import * as test from './utils'
|
||||
import { FileWatched } from '../../src/components/eventbus'
|
||||
|
||||
suite('Auto-build test suite', () => {
|
||||
@ -35,119 +35,119 @@ suite('Auto-build test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build', async () => {
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertAutoBuild(fixture, 'main.tex', 'main.pdf')
|
||||
test.run(suiteName, fixtureName, 'auto build', async () => {
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.auto(fixture, 'main.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with subfiles and onFileChange 1', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with subfiles and onFileChange 1', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'main.pdf')
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with subfiles and onFileChange 2', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with subfiles and onFileChange 2', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with import and onFileChange', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'auto build with import and onFileChange', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'import_base.tex', dst: 'main.tex'},
|
||||
{src: 'import_sub.tex', dst: 'sub/s.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/subsub/sss/sss.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/subsub/sss/sss.tex', 'main.pdf')
|
||||
await test.assert.auto(fixture, 'sub/subsub/sss/sss.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with input and onFileChange', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'auto build with input and onFileChange', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'input_base.tex', dst: 'main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'main.pdf')
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build when editing bib', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'auto build when editing bib', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'bibtex_base.tex', dst: 'main.tex'},
|
||||
{src: 'plain.bib', dst: 'bib.bib'}
|
||||
])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await assertAutoBuild(fixture, 'bib.bib', 'main.pdf', ['skipFirstBuild'])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
await test.assert.auto(fixture, 'bib.bib', 'main.pdf', ['skipFirstBuild'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with input whose path uses a macro', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'auto build with input whose path uses a macro', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'input_macro.tex', dst: 'main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const wait = waitEvent(FileWatched, path.resolve(fixture, 'sub/s.tex'))
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await wait
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'main.pdf', ['skipFirstBuild'])
|
||||
const event = test.wait(FileWatched, path.resolve(fixture, 'sub/s.tex'))
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
await event
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'main.pdf', ['skipFirstBuild'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build when main.tex not in root dir and editing a sub file', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'auto build when main.tex not in root dir and editing a sub file', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'input_parentsub.tex', dst: 'main/main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'main/main.tex', 'main/main.pdf')
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'main/main.pdf', ['skipFirstBuild'])
|
||||
await test.assert.build(fixture, 'main/main.tex', 'main/main.pdf')
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'main/main.pdf', ['skipFirstBuild'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with input and outDir', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with input and outDir', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'input_base.tex', dst: 'main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'out/main.pdf')
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'out/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with watch.files.ignore', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with watch.files.ignore', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.watch.files.ignore', ['**/s.tex'])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'input_base.tex', dst: 'main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'main.pdf', ['skipFirstBuild', 'noAutoBuild'])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'main.pdf', ['skipFirstBuild', 'noAutoBuild'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with subfiles and onSave 1', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with subfiles and onSave 1', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.autoBuild.run', 'onSave')
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'main.pdf', ['onSave'])
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'main.pdf', ['onSave'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with subfiles and onSave 2', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with subfiles and onSave 2', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.autoBuild.run', 'onSave')
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'sub/s.tex', 'sub/s.pdf', ['onSave'])
|
||||
await test.assert.auto(fixture, 'sub/s.tex', 'sub/s.pdf', ['onSave'])
|
||||
})
|
||||
})
|
||||
|
@ -3,7 +3,7 @@ import * as path from 'path'
|
||||
import rimraf from 'rimraf'
|
||||
import * as assert from 'assert'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, assertRoot, runTest, loadTestFile } from './utils'
|
||||
import * as test from './utils'
|
||||
|
||||
suite('Find root file test suite', () => {
|
||||
|
||||
@ -25,57 +25,57 @@ suite('Find root file test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
runTest(suiteName, fixtureName, 'detect root with search.rootFiles.include', async () => {
|
||||
test.run(suiteName, fixtureName, 'detect root with search.rootFiles.include', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.search.rootFiles.include', ['alt/*.tex'])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'input_parentsub.tex', dst: 'alt/main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertRoot(fixture, 'sub/s.tex', 'alt/main.tex')
|
||||
await test.assert.root(fixture, 'sub/s.tex', 'alt/main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'detect root with search.rootFiles.exclude', async () => {
|
||||
test.run(suiteName, fixtureName, 'detect root with search.rootFiles.exclude', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.search.rootFiles.exclude', ['*.tex'])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'input_parentsub.tex', dst: 'alt/main.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertRoot(fixture, 'sub/s.tex', 'alt/main.tex')
|
||||
await test.assert.root(fixture, 'sub/s.tex', 'alt/main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect root with verbatim', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'auto-detect root with verbatim', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'input_base.tex', dst: 'main.tex'},
|
||||
{src: 'plain_verbatim.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertRoot(fixture, 'sub/s.tex', 'main.tex')
|
||||
await test.assert.root(fixture, 'sub/s.tex', 'main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'import package', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'import package', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'import_base.tex', dst: 'main.tex'},
|
||||
{src: 'import_sub.tex', dst: 'sub/s.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/subsub/sss/sss.tex'}
|
||||
])
|
||||
await assertRoot(fixture, 'sub/subsub/sss/sss.tex', 'main.tex')
|
||||
await test.assert.root(fixture, 'sub/subsub/sss/sss.tex', 'main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'circular inclusion', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'circular inclusion', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'include_base.tex', dst: 'main.tex'},
|
||||
{src: 'include_sub.tex', dst: 'alt.tex'},
|
||||
{src: 'plain.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertRoot(fixture, 'alt.tex', 'main.tex')
|
||||
await test.assert.root(fixture, 'alt.tex', 'main.tex')
|
||||
const includedTeX = lw.cacher.getIncludedTeX()
|
||||
assert.ok(includedTeX)
|
||||
assert.ok(includedTeX.includes(path.resolve(fixture, 'main.tex')))
|
||||
|
@ -5,7 +5,7 @@ import * as assert from 'assert'
|
||||
import rimraf from 'rimraf'
|
||||
import glob from 'glob'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, getIntellisense, runTest, openActive, writeTestFile, loadTestFile, waitEvent } from './utils'
|
||||
import * as test from './utils'
|
||||
import { EnvSnippetType, EnvType } from '../../src/providers/completer/environment'
|
||||
import { CmdType } from '../../src/providers/completer/command'
|
||||
import { PkgType } from '../../src/providers/completion'
|
||||
@ -47,37 +47,37 @@ suite('Intellisense test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'check default environment .json completion file', () => {
|
||||
test.run(suiteName, fixtureName, 'check default environment .json completion file', () => {
|
||||
const file = `${lw.extensionRoot}/data/environments.json`
|
||||
const envs = JSON.parse(fs.readFileSync(file, {encoding: 'utf8'})) as {[key: string]: EnvType}
|
||||
assert.ok(Object.keys(envs).length > 0)
|
||||
Object.keys(envs).forEach(name => {
|
||||
Object.values(envs).forEach(env => {
|
||||
assertKeys(
|
||||
Object.keys(envs[name]),
|
||||
Object.keys(env),
|
||||
['name', 'snippet', 'detail'],
|
||||
file + ': ' + JSON.stringify(envs[name])
|
||||
file + ': ' + JSON.stringify(env)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'check default commands .json completion file', () => {
|
||||
test.run(suiteName, fixtureName, 'check default commands .json completion file', () => {
|
||||
const file = `${lw.extensionRoot}/data/commands.json`
|
||||
const cmds = JSON.parse(fs.readFileSync(file, {encoding: 'utf8'})) as {[key: string]: CmdType}
|
||||
assert.ok(Object.keys(cmds).length > 0)
|
||||
Object.keys(cmds).forEach(name => {
|
||||
Object.values(cmds).forEach(cmd => {
|
||||
assertKeys(
|
||||
Object.keys(cmds[name]),
|
||||
Object.keys(cmd),
|
||||
['command', 'snippet', 'documentation', 'detail', 'postAction'],
|
||||
file + ': ' + JSON.stringify(cmds[name])
|
||||
file + ': ' + JSON.stringify(cmd)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test default envs', () => {
|
||||
test.run(suiteName, fixtureName, 'test default envs', () => {
|
||||
let defaultEnvs = lw.completer.environment.getDefaultEnvs(EnvSnippetType.AsCommand).map(e => e.label)
|
||||
assert.ok(defaultEnvs.includes('document'))
|
||||
assert.ok(defaultEnvs.includes('align'))
|
||||
@ -89,53 +89,53 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(defaultEnvs.includes('align'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test default cmds', () => {
|
||||
test.run(suiteName, fixtureName, 'test default cmds', () => {
|
||||
const defaultCommands = lw.completer.command.getDefaultCmds().map(e => e.label)
|
||||
assert.ok(defaultCommands.includes('\\begin'))
|
||||
assert.ok(defaultCommands.includes('\\left('))
|
||||
assert.ok(defaultCommands.includes('\\section{}'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'check package .json completion file', () => {
|
||||
test.run(suiteName, fixtureName, 'check package .json completion file', () => {
|
||||
const files = glob.sync('data/packages/*.json', {cwd: lw.extensionRoot})
|
||||
files.forEach(file => {
|
||||
const pkg = JSON.parse(fs.readFileSync(path.join(lw.extensionRoot, file), {encoding: 'utf8'})) as PkgType
|
||||
Object.keys(pkg.cmds).forEach(name => {
|
||||
Object.values(pkg.cmds).forEach(cmd => {
|
||||
assertKeys(
|
||||
Object.keys(pkg.cmds[name]),
|
||||
Object.keys(cmd),
|
||||
['command', 'snippet', 'option', 'keyvalindex', 'keyvalpos', 'documentation', 'detail'],
|
||||
file + ': ' + JSON.stringify(pkg.cmds[name])
|
||||
file + ': ' + JSON.stringify(cmd)
|
||||
)
|
||||
})
|
||||
Object.keys(pkg.envs).forEach(name => {
|
||||
Object.values(pkg.envs).forEach(env => {
|
||||
assertKeys(
|
||||
Object.keys(pkg.envs[name]),
|
||||
Object.keys(env),
|
||||
['name', 'snippet', 'detail', 'option', 'keyvalindex', 'keyvalpos'],
|
||||
file + ': ' + JSON.stringify(pkg.envs[name])
|
||||
file + ': ' + JSON.stringify(env)
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test isTriggerSuggestNeeded', () => {
|
||||
test.run(suiteName, fixtureName, 'test isTriggerSuggestNeeded', () => {
|
||||
assert.ok(!isTriggerSuggestNeeded('frac'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'command intellisense', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'command intellisense', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
const items = getIntellisense(result.doc, new vscode.Position(0, 1))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
const items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'command intellisense with cmds provided by \\usepackage', async () => {
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_cmd_1.tex', dst: 'main.tex'}])
|
||||
let result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(0, 1))
|
||||
test.run(suiteName, fixtureName, 'command intellisense with cmds provided by \\usepackage', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_cmd_1.tex', dst: 'main.tex'}])
|
||||
let result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -144,9 +144,9 @@ suite('Intellisense test suite', () => {
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_cmd_2.tex', dst: 'main.tex'}])
|
||||
result = await openActive(fixture, 'main.tex')
|
||||
items = getIntellisense(result.doc, new vscode.Position(2, 1))
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_cmd_2.tex', dst: 'main.tex'}])
|
||||
result = await test.open(fixture, 'main.tex')
|
||||
items = test.suggest(result.doc, new vscode.Position(2, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -154,10 +154,10 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(labels.includes('\\lstinline'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'command intellisense with cmds provided by \\usepackage and its argument', async () => {
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_option_on_cmd.tex', dst: 'main.tex'}])
|
||||
let result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(2, 1))
|
||||
test.run(suiteName, fixtureName, 'command intellisense with cmds provided by \\usepackage and its argument', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/package_option_on_cmd.tex', dst: 'main.tex'}])
|
||||
let result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(2, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -166,9 +166,9 @@ suite('Intellisense test suite', () => {
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_cmd_2.tex', dst: 'main.tex'}])
|
||||
result = await openActive(fixture, 'main.tex')
|
||||
items = getIntellisense(result.doc, new vscode.Position(2, 1))
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_cmd_2.tex', dst: 'main.tex'}])
|
||||
result = await test.open(fixture, 'main.tex')
|
||||
items = test.suggest(result.doc, new vscode.Position(2, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -176,14 +176,31 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!labels.includes('\\lstformatfiles'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'command intellisense with config `intellisense.argumentHint.enabled`', async () => {
|
||||
test.run(suiteName, fixtureName, 'command intellisense with cmds defined by \\newcommand', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/newcommand.tex', dst: 'main.tex'}])
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
const items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
const labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('\\WARNING'))
|
||||
assert.ok(labels.includes('\\FIXME{}'))
|
||||
assert.ok(labels.includes('\\FIXME[]{}'))
|
||||
assert.ok(labels.includes('\\fix[]{}{}'))
|
||||
assert.ok(labels.includes('\\fakecommand'))
|
||||
assert.ok(labels.includes('\\fakecommand{}'))
|
||||
assert.ok(labels.includes('\\fakecommand[]{}'))
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'command intellisense with config `intellisense.argumentHint.enabled`', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.argumentHint.enabled', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(0, 1))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -195,10 +212,10 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(snippet.value.includes('${1:'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.argumentHint.enabled', false)
|
||||
const wait = waitEvent(FileParsed, path.resolve(fixture, 'main.tex'))
|
||||
await lw.cacher.refreshContext(path.resolve(fixture, 'main.tex'))
|
||||
await wait
|
||||
items = getIntellisense(result.doc, new vscode.Position(0, 1))
|
||||
const event = test.wait(FileParsed, path.resolve(fixture, 'main.tex'))
|
||||
await lw.cacher.refreshCache(path.resolve(fixture, 'main.tex'))
|
||||
await event
|
||||
items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -210,14 +227,14 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!snippet.value.includes('${1:'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'command intellisense with config `intellisense.commandsJSON.replace`', async () => {
|
||||
test.run(suiteName, fixtureName, 'command intellisense with config `intellisense.commandsJSON.replace`', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.commandsJSON.replace', {'mathbb{}': ''})
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(0, 1))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -225,7 +242,7 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!labels.includes('\\mathbb{}'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.commandsJSON.replace', undefined)
|
||||
items = getIntellisense(result.doc, new vscode.Position(0, 1))
|
||||
items = test.suggest(result.doc, new vscode.Position(0, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -233,14 +250,14 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(labels.includes('\\mathbb{}'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'reference intellisense and config intellisense.label.keyval', async () => {
|
||||
test.run(suiteName, fixtureName, 'reference intellisense and config intellisense.label.keyval', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.label.keyval', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(8, 5))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(8, 5))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -249,10 +266,10 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(labels.includes('eq1'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.label.keyval', false)
|
||||
const wait = waitEvent(FileParsed, path.resolve(fixture, 'main.tex'))
|
||||
await lw.cacher.refreshContext(path.resolve(fixture, 'main.tex'))
|
||||
await wait
|
||||
items = getIntellisense(result.doc, new vscode.Position(8, 5))
|
||||
const event = test.wait(FileParsed, path.resolve(fixture, 'main.tex'))
|
||||
await lw.cacher.refreshCache(path.resolve(fixture, 'main.tex'))
|
||||
await event
|
||||
items = test.suggest(result.doc, new vscode.Position(8, 5))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -261,14 +278,14 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!labels.includes('eq1'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'reference intellisense with `xr` package', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'reference intellisense with `xr` package', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/xr_base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/xr_sub.tex', dst: 'sub.tex'},
|
||||
{src: 'intellisense/xr_dup.tex', dst: 'dup.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
const items = getIntellisense(result.doc, new vscode.Position(6, 5))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
const items = test.suggest(result.doc, new vscode.Position(6, 5))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -278,21 +295,38 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(labels.includes('alt-sec:1'))
|
||||
}, undefined, undefined, true)
|
||||
|
||||
runTest(suiteName, fixtureName, 'environment intellisense', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'reference intellisense with `xr` package', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/xr_base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/xr_sub.tex', dst: 'sub.tex'},
|
||||
{src: 'intellisense/xr_dup.tex', dst: 'dup.tex'}
|
||||
])
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
const items = test.suggest(result.doc, new vscode.Position(6, 5))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
const labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('sec:1'))
|
||||
assert.ok(labels.includes('sec:2'))
|
||||
assert.ok(labels.includes('alt-sec:1'))
|
||||
}, undefined, undefined, true)
|
||||
|
||||
test.run(suiteName, fixtureName, 'environment intellisense', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
const items = getIntellisense(result.doc, new vscode.Position(9, 7))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
const items = test.suggest(result.doc, new vscode.Position(9, 7))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'environment intellisense with envs provided by \\usepackage', async () => {
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_env_1.tex', dst: 'main.tex'}])
|
||||
let result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(3, 7))
|
||||
test.run(suiteName, fixtureName, 'environment intellisense with envs provided by \\usepackage', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_env_1.tex', dst: 'main.tex'}])
|
||||
let result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(3, 7))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -301,9 +335,9 @@ suite('Intellisense test suite', () => {
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_env_2.tex', dst: 'main.tex'}])
|
||||
result = await openActive(fixture, 'main.tex')
|
||||
items = getIntellisense(result.doc, new vscode.Position(3, 7))
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_env_2.tex', dst: 'main.tex'}])
|
||||
result = await test.open(fixture, 'main.tex')
|
||||
items = test.suggest(result.doc, new vscode.Position(3, 7))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -311,10 +345,10 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(labels.includes('algorithm'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'environment intellisense with envs provided by \\usepackage and its argument', async () => {
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_option_on_env.tex', dst: 'main.tex'}])
|
||||
let result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(3, 7))
|
||||
test.run(suiteName, fixtureName, 'environment intellisense with envs provided by \\usepackage and its argument', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/package_option_on_env.tex', dst: 'main.tex'}])
|
||||
let result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(3, 7))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -323,9 +357,9 @@ suite('Intellisense test suite', () => {
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_env_2.tex', dst: 'main.tex'}])
|
||||
result = await openActive(fixture, 'main.tex')
|
||||
items = getIntellisense(result.doc, new vscode.Position(3, 7))
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_env_2.tex', dst: 'main.tex'}])
|
||||
result = await test.open(fixture, 'main.tex')
|
||||
items = test.suggest(result.doc, new vscode.Position(3, 7))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -333,10 +367,10 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!labels.includes('algorithm2e'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'environment intellisense in form of cmds with envs provided by \\usepackage and its argument', async () => {
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_option_on_env.tex', dst: 'main.tex'}])
|
||||
let result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(3, 1))
|
||||
test.run(suiteName, fixtureName, 'environment intellisense in form of cmds with envs provided by \\usepackage and its argument', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/package_option_on_env.tex', dst: 'main.tex'}])
|
||||
let result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(3, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -345,9 +379,9 @@ suite('Intellisense test suite', () => {
|
||||
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
|
||||
await loadTestFile(fixture, [{src: 'intellisense/package_on_env_2.tex', dst: 'main.tex'}])
|
||||
result = await openActive(fixture, 'main.tex')
|
||||
items = getIntellisense(result.doc, new vscode.Position(3, 1))
|
||||
await test.load(fixture, [{src: 'intellisense/package_on_env_2.tex', dst: 'main.tex'}])
|
||||
result = await test.open(fixture, 'main.tex')
|
||||
items = test.suggest(result.doc, new vscode.Position(3, 1))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
|
||||
@ -355,67 +389,67 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!labels.includes('algorithm2e'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'argument intellisense of \\documentclass, \\usepackage, commands, and environments', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'argument intellisense of \\documentclass, \\usepackage, commands, and environments', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(0, 15))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(0, 15))
|
||||
assert.ok(items)
|
||||
let labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('a4paper'))
|
||||
assert.ok(labels.includes('10pt'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(2, 12))
|
||||
items = test.suggest(result.doc, new vscode.Position(2, 12))
|
||||
assert.ok(items)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('savemem'))
|
||||
assert.ok(labels.includes('noaspects'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(13, 11))
|
||||
items = test.suggest(result.doc, new vscode.Position(13, 11))
|
||||
assert.ok(items)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('print'))
|
||||
assert.ok(labels.includes('showlines'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(14, 19))
|
||||
items = test.suggest(result.doc, new vscode.Position(14, 19))
|
||||
assert.ok(items)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('print'))
|
||||
assert.ok(labels.includes('showlines'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'argument intellisense with braces already in the argument', async () => {
|
||||
await loadTestFile(fixture, [{src: 'intellisense/class_option_with_brace.tex', dst: 'main.tex'}])
|
||||
const wait = waitEvent(FileParsed, path.resolve(fixture, 'main.tex'))
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
await wait
|
||||
let items = getIntellisense(result.doc, new vscode.Position(0, 64))
|
||||
test.run(suiteName, fixtureName, 'argument intellisense with braces already in the argument', async () => {
|
||||
await test.load(fixture, [{src: 'intellisense/class_option_with_brace.tex', dst: 'main.tex'}])
|
||||
const event = test.wait(FileParsed, path.resolve(fixture, 'main.tex'))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
await event
|
||||
let items = test.suggest(result.doc, new vscode.Position(0, 64))
|
||||
assert.ok(items)
|
||||
let labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('10pt'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(3, 32))
|
||||
items = test.suggest(result.doc, new vscode.Position(3, 32))
|
||||
assert.ok(items)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('label='))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'package and class intellisense', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'package and class intellisense', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(2, 21))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(2, 21))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
let labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('amsmath'))
|
||||
assert.ok(labels.includes('listings'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(0, 21))
|
||||
items = test.suggest(result.doc, new vscode.Position(0, 21))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
labels = items.map(item => item.label.toString())
|
||||
@ -423,41 +457,41 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(labels.includes('IEEEtran'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'input/include/import/subimport intellisense', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'input/include/import/subimport intellisense', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/plain.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(7, 7))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(7, 7))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
let labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('main.tex'))
|
||||
assert.ok(labels.includes('sub/'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(16, 13))
|
||||
items = test.suggest(result.doc, new vscode.Position(16, 13))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(labels.includes('main.tex'))
|
||||
assert.ok(labels.includes('sub/'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(17, 8))
|
||||
items = test.suggest(result.doc, new vscode.Position(17, 8))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(!labels.includes('main.tex'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(18, 11))
|
||||
items = test.suggest(result.doc, new vscode.Position(18, 11))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
labels = items.map(item => item.label.toString())
|
||||
assert.ok(!labels.includes('main.tex'))
|
||||
assert.ok(labels.includes('sub/'))
|
||||
|
||||
items = getIntellisense(result.doc, new vscode.Position(18, 17))
|
||||
items = test.suggest(result.doc, new vscode.Position(18, 17))
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
labels = items.map(item => item.label.toString())
|
||||
@ -466,15 +500,15 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!labels.includes('sub/'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'citation intellisense and configs intellisense.citation.*', async () => {
|
||||
test.run(suiteName, fixtureName, 'citation intellisense and configs intellisense.citation.*', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.citation.label', 'bibtex key')
|
||||
writeTestFile(fixture, 'main.tex', '\\documentclass{article}', '\\begin{document}', 'abc\\cite{}', '\\bibliography{main}', '\\end{document}')
|
||||
await loadTestFile(fixture, [{src: 'base.bib', dst: 'main.bib'}])
|
||||
const wait = waitEvent(FileParsed, path.resolve(fixture, 'main.bib'))
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
await wait
|
||||
test.write(fixture, 'main.tex', '\\documentclass{article}', '\\begin{document}', 'abc\\cite{}', '\\bibliography{main}', '\\end{document}')
|
||||
await test.load(fixture, [{src: 'base.bib', dst: 'main.bib'}])
|
||||
const event = test.wait(FileParsed, path.resolve(fixture, 'main.bib'))
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
await event
|
||||
|
||||
let items = getIntellisense(result.doc, new vscode.Position(2, 9))
|
||||
let items = test.suggest(result.doc, new vscode.Position(2, 9))
|
||||
assert.ok(items)
|
||||
assert.strictEqual(items.length, 3)
|
||||
assert.strictEqual(items[0].label, 'art1')
|
||||
@ -483,19 +517,19 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(!items[0].filterText.includes('hintFake'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.citation.label', 'title')
|
||||
items = getIntellisense(result.doc, new vscode.Position(2, 9))
|
||||
items = test.suggest(result.doc, new vscode.Position(2, 9))
|
||||
assert.ok(items)
|
||||
assert.strictEqual(items.length, 3)
|
||||
assert.strictEqual(items[0].label, 'A fake article')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.citation.label', 'authors')
|
||||
items = getIntellisense(result.doc, new vscode.Position(2, 9))
|
||||
items = test.suggest(result.doc, new vscode.Position(2, 9))
|
||||
assert.ok(items)
|
||||
assert.strictEqual(items.length, 3)
|
||||
assert.strictEqual(items[0].label, 'Davis, J. and Jones, M.')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.citation.format', ['title', 'year', 'description', 'nonexisting'])
|
||||
items = getIntellisense(result.doc, new vscode.Position(2, 9))
|
||||
items = test.suggest(result.doc, new vscode.Position(2, 9))
|
||||
assert.ok(items)
|
||||
assert.strictEqual(items.length, 3)
|
||||
assert.ok(items[0].filterText)
|
||||
@ -503,15 +537,15 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(items[0].filterText.includes('hintFake'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'glossary intellisense', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'glossary intellisense', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/glossary.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/glossaryentries.tex', dst: 'sub/glossary.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
await lw.cacher.refreshContext(path.resolve(fixture, 'sub/glossary.tex'), fs.readFileSync(path.resolve(fixture, 'sub/glossary.tex')).toString())
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
await lw.cacher.refreshCache(path.resolve(fixture, 'sub/glossary.tex'), fs.readFileSync(path.resolve(fixture, 'sub/glossary.tex')).toString())
|
||||
|
||||
const items = getIntellisense(result.doc, new vscode.Position(5, 5))
|
||||
const items = test.suggest(result.doc, new vscode.Position(5, 5))
|
||||
assert.ok(items)
|
||||
assert.strictEqual(items.length, 7)
|
||||
assert.ok(items.find(item => item.label === 'rf' && item.detail === 'radio-frequency'))
|
||||
@ -523,15 +557,15 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(items.find(item => item.label === 'abbr_x' && item.detail === 'A first abbreviation'))
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, '@-snippet intellisense and configs intellisense.atSuggestion*', async () => {
|
||||
test.run(suiteName, fixtureName, '@-snippet intellisense and configs intellisense.atSuggestion*', async () => {
|
||||
const replaces = {'@+': '\\sum', '@8': '', '@M': '\\sum'}
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.atSuggestionJSON.replace', replaces)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'intellisense/base.tex', dst: 'main.tex'},
|
||||
{src: 'intellisense/sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
const result = await openActive(fixture, 'main.tex')
|
||||
let items = getIntellisense(result.doc, new vscode.Position(5, 1), true)
|
||||
const result = await test.open(fixture, 'main.tex')
|
||||
let items = test.suggest(result.doc, new vscode.Position(5, 1), true)
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
assert.ok(items.find(item => item.label === '@+' && item.insertText instanceof vscode.SnippetString && item.insertText.value === '\\sum'))
|
||||
@ -540,7 +574,7 @@ suite('Intellisense test suite', () => {
|
||||
assert.ok(undefined === items.find(item => item.label === '@8'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.atSuggestion.trigger.latex', '#')
|
||||
items = getIntellisense(result.doc, new vscode.Position(6, 1), true)
|
||||
items = test.suggest(result.doc, new vscode.Position(6, 1), true)
|
||||
assert.ok(items)
|
||||
assert.ok(items.length > 0)
|
||||
assert.ok(items.find(item => item.label === '#+' && item.insertText instanceof vscode.SnippetString && item.insertText.value === '\\sum'))
|
||||
|
@ -2,7 +2,7 @@ import * as vscode from 'vscode'
|
||||
import * as path from 'path'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, assertBuild, assertViewer, runTest, loadTestFile, waitEvent } from './utils'
|
||||
import * as test from './utils'
|
||||
import { BuildDone } from '../../src/components/eventbus'
|
||||
|
||||
suite('PDF viewer test suite', () => {
|
||||
@ -32,84 +32,84 @@ suite('PDF viewer test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build and view', async () => {
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'main.pdf')
|
||||
await assertViewer(fixture, 'main.pdf')
|
||||
test.run(suiteName, fixtureName, 'basic build and view', async () => {
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'main.pdf')
|
||||
await test.assert.viewer(fixture, 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build main.tex and view it', async () => {
|
||||
test.run(suiteName, fixtureName, 'build main.tex and view it', async () => {
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'main.pdf')
|
||||
await assertViewer(fixture, 'main.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'main.pdf')
|
||||
await test.assert.viewer(fixture, 'main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build a subfile and view it', async () => {
|
||||
test.run(suiteName, fixtureName, 'build a subfile and view it', async () => {
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration().update('latex-workshop.latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
await assertViewer(fixture, 'sub/s.pdf')
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/s.pdf')
|
||||
await test.assert.viewer(fixture, 'sub/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build main.tex with QuickPick and view it', async () => {
|
||||
test.run(suiteName, fixtureName, 'build main.tex with QuickPick and view it', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'main.pdf', async () => {
|
||||
const wait = waitEvent(BuildDone)
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'main.pdf', async () => {
|
||||
const event = test.wait(BuildDone)
|
||||
void vscode.commands.executeCommand('latex-workshop.build')
|
||||
await sleep(1000)
|
||||
await test.sleep(1000)
|
||||
await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem')
|
||||
await wait
|
||||
await event
|
||||
})
|
||||
await assertViewer(fixture, 'main.pdf', async () => {
|
||||
await sleep(1000)
|
||||
await test.assert.viewer(fixture, 'main.pdf', async () => {
|
||||
await test.sleep(1000)
|
||||
await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem')
|
||||
})
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build s.tex with QuickPick and view it', async () => {
|
||||
test.run(suiteName, fixtureName, 'build s.tex with QuickPick and view it', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await assertBuild(fixture, 'sub/s.tex', 'sub/s.pdf', async () => {
|
||||
const wait = waitEvent(BuildDone)
|
||||
await test.assert.build(fixture, 'sub/s.tex', 'sub/s.pdf', async () => {
|
||||
const event = test.wait(BuildDone)
|
||||
void vscode.commands.executeCommand('latex-workshop.build')
|
||||
await sleep(1000)
|
||||
await test.sleep(1000)
|
||||
await vscode.commands.executeCommand('workbench.action.quickOpenSelectNext')
|
||||
await sleep(500)
|
||||
await test.sleep(500)
|
||||
await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem')
|
||||
await wait
|
||||
await event
|
||||
})
|
||||
await assertViewer(fixture, 'sub/s.pdf', async () => {
|
||||
await sleep(1000)
|
||||
await test.assert.viewer(fixture, 'sub/s.pdf', async () => {
|
||||
await test.sleep(1000)
|
||||
await vscode.commands.executeCommand('workbench.action.quickOpenSelectNext')
|
||||
await sleep(500)
|
||||
await test.sleep(500)
|
||||
await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem')
|
||||
})
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with outDir and view it', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with outDir and view it', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await assertBuild(fixture, 'main.tex', 'out/main.pdf')
|
||||
await assertViewer(fixture, 'out/main.pdf')
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'main.tex'}])
|
||||
await test.assert.build(fixture, 'main.tex', 'out/main.pdf')
|
||||
await test.assert.viewer(fixture, 'out/main.pdf')
|
||||
})
|
||||
})
|
||||
|
@ -3,11 +3,11 @@ import * as path from 'path'
|
||||
import * as assert from 'assert'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, runTest, openActive, loadTestFile } from './utils'
|
||||
import * as test from './utils'
|
||||
import { SectionNodeProvider } from '../../src/providers/structure'
|
||||
|
||||
async function loadTestFiles(fixture: string) {
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'structure_base.tex', dst: 'main.tex'},
|
||||
{src: 'structure_sub.tex', dst: 'sub/s.tex'},
|
||||
{src: 'structure_s2.tex', dst: 'sub/s2.tex'},
|
||||
@ -42,13 +42,13 @@ suite('Document structure test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test structure', async () => {
|
||||
test.run(suiteName, fixtureName, 'test structure', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await structure.update(true)
|
||||
const sections = structure.ds
|
||||
@ -71,9 +71,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[5].children[5].label, 'Frame 3')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test structure with nested floats', async () => {
|
||||
await loadTestFile(fixture, [{src: 'structure_nested.tex', dst: 'main.tex'}])
|
||||
await openActive(fixture, 'main.tex')
|
||||
test.run(suiteName, fixtureName, 'test structure with nested floats', async () => {
|
||||
await test.load(fixture, [{src: 'structure_nested.tex', dst: 'main.tex'}])
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await structure.update(true)
|
||||
const sections = structure.ds
|
||||
@ -83,9 +83,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[0].children[0].children.length, 1)
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test view.outline.numbers.enabled', async () => {
|
||||
test.run(suiteName, fixtureName, 'test view.outline.numbers.enabled', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('view.outline.numbers.enabled', false)
|
||||
await structure.update(true)
|
||||
@ -94,9 +94,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[1].children[0].label, '2.0.1')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test view.outline.sections', async () => {
|
||||
test.run(suiteName, fixtureName, 'test view.outline.sections', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('view.outline.sections', ['section', 'altsection', 'subsubsection'])
|
||||
await structure.update(true)
|
||||
@ -106,9 +106,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[0].children[1].label, '1.1 1.1?')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test view.outline.floats.enabled', async () => {
|
||||
test.run(suiteName, fixtureName, 'test view.outline.floats.enabled', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('view.outline.floats.enabled', false)
|
||||
await structure.update(true)
|
||||
@ -120,9 +120,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[5].children[2].label, 'Frame 3')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test view.outline.floats.number.enabled', async () => {
|
||||
test.run(suiteName, fixtureName, 'test view.outline.floats.number.enabled', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('view.outline.floats.number.enabled', false)
|
||||
await structure.update(true)
|
||||
@ -137,9 +137,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[5].children[5].label, 'Frame')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test view.outline.floats.caption.enabled', async () => {
|
||||
test.run(suiteName, fixtureName, 'test view.outline.floats.caption.enabled', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('view.outline.floats.caption.enabled', false)
|
||||
await structure.update(true)
|
||||
@ -154,9 +154,9 @@ suite('Document structure test suite', () => {
|
||||
assert.strictEqual(sections[5].children[5].label, 'Frame 3')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test view.outline.fastparse.enabled', async () => {
|
||||
test.run(suiteName, fixtureName, 'test view.outline.fastparse.enabled', async () => {
|
||||
await loadTestFiles(fixture)
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const structure = new SectionNodeProvider()
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('view.outline.fastparse.enabled', true)
|
||||
await structure.update(true)
|
||||
|
@ -3,7 +3,7 @@ import * as path from 'path'
|
||||
import * as assert from 'assert'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, runTest } from './utils'
|
||||
import * as test from './utils'
|
||||
import { TextDocumentLike } from '../../src/providers/preview/mathpreviewlib/textdocumentlike'
|
||||
import { TeXMathEnvFinder } from '../../src/providers/preview/mathpreviewlib/texmathenvfinder'
|
||||
import { CursorRenderer } from '../../src/providers/preview/mathpreviewlib/cursorrenderer'
|
||||
@ -28,11 +28,11 @@ suite('Math preview test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test insertCursor', async () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test insertCursor', async () => {
|
||||
const docString = '$a+b$'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 2)
|
||||
@ -42,7 +42,7 @@ suite('Math preview test suite', () => {
|
||||
assert.strictEqual(result, '${~a|+b~}$')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test shouldNotWriteCursor', () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test shouldNotWriteCursor', () => {
|
||||
const docString = '$a+b$'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 0)
|
||||
@ -66,7 +66,7 @@ suite('Math preview test suite', () => {
|
||||
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test \\f|rac{1}{2}', async () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test \\f|rac{1}{2}', async () => {
|
||||
const docString = '$\\frac{1}{2}$'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 3)
|
||||
@ -76,7 +76,7 @@ suite('Math preview test suite', () => {
|
||||
assert.strictEqual(result, '$\\frac{1}{2}$')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test a^|b', async () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test a^|b', async () => {
|
||||
const docString = '$a^b$'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 3)
|
||||
@ -86,7 +86,7 @@ suite('Math preview test suite', () => {
|
||||
assert.strictEqual(result, '$a^{~|b~}$')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test $a^b| $', async () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test $a^b| $', async () => {
|
||||
const docString = '$a^b $'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 4)
|
||||
@ -96,7 +96,7 @@ suite('Math preview test suite', () => {
|
||||
assert.strictEqual(result, '${~a^b|~} $')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test $a^{b} $', async () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test $a^{b} $', async () => {
|
||||
const docString = '$a^{b} $'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 5)
|
||||
@ -106,7 +106,7 @@ suite('Math preview test suite', () => {
|
||||
assert.strictEqual(result, '$a^{~b|~} $')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test a_|b', async () => {
|
||||
test.run(suiteName, fixtureName, 'mathpreviewlib/cursorrenderer: test a_|b', async () => {
|
||||
const docString = '$a_b$'
|
||||
const doc = new TextDocumentLike(docString)
|
||||
const cursorPos = new vscode.Position(0, 3)
|
||||
|
@ -3,7 +3,7 @@ import * as path from 'path'
|
||||
import * as assert from 'assert'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, runTest, openActive, loadTestFile } from './utils'
|
||||
import * as test from './utils'
|
||||
import { ChkTeX } from '../../src/components/linterlib/chktex'
|
||||
import { LaCheck } from '../../src/components/linterlib/lacheck'
|
||||
|
||||
@ -27,16 +27,16 @@ suite('Linter test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test chktex log parser', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'test chktex log parser', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'linter_base.tex', dst: 'main.tex'},
|
||||
{src: 'linter_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const linter = new ChkTeX()
|
||||
const log = 'main.tex:5:18:1:Warning:24:Delete this space to maintain correct pagereferences.\nsub/s.tex:1:26:1:Warning:24:Delete this space to maintain correct pagereferences.\n'
|
||||
linter.parseLog(log)
|
||||
@ -46,24 +46,24 @@ suite('Linter test suite', () => {
|
||||
assert.match(linter.linterDiagnostics.get(vscode.Uri.file(path.resolve(fixture, 'sub/s.tex')))?.[0].message || '', /Delete this space/)
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test lacheck', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'test lacheck', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'linter_base.tex', dst: 'main.tex'},
|
||||
{src: 'linter_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
assert.ok(lw.manager.rootFile)
|
||||
const linter = new LaCheck()
|
||||
await linter.lintRootFile(lw.manager.rootFile)
|
||||
assert.strictEqual(linter.linterDiagnostics.name, 'LaCheck')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test lacheck log parser', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
test.run(suiteName, fixtureName, 'test lacheck log parser', async () => {
|
||||
await test.load(fixture, [
|
||||
{src: 'linter_base.tex', dst: 'main.tex'},
|
||||
{src: 'linter_sub.tex', dst: 'sub/s.tex'}
|
||||
])
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.open(fixture, 'main.tex')
|
||||
const linter = new LaCheck()
|
||||
const log = '"main.tex", line 7: double space at "~~"\n** sub/sub:\n"sub/s.tex", line 2: double space at "~~"\n'
|
||||
linter.parseLog(log)
|
||||
|
@ -3,7 +3,8 @@ import * as path from 'path'
|
||||
import * as assert from 'assert'
|
||||
import rimraf from 'rimraf'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, runTest, openActive, loadTestFile } from './utils'
|
||||
import * as test from './utils'
|
||||
import { DocumentChanged } from '../../src/components/eventbus'
|
||||
|
||||
suite('Formatter test suite', () => {
|
||||
|
||||
@ -25,44 +26,287 @@ suite('Formatter test suite', () => {
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latexindent.path', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latexindent.args', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.tab', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.surround', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.case', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.trailingComma', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sortby', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.handleDuplicates', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sort.enabled', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.align-equal.enabled', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-entries.first', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.sort.enabled', undefined)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.order', undefined)
|
||||
|
||||
if (path.basename(fixture) === 'testground') {
|
||||
rimraf(fixture + '/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'test latex formatter', async () => {
|
||||
await loadTestFile(fixture, [
|
||||
{src: 'formatter/latex_base.tex', dst: 'main.tex'}
|
||||
])
|
||||
await openActive(fixture, 'main.tex')
|
||||
test.run(suiteName, fixtureName, 'test latex formatter', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/latex_base.tex', dst: 'main.tex'}])
|
||||
await test.open(fixture, 'main.tex')
|
||||
const original = vscode.window.activeTextEditor?.document.getText()
|
||||
const promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await sleep(1000)
|
||||
await promise
|
||||
const formatted = vscode.window.activeTextEditor?.document.getText()
|
||||
assert.notStrictEqual(original, formatted)
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'change latexindent.path on the fly', async () => {
|
||||
test.run(suiteName, fixtureName, 'change latexindent.path on the fly', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latexindent.path', 'echo')
|
||||
await loadTestFile(fixture, [
|
||||
{src: 'formatter/latex_base.tex', dst: 'main.tex'}
|
||||
])
|
||||
await openActive(fixture, 'main.tex')
|
||||
await test.load(fixture, [{src: 'formatter/latex_base.tex', dst: 'main.tex'}])
|
||||
await test.open(fixture, 'main.tex')
|
||||
const original = vscode.window.activeTextEditor?.document.getText()
|
||||
// echo add a new \n to the end of stdin
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latexindent.args', [original?.slice(0, -1)])
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await sleep(1000) // wait for formatter finish
|
||||
await test.sleep(250) // wait for echo finish
|
||||
const echoed = vscode.window.activeTextEditor?.document.getText()
|
||||
assert.strictEqual(original, echoed)
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latexindent.path', 'latexindent')
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latexindent.args', ['-c', '%DIR%/', '%TMPFILE%', '-y=defaultIndent: \'%INDENT%\''])
|
||||
const promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await sleep(1000) // wait for formatter finish
|
||||
await promise
|
||||
const formatted = vscode.window.activeTextEditor?.document.getText()
|
||||
assert.notStrictEqual(original, formatted)
|
||||
}, ['linux', 'darwin']) // Skip win for very high false alarm rate
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
const original = vscode.window.activeTextEditor?.document.getText()
|
||||
const promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
const formatted = vscode.window.activeTextEditor?.document.getText()
|
||||
assert.notStrictEqual(original, formatted)
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.tab`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.tab', 'tab')
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines[1].slice(0, 1), '\t')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.tab', '2 spaces')
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines[1].slice(0, 2), ' ')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.tab', '4')
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines[1].slice(0, 4), ' ')
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.surround`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.surround', 'Curly braces')
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines[1].slice(-2, -1), '}')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.surround', 'Quotation marks')
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines[1].slice(-2, -1), '"')
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.case`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.case', 'UPPERCASE')
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.ok(lines[1].trim().slice(0, 1).match(/[A-Z]/))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.case', 'lowercase')
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.ok(lines[1].trim().slice(0, 1).match(/[a-z]/))
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.trailingComma`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.trailingComma', true)
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines[5].trim().slice(-1), ',')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.trailingComma', false)
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.notStrictEqual(lines[5].trim().slice(-1), ',')
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex sorter with `bibtex-format.sortby`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sortby', ['year'])
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('latex-workshop.bibsort')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
let entries = lines.filter(line => line.includes('@'))
|
||||
assert.ok(entries[2].includes('art1'))
|
||||
assert.ok(entries[1].includes('lamport1994latex'))
|
||||
assert.ok(entries[0].includes('MR1241645'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sortby', ['year-desc'])
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('latex-workshop.bibsort')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
entries = lines.filter(line => line.includes('@'))
|
||||
assert.ok(entries[0].includes('art1'))
|
||||
assert.ok(entries[1].includes('lamport1994latex'))
|
||||
assert.ok(entries[2].includes('MR1241645'))
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex sorter with `bibtex-format.handleDuplicates`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_dup.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.handleDuplicates', 'Comment Duplicates')
|
||||
const promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('latex-workshop.bibsort')
|
||||
await promise
|
||||
const lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.strictEqual(lines.filter(line => line.includes('@')).length, 1)
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.sort.enabled`', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sortby', ['year'])
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sort.enabled', true)
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
const promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
const lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
const entries = lines.filter(line => line.includes('@'))
|
||||
assert.ok(entries[2].includes('art1'))
|
||||
assert.ok(entries[1].includes('lamport1994latex'))
|
||||
assert.ok(entries[0].includes('MR1241645'))
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex formatter with `bibtex-format.align-equal.enabled`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.align-equal.enabled', false)
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
const allEqual = (arr: number[]) => arr.every(val => val === arr[0])
|
||||
assert.ok(!allEqual(lines.filter(line => line.includes('=')).map(line => line.indexOf('='))))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.align-equal.enabled', true)
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('editor.action.formatDocument')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
assert.ok(allEqual(lines.filter(line => line.includes('=')).map(line => line.indexOf('='))))
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex sorter with `bibtex-entries.first`', async () => {
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_base.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-entries.first', ['book'])
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-format.sortby', ['key'])
|
||||
const promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('latex-workshop.bibsort')
|
||||
await promise
|
||||
const lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
const entries = lines.filter(line => line.includes('@'))
|
||||
assert.ok(entries[2].includes('art1'))
|
||||
assert.ok(entries[0].includes('lamport1994latex'))
|
||||
assert.ok(entries[1].includes('MR1241645'))
|
||||
})
|
||||
|
||||
test.run(suiteName, fixtureName, 'test bibtex aligner with `bibtex-fields.sort.enabled` and `bibtex-fields.order`', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.sort.enabled', true)
|
||||
await test.load(fixture, [{src: 'formatter/bibtex_sortfield.bib', dst: 'main.bib'}])
|
||||
await test.open(fixture, 'main.bib')
|
||||
|
||||
if (!vscode.window.activeTextEditor) {
|
||||
return
|
||||
}
|
||||
|
||||
let promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('latex-workshop.bibalign')
|
||||
await promise
|
||||
let lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
let entries = lines.filter(line => line.includes('='))
|
||||
assert.ok(entries[0].includes('author'))
|
||||
assert.ok(entries[1].includes('description'))
|
||||
assert.ok(entries[2].includes('journal'))
|
||||
assert.ok(entries[3].includes('title'))
|
||||
assert.ok(entries[4].includes('year'))
|
||||
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('bibtex-fields.order', ['title', 'author', 'year'])
|
||||
promise = test.wait(DocumentChanged)
|
||||
await vscode.commands.executeCommand('latex-workshop.bibalign')
|
||||
await promise
|
||||
lines = vscode.window.activeTextEditor?.document.getText().split('\n')
|
||||
assert.ok(lines)
|
||||
entries = lines.filter(line => line.includes('='))
|
||||
assert.ok(entries[0].includes('title'))
|
||||
assert.ok(entries[1].includes('author'))
|
||||
assert.ok(entries[2].includes('year'))
|
||||
assert.ok(entries[3].includes('description'))
|
||||
assert.ok(entries[4].includes('journal'))
|
||||
})
|
||||
})
|
||||
|
@ -3,7 +3,7 @@ import * as path from 'path'
|
||||
import rimraf from 'rimraf'
|
||||
import * as assert from 'assert'
|
||||
import * as lw from '../../src/lw'
|
||||
import { sleep, runTest, assertBuild, assertAutoBuild, writeTestFile, loadTestFile, getIntellisense, assertRoot, openActive } from './utils'
|
||||
import * as test from './utils'
|
||||
|
||||
suite('Multi-root workspace test suite', () => {
|
||||
|
||||
@ -38,11 +38,11 @@ suite('Multi-root workspace test suite', () => {
|
||||
|
||||
if (path.basename(fixture) === 'multiroot') {
|
||||
rimraf(fixture + '/{A,B}/{*,.vscode/*}', (e) => {if (e) {console.error(e)}})
|
||||
await sleep(500) // Required for pooling
|
||||
await test.sleep(500) // Required for pooling
|
||||
}
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build A', async () => {
|
||||
test.run(suiteName, fixtureName, 'basic build A', async () => {
|
||||
const tools = [
|
||||
{name: 'latexmk', command: 'latexmk', args: ['-synctex=1', '-interaction=nonstopmode', '-file-line-error', '-pdf', '-outdir=%OUTDIR%', '-jobname=wsA', '%DOC%'], env: {}},
|
||||
{name: 'fake', command: 'touch', args: ['%DIR%/fake.pdf']}
|
||||
@ -50,14 +50,14 @@ suite('Multi-root workspace test suite', () => {
|
||||
const recipes = [{name: 'latexmk', tools: ['latexmk']}]
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.tools', tools)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.recipes', recipes)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'base.tex', dst: 'A/main.tex'},
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'A/main.tex', 'A/wsA.pdf')
|
||||
await test.assert.build(fixture, 'A/main.tex', 'A/wsA.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build B', async () => {
|
||||
test.run(suiteName, fixtureName, 'basic build B', async () => {
|
||||
const tools = [
|
||||
{name: 'latexmk', command: 'latexmk', args: ['-synctex=1', '-interaction=nonstopmode', '-file-line-error', '-pdf', '-outdir=%OUTDIR%', '-jobname=wsB', '%DOC%'], env: {}},
|
||||
{name: 'fake', command: 'touch', args: ['%DIR%/fake.pdf']}
|
||||
@ -65,163 +65,163 @@ suite('Multi-root workspace test suite', () => {
|
||||
const recipes = [{name: 'latexmk', tools: ['latexmk']}]
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.tools', tools)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.recipes', recipes)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'base.tex', dst: 'B/main.tex'},
|
||||
{src: 'empty', dst: 'A/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'B/main.tex', 'B/wsB.pdf')
|
||||
await test.assert.build(fixture, 'B/main.tex', 'B/wsB.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build with outDir A', async () => {
|
||||
test.run(suiteName, fixtureName, 'basic build with outDir A', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'base.tex', dst: 'A/main.tex'},
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'A/main.tex', 'A/out/main.pdf')
|
||||
await test.assert.build(fixture, 'A/main.tex', 'A/out/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'basic build with outDir B', async () => {
|
||||
test.run(suiteName, fixtureName, 'basic build with outDir B', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.outDir', './out')
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'base.tex', dst: 'B/main.tex'},
|
||||
{src: 'empty', dst: 'A/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'B/main.tex', 'B/out/main.pdf')
|
||||
await test.assert.build(fixture, 'B/main.tex', 'B/out/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'build with forceRecipeUsage: true', async () => {
|
||||
test.run(suiteName, fixtureName, 'build with forceRecipeUsage: true', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.build.forceRecipeUsage', true)
|
||||
await loadTestFile(fixture, [{src: 'magic_invalid.tex', dst: 'A/main.tex'}])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [{src: 'magic_invalid.tex', dst: 'A/main.tex'}])
|
||||
await test.load(fixture, [
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'A/main.tex', 'A/main.pdf')
|
||||
await test.assert.build(fixture, 'A/main.tex', 'A/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'detect root with search.rootFiles.include', async () => {
|
||||
test.run(suiteName, fixtureName, 'detect root with search.rootFiles.include', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.search.rootFiles.include', ['alt/*.tex'])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'A/main.tex'},
|
||||
{src: 'input_parentsub.tex', dst: 'A/alt/main.tex'},
|
||||
{src: 'plain.tex', dst: 'A/sub/s.tex'}
|
||||
])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertRoot(fixture, 'A/sub/s.tex', 'A/alt/main.tex')
|
||||
await test.assert.root(fixture, 'A/sub/s.tex', 'A/alt/main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'detect root with search.rootFiles.exclude', async () => {
|
||||
test.run(suiteName, fixtureName, 'detect root with search.rootFiles.exclude', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.search.rootFiles.exclude', ['*.tex'])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'A/main.tex'},
|
||||
{src: 'input_parentsub.tex', dst: 'A/alt/main.tex'},
|
||||
{src: 'plain.tex', dst: 'A/sub/s.tex'}
|
||||
])
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertRoot(fixture, 'A/sub/s.tex', 'A/alt/main.tex')
|
||||
await test.assert.root(fixture, 'A/sub/s.tex', 'A/alt/main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect subfile root and build A1', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto-detect subfile root and build A1', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'A/main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'A/sub/s.tex'},
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'A/sub/s.tex', 'A/sub/s.pdf')
|
||||
await test.assert.build(fixture, 'A/sub/s.tex', 'A/sub/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect subfile root and build A2', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto-detect subfile root and build A2', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'A/main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'A/sub/s.tex'},
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'A/sub/s.tex', 'A/main.pdf')
|
||||
await test.assert.build(fixture, 'A/sub/s.tex', 'A/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect subfile root and build B1', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto-detect subfile root and build B1', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'B/main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'B/sub/s.tex'},
|
||||
{src: 'empty', dst: 'A/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'B/sub/s.tex', 'B/sub/s.pdf')
|
||||
await test.assert.build(fixture, 'B/sub/s.tex', 'B/sub/s.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto-detect subfile root and build B2', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto-detect subfile root and build B2', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'B/main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'B/sub/s.tex'},
|
||||
{src: 'empty', dst: 'A/empty'}
|
||||
])
|
||||
await assertBuild(fixture, 'B/sub/s.tex', 'B/main.pdf')
|
||||
await test.assert.build(fixture, 'B/sub/s.tex', 'B/main.pdf')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with subfiles and onSave 1', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with subfiles and onSave 1', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.autoBuild.run', 'onSave')
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', false)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'A/main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'A/sub/s.tex'},
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'A/sub/s.tex', 'A/main.pdf', ['onSave'])
|
||||
await test.assert.auto(fixture, 'A/sub/s.tex', 'A/main.pdf', ['onSave'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'auto build with subfiles and onSave 2', async () => {
|
||||
test.run(suiteName, fixtureName, 'auto build with subfiles and onSave 2', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.autoBuild.run', 'onSave')
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.doNotPrompt', true)
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('latex.rootFile.useSubFile', true)
|
||||
await loadTestFile(fixture, [
|
||||
await test.load(fixture, [
|
||||
{src: 'subfile_base.tex', dst: 'A/main.tex'},
|
||||
{src: 'subfile_sub.tex', dst: 'A/sub/s.tex'},
|
||||
{src: 'empty', dst: 'B/empty'}
|
||||
])
|
||||
await assertAutoBuild(fixture, 'A/sub/s.tex', 'A/sub/s.pdf', ['onSave'])
|
||||
await test.assert.auto(fixture, 'A/sub/s.tex', 'A/sub/s.pdf', ['onSave'])
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'switching rootFile', async () => {
|
||||
await loadTestFile(fixture, [{src: 'base.tex', dst: 'A/main.tex'},
|
||||
test.run(suiteName, fixtureName, 'switching rootFile', async () => {
|
||||
await test.load(fixture, [{src: 'base.tex', dst: 'A/main.tex'},
|
||||
{src: 'base.tex', dst: 'B/main.tex'}])
|
||||
await assertRoot(fixture, 'A/main.tex', 'A/main.tex')
|
||||
await assertRoot(fixture, 'B/main.tex', 'B/main.tex')
|
||||
await assertRoot(fixture, 'A/main.tex', 'A/main.tex')
|
||||
await test.assert.root(fixture, 'A/main.tex', 'A/main.tex')
|
||||
await test.assert.root(fixture, 'B/main.tex', 'B/main.tex')
|
||||
await test.assert.root(fixture, 'A/main.tex', 'A/main.tex')
|
||||
})
|
||||
|
||||
runTest(suiteName, fixtureName, 'switching intellisense', async () => {
|
||||
test.run(suiteName, fixtureName, 'switching intellisense', async () => {
|
||||
await vscode.workspace.getConfiguration('latex-workshop').update('intellisense.citation.label', 'bibtex key')
|
||||
writeTestFile(fixture, 'A/main.tex', '\\documentclass{article}', '\\begin{document}', 'abc\\cite{}', '\\bibliography{A.bib}', '\\end{document}')
|
||||
writeTestFile(fixture, 'B/main.tex', '\\documentclass{article}', '\\begin{document}', 'abc\\cite{}', '\\bibliography{B.bib}', '\\end{document}')
|
||||
await loadTestFile(fixture, [
|
||||
test.write(fixture, 'A/main.tex', '\\documentclass{article}', '\\begin{document}', 'abc\\cite{}', '\\bibliography{A.bib}', '\\end{document}')
|
||||
test.write(fixture, 'B/main.tex', '\\documentclass{article}', '\\begin{document}', 'abc\\cite{}', '\\bibliography{B.bib}', '\\end{document}')
|
||||
await test.load(fixture, [
|
||||
{src: 'base.bib', dst: 'A/A.bib'},
|
||||
{src: 'base.bib', dst: 'B/B.bib'}
|
||||
])
|
||||
await lw.completer.citation.parseBibFile(path.resolve(fixture, 'A/A.bib'))
|
||||
await lw.completer.citation.parseBibFile(path.resolve(fixture, 'B/B.bib'))
|
||||
|
||||
const resultA = await openActive(fixture, 'A/main.tex')
|
||||
const resultA = await test.open(fixture, 'A/main.tex')
|
||||
|
||||
const uri = vscode.window.activeTextEditor?.document.uri
|
||||
assert.ok(uri)
|
||||
const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri)
|
||||
await vscode.workspace.getConfiguration('latex-workshop', workspaceFolder).update('intellisense.citation.label', 'title', vscode.ConfigurationTarget.WorkspaceFolder)
|
||||
|
||||
const itemsA = getIntellisense(resultA.doc, new vscode.Position(2, 9))
|
||||
const itemsA = test.suggest(resultA.doc, new vscode.Position(2, 9))
|
||||
assert.ok(itemsA)
|
||||
assert.strictEqual(itemsA.length, 3)
|
||||
assert.strictEqual(itemsA[0].label, 'A fake article')
|
||||
@ -229,7 +229,7 @@ suite('Multi-root workspace test suite', () => {
|
||||
assert.ok(itemsA[0].filterText.includes('Journal of CI tests'))
|
||||
assert.ok(!itemsA[0].filterText.includes('hintFake'))
|
||||
|
||||
const resultB = await openActive(fixture, 'B/main.tex')
|
||||
const resultB = await test.open(fixture, 'B/main.tex')
|
||||
const cache = lw.cacher.get(path.resolve(fixture, 'B/main.tex'))
|
||||
if (cache) {
|
||||
cache.bibfiles = new Set([path.resolve(fixture, 'B/B.bib')])
|
||||
@ -237,7 +237,7 @@ suite('Multi-root workspace test suite', () => {
|
||||
return
|
||||
}
|
||||
|
||||
const itemsB = getIntellisense(resultB.doc, new vscode.Position(2, 9))
|
||||
const itemsB = test.suggest(resultB.doc, new vscode.Position(2, 9))
|
||||
assert.ok(itemsB)
|
||||
assert.strictEqual(itemsB.length, 3)
|
||||
assert.strictEqual(itemsB[0].label, 'art1')
|
||||
|
@ -3,24 +3,29 @@ import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import * as glob from 'glob'
|
||||
import * as os from 'os'
|
||||
import * as assert from 'assert'
|
||||
import { ok, strictEqual } from 'assert'
|
||||
import * as lw from '../../src/lw'
|
||||
import { BuildDone, FileParsed, FileWatched, RootFileSearched, ViewerPageLoaded, ViewerStatusChanged } from '../../src/components/eventbus'
|
||||
import type { EventName } from '../../src/components/eventbus'
|
||||
import { getCachedLog, getLogger, resetCachedLog } from '../../src/components/logger'
|
||||
|
||||
let testCounter = 0
|
||||
const logger = getLogger('Test')
|
||||
|
||||
export function runTestOnly(suiteName: string, fixtureName: string, testName: string, cb: () => unknown, platforms?: NodeJS.Platform[], timeout?: number) {
|
||||
return runTest(suiteName, fixtureName, testName, cb, platforms, timeout, true)
|
||||
export function only(suiteName: string, fixtureName: string, testName: string, cb: () => unknown, platforms?: NodeJS.Platform[], timeout?: number) {
|
||||
return run(suiteName, fixtureName, testName, cb, platforms, timeout, true)
|
||||
}
|
||||
|
||||
export function runTest(suiteName: string, fixtureName: string, testName: string, cb: () => unknown, platforms?: NodeJS.Platform[], timeout?: number, only?: boolean) {
|
||||
export function run(suiteName: string, fixtureName: string, testName: string, cb: () => unknown, platforms?: NodeJS.Platform[], timeout?: number, runonly?: boolean) {
|
||||
resetCachedLog()
|
||||
logger.log(`${testName}`)
|
||||
let fixture: string | undefined
|
||||
if (vscode.workspace.workspaceFile) {
|
||||
fixture = path.dirname(vscode.workspace.workspaceFile.fsPath)
|
||||
} else {
|
||||
fixture = vscode.workspace.workspaceFolders?.[0].uri.fsPath
|
||||
}
|
||||
logger.log(`Test fixture path: ${fixture} .`)
|
||||
|
||||
if (fixture === undefined) {
|
||||
return
|
||||
@ -36,15 +41,14 @@ export function runTest(suiteName: string, fixtureName: string, testName: string
|
||||
}
|
||||
|
||||
testCounter++
|
||||
const testFunction = (process.env['LATEXWORKSHOP_CLI'] || !only) ? test : test.only
|
||||
const testFunction = (process.env['LATEXWORKSHOP_CLI'] || !runonly) ? test : test.only
|
||||
const counterString = testCounter.toLocaleString('en-US', {minimumIntegerDigits: 3, useGrouping: false})
|
||||
|
||||
testFunction(`[${counterString}] ${suiteName}: ${testName}`, async () => {
|
||||
try {
|
||||
await cb()
|
||||
} catch (error) {
|
||||
await log(counterString)
|
||||
throw error
|
||||
} finally {
|
||||
log(fixtureName, testName, counterString)
|
||||
}
|
||||
}).timeout(timeout || 15000)
|
||||
}
|
||||
@ -53,33 +57,33 @@ export function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
|
||||
async function log(counter: string) {
|
||||
await vscode.commands.executeCommand('workbench.action.closeAllEditors')
|
||||
await sleep(500)
|
||||
await vscode.commands.executeCommand('workbench.action.output.toggleOutput')
|
||||
await sleep(500)
|
||||
await vscode.commands.executeCommand('latex-workshop.log')
|
||||
await sleep(500)
|
||||
const extensionMessage = vscode.window.activeTextEditor?.document.getText()
|
||||
await vscode.commands.executeCommand('latex-workshop.compilerlog')
|
||||
await sleep(500)
|
||||
const compilerMessage = vscode.window.activeTextEditor?.document.getText()
|
||||
|
||||
function log(fixtureName: string, testName: string, counter: string) {
|
||||
logger.log('Recording cached log messages.')
|
||||
const cachedLog = getCachedLog()
|
||||
const logFolder = path.resolve(__dirname, '../../../test/log')
|
||||
fs.mkdirSync(logFolder, {recursive: true})
|
||||
fs.writeFileSync(path.resolve(logFolder, `${counter}.extension.log`), extensionMessage || '')
|
||||
fs.writeFileSync(path.resolve(logFolder, `${counter}.compiler.log`), compilerMessage || '')
|
||||
fs.writeFileSync(path.resolve(logFolder, `${fixtureName}-${counter}.log`),
|
||||
testName +
|
||||
'\n\n' + new Array(80).fill('=').join('') + '\n\n' +
|
||||
cachedLog.CACHED_EXTLOG.join('\n') +
|
||||
'\n\n' + new Array(80).fill('=').join('') + '\n\n' +
|
||||
cachedLog.CACHED_COMPILER.join('\n') +
|
||||
'\n\n' + new Array(80).fill('=').join('') + '\n\n' +
|
||||
vscode.window.activeTextEditor?.document.uri.fsPath + '\n\n' +
|
||||
vscode.window.activeTextEditor?.document.getText())
|
||||
}
|
||||
|
||||
export function writeTestFile(fixture: string, fileName: string, ...contents: string[]) {
|
||||
export function write(fixture: string, fileName: string, ...contents: string[]) {
|
||||
logger.log(`Writing fixture file: ${fileName} .`)
|
||||
fs.mkdirSync(path.resolve(fixture, path.dirname(fileName)), {recursive: true})
|
||||
fs.writeFileSync(path.resolve(fixture, fileName), contents.join('\n'))
|
||||
}
|
||||
|
||||
export async function loadTestFile(fixture: string, files: {src: string, dst: string}[]) {
|
||||
export async function load(fixture: string, files: {src: string, dst: string}[]) {
|
||||
let unlinked = false
|
||||
for (const file of files) {
|
||||
if (fs.existsSync(path.resolve(fixture, file.dst))) {
|
||||
logger.log(`Unlinking previous fixture file ${file.dst} .`)
|
||||
fs.unlinkSync(path.resolve(fixture, file.dst))
|
||||
unlinked = true
|
||||
}
|
||||
@ -88,74 +92,33 @@ export async function loadTestFile(fixture: string, files: {src: string, dst: st
|
||||
await sleep(500)
|
||||
}
|
||||
for (const file of files) {
|
||||
logger.log(`Loading fixture file ${file.src} to ${file.dst} .`)
|
||||
fs.mkdirSync(path.resolve(fixture, path.dirname(file.dst)), {recursive: true})
|
||||
fs.copyFileSync(path.resolve(fixture, '../armory', file.src), path.resolve(fixture, file.dst))
|
||||
}
|
||||
await sleep(250)
|
||||
}
|
||||
|
||||
export async function openActive(fixture: string, fileName: string, doContext = true) {
|
||||
export async function open(fixture: string, fileName: string, doCache = true) {
|
||||
logger.log(`Opening fixture file ${fileName} .`)
|
||||
const texFilePath = vscode.Uri.file(path.join(fixture, fileName))
|
||||
let wait = waitEvent(FileParsed, path.resolve(fixture, fileName))
|
||||
let event = wait(FileParsed, path.resolve(fixture, fileName))
|
||||
logger.log('Try to open a text document.')
|
||||
const doc = await vscode.workspace.openTextDocument(texFilePath)
|
||||
await vscode.window.showTextDocument(doc)
|
||||
if (doContext) {
|
||||
await lw.cacher.refreshContext(path.resolve(fixture, fileName))
|
||||
await wait
|
||||
if (doCache) {
|
||||
logger.log(`Caching ${fileName} .`)
|
||||
await lw.cacher.refreshCache(path.resolve(fixture, fileName))
|
||||
await event
|
||||
}
|
||||
wait = waitEvent(RootFileSearched)
|
||||
logger.log('Searching for root file.')
|
||||
event = wait(RootFileSearched)
|
||||
const root = await lw.manager.findRoot()
|
||||
await wait
|
||||
await event
|
||||
return {root, doc}
|
||||
}
|
||||
|
||||
export async function assertBuild(fixture: string, texName: string, pdfName: string, build?: () => unknown) {
|
||||
await openActive(fixture, texName, false)
|
||||
if (build) {
|
||||
await build()
|
||||
} else {
|
||||
await lw.commander.build()
|
||||
}
|
||||
|
||||
const files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
const pdfPath = path.join(fixture, pdfName)
|
||||
assert.strictEqual(files.map(file => path.resolve(fixture, file)).join(','), pdfName === '' ? pdfName : pdfPath)
|
||||
}
|
||||
|
||||
export async function assertAutoBuild(fixture: string, texName: string, pdfName: string, mode?: ('skipFirstBuild' | 'noAutoBuild' | 'onSave')[], build?: () => unknown) {
|
||||
if (!mode?.includes('skipFirstBuild')) {
|
||||
await assertBuild(fixture, texName, pdfName, build)
|
||||
}
|
||||
fs.rmSync(path.resolve(fixture, pdfName))
|
||||
|
||||
let files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
assert.strictEqual(files.map(file => path.resolve(fixture, file)).join(','), '')
|
||||
await sleep(250)
|
||||
|
||||
let wait = waitEvent(FileWatched, path.resolve(fixture, texName))
|
||||
if (!mode?.includes('noAutoBuild') && texName.endsWith('.tex') && !lw.cacher.watched(path.resolve(fixture, texName))) {
|
||||
await wait
|
||||
}
|
||||
|
||||
wait = waitEvent(BuildDone)
|
||||
if (mode?.includes('onSave')) {
|
||||
await vscode.commands.executeCommand('workbench.action.files.save')
|
||||
} else {
|
||||
fs.appendFileSync(path.resolve(fixture, texName), ' % edit')
|
||||
}
|
||||
|
||||
if (mode?.includes('noAutoBuild')) {
|
||||
await sleep(3000)
|
||||
files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
assert.strictEqual(files.map(file => path.resolve(fixture, file)).join(','), '')
|
||||
} else {
|
||||
await wait
|
||||
files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
assert.strictEqual(files.map(file => path.resolve(fixture, file)).join(','), path.resolve(fixture, pdfName))
|
||||
}
|
||||
}
|
||||
|
||||
export async function waitEvent(event: EventName, arg?: any) {
|
||||
export async function wait(event: EventName, arg?: any) {
|
||||
return new Promise<void>((resolve, _) => {
|
||||
const disposable = lw.eventBus.on(event, (eventArg) => {
|
||||
if (arg && arg !== eventArg) {
|
||||
@ -167,30 +130,8 @@ export async function waitEvent(event: EventName, arg?: any) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function assertRoot(fixture: string, openName: string, rootName: string) {
|
||||
await vscode.commands.executeCommand('latex-workshop.activate')
|
||||
const result = await openActive(fixture, openName)
|
||||
assert.strictEqual(result.root, path.join(fixture, rootName))
|
||||
}
|
||||
|
||||
export async function assertViewer(fixture: string, pdfName: string, action?: () => unknown) {
|
||||
await sleep(250)
|
||||
const wait = Promise.all([
|
||||
waitEvent(ViewerPageLoaded),
|
||||
waitEvent(ViewerStatusChanged)
|
||||
])
|
||||
void vscode.commands.executeCommand('latex-workshop.view')
|
||||
if (action) {
|
||||
await action()
|
||||
}
|
||||
await wait
|
||||
const pdfFilePath = path.resolve(fixture, pdfName)
|
||||
const status = lw.viewer.getViewerState(vscode.Uri.file(pdfFilePath))[0]
|
||||
assert.ok(status)
|
||||
assert.strictEqual(status.pdfFileUri, vscode.Uri.file(path.resolve(fixture, pdfName)).toString(true))
|
||||
}
|
||||
|
||||
export function getIntellisense(doc: vscode.TextDocument, pos: vscode.Position, atSuggestion = false) {
|
||||
export function suggest(doc: vscode.TextDocument, pos: vscode.Position, atSuggestion = false) {
|
||||
logger.log('Getting suggestion.')
|
||||
const completer = atSuggestion ? lw.atSuggestionCompleter : lw.completer
|
||||
return completer?.provideCompletionItems(
|
||||
doc, pos, new vscode.CancellationTokenSource().token, {
|
||||
@ -199,3 +140,91 @@ export function getIntellisense(doc: vscode.TextDocument, pos: vscode.Position,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export const assert = {
|
||||
build: assertBuild,
|
||||
auto: assertAutoBuild,
|
||||
root: assertRoot,
|
||||
viewer: assertViewer
|
||||
}
|
||||
|
||||
async function assertBuild(fixture: string, texName: string, pdfName: string, build?: () => unknown) {
|
||||
await open(fixture, texName, false)
|
||||
logger.log(`Building fixture file ${texName} .`)
|
||||
if (build) {
|
||||
await build()
|
||||
} else {
|
||||
await lw.commander.build()
|
||||
}
|
||||
|
||||
const files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
const pdfPath = path.join(fixture, pdfName)
|
||||
logger.log(`PDF produced: ${files ? files.join(' , ') : 'nothing'} .`)
|
||||
strictEqual(files.map(file => path.resolve(fixture, file)).join(','), pdfName === '' ? pdfName : pdfPath)
|
||||
}
|
||||
|
||||
async function assertAutoBuild(fixture: string, texName: string, pdfName: string, mode?: ('skipFirstBuild' | 'noAutoBuild' | 'onSave')[], build?: () => unknown) {
|
||||
logger.log(`Auto-building fixture file ${texName} .`)
|
||||
if (!mode?.includes('skipFirstBuild')) {
|
||||
await assertBuild(fixture, texName, pdfName, build)
|
||||
}
|
||||
fs.rmSync(path.resolve(fixture, pdfName))
|
||||
|
||||
let files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
strictEqual(files.map(file => path.resolve(fixture, file)).join(','), '')
|
||||
logger.log('First manual build PDF has been unlinked.')
|
||||
await sleep(250)
|
||||
|
||||
let event = wait(FileWatched, path.resolve(fixture, texName))
|
||||
if (!mode?.includes('noAutoBuild') && texName.endsWith('.tex') && !lw.cacher.watched(path.resolve(fixture, texName))) {
|
||||
logger.log(`Waiting for watching ${texName} .`)
|
||||
await event
|
||||
}
|
||||
|
||||
event = wait(BuildDone)
|
||||
if (mode?.includes('onSave')) {
|
||||
logger.log('Saving.')
|
||||
await vscode.commands.executeCommand('workbench.action.files.save')
|
||||
} else {
|
||||
logger.log('Editing.')
|
||||
fs.appendFileSync(path.resolve(fixture, texName), ' % edit')
|
||||
}
|
||||
|
||||
logger.log('Waiting.')
|
||||
if (mode?.includes('noAutoBuild')) {
|
||||
await sleep(3000)
|
||||
files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
logger.log(`PDF produced: ${files ? files.join(' , ') : 'nothing'} .`)
|
||||
strictEqual(files.map(file => path.resolve(fixture, file)).join(','), '')
|
||||
} else {
|
||||
await event
|
||||
files = glob.sync('**/**.pdf', { cwd: fixture })
|
||||
logger.log(`PDF produced: ${files ? files.join(' , ') : 'nothing'} .`)
|
||||
strictEqual(files.map(file => path.resolve(fixture, file)).join(','), path.resolve(fixture, pdfName))
|
||||
}
|
||||
}
|
||||
|
||||
async function assertRoot(fixture: string, openName: string, rootName: string) {
|
||||
await vscode.commands.executeCommand('latex-workshop.activate')
|
||||
const result = await open(fixture, openName)
|
||||
logger.log('Asserting current root.')
|
||||
strictEqual(result.root, path.join(fixture, rootName))
|
||||
}
|
||||
|
||||
async function assertViewer(fixture: string, pdfName: string, action?: () => unknown) {
|
||||
logger.log(`Asserting viewer for ${pdfName} .`)
|
||||
await sleep(250)
|
||||
const promise = Promise.all([
|
||||
wait(ViewerPageLoaded),
|
||||
wait(ViewerStatusChanged)
|
||||
])
|
||||
void vscode.commands.executeCommand('latex-workshop.view')
|
||||
if (action) {
|
||||
await action()
|
||||
}
|
||||
await promise
|
||||
const pdfFilePath = path.resolve(fixture, pdfName)
|
||||
const status = lw.viewer.getViewerState(vscode.Uri.file(pdfFilePath))[0]
|
||||
ok(status)
|
||||
strictEqual(status.pdfFileUri, vscode.Uri.file(path.resolve(fixture, pdfName)).toString(true))
|
||||
}
|
||||
|
@ -93,6 +93,7 @@ export type PdfViewerState = {
|
||||
scale?: string,
|
||||
scrollTop?: number,
|
||||
scrollLeft?: number,
|
||||
sidebarView?: number,
|
||||
trim?: number,
|
||||
scrollMode?: number,
|
||||
spreadMode?: number,
|
||||
|
@ -78,7 +78,9 @@ export interface IPDFViewerApplication {
|
||||
}
|
||||
},
|
||||
pdfSidebar: {
|
||||
isOpen: boolean
|
||||
isOpen: boolean,
|
||||
visibleView: number,
|
||||
switchView(view: number): void
|
||||
},
|
||||
secondaryToolbar: {
|
||||
close: () => void,
|
||||
|
@ -56,12 +56,8 @@ export function registerPageTrimmer() {
|
||||
for ( const opt of scaleSelect.options ) {
|
||||
opt.disabled = true
|
||||
}
|
||||
if (currentUserSelectScale === undefined) {
|
||||
currentUserSelectScale = PDFViewerApplication.pdfViewer._currentScale
|
||||
}
|
||||
if (originalUserSelectIndex === undefined) {
|
||||
originalUserSelectIndex = scaleSelect.selectedIndex
|
||||
}
|
||||
currentUserSelectScale = currentUserSelectScale ?? PDFViewerApplication.pdfViewer._currentScale
|
||||
originalUserSelectIndex = originalUserSelectIndex ?? scaleSelect.selectedIndex
|
||||
const opt = document.getElementById('trimOption') as HTMLOptionElement
|
||||
opt.value = (currentUserSelectScale * trimScale).toString()
|
||||
opt.selected = true
|
||||
|
@ -39,7 +39,7 @@ export class ViewerHistory {
|
||||
|
||||
private lastIndex() {
|
||||
if (this.history.length === 0) {
|
||||
return undefined
|
||||
return
|
||||
} else {
|
||||
return this.history.length - 1
|
||||
}
|
||||
|
@ -152,6 +152,7 @@ class LateXWorkshopPdfViewer implements ILatexWorkshopPdfViewer {
|
||||
pdfFileUri: this.pdfFileUri,
|
||||
scale: PDFViewerApplication.pdfViewer.currentScaleValue,
|
||||
scrollMode: PDFViewerApplication.pdfViewer.scrollMode,
|
||||
sidebarView: PDFViewerApplication.pdfSidebar.visibleView,
|
||||
spreadMode: PDFViewerApplication.pdfViewer.spreadMode,
|
||||
scrollTop: (document.getElementById('viewerContainer') as HTMLElement).scrollTop,
|
||||
scrollLeft: (document.getElementById('viewerContainer') as HTMLElement).scrollLeft,
|
||||
@ -172,7 +173,7 @@ class LateXWorkshopPdfViewer implements ILatexWorkshopPdfViewer {
|
||||
if (this.embedded) {
|
||||
return this.#restoredState.promise
|
||||
} else {
|
||||
return undefined
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -233,6 +234,9 @@ class LateXWorkshopPdfViewer implements ILatexWorkshopPdfViewer {
|
||||
if (state.scrollLeft !== undefined) {
|
||||
(document.getElementById('viewerContainer') as HTMLElement).scrollLeft = state.scrollLeft
|
||||
}
|
||||
if (state.sidebarView !== undefined) {
|
||||
PDFViewerApplication.pdfSidebar.switchView(state.sidebarView)
|
||||
}
|
||||
if (state.synctexEnabled !== undefined) {
|
||||
this.setSynctex(state.synctexEnabled)
|
||||
}
|
||||
@ -260,6 +264,9 @@ class LateXWorkshopPdfViewer implements ILatexWorkshopPdfViewer {
|
||||
if (state.scrollTop !== undefined) {
|
||||
(document.getElementById('viewerContainer') as HTMLElement).scrollTop = state.scrollTop
|
||||
}
|
||||
if (state.sidebarView !== undefined) {
|
||||
PDFViewerApplication.pdfSidebar.switchView(state.sidebarView)
|
||||
}
|
||||
this.sendCurrentStateToPanelManager()
|
||||
})
|
||||
}
|
||||
@ -313,6 +320,7 @@ class LateXWorkshopPdfViewer implements ILatexWorkshopPdfViewer {
|
||||
const pack = {
|
||||
scale: PDFViewerApplication.pdfViewer.currentScaleValue,
|
||||
scrollMode: PDFViewerApplication.pdfViewer.scrollMode,
|
||||
sidebarView: PDFViewerApplication.pdfSidebar.visibleView,
|
||||
spreadMode: PDFViewerApplication.pdfViewer.spreadMode,
|
||||
scrollTop: (document.getElementById('viewerContainer') as HTMLElement).scrollTop,
|
||||
scrollLeft: (document.getElementById('viewerContainer') as HTMLElement).scrollLeft
|
||||
@ -330,6 +338,7 @@ class LateXWorkshopPdfViewer implements ILatexWorkshopPdfViewer {
|
||||
document.title = this.documentTitle
|
||||
})
|
||||
this.onPagesInit(() => {
|
||||
PDFViewerApplication.pdfSidebar.switchView(pack.sidebarView)
|
||||
PDFViewerApplication.pdfViewer.currentScaleValue = pack.scale
|
||||
PDFViewerApplication.pdfViewer.scrollMode = pack.scrollMode
|
||||
PDFViewerApplication.pdfViewer.spreadMode = pack.spreadMode;
|
||||
|
Loading…
Reference in New Issue
Block a user