-
-
Notifications
You must be signed in to change notification settings - Fork 89
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3467 from Hannah-Sten/run-config-completion
Autocompletion for compiler arguments in run configuration settings
- Loading branch information
Showing
7 changed files
with
225 additions
and
8 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
108 changes: 108 additions & 0 deletions
108
src/nl/hannahsten/texifyidea/run/latex/LatexCommandLineOptionsCache.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package nl.hannahsten.texifyidea.run.latex | ||
|
||
import arrow.atomic.AtomicBoolean | ||
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 nl.hannahsten.texifyidea.run.compiler.LatexCompiler | ||
import nl.hannahsten.texifyidea.util.remove | ||
import nl.hannahsten.texifyidea.util.runCommandWithExitCode | ||
import org.apache.commons.cli.Option | ||
import org.apache.commons.cli.Options | ||
|
||
/** | ||
* Automatically get available command line options for all the LaTeX compilers. | ||
*/ | ||
object LatexCommandLineOptionsCache { | ||
// Map compiler name to list of (name, description) pairs where name is without the - or -- prefix | ||
val cache = mutableMapOf<String, Options>() | ||
|
||
private val isCacheFillInProgress = AtomicBoolean(false) | ||
|
||
/** | ||
* Get the options for the given compiler, or fill the cache if it is empty. | ||
* Cache fill is done in the background because it requires system calls so may take significant time. | ||
*/ | ||
fun getOptionsOrFillCache(givenCompiler: String, project: Project): Options { | ||
if (cache.isNotEmpty()) { | ||
return cache[givenCompiler] ?: Options() | ||
} | ||
|
||
if (isCacheFillInProgress.compareAndSet(expected = true, new = true)) { | ||
return Options() | ||
} | ||
isCacheFillInProgress.getAndSet(true) | ||
|
||
fillCache(project) | ||
return Options() | ||
} | ||
|
||
private fun getOptions(optionsList: List<Pair<String, String>>): Options { | ||
return Options().apply { | ||
for ((option, description) in optionsList) { | ||
// option is with one - and .longOpt is with two --, but both are possible it seems with pdflatex | ||
addOption(Option.builder().longOpt(option).desc(description).build()) | ||
} | ||
} | ||
} | ||
|
||
private fun fillCache(project: Project): List<Pair<String, String>> { | ||
ProgressManager.getInstance().run(object : Backgroundable(project, "Retrieving available command line options for LaTeX compilers...") { | ||
override fun run(indicator: ProgressIndicator) { | ||
try { | ||
for (compiler in LatexCompiler.values()) { | ||
val (output, _) = runCommandWithExitCode(compiler.executableName, "--help") | ||
if (output != null) { | ||
val optionsList = parseHelpOutput(compiler.executableName, output) | ||
cache[compiler.executableName] = getOptions(optionsList) | ||
} | ||
else { | ||
cache[compiler.executableName] = Options() | ||
} | ||
} | ||
} | ||
finally { | ||
isCacheFillInProgress.getAndSet(false) | ||
} | ||
} | ||
}) | ||
|
||
return emptyList() | ||
} | ||
|
||
/** | ||
* Parse the output of pdflatex --help to get available compiler options. | ||
* These are slightly different per compiler. | ||
* Tested with pdflatex, lualatex, xelatex and latexmk | ||
*/ | ||
fun parseHelpOutput(compiler: String, text: String): List<Pair<String, String>> { | ||
return text.split("\n") | ||
.asSequence() | ||
.map { it.trim(' ').split(if (compiler == "latexmk") " - " else " ") } | ||
.filter { it.size >= 2 } | ||
.map { Pair(it.first(), it.drop(1).joinToString(" ").trim(' ')) } | ||
.flatMap { (option, description) -> | ||
// [-no] for pdflatex, --[no-] for lualatex | ||
if (option.contains("[-no]") || option.contains("[no-]")) { | ||
val cleanedOption = option.remove("[-no]").remove("[no-]").trim('-') | ||
listOf( | ||
Pair(cleanedOption, description), | ||
Pair("no-$cleanedOption", description) | ||
) | ||
} | ||
// latexmk | ||
else if (option.contains(" or ")) { | ||
option.split(" or ").map { singleOption -> Pair(singleOption, description) } | ||
} | ||
else if (option.startsWith("-")) { | ||
listOf(Pair(option, description)) | ||
} | ||
else { | ||
emptyList() | ||
} | ||
} | ||
.map { Pair(it.first.trim(' ').trimStart('-'), it.second) } | ||
.toList() | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/nl/hannahsten/texifyidea/run/latex/ui/LatexArgumentsCompletionProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package nl.hannahsten.texifyidea.run.latex.ui | ||
|
||
import com.intellij.codeInsight.completion.CompletionResultSet | ||
import com.intellij.openapi.externalSystem.service.execution.cmd.CommandLineCompletionProvider | ||
import org.apache.commons.cli.Options | ||
|
||
/** | ||
* Simple way to add autocompletion to a command line editor. | ||
* Based on MavenArgumentsCompletionProvider used in MavenBeforeRunTasksProvider | ||
* Note that there is a similar (and better) solution for fragments, see MavenRunConfigurationSettingsEditor#addCommandLineFragment | ||
*/ | ||
class LatexArgumentsCompletionProvider(options: Options) : CommandLineCompletionProvider(options) { | ||
|
||
override fun addArgumentVariants(result: CompletionResultSet) { | ||
// Here we can add things to the autocompletion without the - or -- prefix, for example: | ||
// result.addAllElements(listOf("one", "two").map { LookupElementBuilder.create(it) }) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
test/nl/hannahsten/texifyidea/run/LatexCompilerOptionsParserTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package nl.hannahsten.texifyidea.run | ||
|
||
import com.intellij.testFramework.fixtures.BasePlatformTestCase | ||
import nl.hannahsten.texifyidea.run.latex.LatexCommandLineOptionsCache | ||
|
||
class LatexCompilerOptionsParserTest : BasePlatformTestCase() { | ||
|
||
fun testPdflatex() { | ||
val output = """ | ||
Usage: pdftex [OPTION]... [TEXNAME[.tex]] [COMMANDS] | ||
or: pdftex [OPTION]... \FIRST-LINE | ||
or: pdftex [OPTION]... &FMT ARGS | ||
Run pdfTeX on TEXNAME, usually creating TEXNAME.pdf. | ||
If no arguments or options are specified, prompt for input. | ||
(...) | ||
-cnf-line=STRING parse STRING as a configuration file line | ||
-etex enable e-TeX extensions | ||
[-no]-file-line-error disable/enable file:line:error style messages | ||
""".trimIndent() | ||
val options = LatexCommandLineOptionsCache.parseHelpOutput("pdflatex", output) | ||
assertEquals( | ||
listOf( | ||
Pair("cnf-line=STRING", "parse STRING as a configuration file line"), | ||
Pair("etex", "enable e-TeX extensions"), | ||
Pair("file-line-error", "disable/enable file:line:error style messages"), | ||
Pair("no-file-line-error", "disable/enable file:line:error style messages"), | ||
), | ||
options | ||
) | ||
} | ||
|
||
fun testLualatex() { | ||
val output = """ | ||
Usage: luahbtex --lua=FILE [OPTION]... [TEXNAME[.tex]] [COMMANDS] | ||
or: luahbtex --lua=FILE [OPTION]... \FIRST-LINE | ||
or: luahbtex --lua=FILE [OPTION]... &FMT ARGS | ||
Run LuaHBTeX on TEXNAME, usually creating TEXNAME.pdf. | ||
(...) | ||
--cnf-line =STRING parse STRING as a configuration file line | ||
--debug-format enable format debugging | ||
--[no-]file-line-error disable/enable file:line:error style messages | ||
""".trimIndent() | ||
val options = LatexCommandLineOptionsCache.parseHelpOutput("lualatex", output) | ||
assertEquals( | ||
listOf( | ||
// I don't know, maybe a typo in lualatex? | ||
Pair("cnf-line", "=STRING parse STRING as a configuration file line"), | ||
Pair("debug-format", "enable format debugging"), | ||
Pair("file-line-error", "disable/enable file:line:error style messages"), | ||
Pair("no-file-line-error", "disable/enable file:line:error style messages"), | ||
), | ||
options | ||
) | ||
} | ||
|
||
fun testLatexmk() { | ||
val output = """ | ||
Latexmk 4.83: Automatic LaTeX document generation routine | ||
Usage: latexmk [latexmk_options] [filename ...] | ||
Latexmk_options: | ||
-bibtex - use bibtex when needed (default) | ||
-bibtex- - never use bibtex | ||
-bibfudge- or -bibtexfudge- - don't change directory when running bibtex | ||
""".trimIndent() | ||
val options = LatexCommandLineOptionsCache.parseHelpOutput("latexmk", output) | ||
assertEquals( | ||
listOf( | ||
Pair("bibtex", "use bibtex when needed (default)"), | ||
Pair("bibtex-", "never use bibtex"), | ||
Pair("bibfudge-", "don't change directory when running bibtex"), | ||
Pair("bibtexfudge-", "don't change directory when running bibtex"), | ||
), | ||
options | ||
) | ||
} | ||
} |