Skip to content
This repository has been archived by the owner on Nov 30, 2024. It is now read-only.

Commit

Permalink
Initial support for reformatting by Ormolu by replacing custom Hinden…
Browse files Browse the repository at this point in the history
…t and Stylish-Haskell paths by Ormolu path.
  • Loading branch information
rikvdkleij committed Feb 9, 2020
1 parent efe93aa commit 537906a
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 32 deletions.
6 changes: 6 additions & 0 deletions src/main/scala/intellij/haskell/HTool.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,10 @@ object HTool {
case object StylishHaskell extends HTool {
def name: String = "stylish-haskell"
}

case object Ormolu extends HTool {
def name: String = "ormolu"

}

}
19 changes: 14 additions & 5 deletions src/main/scala/intellij/haskell/action/HaskellReformatAction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.intellij.openapi.actionSystem.{AnActionEvent, Presentation}
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import intellij.haskell.external.component.StackProjectManager
import intellij.haskell.settings.HaskellSettingsState
import intellij.haskell.util.{HaskellEditorUtil, HaskellFileUtil}

class HaskellReformatAction extends ReformatCodeAction {
Expand All @@ -32,7 +33,7 @@ class HaskellReformatAction extends ReformatCodeAction {
ActionUtil.findActionContext(actionEvent).foreach(actionContext => {
val psiFile = actionContext.psiFile
if (HaskellFileUtil.isHaskellFile(psiFile)) {
HaskellEditorUtil.enableExternalAction(actionEvent, (project: Project) => StackProjectManager.isStylishHaskellAvailable(project) && StackProjectManager.isHindentAvailable(project))
HaskellEditorUtil.enableExternalAction(actionEvent, (project: Project) => (StackProjectManager.isStylishHaskellAvailable(project) && StackProjectManager.isHindentAvailable(project)) || HaskellReformatAction.reformatByOrmolu)
} else {
super.update(actionEvent)
}
Expand All @@ -45,10 +46,10 @@ class HaskellReformatAction extends ReformatCodeAction {
if (HaskellFileUtil.isHaskellFile(psiFile)) {
val selectionModel = actionContext.selectionModel
selectionModel match {
case Some(_) =>
case Some(_) if StackProjectManager.isHindentAvailable(actionEvent.getProject) =>
HindentReformatAction.format(psiFile, selectionModel.map(m =>
HindentReformatAction.translateSelectionModelToSelectionContext(m)))
case None => HaskellReformatAction.reformatFile(psiFile)
case _ => HaskellReformatAction.reformatFile(psiFile)
}
} else {
super.actionPerformed(actionEvent)
Expand All @@ -59,9 +60,17 @@ class HaskellReformatAction extends ReformatCodeAction {

object HaskellReformatAction {

def reformatByOrmolu: Boolean = {
HaskellSettingsState.ormoluPath.isDefined
}

def reformatFile(psiFile: PsiFile): Boolean = {
HindentReformatAction.format(psiFile)
StylishHaskellReformatAction.format(psiFile)
HaskellSettingsState.ormoluPath match {
case Some(p) => OrmoluReformatAction.format(psiFile, p)
case None =>
HindentReformatAction.format(psiFile)
StylishHaskellReformatAction.format(psiFile)
}
true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import intellij.haskell.external.component.StackProjectManager
import intellij.haskell.external.execution.CommandLine
import intellij.haskell.settings.HaskellSettingsState
import intellij.haskell.util._
import intellij.haskell.{GlobalInfo, HTool, HaskellLanguage, HaskellNotificationGroup}

Expand All @@ -52,7 +51,7 @@ class HindentReformatAction extends AnAction {
}

object HindentReformatAction {
private def hindentPath = HaskellSettingsState.hindentPath.getOrElse(GlobalInfo.defaultHindentPath.toString)
private def hindentPath = GlobalInfo.defaultHindentPath.toString

def format(psiFile: PsiFile, selectionContext: Option[SelectionContext] = None): Boolean = {
val lineLength = CodeStyle.getSettings(psiFile.getProject).getRightMargin(HaskellLanguage.Instance)
Expand Down
77 changes: 77 additions & 0 deletions src/main/scala/intellij/haskell/action/OrmoluReformatAction.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2014-2019 Rik van der Kleij
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package intellij.haskell.action

import com.intellij.execution.process.ProcessOutput
import com.intellij.openapi.actionSystem.{AnAction, AnActionEvent}
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import intellij.haskell.external.execution.CommandLine
import intellij.haskell.settings.HaskellSettingsState
import intellij.haskell.util._
import intellij.haskell.{HTool, HaskellNotificationGroup}

sealed case class SelectionContext(start: Int, end: Int, text: String)

class OrmoluReformatAction extends AnAction {

override def update(actionEvent: AnActionEvent): Unit = {
HaskellEditorUtil.enableExternalAction(actionEvent, (project: Project) => HaskellReformatAction.reformatByOrmolu)
}

override def actionPerformed(actionEvent: AnActionEvent): Unit = {
ActionUtil.findActionContext(actionEvent).foreach { actionContext =>
val psiFile = actionContext.psiFile
HaskellSettingsState.ormoluPath match {
case Some(p) => OrmoluReformatAction.format(psiFile, p)
case None => ()
}
}
}
}

object OrmoluReformatAction {

def format(psiFile: PsiFile, ormoluPath: String): Unit = {
val project = psiFile.getProject
HaskellFileUtil.saveFile(psiFile)

HaskellFileUtil.getAbsolutePath(psiFile) match {
case Some(path) =>
val processOutputFuture = ApplicationManager.getApplication.executeOnPooledThread(ScalaUtil.callable[ProcessOutput] {
CommandLine.run(project, ormoluPath, Seq(path))
})

FutureUtil.waitForValue(project, processOutputFuture, s"reformatting by ${HTool.Ormolu.name}") match {
case None => ()
case Some(processOutput) =>
if (processOutput.getStderrLines.isEmpty) {
HaskellFileUtil.saveFileWithNewContent(psiFile, processOutput.getStdout)
} else {
HaskellNotificationGroup.logInfoEvent(project, s"Error while reformatting by `${HTool.Ormolu.name}`. Error: ${processOutput.getStderr}")
}
}
case None => HaskellNotificationGroup.logWarningBalloonEvent(psiFile.getProject, s"Can not reformat file because could not determine path for file `${psiFile.getName}`. File exists only in memory")
}
}


def versionInfo(project: Project): String = {
HaskellSettingsState.ormoluPath.map(p => CommandLine.run(project, p, Seq("--version")).getStdout).getOrElse("-")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiFile
import intellij.haskell.external.component.StackProjectManager
import intellij.haskell.external.execution.CommandLine
import intellij.haskell.settings.HaskellSettingsState
import intellij.haskell.util.{FutureUtil, HaskellEditorUtil, HaskellFileUtil, ScalaUtil}
import intellij.haskell.{GlobalInfo, HTool, HaskellNotificationGroup}

Expand All @@ -41,7 +40,7 @@ class StylishHaskellReformatAction extends AnAction {
}

object StylishHaskellReformatAction {
private def stylishHaskellPath = HaskellSettingsState.stylishHaskellPath.getOrElse(GlobalInfo.defaultStylishHaskellPath.toString)
private def stylishHaskellPath = GlobalInfo.defaultStylishHaskellPath.toString

def versionInfo(project: Project): String = {
if (StackProjectManager.isStylishHaskellAvailable(project)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ object CommandLine {
val commandLine = createCommandLine(workDir, commandPath, arguments)

if (!logOutput) {
HaskellNotificationGroup.logInfoEvent(project, s"Executing: `${commandLine.getCommandLineString}`")
HaskellNotificationGroup.logInfoEvent(project, s"Executing: ${commandLine.getCommandLineString} ")
}

val processHandler = createProcessHandler(project, commandLine, logOutput)
Expand Down
26 changes: 12 additions & 14 deletions src/main/scala/intellij/haskell/settings/HaskellConfigurable.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class HaskellConfigurable extends Configurable {
private val hindentPathField = new JTextField
private val hlintPathField = new JTextField
private val hooglePathField = new JTextField
private val ormoluPathField = new JTextField
private val stylishHaskellPathField = new JTextField
private val useCustomToolsToggle = new JCheckBox
private val extraStackArgumentsField = new JTextField
Expand All @@ -54,6 +55,7 @@ class HaskellConfigurable extends Configurable {
hlintPathField.setVisible(visible)
hooglePathField.setVisible(visible)
stylishHaskellPathField.setVisible(visible)
ormoluPathField.setVisible(visible)
}

toggleToolPathsVisibility()
Expand All @@ -68,10 +70,9 @@ class HaskellConfigurable extends Configurable {
hlintOptionsField.getDocument.addDocumentListener(docListener)
replTimeoutField.getDocument.addDocumentListener(docListener)
newProjectTemplateNameField.getDocument.addDocumentListener(docListener)
hindentPathField.getDocument.addDocumentListener(docListener)
hlintPathField.getDocument.addDocumentListener(docListener)
hooglePathField.getDocument.addDocumentListener(docListener)
stylishHaskellPathField.getDocument.addDocumentListener(docListener)
ormoluPathField.getDocument.addDocumentListener(docListener)
useSystemGhcToggle.addChangeListener { _ =>
isModifiedByUser = true
}
Expand Down Expand Up @@ -126,10 +127,9 @@ class HaskellConfigurable extends Configurable {
(new JLabel(NewProjectTemplateName), newProjectTemplateNameField),
(new JLabel(BuildToolsUsingSystemGhc), useSystemGhcToggle),
(new JLabel(UseCustomTool), useCustomToolsToggle),
(new JLabel(HindentPath), hindentPathField),
(new JLabel(HlintPath), hlintPathField),
(new JLabel(HooglePath), hooglePathField),
(new JLabel(StylishHaskellPath), stylishHaskellPathField),
(new JLabel(OrmoluPath), ormoluPathField),
(new JLabel(""), afterRestartLabel)
)

Expand Down Expand Up @@ -163,10 +163,9 @@ class HaskellConfigurable extends Configurable {
state.hlintOptions = hlintOptionsField.getText
state.useSystemGhc = useSystemGhcToggle.isSelected
state.newProjectTemplateName = newProjectTemplateNameField.getText
state.hindentPath = hindentPathField.getText
state.hlintPath = hlintPathField.getText
state.hooglePath = hooglePathField.getText
state.stylishHaskellPath = stylishHaskellPathField.getText
state.ormoluPath = ormoluPathField.getText
state.customTools = useCustomToolsToggle.isSelected
state.extraStackArguments = extraStackArgumentsField.getText
}
Expand All @@ -192,17 +191,16 @@ class HaskellConfigurable extends Configurable {

private def validateCustomTools(): Unit = {
if (useCustomToolsToggle.isSelected) {
if (hindentPathField.getText.trim.isEmpty ||
hlintPathField.getText.trim.isEmpty ||
hooglePathField.getText.trim.isEmpty ||
stylishHaskellPathField.getText.trim.isEmpty) {
if (
ormoluPathField.getText.trim.isEmpty ||
hlintPathField.getText.trim.isEmpty ||
hooglePathField.getText.trim.isEmpty) {
throw new ConfigurationException(s"All Haskell tools paths have to be set")
}

checkFileExists(hindentPathField.getText)
checkFileExists(hlintPathField.getText)
checkFileExists(hooglePathField.getText)
checkFileExists(stylishHaskellPathField.getText)
checkFileExists(ormoluPathField.getText)
}
}

Expand All @@ -217,10 +215,9 @@ class HaskellConfigurable extends Configurable {
useSystemGhcToggle.setSelected(state.useSystemGhc)
replTimeoutField.setText(state.replTimeout.toString)
newProjectTemplateNameField.setText(state.newProjectTemplateName)
hindentPathField.setText(state.hindentPath)
hlintPathField.setText(state.hlintPath)
hooglePathField.setText(state.hooglePath)
stylishHaskellPathField.setText(state.stylishHaskellPath)
ormoluPathField.setText(state.ormoluPath)
useCustomToolsToggle.setSelected(state.customTools)
extraStackArgumentsField.setText(state.extraStackArguments)
}
Expand All @@ -235,6 +232,7 @@ object HaskellConfigurable {
final val HlintPath = "Hlint path"
final val HooglePath = "Hoogle path"
final val StylishHaskellPath = "Stylish Haskell path"
final val OrmoluPath = "Ormolu path"
final val UseCustomTool = "Use custom Haskell tools *"
final val CustomToolPathWarning =
"""WARNING! Specifying a path for a Haskell tool will override the default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,9 @@ static class HaskellSettingsState {
public Boolean reformatCodeBeforeCommit = false;
public Boolean optimizeImportsBeforeCommit = false;
public String newProjectTemplateName = "new-template";
public String hindentPath = "";
public String hlintPath = "";
public String hooglePath = "";
public String stylishHaskellPath = "";
public String ormoluPath = "";
public Boolean customTools = false;
public String extraStackArguments = "";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ object HaskellSettingsState {
state.customTools
}

def hindentPath: Option[String] = {
Option.when(customTools && state.hindentPath.nonEmpty)(state.hindentPath)
}

def hlintPath: Option[String] = {
Option.when(customTools && state.hlintPath.nonEmpty)(state.hlintPath)
}
Expand All @@ -67,8 +63,8 @@ object HaskellSettingsState {
Option.when(customTools && state.hooglePath.nonEmpty)(state.hooglePath)
}

def stylishHaskellPath: Option[String] = {
Option.when(customTools && state.stylishHaskellPath.nonEmpty)(state.stylishHaskellPath)
def ormoluPath: Option[String] = {
Option.when(customTools && state.ormoluPath.nonEmpty)(state.ormoluPath)
}

def useCustomTools: Boolean = {
Expand Down

0 comments on commit 537906a

Please sign in to comment.