Add support for MarkupContent in diagnostic message#2845
Add support for MarkupContent in diagnostic message#2845jwortmann merged 12 commits intosublimelsp:mainfrom
Conversation
Alternatively we could use |
|
Hi Janos,
I have a feeling that you think that sublimelsp/lsp-python-types relies on microsoft/lsprotocol, but that is not correct. sublimelsp/lsp-python-types relies on https://github.com/microsoft/vscode-languageserver-node This is the file that lsp-python-types fetches to generate the Python types |
Oh indeed I didn't know that. So if the |
Yes, that is correct. If you want feel free to ask in https://github.com/microsoft/vscode-languageserver-node when they plan to release the metaModel.json file for 3.18 (Sorry, I accidentally closed the PR while typing this message on a phone) |
|
Okay, so it still depends on an update in an upstream repository, just a different one... :) But it was added to the specs website already 2 years ago on 2024-03-19: microsoft/language-server-protocol@df7c77b But then it seems like it was later overwritten (accidentally?) in another commit microsoft/language-server-protocol@7e1b69d on 2024-08-05. So maybe that's a bug that prevents the upstream types from ever being updated correctly. |
|
I've created microsoft/language-server-protocol#2246 Let's see if we get an answer there. |
|
Until they answer, |
|
I remember using TypeGuard to narrow down types (similar to TypeIs), pyright did understand TypeGuard |
|
If pyright doesn't support it correctly then we should probably not use it. I guess the alternatives could be to either:
|
|
The newlines also seem to be missing... Diagnostic from the screenshot: {
"code": "missing-import",
"codeDescription": {
"href": "https://pyrefly.org/en/docs/error-kinds/#missing-import"
},
"data": "committing-transaction",
"message": {
"kind": "markdown",
"value": "Cannot find module `sublime`\n Looked in these locations (from config in `/usr/local/workspace/sublime-packages/LSP/pyproject.toml`):\n Import root (inferred from project layout): \"/usr/local/workspace/sublime-packages/LSP\"\n Site package path queried from interpreter: \\[\"/usr/local/workspace/sublime-packages/LSP/.venv/lib/python3.8/site-packages\"\\]"
},
"range": {
"end": {
"character": 14,
"line": 27
},
"start": {
"character": 7,
"line": 27
}
},
"severity": 1,
"source": "Pyrefly"
},Pure markdown value is: which github parser seems to render with newlines but without leading spaces: Cannot find module So it doesn't seem to be perfectly authored markdown code. |
It doesn't look like that for me (see screenshots in opening comment). Have you restarted ST? The CSS changes are only picked up after a restart. |
|
I'm on a new internal build from few days ago that runs on 3.14 and mdpopups uses new parser of course. Here is how the popup content looks like here: Click to expand<style>
html {
--mdpopups-fg: var(--foreground);
--mdpopups-link: var(--bluish);
--mdpopups-del: var(--redish);
--mdpopups-kbd-fg: var(--background);
--mdpopups-kbd-bg: var(--foreground);
--mdpopups-font-mono: "sf mono", Consolas, "Liberation Mono", Menlo, Courier, monospace;
--mdpopups-admon-fg: var(--foreground);
--mdpopups-admon-note-fg: var(--foreground);
--mdpopups-admon-tip-fg: var(--foreground);
--mdpopups-admon-warning-fg: var(--foreground);
--mdpopups-admon-caution-fg: var(--foreground);
--mdpopups-admon-important-fg: var(--foreground);
--mdpopups-admon-bg: var(--background);
--mdpopups-admon-note-bg: var(--background);
--mdpopups-admon-tip-bg: var(--background);
--mdpopups-admon-warning-bg: var(--background);
--mdpopups-admon-caution-bg: var(--background);
--mdpopups-admon-important-bg: var(--background);
--mdpopups-admon-title-fg: var(--foreground);
--mdpopups-admon-note-title-fg: var(--foreground);
--mdpopups-admon-tip-title-fg: var(--foreground);
--mdpopups-admon-warning-title-fg: var(--foreground);
--mdpopups-admon-caution-title-fg: var(--foreground);
--mdpopups-admon-important-title-fg: var(--foreground);
--mdpopups-admon-accent: color(var(--background) blend(var(--foreground) 50%));
--mdpopups-admon-note-accent: color(var(--background) blend(var(--bluish) 50%));
--mdpopups-admon-tip-accent: color(var(--background) blend(var(--greenish) 50%));
--mdpopups-admon-warning-accent: color(var(--background) blend(var(--orangish) 50%));
--mdpopups-admon-caution-accent: color(var(--background) blend(var(--redish) 50%));
--mdpopups-admon-important-accent: color(var(--background) blend(var(--purplish) 50%));
--mdpopups-admon-info-fg: var(--foreground);
--mdpopups-admon-error-fg: var(--foreground);
--mdpopups-admon-success-fg: var(--foreground);
--mdpopups-admon-info-bg: var(--background);
--mdpopups-admon-error-bg: var(--background);
--mdpopups-admon-success-bg: var(--background);
--mdpopups-admon-info-title-fg: var(--foreground);
--mdpopups-admon-error-title-fg: var(--foreground);
--mdpopups-admon-success-title-fg: var(--foreground);
--mdpopups-admon-info-accent: color(var(--background) blend(var(--bluish) 50%));
--mdpopups-admon-error-accent: color(var(--background) blend(var(--redish) 50%));
--mdpopups-admon-success-accent: color(var(--background) blend(var(--greenish) 50%));
}
html.light {
--mdpopups-bg: color(var(--background) blend(black 95%));
--mdpopups-hr: color(var(--background) blend(black 85%));
--mdpopups-kbd-border: color(var(--foreground) blend(white 80%));
--mdpopups-hl-border: color(var(--background) blend(black 90%));
--mdpopups-hl-bg: color(var(--background) blend(black 98%));
background-color: var(--mdpopups-bg);
}
html.dark {
--mdpopups-bg: color(var(--background) blend(white 95%));
--mdpopups-hr: color(var(--background) blend(white 85%));
--mdpopups-kbd-border: color(var(--foreground) blend(black 80%));
--mdpopups-hl-border: color(var(--background) blend(white 90%));
--mdpopups-hl-bg: color(var(--background) blend(white 98%));
background-color: var(--mdpopups-bg);
}
html,
body {
padding: 0;
margin: 0;
}
div.mdpopups {
display: block;
margin: 0;
padding: 0;
font-size: 1rem;
line-height: 1.1rem;
color: var(--mdpopups-fg);
background-color: var(--mdpopups-bg);
}
.mdpopups a {
color: var(--mdpopups-link);
}
.mdpopups ins {
text-decoration: underline;
}
.mdpopups del {
color: var(--mdpopups-del);
}
.mdpopups .highlight,
.mdpopups code,
.mdpopups var,
.mdpopups tt {
font-family: var(--mdpopups-font-mono);
}
.mdpopups div {
display: block;
}
.mdpopups h1 {
font-size: 1.5rem;
}
.mdpopups h2 {
font-size: 1.4rem;
}
.mdpopups h3 {
font-size: 1.3rem;
}
.mdpopups h4 {
font-size: 1.2rem;
}
.mdpopups h5 {
font-size: 1.1rem;
}
.mdpopups h6 {
font-size: 1rem;
}
.mdpopups h1,
.mdpopups h2,
.mdpopups h3,
.mdpopups h4,
.mdpopups h5,
.mdpopups h6 {
margin-top: 0.2rem;
margin-bottom: 0.2rem;
}
.mdpopups blockquote {
display: block;
margin-top: 0;
margin-bottom: 0.5rem;
margin-left: 0;
margin-right: 0;
padding: 0.5rem;
border-left: 0.25rem solid var(--mdpopups-fg);
}
.mdpopups hr {
display: block;
border-color: var(--mdpopups-hr);
border-style: solid;
border-width: 0 0 1px 0;
margin-top: 1rem;
margin-bottom: 1rem;
}
.mdpopups dl {
display: block;
}
.mdpopups dt {
display: block;
font-style: italic;
font-weight: bold;
margin-bottom: 0.5rem;
}
.mdpopups dd {
display: block;
margin-left: 1.5rem;
margin-bottom: 0.5rem;
}
.mdpopups pre {
display: block;
}
.mdpopups ol,
.mdpopups ul,
.mdpopups dl,
.mdpopups p {
padding: 0;
margin-top: 0;
margin-bottom: 0.5rem;
margin-left: 0;
margin-right: 0;
}
.mdpopups ul,
.mdpopups ol {
padding-left: 2rem;
}
.mdpopups kbd {
display: inline;
font-size: 0.9rem;
padding: 0.05rem 0.25rem;
border-radius: 0.25rem;
background-color: var(--mdpopups-kbd-bg);
color: var(--mdpopups-kbd-fg);
border: 1px solid var(--mdpopups-kbd-border);
}
.mdpopups .admonition,
.mdpopups blockquote.alert {
display: block;
padding: 0 0.5rem 0.5rem 0.5rem;
border-radius: 0.25rem;
margin-bottom: 0.5rem;
background-color: var(--mdpopups-admon-bg);
color: var(--mdpopups-admon-fg);
border: 1px solid var(--mdpopups-admon-accent);
}
.mdpopups .admonition-title,
.mdpopups .alert-title {
font-weight: 600;
font-size: 1.1rem;
margin: 0 -0.5rem 0.5rem -0.5rem;
padding: 0.1rem 0.5rem 0.1rem 0.5rem;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
color: var(--mdpopups-admon-title-fg);
background-color: var(--mdpopups-admon-accent);
}
.mdpopups .admonition.panel-info .admonition-title {
color: var(--mdpopups-admon-info-title-fg);
background-color: var(--mdpopups-admon-info-accent);
}
.mdpopups .admonition.panel-info {
color: var(--mdpopups-admon-info-fg);
background-color: var(--mdpopups-admon-info-bg);
border-color: var(--mdpopups-admon-info-accent);
}
.mdpopups .admonition.panel-success .admonition-title {
color: var(--mdpopups-admon-success-title-fg);
background-color: var(--mdpopups-admon-success-accent);
}
.mdpopups .admonition.panel-success {
color: var(--mdpopups-admon-success-fg);
background-color: var(--mdpopups-admon-success-bg);
border-color: var(--mdpopups-admon-success-accent);
}
.mdpopups .admonition.panel-error .admonition-title {
color: var(--mdpopups-admon-error-title-fg);
background-color: var(--mdpopups-admon-error-accent);
}
.mdpopups .admonition.panel-error {
color: var(--mdpopups-admon-error-fg);
background-color: var(--mdpopups-admon-error-bg);
border-color: var(--mdpopups-admon-error-accent);
}
.mdpopups .admonition.tip .admonition-title,
.mdpopups blockquote.alert-tip .alert-title {
color: var(--mdpopups-admon-tip-title-fg);
background-color: var(--mdpopups-admon-tip-accent);
}
.mdpopups .admonition.tip,
.mdpopups blockquote.alert-tip {
color: var(--mdpopups-admon-tip-fg);
background-color: var(--mdpopups-admon-tip-bg);
border-color: var(--mdpopups-admon-tip-accent);
}
.mdpopups .admonition.warning .admonition-title,
.mdpopups blockquote.alert-warning .alert-title,
.mdpopups .admonition.panel-warning .admonition-title {
color: var(--mdpopups-admon-warning-title-fg);
background-color: var(--mdpopups-admon-warning-accent);
}
.mdpopups .admonition.warning,
.mdpopups blockquote.alert-warning,
.mdpopups .admonition.panel-warning {
color: var(--mdpopups-admon-warning-fg);
background-color: var(--mdpopups-admon-warning-bg);
border-color: var(--mdpopups-admon-warning-accent);
}
.mdpopups .admonition.caution .admonition-title,
.mdpopups blockquote.alert-caution .alert-title {
color: var(--mdpopups-admon-caution-title-fg);
background-color: var(--mdpopups-admon-caution-accent);
}
.mdpopups .admonition.caution,
.mdpopups blockquote.alert-caution {
color: var(--mdpopups-admon-caution-fg);
background-color: var(--mdpopups-admon-caution-bg);
border-color: var(--mdpopups-admon-caution-accent);
}
.mdpopups .admonition.note .admonition-title,
.mdpopups blockquote.alert-note .alert-title {
color: var(--mdpopups-admon-note-title-fg);
background-color: var(--mdpopups-admon-note-accent);
}
.mdpopups .admonition.note,
.mdpopups blockquote.alert-note {
color: var(--mdpopups-admon-note-fg);
background-color: var(--mdpopups-admon-note-bg);
border-color: var(--mdpopups-admon-note-accent);
}
.mdpopups .admonition.important .admonition-title,
.mdpopups blockquote.alert-important .alert-title {
color: var(--mdpopups-admon-important-title-fg);
background-color: var(--mdpopups-admon-important-accent);
}
.mdpopups .admonition.important,
.mdpopups blockquote.alert-important {
color: var(--mdpopups-admon-important-fg);
background-color: var(--mdpopups-admon-important-bg);
border-color: var(--mdpopups-admon-important-accent);
}
.mdpopups .highlight,
.mdpopups code {
border: 1px solid var(--mdpopups-hl-border);
border-radius: 0.25rem;
font-size: 0.9rem;
background-color: var(--mdpopups-hl-bg);
}
.mdpopups div.highlight,
.mdpopups pre.highlight {
padding: 0.5rem;
margin-bottom: 0.5rem;
font-size: 1rem;
}
.mdpopups code.highlight,
.mdpopups code {
padding: 0.05rem 0.25rem;
}
.mdpopups pre code {
border: none;
border-radius: 0;
padding: 0;
}
.lsp_popup {
--font-size: 1rem;
--font-size-sm: 0.9rem;
font-family: system;
font-size: var(--font-size);
}
.mdpopups h1,
.mdpopups h2,
.mdpopups h3,
.mdpopups h4,
.mdpopups h5,
.mdpopups h6,
.lsp_popup div.highlight,
.lsp_popup pre.highlight {
font-size: var(--font-size);
}
.lsp_popup code.highlight {
font-size: var(--font-size-sm);
}
.mdpopups hr {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
border-color: color(var(--foreground) alpha(0.10));
}
.mdpopups kbd {
background-color: color(var(--mdpopups-bg) lightness(+ 5%));
border-color: color(var(--mdpopups-fg) alpha(0.25));
color: var(--mdpopups-fg);
font-size: 0.8rem;
line-height: 0.8rem;
}
.mdpopups blockquote.alert {
border-radius: 0;
border-width: 0;
border-left-width: 4px;
}
.mdpopups blockquote.alert p {
margin-bottom: 0;
}
.mdpopups blockquote.alert p.alert-title {
font-size: var(--font-size);
margin-bottom: 0.5rem;
margin-left: 0;
padding-left: 0;
}
.mdpopups blockquote.alert-tip .alert-title {
color: var(--mdpopups-admon-tip-accent);
background-color: transparent;
}
.mdpopups blockquote.alert-warning .alert-title {
color: var(--mdpopups-admon-warning-accent);
background-color: transparent;
}
.mdpopups blockquote.alert-caution .alert-title {
color: var(--mdpopups-admon-caution-accent);
background-color: transparent;
}
.mdpopups blockquote.alert-note .alert-title {
color: var(--mdpopups-admon-note-accent);
background-color: transparent;
}
.mdpopups blockquote.alert-important .alert-title {
color: var(--mdpopups-admon-important-accent);
background-color: transparent;
}
.lsp_popup .wrapper {
padding: 0.5rem;
padding-bottom: 0;
}
.lsp_popup .wrapper--spacer {
margin-top: .5rem;
}
.lsp_popup .m-0 {
margin: 0;
}
.diagnostics code.highlight {
background-color: color(white alpha(0.1));
border-color: transparent;
}
html.light .diagnostics code.highlight {
background-color: color(black alpha(0.1));
}
.color-muted {
color: color(var(--foreground) alpha(0.6));
}
.error,
.warning,
.information,
.hint {
color: var(--foreground);
}
.error {
background-color: color(var(--redish) alpha(0.2));
}
.warning {
background-color: color(var(--yellowish) alpha(0.2));
}
.information {
background-color: color(var(--bluish) alpha(0.2));
}
.hint {
background-color: color(var(--bluish) alpha(0.2));
}
.signature-help-intro {
font-size: var(--font-size-sm);
}
.actions {
background-color: color(var(--foreground) alpha(0.1));
}
.actions a {
text-decoration: none;
}
.lightbulb {
position: relative;
bottom: -2px;
padding-right: 0.5rem;
}
.lightbulb img {
width: 1rem;
height: 1rem;
}
a.copy-icon {
padding: 0.5rem;
text-decoration: none;
color: color(var(--foreground) alpha(0.6));
}
</style>
<div class="mdpopups">
<div class="lsp_popup">
<body>
<div class="diagnostics">
<div class="wrapper error">
<p>Cannot find module <code>mdpopups.marko</code>
Looked in these locations (from config in <code>/usr/local/workspace/sublime-packages/LSP/pyproject.toml</code>):
Search path (from config file): ["/usr/local/workspace/sublime-packages/LSP/stubs"]
Import root (inferred from project layout): "/usr/local/workspace/sublime-packages/LSP"
Site package path queried from interpreter: ["/usr/local/workspace/sublime-packages/LSP/.venv/lib/python3.8/site-packages"]</p>
<span class="color-muted">Pyrefly(<a href='https://pyrefly.org/en/docs/error-kinds/#missing-import' title='https://pyrefly.org/en/docs/error-kinds/#missing-import'>missing-import</a>)</span><a class='copy-icon' title='Copy to clipboard' href='subl:lsp_copy_text {"text":"Cannot find module `mdpopups.marko`\n Looked in these locations (from config in `/usr/local/workspace/sublime-packages/LSP/pyproject.toml`):\n Search path (from config file): \\[\"/usr/local/workspace/sublime-packages/LSP/stubs\"\\]\n Import root (inferred from project layout): \"/usr/local/workspace/sublime-packages/LSP\"\n Site package path queried from interpreter: \\[\"/usr/local/workspace/sublime-packages/LSP/.venv/lib/python3.8/site-packages\"\\] (Pyrefly)"}'>⧉</a>
<div class="wrapper--spacer"></div>
</div>
</div>
</body>
</div>
</div> |
No, actually it should be spaces before the linebreak: And now I see why the formatting looked good on my side; it turned out that these are soft wraps due to the max width of the popup matching perfectly to that content, lol. With something like But then it's still a server issue and we can't really do anything about that I guess. |
Maybe expected in new parser but asked in facelessuser/sublime-markdown-popups#158 |
|
It's likely that default style of <body id="annotation" class="lsp_annotation">
<style>
.lsp_annotation {
margin: 0;
border-width: 0;
font-family: system;
}
.error {
color: color(var(--redish) alpha(0.85));
}
.warning {
color: color(var(--yellowish) alpha(0.85));
}
.information {
color: color(var(--bluish) alpha(0.85));
}
.hint {
color: color(var(--bluish) alpha(0.85));
}
.color-muted {
color: color(var(--foreground) alpha(0.6));
}
</style>
<div class="error">
<p>Cannot find module <code>sublime</code>
Looked in these locations (from config in <code>/usr/local/workspace/sublime-packages/LSP/pyproject.toml</code>):
Import root (inferred from project layout): "/usr/local/workspace/sublime-packages/LSP"
Site package path queried from interpreter: ["/usr/local/workspace/sublime-packages/LSP/.venv/lib/python3.8/site-packages"]</p>
<span class="color-muted">Pyrefly</span>
</div>
</body> |
I had put this code in html = minihtml(view, message, FORMAT_MARKUP_CONTENT)
if html.startswith('<p>') and html.endswith('</p>'):
html = html[3:-4]I think it should apply here. Can you check what the raw output of the |
|
Interestingly mdpopups on Py3.14 uses just The simple |
I think it's just a trailing whitespace that trips it but to be honest I don't think that messing with html is a good approach. |
|
I changed that to use a CSS style instead. Now I also know why the styles for the popup didn't work for you. The reason was because mdpopups on 3.14 doesn't use the |
|
I'm open for suggestions for the |
|
For one the text in I will tweak things a bit and you can decide if we keep those. |
|
But I think it now should match the look in the hover popup (at least size wise). |
|
I didn't realize that code in popups also uses such a small font size (from mdpopups defaults), because I have an override for I pushed a commit c9b3470 that should make it look good on all OS. Also removed the CSS variables, since they were only used in one place and annotations are not rendered via mdpopups (so user overrides have no effect for annotations, and using the same variable names there would just be misleading). And I assume "sf mono" is the default monospace font on Mac, so using just |
I think it would still make sense to keep same variable names as a way to indicate that those should be kept in sync. Though mdpopups overrides not applying in annotations is indeed not ideal.
"sf mono" is not included on Mac by default. "Menlo" is the default. Technically using "monospace" should be no different from having all those fonts specified for a stock Mac setup but: |
But these should not be kept in sync because html popups and the annotations use different styling. For example the font color for diagnostics in popups is white/black and in annotations it uses red/yellow/blue font color based on the severity. The annotations only support / use basic font styling. Using same variable names for things that are different is misleading and could be confusing to users if they think they could override the CSS variables.
Consolas is even a paid font, so I assume it's rare for Mac users to install that font. The 1rem |











This is the code for the change I mentioned in #2788 (comment), with small tweaks to the styles.
From the 3.18 specs:
Linting will fail until we update the LSP types to the 3.18 specs for this. But it seems that the upstream repo https://github.com/microsoft/lsprotocol is kind of stalled (last update 9 months ago). So I'll mark this as a draft for now, and we can re-run CI when the types eventually are updated.
Diagnostics in hover popup and annotations with Breakers / Mariana / Monokai color schemes (the foreground color for code gets hardcoded into the html by mdpopups, so it's not easily possible to change that for the annotations):
Goto Diagnostic:
Diagnostics output panel: