diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/CreateTBXReferenceTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/CreateTBXReferenceTest.kt index f8dca6f4c369..32f893c68069 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/CreateTBXReferenceTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/CreateTBXReferenceTest.kt @@ -3,7 +3,6 @@ package com.intellij.java.codeInsight import com.intellij.JavaTestUtil import com.intellij.ide.DataManager -import com.intellij.idea.Bombed import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionPlaces import com.intellij.openapi.actionSystem.AnActionEvent @@ -27,7 +26,6 @@ class CreateTBXReferenceTest : BasePlatformTestCase() { doTest("jetbrains://idea/navigate/reference?project=light_temp&fqn=X&selection=3:3-7:3") } - @Bombed(year = 2019, month = 9, day = 10, user = "kradima") fun testMultipleSelections() { doTest( "jetbrains://idea/navigate/reference?project=light_temp&path=MultipleSelections.java:11:5&selection1=2:5-4:5&selection2=5:5-7:5&selection3=8:5-10:5&selection4=11:5-13:5") @@ -38,7 +36,6 @@ class CreateTBXReferenceTest : BasePlatformTestCase() { getTestName(false) + ".groovy") } - @Bombed(year = 2019, month = 9, day = 10, user = "kradima") fun testPathWithLocation() { doTest("jetbrains://idea/navigate/reference?project=light_temp&path=PathWithLocation.java:4:13") } diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CopyPathProvider.kt b/platform/lang-impl/src/com/intellij/ide/actions/CopyPathProvider.kt index 109a642bbfd5..c6cd50c8e7a9 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CopyPathProvider.kt +++ b/platform/lang-impl/src/com/intellij/ide/actions/CopyPathProvider.kt @@ -16,6 +16,7 @@ import com.intellij.openapi.roots.ProjectFileIndex import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiElement +import java.awt.datatransfer.StringSelection abstract class CopyPathProvider : DumbAwareAction() { override fun update(e: AnActionEvent) { @@ -41,10 +42,13 @@ abstract class CopyPathProvider : DumbAwareAction() { val dataContext = e.dataContext val editor = CommonDataKeys.EDITOR.getData(dataContext) - val copy = project?.let { getQualifiedName(it, getElementsToCopy(editor, dataContext), editor) } + val elements = getElementsToCopy(editor, dataContext) + val copy = project?.let { getQualifiedName(it, elements, editor) } - CopyPasteManager.getInstance().setContents(CopyReferenceFQNTransferable(copy)) + CopyPasteManager.getInstance().setContents(StringSelection(copy)) setStatusBarText(project, IdeBundle.message("message.path.to.fqn.has.been.copied", copy)) + + CopyReferenceUtil.highlight(editor, project, elements) } open fun getQualifiedName(project: Project?, elements: List, editor: Editor?): String? { @@ -112,6 +116,6 @@ class CopySourceRootPathProvider : CopyPathProvider() { class CopyTBXReferenceProvider : CopyPathProvider() { override fun getQualifiedName(project: Project?, elements: List, - editor: Editor?): String = - project?.let { CopyTBXReferenceAction.createJetbrainsLink(project, elements, editor) } ?: "" + editor: Editor?): String? = + project?.let { CopyTBXReferenceAction.createJetbrainsLink(project, elements, editor) } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CopyReferencePopupAction.java b/platform/lang-impl/src/com/intellij/ide/actions/CopyReferencePopupAction.java index 23ad64d31d29..3c9dcaf6d162 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CopyReferencePopupAction.java +++ b/platform/lang-impl/src/com/intellij/ide/actions/CopyReferencePopupAction.java @@ -1,17 +1,14 @@ // 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.ide.actions; -import com.intellij.codeInsight.TargetElementUtil; import com.intellij.ide.IdeBundle; import com.intellij.ide.dnd.FileCopyPasteUtil; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.ide.CopyPasteManager; import com.intellij.openapi.project.DumbAwareAction; -import com.intellij.openapi.project.DumbService; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; import one.util.streamex.StreamEx; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,8 +32,7 @@ class CopyReferencePopupAction extends DumbAwareAction { presentation.setEnabled(enabled); presentation.setVisible(!ActionPlaces.isPopupPlace(e.getPlace()) || enabled); presentation.setText(elements.size() > 1 ? "References" : "Reference"); - presentation.putClientProperty(CopyReferencePopup.COPY_REFERENCE_KEY, - doElementsCopy(getElementsToCopy(editor, dataContext), editor)); + presentation.putClientProperty(CopyReferencePopup.COPY_REFERENCE_KEY, doElementsCopy(getElementsToCopy(editor, dataContext), editor)); } @Override @@ -58,37 +54,9 @@ class CopyReferencePopupAction extends DumbAwareAction { } } - @Nullable - static String getQualifiedNameFromProviders(@Nullable PsiElement element) { - if (element == null) return null; - DumbService.getInstance(element.getProject()).setAlternativeResolveEnabled(true); - try { - return QualifiedNameProviderUtil.getQualifiedName(element); - } - finally { - DumbService.getInstance(element.getProject()).setAlternativeResolveEnabled(false); - } - } - static String doElementsCopy(@NotNull List elements, @Nullable Editor editor) { if (elements.isEmpty()) return null; - return StreamEx.of(elements).map(element -> getQualifiedReference(element, editor)).filter(fqn -> fqn != null).joining("\n"); - } - - @Nullable - private static String getQualifiedReference(@Nullable PsiElement element, - @Nullable Editor editor) { - String result = getQualifiedNameFromProviders(element); - if (result != null) return result; - - if (editor != null) { //IDEA-70346 - PsiReference reference = TargetElementUtil.findReference(editor, editor.getCaretModel().getOffset()); - if (reference != null) { - result = getQualifiedNameFromProviders(reference.resolve()); - if (result != null) return result; - } - } - return null; + return StreamEx.of(elements).map(element -> elementToFqn(element, editor)).filter(fqn -> fqn != null).joining("\n"); } } \ No newline at end of file diff --git a/platform/lang-impl/src/com/intellij/ide/actions/CopyTBXReferenceAction.kt b/platform/lang-impl/src/com/intellij/ide/actions/CopyTBXReferenceAction.kt index d83bd032aae9..7ae149638606 100644 --- a/platform/lang-impl/src/com/intellij/ide/actions/CopyTBXReferenceAction.kt +++ b/platform/lang-impl/src/com/intellij/ide/actions/CopyTBXReferenceAction.kt @@ -1,7 +1,6 @@ // 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.ide.actions -import com.intellij.ide.IdeBundle import com.intellij.ide.actions.CopyReferenceUtil.* import com.intellij.navigation.JBProtocolNavigateCommand.Companion.FQN_KEY import com.intellij.navigation.JBProtocolNavigateCommand.Companion.NAVIGATE_COMMAND @@ -9,185 +8,115 @@ import com.intellij.navigation.JBProtocolNavigateCommand.Companion.PATH_KEY import com.intellij.navigation.JBProtocolNavigateCommand.Companion.PROJECT_NAME_KEY import com.intellij.navigation.JBProtocolNavigateCommand.Companion.REFERENCE_TARGET import com.intellij.navigation.JBProtocolNavigateCommand.Companion.SELECTION -import com.intellij.openapi.actionSystem.ActionPlaces -import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.JetBrainsProtocolHandler import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.editor.Caret import com.intellij.openapi.editor.Editor -import com.intellij.openapi.fileEditor.FileDocumentManager -import com.intellij.openapi.ide.CopyPasteManager -import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.util.registry.Registry import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiElement import com.intellij.psi.PsiFileSystemItem import com.intellij.util.PlatformUtils.* import com.intellij.util.io.encodeUrlQueryParameter -import java.awt.datatransfer.StringSelection import java.util.stream.Collectors import java.util.stream.IntStream -class CopyTBXReferenceAction : DumbAwareAction() { - init { - isEnabledInModalContext = true - setInjectedContext(true) - } +object CopyTBXReferenceAction { + private val LOG = Logger.getInstance(CopyTBXReferenceAction::class.java) + private const val JETBRAINS_NAVIGATE = JetBrainsProtocolHandler.PROTOCOL + private val IDE_TAGS = mapOf(IDEA_PREFIX to "idea", + IDEA_CE_PREFIX to "idea", + APPCODE_PREFIX to "appcode", + CLION_PREFIX to "clion", + PYCHARM_PREFIX to "pycharm", + PYCHARM_CE_PREFIX to "pycharm", + PYCHARM_EDU_PREFIX to "pycharm", + PHP_PREFIX to "php-storm", + RUBY_PREFIX to "rubymine", + WEB_PREFIX to "web-storm", + RIDER_PREFIX to "rd", + GOIDE_PREFIX to "goland") - override fun update(e: AnActionEvent) { - if (!Registry.`is`("copy.tbx.reference.enabled")) { - e.presentation.isEnabledAndVisible = false - return + fun createJetbrainsLink(project: Project, elements: List, editor: Editor?): String? { + val entries = IntArray(elements.size) { i -> i } + .associateBy({ it }, { elementToFqn(elements[it], editor) }) + .filter { it.value != null } + .mapValues { FileUtil.getLocationRelativeToUserHome(it.value, false) } + .entries + + val refsParameters = if (entries.isEmpty()) null + else entries.joinToString("") { + createRefs(isFile(elements[it.key]), if (elements.size > 1) it.value.encodeUrlQueryParameter() else it.value, + parameterIndex(it.key, elements.size)) } - var plural = false - var enabled: Boolean - var paths = false + val copy = createLink(editor, project, refsParameters) + if (copy != null) return copy - val dataContext = e.dataContext - val editor = CommonDataKeys.EDITOR.getData(dataContext) - if (editor != null && FileDocumentManager.getInstance().getFile(editor.document) != null) { - enabled = true + if (editor == null) return null + val file = PsiDocumentManager.getInstance(project).getCachedPsiFile(editor.document) + + if (file == null) return null + val logicalPosition = editor.caretModel.logicalPosition + val path = "${getFileFqn(file)}:${logicalPosition.line + 1}:${logicalPosition.column + 1}" + + return createLink(editor, project, createRefs(true, path, "")) + } + + private fun isFile(element: PsiElement) = element is PsiFileSystemItem && getQualifiedNameFromProviders(element) == null + + private fun parameterIndex(index: Int, size: Int) = if (size == 1) "" else "${index + 1}" + + private fun createRefs(isFile: Boolean, reference: String?, index: String) = "&${if (isFile) PATH_KEY else FQN_KEY}${index}=$reference" + + private fun createLink(editor: Editor?, project: Project, refsParameters: String?): String? { + if (refsParameters == null) return null + + val tool = IDE_TAGS[getPlatformPrefix()] + if (tool == null) { + LOG.warn("Cannot find TBX tool for IDE: ${getPlatformPrefix()}") + return null + } + + val selectionParameters = getSelectionParameters(editor) ?: "" + val projectParameter = "$PROJECT_NAME_KEY=${project.name}" + + return "$JETBRAINS_NAVIGATE$tool/$NAVIGATE_COMMAND/$REFERENCE_TARGET?$projectParameter$refsParameters$selectionParameters" + } + + private fun getSelectionParameters(editor: Editor?): String? { + if (editor == null) { + return null + } + + ApplicationManager.getApplication().assertReadAccessAllowed() + if (editor.caretModel.supportsMultipleCarets()) { + val carets = editor.caretModel.allCarets + return IntStream.range(0, carets.size).mapToObj { i -> getSelectionParameters(editor, carets[i], parameterIndex(i, carets.size)) } + .filter { it != null }.collect(Collectors.joining()) } else { - val elements = getElementsToCopy(editor, dataContext) - enabled = !elements.isEmpty() - plural = elements.size > 1 - paths = elements.stream().allMatch { el -> el is PsiFileSystemItem && getQualifiedNameFromProviders(el) == null } + return getSelectionParameters(editor, editor.caretModel.currentCaret, "") } - - enabled = enabled && (ActionPlaces.MAIN_MENU == e.place) - e.presentation.isEnabled = enabled - if (ActionPlaces.isPopupPlace(e.place)) { - e.presentation.isVisible = enabled - } - else { - e.presentation.isVisible = true - } - e.presentation.text = if (paths) - - if (plural) "Cop&y Toolbox Relative Paths URL" else "Cop&y Toolbox Relative Path URL" - else if (plural) "Cop&y Toolbox References URL" else "Cop&y Toolbox Reference URL" } - override fun actionPerformed(e: AnActionEvent) { - val dataContext = e.dataContext - val editor = CommonDataKeys.EDITOR.getData(dataContext) - val project = CommonDataKeys.PROJECT.getData(dataContext) - val elements = getElementsToCopy(editor, dataContext) + private fun getSelectionParameters(editor: Editor, caret: Caret, index: String): String? = + getSelectionRange(editor, caret)?.let { "&$SELECTION$index=$it" } - if (project == null) { - LOG.warn("'Copy TBX Reference' action cannot find project.") - return + private fun getSelectionRange(editor: Editor, caret: Caret): String? { + if (!caret.hasSelection()) { + return null } - var copy = createJetbrainsLink(project, elements, editor) - if (copy != null) { - CopyPasteManager.getInstance().setContents(CopyReferenceFQNTransferable(copy)) - setStatusBarText(project, IdeBundle.message("message.reference.to.fqn.has.been.copied", copy)) - } - else if (editor != null) { - val document = editor.document - val file = PsiDocumentManager.getInstance(project).getCachedPsiFile(document) - if (file != null) { - val logicalPosition = editor.caretModel.logicalPosition - val path = "${getFileFqn(file)}:${logicalPosition.line + 1}:${logicalPosition.column + 1}" - copy = createLink(editor, project, createRefs(true, path, "")) - CopyPasteManager.getInstance().setContents(StringSelection(copy)) - setStatusBarText(project, "$copy has been copied") - } - return - } + val selectionStart = editor.visualToLogicalPosition(caret.selectionStartPosition) + val selectionEnd = editor.visualToLogicalPosition(caret.selectionEndPosition) - highlight(editor, project, elements) - } - - companion object { - private val LOG = Logger.getInstance(CopyTBXReferenceAction::class.java) - private const val JETBRAINS_NAVIGATE = JetBrainsProtocolHandler.PROTOCOL - private val IDE_TAGS = mapOf(IDEA_PREFIX to "idea", - IDEA_CE_PREFIX to "idea", - APPCODE_PREFIX to "appcode", - CLION_PREFIX to "clion", - PYCHARM_PREFIX to "pycharm", - PYCHARM_CE_PREFIX to "pycharm", - PYCHARM_EDU_PREFIX to "pycharm", - PHP_PREFIX to "php-storm", - RUBY_PREFIX to "rubymine", - WEB_PREFIX to "web-storm", - RIDER_PREFIX to "rd", - GOIDE_PREFIX to "goland") - - fun createJetbrainsLink(project: Project, elements: List, editor: Editor?): String? { - val refsParameters = - IntArray(elements.size) { i -> i } - .associateBy({ it }, { elementToFqn(elements[it], editor) }) - .filter { it.value != null } - .mapValues { FileUtil.getLocationRelativeToUserHome(it.value, false) } - .entries - .ifEmpty { return null } - .joinToString("") { - val reference = if (elements.size > 1) it.value.encodeUrlQueryParameter() else it.value - createRefs(isFile(elements[it.key]), reference, parameterIndex(it.key, elements.size)) } - - return createLink(editor, project, refsParameters) - } - - private fun isFile(element: PsiElement) = element is PsiFileSystemItem && getQualifiedNameFromProviders(element) == null - - private fun parameterIndex(index: Int, size: Int) = if (size == 1) "" else "${index + 1}" - - private fun createRefs(isFile: Boolean, reference: String?, index: String) = "&${if (isFile) PATH_KEY else FQN_KEY}${index}=$reference" - - private fun createLink(editor: Editor?, project: Project, refsParameters: String?): String? { - val tool = IDE_TAGS[getPlatformPrefix()] - if (tool == null) { - LOG.warn("Cannot find TBX tool for IDE: ${getPlatformPrefix()}") - return null - } - - val selectionParameters = getSelectionParameters(editor) ?: "" - val projectParameter = "$PROJECT_NAME_KEY=${project.name}" - - return "$JETBRAINS_NAVIGATE$tool/$NAVIGATE_COMMAND/$REFERENCE_TARGET?$projectParameter$refsParameters$selectionParameters" - } - - private fun getSelectionParameters(editor: Editor?): String? { - if (editor == null) { - return null - } - - ApplicationManager.getApplication().assertReadAccessAllowed() - if (editor.caretModel.supportsMultipleCarets()) { - val carets = editor.caretModel.allCarets - return IntStream.range(0, carets.size).mapToObj { i -> getSelectionParameters(editor, carets[i], parameterIndex(i, carets.size)) } - .filter { it != null }.collect(Collectors.joining()) - } - else { - return getSelectionParameters(editor, editor.caretModel.currentCaret, "") - } - } - - private fun getSelectionParameters(editor: Editor, caret: Caret, index: String): String? = - getSelectionRange(editor, caret)?.let { "&$SELECTION$index=$it" } - - private fun getSelectionRange(editor: Editor, caret: Caret): String? { - if (!caret.hasSelection()) { - return null - } - - val selectionStart = editor.visualToLogicalPosition(caret.selectionStartPosition) - val selectionEnd = editor.visualToLogicalPosition(caret.selectionEndPosition) - - return String.format("%d:%d-%d:%d", - selectionStart.line + 1, - selectionStart.column + 1, - selectionEnd.line + 1, - selectionEnd.column + 1) - } + return String.format("%d:%d-%d:%d", + selectionStart.line + 1, + selectionStart.column + 1, + selectionEnd.line + 1, + selectionEnd.column + 1) } } \ No newline at end of file diff --git a/platform/platform-resources-en/src/messages/ActionsBundle.properties b/platform/platform-resources-en/src/messages/ActionsBundle.properties index 1051adcb9e07..c93c726c961c 100644 --- a/platform/platform-resources-en/src/messages/ActionsBundle.properties +++ b/platform/platform-resources-en/src/messages/ActionsBundle.properties @@ -346,8 +346,6 @@ action.CopyPaths.text=C_opy Paths action.CopyPaths.description=Copy paths corresponding to selected files or directories to clipboard action.CopyReference.text=Cop_y Reference action.CopyReference.description=Copy reference to selected class, method or function, or a relative path to selected file -action.CopyTBXReference.text=Copy _Toolbox Reference URL -action.CopyTBXReference.description=Copy Toolbox reference URL to selected class, method or function, or a relative path to selected file action.CopySettingsPath.text=Copy Settings Path action.CopySettingsPath.mac.text=Copy Preferences Path action.CopySettingsPath.description=Copy relative path to selected configurable option