IJPL-92247 Let Cmd+B navigate to link target in Markdown

GitOrigin-RevId: 3b2e236ab915c63d5f70c915953b2e4bf4cf0480
This commit is contained in:
Anastasiya Bortnikova
2026-05-28 16:23:54 +00:00
committed by intellij-monorepo-bot
parent b1aad7c225
commit 03f7175f37
5 changed files with 56 additions and 3 deletions
@@ -5,7 +5,7 @@
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* <info descr="Open in browser (Ctrl+Click)">http://www.apache.org/licenses/LICENSE-2.0</info>
* <info descr="Open in browser (Ctrl+Click, Ctrl+B)">http://www.apache.org/licenses/LICENSE-2.0</info>
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
@@ -29,7 +29,7 @@ public class JavaWebReferenceTest extends LightJavaCodeInsightFixtureTestCase {
public void testHighlighting() {
getReferences("class Hi { String url=\"<info descr=\"Open in browser (" +
(SystemInfoRt.isMac ? "⌘Click" : "Ctrl+Click") + ")\">http://foo</info>\"; }");
(SystemInfoRt.isMac ? "⌘Click, ⌘B" : "Ctrl+Click, Ctrl+B") + ")\">http://foo</info>\"; }");
myFixture.testHighlighting(true, true, true);
}
@@ -169,7 +169,15 @@ public class HyperlinkAnnotator implements Annotator, DumbAware {
Shortcut mouseShortcut = ContainerUtil.find(shortcuts, shortcut -> !shortcut.isKeyboard());
if (mouseShortcut != null) {
shortcutText += KeymapUtil.getShortcutText(mouseShortcut);
return shortcutText.replace("Button1 ", "");
shortcutText = shortcutText.replace("Button1 ", "");
}
Shortcut keyboardShortcut = ContainerUtil.find(shortcuts, shortcut -> shortcut.isKeyboard());
if (keyboardShortcut != null) {
if (!shortcutText.isEmpty()) shortcutText += ", ";
shortcutText += KeymapUtil.getShortcutText(keyboardShortcut);
}
if (!shortcutText.isEmpty()) {
return shortcutText;
}
return "";
}
@@ -56,6 +56,10 @@ abstract class BaseToggleStateAction: ToggleAction(), DumbAware {
event.presentation.isEnabled = false
return false
}
if (shouldIgnoreLinkElement(selectionElements)) {
event.presentation.isEnabled = false
return false
}
val commonParents = selectionElements.map { (left, right) -> getCommonParentOfType(left, right, targetNodeType) }
val hasMissingParents = commonParents.any { it == null }
@@ -165,6 +169,11 @@ abstract class BaseToggleStateAction: ToggleAction(), DumbAware {
targetNodeType != MarkdownElementTypes.CODE_SPAN
&& selectionElements.any { getCommonParentOfType(it.first, it.second, MarkdownElementTypes.CODE_SPAN) != null }
private fun shouldIgnoreLinkElement(selectionElements: Sequence<Pair<PsiElement, PsiElement>>) =
selectionElements.any { (left, right) ->
elementsToIgnore.any { type -> getCommonParentOfType(left, right, type) != null }
}
companion object {
private val elementsToIgnore = setOf(
MarkdownElementTypes.LINK_DESTINATION,
@@ -41,6 +41,42 @@ class MarkdownStylingActionsConsistencyTest {
checkResultByText(content)
}
fun `test enabled inside inline link text`() {
val content = """
Click [<selection>JetBrains</selection>](https://jetbrains.com) here
""".trimIndent()
val applied = """
Click [$wrapPrefix<selection>JetBrains</selection>$wrapSuffix](https://jetbrains.com) here
""".trimIndent()
configureFromFileText("some.md", content)
executeAction(actionId)
checkResultByText(applied)
executeAction(actionId)
checkResultByText(content)
}
fun `test disabled inside inline link destination`() {
// language=Markdown
val content = """
Click [text](https://exa<caret>mple.com) here
""".trimIndent()
configureFromFileText("some.md", content)
val action = ActionManager.getInstance().getAction(actionId)
assertFalse(EditorTestUtil.checkActionIsEnabled(editor, action))
checkResultByText(content)
}
fun `test disabled inside autolink`() {
// language=Markdown
val content = """
Visit <https://exa<caret>mple.com>
""".trimIndent()
configureFromFileText("some.md", content)
val action = ActionManager.getInstance().getAction(actionId)
assertFalse(EditorTestUtil.checkActionIsEnabled(editor, action))
checkResultByText(content)
}
fun `test whole line`() {
// language=Markdown
val content = """