mirror of
https://github.com/ilyakooo0/intellij-haskell.git
synced 2024-10-26 23:25:11 +03:00
Improve navigation by Hoogle.
This commit is contained in:
parent
28364e601d
commit
fe02b403f7
@ -171,4 +171,5 @@ private[component] object BrowseModuleComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// value of name is without (operator) parens
|
||||
case class ModuleIdentifier(name: String, moduleName: String, declaration: String, isOperator: Boolean)
|
||||
|
@ -47,7 +47,7 @@ object DeclarationLineUtil {
|
||||
None
|
||||
}
|
||||
}
|
||||
name.map(n => NameAndShortDeclaration(n, declaration))
|
||||
name.map(n => NameAndShortDeclaration(StringUtil.removeOuterParens(n), declaration))
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ private[component] object DefinitionLocationComponent {
|
||||
HaskellReference.findIdentifiersByNameInfo(info, key.qualifiedNameElement.getIdentifierElement, project) match {
|
||||
case Right((mn, ne, pn)) => Right(PackageModuleLocation(findModuleName(ne), ne, name, pn))
|
||||
case Left(noInfo) =>
|
||||
HaskellReference.findIdentifierInFileByName(psiFile, name).
|
||||
HaskellReference.findIdentifierInFileByName(psiFile, name, prioIdInExpression = true).
|
||||
map(ne => Right(PackageModuleLocation(findModuleName(ne), ne, name, None))).getOrElse(Left(noInfo))
|
||||
}
|
||||
case None => Left(NoInfoAvailable(name, psiFile.getName))
|
||||
@ -234,7 +234,7 @@ private[component] object DefinitionLocationComponent {
|
||||
case Some(r) => r
|
||||
case None => Left(NoInfoAvailable(name, key.psiFile.getName))
|
||||
}
|
||||
case Left(NoMatchingExport) => HaskellReference.findIdentifierInFileByName(psiFile, name) match {
|
||||
case Left(NoMatchingExport) => HaskellReference.findIdentifierInFileByName(psiFile, name, prioIdInExpression = true) match {
|
||||
case Some(ne) => Right(LocalModuleLocation(psiFile, ne, name))
|
||||
case None => Left(NoInfoAvailable(name, psiFile.getName))
|
||||
}
|
||||
@ -263,7 +263,7 @@ private[component] object DefinitionLocationComponent {
|
||||
case Right(files) =>
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
files.headOption.flatMap(HaskellReference.findIdentifierInFileByName(_, name)) match {
|
||||
files.headOption.flatMap(HaskellReference.findIdentifierInFileByName(_, name, prioIdInExpression = true)) match {
|
||||
case Some(e) => Right(PackageModuleLocation(mn, e, name, Some(pn)))
|
||||
case None => Left(NoInfoAvailable(name, key.psiFile.getName))
|
||||
}
|
||||
|
@ -205,24 +205,18 @@ object HaskellReference {
|
||||
}
|
||||
|
||||
def findIdentifiersByLibraryNameInfo(project: Project, libraryNameInfo: LibraryNameInfo, name: String): Either[NoInfo, (String, HaskellNamedElement)] = {
|
||||
findIdentifiersByModuleAndName(project, libraryNameInfo.moduleName, name)
|
||||
findIdentifiersByModulesAndName(project, Seq(libraryNameInfo.moduleName), name)
|
||||
}
|
||||
|
||||
def findIdentifiersByModuleAndName(project: Project, moduleName: String, name: String): Either[NoInfo, (String, HaskellNamedElement)] = {
|
||||
def findIdentifiersByModulesAndName(project: Project, moduleNames: Seq[String], name: String, prioIdInExpression: Boolean = true): Either[NoInfo, (String, HaskellNamedElement)] = {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
findIdentifiersByModulesAndName(project, Seq(moduleName), name)
|
||||
}
|
||||
|
||||
def findIdentifiersByModulesAndName(project: Project, moduleNames: Seq[String], name: String): Either[NoInfo, (String, HaskellNamedElement)] = {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
findIdentifiersByModuleAndName2(project, moduleNames, name).headOption.map {
|
||||
findIdentifiersByModuleAndName2(project, moduleNames, name, prioIdInExpression).headOption.map {
|
||||
case (mn, nes) => nes.headOption.map(ne => Right((mn, ne))).getOrElse(Left(NoInfoAvailable(name, moduleNames.mkString(" | "))))
|
||||
}.getOrElse(Left(ModuleNotAvailable(moduleNames.mkString(" | "))))
|
||||
}
|
||||
|
||||
private def findIdentifiersByModuleAndName2(project: Project, moduleNames: Seq[String], name: String): Seq[(String, Seq[HaskellNamedElement])] = {
|
||||
private def findIdentifiersByModuleAndName2(project: Project, moduleNames: Seq[String], name: String, prioIdInExpression: Boolean): Seq[(String, Seq[HaskellNamedElement])] = {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
moduleNames.distinct.flatMap(mn => HaskellModuleNameIndex.findFilesByModuleName(project, mn) match {
|
||||
@ -230,13 +224,13 @@ object HaskellReference {
|
||||
case Right(files) =>
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
val identifiers = files.flatMap(f => findIdentifierInFileByName(f, name))
|
||||
val identifiers = files.flatMap(f => findIdentifierInFileByName(f, name, prioIdInExpression))
|
||||
if (identifiers.isEmpty) {
|
||||
val importedModuleNames = files.flatMap(f => FileModuleIdentifiers.findAvailableModuleIdentifiers(f).filter(_.name == name).map(_.moduleName))
|
||||
val importedModuleNames = files.flatMap(f => FileModuleIdentifiers.findAvailableModuleIdentifiers(f).filter(mid => mid.name == name || mid.name == "_" + name).map(_.moduleName))
|
||||
if (importedModuleNames.isEmpty) {
|
||||
Seq()
|
||||
} else {
|
||||
findIdentifiersByModuleAndName2(project, importedModuleNames, name)
|
||||
findIdentifiersByModuleAndName2(project, importedModuleNames, name, prioIdInExpression)
|
||||
}
|
||||
} else {
|
||||
Seq((mn, identifiers))
|
||||
@ -244,20 +238,22 @@ object HaskellReference {
|
||||
})
|
||||
}
|
||||
|
||||
def findIdentifierInFileByName(psifile: PsiFile, name: String): Option[HaskellNamedElement] = {
|
||||
def findIdentifierInFileByName(psiFile: PsiFile, name: String, prioIdInExpression: Boolean): Option[HaskellNamedElement] = {
|
||||
|
||||
ProgressManager.checkCanceled()
|
||||
def findIdInExpressions = {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
val topLevelExpressions = HaskellPsiUtil.findTopLevelExpressions(psifile)
|
||||
val topLevelExpressions = HaskellPsiUtil.findTopLevelExpressions(psiFile)
|
||||
|
||||
ProgressManager.checkCanceled()
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
val expressionIdentifiers = topLevelExpressions.flatMap(_.getQNameList.asScala.headOption.map(_.getIdentifierElement)).find(_.getName == name)
|
||||
topLevelExpressions.flatMap(_.getQNameList.asScala.headOption.map(_.getIdentifierElement)).find(_.getName == name)
|
||||
}
|
||||
|
||||
ProgressManager.checkCanceled()
|
||||
def findIdInDeclarations = {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
if (expressionIdentifiers.isEmpty) {
|
||||
val declarationElements = HaskellPsiUtil.findHaskellDeclarationElements(psifile)
|
||||
val declarationElements = HaskellPsiUtil.findHaskellDeclarationElements(psiFile)
|
||||
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
@ -266,8 +262,22 @@ object HaskellReference {
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
declarationIdentifiers.toSeq.sortWith(sortByClassDeclarationFirst).headOption
|
||||
}
|
||||
|
||||
if (prioIdInExpression) {
|
||||
val expressionIdentifiers = findIdInExpressions
|
||||
if (expressionIdentifiers.isEmpty) {
|
||||
findIdInDeclarations
|
||||
} else {
|
||||
expressionIdentifiers
|
||||
}
|
||||
} else {
|
||||
expressionIdentifiers
|
||||
val declarationIdentifiers = findIdInDeclarations
|
||||
if (declarationIdentifiers.isEmpty) {
|
||||
findIdInExpressions
|
||||
} else {
|
||||
declarationIdentifiers
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,9 @@ package intellij.haskell.navigation
|
||||
import com.intellij.navigation.{ChooseByNameContributor, ItemPresentation, NavigationItem}
|
||||
import com.intellij.openapi.progress.ProgressManager
|
||||
import com.intellij.openapi.project.Project
|
||||
import intellij.haskell.external.component.NameInfoComponentResult.{LibraryNameInfo, ProjectNameInfo}
|
||||
import intellij.haskell.external.component._
|
||||
import intellij.haskell.psi.{HaskellDeclarationElement, HaskellPsiUtil}
|
||||
import intellij.haskell.psi.HaskellPsiUtil
|
||||
import intellij.haskell.util.index.HaskellModuleNameIndex
|
||||
import intellij.haskell.util.{HaskellFileUtil, StringUtil}
|
||||
import javax.swing.Icon
|
||||
|
||||
class HoogleByNameContributor extends ChooseByNameContributor {
|
||||
@ -37,10 +35,6 @@ class HoogleByNameContributor extends ChooseByNameContributor {
|
||||
}
|
||||
|
||||
override def getItemsByName(name: String, pattern: String, project: Project, includeNonProjectItems: Boolean): Array[NavigationItem] = {
|
||||
def NotFoundResult(moduleName: String, declaration: String): Seq[NotFoundNavigationItem] = {
|
||||
Seq(NotFoundNavigationItem(declaration, Some(moduleName)))
|
||||
}
|
||||
|
||||
val hooglePattern =
|
||||
if (includeNonProjectItems) {
|
||||
pattern
|
||||
@ -50,7 +44,7 @@ class HoogleByNameContributor extends ChooseByNameContributor {
|
||||
|
||||
ProgressManager.checkCanceled()
|
||||
|
||||
val navigationItems = HoogleComponent.runHoogle(project, hooglePattern, count = 25).getOrElse(Seq()).flatMap {
|
||||
val navigationItems: Seq[NavigationItem] = HoogleComponent.runHoogle(project, hooglePattern, count = 25).getOrElse(Seq()).flatMap {
|
||||
case ModulePattern(moduleName) =>
|
||||
ProgressManager.checkCanceled()
|
||||
HaskellModuleNameIndex.findFilesByModuleName(project, moduleName) match {
|
||||
@ -59,42 +53,25 @@ class HoogleByNameContributor extends ChooseByNameContributor {
|
||||
}
|
||||
case PackagePattern(packageName) =>
|
||||
ProgressManager.checkCanceled()
|
||||
Seq(NotFoundNavigationItem(packageName))
|
||||
Seq()
|
||||
case DeclarationPattern(moduleName, declaration) =>
|
||||
ProgressManager.checkCanceled()
|
||||
DeclarationLineUtil.findName(declaration).toSeq.flatMap(nd => {
|
||||
val name = StringUtil.removeOuterParens(nd.name)
|
||||
ProgressManager.checkCanceled()
|
||||
val result = HaskellComponentsManager.findNameInfoByModuleName(project, moduleName, name)
|
||||
ProgressManager.checkCanceled()
|
||||
val navigationItemByNameInfo = result.toOption.flatMap(_.headOption) match {
|
||||
case Some(lni: LibraryNameInfo) => HaskellReference.findIdentifiersByLibraryNameInfo(project, lni, name).toOption.
|
||||
flatMap(x => HaskellPsiUtil.findDeclarationElement(x._2)).map(d => createLibraryNavigationItem(d, moduleName)).toSeq
|
||||
case Some(pni: ProjectNameInfo) =>
|
||||
HaskellFileUtil.findFileInRead(project, pni.filePath) match {
|
||||
case (Some(virtualFile), Right(psiFile)) => HaskellReference.findIdentifierByLocation(project, virtualFile, psiFile, pni.lineNr, pni.columnNr, name).flatMap(HaskellPsiUtil.findDeclarationElement).toSeq
|
||||
case (_, _) => Seq()
|
||||
}
|
||||
case _ => Seq()
|
||||
}
|
||||
ProgressManager.checkCanceled()
|
||||
if (navigationItemByNameInfo.nonEmpty) {
|
||||
navigationItemByNameInfo
|
||||
} else {
|
||||
val identifiers = HaskellReference.findIdentifiersByModuleAndName(project, moduleName, name).toOption.map(_._2).toSeq
|
||||
DeclarationLineUtil.findName(declaration) match {
|
||||
case Some(nameAndShortDeclaration) =>
|
||||
val identifiers = HaskellReference.findIdentifiersByModulesAndName(project, Seq(moduleName), nameAndShortDeclaration.name, prioIdInExpression = false).toOption.map(_._2).toSeq
|
||||
if (identifiers.isEmpty) {
|
||||
NotFoundResult(moduleName, declaration)
|
||||
Seq()
|
||||
} else {
|
||||
identifiers.flatMap(e => HaskellPsiUtil.findDeclarationElement(e))
|
||||
identifiers.map(e => HaskellPsiUtil.findDeclarationElement(e).getOrElse(e)).map(d => createLibraryNavigationItem(d, moduleName))
|
||||
}
|
||||
}
|
||||
})
|
||||
case None => Seq()
|
||||
}
|
||||
case d =>
|
||||
ProgressManager.checkCanceled()
|
||||
Seq(NotFoundNavigationItem(d))
|
||||
Seq()
|
||||
}
|
||||
|
||||
navigationItems.groupBy(_.getPresentation.getLocationString).flatMap(_._2.headOption).zipWithIndex.map({ case (item, i) => new NavigationItem {
|
||||
navigationItems.zipWithIndex.map({ case (item, i) => new NavigationItem {
|
||||
|
||||
// Hack to display items in same order as given by Hoogle
|
||||
override def getName: String = {
|
||||
@ -112,7 +89,7 @@ class HoogleByNameContributor extends ChooseByNameContributor {
|
||||
}).toArray
|
||||
}
|
||||
|
||||
private def createLibraryNavigationItem(namedElement: HaskellDeclarationElement, moduleNameFromHoogle: String): NavigationItem = {
|
||||
private def createLibraryNavigationItem(namedElement: NavigationItem, moduleNameFromHoogle: String): NavigationItem = {
|
||||
new NavigationItem {
|
||||
|
||||
override def getName: String = namedElement.getName
|
||||
@ -132,23 +109,4 @@ class HoogleByNameContributor extends ChooseByNameContributor {
|
||||
override def canNavigateToSource: Boolean = namedElement.canNavigateToSource
|
||||
}
|
||||
}
|
||||
|
||||
case class NotFoundNavigationItem(declaration: String, moduleName: Option[String] = None) extends NavigationItem {
|
||||
override def getName: String = declaration
|
||||
|
||||
override def getPresentation: ItemPresentation = new ItemPresentation {
|
||||
override def getIcon(unused: Boolean): Icon = null
|
||||
|
||||
override def getLocationString: String = moduleName.getOrElse("")
|
||||
|
||||
override def getPresentableText: String = getName
|
||||
}
|
||||
|
||||
override def canNavigateToSource: Boolean = false
|
||||
|
||||
override def canNavigate: Boolean = false
|
||||
|
||||
override def navigate(requestFocus: Boolean): Unit = ()
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user