Skip to content

Commit

Permalink
lsp: Typing fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
alcarney committed Jan 14, 2023
1 parent 532e056 commit 74f100e
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 34 deletions.
10 changes: 5 additions & 5 deletions docs/lsp/extending/directives/directive-registry.rst
Expand Up @@ -44,7 +44,7 @@ This method should return a dictionary where the keys are the canonical name of
def __init__(self, app: Sphinx):
self.app = app # Sphinx application instance.

def index_directives(self) -> Dict[str, Directive]:
def index_directives(self) -> Dict[str, Type[Directive]]:
directives = {}
for prefix, domain in self.app.domains.items():
for name, directive in domain.directives.items():
Expand Down Expand Up @@ -74,12 +74,12 @@ The :meth:`~DirectiveLanguageFeature.suggest_directives` method is called each t
It can be used to tailor the list of directives that are offered to the user, depending on the current context.
Each ``DirectiveLanguageFeature`` has a default implementation, which may be sufficient depending on your use case::

def suggest_directives(self, context: CompletionContext) -> Iterable[Tuple[str, Directive]]:
def suggest_directives(self, context: CompletionContext) -> Iterable[Tuple[str, Type[Directive]]]:
return self.index_directives().items()

However, in the case of Sphinx domains, we need to modify this to also include the short form of the directives in the standard and primary domains::

def suggest_directives(self, context: CompletionContext) -> Iterable[Tuple[str, Directive]]:
def suggest_directives(self, context: CompletionContext) -> Iterable[Tuple[str, Type[Directive]]]:
directives = self.index_directives()
primary_domain = self.app.config.primary_domain

Expand All @@ -103,12 +103,12 @@ The :meth:`~DirectiveLanguageFeature.get_implementation` method is used by the l
This powers features such as documentation hovers and goto implementation.
As with ``suggest_directives``, each ``DirectiveLanguageFeature`` has a default implementation which may be sufficient for your use case::

def get_implementation(self, directive: str, domain: Optional[str]) -> Optional[Directive]:
def get_implementation(self, directive: str, domain: Optional[str]) -> Optional[Type[Directive]]:
return self.index_directives().get(directive, None)

In the case of Sphinx domains, if we see a directive without a domain prefix we need to see if it belongs to the standard or primary domains::

def get_implementation(self, directive: str, domain: Optional[str]) -> Optional[Directive]:
def get_implementation(self, directive: str, domain: Optional[str]) -> Optional[Type[Directive]]:
directives = self.index_directives()

if domain is not None:
Expand Down
4 changes: 2 additions & 2 deletions lib/esbonio/esbonio/lsp/__init__.py
Expand Up @@ -253,7 +253,7 @@ def on_completion(ls: RstLanguageServer, params: CompletionParams):
ls.logger.debug("Completion context: %s", context)

for item in feature.complete(context):
item.data = {"source_feature": name, **(item.data or {})}
item.data = {"source_feature": name, **(item.data or {})} # type: ignore
items.append(item)

return CompletionList(is_incomplete=False, items=items)
Expand All @@ -264,7 +264,7 @@ def on_completion(ls: RstLanguageServer, params: CompletionParams):
def on_completion_resolve(
ls: RstLanguageServer, item: CompletionItem
) -> CompletionItem:
source = (item.data or {}).get("source_feature", "")
source = (item.data or {}).get("source_feature", "") # type: ignore
feature = ls.get_feature(source)

if not feature:
Expand Down
19 changes: 10 additions & 9 deletions lib/esbonio/esbonio/lsp/directives.py
Expand Up @@ -8,6 +8,7 @@
from typing import List
from typing import Optional
from typing import Tuple
from typing import Type

from docutils.parsers.rst import Directive
from lsprotocol.types import CompletionItem
Expand Down Expand Up @@ -57,17 +58,17 @@ def complete_arguments(

def get_implementation(
self, directive: str, domain: Optional[str]
) -> Optional[Directive]:
) -> Optional[Type[Directive]]:
"""Return the implementation for the given directive name."""
return self.index_directives().get(directive, None)

