Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
94d7b66
Copy hover response content and diagnostics text from the hover popup
predragnikolic Aug 16, 2025
17f0c5e
fix display of errors diagnostics
predragnikolic Aug 16, 2025
a57a692
prepend the source of the diagnostics when coping diagnostics
predragnikolic Aug 16, 2025
6e524fb
allow copying text from the popup that appears with completions COOPE…
predragnikolic Aug 16, 2025
7d4ade4
cover signature help
predragnikolic Aug 16, 2025
c0ba0a1
rename copy_text_html_element to copy_text_html
predragnikolic Aug 16, 2025
75b3549
remove unused imports
predragnikolic Sep 2, 2025
1d8a53a
set status message as the original copy command
predragnikolic Sep 2, 2025
03c6702
fix flake8
predragnikolic Sep 2, 2025
9765365
make copy_text not nullable
predragnikolic Sep 2, 2025
5a77bf4
inherit the color instead of overriding it
predragnikolic Sep 2, 2025
51417da
fix flake8
predragnikolic Sep 2, 2025
0a25dab
don't expose _markup_to_string and only expose copy_text_html
predragnikolic Sep 2, 2025
bc2a060
split import
predragnikolic Sep 2, 2025
ce73520
sublime.command_url already does html.unescape
predragnikolic Sep 3, 2025
ab65e90
this is the reason why copying content from the signature help opened…
predragnikolic Sep 3, 2025
95d0512
wrap both the diagnostic message and source in a block element
predragnikolic Sep 5, 2025
18b26db
don't handle signature help for now
predragnikolic Sep 10, 2025
8c5a999
Revert "don't handle signature help for now"
predragnikolic Sep 10, 2025
a6655ae
Signature help was actually working, but the tests needed to be updated
predragnikolic Sep 12, 2025
8198c66
Update plugin/core/views.py
predragnikolic Sep 13, 2025
6f52d0d
sort lines
predragnikolic Sep 13, 2025
0e4ce02
if instead of elif
predragnikolic Sep 13, 2025
baed32c
remove .replace(' ', ' ') as I cannot seem to find the example hover …
predragnikolic Sep 13, 2025
1eea3a8
move _markup_to_string after copy_text_html
predragnikolic Sep 13, 2025
1ae508b
rename copy_text_html to wrap_in_copy_link and call markup_to_string …
predragnikolic Sep 13, 2025
08ae8cb
Merge branch 'main' into feature/copy_hover_content
predragnikolic Oct 15, 2025
7b327aa
add debug logs when on_navigate logic is not handled
predragnikolic Oct 15, 2025
aa4be0f
Add copy button for each diagnostic, but remove ability to copy text …
predragnikolic Oct 15, 2025
f05e74a
Revert test changes
predragnikolic Oct 15, 2025
d128f6d
remove wrap_in_copy_link
predragnikolic Oct 15, 2025
5b6088e
Change the look of the copy button
predragnikolic Oct 15, 2025
3b3839c
revert as it was
predragnikolic Oct 15, 2025
e02f3db
Reduce the padding
predragnikolic Oct 15, 2025
7945e79
Merge branch 'main' into feature/copy_hover_content
predragnikolic Nov 11, 2025
efbdd30
Use an UTF char for the icon
predragnikolic Nov 11, 2025
d79f9a7
reduce the UTF icon(char) size
predragnikolic Nov 11, 2025
199e68c
Use ⧉ and remove text
predragnikolic Nov 11, 2025
3fbf73d
keep source at the end with parentheses
predragnikolic Nov 11, 2025
4e6d21f
move inline style for color: inherit to popups.css
predragnikolic Nov 11, 2025
89f3bab
use single quotes for consistency
predragnikolic Nov 11, 2025
096d29f
use space instead of  
predragnikolic Nov 11, 2025
09113ba
revert unnecessary change
predragnikolic Nov 11, 2025
6f9be2e
use pngs, they can be rendered successfully
predragnikolic Nov 12, 2025
87cf18b
adjust based on feedback
predragnikolic Nov 13, 2025
b0393ba
Copy -> Copy to clipboard
predragnikolic Nov 13, 2025
226e125
change LspCopyTextCommand to be a WindowCommand
predragnikolic Nov 13, 2025
ee173a7
change class names
predragnikolic Nov 13, 2025
c0957cb
adjust based on latest feedback
predragnikolic Nov 13, 2025
fa851c0
remove font-size: 1rem
predragnikolic Nov 13, 2025
478f64c
remove span
predragnikolic Nov 13, 2025
fd2c7e0
add "on_navigate unhandled href"
predragnikolic Nov 13, 2025
5726cd6
inline code
predragnikolic Nov 14, 2025
b2791ce
remove line at the end of popups.css
predragnikolic Nov 14, 2025
13be4ea
replace OxaO with a space char
predragnikolic Nov 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions boot.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
from .plugin.hierarchy import LspCallHierarchyCommand
from .plugin.hierarchy import LspHierarchyToggleCommand
from .plugin.hierarchy import LspTypeHierarchyCommand
from .plugin.hover import LspCopyTextCommand
from .plugin.hover import LspHoverCommand
from .plugin.hover import LspToggleHoverPopupsCommand
from .plugin.inlay_hint import LspInlayHintClickCommand
Expand Down Expand Up @@ -158,6 +159,7 @@
"LspUpdateLogPanelCommand",
"LspUpdatePanelCommand",
"LspWorkspaceSymbolsCommand",
'LspCopyTextCommand',
Comment thread
rchl marked this conversation as resolved.
Outdated
"TextChangeListener",
"plugin_loaded",
"plugin_unloaded",
Expand Down
8 changes: 5 additions & 3 deletions plugin/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
from .core.edit import apply_text_edits
from .core.logging import debug
from .core.promise import Promise
from .core.protocol import EditRangeWithInsertReplace
from .core.protocol import CompletionItem
from .core.protocol import CompletionItemDefaults
from .core.protocol import CompletionItemKind
from .core.protocol import CompletionItemTag
from .core.protocol import CompletionList
from .core.protocol import CompletionParams
from .core.protocol import EditRangeWithInsertReplace
from .core.protocol import Error
from .core.protocol import InsertReplaceEdit
from .core.protocol import InsertTextFormat
Expand All @@ -20,7 +20,9 @@
from .core.registry import LspTextCommand
from .core.sessions import Session
from .core.settings import userprefs
from .core.views import copy_text_html
from .core.views import FORMAT_STRING, FORMAT_MARKUP_CONTENT
from .core.views import markup_to_string
from .core.views import MarkdownLangMap
from .core.views import minihtml
from .core.views import range_to_region
Expand Down Expand Up @@ -303,9 +305,9 @@ def _handle_resolve_response_async(self, language_map: MarkdownLangMap | None, i
documentation = self._format_documentation(markdown, None)
minihtml_content = ""
if detail:
minihtml_content += f"<div class='highlight'>{detail}</div>"
minihtml_content += copy_text_html(f"<div class='highlight'>{detail}</div>", copy_text=item.get('detail'))
if documentation:
minihtml_content += documentation
minihtml_content += copy_text_html(documentation, markup_to_string(item.get("documentation") or ""))
Comment thread
rchl marked this conversation as resolved.
Outdated

def run_main() -> None:
if not self.view.is_valid():
Expand Down
12 changes: 6 additions & 6 deletions plugin/core/signature_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from .protocol import SignatureHelp
from .protocol import SignatureInformation
from .registry import LspTextCommand
from .views import FORMAT_MARKUP_CONTENT
from .views import FORMAT_MARKUP_CONTENT, copy_text_html, markup_to_string
from .views import FORMAT_STRING
from .views import MarkdownLangMap
from .views import minihtml
Expand Down Expand Up @@ -83,7 +83,7 @@ def render(self, view: sublime.View) -> str:
else:
self._active_parameter_bold = active_parameter_style.get('bold', False)
self._active_parameter_underline = active_parameter_style.get('underline', False)
formatted.extend(self._render_label(signature))
formatted.append(self._render_label(signature))
formatted.extend(self._render_docs(view, signature))
return "".join(formatted)

Expand Down Expand Up @@ -111,7 +111,7 @@ def _render_intro(self) -> str:
len(self._signatures),
)

