Various improvements.

This commit is contained in:
Rik van der Kleij 2019-02-03 21:02:05 +01:00
parent d3abf9b468
commit 47dbe78f9e
11 changed files with 48 additions and 60 deletions

View File

@ -20,9 +20,7 @@ import com.intellij.openapi.actionSystem.{AnAction, AnActionEvent}
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtil
import intellij.haskell.external.component.{HoogleComponent, StackProjectManager}
import intellij.haskell.util.{ApplicationUtil, HaskellEditorUtil}
import scala.concurrent.duration._
import intellij.haskell.util.HaskellEditorUtil
class HoogleAction extends AnAction {
@ -38,12 +36,10 @@ class HoogleAction extends AnAction {
val selectionModel = actionContext.selectionModel
selectionModel.map(_.getSelectedText).orElse(Option(psiFile.findElementAt(offset)).map(_.getText)).foreach(text => {
ApplicationUtil.scheduleInReadActionWithWriteActionPriority(psiFile.getProject, {
HoogleComponent.runHoogle(psiFile.getProject, text) match {
case Some(results) => HaskellEditorUtil.showList(results, editor)
case _ => HaskellEditorUtil.showHint(editor, s"No Hoogle result for ${StringUtil.escapeXml(text)}")
}
}, "hoogling", 5.seconds)
HoogleComponent.runHoogle(psiFile.getProject, text) match {
case Some(results) => HaskellEditorUtil.showList(results, editor)
case _ => HaskellEditorUtil.showHint(editor, s"No Hoogle result for ${StringUtil.escapeXml(text)}")
}
})
})
}

View File