def index_directives(self) -> Dict[str, Directive]:
def index_directives(self) -> Dict[str, Type[Directive]]:
"""Return all known directives."""
return dict()

def suggest_directives(
self, context: CompletionContext
) -> Iterable[Tuple[str, Directive]]:
) -> Iterable[Tuple[str, Type[Directive]]]:
"""Suggest directives that may be used, given a completion context."""
return self.index_directives().items()

Expand All @@ -80,7 +81,7 @@ def suggest_options(
if impl is None:
return []

option_spec = impl.option_spec or {}
option_spec = getattr(impl, "option_spec", {})
return option_spec.keys()

def resolve_argument_link(
Expand Down Expand Up @@ -427,7 +428,7 @@ class name of the directive's implementation.
doc["description"] = "\n".join(description)
self._documentation[key] = doc

def get_directives(self) -> Dict[str, Directive]:
def get_directives(self) -> Dict[str, Type[Directive]]:
"""Return a dictionary of all known directives."""

directives = {}
Expand All @@ -446,7 +447,7 @@ def get_directives(self) -> Dict[str, Directive]:

def get_implementation(
self, directive: str, domain: Optional[str]
) -> Optional[Directive]:
) -> Optional[Type[Directive]]:
"""Return the implementation of a directive given its name
Parameters
Expand Down Expand Up @@ -483,7 +484,7 @@ def get_implementation(

def suggest_directives(
self, context: CompletionContext
) -> Iterable[Tuple[str, Directive]]:
) -> Iterable[Tuple[str, Type[Directive]]]:
"""Suggest directives that may be used, given a completion context.
Parameters
Expand Down Expand Up @@ -604,9 +605,9 @@ def complete_directives(self, context: CompletionContext) -> List[CompletionItem
# TODO: Give better names to arguments based on what they represent.
if include_argument:
insert_format = InsertTextFormat.Snippet
nargs = getattr(directive, "required_arguments", 0)
args = " " + " ".join(
"${{{0}:arg{0}}}".format(i)
for i in range(1, directive.required_arguments + 1)
"${{{0}:arg{0}}}".format(i) for i in range(1, nargs + 1)
)
else:
args = ""
Expand Down
11 changes: 7 additions & 4 deletions lib/esbonio/esbonio/lsp/rst/directives.py
Expand Up @@ -3,6 +3,7 @@
from typing import Dict
from typing import Optional
from typing import Tuple
from typing import Type
from typing import Union

import pkg_resources
Expand All @@ -18,11 +19,11 @@ class Docutils(DirectiveLanguageFeature):

def __init__(self) -> None:

self._directives: Optional[Dict[str, Directive]] = None
self._directives: Optional[Dict[str, Type[Directive]]] = None
"""Cache for known directives."""

@property
def directives(self) -> Dict[str, Directive]:
def directives(self) -> Dict[str, Type[Directive]]:
if self._directives is not None:
return self._directives

Expand All @@ -46,11 +47,13 @@ def get_implementation(self, directive: str, domain: Optional[str]):

return self.directives.get(directive, None)

def index_directives(self) -> Dict[str, Directive]:
def index_directives(self) -> Dict[str, Type[Directive]]:
return self.directives


def resolve_directive(directive: Union[Directive, Tuple[str, str]]) -> Directive:
def resolve_directive(
directive: Union[Type[Directive], Tuple[str, str]]
) -> Type[Directive]:
"""Return the directive based on the given reference.
'Core' docutils directives are returned as tuples ``(modulename, ClassName)``
Expand Down
16 changes: 10 additions & 6 deletions lib/esbonio/esbonio/lsp/spelling.py
Expand Up @@ -9,13 +9,13 @@
from lsprotocol.types import CodeAction
from lsprotocol.types import CodeActionKind
from lsprotocol.types import CodeActionParams
from lsprotocol.types import Diagnostic
from lsprotocol.types import DiagnosticSeverity
from lsprotocol.types import DidSaveTextDocumentParams
from lsprotocol.types import Position
from lsprotocol.types import Range
from lsprotocol.types import TextEdit
from lsprotocol.types import WorkspaceEdit
from lsprotocol.types.basic_structures import Diagnostic
from lsprotocol.types.basic_structures import DiagnosticSeverity
from lsprotocol.types.basic_structures import Position
from lsprotocol.types.basic_structures import Range
from lsprotocol.types.workspace import DidSaveTextDocumentParams
from spellchecker import SpellChecker # type: ignore

from esbonio.lsp.rst import LanguageFeature
Expand Down Expand Up @@ -48,7 +48,11 @@ def code_action(self, params: CodeActionParams) -> List[CodeAction]:
if len(ranges) > 0 and diagnostic.range not in ranges:
continue

for fix in self.lang.candidates(error.text):
fixes = self.lang.candidates(error.text)
if fixes is None:
continue

for fix in fixes:
actions.append(
CodeAction(
title=f"Correct '{error.text}' -> '{fix}'",
Expand Down
7 changes: 5 additions & 2 deletions lib/esbonio/esbonio/lsp/sphinx/cli.py
Expand Up @@ -4,6 +4,7 @@
import sys
from typing import List

from esbonio.cli import esbonio_converter
from esbonio.lsp.sphinx import SphinxConfig


Expand All @@ -17,7 +18,8 @@ def config_cmd(args, extra):


def config_to_cli(config: str):
conf = SphinxConfig(**json.loads(config))
converter = esbonio_converter()
conf = converter.structure(json.loads(config), SphinxConfig)
print(" ".join(conf.to_cli_args()))
return 0

Expand All @@ -27,7 +29,8 @@ def cli_to_config(cli_args: List[str]):
if conf is None:
return 1

print(json.dumps(conf.dict(by_alias=True), indent=2))
converter = esbonio_converter()
print(json.dumps(converter.unstructure(conf), indent=2))
return 0


Expand Down
14 changes: 8 additions & 6 deletions lib/esbonio/esbonio/lsp/sphinx/domains.py
Expand Up @@ -7,6 +7,7 @@
from typing import Optional
from typing import Set
from typing import Tuple
from typing import Type

import pygls.uris as Uri
from docutils import nodes
Expand Down Expand Up @@ -70,11 +71,11 @@ class DomainDirectives(DirectiveLanguageFeature, DomainHelpers):
def __init__(self, rst: SphinxLanguageServer):
self.rst = rst

self._directives: Optional[Dict[str, Directive]] = None
self._directives: Optional[Dict[str, Type[Directive]]] = None
"""Cache for known directives."""

@property
def directives(self) -> Dict[str, Directive]:
def directives(self) -> Dict[str, Type[Directive]]:

if self._directives is not None:
return self._directives
Expand All @@ -89,7 +90,7 @@ def directives(self) -> Dict[str, Directive]:

def get_implementation(
self, directive: str, domain: Optional[str]
) -> Optional[Directive]:
) -> Optional[Type[Directive]]:

if domain is not None:
return self.directives.get(f"{domain}:{directive}", None)
Expand All @@ -106,12 +107,12 @@ def get_implementation(
# Try the std domain
return self.directives.get(f"std:{directive}", None)

def index_directives(self) -> Dict[str, Directive]:
def index_directives(self) -> Dict[str, Type[Directive]]:
return self.directives

def suggest_directives(
self, context: CompletionContext
) -> Iterable[Tuple[str, Directive]]:
) -> Iterable[Tuple[str, Type[Directive]]]:

# In addition to providing each directive fully qualified, we should provide a
# suggestion for directives in the std and primary domains without the prefix.
Expand All @@ -137,7 +138,8 @@ def suggest_options(
if impl is None:
return []

return impl.option_spec.keys()
option_spec = getattr(impl, "option_spec", {})
return option_spec.keys()


class DomainRoles(RoleLanguageFeature, DomainHelpers):
Expand Down

0 comments on commit 74f100e

Please sign in to comment.