[platform] add new go to declaration handler using GotoDeclarationProvider API (IDEA-198180)

This commit is contained in:
Daniil Ovchinnikov
2019-02-05 18:54:01 +03:00
parent 9f76197c40
commit 5d1817d628
4 changed files with 120 additions and 1 deletions
@@ -2,11 +2,14 @@
package com.intellij.codeInsight.navigation.actions
import com.intellij.codeInsight.CodeInsightActionHandler
import com.intellij.openapi.util.registry.Registry
/**
* Go To Declaration which doesn't invoke Show Usages if there are no declarations to go
*/
class GotoDeclarationOnlyAction : GotoDeclarationAction() {
override fun getHandler(): CodeInsightActionHandler = GotoDeclarationOnlyHandler
override fun getHandler(): CodeInsightActionHandler {
return if (Registry.`is`("ide.goto.target")) GotoDeclarationOnlyHandler2 else GotoDeclarationOnlyHandler
}
}
@@ -0,0 +1,76 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.codeInsight.navigation.actions
import com.intellij.codeInsight.CodeInsightActionHandler
import com.intellij.codeInsight.CodeInsightBundle
import com.intellij.codeInsight.findAllTargets
import com.intellij.codeInsight.hint.HintManager
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.isKeywordUnderCaret
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction.underModalProgress
import com.intellij.featureStatistics.FeatureUsageTracker
import com.intellij.navigation.NavigationTarget
import com.intellij.navigation.chooseTarget
import com.intellij.openapi.command.executeCommand
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.fileEditor.ex.IdeDocumentHistory
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.project.IndexNotReadyException
import com.intellij.openapi.project.Project
import com.intellij.pom.Navigatable
import com.intellij.psi.PsiFile
object GotoDeclarationOnlyHandler2 : CodeInsightActionHandler {
override fun startInWriteAction(): Boolean = false
override fun invoke(project: Project, editor: Editor, file: PsiFile) {
FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.declaration")
val targets = try {
underModalProgress(project, "Resolving Reference...") {
findAllTargets(project, editor, file)
}
}
catch (e: IndexNotReadyException) {
DumbService.getInstance(project).showDumbModeNotification("Navigation is not available here during index update")
return
}
if (targets.isEmpty()) {
notifyCantGoAnywhere(project, editor, file)
}
else {
chooseTarget(project, editor, CodeInsightBundle.message("declaration.navigation.title"), targets.toList()) {
gotoTarget(project, editor, file, it)
}
}
}
private fun notifyCantGoAnywhere(project: Project, editor: Editor, file: PsiFile) {
if (!isKeywordUnderCaret(project, file, editor.caretModel.offset)) {
HintManager.getInstance().showErrorHint(editor, "Cannot find declaration to go to")
}
}
private fun gotoTarget(project: Project, editor: Editor, file: PsiFile, target: NavigationTarget) {
val navigatable = target.navigatable ?: return
if (navigateInCurrentEditor(project, editor, file, navigatable)) {
return
}
if (navigatable.canNavigate()) {
navigatable.navigate(true)
}
}
private fun navigateInCurrentEditor(project: Project, editor: Editor, file: PsiFile, target: Navigatable): Boolean {
if (!editor.isDisposed && target is OpenFileDescriptor && target.file == file.virtualFile) {
executeCommand {
IdeDocumentHistory.getInstance(project).includeCurrentCommandAsNavigation()
target.navigateIn(editor)
}
return true
}
return false
}
}
@@ -0,0 +1,38 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
@file:Experimental
package com.intellij.navigation
import com.intellij.ide.ui.createTargetPresentationRenderer
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.popup.JBPopupFactory
import com.intellij.util.Consumer
import org.jetbrains.annotations.ApiStatus.Experimental
fun chooseTarget(project: Project, editor: Editor, title: String, targets: List<NavigationTarget>, handler: (NavigationTarget) -> Unit) {
chooseTarget(project, editor, title, targets, Consumer(handler))
}
fun chooseTarget(project: Project, editor: Editor, title: String, targets: List<NavigationTarget>, consumer: Consumer<NavigationTarget>) {
targets.singleOrNull()?.let {
consumer.consume(it)
return
}
val renderer = createTargetPresentationRenderer(project, NavigationTarget::getPresentationIfValid)
return JBPopupFactory.getInstance()
.createPopupChooserBuilder(targets)
.setRenderer(renderer)
.setNamerForFiltering(renderer::getItemSearchString)
.setFont(EditorUtil.getEditorFont())
.setTitle(title)
.setItemChosenCallback(consumer)
.withHintUpdateSupply()
.createPopup()
.showInBestPositionFor(editor)
}
private fun NavigationTarget.getPresentationIfValid(): TargetPresentation? {
return if (isValid) targetPresentation else null
}
@@ -1684,6 +1684,8 @@ ide.jvm.run.marker=false
ide.jvm.run.marker.description=Enable JVM-lang based run line markers
ide.create.field.enable.shortening=true
ide.create.field.enable.shortening.description=Always enable shortening of FQNs in templates in Create Field fixes
ide.goto.target=false
ide.goto.target.description=Use NavigationTarget/Symbol navigation instead of PsiElement navigation
use.prebuilt.indices=true
use.prebuilt.indices.description=Use bundled prebuilt stubs if they are available for better indexing performance