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

Commit

Permalink
Various improvements and some decoupling from stack commands.
Browse files Browse the repository at this point in the history
  • Loading branch information
rikvdkleij committed Nov 4, 2018
1 parent 3b467f3 commit 17a55b3
Show file tree
Hide file tree
Showing 28 changed files with 321 additions and 239 deletions.
2 changes: 1 addition & 1 deletion intellij-haskell/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
]]></description>

<change-notes><![CDATA[
<p>1.0.0-beta30</p>
<p>1.0.0-beta31</p>
<b>IMPORTANT: Stack version should be > 1.7.0 and please reimport your Haskell Stack project after updating the plugin.</b>
<ul>
<li>Improved responsiveness, especially for multi-package projects</li>
Expand Down
8 changes: 4 additions & 4 deletions src/main/scala/intellij/haskell/action/AboutAction.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package intellij.haskell.action
import com.intellij.openapi.actionSystem.{AnAction, AnActionEvent}
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.SystemInfo
import intellij.haskell.external.component.{HLintComponent, HoogleComponent, StackProjectManager}
import intellij.haskell.external.execution.StackCommandLine
import intellij.haskell.external.component.{HLintComponent, HaskellComponentsManager, HoogleComponent, StackProjectManager}
import intellij.haskell.external.execution.{CommandLine, StackCommandLine}
import intellij.haskell.util.HaskellEditorUtil

import scala.collection.mutable.ArrayBuffer
Expand All @@ -43,8 +43,8 @@ class AboutAction extends AnAction {
val messages = new ArrayBuffer[String]
val project = actionEvent.getProject
messages.+=(s"${boldToolName("Stack")} version: " + StackCommandLine.run(project, Seq("--numeric-version")).map(_.getStdout).getOrElse("-"))
messages.+=(s"${boldToolName("GHC")}: " + StackCommandLine.run(project, Seq("exec", "--", "ghc", "--version")).map(_.getStdout).getOrElse("-"))
messages.+=(s"${boldToolName("Intero")}: " + StackCommandLine.run(project, Seq("exec", "--", "intero", "--version")).map(_.getStdout).getOrElse("-"))
messages.+=(s"${boldToolName("GHC")}: " + HaskellComponentsManager.getGhcVersion(project).map(_.prettyString).getOrElse("-"))
messages.+=(s"${boldToolName("Intero")}: " + HaskellComponentsManager.getInteroPath(project).map(p => CommandLine.run(project, p, Seq("--version")).getStdout).getOrElse("-"))
messages.+=(s"${boldToolName("HLint")}: " + HLintComponent.versionInfo(project))
messages.+=(s"${boldToolName("Hoogle")}: " + HoogleComponent.versionInfo(project))
messages.+=(s"${boldToolName("Hindent")}: " + HindentReformatAction.versionInfo(project))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ object HindentReformatAction {

def versionInfo(project: Project): String = {
if (StackProjectManager.isHindentAvailable(project)) {
CommandLine.run(Some(project), project.getBasePath, HindentPath, Seq("--version")).getStdout
CommandLine.run(project, HindentPath, Seq("--version")).getStdout
} else {
"-"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ object StylishHaskellReformatAction {

def versionInfo(project: Project): String = {
if (StackProjectManager.isStylishHaskellAvailable(project)) {
CommandLine.run(Some(project), project.getBasePath, StylishHaskellPath, Seq("--version")).getStdout
CommandLine.run(project, StylishHaskellPath, Seq("--version")).getStdout
} else {
"-"
}
Expand All @@ -58,7 +58,7 @@ object StylishHaskellReformatAction {
HaskellFileUtil.getAbsolutePath(psiFile) match {
case Some(path) =>
val processOutputFuture = ApplicationManager.getApplication.executeOnPooledThread(ScalaUtil.callable[ProcessOutput] {
CommandLine.run(Some(project), project.getBasePath, StylishHaskellPath, Seq(path))
CommandLine.run(project, StylishHaskellPath, Seq(path))
})

FutureUtil.waitForValue(project, processOutputFuture, s"reformatting by $StylishHaskellName") match {
Expand Down
14 changes: 9 additions & 5 deletions src/main/scala/intellij/haskell/annotator/HaskellAnnotator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -432,10 +432,10 @@ class NotInScopeIntentionAction(identifier: String, moduleName: String, psiFile:
val commaElement = importIdsSpec.addAfter(HaskellElementFactory.createComma(project), importId)
HaskellElementFactory.createImportId(project, identifier).foreach(mi => importIdsSpec.addAfter(mi, commaElement))
})
case None => createImportDeclaration(importDeclarationElement, ids)
case None => createImportDeclaration(importDeclarationElement, ids, project)
}
case None =>
createImportDeclaration(importDeclarationElement, ids)
createImportDeclaration(importDeclarationElement, ids, project)
}
case _ =>
HaskellPsiUtil.findModuleDeclaration(psiFile) match {
Expand All @@ -448,9 +448,13 @@ class NotInScopeIntentionAction(identifier: String, moduleName: String, psiFile:
)
}

private def createImportDeclaration(importDeclarationElement: HaskellImportDeclaration, ids: HaskellImportDeclarations) = {
val lastImportDeclaration = HaskellPsiUtil.findImportDeclarations(psiFile).lastOption.orNull
ids.addAfter(importDeclarationElement, lastImportDeclaration)
private def createImportDeclaration(importDeclarationElement: HaskellImportDeclaration, ids: HaskellImportDeclarations, project: Project) = {
HaskellPsiUtil.findImportDeclarations(psiFile).lastOption match {
case Some(id) =>
val newLine = ids.addAfter(HaskellElementFactory.createNewLine(project), id)
ids.addAfter(importDeclarationElement, newLine)
case None => ids.addAfter(importDeclarationElement, null)
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/main/scala/intellij/haskell/cabal/CabalInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ class CabalInfo(cabalFile: CabalFile, modulePath: String) {
ff <- HaskellPsiUtil.getChildOfType(pkgName, classOf[Freeform])
} yield ff.getText).getOrElse(throw new IllegalStateException(s"Can not find package name in Cabal file ${cabalFile.getName}"))

val packageVersion: String = (for {
pkgVersion <- HaskellPsiUtil.getChildOfType(cabalFile, classOf[PkgVersion])
ff <- HaskellPsiUtil.getChildOfType(pkgVersion, classOf[Freeform])
} yield ff.getText).getOrElse(throw new IllegalStateException(s"Can not find package version in Cabal file ${cabalFile.getName}"))

lazy val library: Option[LibraryCabalStanza] = {
cabalFile.getChildren.collectFirst {
case c: Library => LibraryCabalStanza(c, packageName, modulePath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ object HaskellCompletionContributor {
f4 <- idsF4
} yield doIt(f1, f2, f3, f4)

new WaitFor(2000, 10) {
new WaitFor(4000, 10) {
override def condition(): Boolean = {
ProgressManager.checkCanceled()
f.isCompleted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ private[component] object AvailableModuleNamesComponent {
}

private def findAvailableLibraryModuleNames(stackComponentInfo: StackComponentInfo): Iterable[String] = {
HaskellComponentsManager.findStackComponentGlobalInfo(stackComponentInfo).map(_.libraryModuleNames.flatMap(_.exposed)).getOrElse(Iterable())
HaskellComponentsManager.findStackComponentGlobalInfo(stackComponentInfo).map(_.libraryModuleNames.flatMap(_.exposedModuleNames)).getOrElse(Iterable())
}

private def findModuleNamesInModule(project: Project, currentModule: Module, modules: Seq[Module], includeTests: Boolean): Iterable[String] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private[component] object BrowseModuleComponent {
}

def findExportedIdentifiers(stackComponentGlobalInfo: StackComponentGlobalInfo, psiFile: PsiFile, moduleName: String)(implicit ec: ExecutionContext): Future[Iterable[ModuleIdentifier]] = {
if (stackComponentGlobalInfo.libraryModuleNames.exists(_.exposed.toSeq.contains(moduleName))) {
if (stackComponentGlobalInfo.libraryModuleNames.exists(_.exposedModuleNames.contains(moduleName))) {
findLibraryModuleIdentifiers(psiFile.getProject, moduleName)
} else {
val key = Key(psiFile.getProject, moduleName, Some(psiFile), exported = true)
Expand Down Expand Up @@ -114,9 +114,11 @@ private[component] object BrowseModuleComponent {
case Some(repl) =>
if (repl.isBusy) {
Left(ReplIsBusy)
} else if (!repl.available) {
Left(ReplNotAvailable)
} else {
repl.getLocalModuleIdentifiers(moduleName, psiFile) match {
case Some(output) if output.stderrLines.isEmpty => Right(output.stdoutLines.takeWhile(l => !l.startsWith("-- imported via")).flatMap(l => findModuleIdentifiers(project, l, moduleName)))
case Some(output) if output.stderrLines.isEmpty && output.stdoutLines.nonEmpty => Right(output.stdoutLines.takeWhile(l => !l.startsWith("-- imported via")).flatMap(l => findModuleIdentifiers(project, l, moduleName)))
case _ => Left(ReplNotAvailable)
}
}
Expand All @@ -130,9 +132,11 @@ private[component] object BrowseModuleComponent {
case Some(repl) =>
if (repl.isBusy) {
Left(ReplIsBusy)
} else if (!repl.available) {
Left(ReplNotAvailable)
} else {
repl.getModuleIdentifiers(moduleName, psiFile) match {
case Some(output) if output.stderrLines.isEmpty => Right(output.stdoutLines.flatMap(l => findModuleIdentifiers(project, l, moduleName)))
case Some(output) if output.stderrLines.isEmpty && output.stdoutLines.nonEmpty => Right(output.stdoutLines.flatMap(l => findModuleIdentifiers(project, l, moduleName)))
case _ => Left(ReplNotAvailable)
}
}
Expand All @@ -144,15 +148,18 @@ private[component] object BrowseModuleComponent {

private def findLibModuleIdentifiers(project: Project, moduleName: String): Either[NoInfo, Seq[ModuleIdentifier]] = {
StackReplsManager.getGlobalRepl(project) match {
case Some(repl) => if (repl.isBusy) {
Left(ReplIsBusy)
} else {
repl.getModuleIdentifiers(moduleName) match {
case None => Left(ReplNotAvailable)
case Some(o) if o.stdoutLines.nonEmpty => Right(o.stdoutLines.flatMap(l => findModuleIdentifiers(project, l, moduleName).toSeq))
case _ => Left(NoInfoAvailable(moduleName, "-"))
case Some(repl) =>
if (repl.isBusy) {
Left(ReplIsBusy)
} else if (!repl.available) {
Left(ReplNotAvailable)
} else {
repl.getModuleIdentifiers(moduleName) match {
case None => Left(ReplNotAvailable)
case Some(o) if o.stdoutLines.nonEmpty => Right(o.stdoutLines.flatMap(l => findModuleIdentifiers(project, l, moduleName).toSeq))
case _ => Left(NoInfoAvailable(moduleName, "-"))
}
}
}
case None => Left(ReplNotAvailable)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,11 @@ private[component] object DefinitionLocationComponent {
case Some(repl) =>
if (repl.isBusy) {
Left(ReplIsBusy)
} else if (!repl.available) {
Left(ReplNotAvailable)
} else {
f(repl) match {
case Some(o) if o.stderrLines.isEmpty => Right(o)
case Some(o) if o.stderrLines.isEmpty && o.stdoutLines.nonEmpty => Right(o)
case _ => Left(ReplNotAvailable)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@

package intellij.haskell.external.component

import java.nio.file.Paths

import com.github.blemale.scaffeine.{LoadingCache, Scaffeine}
import com.intellij.openapi.project.Project
import intellij.haskell.external.execution.{CommandLine, StackCommandLine}
import intellij.haskell.module.HaskellModuleBuilder
import intellij.haskell.module.HaskellModuleBuilder.HaskellDependency
import intellij.haskell.util.GhcVersion
import intellij.haskell.util.{GhcVersion, ScalaUtil}

import scala.collection.JavaConverters._

Expand All @@ -41,16 +41,13 @@ private[component] object GlobalProjectInfoComponent {
}
}

def getSupportedLanguageExtensions(project: Project): Option[Iterable[String]] = {
findGhcPath(project).map(ghcPath => {
CommandLine.run(
Some(project),
project.getBasePath,
ghcPath,
Seq("--supported-languages"),
notifyBalloonError = true
).getStdoutLines.asScala
})
def getSupportedLanguageExtensions(project: Project, ghcPath: String): Seq[String] = {
CommandLine.run(
project,
ghcPath,
Seq("--supported-languages"),
notifyBalloonError = true
).getStdoutLines.asScala
}

def getAvailableStackagesPackages(project: Project): Iterable[String] = {
Expand All @@ -65,22 +62,47 @@ private[component] object GlobalProjectInfoComponent {
private def createGlobalProjectInfo(key: Key): Option[GlobalProjectInfo] = {
val project = key.project
for {
extensions <- getSupportedLanguageExtensions(project)
pathLines <- findPathLines(project)
pathInfoMap = ScalaUtil.linesToMap(pathLines)
binPaths <- findBinPaths(pathInfoMap)
packageDbPaths <- findPackageDbPaths(pathInfoMap)
ghcPath = Paths.get(binPaths.compilerBinPath, "ghc").toString
ghcPkgPath = Paths.get(binPaths.compilerBinPath, "ghc-pkg").toString
interoPath = Paths.get(binPaths.localBinPath, "intero").toString
extensions = getSupportedLanguageExtensions(project, ghcPath)
stackagePackageNames = getAvailableStackagesPackages(project)
ghcVersion <- findGhcVersion(project)
projectDependencies = HaskellModuleBuilder.getProjectLibraryDependencies(project)
} yield GlobalProjectInfo(ghcVersion, extensions, projectDependencies, stackagePackageNames)
ghcVersion = findGhcVersion(project, ghcPath)
} yield GlobalProjectInfo(ghcVersion, ghcPath, ghcPkgPath, interoPath, packageDbPaths, binPaths, extensions, stackagePackageNames)
}

private def findGhcPath(project: Project) = {
StackCommandLine.run(project, Seq("path", "--compiler-exe")).flatMap(_.getStdoutLines.asScala.headOption)
private def findPathLines(project: Project) = {
StackCommandLine.run(project, Seq("path")).map(_.getStdoutLines.asScala.toSeq)
}

private def findGhcVersion(project: Project): Option[GhcVersion] = {
StackCommandLine.run(project, Seq("exec", "--", "ghc", "--numeric-version"))
.map(o => GhcVersion.parse(o.getStdout.trim))
private def findGhcVersion(project: Project, ghcPath: String): GhcVersion = {
val output = CommandLine.run(project, ghcPath, Seq("--numeric-version"))
GhcVersion.parse(output.getStdout.trim)
}

private def findBinPaths(pathInfoMap: Map[String, String]): Option[ProjectBinPaths] = {
for {
compilerBinPath <- pathInfoMap.get("compiler-bin")
localBinPath <- pathInfoMap.get("local-install-root").map(p => Paths.get(p, "bin").toString)
} yield ProjectBinPaths(compilerBinPath, localBinPath)
}

private def findPackageDbPaths(pathInfoMap: Map[String, String]): Option[PackageDbPaths] = {
for {
globalPackageDbPath <- pathInfoMap.get("global-pkg-db")
snapshotPackageDbPath <- pathInfoMap.get("snapshot-pkg-db")
localPackageDbPath <- pathInfoMap.get("local-pkg-db")
} yield PackageDbPaths(globalPackageDbPath, snapshotPackageDbPath, localPackageDbPath)
}
}


case class GlobalProjectInfo(ghcVersion: GhcVersion, supportedLanguageExtensions: Iterable[String], dependencies: Iterable[HaskellDependency], availableStackagePackageNames: Iterable[String])
case class GlobalProjectInfo(ghcVersion: GhcVersion, ghcPath: String, ghcPkgPath: String, interoPath: String, packageDbPaths: PackageDbPaths, projectBinPaths: ProjectBinPaths, supportedLanguageExtensions: Iterable[String], availableStackagePackageNames: Iterable[String])

case class PackageDbPaths(globalPackageDbPath: String, snapshotPackageDbPath: String, localPackageDbPath: String)

case class ProjectBinPaths(compilerBinPath: String, localBinPath: String)
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ object HLintComponent {
}

private def runHLint(project: Project, arguments: Seq[String], ignoreExitCode: Boolean) = {
CommandLine.run(Some(project), project.getBasePath, HLintPath, arguments, logOutput = true, ignoreExitCode = ignoreExitCode)
CommandLine.run(project, HLintPath, arguments, logOutput = true, ignoreExitCode = ignoreExitCode)
}

private object HlintJsonProtocol extends DefaultJsonProtocol {
Expand Down
Loading

0 comments on commit 17a55b3

Please sign in to comment.