Skip to content

Commit

Permalink
Merge pull request #3572 from Hannah-Sten/tex-variables
Browse files Browse the repository at this point in the history
Index files in texinputs
  • Loading branch information
PHPirates authored Jun 9, 2024
2 parents 3a74375 + b284a87 commit aead4b4
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 49 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@

### Fixed

## [0.9.7-alpha.1] - 2024-06-06

### Added

* Support TeX Live docker image
* Formatter support for plain TeX \if-statements
* Index files from the TEXINPUTS variable, for autocompletion

## [0.9.6] - 2024-06-01

Welcome to TeXiFy IDEA 0.9.6! This release fixes an issue with the table insertion wizard, fixes pasting from a pdf file, and more.
Expand Down Expand Up @@ -358,7 +366,8 @@ Thanks to @jojo2357 and @MisterDeenis for contributing to this release!
* Fix some intention previews. ([#2796](https://github.com/Hannah-Sten/TeXiFy-IDEA/issues/2796))
* Other small bug fixes and improvements. ([#2776](https://github.com/Hannah-Sten/TeXiFy-IDEA/issues/2776), [#2774](https://github.com/Hannah-Sten/TeXiFy-IDEA/issues/2774), [#2765](https://github.com/Hannah-Sten/TeXiFy-IDEA/issues/2765)-[#2773](https://github.com/Hannah-Sten/TeXiFy-IDEA/issues/2773))

[Unreleased]: https://github.com/Hannah-Sten/TeXiFy-IDEA/compare/v0.9.6...HEAD
[Unreleased]: https://github.com/Hannah-Sten/TeXiFy-IDEA/compare/v0.9.7-alpha.1...HEAD
[0.9.7-alpha.1]: https://github.com/Hannah-Sten/TeXiFy-IDEA/compare/v0.9.6...v0.9.7-alpha.1
[0.9.6]: https://github.com/Hannah-Sten/TeXiFy-IDEA/compare/v0.9.5...v0.9.6
[0.9.5]: https://github.com/Hannah-Sten/TeXiFy-IDEA/compare/v0.9.4...v0.9.5
[0.9.4]: https://github.com/Hannah-Sten/TeXiFy-IDEA/compare/v0.9.3...v0.9.4
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pluginVersion = 0.9.6
pluginVersion = 0.9.7-alpha.1

# Info about build ranges: https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html
# Note that an xyz branch corresponds to version 20xy.z and a since build of xyz.*
Expand Down
2 changes: 1 addition & 1 deletion resources/META-INF/actions/actions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
<!-- LaTeX Analyze menu -->
<action class="nl.hannahsten.texifyidea.action.analysis.WordCountAction" id="texify.analysis.WordCount"
text="_Word Count" description="Estimate the word count of the currently active .tex file and inclusions." icon="nl.hannahsten.texifyidea.TexifyIcons.WORD_COUNT">
<keyboard-shortcut first-keystroke="control alt W" keymap="$default"/>
<keyboard-shortcut first-keystroke="alt W" keymap="$default"/>
<override-text place="GoToAction" text="LaTeX _Word Count"/>
<!-- Prior to idea 213, the Code menu was called Analyze (but only in IntelliJ) -->
<add-to-group group-id="CodeMenu" anchor="last"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.intellij.icons.AllIcons
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.ui.DialogBuilder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
Expand Down Expand Up @@ -71,6 +72,8 @@ open class WordCountAction : AnAction() {
// Prefer texcount, I think it is slightly more accurate
val dialog = if (SystemEnvironment.isAvailable("texcount")) {
val root = psiFile.findRootFile().virtualFile
// Make sure the file is written to disk before running an external tool on it
FileDocumentManager.getInstance().apply { saveDocument(getDocument(root) ?: return@apply) }
val (output, exitCode) = runCommandWithExitCode("texcount", "-1", "-inc", "-sum", root.name, workingDirectory = File(root.parent.path))
if (exitCode == 0 && output?.toIntOrNull() != null) {
makeDialog(psiFile, output.toInt())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.Task.Backgroundable
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.util.indexing.IndexableSetContributor
import nl.hannahsten.texifyidea.settings.TexifySettings
import nl.hannahsten.texifyidea.settings.sdk.LatexSdkUtil
import nl.hannahsten.texifyidea.util.Log
import nl.hannahsten.texifyidea.util.getTexinputsPaths
import nl.hannahsten.texifyidea.util.isTestProject
import org.codehaus.plexus.archiver.ArchiverException
import org.codehaus.plexus.archiver.tar.TarBZip2UnArchiver
Expand Down Expand Up @@ -58,6 +60,8 @@ class LatexIndexableSetContributor : IndexableSetContributor() {
// Unfortunately, since .sty is a LaTeX file type, these will all be parsed, which will take an enormous amount of time.
// Note that using project-independent getAdditionalRootsToIndex does not fix this
roots.addAll(LatexSdkUtil.getSdkSourceRoots(project) { sdkType, homePath -> sdkType.getDefaultStyleFilesPath(homePath) })

roots.addAll(getTexinputsPaths(project, rootFiles = listOf(), expandPaths = false).mapNotNull { LocalFileSystem.getInstance().findFileByPath(it) })
Log.debug("Indexing source roots $roots")

return roots
Expand Down
34 changes: 1 addition & 33 deletions src/nl/hannahsten/texifyidea/reference/InputFileReference.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package nl.hannahsten.texifyidea.reference

import com.intellij.execution.RunManager
import com.intellij.execution.impl.RunManagerImpl
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.vfs.LocalFileSystem
Expand All @@ -15,12 +13,10 @@ import nl.hannahsten.texifyidea.completion.pathcompletion.LatexGraphicsPathProvi
import nl.hannahsten.texifyidea.lang.commands.LatexGenericRegularCommand
import nl.hannahsten.texifyidea.psi.LatexCommands
import nl.hannahsten.texifyidea.psi.LatexPsiHelper
import nl.hannahsten.texifyidea.run.latex.LatexRunConfiguration
import nl.hannahsten.texifyidea.settings.sdk.LatexSdkUtil
import nl.hannahsten.texifyidea.util.*
import nl.hannahsten.texifyidea.util.files.*
import nl.hannahsten.texifyidea.util.magic.CommandMagic
import java.io.File

/**
* Reference to a file, based on the command and the range of the filename within the command text.
Expand All @@ -40,10 +36,6 @@ class InputFileReference(

companion object {

private val texinputs by lazy {
runCommand("kpsewhich", "--expand-var", "'\$TEXINPUTS'")
}

/**
* Handle element rename, but taking into account whether the given
* newElementName is just a filename which we have to replace,
Expand Down Expand Up @@ -123,31 +115,7 @@ class InputFileReference(
val rootDirectories = rootFiles.mapNotNull { it.parent }

// Check environment variables
val runManager = RunManagerImpl.getInstanceImpl(element.project) as RunManager
val texinputsVariable = runManager.allConfigurationsList
.filterIsInstance<LatexRunConfiguration>()
.firstOrNull { it.mainFile in rootFiles }
?.environmentVariables
?.envs
?.getOrDefault("TEXINPUTS", null)
// Not sure which of these takes precedence, or if they are joined together
?: LatexmkRcFileFinder.getTexinputsVariable(element.containingFile, null)
?: texinputs

for (texInputPath in texinputsVariable?.trim('\'')?.split(File.pathSeparator)?.filter { it.isNotBlank() } ?: emptyList()) {
val path = texInputPath.trimEnd(File.pathSeparatorChar)
searchPaths.add(path.trimEnd('/'))
// See the kpathsea manual, // expands to subdirs
if (path.endsWith("//")) {
LocalFileSystem.getInstance().findFileByPath(path.trimEnd('/'))?.let { parent ->
searchPaths.addAll(
parent.allChildDirectories()
.filter { it.isDirectory }
.map { it.path }
)
}
}
}
searchPaths += getTexinputsPaths(element.project, rootFiles, expandPaths = true, latexmkSearchDirectory = element.containingFile?.virtualFile?.parent)

// BIBINPUTS
// Not used for building the fileset, so we can use the fileset to lookup the BIBINPUTS environment variable
Expand Down
23 changes: 10 additions & 13 deletions src/nl/hannahsten/texifyidea/util/LatexmkRcFileFinder.kt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package nl.hannahsten.texifyidea.util

import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import nl.hannahsten.texifyidea.run.compiler.LatexCompiler
import nl.hannahsten.texifyidea.run.latex.LatexRunConfiguration
import java.io.File
Expand Down Expand Up @@ -116,12 +116,12 @@ object LatexmkRcFileFinder {
* Get the first TEXINPUTS we can find in latexmkrc files.
* Cached because searching involves quite some system calls, and it's a rarely used feature.
*/
fun getTexinputsVariable(someFile: PsiFile?, runConfig: LatexRunConfiguration?): String? {
fun getTexinputsVariable(directory: VirtualFile, runConfig: LatexRunConfiguration?, project: Project): String? {
return if (usesLatexmkrc == false) {
null
}
else {
val texinputs = getTexinputsVariableNoCache(someFile, runConfig)
val texinputs = getTexinputsVariableNoCache(directory, runConfig, project)
if (usesLatexmkrc == null) {
usesLatexmkrc = texinputs != null
}
Expand All @@ -132,27 +132,24 @@ object LatexmkRcFileFinder {
/**
* Check the (first) latexmkrc file for any additions to TEXINPUTS and return that if present.
*
* @param someFile Any file, the parent directories will be searched.
* @param runConfig Run configuration to check for working directory and arguments.
*/
private fun getTexinputsVariableNoCache(someFile: PsiFile?, runConfig: LatexRunConfiguration?): String? {
private fun getTexinputsVariableNoCache(directory: VirtualFile, runConfig: LatexRunConfiguration?, project: Project): String? {
systemLatexmkRcFile?.let { return getTexinputs(it) }
if (runConfig != null) {
getLocalLatexmkRcFile(runConfig.compilerArguments, runConfig.mainFile?.parent?.path)?.let { return getTexinputs(it) }
}
// File could be anywhere if run configurations are not used, but searching the whole project could be too expensive
someFile?.virtualFile?.parent?.let { parentDir ->
parentDir.findChild(".latexmkrc")?.let { return getTexinputs(it) }
parentDir.findChild("latexmkrc")?.let { return getTexinputs(it) }
}
val project = someFile?.project ?: return null
directory.findChild(".latexmkrc")?.let { return getTexinputs(it) }
directory.findChild("latexmkrc")?.let { return getTexinputs(it) }

val projectDir = project.guessProjectDir()
if (projectDir?.isValid == false) return null
projectDir?.findChild(".latexmkrc")?.let { return getTexinputs(it) }
projectDir?.findChild("latexmkrc")?.let { return getTexinputs(it) }
projectDir?.children?.forEach { directory ->
directory?.findChild(".latexmkrc")?.let { return getTexinputs(it) }
directory?.findChild("latexmkrc")?.let { return getTexinputs(it) }
projectDir?.children?.forEach { childDir ->
childDir?.findChild(".latexmkrc")?.let { return getTexinputs(it) }
childDir?.findChild("latexmkrc")?.let { return getTexinputs(it) }
}
return null
}
Expand Down
59 changes: 59 additions & 0 deletions src/nl/hannahsten/texifyidea/util/SystemEnvironment.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
package nl.hannahsten.texifyidea.util

import com.intellij.execution.RunManager
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.impl.RunManagerImpl
import com.intellij.execution.process.ProcessNotCreatedException
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.guessProjectDir
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import nl.hannahsten.texifyidea.run.latex.LatexRunConfiguration
import nl.hannahsten.texifyidea.util.files.*
import org.apache.maven.artifact.versioning.DefaultArtifactVersion
import java.io.File
import java.io.IOException
Expand Down Expand Up @@ -53,6 +61,10 @@ class SystemEnvironment {
val evinceVersion: DefaultArtifactVersion by lazy {
DefaultArtifactVersion("evince --version".runCommand()?.split(" ")?.lastOrNull() ?: "")
}

val texinputs by lazy {
runCommand("kpsewhich", "--expand-var", "'\$TEXINPUTS'")
}
}
}

Expand Down Expand Up @@ -146,3 +158,50 @@ private fun readInputStream(nonBlocking: Boolean, proc: Process): String {
}
return output
}

/**
* Collect texinputs from various places
*
* @param rootFiles If provided, filter run configurations
* @param expandPaths Expand subdirectories
*/
fun getTexinputsPaths(
project: Project,
rootFiles: Collection<VirtualFile>,
expandPaths: Boolean = true,
latexmkSearchDirectory: VirtualFile? = null
): List<String> {
val searchPaths = mutableListOf<String>()
val runManager = RunManagerImpl.getInstanceImpl(project) as RunManager
val allConfigurations = runManager.allConfigurationsList
.filterIsInstance<LatexRunConfiguration>()
val selectedConfiguratios = if (rootFiles.isEmpty()) allConfigurations else allConfigurations.filter { it.mainFile in rootFiles }
val configurationTexinputsVariables = selectedConfiguratios.map { it.environmentVariables.envs }.mapNotNull { it.getOrDefault("TEXINPUTS", null) }
// Not sure which of these takes precedence, or if they are joined together
val texinputsVariables = configurationTexinputsVariables +
selectedConfiguratios.map { LatexmkRcFileFinder.getTexinputsVariable(latexmkSearchDirectory ?: project.guessProjectDir() ?: return@map null, it, project) } +
listOf(if (expandPaths) SystemEnvironment.texinputs else System.getenv("TEXINPUTS"))

for (texinputsVariable in texinputsVariables.filterNotNull()) {
for (texInputPath in texinputsVariable.trim('\'').split(File.pathSeparator).filter { it.isNotBlank() }) {
val path = texInputPath.trimEnd(File.pathSeparatorChar)
searchPaths.add(path.trimEnd('/'))
// See the kpathsea manual, // expands to subdirs
if (path.endsWith("//")) {
LocalFileSystem.getInstance().findFileByPath(path.trimEnd('/'))?.let { parent ->
if (expandPaths) {
searchPaths.addAll(
parent.allChildDirectories()
.filter { it.isDirectory }
.map { it.path }
)
}
else {
searchPaths.add(parent.path)
}
}
}
}
}
return searchPaths
}

0 comments on commit aead4b4

Please sign in to comment.