mirror of
https://github.com/ilyakooo0/intellij-haskell.git
synced 2024-09-11 14:56:19 +03:00
Improved Hoogle documentation. Fix issue #411.
This commit is contained in:
parent
6e0f73d7c0
commit
91989d16f6
@ -49,8 +49,7 @@ class ShowNameInfoAction extends AnAction {
|
||||
private def createInfoText(nameInfo: NameInfo): String = {
|
||||
nameInfo match {
|
||||
case pi: ProjectNameInfo => s"${pi.declaration} -- ${pi.filePath}"
|
||||
case li: LibraryNameInfo => s"${li.shortenedDeclaration} -- ${li.moduleName}"
|
||||
case bi: BuiltInNameInfo => s"${bi.shortenedDeclaration} -- ${bi.moduleName} BUILT-IN"
|
||||
case li: LibraryNameInfo => s"${li.shortenedDeclaration} -- ${li.moduleName} ${li.packageName.getOrElse("")}"
|
||||
case ii: InfixInfo => ii.declaration
|
||||
}
|
||||
}
|
||||
|
@ -131,10 +131,10 @@ private[component] object DefinitionLocationComponent {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
HaskellReference.findIdentifiersByNameInfo(info, key.qualifiedNameElement.getIdentifierElement, project) match {
|
||||
case Right((mn, ne)) => Right(PackageModuleLocation(findModuleName(ne), ne, name))
|
||||
case Right((mn, ne, pn)) => Right(PackageModuleLocation(findModuleName(ne), ne, name, pn))
|
||||
case Left(noInfo) =>
|
||||
HaskellReference.findIdentifierInFileByName(psiFile, name).
|
||||
map(ne => Right(PackageModuleLocation(findModuleName(ne), ne, name))).getOrElse(Left(noInfo))
|
||||
map(ne => Right(PackageModuleLocation(findModuleName(ne), ne, name, None))).getOrElse(Left(noInfo))
|
||||
}
|
||||
case None => Left(NoInfoAvailable(name, psiFile.getName))
|
||||
}
|
||||
@ -179,7 +179,7 @@ private[component] object DefinitionLocationComponent {
|
||||
Left(ModuleNotAvailable("Prelude"))
|
||||
} else {
|
||||
HaskellReference.findIdentifiersByModulesAndName(project, moduleNames, name) match {
|
||||
case Right((mn, ne)) => Right(PackageModuleLocation(mn, ne, name))
|
||||
case Right((mn, ne)) => Right(PackageModuleLocation(mn, ne, name, None))
|
||||
case Left(noInfo) => Left(noInfo)
|
||||
}
|
||||
}
|
||||
@ -209,7 +209,8 @@ private[component] object DefinitionLocationComponent {
|
||||
Left(ReplNotAvailable)
|
||||
} else {
|
||||
f(repl) match {
|
||||
case Some(o) if o.stderrLines.isEmpty && o.stdoutLines.nonEmpty => Right(o)
|
||||
case Some(o) if o.stderrLines.isEmpty && o.stdoutLines.nonEmpty => Right(o.stdoutLines)
|
||||
case Some(o) if o.stdoutLines.isEmpty && o.stderrLines.nonEmpty => Right(o.stderrLines) // For some unknown reason REPL write sometimes correct output to stderr
|
||||
case None => Left(ReplNotAvailable)
|
||||
case _ => Left(NoInfoAvailable(name, psiFile.getName))
|
||||
}
|
||||
@ -219,7 +220,7 @@ private[component] object DefinitionLocationComponent {
|
||||
}
|
||||
|
||||
locationInfo match {
|
||||
case Right(o) => o.stdoutLines.headOption.map(l => createLocationByReplResult(project, psiFile, l, key, name)) match {
|
||||
case Right(o) => o.headOption.map(l => createLocationByReplResult(project, psiFile, l, key, name)) match {
|
||||
case Some(r) => r
|
||||
case None => Left(NoInfoAvailable(name, key.psiFile.getName))
|
||||
}
|
||||
@ -243,13 +244,13 @@ private[component] object DefinitionLocationComponent {
|
||||
}
|
||||
case (_, _) => Left(NoInfoAvailable(name, psiFile.getName))
|
||||
}
|
||||
case PackageModulePattern(_, mn) =>
|
||||
case PackageModulePattern(pn, mn) =>
|
||||
findFilesByModuleName(project, mn) match {
|
||||
case Right(files) =>
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
files.headOption.flatMap(HaskellReference.findIdentifierInFileByName(_, name)) match {
|
||||
case Some(e) => Right(PackageModuleLocation(mn, e, name))
|
||||
case Some(e) => Right(PackageModuleLocation(mn, e, name, Some(pn)))
|
||||
case None => Left(NoInfoAvailable(name, key.psiFile.getName))
|
||||
}
|
||||
case Left(noInfo) => Left(noInfo)
|
||||
@ -266,7 +267,7 @@ sealed trait DefinitionLocation {
|
||||
def originalName: String
|
||||
}
|
||||
|
||||
case class PackageModuleLocation(moduleName: String, namedElement: HaskellNamedElement, originalName: String) extends DefinitionLocation
|
||||
case class PackageModuleLocation(moduleName: String, namedElement: HaskellNamedElement, originalName: String, packageName: Option[String]) extends DefinitionLocation
|
||||
|
||||
case class LocalModuleLocation(psiFile: PsiFile, namedElement: HaskellNamedElement, originalName: String) extends DefinitionLocation
|
||||
|
||||
|
@ -24,7 +24,7 @@ import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import intellij.haskell.external.execution.{CommandLine, StackCommandLine}
|
||||
import intellij.haskell.psi.{HaskellPsiUtil, HaskellQualifiedNameElement}
|
||||
import intellij.haskell.util.{HaskellProjectUtil, HtmlElement, ScalaFutureUtil}
|
||||
import intellij.haskell.util.{HtmlElement, ScalaFutureUtil}
|
||||
import intellij.haskell.{GlobalInfo, HaskellNotificationGroup}
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
@ -61,37 +61,24 @@ object HoogleComponent {
|
||||
|
||||
val name = qualifiedNameElement.getIdentifierElement.getName
|
||||
val psiFile = qualifiedNameElement.getContainingFile.getOriginalFile
|
||||
if (HaskellProjectUtil.isSourceFile(psiFile)) {
|
||||
DefinitionLocationComponent.findDefinitionLocation(psiFile, qualifiedNameElement, None) match {
|
||||
case Left(noInfo) =>
|
||||
HaskellNotificationGroup.logWarningEvent(project, s"No documentation because no location info could be found for identifier `$name` because ${noInfo.message}")
|
||||
None
|
||||
case Right(info) =>
|
||||
val moduleName = info match {
|
||||
case PackageModuleLocation(mn, _, _) => Some(mn)
|
||||
case LocalModuleLocation(pf, _, _) => HaskellPsiUtil.findModuleName(pf)
|
||||
}
|
||||
moduleName match {
|
||||
case None =>
|
||||
HaskellNotificationGroup.logWarningEvent(project, s"No documentation because could not find module for identifier `$name`")
|
||||
None
|
||||
case Some(mn) =>
|
||||
ProgressManager.checkCanceled()
|
||||
HoogleComponent.createDocumentation(project, name, mn)
|
||||
}
|
||||
}
|
||||
} else if (HaskellProjectUtil.isLibraryFile(psiFile)) {
|
||||
val moduleName = HaskellPsiUtil.findModuleName(psiFile)
|
||||
moduleName.flatMap(mn => createDocumentation(project, name, mn))
|
||||
} else {
|
||||
None
|
||||
DefinitionLocationComponent.findDefinitionLocation(psiFile, qualifiedNameElement, None) match {
|
||||
case Left(noInfo) =>
|
||||
HaskellNotificationGroup.logWarningEvent(project, s"No documentation because no location info could be found for identifier `$name` because ${noInfo.message}")
|
||||
None
|
||||
case Right(info) =>
|
||||
val locationName = info match {
|
||||
case PackageModuleLocation(_, _, _, pn) => pn
|
||||
case LocalModuleLocation(pf, _, _) => HaskellPsiUtil.findModuleName(pf)
|
||||
}
|
||||
ProgressManager.checkCanceled()
|
||||
HoogleComponent.createDocumentation(project, name, locationName)
|
||||
}
|
||||
} else {
|
||||
Some("No documentation because Hoogle (database) is not available")
|
||||
}
|
||||
}
|
||||
|
||||
private def createDocumentation(project: Project, name: String, moduleName: String): Option[String] = {
|
||||
private def createDocumentation(project: Project, name: String, locationName: Option[String]): Option[String] = {
|
||||
def mkString(lines: Seq[String]) = {
|
||||
lines.mkString("\n").
|
||||
replace("<", HtmlElement.Lt).
|
||||
@ -102,7 +89,7 @@ object HoogleComponent {
|
||||
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
runHoogle(project, Seq("-i", name, s"+$moduleName", "+Prelude")).
|
||||
runHoogle(project, Seq("-i", name) ++ locationName.map("+" + _).toSeq).
|
||||
flatMap(processOutput =>
|
||||
if (processOutput.getStdoutLines.isEmpty || processOutput.getStdout.contains("No results found")) {
|
||||
None
|
||||
|
@ -93,7 +93,7 @@ private[component] object LibraryPackageInfoComponent {
|
||||
|
||||
private final val PackageNameVersionPattern = """([\w\-]+)-([\d\.]+)(?:\-.*)?""".r
|
||||
|
||||
private def toPackageNameversion(depends: String): Option[PackageNameVersion] = {
|
||||
def toPackageNameversion(depends: String): Option[PackageNameVersion] = {
|
||||
depends match {
|
||||
case PackageNameVersionPattern(name, version) => Some(PackageNameVersion(name, version))
|
||||
case _ => None
|
||||
|
@ -142,14 +142,12 @@ private[component] object NameInfoComponent {
|
||||
private def createNameInfo(outputLine: String, project: Project): Option[NameInfo] = {
|
||||
val result = outputLine match {
|
||||
case ProjectInfoPattern(declaration, filePath, lineNr, colNr) => Some(ProjectNameInfo(declaration, filePath, lineNr.toInt, colNr.toInt))
|
||||
case LibraryModuleInfoPattern(declaration, libraryName, moduleName) =>
|
||||
if (libraryName == "ghc-prim" || libraryName == "integer-gmp") {
|
||||
Some(BuiltInNameInfo(declaration, libraryName, "GHC.Base"))
|
||||
case LibraryModuleInfoPattern(declaration, packageId, moduleName) =>
|
||||
LibraryPackageInfoComponent.toPackageNameversion(packageId) match {
|
||||
case Some(packageNameVersion) => Some(LibraryNameInfo(declaration, Some(packageNameVersion.name), moduleName))
|
||||
case None => Some(LibraryNameInfo(declaration, None, moduleName))
|
||||
}
|
||||
else {
|
||||
Some(LibraryNameInfo(declaration, moduleName))
|
||||
}
|
||||
case ModuleInfoPattern(declaration, moduleName) => Some(LibraryNameInfo(declaration, moduleName))
|
||||
case ModuleInfoPattern(declaration, moduleName) => Some(LibraryNameInfo(declaration, None, moduleName))
|
||||
case InfixInfoPattern(declaration) => Some(InfixInfo(declaration))
|
||||
case _ => None
|
||||
}
|
||||
@ -206,9 +204,7 @@ object NameInfoComponentResult {
|
||||
|
||||
case class ProjectNameInfo(declaration: String, filePath: String, lineNr: Int, columnNr: Int) extends NameInfo
|
||||
|
||||
case class LibraryNameInfo(declaration: String, moduleName: String) extends NameInfo
|
||||
|
||||
case class BuiltInNameInfo(declaration: String, libraryName: String, moduleName: String) extends NameInfo
|
||||
case class LibraryNameInfo(declaration: String, packageName: Option[String], moduleName: String) extends NameInfo
|
||||
|
||||
case class InfixInfo(declaration: String) extends NameInfo
|
||||
|
||||
|
@ -167,7 +167,7 @@ class HaskellReference(element: HaskellNamedElement, textRange: TextRange) exten
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
HaskellComponentsManager.findDefinitionLocation(psiFile, qualifiedNameElement, importQualifier) match {
|
||||
case Right(PackageModuleLocation(_, ne, _)) => Right(ne)
|
||||
case Right(PackageModuleLocation(_, ne, _, _)) => Right(ne)
|
||||
case Right(LocalModuleLocation(_, ne, _)) => Right(ne)
|
||||
case Left(noInfo) => Left(noInfo)
|
||||
}
|
||||
@ -303,7 +303,7 @@ object HaskellReference {
|
||||
}
|
||||
}
|
||||
|
||||
def findIdentifiersByNameInfo(nameInfo: NameInfo, namedElement: HaskellNamedElement, project: Project): Either[NoInfo, (Option[String], HaskellNamedElement)] = {
|
||||
def findIdentifiersByNameInfo(nameInfo: NameInfo, namedElement: HaskellNamedElement, project: Project): Either[NoInfo, (Option[String], HaskellNamedElement, Option[String])] = {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
val name = namedElement.getName
|
||||
@ -312,11 +312,11 @@ object HaskellReference {
|
||||
val (virtualFile, psiFile) = HaskellFileUtil.findFileInRead(project, pni.filePath)
|
||||
ProgressManager.checkCanceled()
|
||||
(virtualFile, psiFile) match {
|
||||
case (Some(vf), Right(pf)) => findIdentifierByLocation(project, vf, pf, pni.lineNr, pni.columnNr, name).map(r => Right(HaskellPsiUtil.findModuleName(pf), r)).getOrElse(Left(NoInfoAvailable(name, "-")))
|
||||
case (Some(vf), Right(pf)) => findIdentifierByLocation(project, vf, pf, pni.lineNr, pni.columnNr, name).map(r => Right(HaskellPsiUtil.findModuleName(pf), r, None)).getOrElse(Left(NoInfoAvailable(name, "-")))
|
||||
case (_, Right(_)) => Left(NoInfoAvailable(name, "-"))
|
||||
case (_, Left(noInfo)) => Left(noInfo)
|
||||
}
|
||||
case lni: LibraryNameInfo => findIdentifiersByLibraryNameInfo(project, lni, name).map({ case (mn, nes) => (Some(mn), nes) })
|
||||
case lni: LibraryNameInfo => findIdentifiersByLibraryNameInfo(project, lni, name).map({ case (mn, nes) => (Some(mn), nes, lni.packageName) })
|
||||
case _ => Left(NoInfoAvailable(name, "-"))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user