forked from KronicDeth/intellij-elixir
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
mix format
external format processor
Fixes KronicDeth#997 To format manually: With the keyboard * Mac: ⌥⇧⌘L * Linux/Windows: Ctrl+Alt+Shift+L From the menus 1. Code 2. Reformat File 3. Click Run in the "Reformat File" dialog To tun on format on save: 1. Preferences 2. Tools > Actions on Save. 3. Check "Reformat code". 4. Make sure "All file types" is set or at least "Files: Elixir" is set. Autosave JetBrains IDEs have autosave turned on by default, but you can adjust the settings: 1. Preferences 2. Appearance & Behavior > System Settings. 3. Check or uncheck the settings in the Autosave section.
- Loading branch information
1 parent
78be640
commit e112efe
Showing
2 changed files
with
110 additions
and
88 deletions.
There are no files selected for viewing
88 changes: 0 additions & 88 deletions
88
src/org/elixir_lang/formatter/MixFmtExternalFormatProcessor.java
This file was deleted.
Oops, something went wrong.
110 changes: 110 additions & 0 deletions
110
src/org/elixir_lang/formatter/MixFmtExternalFormatProcessor.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,110 @@ | ||
package org.elixir_lang.formatter | ||
|
||
import com.intellij.execution.process.CapturingProcessHandler | ||
import com.intellij.openapi.application.ApplicationManager | ||
import com.intellij.openapi.command.CommandProcessor | ||
import com.intellij.openapi.diagnostic.Logger | ||
import com.intellij.openapi.progress.ProgressManager | ||
import com.intellij.openapi.projectRoots.Sdk | ||
import com.intellij.openapi.roots.ProjectRootManager | ||
import com.intellij.openapi.util.TextRange | ||
import com.intellij.psi.PsiFile | ||
import com.intellij.psi.codeStyle.ExternalFormatProcessor | ||
import org.elixir_lang.Mix | ||
import org.elixir_lang.psi.ElixirFile | ||
import org.elixir_lang.sdk.elixir.Type.Companion.mostSpecificSdk | ||
import java.util.concurrent.TimeUnit | ||
|
||
@Suppress("UnstableApiUsage") | ||
@SuppressWarnings("UnstableApiUsage") | ||
class MixFmtExternalFormatProcessor : ExternalFormatProcessor { | ||
override fun activeForFile(source: PsiFile): Boolean { | ||
return source is ElixirFile | ||
} | ||
|
||
override fun getId(): String = "elixir_lang.mixFmtExternalFormatProcessor" | ||
|
||
override fun format( | ||
source: PsiFile, | ||
range: TextRange, | ||
canChangeWhiteSpacesOnly: Boolean, | ||
keepLineBreaks: Boolean, | ||
enableBulkUpdate: Boolean, | ||
cursorOffset: Int | ||
): TextRange? = | ||
// mix fmt doesn't support to format parts of a file | ||
if (source.isValid && range == source.textRange) { | ||
source.viewProvider.document?.let { document -> | ||
val application = ApplicationManager.getApplication() | ||
|
||
application.executeOnPooledThread { | ||
workingDirectory(source)?.let { workingDirectory -> | ||
mostSpecificSdk(source)?.let { sdk -> | ||
format(workingDirectory, sdk, document.text)?.let { formattedText -> | ||
application.invokeLater { | ||
if (source.isValid) { | ||
CommandProcessor.getInstance().runUndoTransparentAction { | ||
application.runWriteAction { | ||
document.setText(formattedText) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
source.textRange | ||
} | ||
} else { | ||
null | ||
} | ||
|
||
override fun indent(source: PsiFile, lineStartOffset: Int): String? = null | ||
|
||
companion object { | ||
private val LOGGER = Logger.getInstance(MixFmtExternalFormatProcessor::class.java) | ||
|
||
private fun workingDirectory(psiFile: PsiFile): String? = | ||
psiFile | ||
.virtualFile | ||
?.let { virtualFile -> | ||
ProjectRootManager.getInstance(psiFile.project).fileIndex.getContentRootForFile(virtualFile) | ||
} | ||
?.takeIf { contentRoot -> | ||
contentRoot.findChild("mix.exs") != null | ||
} | ||
?.path | ||
|
||
private fun format(workingDirectory: String, sdk: Sdk, unformattedText: String): String? { | ||
val commandline = Mix.commandLine(emptyMap(), workingDirectory, sdk) | ||
commandline.addParameter("format") | ||
// `-` turns on stdin/stdout for text to format | ||
commandline.addParameter("-") | ||
val processHandler = CapturingProcessHandler(commandline) | ||
processHandler.processInput.use { stdin -> | ||
stdin.write(unformattedText.toByteArray()) | ||
stdin.flush() | ||
} | ||
|
||
val indicator = ProgressManager.getGlobalProgressIndicator() | ||
val timeout = TimeUnit.SECONDS.toMillis(5).toInt() | ||
val output = if (indicator != null) { | ||
processHandler.runProcessWithProgressIndicator( | ||
indicator, | ||
timeout, | ||
true | ||
) | ||
} else { | ||
processHandler.runProcess(timeout, true) | ||
} | ||
|
||
return if (output.checkSuccess(LOGGER)) { | ||
output.stdout | ||
} else { | ||
null | ||
} | ||
} | ||
} | ||
} |