Skip to content

Commit c6e7e28

Browse files
committed
lsp: Implement completion suggestions for .. code-block::
and `.. highlight::` and `.. source-code::`
1 parent 414aff9 commit c6e7e28

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

lib/esbonio/esbonio/server/features/sphinx_support/directives.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,42 @@
1010
from esbonio.sphinx_agent import types
1111

1212
if typing.TYPE_CHECKING:
13+
import logging
14+
from typing import Any
15+
16+
import cattrs
17+
18+
from esbonio.server import EsbonioLanguageServer
1319
from esbonio.server import Uri
1420
from esbonio.server.features.project_manager import Project
1521

1622

23+
class ValuesProvider(directives.DirectiveArgumentProvider):
24+
"""Simple completions provider that supports a static list of values."""
25+
26+
def __init__(self, converter: cattrs.Converter, logger: logging.Logger):
27+
self.converter = converter
28+
self.logger = logger
29+
30+
def suggest_arguments( # type: ignore[override]
31+
self, context: server.CompletionContext, *, values: list[str | dict[str, Any]]
32+
) -> list[lsp.CompletionItem]:
33+
"""Given a completion context, suggest directive arguments that may be used."""
34+
result: list[lsp.CompletionItem] = []
35+
36+
for value in values:
37+
if isinstance(value, str):
38+
result.append(lsp.CompletionItem(label=value))
39+
continue
40+
41+
try:
42+
result.append(self.converter.structure(value, lsp.CompletionItem))
43+
except Exception:
44+
self.logger.exception("Unable to create CompletionItem")
45+
46+
return result
47+
48+
1749
class SphinxDirectives(directives.DirectiveProvider):
1850
"""Support for directives in a sphinx project."""
1951

@@ -96,8 +128,15 @@ async def suggest_directives(
96128

97129

98130
def esbonio_setup(
131+
esbonio: EsbonioLanguageServer,
99132
project_manager: ProjectManager,
100133
directive_feature: directives.DirectiveFeature,
101134
):
102135
provider = SphinxDirectives(project_manager)
136+
137+
values_provider = ValuesProvider(
138+
esbonio.converter, esbonio.logger.getChild("ValuesProvider")
139+
)
140+
103141
directive_feature.add_directive_provider(provider)
142+
directive_feature.add_directive_argument_provider("values", values_provider)

lib/esbonio/esbonio/sphinx_agent/handlers/directives.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from docutils.parsers.rst import Directive
88
from docutils.parsers.rst import directives as docutils_directives
9+
from pygments.lexers import get_all_lexers
910

1011
from .. import types
1112
from ..app import Database
@@ -100,6 +101,8 @@ def index_directives(app: Sphinx):
100101

101102
directives[name] = types.Directive(name, get_impl_name(directive))
102103

104+
_add_providers(directives)
105+
103106
app.esbonio.db.ensure_table(DIRECTIVES_TABLE)
104107
app.esbonio.db.clear_table(DIRECTIVES_TABLE)
105108
app.esbonio.db.insert_values(
@@ -109,3 +112,36 @@ def index_directives(app: Sphinx):
109112

110113
def setup(app: Sphinx):
111114
app.connect("builder-inited", index_directives, priority=999)
115+
116+
117+
def _add_providers(directives: dict[str, types.Directive]):
118+
"""Add provider definitions to built in directive types we know about."""
119+
120+
lexers_provider = _get_lexers_provider()
121+
122+
for name in ["code-block", "sourcecode", "highlight"]:
123+
if (directive := directives.get(name)) is not None:
124+
directive.argument_providers = [lexers_provider]
125+
126+
127+
def _get_lexers_provider() -> types.Directive.ArgumentProvider:
128+
"""Get the argument provider instance that returns the names of pygments lexers."""
129+
130+
langs = []
131+
for name, labels, files, mimes in get_all_lexers():
132+
filenames = ", ".join(f"`{f}`" for f in files)
133+
mimetypes = ", ".join(f"`{m}`" for m in mimes)
134+
135+
for label in labels:
136+
langs.append(
137+
{
138+
"label": label,
139+
"kind": 21, # Constant
140+
"documentation": {
141+
"kind": "markdown",
142+
"value": f"### {name}\nFilenames: {filenames}\n\nMIME Types: {mimetypes}",
143+
},
144+
}
145+
)
146+
147+
return types.Directive.ArgumentProvider("values", {"values": langs})

0 commit comments

Comments
 (0)