Skip to content

Commit 57d6763

Browse files
Use IJ Platform infrastructure for executing processes
1 parent 16ebec0 commit 57d6763

File tree

7 files changed

+97
-77
lines changed

7 files changed

+97
-77
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.firsttimeinforever.intellij.pdf.viewer.tex
2+
3+
import com.firsttimeinforever.intellij.pdf.viewer.util.CommandExecutionUtils
4+
import com.intellij.execution.configurations.GeneralCommandLine
5+
import com.intellij.openapi.vfs.VirtualFile
6+
7+
object SynctexUtils {
8+
/**
9+
* Checks if there is a SyncTeX file in the same folder as [this] file,
10+
* with the same base name (until the first period).
11+
* When there is no such SyncTeX file, all SyncTeX features should be disabled.
12+
*
13+
* Call this function on a pdf file to check if it has an accompanying SyncTeX file in the same folder.
14+
*/
15+
fun VirtualFile.isSynctexFileAvailable(): Boolean {
16+
return parent.children
17+
.filter { it.name.contains("synctex") }
18+
.any { file ->
19+
file.name.takeWhile { it != '.' } == name.takeWhile { it != '.' }
20+
}
21+
}
22+
23+
/**
24+
* Check if the SyncTeX command line utility is installed by trying to execute a SyncTeX command.
25+
*/
26+
fun isSynctexInstalled(): Boolean {
27+
val output = CommandExecutionUtils.runCommand(GeneralCommandLine("synctex", "version")) ?: return false
28+
return output.stdout.contains("This is SyncTeX command line utility") ||
29+
output.stderr.contains("This is SyncTeX command line utility")
30+
}
31+
}

src/main/kotlin/com/firsttimeinforever/intellij/pdf/viewer/tex/TexFileInfo.kt

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package com.firsttimeinforever.intellij.pdf.viewer.tex
22

