From 24f159329408182ed7e52b8df20ee7b5f2cbee9e Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Wed, 11 Dec 2024 21:31:40 +0100 Subject: [PATCH 01/14] Add missing glossary reference inspection --- .../inspections/latex/code-maturity.xml | 4 ++ .../LatexMissingGlossaryReference.html | 10 ++++ ...LatexMissingGlossaryReferenceInspection.kt | 60 +++++++++++++++++++ .../lang/commands/LatexGlossariesCommand.kt | 18 ++++++ .../texifyidea/util/magic/CommandMagic.kt | 1 + ...xMissingGlossaryReferenceInspectionTest.kt | 23 +++++++ 6 files changed, 116 insertions(+) create mode 100644 resources/inspectionDescriptions/LatexMissingGlossaryReference.html create mode 100644 src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt create mode 100644 test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt diff --git a/resources/META-INF/extensions/inspections/latex/code-maturity.xml b/resources/META-INF/extensions/inspections/latex/code-maturity.xml index 705b251f6e..a3b54d6fb6 100644 --- a/resources/META-INF/extensions/inspections/latex/code-maturity.xml +++ b/resources/META-INF/extensions/inspections/latex/code-maturity.xml @@ -24,5 +24,9 @@ groupPath="LaTeX" groupName="Code maturity" displayName="Discouraged use of \makeatletter in tex sources" enabledByDefault="true" level="WARNING" /> + \ No newline at end of file diff --git a/resources/inspectionDescriptions/LatexMissingGlossaryReference.html b/resources/inspectionDescriptions/LatexMissingGlossaryReference.html new file mode 100644 index 0000000000..711864e3ea --- /dev/null +++ b/resources/inspectionDescriptions/LatexMissingGlossaryReference.html @@ -0,0 +1,10 @@ + + +Reports occurrences of glossary entries that are not marked with a \gls command. + +

+ When using a glossary, it is good practice to reference every glossary entry with a \gls-like command. + This makes sure that the list of pages with occurrences in the glossary is complete. +