@ -278,7 +278,7 @@ class HaskellCompletionContributor extends CompletionContributor {
private def createLookupElement(typeSignature: String): Option[LookupElementBuilder] = {
typeSignature.split("::", 2).toSeq match {
case Seq(n, t) => Some(LookupElementBuilder.create(n.trim).withTypeText(StringEscapeUtils.unescapeHtml(typeSignature)))
case Seq(n, _) => Some(LookupElementBuilder.create(n.trim).withTypeText(StringEscapeUtils.unescapeHtml(typeSignature)))
case _ => None
}
}
@ -549,7 +549,7 @@ object FileModuleIdentifiers {
} yield (f1, f2, f3)
try {
val (x, y, z) = Await.result(f, 4800.milli)
val (x, y, z) = Await.result(f, 5.seconds)
Some(x ++ y ++ z)
} catch {
case _: TimeoutException =>
@ -581,7 +581,7 @@ object HaskellCompletionContributor {
(r1, r2)
}
ScalaFutureUtil.waitWithCheckCancelled(psiFile.getProject, result, s"In useAvailableModuleIdentifiers wait for all module identifiers for ${psiFile.getName} ", 5.seconds) match {
ScalaFutureUtil.waitWithCheckCancelled(psiFile.getProject, result, s"In useAvailableModuleIdentifiers wait for all module identifiers for ${psiFile.getName}") match {
case Some((result1, result2)) =>
(result1, result2) match {
case (Some(x), Some(y)) => doIt(x, y)

View File

@ -106,6 +106,11 @@ private[component] object BrowseModuleComponent {
Cache.synchronous().refresh(key)
}
def invalidateTopLevel(project: Project, moduleName: String, psiFile: PsiFile): Unit = {
val key = Key(project, moduleName, Some(psiFile), exported = false)
Cache.synchronous().invalidate(key)
}
def invalidateExportedModuleName(project: Project, moduleName: String): Unit = {
val synchronousCache = Cache.synchronous
val key = synchronousCache.asMap().keys.filter(k => k.moduleName == moduleName && k.exported) // Can be more than one for a module name if file of module can not be found

View File

@ -33,7 +33,7 @@ object HLintComponent {
final val HLintName = "hlint"
private final val HLintPath = GlobalInfo.toolPath(HLintName).toString
private final val Timeout = 1.seconds
private final val Timeout = 1.second
def check(psiFile: PsiFile): Seq[HLintInfo] = {
if (StackProjectManager.isHlintAvailable(psiFile.getProject)) {
@ -45,7 +45,6 @@ object HLintComponent {
case None => ()
case Some(d) =>
val deadline = Timeout.fromNow
while (isFileUnsaved(d) && deadline.hasTimeLeft() && !project.isDisposed) {
Thread.sleep(1)
}

View File

@ -20,16 +20,15 @@ import java.io.File
import com.intellij.execution.process.ProcessOutput
import com.intellij.lang.documentation.DocumentationMarkup
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.util.WaitFor
import intellij.haskell.external.execution.{CommandLine, StackCommandLine}
import intellij.haskell.psi.{HaskellPsiUtil, HaskellQualifiedNameElement}
import intellij.haskell.util.{HaskellProjectUtil, HtmlElement, ScalaUtil}
import intellij.haskell.util.{HaskellProjectUtil, HtmlElement, ScalaFutureUtil}
import intellij.haskell.{GlobalInfo, HaskellNotificationGroup}
import scala.collection.JavaConverters._
import scala.concurrent.Future
object HoogleComponent {
@ -163,27 +162,12 @@ object HoogleComponent {
}
}
import scala.concurrent.ExecutionContext.Implicits.global
private def runHoogle(project: Project, arguments: Seq[String]): Option[ProcessOutput] = {
ProgressManager.checkCanceled()
val hoogleFuture = ApplicationManager.getApplication.executeOnPooledThread(ScalaUtil.callable[ProcessOutput] {
CommandLine.run(project, HooglePath, Seq(s"--database=${hoogleDbPath(project)}") ++ arguments, logOutput = true)
})
ProgressManager.checkCanceled()
new WaitFor(5000, 1) {
override def condition(): Boolean = {
ProgressManager.checkCanceled()
hoogleFuture.isDone
}
}
if (hoogleFuture.isDone) {
Some(hoogleFuture.get())
} else {
None
}
ScalaFutureUtil.waitWithCheckCancelled(project, Future(CommandLine.run(project, HooglePath, Seq(s"--database=${hoogleDbPath(project)}") ++ arguments, logOutput = true)), "runHoogle")
}
private def hoogleDbPath(project: Project) = {

View File

@ -76,24 +76,26 @@ private[component] object LoadComponent {
projectRepl.load(psiFile, Some(fileChanged)) match {
case Some((loadOutput, loadFailed)) =>
ApplicationManager.getApplication.executeOnPooledThread(ScalaUtil.runnable {
if (fileChanged) {
ApplicationManager.getApplication.executeOnPooledThread(ScalaUtil.runnable {
TypeInfoComponent.invalidate(psiFile)
DefinitionLocationComponent.invalidate(psiFile)
HaskellModuleNameIndex.invalidateNotFoundEntries(project)
TypeInfoComponent.invalidate(psiFile)
DefinitionLocationComponent.invalidate(psiFile)
HaskellModuleNameIndex.invalidateNotFoundEntries(project)
val moduleName = HaskellPsiUtil.findModuleName(psiFile)
if (!loadFailed) {
NameInfoComponent.invalidate(psiFile)
moduleName.foreach(mn => {
BrowseModuleComponent.invalidateExportedModuleName(project, mn)
BrowseModuleComponent.refreshTopLevel(project, mn, psiFile)
FileModuleIdentifiers.refresh(psiFile)
})
val moduleName = HaskellPsiUtil.findModuleName(psiFile)
if (!loadFailed) {
NameInfoComponent.invalidate(psiFile)
moduleName.foreach(mn => {
BrowseModuleComponent.invalidateTopLevel(project, mn, psiFile)
FileModuleIdentifiers.refresh(psiFile)
BrowseModuleComponent.invalidateExportedModuleName(project, mn)
})
}
DocumentationManager.getInstance(project).updateToolwindowContext()
})
}
DocumentationManager.getInstance(project).updateToolwindowContext()
})
}
Some(HaskellCompilationResultHelper.createCompilationResult(psiFile, loadOutput.stderrLines, loadFailed))
case _ => None
}

View File

@ -99,9 +99,6 @@ object ProjectLibraryFileWatcher {
dependentRepls.foreach { repl =>
repl.restart()
if (repl.available && repl.stanzaType == LibType) {
repl.load(repl.stackComponentInfo.exposedModuleNames)
}
}
// When project is opened and has build errors some REPLs could not have been started

View File

@ -91,15 +91,19 @@ private[component] object TypeInfoComponent {
private def findTypeInfoResult(key: Key): TypeInfoResult = {
val psiFile = key.psiFile
val qne = key.qualifiedNameElement
ProgressManager.checkCanceled()
val findTypeInfo = for {
vf <- HaskellFileUtil.findVirtualFile(psiFile)
to = ApplicationUtil.runReadAction(qne.getTextOffset)
sp <- LineColumnPosition.fromOffset(vf, to)
_ = ProgressManager.checkCanceled()
t = ApplicationUtil.runReadAction(qne.getText)
ep <- LineColumnPosition.fromOffset(vf, to + t.length)
t = ApplicationUtil.runReadAction(qne.getText)
_ = ProgressManager.checkCanceled()
mn = HaskellPsiUtil.findModuleName(psiFile)
} yield {
ProgressManager.checkCanceled()
repl: ProjectStackRepl => repl.findTypeInfo(mn, key.psiFile, sp.lineNr, sp.columnNr, ep.lineNr, ep.columnNr, t)
}
@ -177,8 +181,9 @@ private[component] object TypeInfoComponent {
if (f.isCompleted) {
Await.result(f, 1.milli)
} else {
HaskellNotificationGroup.logInfoEvent(key.psiFile.getProject, s"Timeout while getting type info for ${key.qualifiedNameElement.getName}")
Left(ReadActionTimeout(s"Timeout while getting type info for ${key.qualifiedNameElement.getName}"))
val message = s"Timeout while getting type info for ${key.qualifiedNameElement.getName}"
HaskellNotificationGroup.logInfoEvent(key.psiFile.getProject, message)
Left(ReadActionTimeout(message))
}
}
}

View File

@ -68,6 +68,7 @@ case class ProjectStackRepl(project: Project, stackComponentInfo: StackComponent
}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
private def isReadAccessAllowed = ApplicationManager.getApplication.isReadAccessAllowed
@ -79,7 +80,7 @@ case class ProjectStackRepl(project: Project, stackComponentInfo: StackComponent
}
if (isReadAccessAllowed) {
ScalaFutureUtil.waitWithCheckCancelled(project, Future(execute), "Wait on :type-at in ProjectStackRepl").flatten
ScalaFutureUtil.waitWithCheckCancelled(project, Future(execute), "Wait on :type-at in ProjectStackRepl", 30.seconds).flatten
} else {
execute
}
@ -93,7 +94,7 @@ case class ProjectStackRepl(project: Project, stackComponentInfo: StackComponent
}
if (isReadAccessAllowed) {
ScalaFutureUtil.waitWithCheckCancelled(project, Future(execute), "Wait on :loc-at in ProjectStackRepl").flatten
ScalaFutureUtil.waitWithCheckCancelled(project, Future(execute), "Wait on :loc-at in ProjectStackRepl", timeout = 30.seconds).flatten
} else {
execute
}
@ -105,7 +106,7 @@ case class ProjectStackRepl(project: Project, stackComponentInfo: StackComponent
}
if (isReadAccessAllowed) {
ScalaFutureUtil.waitWithCheckCancelled(psiFile.getProject, Future(execute), "Wait on :info in ProjectStackRepl").flatten
ScalaFutureUtil.waitWithCheckCancelled(psiFile.getProject, Future(execute), "Wait on :info in ProjectStackRepl", 30.seconds).flatten
} else {
execute
}

View File

@ -16,5 +16,4 @@ object FutureUtil {
None
}
}
}

View File

@ -20,7 +20,7 @@ object ScalaFutureUtil {
}
}
def waitWithCheckCancelled[T](project: Project, future: Future[T], actionDescription: String, timeout: FiniteDuration = 100.millis): Option[T] = {
def waitWithCheckCancelled[T](project: Project, future: Future[T], actionDescription: String, timeout: FiniteDuration = 5.seconds): Option[T] = {
try {
new WaitFor(timeout.toMillis.toInt, 1) {
override def condition(): Boolean = {