33
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.objects.SynctexInverseDataObject
4-
import com.firsttimeinforever.intellij.pdf.viewer.util.runCommand
4+
import com.firsttimeinforever.intellij.pdf.viewer.util.CommandExecutionUtils.getCommandStdoutIfSuccessful
5+
import com.intellij.execution.configurations.GeneralCommandLine
56
import com.intellij.openapi.application.runInEdt
67
import com.intellij.openapi.fileEditor.FileEditorManager
78
import com.intellij.openapi.fileEditor.OpenFileDescriptor
@@ -17,7 +18,6 @@ import java.io.File
1718
* aka inverse or backward search.
1819
*/
1920
class TexFileInfo(val file: VirtualFile, private val line: Int, private val column: Int) {
20-
2121
/**
2222
* Use SyncTeX to open the corresponding tex [file] at [line] and [column].
2323
*
@@ -64,16 +64,17 @@ class TexFileInfo(val file: VirtualFile, private val line: Int, private val colu
6464
fun fromSynctexInfoData(pdfFile: VirtualFile, data: SynctexInverseDataObject): TexFileInfo? {
6565
// Use presentableUrl instead of path to get a valid Windows path (with backslashes instead of forward slashes).
6666
val pdfDir = File(pdfFile.parent.presentableUrl)
67-
68-
val command = arrayOf(
69-
"synctex", "edit", "-o", "${data.page}:${data.x}:${data.y}:${pdfFile.presentableUrl}",
70-
)
71-
val synctexOutput = runCommand(*command, directory = pdfDir) ?: return null
72-
println(synctexOutput)
73-
val texPath = INPUT_REGEX.find(synctexOutput)?.groups?.get("file")?.value ?: return null
74-
val line = LINE_REGEX.find(synctexOutput)?.groups?.get("line")?.value?.toInt() ?: 1
75-
val column = COLUMN_REGEX.find(synctexOutput)?.groups?.get("col")?.value?.toInt() ?: 1
76-
67+
val command = GeneralCommandLine(
68+
"synctex",
69+
"edit",
70+
"-o",
71+
"${data.page}:${data.x}:${data.y}:${pdfFile.presentableUrl}"
72+
).withWorkDirectory(pdfDir)
73+
val output = getCommandStdoutIfSuccessful(command) ?: return null
74+
println(output)
75+
val texPath = INPUT_REGEX.find(output)?.groups?.get("file")?.value ?: return null
76+
val line = LINE_REGEX.find(output)?.groups?.get("line")?.value?.toInt() ?: 1
77+
val column = COLUMN_REGEX.find(output)?.groups?.get("col")?.value?.toInt() ?: 1
7778
val texFile = LocalFileSystem.getInstance().findFileByPath(texPath.trim()) ?: return null
7879
return TexFileInfo(texFile, line, column)
7980
}

src/main/kotlin/com/firsttimeinforever/intellij/pdf/viewer/tex/TexPdfViewer.kt

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ package com.firsttimeinforever.intellij.pdf.viewer.tex
22

33
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.PdfFileEditor
44
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.objects.SynctexFowardDataObject
5-
import com.firsttimeinforever.intellij.pdf.viewer.util.isSynctexInstalled
6-
import com.firsttimeinforever.intellij.pdf.viewer.util.runCommand
5+
import com.firsttimeinforever.intellij.pdf.viewer.util.CommandExecutionUtils.getCommandStdoutIfSuccessful
6+
import com.intellij.execution.configurations.GeneralCommandLine
77
import com.intellij.ide.actions.OpenInRightSplitAction
88
import com.intellij.notification.Notification
99
import com.intellij.notification.NotificationType
10-
import com.intellij.notification.Notifications
1110
import com.intellij.openapi.application.invokeLater
1211
import com.intellij.openapi.fileEditor.FileEditorManager
1312
import com.intellij.openapi.fileEditor.OpenFileDescriptor
@@ -43,7 +42,7 @@ class TexPdfViewer : ExternalPdfViewer {
4342
project: Project,
4443
focusAllowed: Boolean
4544
) {
46-
if (!isSynctexInstalled()) {
45+
if (!SynctexUtils.isSynctexInstalled()) {
4746
Notification(
4847
"LaTeX",
4948
"SyncTeX not installed",
@@ -78,9 +77,16 @@ class TexPdfViewer : ExternalPdfViewer {
7877
editorWindow?.selectedEditor?.selectedWithProvider?.fileEditor as PdfFileEditor
7978
}
8079

81-
val command = arrayOf("synctex", "view", "-i", "$line:0:${texFile.path}", "-o", file.path)
82-
val synctexOutput = runCommand(*command, directory = File(file.parent.path)) ?: return@invokeLater
83-
val values: Map<String?, String?> = NUMBER_REGEX.findAll(synctexOutput)
80+
val command = GeneralCommandLine(
81+
"synctex",
82+
"view",
83+
"-i",
84+
"$line:0:${texFile.path}",
85+
"-o",
86+
file.path
87+
).withWorkDirectory(File(file.parent.path))
88+
val output = getCommandStdoutIfSuccessful(command) ?: return@invokeLater
89+
val values: Map<String?, String?> = NUMBER_REGEX.findAll(output)
8490
.associate { it.groups["id"]?.value to it.groups["value"]?.value }
8591
.filter { it.key != null && it.value != null }
8692

src/main/kotlin/com/firsttimeinforever/intellij/pdf/viewer/ui/editor/panel/jcef/PdfFileEditorJcefPanel.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ package com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef
22

33
import com.firsttimeinforever.intellij.pdf.viewer.PdfViewerBundle
44
import com.firsttimeinforever.intellij.pdf.viewer.settings.PdfViewerSettings
5-
import com.firsttimeinforever.intellij.pdf.viewer.tex.TexFileInfo
65
import com.firsttimeinforever.intellij.pdf.viewer.settings.PdfViewerSettingsListener
6+
import com.firsttimeinforever.intellij.pdf.viewer.tex.SynctexUtils.isSynctexFileAvailable
7+
import com.firsttimeinforever.intellij.pdf.viewer.tex.SynctexUtils.isSynctexInstalled
8+
import com.firsttimeinforever.intellij.pdf.viewer.tex.TexFileInfo
79
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.StaticServer
810
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.PdfFileEditorPanel
911
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.MessageEventReceiver
1012
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.MessageEventSender
1113
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.SubscribableEventType
1214
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.TriggerableEventType
1315
import com.firsttimeinforever.intellij.pdf.viewer.ui.editor.panel.jcef.events.objects.*
14-
import com.firsttimeinforever.intellij.pdf.viewer.util.isSynctexFileAvailable
15-
import com.firsttimeinforever.intellij.pdf.viewer.util.isSynctexInstalled
1616
import com.intellij.notification.Notification
1717
import com.intellij.notification.NotificationType
1818
import com.intellij.notification.Notifications
@@ -28,13 +28,15 @@ import com.intellij.openapi.project.DumbAware
2828
import com.intellij.openapi.project.Project
2929
import com.intellij.openapi.ui.DialogBuilder
3030
import com.intellij.openapi.util.Disposer
31-
import com.intellij.openapi.vfs.*
31+
import com.intellij.openapi.vfs.VirtualFile
32+
import com.intellij.openapi.vfs.VirtualFileManager
3233
import com.intellij.openapi.vfs.newvfs.BulkFileListener
3334
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
3435
import com.intellij.ui.jcef.JCEFHtmlPanel
3536
import com.intellij.util.ui.UIUtil
3637
import kotlinx.serialization.decodeFromString
37-
import kotlinx.serialization.json.*
38+
import kotlinx.serialization.json.Json
39+
import kotlinx.serialization.json.encodeToJsonElement
3840
import org.cef.browser.CefBrowser
3941
import org.cef.browser.CefFrame
4042
import org.cef.handler.CefLoadHandlerAdapter
@@ -267,7 +269,10 @@ class PdfFileEditorJcefPanel(project: Project, virtualFile: VirtualFile):
267269
updatePageNumber(currentPageNumber)
268270
setThemeColors()
269271
setScale(currentScaleValue)
270-
eventSender.triggerWith(TriggerableEventType.SET_SYNCTEX_AVAILABLE, virtualFile.isSynctexFileAvailable() && isSynctexInstalled())
272+
eventSender.triggerWith(
273+
TriggerableEventType.SET_SYNCTEX_AVAILABLE,
274+
virtualFile.isSynctexFileAvailable() && isSynctexInstalled()
275+
)
271276
}
272277
}, browserPanel.cefBrowser)
273278
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.firsttimeinforever.intellij.pdf.viewer.util
2+
3+
import com.intellij.execution.ExecutionException
4+
import com.intellij.execution.configurations.GeneralCommandLine
5+
import com.intellij.execution.process.ProcessOutput
6+
import com.intellij.execution.util.ExecUtil
7+
import com.intellij.openapi.application.ApplicationManager
8+
9+
internal object CommandExecutionUtils {
10+
fun runCommand(commandLine: GeneralCommandLine): ProcessOutput? {
11+
return ApplicationManager.getApplication().executeOnPooledThread<ProcessOutput?> {
12+
try {
13+
ExecUtil.execAndGetOutput(commandLine, timeoutInMilliseconds = 3000)
14+
} catch (exception: ExecutionException) {
15+
exception.printStackTrace()
16+
null
17+
}
18+
}.get()
19+
}
20+
21+
fun getCommandStdoutIfSuccessful(commandLine: GeneralCommandLine): String? {
22+
return runCommand(commandLine)?.let {
23+
when (it.exitCode) {
24+
0 -> it.stdout
25+
else -> null
26+
}
27+
}
28+
}
29+
}

src/main/kotlin/com/firsttimeinforever/intellij/pdf/viewer/util/Synctex.kt

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/main/kotlin/com/firsttimeinforever/intellij/pdf/viewer/util/System.kt

Lines changed: 0 additions & 31 deletions
This file was deleted.

0 commit comments

Comments
 (0)