+ + \ No newline at end of file diff --git a/src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt b/src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt new file mode 100644 index 0000000000..1872d6ef8e --- /dev/null +++ b/src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt @@ -0,0 +1,60 @@ +package nl.hannahsten.texifyidea.inspections.latex.codematurity + +import com.intellij.codeInspection.InspectionManager +import com.intellij.codeInspection.LocalQuickFix +import com.intellij.codeInspection.ProblemDescriptor +import com.intellij.codeInspection.ProblemHighlightType +import com.intellij.openapi.project.Project +import com.intellij.psi.PsiFile +import nl.hannahsten.texifyidea.index.LatexGlossaryEntryIndex +import nl.hannahsten.texifyidea.inspections.InsightGroup +import nl.hannahsten.texifyidea.inspections.TexifyInspectionBase +import nl.hannahsten.texifyidea.lang.commands.LatexGlossariesCommand +import nl.hannahsten.texifyidea.psi.LatexNormalText +import nl.hannahsten.texifyidea.util.parser.childrenOfType +import nl.hannahsten.texifyidea.util.toTextRange + +/** + * Glossary entries should be referenced for all occurrences. + */ +class LatexMissingGlossaryReferenceInspection : TexifyInspectionBase() { + override val inspectionGroup = InsightGroup.LATEX + override val inspectionId = "MissingGlossaryReference" + override fun getDisplayName() = "Missing glossary reference" + + override fun inspectFile(file: PsiFile, manager: InspectionManager, isOntheFly: Boolean): List { + val descriptors = mutableListOf() + val names = LatexGlossaryEntryIndex.Util.getItemsInFileSet(file).mapNotNull { LatexGlossariesCommand.extractGlossaryName(it) } + // Unfortunately the lowest level we have is a block of text, so we have to do a text-based search + file.childrenOfType().forEach { textElement -> + val text = textElement.text + names.forEach { name -> + val correctOccurrences = "\\\\gls[^{]+\\{($name)}".toRegex().findAll(text).mapNotNull { it.groups.firstOrNull()?.range } + val allOccurrences = name.toRegex().findAll(text).map { it.range } + allOccurrences.filter { !correctOccurrences.contains(it) }.forEach { range -> + descriptors.add(manager.createProblemDescriptor( + textElement, + range.toTextRange(), + "Missing glossary reference", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + isOntheFly, + AddGlsFix(), + )) + } + + } + } + return descriptors + } + + private class AddGlsFix : LocalQuickFix { + override fun getFamilyName(): String { + TODO("Not yet implemented") + } + + override fun applyFix(project: Project, descriptor: ProblemDescriptor) { + TODO("Not yet implemented") + } + + } +} \ No newline at end of file diff --git a/src/nl/hannahsten/texifyidea/lang/commands/LatexGlossariesCommand.kt b/src/nl/hannahsten/texifyidea/lang/commands/LatexGlossariesCommand.kt index 248c5204b1..40b0e32626 100644 --- a/src/nl/hannahsten/texifyidea/lang/commands/LatexGlossariesCommand.kt +++ b/src/nl/hannahsten/texifyidea/lang/commands/LatexGlossariesCommand.kt @@ -5,7 +5,9 @@ import nl.hannahsten.texifyidea.lang.LatexPackage import nl.hannahsten.texifyidea.psi.LatexCommands import nl.hannahsten.texifyidea.psi.LatexParameterText import nl.hannahsten.texifyidea.util.magic.CommandMagic +import nl.hannahsten.texifyidea.util.magic.cmd import nl.hannahsten.texifyidea.util.parser.firstChildOfType +import nl.hannahsten.texifyidea.util.parser.requiredParameter import nl.hannahsten.texifyidea.util.parser.requiredParameters enum class LatexGlossariesCommand( @@ -80,5 +82,21 @@ enum class LatexGlossariesCommand( if (!CommandMagic.glossaryEntry.contains(command.name)) return null return command.requiredParameters()[0].firstChildOfType(LatexParameterText::class) } + + /** + * Find the name, which is the text that will appear in the document, from the given glossary entry definition. + */ + fun extractGlossaryName(command: LatexCommands): String? { + if (setOf(NEWGLOSSARYENTRY, LONGNEWGLOSSARYENTRY).map { it.cmd }.contains(command.name)) { + val keyValueList = command.requiredParameter(1) ?: return null + return "name=\\{([^}]+)}".toRegex().find(keyValueList)?.groupValues?.get(1) + } + else if (setOf(NEWACRONYM, NEWABBREVIATION).map { it.cmd }.contains(command.name)) { + return command.requiredParameter(1) + } + else { + return null + } + } } } \ No newline at end of file diff --git a/src/nl/hannahsten/texifyidea/util/magic/CommandMagic.kt b/src/nl/hannahsten/texifyidea/util/magic/CommandMagic.kt index dece03b37d..46faf3e9c3 100644 --- a/src/nl/hannahsten/texifyidea/util/magic/CommandMagic.kt +++ b/src/nl/hannahsten/texifyidea/util/magic/CommandMagic.kt @@ -193,6 +193,7 @@ object CommandMagic { /** * All commands that define a glossary entry of the glossaries package (e.g. \newacronym). + * When adding a command, define how to get the glossary name in [nl.hannahsten.texifyidea.lang.commands.LatexGlossariesCommand.extractGlossaryName]. */ val glossaryEntry = hashSetOf(NEWGLOSSARYENTRY, LONGNEWGLOSSARYENTRY, NEWACRONYM, NEWABBREVIATION).map { it.cmd }.toSet() diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt new file mode 100644 index 0000000000..2011e60437 --- /dev/null +++ b/test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt @@ -0,0 +1,23 @@ +package nl.hannahsten.texifyidea.inspections.latex.codematurity + +import nl.hannahsten.texifyidea.file.LatexFileType +import nl.hannahsten.texifyidea.inspections.TexifyInspectionTestBase + +class LatexMissingGlossaryReferenceInspectionTest : TexifyInspectionTestBase(LatexMissingGlossaryReferenceInspection()) { + + fun testMissingReference() { + myFixture.configureByText(LatexFileType, """\newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} sample""") + myFixture.checkHighlighting() + } + + fun testAddGls() { + testQuickFix( + """ + \newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} sample + """.trimIndent(), + """ + \newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} \gls{sample} + """.trimIndent() + ) + } +} \ No newline at end of file From 7d4c7044b0b6b4d3fca0bf72234656738f100fe4 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Thu, 12 Dec 2024 20:15:24 +0100 Subject: [PATCH 02/14] Update to 2024.3 --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index 209ff7a64e..7412250e6c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -96,7 +96,7 @@ dependencies { testFramework(TestFrameworkType.Platform) testFramework(TestFrameworkType.Plugin.Java) - intellijIdeaCommunity("2024.2.3") + intellijIdeaCommunity("2024.3.1") // Docs: https://github.com/JetBrains/gradle-intellij-plugin#intellij-platform-properties // All snapshot versions: https://www.jetbrains.com/intellij-repository/snapshots/ From 07e3f08a1724571cea7f852836974582b964e602 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Thu, 12 Dec 2024 20:46:13 +0100 Subject: [PATCH 03/14] Add quickfix --- CHANGELOG.md | 1 + Writerside/topics/Typesetting-issues.md | 8 ++++- .../inspections/latex/code-maturity.xml | 4 --- .../latex/typesetting/typesetting.xml | 4 +++ ...LatexMissingGlossaryReferenceInspection.kt | 34 +++++++++++-------- ...xMissingGlossaryReferenceInspectionTest.kt | 8 ++--- 6 files changed, 35 insertions(+), 24 deletions(-) rename src/nl/hannahsten/texifyidea/inspections/latex/{codematurity => typesetting}/LatexMissingGlossaryReferenceInspection.kt (68%) rename test/nl/hannahsten/texifyidea/inspections/latex/{codematurity => typesetting}/LatexMissingGlossaryReferenceInspectionTest.kt (75%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7975c0b53b..a0613a32b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Added +* Add inspection to warn about a missing reference for a glossary occurrence ### Fixed * Fix LaTeX files not showing up when choosing main file in run configuration diff --git a/Writerside/topics/Typesetting-issues.md b/Writerside/topics/Typesetting-issues.md index b5414bd243..acb3c80925 100644 --- a/Writerside/topics/Typesetting-issues.md +++ b/Writerside/topics/Typesetting-issues.md @@ -41,4 +41,10 @@ For example, instead of `(\frac 1 2)` write `\left(\frac 1 2\right)`. ## Citations must be placed before interpunction -Use `Sentence~\cite{knuth1990}.` and not `Sentence.~\cite{knuth1990}` \ No newline at end of file +Use `Sentence~\cite{knuth1990}.` and not `Sentence.~\cite{knuth1990}` + +## Missing glossary reference + +When using a glossary, it is good practice to reference every glossary entry with a \gls-like command. +This makes sure that the list of pages with occurrences in the glossary is complete. +For examples on how to use a glossary, see [External tools](External-tools.md#glossary-examples). \ No newline at end of file diff --git a/resources/META-INF/extensions/inspections/latex/code-maturity.xml b/resources/META-INF/extensions/inspections/latex/code-maturity.xml index a3b54d6fb6..705b251f6e 100644 --- a/resources/META-INF/extensions/inspections/latex/code-maturity.xml +++ b/resources/META-INF/extensions/inspections/latex/code-maturity.xml @@ -24,9 +24,5 @@ groupPath="LaTeX" groupName="Code maturity" displayName="Discouraged use of \makeatletter in tex sources" enabledByDefault="true" level="WARNING" /> - \ No newline at end of file diff --git a/resources/META-INF/extensions/inspections/latex/typesetting/typesetting.xml b/resources/META-INF/extensions/inspections/latex/typesetting/typesetting.xml index 40b4b4a8c8..bf3a90c803 100644 --- a/resources/META-INF/extensions/inspections/latex/typesetting/typesetting.xml +++ b/resources/META-INF/extensions/inspections/latex/typesetting/typesetting.xml @@ -44,5 +44,9 @@ groupPath="LaTeX" groupName="Typesetting issues" displayName="Incorrectly typeset quotation marks" enabledByDefault="true" level="WARNING" /> + \ No newline at end of file diff --git a/src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt b/src/nl/hannahsten/texifyidea/inspections/latex/typesetting/LatexMissingGlossaryReferenceInspection.kt similarity index 68% rename from src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt rename to src/nl/hannahsten/texifyidea/inspections/latex/typesetting/LatexMissingGlossaryReferenceInspection.kt index 1872d6ef8e..877e3161c2 100644 --- a/src/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspection.kt +++ b/src/nl/hannahsten/texifyidea/inspections/latex/typesetting/LatexMissingGlossaryReferenceInspection.kt @@ -1,4 +1,4 @@ -package nl.hannahsten.texifyidea.inspections.latex.codematurity +package nl.hannahsten.texifyidea.inspections.latex.typesetting import com.intellij.codeInspection.InspectionManager import com.intellij.codeInspection.LocalQuickFix @@ -11,6 +11,7 @@ import nl.hannahsten.texifyidea.inspections.InsightGroup import nl.hannahsten.texifyidea.inspections.TexifyInspectionBase import nl.hannahsten.texifyidea.lang.commands.LatexGlossariesCommand import nl.hannahsten.texifyidea.psi.LatexNormalText +import nl.hannahsten.texifyidea.psi.LatexPsiHelper import nl.hannahsten.texifyidea.util.parser.childrenOfType import nl.hannahsten.texifyidea.util.toTextRange @@ -32,29 +33,32 @@ class LatexMissingGlossaryReferenceInspection : TexifyInspectionBase() { val correctOccurrences = "\\\\gls[^{]+\\{($name)}".toRegex().findAll(text).mapNotNull { it.groups.firstOrNull()?.range } val allOccurrences = name.toRegex().findAll(text).map { it.range } allOccurrences.filter { !correctOccurrences.contains(it) }.forEach { range -> - descriptors.add(manager.createProblemDescriptor( - textElement, - range.toTextRange(), - "Missing glossary reference", - ProblemHighlightType.GENERIC_ERROR_OR_WARNING, - isOntheFly, - AddGlsFix(), - )) + descriptors.add( + manager.createProblemDescriptor( + textElement, + range.toTextRange(), + "Missing glossary reference", + ProblemHighlightType.GENERIC_ERROR_OR_WARNING, + isOntheFly, + AddGlsFix(), + ) + ) } - } } return descriptors } private class AddGlsFix : LocalQuickFix { - override fun getFamilyName(): String { - TODO("Not yet implemented") - } + override fun getFamilyName() = "Add \\gls command" override fun applyFix(project: Project, descriptor: ProblemDescriptor) { - TODO("Not yet implemented") - } + val range = descriptor.textRangeInElement + val newText = descriptor.psiElement.text.replaceRange(range.endOffset, range.endOffset, "}") + .replaceRange(range.startOffset, range.startOffset, "\\gls{") + val newElement = LatexPsiHelper(project).createFromText(newText).firstChild + descriptor.psiElement.replace(newElement) + } } } \ No newline at end of file diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/typesetting/LatexMissingGlossaryReferenceInspectionTest.kt similarity index 75% rename from test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt rename to test/nl/hannahsten/texifyidea/inspections/latex/typesetting/LatexMissingGlossaryReferenceInspectionTest.kt index 2011e60437..03f515e672 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/codematurity/LatexMissingGlossaryReferenceInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/typesetting/LatexMissingGlossaryReferenceInspectionTest.kt @@ -1,4 +1,4 @@ -package nl.hannahsten.texifyidea.inspections.latex.codematurity +package nl.hannahsten.texifyidea.inspections.latex.typesetting import nl.hannahsten.texifyidea.file.LatexFileType import nl.hannahsten.texifyidea.inspections.TexifyInspectionTestBase @@ -6,17 +6,17 @@ import nl.hannahsten.texifyidea.inspections.TexifyInspectionTestBase class LatexMissingGlossaryReferenceInspectionTest : TexifyInspectionTestBase(LatexMissingGlossaryReferenceInspection()) { fun testMissingReference() { - myFixture.configureByText(LatexFileType, """\newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} sample""") + myFixture.configureByText(LatexFileType, """\newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} \Glslink{sample} sample""") myFixture.checkHighlighting() } fun testAddGls() { testQuickFix( """ - \newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} sample + \newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} sample text """.trimIndent(), """ - \newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} \gls{sample} + \newglossaryentry{sample}{name={sample},description={an example}} \gls{sample} \gls{sample} text """.trimIndent() ) } From ffc5181a02d7c1f48e8ed91c7903f397a8eba226 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Fri, 13 Dec 2024 10:59:34 +0100 Subject: [PATCH 04/14] Replace deprecated FileTypeDescriptor --- .../run/bibtex/BibtexSettingsEditor.kt | 6 ++++-- .../externaltool/ExternalToolSettingsEditor.kt | 6 ++++-- .../run/latex/ui/LatexSettingsEditor.kt | 17 ++++++++++------- .../run/makeindex/MakeindexSettingsEditor.kt | 6 ++++-- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/nl/hannahsten/texifyidea/run/bibtex/BibtexSettingsEditor.kt b/src/nl/hannahsten/texifyidea/run/bibtex/BibtexSettingsEditor.kt index f029f34501..0b3ea053cf 100644 --- a/src/nl/hannahsten/texifyidea/run/bibtex/BibtexSettingsEditor.kt +++ b/src/nl/hannahsten/texifyidea/run/bibtex/BibtexSettingsEditor.kt @@ -2,7 +2,7 @@ package nl.hannahsten.texifyidea.run.bibtex import com.intellij.execution.configuration.EnvironmentVariablesComponent import com.intellij.openapi.fileChooser.FileChooserDescriptor -import com.intellij.openapi.fileChooser.FileTypeDescriptor +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory import com.intellij.openapi.options.SettingsEditor import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectRootManager @@ -108,7 +108,9 @@ class BibtexSettingsEditor(private val project: Project) : SettingsEditor Date: Fri, 13 Dec 2024 11:10:26 +0100 Subject: [PATCH 05/14] Copy deleted MockInlineMethodOptions --- .../texifyidea/refactoring/InlineFileTest.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/nl/hannahsten/texifyidea/refactoring/InlineFileTest.kt b/test/nl/hannahsten/texifyidea/refactoring/InlineFileTest.kt index d2a3f68e9e..1bc3243bca 100644 --- a/test/nl/hannahsten/texifyidea/refactoring/InlineFileTest.kt +++ b/test/nl/hannahsten/texifyidea/refactoring/InlineFileTest.kt @@ -6,10 +6,8 @@ import com.intellij.openapi.util.io.FileUtilRt import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.psi.PsiFileFactory import com.intellij.refactoring.BaseRefactoringProcessor.ConflictsInTestsException -import com.intellij.refactoring.MockInlineMethodOptions import com.intellij.refactoring.inline.InlineOptions import com.intellij.testFramework.LightPlatformCodeInsightTestCase -import junit.framework.TestCase import nl.hannahsten.texifyidea.file.LatexFileType import nl.hannahsten.texifyidea.refactoring.inlinecommand.LatexInlineCommandHandler.Util.getReference import nl.hannahsten.texifyidea.refactoring.inlinefile.LatexInlineFileHandler.Util.canInlineLatexElement @@ -127,7 +125,7 @@ class InlineFileTest : LightPlatformCodeInsightTestCase() { private fun configure(testIndex: Int? = null): String { @NonNls val fileName = getTestName(false) + (testIndex ?: "") + ".tex" configureByFile(fileName) - TestCase.assertTrue(file.parent != null) + assertTrue(file.parent != null) if (file.parent?.children?.any { it.containingFile.name == inlineFile } == false) { val ioFile = File(testDataPath + inlineFile) checkCaseSensitiveFS(testDataPath + inlineFile, ioFile) @@ -182,4 +180,12 @@ class InlineFileTest : LightPlatformCodeInsightTestCase() { ) processor.run() } + + open class MockInlineMethodOptions : InlineOptions { + override fun isInlineThisOnly() = false + + override fun close(p0: Int) {} + + override fun isPreviewUsages() = false + } } \ No newline at end of file From ff3ca4c1d12c92c4cc4f6fb013fcc41239051f82 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Fri, 13 Dec 2024 14:27:03 +0100 Subject: [PATCH 06/14] DeclareGraphicsExtensions --- CHANGELOG.md | 1 + .../LatexFileNotFoundInspection.kt | 4 +-- .../commands/LatexGenericRegularCommand.kt | 1 + .../lang/commands/RequiredFileArgument.kt | 7 +---- .../reference/InputFileReference.kt | 28 ++++++++++++++++-- .../util/parser/LatexCommandsImplMixinUtil.kt | 4 +-- .../texifyidea/gutter/LatexGutterTest.kt | 12 +++++--- test/resources/gutter/GraphicsExtensions.tex | 8 +++++ test/resources/gutter/figures/duck.pdf | Bin 0 -> 12742 bytes test/resources/gutter/figures/duck.png | Bin 0 -> 17373 bytes 10 files changed, 48 insertions(+), 17 deletions(-) create mode 100644 test/resources/gutter/GraphicsExtensions.tex create mode 100644 test/resources/gutter/figures/duck.pdf create mode 100644 test/resources/gutter/figures/duck.png diff --git a/CHANGELOG.md b/CHANGELOG.md index d7b719f61c..f93b0c1fce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## [Unreleased] ### Added +* Add support for DeclareGraphicsExtensions * Include optional parameters in spellcheck, if it contains text ### Fixed diff --git a/src/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspection.kt b/src/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspection.kt index e13a9fb52f..7345b34ef2 100644 --- a/src/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspection.kt +++ b/src/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspection.kt @@ -81,8 +81,8 @@ open class LatexFileNotFoundInspection : TexifyInspectionBase() { // Find expected extension val extension = fileName.getFileExtension().ifEmpty { - reference.defaultExtension - } + reference.extensions.firstOrNull() + } ?: "tex" descriptors.add( manager.createProblemDescriptor( diff --git a/src/nl/hannahsten/texifyidea/lang/commands/LatexGenericRegularCommand.kt b/src/nl/hannahsten/texifyidea/lang/commands/LatexGenericRegularCommand.kt index 3cc09bcb29..83522ac090 100644 --- a/src/nl/hannahsten/texifyidea/lang/commands/LatexGenericRegularCommand.kt +++ b/src/nl/hannahsten/texifyidea/lang/commands/LatexGenericRegularCommand.kt @@ -77,6 +77,7 @@ enum class LatexGenericRegularCommand( TEXT_DAGGER("dag", display = "†"), TEXT_DOUBLE_DAGGER("ddag", display = "‡"), DATE("date", "text".asRequired(Argument.Type.TEXT)), + DECLAREGRAPHICSEXTENSIONS("DeclareGraphicsExtensions", "extensions".asRequired(), dependency = GRAPHICX), DECLARE_MATH_OPERATOR("DeclareMathOperator", "command".asRequired(), "operator".asRequired(Argument.Type.TEXT), dependency = AMSMATH), DEF("def"), DOCUMENTCLASS("documentclass", "options".asOptional(), RequiredFileArgument("class", true, false, "cls")), diff --git a/src/nl/hannahsten/texifyidea/lang/commands/RequiredFileArgument.kt b/src/nl/hannahsten/texifyidea/lang/commands/RequiredFileArgument.kt index 8cbf230e45..acb2b5b9db 100644 --- a/src/nl/hannahsten/texifyidea/lang/commands/RequiredFileArgument.kt +++ b/src/nl/hannahsten/texifyidea/lang/commands/RequiredFileArgument.kt @@ -22,8 +22,6 @@ import java.util.regex.Pattern open class RequiredFileArgument(name: String?, open val isAbsolutePathSupported: Boolean = true, open val commaSeparatesArguments: Boolean, vararg extensions: String, open val supportsAnyExtension: Boolean = true) : RequiredArgument(name!!, Type.FILE), FileNameMatcher, FileExtensionMatcher { lateinit var supportedExtensions: List - lateinit var defaultExtension: String - private set private var pattern: Pattern? = null init { @@ -44,12 +42,9 @@ open class RequiredFileArgument(name: String?, open val isAbsolutePathSupported: if (extensions.isEmpty()) { setRegex(regex.toString()) this.supportedExtensions = supportedExtensions - this.defaultExtension = "" return } - else { - defaultExtension = extensions[0] - } + regex.append("(") for (extension in extensions) { regex.append("\\.") diff --git a/src/nl/hannahsten/texifyidea/reference/InputFileReference.kt b/src/nl/hannahsten/texifyidea/reference/InputFileReference.kt index 3866b0888a..55d1b802d3 100644 --- a/src/nl/hannahsten/texifyidea/reference/InputFileReference.kt +++ b/src/nl/hannahsten/texifyidea/reference/InputFileReference.kt @@ -8,25 +8,27 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager import com.intellij.psi.PsiReferenceBase +import com.intellij.psi.search.GlobalSearchScope import nl.hannahsten.texifyidea.algorithm.BFS import nl.hannahsten.texifyidea.completion.pathcompletion.LatexGraphicsPathProvider +import nl.hannahsten.texifyidea.index.LatexCommandsIndex +import nl.hannahsten.texifyidea.lang.LatexPackage +import nl.hannahsten.texifyidea.lang.commands.LatexCommand import nl.hannahsten.texifyidea.lang.commands.LatexGenericRegularCommand import nl.hannahsten.texifyidea.psi.LatexCommands import nl.hannahsten.texifyidea.psi.LatexPsiHelper import nl.hannahsten.texifyidea.util.* import nl.hannahsten.texifyidea.util.files.* import nl.hannahsten.texifyidea.util.magic.CommandMagic +import nl.hannahsten.texifyidea.util.parser.requiredParameter /** * Reference to a file, based on the command and the range of the filename within the command text. - * - * @param defaultExtension Default extension of the command in which this reference is, in case the argument does not have an extension. */ class InputFileReference( element: LatexCommands, val range: TextRange, val extensions: List, - val defaultExtension: String, val supportsAnyExtension: Boolean, ) : PsiReferenceBase(element) { @@ -122,6 +124,26 @@ class InputFileReference( } } + // Overrides the default for commands from the graphicx package + val extensions = if (!isBuildingFileset) { + val command = LatexCommand.lookup(element.name)?.firstOrNull() + if (command?.dependency == LatexPackage.GRAPHICX) { + // We cannot use the file set at this point, so we take the first command in the project and hope for the best + LatexCommandsIndex.Util.getCommandsByName(LatexGenericRegularCommand.DECLAREGRAPHICSEXTENSIONS.command, element.project, GlobalSearchScope.projectScope(element.project)) + .firstOrNull() + ?.requiredParameter(0) + ?.split(",") + // Graphicx requires the dot to be included + ?.map { it.trim(' ', '.') } ?: extensions + } + else { + extensions + } + } + else { + extensions + } + var processedKey = expandCommandsOnce(key, element.project, file = rootFiles.firstOrNull()?.psiFile(element.project)) ?: key // Leading and trailing whitespaces seem to be ignored, at least it holds for \include-like commands processedKey = processedKey.trim() diff --git a/src/nl/hannahsten/texifyidea/util/parser/LatexCommandsImplMixinUtil.kt b/src/nl/hannahsten/texifyidea/util/parser/LatexCommandsImplMixinUtil.kt index 5efd15c18c..1809827700 100644 --- a/src/nl/hannahsten/texifyidea/util/parser/LatexCommandsImplMixinUtil.kt +++ b/src/nl/hannahsten/texifyidea/util/parser/LatexCommandsImplMixinUtil.kt @@ -60,7 +60,7 @@ fun LatexCommands.getFileArgumentsReferences(): List { } for (subParamRange in subParamRanges) { - inputFileReferences.add(InputFileReference(this, subParamRange, extensions, fileArgument.defaultExtension, supportsAnyExtension = true)) + inputFileReferences.add(InputFileReference(this, subParamRange, extensions, supportsAnyExtension = fileArgument.supportsAnyExtension)) } } @@ -69,7 +69,7 @@ fun LatexCommands.getFileArgumentsReferences(): List { if (name == LatexGenericRegularCommand.DOCUMENTCLASS.cmd && SUBFILES.name in getRequiredParameters() && getOptionalParameterMap().isNotEmpty()) { val range = this.firstChildOfType(LatexParameter::class)?.textRangeInParent if (range != null) { - inputFileReferences.add(InputFileReference(this, range.shrink(1), listOf("tex"), "tex", supportsAnyExtension = true)) + inputFileReferences.add(InputFileReference(this, range.shrink(1), listOf("tex"), supportsAnyExtension = true)) } } diff --git a/test/nl/hannahsten/texifyidea/gutter/LatexGutterTest.kt b/test/nl/hannahsten/texifyidea/gutter/LatexGutterTest.kt index 9908b1b7ca..0756167985 100644 --- a/test/nl/hannahsten/texifyidea/gutter/LatexGutterTest.kt +++ b/test/nl/hannahsten/texifyidea/gutter/LatexGutterTest.kt @@ -7,8 +7,8 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.testFramework.fixtures.BasePlatformTestCase import io.mockk.every import io.mockk.mockkStatic +import nl.hannahsten.texifyidea.TexifyIcons import nl.hannahsten.texifyidea.util.runCommandWithExitCode -import org.junit.Test class LatexGutterTest : BasePlatformTestCase() { @@ -22,7 +22,6 @@ class LatexGutterTest : BasePlatformTestCase() { return "test/resources/gutter" } - @Test fun testShowCompileGutter() { val testName = getTestName(false) val gutters = myFixture.findAllGutters("$testName.tex") @@ -30,7 +29,13 @@ class LatexGutterTest : BasePlatformTestCase() { assertEquals("Compile document", gutters.first().tooltipText) } - @Test + fun testGraphicsExtensions() { + val testName = getTestName(false) + myFixture.copyDirectoryToProject("figures", "figures") + val gutters = myFixture.findAllGutters("$testName.tex") + assertEquals(TexifyIcons.FILE, gutters.last().icon) + } + fun testShowMethodSeparators() { val testName = getTestName(false) withLineMarkersEnabled { @@ -44,7 +49,6 @@ class LatexGutterTest : BasePlatformTestCase() { } } - @Test fun testShowNavigationGutter() { val testName = getTestName(false) myFixture.configureByFile("$testName.tex") diff --git a/test/resources/gutter/GraphicsExtensions.tex b/test/resources/gutter/GraphicsExtensions.tex new file mode 100644 index 0000000000..0e019f1eb0 --- /dev/null +++ b/test/resources/gutter/GraphicsExtensions.tex @@ -0,0 +1,8 @@ +\documentclass{article} + +\usepackage{graphicx} +\DeclareGraphicsExtensions{.png, .pdf} + +\begin{document} + \includegraphics{figures/duck} +\end{document} diff --git a/test/resources/gutter/figures/duck.pdf b/test/resources/gutter/figures/duck.pdf new file mode 100644 index 0000000000000000000000000000000000000000..77e9d96857574dd7978621ba52d70b34cbd7758b GIT binary patch literal 12742 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%0D`~A+7%ECZAVLd-ezp&xs@~NwtVK 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 literal 0 HcmV?d00001 From ca8586e014ca3fbba58fd4a91726ffbc53ff4f6e Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Fri, 13 Dec 2024 20:39:31 +0100 Subject: [PATCH 07/14] Search for external bib files in background --- .../file/LatexIndexableSetContributor.kt | 37 +++++++------------ 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt b/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt index cbc8bae9e3..55ac6800d1 100644 --- a/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt +++ b/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt @@ -17,6 +17,7 @@ import nl.hannahsten.texifyidea.util.getTexinputsPaths import nl.hannahsten.texifyidea.util.isTestProject import nl.hannahsten.texifyidea.util.magic.CommandMagic import nl.hannahsten.texifyidea.util.parser.requiredParameter +import nl.hannahsten.texifyidea.util.runInBackground import org.codehaus.plexus.archiver.ArchiverException import org.codehaus.plexus.archiver.tar.TarBZip2UnArchiver import org.codehaus.plexus.archiver.tar.TarXZUnArchiver @@ -73,31 +74,21 @@ class LatexIndexableSetContributor : IndexableSetContributor() { roots.addAll(getTexinputsPaths(project, rootFiles = listOf(), expandPaths = false).mapNotNull { LocalFileSystem.getInstance().findFileByPath(it) }) // Using the index while building it may be problematic, cache the result and hope it doesn't create too much trouble - if (Cache.externalDirectFileInclusions == null) { - if (!DumbService.isDumb(project)) { - try { - // For now, just do this for bibliography and direct input commands, as there this is most common - val externalFiles = LatexIncludesIndex.Util.getCommandsByNames(CommandMagic.includeOnlyExtensions.entries.filter { it.value.contains("bib") || it.value.contains("tex") }.map { it.key }.toSet(), project, GlobalSearchScope.projectScope(project)) - // We can't add single files, so take the parent - .mapNotNull { - val path = it.requiredParameter(0) ?: return@mapNotNull null - if (File(path).isAbsolute) { - LocalFileSystem.getInstance().findFileByPath(path)?.parent - } - else { - it.containingFile.parent?.virtualFile?.findFileByRelativePath(path)?.parent - } + if (Cache.externalDirectFileInclusions == null && !DumbService.isDumb(project)) { + runInBackground(project, "Searching for external bib files...") { + // For now, just do this for bibliography and direct input commands, as there this is most common + val externalFiles = LatexIncludesIndex.Util.getCommandsByNames(CommandMagic.includeOnlyExtensions.entries.filter { it.value.contains("bib") || it.value.contains("tex") }.map { it.key }.toSet(), project, GlobalSearchScope.projectScope(project)) + // We can't add single files, so take the parent + .mapNotNull { + val path = it.requiredParameter(0) ?: return@mapNotNull null + if (File(path).isAbsolute) { + LocalFileSystem.getInstance().findFileByPath(path)?.parent + } + else { + it.containingFile.parent?.virtualFile?.findFileByRelativePath(path)?.parent } - Cache.externalDirectFileInclusions = externalFiles.toSet() - } catch (e: Throwable) { - // This is very rare, but it can happen, in which case we will ignore and try again later - if (e.message?.contains("Indexing process should not rely on non-indexed file data") == true) { - Log.warn("Ignored index not ready: " + e.message) - } - else { - throw e } - } + Cache.externalDirectFileInclusions = externalFiles.toSet() } } roots.addAll(Cache.externalDirectFileInclusions?.filter { it.exists() } ?: emptyList()) From 815638f8403fd34094f524658b32a4fcf2933b17 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Fri, 13 Dec 2024 21:06:59 +0100 Subject: [PATCH 08/14] Add read actions --- .../index/file/LatexIndexableSetContributor.kt | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt b/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt index 55ac6800d1..70aef3cd79 100644 --- a/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt +++ b/src/nl/hannahsten/texifyidea/index/file/LatexIndexableSetContributor.kt @@ -1,5 +1,6 @@ package nl.hannahsten.texifyidea.index.file +import com.intellij.openapi.application.runReadAction import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.progress.Task.Backgroundable @@ -77,16 +78,20 @@ class LatexIndexableSetContributor : IndexableSetContributor() { if (Cache.externalDirectFileInclusions == null && !DumbService.isDumb(project)) { runInBackground(project, "Searching for external bib files...") { // For now, just do this for bibliography and direct input commands, as there this is most common - val externalFiles = LatexIncludesIndex.Util.getCommandsByNames(CommandMagic.includeOnlyExtensions.entries.filter { it.value.contains("bib") || it.value.contains("tex") }.map { it.key }.toSet(), project, GlobalSearchScope.projectScope(project)) + val commandNames = CommandMagic.includeOnlyExtensions.entries.filter { it.value.contains("bib") || it.value.contains("tex") }.map { it.key }.toSet() + val externalFiles = runReadAction { + LatexIncludesIndex.Util.getCommandsByNames(commandNames, project, GlobalSearchScope.projectScope(project)) + } // We can't add single files, so take the parent .mapNotNull { - val path = it.requiredParameter(0) ?: return@mapNotNull null - if (File(path).isAbsolute) { - LocalFileSystem.getInstance().findFileByPath(path)?.parent + val path = runReadAction { it.requiredParameter(0) } ?: return@mapNotNull null + val file = if (File(path).isAbsolute) { + LocalFileSystem.getInstance().findFileByPath(path) } else { - it.containingFile.parent?.virtualFile?.findFileByRelativePath(path)?.parent + runReadAction { it.containingFile.parent }?.virtualFile?.findFileByRelativePath(path) } + runReadAction { file?.parent } } Cache.externalDirectFileInclusions = externalFiles.toSet() } From 09bf0159076103a4f2e5557a84ef75ef5d2dbcbe Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Sat, 14 Dec 2024 12:00:31 +0100 Subject: [PATCH 09/14] Move test file to avoid "VfsRootAccess$VfsRootAccessNotAllowedError: File accessed outside allowed roots" --- .../latex/probablebugs/LatexFileNotFoundInspectionTest.kt | 2 +- test/resources/completion/path/myOtherPicture.PNG | 0 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 test/resources/completion/path/myOtherPicture.PNG diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt index fe159a6760..5577fa4b50 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt @@ -40,7 +40,7 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou } fun testValidAbsolutePathCaps() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/inspections/latex/filenotfound/myOtherPicture.PNG}""") + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myOtherPicture.PNG}""") myFixture.checkHighlighting() } diff --git a/test/resources/completion/path/myOtherPicture.PNG b/test/resources/completion/path/myOtherPicture.PNG new file mode 100644 index 0000000000..e69de29bb2 From 25b94024af526aa29384dcea886106accebd72fb Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Sat, 14 Dec 2024 12:13:26 +0100 Subject: [PATCH 10/14] Move file to avoid other test failure --- .../latex/probablebugs/LatexFileNotFoundInspectionTest.kt | 2 +- .../completion/path/{ => filenotfound}/myOtherPicture.PNG | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/resources/completion/path/{ => filenotfound}/myOtherPicture.PNG (100%) diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt index 5577fa4b50..6c744ed9b9 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt @@ -40,7 +40,7 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou } fun testValidAbsolutePathCaps() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myOtherPicture.PNG}""") + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/filenotfound/myOtherPicture.PNG}""") myFixture.checkHighlighting() } diff --git a/test/resources/completion/path/myOtherPicture.PNG b/test/resources/completion/path/filenotfound/myOtherPicture.PNG similarity index 100% rename from test/resources/completion/path/myOtherPicture.PNG rename to test/resources/completion/path/filenotfound/myOtherPicture.PNG From 541ff3c5a21220bef9e300a19b17dbf1b35942a6 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Sat, 14 Dec 2024 12:37:42 +0100 Subject: [PATCH 11/14] Revert "Move file to avoid other test failure" This reverts commit 25b94024af526aa29384dcea886106accebd72fb. --- .../latex/probablebugs/LatexFileNotFoundInspectionTest.kt | 2 +- .../completion/path/{filenotfound => }/myOtherPicture.PNG | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/resources/completion/path/{filenotfound => }/myOtherPicture.PNG (100%) diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt index 6c744ed9b9..5577fa4b50 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt @@ -40,7 +40,7 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou } fun testValidAbsolutePathCaps() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/filenotfound/myOtherPicture.PNG}""") + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myOtherPicture.PNG}""") myFixture.checkHighlighting() } diff --git a/test/resources/completion/path/filenotfound/myOtherPicture.PNG b/test/resources/completion/path/myOtherPicture.PNG similarity index 100% rename from test/resources/completion/path/filenotfound/myOtherPicture.PNG rename to test/resources/completion/path/myOtherPicture.PNG From 86c85327c13f9f4f10b07b9d6f9d71dbdd31befd Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Sat, 14 Dec 2024 12:37:42 +0100 Subject: [PATCH 12/14] Revert "Move test file to avoid "VfsRootAccess$VfsRootAccessNotAllowedError: File accessed outside allowed roots"" This reverts commit 09bf0159076103a4f2e5557a84ef75ef5d2dbcbe. --- .../latex/probablebugs/LatexFileNotFoundInspectionTest.kt | 2 +- test/resources/completion/path/myOtherPicture.PNG | 0 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 test/resources/completion/path/myOtherPicture.PNG diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt index 5577fa4b50..fe159a6760 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt @@ -40,7 +40,7 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou } fun testValidAbsolutePathCaps() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myOtherPicture.PNG}""") + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/inspections/latex/filenotfound/myOtherPicture.PNG}""") myFixture.checkHighlighting() } diff --git a/test/resources/completion/path/myOtherPicture.PNG b/test/resources/completion/path/myOtherPicture.PNG deleted file mode 100644 index e69de29bb2..0000000000 From a0cf1f2fb0ce6db4247a63de200b2d9269e11322 Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Sat, 14 Dec 2024 14:19:06 +0100 Subject: [PATCH 13/14] Another attempt to work around gh actions failure --- .../latex/probablebugs/LatexFileNotFoundInspectionTest.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt index fe159a6760..9cc87d176d 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt @@ -3,6 +3,7 @@ package nl.hannahsten.texifyidea.inspections.latex.probablebugs import io.mockk.every import io.mockk.mockkStatic import nl.hannahsten.texifyidea.file.LatexFileType +import nl.hannahsten.texifyidea.gutter.LatexNavigationGutter import nl.hannahsten.texifyidea.inspections.TexifyInspectionTestBase import nl.hannahsten.texifyidea.util.runCommandWithExitCode import java.io.File @@ -22,6 +23,8 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou super.setUp() mockkStatic(::runCommandWithExitCode) every { runCommandWithExitCode(*anyVararg(), workingDirectory = any(), timeout = any(), returnExceptionMessage = any()) } returns Pair(null, 0) + + mockkStatic(LatexNavigationGutter::collectNavigationMarkers) } override fun getTestDataPath(): String { From 12512a247a873454952f574cc1644a95036b10dd Mon Sep 17 00:00:00 2001 From: Thomas Schouten Date: Sun, 15 Dec 2024 11:52:52 +0100 Subject: [PATCH 14/14] Disable some broken tests on Windows --- .../LatexFileNotFoundInspectionTest.kt | 50 +++++++++++++------ 1 file changed, 34 insertions(+), 16 deletions(-) diff --git a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt index 9cc87d176d..f3a7322f37 100644 --- a/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt +++ b/test/nl/hannahsten/texifyidea/inspections/latex/probablebugs/LatexFileNotFoundInspectionTest.kt @@ -1,5 +1,6 @@ package nl.hannahsten.texifyidea.inspections.latex.probablebugs +import com.intellij.openapi.util.SystemInfo import io.mockk.every import io.mockk.mockkStatic import nl.hannahsten.texifyidea.file.LatexFileType @@ -32,29 +33,40 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou } fun testMissingAbsolutePath() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myPicture.myinvalidextension}""") - myFixture.checkHighlighting() + // Avoid "VfsRootAccess$VfsRootAccessNotAllowedError: File accessed outside allowed roots" on Windows in github actions + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myPicture.myinvalidextension}""") + myFixture.checkHighlighting() + } } fun testValidAbsolutePath() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myPicture.png}""") + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myPicture.png}""") - myFixture.checkHighlighting() + myFixture.checkHighlighting() + } } fun testValidAbsolutePathCaps() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/inspections/latex/filenotfound/myOtherPicture.PNG}""") - myFixture.checkHighlighting() + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/inspections/latex/filenotfound/myOtherPicture.PNG}""") + myFixture.checkHighlighting() + } } fun testBackActionAbsolute() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/../path/../path/myPicture.png}""") - myFixture.checkHighlighting() + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/../path/../path/myPicture.png}""") + myFixture.checkHighlighting() + } } fun testCurrDirActionAbsolute() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/./resources/./././completion/path/././myPicture.png}""") - myFixture.checkHighlighting() + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/./resources/./././completion/path/././myPicture.png}""") + myFixture.checkHighlighting() + } } fun testAbsoluteGraphicsDirWithInclude() { @@ -84,19 +96,25 @@ class LatexFileNotFoundInspectionTest : TexifyInspectionTestBase(LatexFileNotFou } fun testDefaultExtensionCompletion() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myPicture}""") - myFixture.checkHighlighting() + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myPicture}""") + myFixture.checkHighlighting() + } } fun testDefaultUpperCaseExtensionCompletion() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/inspections/latex/filenotfound/myOtherPicture}""") - myFixture.checkHighlighting() + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/inspections/latex/filenotfound/myOtherPicture}""") + myFixture.checkHighlighting() + } } fun testDefaultMixedCaseExtensionCompletion() { - myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myBadPicture}""") + if (!SystemInfo.isWindows) { + myFixture.configureByText(LatexFileType, """\includegraphics{$absoluteWorkingPath/test/resources/completion/path/myBadPicture}""") - myFixture.checkHighlighting() + myFixture.checkHighlighting() + } } fun testNoWarningInDefinition() {