def _render_label(self, signature: SignatureInformation) -> list[str]:
def _render_label(self, signature: SignatureInformation) -> str:
formatted: list[str] = []
# Note that this <div> class and the extra <pre> are copied from mdpopups' HTML output. When mdpopups changes
# its output style, we must update this literal string accordingly.
Expand Down Expand Up @@ -147,7 +147,7 @@ def _render_label(self, signature: SignatureInformation) -> list[str]:
else:
formatted.append(self._function(label))
formatted.append("</pre></div>")
return formatted
return copy_text_html("".join(formatted), label)

def _render_docs(self, view: sublime.View, signature: SignatureInformation) -> list[str]:
formatted: list[str] = []
Expand Down Expand Up @@ -175,14 +175,14 @@ def _parameter_documentation(self, view: sublime.View, signature: SignatureInfor
documentation = parameter.get("documentation")
if documentation:
allowed_formats = FORMAT_STRING | FORMAT_MARKUP_CONTENT
return minihtml(view, documentation, allowed_formats, self._language_map)
return copy_text_html(minihtml(view, documentation, allowed_formats, self._language_map), copy_text=markup_to_string(documentation))
return None

def _signature_documentation(self, view: sublime.View, signature: SignatureInformation) -> str | None:
documentation = signature.get("documentation")
if documentation:
allowed_formats = FORMAT_STRING | FORMAT_MARKUP_CONTENT
return minihtml(view, documentation, allowed_formats, self._language_map)
return copy_text_html(minihtml(view, documentation, allowed_formats, self._language_map), copy_text=markup_to_string(documentation))
return None

def _function(self, content: str) -> str:
Expand Down
23 changes: 21 additions & 2 deletions plugin/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -820,9 +820,9 @@ def _html_element(name: str, text: str, class_name: str | None = None, escape: b


def format_diagnostic_for_html(config: ClientConfig, diagnostic: Diagnostic, base_dir: str | None = None) -> str:
html = _html_element('span', diagnostic["message"])
code = diagnostic.get("code")
source = diagnostic.get("source")
source = diagnostic.get("source") or ""
Comment thread
rchl marked this conversation as resolved.
Outdated
html = copy_text_html(_html_element('span', diagnostic["message"]), copy_text=f"{source} {diagnostic['message']}")
if source or code is not None:
meta_info = ""
if source:
Expand All @@ -840,6 +840,25 @@ def format_diagnostic_for_html(config: ClientConfig, diagnostic: Diagnostic, bas
return _html_element("pre", html, class_name=severity_class, escape=False)


def markup_to_string(content: MarkupContent | MarkedString | list[MarkedString]) -> str:
if isinstance(content, str):
return content
elif isinstance(content, dict):
return content.get('value', '')
elif isinstance(content, list):
Comment thread
rchl marked this conversation as resolved.
Outdated
return " ".join(content) # pyright: ignore[reportCallIssue, reportUnknownVariableType, reportArgumentType]
Comment thread
predragnikolic marked this conversation as resolved.
Outdated


def copy_text_html(html_content: str, copy_text: str | None = None) -> str:
if copy_text is None:
copy_text = html_content
return f"""<a title="Click to Copy"
style='text-decoration: none; display: block; color: var(--foreground)'
href='{sublime.command_url('lsp_copy_text', {
'text': html.unescape(copy_text.replace(' ', ' '))
})}'>{html_content}</a>"""


def format_code_actions_for_quick_panel(
session_actions: Iterable[tuple[str, CodeAction | Command]]
) -> tuple[list[sublime.QuickPanelItem], int]:
Expand Down
17 changes: 14 additions & 3 deletions plugin/hover.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
from .core.protocol import DocumentLink
from .core.protocol import Error
from .core.protocol import Hover
from .core.protocol import MarkedString
from .core.protocol import MarkupContent
from .core.protocol import Position
from .core.protocol import Range
from .core.protocol import Request
Expand All @@ -23,11 +25,13 @@
from .core.sessions import SessionBufferProtocol
from .core.settings import userprefs
from .core.url import parse_uri
from .core.views import copy_text_html
from .core.views import diagnostic_severity
from .core.views import format_code_actions_for_quick_panel
from .core.views import format_diagnostic_for_html
from .core.views import FORMAT_MARKED_STRING
from .core.views import FORMAT_MARKUP_CONTENT
from .core.views import markup_to_string
from .core.views import is_location_href
from .core.views import make_command_link
from .core.views import make_link
Expand All @@ -46,7 +50,6 @@
import sublime
import sublime_plugin


SessionName = str
ResolvedHover = Union[Hover, Error]

Expand Down Expand Up @@ -259,11 +262,14 @@ def diagnostics_content(self) -> str:
return "".join(formatted)

def hover_content(self) -> str:
contents = []
contents: list[str] = []
for hover, language_map in self._hover_responses:
content = (hover.get('contents') or '') if isinstance(hover, dict) else ''
allowed_formats = FORMAT_MARKED_STRING | FORMAT_MARKUP_CONTENT
contents.append(minihtml(self.view, content, allowed_formats, language_map))
html_content = minihtml(self.view, content, allowed_formats, language_map)
copy_text = markup_to_string(content)
html_content = copy_text_html(html_content, copy_text)
contents.append(html_content)
return '<hr>'.join(contents)

def hover_range(self) -> sublime.Region | None:
Expand Down Expand Up @@ -420,3 +426,8 @@ def _update_views_async(self, enable: bool) -> None:
session_view.view.settings().set(SHOW_DEFINITIONS_KEY, False)
else:
session_view.reset_show_definitions()


class LspCopyTextCommand(sublime_plugin.TextCommand):
Comment thread
rchl marked this conversation as resolved.
Outdated
Comment thread
predragnikolic marked this conversation as resolved.
Outdated
def run(self, edit, text: str) -> None:
sublime.set_clipboard(text)
Comment thread
rchl marked this conversation as resolved.
Outdated
Loading