A rough sketch of how the language server(s) in Esbonio are architected.
-
diff --git a/docs/lsp/advanced-usage.rst b/docs/lsp/advanced-usage.rst
deleted file mode 100644
index 378b7dbb1..000000000
--- a/docs/lsp/advanced-usage.rst
+++ /dev/null
@@ -1,161 +0,0 @@
-.. _lsp-advanced:
-
-Advanced Usage
-==============
-
-The :doc:`/lsp/getting-started` guide should contain all you need to get up and running with your
-editor of choice. However there may come a time when you will want to enable/disable certain
-functionality or use a different server entirely.
-
-**Wait.. there are different servers?**
-
-Yes there are!
-
-Due to the extensible nature of Sphinx and reStructuredText, the ``esbonio`` python package
-is actually a framework for building reStructuredText language servers. It just so happens
-that it also comes with a default implementation that works well for Sphinx projects (see
-the section on :doc:`/lsp/extending` if you want to know more)
-
-However, all that we need to know for the moment is the concept of startup modules.
-
-.. _lsp-startup-mods:
-
-Startup Modules
----------------
-
-A startup module is any python module (or script) that results in a running language server.
-The following startup modules are included with the ``esbonio`` python package.
-
-.. startmod:: esbonio
-
- The default startup module you are probably already familiar with.
- It is in fact just an alias for the :startmod:`esbonio.lsp.sphinx` startup module.
-
- .. .. cli-help:: esbonio.__main__
-
-.. startmod:: esbonio.lsp.rst
-
- A "vanilla" reStructuedText language server for use with docutils projects.
-
- .. .. cli-help:: esbonio.lsp.rst
-
-.. startmod:: esbonio.lsp.sphinx
-
- A language server tailored for use with Sphinx projects.
-
- .. .. cli-help:: esbonio.lsp.sphinx
-
-.. _lsp-extension-modules:
-
-Extension Modules
------------------
-
-Inspired by the way Sphinx extensions work, functionality is added to a language server through a list of python modules with each module contributing some features.
-
-Below is the list of modules loaded by default for each of the provided servers.
-
-.. relevant-to:: Startup Module
-
- esbonio
- .. literalinclude:: ../../lib/esbonio/esbonio/lsp/sphinx/__init__.py
- :language: python
- :start-at: DEFAULT_MODULES
- :end-at: ]
-
- esbonio.lsp.rst
- .. literalinclude:: ../../lib/esbonio/esbonio/lsp/rst/__init__.py
- :language: python
- :start-at: DEFAULT_MODULES
- :end-at: ]
-
- esbonio.lsp.sphinx
- .. literalinclude:: ../../lib/esbonio/esbonio/lsp/sphinx/__init__.py
- :language: python
- :start-at: DEFAULT_MODULES
- :end-at: ]
-
-In addition to the modules enabled by default, the following modules are provided and can be
-enabled if you wish.
-
-.. extmod:: esbonio.lsp.spelling
-
- **Experimental**
-
- Basic spell checking, with errors reported as diagnostics and corrections suggested as code actions.
- Currently only available for English and can be confused by reStructuredText syntax.
-
-Commands
---------
-
-The bundled language servers offer some commands that can be invoked from a language client using
-a :lsp:`workspace/executeCommand` request.
-
-
-.. command:: esbonio.server.build
-
- .. relevant-to:: Startup Module
-
- esbonio
- .. include:: ./advanced/_esbonio.lsp.sphinx_build_command.rst
-
- esbonio.lsp.rst
- Currently a placeholder.
-
- esbonio.lsp.sphinx
- .. include:: ./advanced/_esbonio.lsp.sphinx_build_command.rst
-
-.. command:: esbonio.server.configuration
-
- .. relevant-to:: Startup Module
-
- esbonio
- .. include:: ./advanced/_esbonio.lsp.sphinx_configuration_command.rst
-
- esbonio.lsp.rst
- Returns the server's current configuration.
-
- .. code-block:: json
-
- {
- "server": {
- "logLevel": "debug",
- "logFilter": [],
- "hideSphinxOutput": false
- }
- }
-
-
- esbonio.lsp.sphinx
- .. include:: ./advanced/_esbonio.lsp.sphinx_configuration_command.rst
-
-.. command:: esbonio.server.preview
-
- .. relevant-to:: Startup Module
-
- esbonio
- .. include:: ./advanced/_esbonio.lsp.sphinx_preview_command.rst
-
- esbonio.lsp.rst
- Currently a placeholder.
-
- esbonio.lsp.sphinx
- .. include:: ./advanced/_esbonio.lsp.sphinx_preview_command.rst
-
-
-
-Notifications
--------------
-
-The bundled language servers also emit custom notifications that language clients
-can use to react to events happening within the server.
-
-.. relevant-to:: Startup Module
-
- esbonio
- .. include:: ./advanced/_esbonio.lsp.sphinx_notifications.rst
-
- esbonio.lsp.rst
- Currently this server implements no custom notifications.
-
- esbonio.lsp.sphinx
- .. include:: ./advanced/_esbonio.lsp.sphinx_notifications.rst
diff --git a/docs/lsp/advanced/_esbonio.lsp.sphinx_build_command.rst b/docs/lsp/advanced/_esbonio.lsp.sphinx_build_command.rst
deleted file mode 100644
index cf2237b3c..000000000
--- a/docs/lsp/advanced/_esbonio.lsp.sphinx_build_command.rst
+++ /dev/null
@@ -1 +0,0 @@
-Trigger a Sphinx build.
diff --git a/docs/lsp/advanced/_esbonio.lsp.sphinx_configuration_command.rst b/docs/lsp/advanced/_esbonio.lsp.sphinx_configuration_command.rst
deleted file mode 100644
index 26c7d615c..000000000
--- a/docs/lsp/advanced/_esbonio.lsp.sphinx_configuration_command.rst
+++ /dev/null
@@ -1,36 +0,0 @@
-Returns the server's current configuration.
-
-.. code-block:: json
-
- {
- "config": {
- "sphinx": {
- "buildDir": "/home/.../docs/_build/html",
- "builderName": "html",
- "confDir": "/home/.../docs",
- "configOverrides": {},
- "doctreeDir": "/home/.../docs/_build/doctrees",
- "forceFullBuild": false,
- "keepGoing": false,
- "makeMode": true,
- "numJobs": 1,
- "quiet": false,
- "silent": false,
- "srcDir": "/home/.../docs",
- "tags": [],
- "verbosity": 0,
- "warningIsError": false,
- "command": [
- "sphinx-build", "-M", "html", "./docs", "./docs/_build",
- ],
- "version": "4.4.0"
- },
- "server": {
- "logLevel": "debug",
- "logFilter": [],
- "hideSphinxOutput": false
- }
- },
- "error": false,
- "warnings": 1
- }
diff --git a/docs/lsp/advanced/_esbonio.lsp.sphinx_notifications.rst b/docs/lsp/advanced/_esbonio.lsp.sphinx_notifications.rst
deleted file mode 100644
index 306aeb301..000000000
--- a/docs/lsp/advanced/_esbonio.lsp.sphinx_notifications.rst
+++ /dev/null
@@ -1,31 +0,0 @@
-
-``esbonio/buildStart``
- Emitted whenever a Sphinx build is started.
-
- .. code-block:: json
-
- {}
-
-``esbonio/buildComplete``
- Emitted whenever a Sphinx build is complete.
-
- .. code-block:: json
-
- {
- "config": {
- "sphinx": {
- "version": "4.4.0",
- "confDir": "/home/.../docs",
- "srcDir": "/home/.../docs",
- "buildDir": "/home/.../docs/_build/html",
- "builderName": "html"
- },
- "server": {
- "log_level": "debug",
- "log_filter": [],
- "hide_sphinx_output": false
- }
- },
- "error": false,
- "warnings": 0
- }
diff --git a/docs/lsp/advanced/_esbonio.lsp.sphinx_preview_command.rst b/docs/lsp/advanced/_esbonio.lsp.sphinx_preview_command.rst
deleted file mode 100644
index b3caf34aa..000000000
--- a/docs/lsp/advanced/_esbonio.lsp.sphinx_preview_command.rst
+++ /dev/null
@@ -1,23 +0,0 @@
-Start a local preview webserver.
-
-The server will spin up a local :mod:`python:http.server` on a random port in the
-project's configured :confval:`buildDir ` which can be used to
-preview the result of building the project. The server will return an object like the
-following.
-
-.. code-block:: json
-
- { "port": 12345 }
-
-This command also accepts a parameters object with the following structure
-
-.. code-block:: json
-
- { "show": true }
-
-By default the ``show`` parameter will default to ``true`` which means the server will
-also send a :lsp:`window/showDocument` request, asking the client to open the preview in a
-web browser.
-
-If a client wants to implement its own preview mechanism (like the `VSCode Extension `_)
-it can set ``show`` to ``false`` to suppress this behavior.
diff --git a/docs/lsp/editors/nvim-lspconfig/init.vim b/docs/lsp/editors/nvim-lspconfig/init.vim
index ff99a205d..19ab5713e 100644
--- a/docs/lsp/editors/nvim-lspconfig/init.vim
+++ b/docs/lsp/editors/nvim-lspconfig/init.vim
@@ -85,8 +85,11 @@ lspconfig.esbonio.setup {
-- VSCode style output window.
cmd = { 'lsp-devtools', 'agent', '--port', LSP_DEVTOOLS_PORT, '--', 'esbonio' },
init_options = {
- server = {
- logLevel = 'debug',
+ logging = {
+ level = 'debug',
+ -- Redirect logging output to window/logMessage notifications so that lsp-devtools can capture it.
+ stderr = false,
+ window = true,
}
},
settings = {
diff --git a/docs/lsp/extending.rst b/docs/lsp/extending.rst
index 7ddf6a7a1..362a8d438 100644
--- a/docs/lsp/extending.rst
+++ b/docs/lsp/extending.rst
@@ -3,68 +3,4 @@
Extending
=========
-In order to support the extensible nature of reStructuredText and Sphinx, Esbonio itself is structured so that it can be easily extended.
-This section of the documentation outlines the server's architecture and how you can write your own extensions.
-
-.. toctree::
- :maxdepth: 1
-
- extending/directives
- extending/roles
- extending/api-reference
-
-.. _lsp_architecture:
-
-Architecture
-------------
-
-.. include:: ./_architecture.rst
-
-.. glossary::
-
- Language Server
- A language server is a subclass of the ``LanguageServer`` class provided by the `pygls`_ library.
-
- In Esbonio, all the features you would typically associate with a language server, e.g. completions are not actually implemented by the language server.
- These features are provided through a number of "language features" (see below).
- Instead a language server acts a container for all the active language features and provides an API they can use to query aspects of the environment.
-
- Esbonio currently provides two language servers
-
- - :class:`~esbonio.lsp.rst.RstLanguageServer`: Base language server, meant for "vanilla" docutils projects.
- - :class:`~esbonio.lsp.sphinx.SphinxLanguageServer` Language server, specialising in Sphinx projects.
-
- Language Feature
- Language features are subclasses of :class:`~esbonio.lsp.rst.LanguageFeature`.
- They are typically based on a single aspect of reStructuredText (e.g. :class:`~esbonio.lsp.roles.Roles`).
-
- Language Features (where it makes sense) should be server agnostic, that way the same features can be reused across different envrionments.
-
- Engine
- For lack of a better name... an "engine" is responsible for mapping messages from the LSP Protocol into function calls within the language server.
- Unlike the other components of the architecture, an "engine" isn't formally defined and there is no API to implement.
- Instead it's just the term used to refer to all the ``@server.feature()`` handlers that define how LSP messages should be handled.
-
- Currently we provide just a single "engine" :func:`~esbonio.lsp.create_language_server`.
- As an example, here is how it handles ``textDocument/completion`` requests.
-
- .. literalinclude:: ../../lib/esbonio/esbonio/lsp/__init__.py
- :language: python
- :dedent:
- :start-after: #
- :end-before: #
-
- There is nothing in Esbonio that would prevent you from writing your own if you so desired.
-
- Extension Module
- Ordinary Python modules are used to group related functionality together.
- Taking inspiration from how Sphinx is architected, language servers are assembled by passing the list of modules to load to the :func:`~esbonio.lsp.create_language_server`.
- This assembly process calls any functions with the name ``esbonio_setup`` allowing for ``LanguageFeatures`` to be configured and loaded into the server.
-
- Startup Module
- As mentioned above, language servers are assembled and this is done inside a startup module.
- A startup module in Esbonio is any Python script or module runnable by a ``python -m `` command that results in a running language server.
- A good use case for a custom entry point would be starting up a language server instance pre configured with all the extensions required by your project.
-
-
-.. _pygls: https://pygls.readthedocs.io/en/latest/index.html
+Coming soon\ :sup:`TM`
diff --git a/docs/lsp/extending/api-reference.rst b/docs/lsp/extending/api-reference.rst
deleted file mode 100644
index 25314b70a..000000000
--- a/docs/lsp/extending/api-reference.rst
+++ /dev/null
@@ -1,71 +0,0 @@
-API Reference
-=============
-
-.. warning::
-
- While we will try not to break the API outlined below, until the language server
- reaches ``v1.0`` we do not offer any stability guarantees.
-
-Language Servers
-----------------
-
-.. autofunction:: esbonio.lsp.create_language_server
-
-RstLanguageServer
-^^^^^^^^^^^^^^^^^
-
-.. autoclass:: esbonio.lsp.rst.RstLanguageServer
- :members:
- :show-inheritance:
-
-.. autoclass:: esbonio.lsp.rst.InitializationOptions
- :members:
-
-.. autoclass:: esbonio.lsp.rst.config.ServerConfig
- :members:
-
-.. autoclass:: esbonio.lsp.rst.config.ServerCompletionConfig
- :members:
-
-
-SphinxLanguageServer
-^^^^^^^^^^^^^^^^^^^^
-
-.. currentmodule:: esbonio.lsp.sphinx
-
-.. autoclass:: SphinxLanguageServer
- :members:
- :show-inheritance:
-
-.. autoclass:: InitializationOptions
- :members:
-
-.. autoclass:: SphinxServerConfig
- :members:
-
-.. autoclass:: SphinxConfig
- :members:
-
-.. autoclass:: MissingConfigError
-
-Language Features
------------------
-
-.. autoclass:: esbonio.lsp.LanguageFeature
- :members:
-
-.. autoclass:: esbonio.lsp.CompletionContext
- :members:
-
-.. autoclass:: esbonio.lsp.DefinitionContext
- :members:
-
-.. autoclass:: esbonio.lsp.DocumentLinkContext
- :members:
-
-
-Testing
--------
-
-.. automodule:: esbonio.lsp.testing
- :members:
diff --git a/docs/lsp/extending/directives.rst b/docs/lsp/extending/directives.rst
deleted file mode 100644
index 253e164cc..000000000
--- a/docs/lsp/extending/directives.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-Directives
-==========
-
-How To Guides
--------------
-
-The following guides outline how to extend the language server to add support for your custom directives.
-
-.. toctree::
- :glob:
- :maxdepth: 1
-
- directives/*
-
-API Reference
--------------
-
-.. currentmodule:: esbonio.lsp.directives
-
-.. autoclass:: Directives
- :members: add_argument_completion_provider,
- add_argument_definition_provider,
- add_argument_link_provider,
- add_documentation,
- add_feature,
- get_directives,
- get_documentation,
- get_implementation,
- suggest_directives,
- suggest_options
-
-.. autoclass:: DirectiveLanguageFeature
- :members:
-
-.. autodata:: esbonio.lsp.util.patterns.DIRECTIVE
- :no-value:
-
-.. autodata:: esbonio.lsp.util.patterns.DIRECTIVE_OPTION
- :no-value:
-
-.. autoclass:: ArgumentCompletion
- :members:
-
-.. autoclass:: ArgumentDefinition
- :members:
-
-.. autoclass:: ArgumentLink
- :members:
diff --git a/docs/lsp/extending/directives/directive-registry.rst b/docs/lsp/extending/directives/directive-registry.rst
deleted file mode 100644
index d74a490db..000000000
--- a/docs/lsp/extending/directives/directive-registry.rst
+++ /dev/null
@@ -1,122 +0,0 @@
-Supporting Custom Directive Registries
-======================================
-
-.. currentmodule:: esbonio.lsp.directives
-
-This guide walks through the process of teaching the language server how to discover directives stored in a custom registry.
-Once complete, the following LSP features should start working with your directives.
-
-- Basic directive completions i.e. ``.. directive-name::`` but no argument completions.
-- Basic option key completions i.e. ``:option-name:`` assuming options are declared in a directive's ``option_spec``, but no option value completions.
-- Documentation hovers assuming you've provided documentation.
-- Goto Implementation.
-
-.. note::
-
- You may not need this guide.
-
- If you're registering your directive directly with
- `docutils `__ or
- `sphinx `__,
- or using a `custom domain `__
- then you should find that the language server already has basic support for your custom directives out of the box.
-
- This guide is indended for adding support for directives that are not registered in a standard location.
-
-Still here? Great! Let's get started.
-
-Indexing Directives
--------------------
-
-As an example, we'll walk through the steps required to add (basic) support for Sphinx domains to the language server.
-
-.. note::
-
- For the sake of brevity, some details have been omitted from the code examples below.
-
- If you're interested, you can find the actual implementation of the ``DomainDirectives`` class
- `here `__.
-
-So that the server can discover the available directives, we have to provide a :class:`DirectiveLanguageFeature` that implements the :meth:`~DirectiveLanguageFeature.index_directives` method.
-This method should return a dictionary where the keys are the canonical name of a directive which map to the class that implements it::
-
- class DomainDirectives(DirectiveLanguageFeature):
- def __init__(self, app: Sphinx):
- self.app = app # Sphinx application instance.
-
- def index_directives(self) -> Dict[str, Type[Directive]]:
- directives = {}
- for prefix, domain in self.app.domains.items():
- for name, directive in domain.directives.items():
- directives[f"{prefix}:{name}"] = directive
-
- return directives
-
-In the case of Sphinx domains a directive's canonical name is of the form ``:`` e.g. ``py:function`` or ``c:macro``.
-
-This is the bare minimum required to make the language server aware of your custom directives, in fact if you were to try the above implementation you would already find completions being offered for domain based directives.
-However, you would also notice that the short form of directives (e.g. ``function``) in the :ref:`standard ` and :confval:`primary ` domains are not included in the list of completions - despite being valid.
-
-To remedy this, you might be tempted to start adding multiple entries to the dictionary, one for each valid name **do not do this.**
-Instead you can implement the :meth:`~DirectiveLanguageFeature.suggest_directives` method which solves this exact use case.
-
-.. tip::
-
- If you want to play around with your own version of the ``DomainDirectives`` class you can disable the built in version by:
-
- - Passing the ``--exclude esbonio.lsp.sphinx.domains`` cli option, or
- - If you're using VSCode adding ``esbonio.lsp.sphinx.domains`` to the :confval:`esbonio.server.excludedModules (string[])` option.
-
-(Optional) Suggesting Directives
---------------------------------
-
-The :meth:`~DirectiveLanguageFeature.suggest_directives` method is called each time the server is generating directive completions.
-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, 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, Type[Directive]]]:
- directives = self.index_directives()
- primary_domain = self.app.config.primary_domain
-
- for key, directive in directives.items():
-
- if key.startswith("std:"):
- directives[key.replace("std:", "")] = directive
-
- if primary_domain and key.startswith(f"{primary_domain}:"):
- directives[key.replace(f"{primary_domain}:", "")] = directive
-
- return directives.items()
-
-Now if you were to try this version, the short forms of the relevant directives would be offered as completion suggestions, but you would also notice that features like documentation hovers still don't work.
-This is due to the language server not knowing which class implements these short form directives.
-
-(Optional) Implementation Lookups
----------------------------------
-
-The :meth:`~DirectiveLanguageFeature.get_implementation` method is used by the language server to take a directive's name and lookup its implementation.
-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[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[Type[Directive]]:
- directives = self.index_directives()
-
- if domain is not None:
- return directives.get(f"{domain}:{directive}", None)
-
- primary_domain = self.app.config.primary_domain
- impl = directives.get(f"{primary_domain}:{directive}", None)
- if impl is not None:
- return impl
-
- return directives.get(f"std:{directive}", None)
diff --git a/docs/lsp/extending/roles.rst b/docs/lsp/extending/roles.rst
deleted file mode 100644
index 9253104ac..000000000
--- a/docs/lsp/extending/roles.rst
+++ /dev/null
@@ -1,49 +0,0 @@
-Roles
-=====
-
-How To Guides
--------------
-
-The following guides outlne how to extens the language server to add support for your custom roles.
-
-.. toctree::
- :glob:
- :maxdepth: 1
-
- roles/*
-
-API Reference
--------------
-
-.. currentmodule:: esbonio.lsp.roles
-
-.. autoclass:: Roles
- :members: add_documentation,
- add_feature,
- add_target_completion_provider,
- add_target_definition_provider,
- add_target_link_provider,
- get_documentation,
- get_implementation,
- get_roles,
- resolve_target_link,
- suggest_roles,
- suggest_targets
-
-.. autoclass:: RoleLanguageFeature
- :members:
-
-.. autodata:: esbonio.lsp.util.patterns.ROLE
- :no-value:
-
-.. autodata:: esbonio.lsp.util.patterns.DEFAULT_ROLE
- :no-value:
-
-.. autoclass:: TargetDefinition
- :members:
-
-.. autoclass:: TargetCompletion
- :members:
-
-.. autoclass:: TargetLink
- :members:
diff --git a/docs/lsp/extending/roles/role-registry.rst b/docs/lsp/extending/roles/role-registry.rst
deleted file mode 100644
index 12ae2e658..000000000
--- a/docs/lsp/extending/roles/role-registry.rst
+++ /dev/null
@@ -1,123 +0,0 @@
-Supporting Custom Role Registries
-=================================
-
-.. currentmodule:: esbonio.lsp.roles
-
-This guide walks through the process of teaching the language server how to discover roles stored in a custom registry.
-Once complete, the following LSP features should start working with your roles.
-
-- Basic role completions i.e. ``:role-name:`` but no target completions.
-- Documentation hovers (assuming you've provided documentation)
-- Goto Implementation
-
-.. note::
-
- You may not need this guide.
-
- If you're registering your role directly with
- `docutils `__ or
- `sphinx `__,
- or using a `custom domain `__
- then you should find that the language server already has basic support for your custom roles out of the box.
-
- This guide is indended for adding support for roles that are not registered in a standard location.
-
-Still here? Great! Let's get started.
-
-Indexing Roles
---------------
-
-As an example, we'll walk through the steps required to add (basic) support for Sphinx domains to the language server.
-
-.. note::
-
- For the sake of brevity, some details have been omitted from the code examples below.
-
- If you're interested, you can find the actual implementation of the ``DomainRoles`` class
- `here `__.
-
-So that the server can discover the available roles, we have to provide a :class:`RoleLanguageFeature` that implements the :meth:`~RoleLanguageFeature.index_roles` method.
-This method should return a dictionary where the keys are the canonical name of the role which map to the function that implements it::
-
- class DomainRoles(RoleLanguageFeature):
- def __init__(self, app: Sphinx):
- self.app = app # Sphinx application instance.
-
- def index_roles(self) -> Dict[str, Any]:
- roles = {}
- for prefix, domain in self.app.domains.items():
- for name, role in domain.roles.items():
- roles[f"{prefix}:{name}"] = role
-
- return roles
-
-In the case of Sphinx domains a role's canonical name is of the form ``:`` e.g. ``py:func`` or ``c:macro``.
-
-This is the bare minimum required to make the language server aware of your custom roles, in fact if you were to try the above implementation you would already find completions being offered for domain based roles.
-However, you would also notice that the short form of roles (e.g. ``func``) in the :ref:`standard ` and :confval:`primary ` domains are not included in the list of completions - despite being valid.
-
-To remedy this, you might be tempted to start adding multiple entries to the dictionary, one for each valid name **do not do this.**
-Instead you can implement the :meth:`~RoleLanguageFeature.suggest_roles` method which solves this exact use case.
-
-.. tip::
-
- If you want to play around with your own version of the ``DomainRoles`` class you can disable the built in version by:
-
- - Passing the ``--exclude esbonio.lsp.sphinx.domains`` cli option, or
- - If you're using VSCode adding ``esbonio.lsp.sphinx.domains`` to the :confval:`esbonio.server.excludedModules (string[])` option.
-
-(Optional) Suggesting Roles
----------------------------
-
-The :meth:`~RoleLanguageFeature.suggest_roles` method is called each time the server is generating role completions.
-It can be used to tailor the list of roles that are offered to the user, depending on the current context.
-Each ``RoleLanguageFeature`` has a default implementation, which may be sufficient depending on your use case::
-
- def suggest_roles(self, context: CompletionContext) -> Iterable[Tuple[str, Any]]:
- """Suggest roles that may be used, given a completion context."""
- return self.index_roles().items()
-
-However, in the case of Sphinx domains, we need to modify this to also include the short form of the roles in the standard and primary domains::
-
- def suggest_roles(self, context: CompletionContext) -> Iterable[Tuple[str, Any]]:
- roles = self.index_roles()
- primary_domain = self.app.config.primary_domain
-
- for key, role in roles.items():
-
- if key.startswith("std:"):
- roles[key.replace("std:", "")] = role
-
- if primary_domain and key.startswith(f"{primary_domain}:"):
- roles[key.replace(f"{primary_domain}:", "")] = role
-
- return roles.items()
-
-Now if you were to try this version, the short forms of the relevant directives would be offered as completion suggestions, but you would also notice that features like documentation hovers still don't work.
-This is due to the language server not knowing which class implements these short form directives.
-
-(Optional) Implementation Lookups
----------------------------------
-
-The :meth:`~RoleLanguageFeature.get_implementation` method is used by the language server to take a role's name and lookup its implementation.
-This powers features such as documentation hovers and goto implementation.
-As with ``suggest_roles``, each ``RoleLanguageFeature`` has a default implementation which may be sufficient for your use case::
-
- def get_implementation(self, role: str, domain: Optional[str]) -> Optional[Any]:
- """Return the implementation for the given role name."""
- return self.index_roles().get(role, 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, role: str, domain: Optional[str]) -> Optional[Any]:
- roles = self.index_roles()
-
- if domain is not None:
- return roles.get(f"{domain}:{role}", None)
-
- primary_domain = self.app.config.primary_domain
- impl = roles.get(f"{primary_domain}:{role}", None)
- if impl is not None:
- return impl
-
- return roles.get(f"std:{role}", None)
diff --git a/docs/lsp/getting-started.rst b/docs/lsp/getting-started.rst
index f9aad42a5..86665dbfc 100644
--- a/docs/lsp/getting-started.rst
+++ b/docs/lsp/getting-started.rst
@@ -1,4 +1,4 @@
-.. _lsp_getting_started:
+.. _lsp-getting-started:
Getting Started
===============
diff --git a/docs/lsp/reference.rst b/docs/lsp/reference.rst
index 3e9b42173..cd48bea73 100644
--- a/docs/lsp/reference.rst
+++ b/docs/lsp/reference.rst
@@ -1,3 +1,5 @@
+.. _lsp-reference:
+
Reference
=========
diff --git a/docs/lsp/reference/configuration.rst b/docs/lsp/reference/configuration.rst
index 20947d844..d377e60c6 100644
--- a/docs/lsp/reference/configuration.rst
+++ b/docs/lsp/reference/configuration.rst
@@ -32,10 +32,193 @@ Below are all the configuration options supported by the server and their effect
- :ref:`lsp-configuration-completion`
- :ref:`lsp-configuration-developer`
-- :ref:`lsp-configuration-server`
+- :ref:`lsp-configuration-logging`
- :ref:`lsp-configuration-sphinx`
- :ref:`lsp-configuration-preview`
+.. _lsp-configuration-completion:
+
+Completion
+^^^^^^^^^^
+
+The following options affect completion suggestions.
+
+.. esbonio:config:: esbonio.server.completion.preferredInsertBehavior
+ :scope: global
+ :type: string
+
+ Controls how completions behave when accepted, the following values are supported.
+
+ - ``replace`` (default)
+
+ Accepted completions will replace existing text, allowing the server to rewrite the current line in place.
+ This allows the server to return all possible completions within the current context.
+ In this mode the server will set the ``textEdit`` field of a ``CompletionItem``.
+
+ - ``insert``
+
+ Accepted completions will append to existing text rather than replacing it.
+ Since rewriting is not possible, only the completions that are compatible with any existing text will be returned.
+ In this mode the server will set the ``insertText`` field of a ``CompletionItem`` which should work better with editors that do no support ``textEdits``.
+
+.. _lsp-configuration-developer:
+
+Developer
+^^^^^^^^^
+
+The following options are useful when extending or working on the language server
+
+.. esbonio:config:: esbonio.server.showDeprecationWarnings
+ :scope: global
+ :type: boolean
+
+ Developer flag which, when enabled, the server will publish any deprecation warnings as diagnostics.
+
+.. esbonio:config:: esbonio.server.enableDevTools (boolean)
+ :scope: global
+ :type: boolean
+
+ Enable `lsp-devtools`_ integration for the language server itself.
+
+.. esbonio:config:: esbonio.sphinx.enableDevTools (boolean)
+ :scope: global
+ :type: boolean
+
+ Enable `lsp-devtools`_ integration for the Sphinx subprocess started by the language server.
+
+.. esbonio:config:: esbonio.sphinx.pythonPath (string[])
+ :scope: global
+ :type: string[]
+
+ List of paths to use when constructing the value of ``PYTHONPATH``.
+ Used to inject the sphinx agent into the target environment."
+
+.. _lsp-devtools: https://swyddfa.github.io/lsp-devtools/docs/latest/en/
+
+.. _lsp-configuration-logging:
+
+Logging
+^^^^^^^
+
+The following options control the logging output of the language server.
+
+.. esbonio:config:: esbonio.logging.level
+ :scope: global
+ :type: string
+
+ Sets the default level of log messages emitted by the server.
+ The following values are accepted, sorted in the order from least to most verbose.
+
+ - ``critical``
+ - ``fatal``
+ - ``error`` (default)
+ - ``warning``
+ - ``info``
+ - ``debug``
+
+.. esbonio:config:: esbonio.logging.format
+ :scope: global
+ :type: string
+
+ Sets the default format string to apply to log messages.
+ This can be any valid :external:ref:`%-style ` format string, referencing valid :external:ref:`logrecord-attributes`
+
+ **Default value:** ``[%(name)s]: %(message)s``
+
+.. esbonio:config:: esbonio.logging.filepath
+ :scope: global
+ :type: string
+
+ If set, record log messages in the given filepath (relative to the server's working directory)
+
+.. esbonio:config:: esbonio.logging.stderr
+ :scope: global
+ :type: boolean
+
+ If ``True`` (the default), the server will print log messages to the process' stderr
+
+.. esbonio:config:: esbonio.logging.window
+ :scope: global
+ :type: boolean
+
+ If ``True``, the server will send messages to the client as :lsp:`window/logMessage` notifications
+
+.. esbonio:config:: esbonio.logging.config
+ :scope: global
+ :type: object
+
+ This is an object used to override the default logging configuration for specific, named loggers.
+ Keys in the object are the names of loggers to override, values are a dictionary that can contain the following fields
+
+ - ``level`` if present, overrides the value of :esbonio:conf:`esbonio.logging.level`
+ - ``format`` if present, overrides the value of :esbonio:conf:`esbonio.logging.format`
+ - ``filepath`` if present, overrides the value of :esbonio:conf:`esbonio.logging.filepath`
+ - ``stderr`` if present, overrides the value of :esbonio:conf:`esbonio.logging.stderr`
+ - ``window`` if present, overrides the value of :esbonio:conf:`esbonio.logging.window`
+
+Examples
+""""""""
+
+.. highlight:: json
+
+The following is equivalent to the server's default logging configuration::
+
+ {
+ "esbonio": {
+ "logging": {
+ "level": "error",
+ "format": "[%(name)s]: %(message)s",
+ "stderr": true,
+ "config": {
+ "sphinx": {
+ "level": "info",
+ "format": "%(message)s"
+ }
+ }
+ }
+ }
+ }
+
+This sets the default log level to ``debug`` and dials back or redirects the output from some of the noisier loggers::
+
+ {
+ "esbonio": {
+ "logging": {
+ "level": "debug",
+ "config": {
+ "esbonio.Configuration": {
+ "level": "info"
+ },
+ "esbonio.PreviewServer": {
+ "filename": "http.log",
+ "stderr": false
+ },
+ "esbonio.WebviewServer": {
+ "level": "error"
+ }
+ }
+ }
+ }
+ }
+
+Loggers
+"""""""
+
+The following table summarises (some of) the available loggers and the type of messages they report
+
+========================== ===========
+Name Description
+========================== ===========
+``esbonio`` Messages coming from ``esbonio`` itself that do not belong anywhere else
+``esbonio.Configuration`` Messages about merging configuration from multiple sources and notifying the rest of the server when values change.
+``esbonio.PreviewManager`` Messages from the component orchestrating the HTTP and Websocket servers that power the preview functionality
+``esbonio.PreviewServer`` Records the HTTP traffic from the server that serves the HTML files built by Sphinx
+``esbonio.SphinxManager`` Messages from the component that manages the server's underlying Sphinx processes
+``esbonio.WebviewServer`` Messages about the websocket connection between the HTML viewer and the server
+``py.warnings`` Log messages coming from Python's warnings framework
+``sphinx`` Log messages coming from an underlying sphinx process
+========================== ===========
+
.. _lsp-configuration-sphinx:
Sphinx
@@ -125,95 +308,11 @@ The following options control the behavior of the preview
:type: integer
The port number to bind the HTTP server to.
- If ``0``, a random port number will be chosen".
+ If ``0`` (the default), a random port number will be chosen
.. esbonio:config:: esbonio.preview.wsPort
:scope: project
:type: integer
The port number to bind the WebSocket server to.
- If ``0``, a random port number will be chosen"
-
-.. _lsp-configuration-server:
-
-Server
-^^^^^^
-
-The following options control the behavior of the language server as a whole.
-
-.. esbonio:config:: esbonio.server.logLevel
- :scope: global
- :type: string
-
- This can be used to set the level of log messages emitted by the server.
- This can be set to one of the following values.
-
- - ``error`` (default)
- - ``info``
- - ``debug``
-
-.. esbonio:config:: esbonio.server.logFilter
- :scope: global
- :type: string[]
-
- The language server will typically include log output from all of its components.
- This option can be used to restrict the log output to be only those named.
-
-.. _lsp-configuration-completion:
-
-Completion
-^^^^^^^^^^
-
-The following options affect completion suggestions.
-
-.. esbonio:config:: esbonio.server.completion.preferredInsertBehavior
- :scope: global
- :type: string
-
- Controls how completions behave when accepted, the following values are supported.
-
- - ``replace`` (default)
-
- Accepted completions will replace existing text, allowing the server to rewrite the current line in place.
- This allows the server to return all possible completions within the current context.
- In this mode the server will set the ``textEdit`` field of a ``CompletionItem``.
-
- - ``insert``
-
- Accepted completions will append to existing text rather than replacing it.
- Since rewriting is not possible, only the completions that are compatible with any existing text will be returned.
- In this mode the server will set the ``insertText`` field of a ``CompletionItem`` which should work better with editors that do no support ``textEdits``.
-
-.. _lsp-configuration-developer:
-
-Developer
-^^^^^^^^^
-
-The following options are useful when extending or working on the language server
-
-.. esbonio:config:: esbonio.server.showDeprecationWarnings
- :scope: global
- :type: boolean
-
- Developer flag which, when enabled, the server will publish any deprecation warnings as diagnostics.
-
-.. esbonio:config:: esbonio.server.enableDevTools (boolean)
- :scope: global
- :type: boolean
-
- Enable `lsp-devtools`_ integration for the language server itself.
-
-.. esbonio:config:: esbonio.sphinx.enableDevTools (boolean)
- :scope: global
- :type: boolean
-
- Enable `lsp-devtools`_ integration for the Sphinx subprocess started by the language server.
-
-.. esbonio:config:: esbonio.sphinx.pythonPath (string[])
- :scope: global
- :type: string[]
-
- List of paths to use when constructing the value of ``PYTHONPATH``.
- Used to inject the sphinx agent into the target environment."
-
-.. _lsp-devtools: https://swyddfa.github.io/lsp-devtools/docs/latest/en/
+ If ``0`` (the default), a random port number will be chosen
diff --git a/docs/lsp/reference/notifications.rst b/docs/lsp/reference/notifications.rst
new file mode 100644
index 000000000..3af90708f
--- /dev/null
+++ b/docs/lsp/reference/notifications.rst
@@ -0,0 +1,18 @@
+Notifications
+=============
+
+In addition to the language server protocol, Esbonio will emit the following notifications
+
+.. currentmodule:: esbonio.server.features.sphinx_manager.manager
+
+.. autoclass:: ClientCreatedNotification
+ :members:
+
+.. autoclass:: AppCreatedNotification
+ :members:
+
+.. autoclass:: ClientErroredNotification
+ :members:
+
+.. autoclass:: ClientDestroyedNotification
+ :members:
diff --git a/flake.lock b/flake.lock
index d11d4f426..8d9c47bca 100644
--- a/flake.lock
+++ b/flake.lock
@@ -10,11 +10,11 @@
]
},
"locked": {
- "lastModified": 1704650820,
- "narHash": "sha256-dRztpidI5eMB7u13IT4zD4ku6isWgQlheKSM1piPop4=",
+ "lastModified": 1712600859,
+ "narHash": "sha256-1a2djQq73lSl3MCQvNBGXrBWXbjr8uvqulRC47RG2ow=",
"owner": "swyddfa",
"repo": "lsp-devtools",
- "rev": "13e5cfd55753e87157bc0a1beb7ce587b1bc8410",
+ "rev": "9bb50d3a19b12f0c4f98a5a8f564dee89d0c54cb",
"type": "github"
},
"original": {
@@ -25,11 +25,11 @@
},
"nixpkgs": {
"locked": {
- "lastModified": 1704161960,
- "narHash": "sha256-QGua89Pmq+FBAro8NriTuoO/wNaUtugt29/qqA8zeeM=",
+ "lastModified": 1713128889,
+ "narHash": "sha256-aB90ZqzosyRDpBh+rILIcyP5lao8SKz8Sr2PSWvZrzk=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "63143ac2c9186be6d9da6035fa22620018c85932",
+ "rev": "2748d22b45a99fb2deafa5f11c7531c212b2cefa",
"type": "github"
},
"original": {
@@ -66,11 +66,11 @@
"systems": "systems"
},
"locked": {
- "lastModified": 1701680307,
- "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
+ "lastModified": 1710146030,
+ "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
+ "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
diff --git a/lib/esbonio-extensions/esbonio/ext/spelling.py b/lib/esbonio-extensions/esbonio/ext/spelling.py
index a0e554661..b98610e73 100644
--- a/lib/esbonio-extensions/esbonio/ext/spelling.py
+++ b/lib/esbonio-extensions/esbonio/ext/spelling.py
@@ -1,4 +1,5 @@
"""Spell checking."""
+
import re
from typing import Dict
from typing import List
diff --git a/lib/esbonio-extensions/esbonio/relevant_to/__init__.py b/lib/esbonio-extensions/esbonio/relevant_to/__init__.py
index f81fabb71..58427482b 100644
--- a/lib/esbonio-extensions/esbonio/relevant_to/__init__.py
+++ b/lib/esbonio-extensions/esbonio/relevant_to/__init__.py
@@ -39,8 +39,7 @@ def visit_relevant_to_script(self, node: relevant_to_script):
self.body.append("")
-def depart_relevant_to_script(self, node: relevant_to_script):
- ...
+def depart_relevant_to_script(self, node: relevant_to_script): ...
class selection(nodes.Element):
@@ -91,12 +90,10 @@ def visit_selection(self, node: selection):
)
-def depart_selection(self, node: selection):
- ...
+def depart_selection(self, node: selection): ...
-class relevant_section(nodes.Element):
- ...
+class relevant_section(nodes.Element): ...
def visit_relevant_section(self, node: relevant_section):
diff --git a/lib/esbonio/README.md b/lib/esbonio/README.md
index 207479790..86b544f23 100644
--- a/lib/esbonio/README.md
+++ b/lib/esbonio/README.md
@@ -42,7 +42,7 @@ The language server provides the following features
It's recommended to install the language server with [`pipx`](https://pipx.pypa.io/stable/)
-Be sure to check out the [Getting Started](https://docs.esbon.io/latest/en/lsp/getting-started.html) guide for details on integrating the server with your editor of choice.
+Be sure to check out the [Getting Started](https://docs.esbon.io/en/latest/lsp/getting-started.html) guide for details on integrating the server with your editor of choice.
```
$ pipx install esbonio
diff --git a/lib/esbonio/changes/660.fix.md b/lib/esbonio/changes/660.fix.md
new file mode 100644
index 000000000..e97bfad94
--- /dev/null
+++ b/lib/esbonio/changes/660.fix.md
@@ -0,0 +1 @@
+The server should no longer sometimes spawn duplicated Sphinx processes
diff --git a/lib/esbonio/changes/695.fix.md b/lib/esbonio/changes/695.fix.md
new file mode 100644
index 000000000..870753467
--- /dev/null
+++ b/lib/esbonio/changes/695.fix.md
@@ -0,0 +1 @@
+The server now respects Sphinx configuration values like `suppress_warnings`
diff --git a/lib/esbonio/changes/718.fix.md b/lib/esbonio/changes/718.fix.md
new file mode 100644
index 000000000..8a9e79c0c
--- /dev/null
+++ b/lib/esbonio/changes/718.fix.md
@@ -0,0 +1 @@
+The server will no longer raise a `ValueError` when used in a situation where there is an empty workspace
diff --git a/lib/esbonio/changes/748.breaking.md b/lib/esbonio/changes/748.breaking.md
new file mode 100644
index 000000000..3327c279c
--- /dev/null
+++ b/lib/esbonio/changes/748.breaking.md
@@ -0,0 +1,2 @@
+- Removed the `esbonio.server.logLevel` option, use `esbonio.logging.level` instead.
+- Removed the `esbonio.server.logFilter` option, it has been made obselete by the other `esbonio.logging.*` options
diff --git a/lib/esbonio/changes/748.enhancement.md b/lib/esbonio/changes/748.enhancement.md
new file mode 100644
index 000000000..af44fadcd
--- /dev/null
+++ b/lib/esbonio/changes/748.enhancement.md
@@ -0,0 +1,8 @@
+Added the following configuration options
+
+- `esbonio:config:: esbonio.logging.level`, set the default logging level of the server
+- `esbonio:config:: esbonio.logging.format`, set the default format of server log messages
+- `esbonio:config:: esbonio.logging.filepath`, enable logging to a file
+- `esbonio:config:: esbonio.logging.stderr`, print log messages to stderr
+- `esbonio:config:: esbonio.logging.window`, send log messages as `window/logMessage` notifications
+- `esbonio:config:: esbonio.logging.config`, override logging configuration for individual loggers, see the [documentation](https://docs.esbon.io/en/latest/lsp/reference/configuration.html#lsp-configuration-logging) for details
diff --git a/lib/esbonio/changes/750.enhancement.md b/lib/esbonio/changes/750.enhancement.md
new file mode 100644
index 000000000..d2ca8fb41
--- /dev/null
+++ b/lib/esbonio/changes/750.enhancement.md
@@ -0,0 +1 @@
+The server will now automatically restart the underlying Sphinx process when it detects a change in its configuration
diff --git a/lib/esbonio/changes/756.enhancement.md b/lib/esbonio/changes/756.enhancement.md
new file mode 100644
index 000000000..46cc83076
--- /dev/null
+++ b/lib/esbonio/changes/756.enhancement.md
@@ -0,0 +1 @@
+The server now emits `sphinx/clientCreated`, `sphinx/clientErrored` and `sphinx/clientDestroyed` notifications that correspond to the lifecycle of the underlying Sphinx process
diff --git a/lib/esbonio/esbonio/__main__.py b/lib/esbonio/esbonio/__main__.py
index 4b62e28ca..888ed7eeb 100644
--- a/lib/esbonio/esbonio/__main__.py
+++ b/lib/esbonio/esbonio/__main__.py
@@ -1,4 +1,5 @@
"""Default startup module, identical to calling ``python -m esbonio.server``"""
+
import sys
from esbonio.server.cli import main
diff --git a/lib/esbonio/esbonio/cli/__init__.py b/lib/esbonio/esbonio/cli/__init__.py
deleted file mode 100644
index 1e1299114..000000000
--- a/lib/esbonio/esbonio/cli/__init__.py
+++ /dev/null
@@ -1,113 +0,0 @@
-import argparse
-import logging
-import sys
-import warnings
-from typing import Literal
-from typing import Union
-
-from pygls.protocol import default_converter
-
-
-def esbonio_converter():
- converter = default_converter()
- converter.register_structure_hook(Union[Literal["auto"], int], lambda obj, _: obj)
-
- return converter
-
-
-def setup_cli(progname: str, description: str) -> argparse.ArgumentParser:
- """Return an argument parser with the default command line options required for
- main.
- """
-
- cli = argparse.ArgumentParser(prog=f"python -m {progname}", description=description)
- cli.add_argument(
- "-p",
- "--port",
- type=int,
- default=None,
- help="start a TCP instance of the language server listening on the given port.",
- )
- cli.add_argument(
- "--version", action="store_true", help="print the current version and exit."
- )
-
- modules = cli.add_argument_group(
- "modules", "include/exclude language server modules."
- )
- modules.add_argument(
- "-i",
- "--include",
- metavar="MOD",
- action="append",
- default=[],
- dest="included_modules",
- help="include an additional module in the server configuration, can be given multiple times.",
- )
- modules.add_argument(
- "-e",
- "--exclude",
- metavar="MOD",
- action="append",
- default=[],
- dest="excluded_modules",
- help="exclude a module from the server configuration, can be given multiple times.",
- )
-
- return cli
-
-
-def main(cli: argparse.ArgumentParser):
- """Standard main function for each of the default language servers."""
-
- # Put these here to avoid circular import issues.
- from esbonio.lsp import __version__
- from esbonio.lsp import create_language_server
- from esbonio.lsp.log import LOG_NAMESPACE
- from esbonio.lsp.log import MemoryHandler
-
- args = cli.parse_args()
-
- if args.version:
- print(f"v{__version__}")
- sys.exit(0)
-
- modules = list(args.modules)
-
- for mod in args.included_modules:
- modules.append(mod)
-
- for mod in args.excluded_modules:
- if mod in modules:
- modules.remove(mod)
-
- # Ensure we can capture warnings.
- logging.captureWarnings(True)
- warnlog = logging.getLogger("py.warnings")
-
- if not sys.warnoptions:
- warnings.simplefilter("default") # Enable capture of DeprecationWarnings
-
- # Setup a temporary logging handler that can cache messages until the language server
- # is ready to forward them onto the client.
- logger = logging.getLogger(LOG_NAMESPACE)
- logger.setLevel(logging.DEBUG)
-
- handler = MemoryHandler()
- handler.setLevel(logging.DEBUG)
- logger.addHandler(handler)
- warnlog.addHandler(handler)
-
- server = create_language_server(
- args.server_cls,
- modules,
- name="esbonio",
- version=__version__,
- # TODO: Figure out how to make this extensible
- converter_factory=esbonio_converter,
- )
-
- if args.port:
- server.start_tcp("localhost", args.port)
- else:
- server.start_io()
diff --git a/lib/esbonio/esbonio/cli/py.typed b/lib/esbonio/esbonio/cli/py.typed
deleted file mode 100644
index 4a787c57d..000000000
--- a/lib/esbonio/esbonio/cli/py.typed
+++ /dev/null
@@ -1 +0,0 @@
-# esbonio.cli: marker file for PEP 561
diff --git a/lib/esbonio/esbonio/lsp/__init__.py b/lib/esbonio/esbonio/lsp/__init__.py
deleted file mode 100644
index 9d30bb3cb..000000000
--- a/lib/esbonio/esbonio/lsp/__init__.py
+++ /dev/null
@@ -1,419 +0,0 @@
-import enum
-import importlib
-import json
-import logging
-import textwrap
-import traceback
-from typing import Any
-from typing import Dict
-from typing import Iterable
-from typing import List
-from typing import Optional
-from typing import Type
-
-from lsprotocol.types import COMPLETION_ITEM_RESOLVE
-from lsprotocol.types import INITIALIZE
-from lsprotocol.types import INITIALIZED
-from lsprotocol.types import SHUTDOWN
-from lsprotocol.types import TEXT_DOCUMENT_CODE_ACTION
-from lsprotocol.types import TEXT_DOCUMENT_COMPLETION
-from lsprotocol.types import TEXT_DOCUMENT_DEFINITION
-from lsprotocol.types import TEXT_DOCUMENT_DID_CHANGE
-from lsprotocol.types import TEXT_DOCUMENT_DID_OPEN
-from lsprotocol.types import TEXT_DOCUMENT_DID_SAVE
-from lsprotocol.types import TEXT_DOCUMENT_DOCUMENT_LINK
-from lsprotocol.types import TEXT_DOCUMENT_DOCUMENT_SYMBOL
-from lsprotocol.types import TEXT_DOCUMENT_HOVER
-from lsprotocol.types import TEXT_DOCUMENT_IMPLEMENTATION
-from lsprotocol.types import WORKSPACE_DID_DELETE_FILES
-from lsprotocol.types import CodeActionParams
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import CompletionList
-from lsprotocol.types import CompletionOptions
-from lsprotocol.types import CompletionParams
-from lsprotocol.types import DefinitionParams
-from lsprotocol.types import DeleteFilesParams
-from lsprotocol.types import DidChangeTextDocumentParams
-from lsprotocol.types import DidOpenTextDocumentParams
-from lsprotocol.types import DidSaveTextDocumentParams
-from lsprotocol.types import DocumentLinkParams
-from lsprotocol.types import DocumentSymbolParams
-from lsprotocol.types import FileOperationFilter
-from lsprotocol.types import FileOperationPattern
-from lsprotocol.types import FileOperationRegistrationOptions
-from lsprotocol.types import Hover
-from lsprotocol.types import HoverParams
-from lsprotocol.types import ImplementationParams
-from lsprotocol.types import InitializedParams
-from lsprotocol.types import InitializeParams
-from lsprotocol.types import MarkupContent
-from lsprotocol.types import MarkupKind
-
-from .rst import CompletionContext
-from .rst import DefinitionContext
-from .rst import DocumentLinkContext
-from .rst import HoverContext
-from .rst import ImplementationContext
-from .rst import LanguageFeature
-from .rst import RstLanguageServer
-from .symbols import SymbolVisitor
-
-__version__ = "0.16.2"
-
-__all__ = [
- "CompletionContext",
- "DefinitionContext",
- "DocumentLinkContext",
- "HoverContext",
- "ImplementationContext",
- "LanguageFeature",
- "RstLanguageServer",
- "create_language_server",
-]
-
-logger = logging.getLogger(__name__)
-
-# Commands
-ESBONIO_SERVER_CONFIGURATION = "esbonio.server.configuration"
-ESBONIO_SERVER_PREVIEW = "esbonio.server.preview"
-ESBONIO_SERVER_BUILD = "esbonio.server.build"
-
-
-def create_language_server(
- server_cls: Type[RstLanguageServer], modules: Iterable[str], *args, **kwargs
-) -> RstLanguageServer:
- """Create a new language server instance.
-
- Parameters
- ----------
- server_cls:
- The class definition to create the server from.
- modules:
- The list of modules that should be loaded.
- args, kwargs:
- Any additional arguments that should be passed to the language server's
- constructor.
- """
-
- if "logger" not in kwargs:
- kwargs["logger"] = logger
-
- server = server_cls(*args, **kwargs)
-
- for module in modules:
- _load_module(server, module)
-
- return _configure_lsp_methods(server)
-
-
-def _configure_lsp_methods(server: RstLanguageServer) -> RstLanguageServer:
- @server.feature(INITIALIZE)
- def on_initialize(ls: RstLanguageServer, params: InitializeParams):
- ls.initialize(params)
-
- for feature in ls._features.values():
- feature.initialize(params)
-
- @server.feature(INITIALIZED)
- def on_initialized(ls: RstLanguageServer, params: InitializedParams):
- ls.initialized(params)
-
- for feature in ls._features.values():
- feature.initialized(params)
-
- @server.feature(SHUTDOWN)
- def on_shutdown(ls: RstLanguageServer, *args):
- ls.on_shutdown(*args)
-
- for feature in ls._features.values():
- feature.on_shutdown(*args)
-
- @server.feature(TEXT_DOCUMENT_DID_OPEN)
- def on_open(ls: RstLanguageServer, params: DidOpenTextDocumentParams):
- ...
-
- @server.feature(TEXT_DOCUMENT_DID_CHANGE)
- def on_change(ls: RstLanguageServer, params: DidChangeTextDocumentParams):
- pass
-
- @server.command(ESBONIO_SERVER_BUILD)
- def build(ls: RstLanguageServer, *args):
- params = {} if not args[0] else args[0][0]._asdict()
- force_all: bool = params.get("force_all", False)
- filenames: Optional[List[str]] = params.get("filenames", None)
- ls.build(force_all, filenames)
-
- @server.feature(TEXT_DOCUMENT_DID_SAVE)
- def on_save(ls: RstLanguageServer, params: DidSaveTextDocumentParams):
- ls.save(params)
-
- for feature in ls._features.values():
- feature.save(params)
-
- @server.feature(
- WORKSPACE_DID_DELETE_FILES,
- FileOperationRegistrationOptions(
- filters=[
- FileOperationFilter(
- pattern=FileOperationPattern(glob="**/*.rst"),
- )
- ]
- ),
- )
- def on_delete_files(ls: RstLanguageServer, params: DeleteFilesParams):
- ls.delete_files(params)
-
- for feature in ls._features.values():
- feature.delete_files(params)
-
- @server.feature(TEXT_DOCUMENT_CODE_ACTION)
- def on_code_action(ls: RstLanguageServer, params: CodeActionParams):
- actions = []
-
- for feature in ls._features.values():
- actions += feature.code_action(params)
-
- return actions
-
- @server.feature(TEXT_DOCUMENT_HOVER)
- def on_hover(ls: RstLanguageServer, params: HoverParams):
- uri = params.text_document.uri
- doc = ls.workspace.get_document(uri)
- pos = params.position
- line = ls.line_at_position(doc, pos)
- location = ls.get_location_type(doc, pos)
-
- hover_values = []
- for feature in ls._features.values():
- for pattern in feature.hover_triggers:
- for match in pattern.finditer(line):
- if not match:
- continue
-
- # only trigger hover if the position of the request is within
- # the match
- start, stop = match.span()
- if start <= pos.character <= stop:
- context = HoverContext(
- doc=doc,
- location=location,
- match=match,
- position=pos,
- capabilities=ls.client_capabilities,
- )
- ls.logger.debug("Hover context: %s", context)
-
- hover_value = feature.hover(context)
- hover_values.append(hover_value)
-
- hover_content_values = "\n".join(hover_values)
-
- return Hover(
- contents=MarkupContent(
- kind=MarkupKind.Markdown,
- value=hover_content_values,
- )
- )
-
- #
- @server.feature(
- TEXT_DOCUMENT_COMPLETION,
- CompletionOptions(
- trigger_characters=[">", ".", ":", "`", "<", "/"], resolve_provider=True
- ),
- )
- def on_completion(ls: RstLanguageServer, params: CompletionParams):
- uri = params.text_document.uri
- pos = params.position
-
- doc = ls.workspace.get_document(uri)
- line = ls.line_at_position(doc, pos)
- location = ls.get_location_type(doc, pos)
-
- items = []
-
- for name, feature in ls._features.items():
- for pattern in feature.completion_triggers:
- for match in pattern.finditer(line):
- if not match:
- continue
-
- # Only trigger completions if the position of the request is within
- # the match.
- start, stop = match.span()
- if start <= pos.character <= stop:
- context = CompletionContext(
- doc=doc,
- location=location,
- match=match,
- position=pos,
- config=ls.user_config.server.completion,
- capabilities=ls.client_capabilities,
- )
- ls.logger.debug("Completion context: %s", context)
-
- for item in feature.complete(context):
- item.data = {"source_feature": name, **(item.data or {})} # type: ignore
- items.append(item)
-
- return CompletionList(is_incomplete=False, items=items)
-
- #
-
- @server.feature(COMPLETION_ITEM_RESOLVE)
- def on_completion_resolve(
- ls: RstLanguageServer, item: CompletionItem
- ) -> CompletionItem:
- source = (item.data or {}).get("source_feature", "") # type: ignore
- feature = ls.get_feature(source)
-
- if not feature:
- ls.logger.error(
- "Unable to resolve completion item, unknown source: '%s'", source
- )
- return item
-
- return feature.completion_resolve(item)
-
- @server.feature(TEXT_DOCUMENT_DEFINITION)
- def on_definition(ls: RstLanguageServer, params: DefinitionParams):
- uri = params.text_document.uri
- pos = params.position
-
- doc = ls.workspace.get_document(uri)
- line = ls.line_at_position(doc, pos)
- location = ls.get_location_type(doc, pos)
-
- definitions = []
-
- for feature in ls._features.values():
- for pattern in feature.definition_triggers:
- for match in pattern.finditer(line):
- if not match:
- continue
-
- start, stop = match.span()
- if start <= pos.character and pos.character <= stop:
- context = DefinitionContext(
- doc=doc, location=location, match=match, position=pos
- )
- definitions += feature.definition(context)
-
- return definitions
-
- @server.feature(TEXT_DOCUMENT_IMPLEMENTATION)
- def on_implementation(ls: RstLanguageServer, params: ImplementationParams):
- uri = params.text_document.uri
- pos = params.position
-
- doc = ls.workspace.get_document(uri)
- line = ls.line_at_position(doc, pos)
- location = ls.get_location_type(doc, pos)
-
- implementations = []
-
- for feature in ls._features.values():
- for pattern in feature.implementation_triggers:
- for match in pattern.finditer(line):
- if not match:
- continue
-
- start, stop = match.span()
- if start <= pos.character and pos.character <= stop:
- context = ImplementationContext(
- doc=doc, location=location, match=match, position=pos
- )
- ls.logger.debug("Implementation context: %s", context)
- implementations += feature.implementation(context)
-
- return implementations
-
- @server.feature(TEXT_DOCUMENT_DOCUMENT_LINK)
- def on_document_link(ls: RstLanguageServer, params: DocumentLinkParams):
- uri = params.text_document.uri
- doc = ls.workspace.get_document(uri)
- context = DocumentLinkContext(doc=doc, capabilities=ls.client_capabilities)
-
- links = []
- for feature in ls._features.values():
- links += feature.document_link(context) or []
-
- return links
-
- @server.feature(TEXT_DOCUMENT_DOCUMENT_SYMBOL)
- def on_document_symbol(ls: RstLanguageServer, params: DocumentSymbolParams):
- doctree = ls.get_initial_doctree(uri=params.text_document.uri)
- if doctree is None:
- return None
-
- visitor = SymbolVisitor(ls, doctree)
- doctree.walkabout(visitor)
-
- return visitor.symbols
-
- @server.command(ESBONIO_SERVER_CONFIGURATION)
- def get_configuration(ls: RstLanguageServer, *args):
- """Get the server's configuration.
-
- Not to be confused with the ``workspace/configuration`` request where the server
- can request the client's configuration. This is so clients can ask for sphinx's
- output path for example.
-
- As far as I know, there isn't anything built into the spec to cater for this?
- """
- config = ls.configuration
- ls.logger.debug("%s: %s", ESBONIO_SERVER_CONFIGURATION, dump(config))
-
- return config
-
- @server.command(ESBONIO_SERVER_PREVIEW)
- def preview(ls: RstLanguageServer, *args) -> Dict[str, Any]:
- """Start/Generate a preview of the project"""
- params = {} if not args[0] else args[0][0]
- ls.logger.debug("%s: %s", ESBONIO_SERVER_PREVIEW, params)
-
- return ls.preview(params) or {}
-
- return server
-
-
-def _load_module(server: RstLanguageServer, modname: str):
- """Load an extension module by calling its ``esbonio_setup`` function, if it exists."""
-
- try:
- module = importlib.import_module(modname)
- except ImportError:
- logger.error(
- "Unable to import module '%s'\n%s", modname, traceback.format_exc()
- )
- return None
-
- setup = getattr(module, "esbonio_setup", None)
- if setup is None:
- logger.error("Skipping module '%s', missing 'esbonio_setup' function", modname)
- return None
-
- server.load_extension(modname, setup)
-
-
-def dump(obj) -> str:
- """Debug helper function that converts an object to JSON."""
-
- def default(o):
- if isinstance(o, enum.Enum):
- return o.value
-
- fields = {}
- for k, v in o.__dict__.items():
- if v is None:
- continue
-
- # Truncate long strings - but not uris!
- if isinstance(v, str) and not k.lower().endswith("uri"):
- v = textwrap.shorten(v, width=25)
-
- fields[k] = v
-
- return fields
-
- return json.dumps(obj, default=default)
diff --git a/lib/esbonio/esbonio/lsp/directives/__init__.py b/lib/esbonio/esbonio/lsp/directives/__init__.py
deleted file mode 100644
index b62c836dc..000000000
--- a/lib/esbonio/esbonio/lsp/directives/__init__.py
+++ /dev/null
@@ -1,927 +0,0 @@
-import re
-import traceback
-import typing
-import warnings
-from typing import Any
-from typing import Dict
-from typing import Iterable
-from typing import List
-from typing import Optional
-from typing import Protocol
-from typing import Tuple
-from typing import Type
-
-from docutils.parsers.rst import Directive
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import DocumentLink
-from lsprotocol.types import Location
-from lsprotocol.types import MarkupContent
-from lsprotocol.types import MarkupKind
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-
-from esbonio.lsp import CompletionContext
-from esbonio.lsp import DefinitionContext
-from esbonio.lsp import DocumentLinkContext
-from esbonio.lsp import HoverContext
-from esbonio.lsp import ImplementationContext
-from esbonio.lsp import LanguageFeature
-from esbonio.lsp import RstLanguageServer
-from esbonio.lsp.sphinx import SphinxLanguageServer
-from esbonio.lsp.util.inspect import get_object_location
-from esbonio.lsp.util.patterns import DIRECTIVE
-from esbonio.lsp.util.patterns import DIRECTIVE_OPTION
-
-from .completions import render_directive_completion
-from .completions import render_directive_option_completion
-
-
-class DirectiveLanguageFeature:
- """Base class for directive language features."""
-
- def complete_arguments(
- self, context: CompletionContext, domain: str, name: str
- ) -> List[CompletionItem]:
- """Return a list of completion items representing valid targets for the given
- directive.
-
- Parameters
- ----------
- context:
- The completion context
- domain:
- The name of the domain the directive is a member of
- name:
- The name of the domain
- """
- return []
-
- def get_implementation(
- self, directive: str, domain: Optional[str]
- ) -> Optional[Type[Directive]]:
- """Return the implementation for the given directive name."""
- return self.index_directives().get(directive, None)
-
- def index_directives(self) -> Dict[str, Type[Directive]]:
- """Return all known directives."""
- return dict()
-
- def suggest_directives(
- self, context: CompletionContext
- ) -> Iterable[Tuple[str, Type[Directive]]]:
- """Suggest directives that may be used, given a completion context."""
- return self.index_directives().items()
-
- def suggest_options(
- self, context: CompletionContext, directive: str, domain: Optional[str]
- ) -> Iterable[str]:
- """Suggest options that may be used, given a completion context."""
-
- impl = self.get_implementation(directive, domain)
- if impl is None:
- return []
-
- option_spec = getattr(impl, "option_spec", {}) or {}
- return option_spec.keys()
-
- def resolve_argument_link(
- self,
- context: DocumentLinkContext,
- directive: str,
- domain: Optional[str],
- argument: str,
- ) -> Tuple[Optional[str], Optional[str]]:
- """Resolve a document link request for the given argument.
-
- Parameters
- ----------
- context
- The context of the document link request.
-
- directive
- The name of the directive the argument is associated with.
-
- domain
- The name of the domain the directive belongs to, if applicable.
-
- argument
- The argument to resolve the link for.
- """
- return None, None
-
- def find_argument_definitions(
- self,
- context: DefinitionContext,
- directive: str,
- domain: Optional[str],
- argument: str,
- ) -> List[Location]:
- """Return a list of locations representing definitions of the given argument.
-
- Parameters
- ----------
- context
- The context of the definition request.
-
- directive
- The name of the directive the argument is associated with.
-
- domain
- The name of the domain the directive belongs to, if applicable.
-
- argument
- The argument to find the definition of.
- """
- return []
-
-
-class ArgumentCompletion(Protocol):
- """A completion provider for directive arguments.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``, use subclasses of
- :class:`~esbonio.lsp.directives.DirectiveLanguageFeature` instead.
- """
-
- def complete_arguments(
- self, context: CompletionContext, domain: str, name: str
- ) -> List[CompletionItem]:
- """Return a list of completion items representing valid targets for the given
- directive.
-
- Parameters
- ----------
- context:
- The completion context
- domain:
- The name of the domain the directive is a member of
- name:
- The name of the domain
- """
-
-
-class ArgumentDefinition(Protocol):
- """A definition provider for directive arguments.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``, use subclasses of
- :class:`~esbonio.lsp.directives.DirectiveLanguageFeature` instead.
- """
-
- def find_definitions(
- self,
- context: DefinitionContext,
- directive: str,
- domain: Optional[str],
- argument: str,
- ) -> List[Location]:
- """Return a list of locations representing definitions of the given argument.
-
- Parameters
- ----------
- context:
- The context of the definition request.
- directive:
- The name of the directive the argument is associated with.
- domain:
- The name of the domain the directive belongs to, if applicable.
- argument:
- The argument to find the definition of.
- """
-
-
-class ArgumentLink(Protocol):
- """A document link resolver for directive arguments.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``, use subclasses of
- :class:`~esbonio.lsp.directives.DirectiveLanguageFeature` instead.
- """
-
- def resolve_link(
- self,
- context: DocumentLinkContext,
- directive: str,
- domain: Optional[str],
- argument: str,
- ) -> Tuple[Optional[str], Optional[str]]:
- """Resolve a document link request for the given argument.
-
- Parameters
- ----------
- context:
- The context of the document link request.
- directive:
- The name of the directive the argument is associated with.
- domain:
- The name of the domain the directive belongs to, if applicable.
- argument:
- The argument to resolve the link for.
- """
-
-
-class Directives(LanguageFeature):
- """Directive support for the language server."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self._documentation: Dict[str, Dict[str, str]] = {}
- """Cache for documentation."""
-
- self._features: Dict[str, DirectiveLanguageFeature] = {}
- """The collection of registered features."""
-
- def add_feature(self, feature: DirectiveLanguageFeature):
- """Register a directive language feature.
-
- Parameters
- ----------
- feature
- The directive language feature
- """
- key = f"{feature.__module__}.{feature.__class__.__name__}"
-
- # Create an unique key for this instance.
- if key in self._features:
- key += f".{len([k for k in self._features.keys() if k.startswith(key)])}"
-
- self._features[key] = feature
-
- def add_argument_completion_provider(self, provider: ArgumentCompletion) -> None:
- """Register an :class:`~esbonio.lsp.directives.ArgumentCompletion` provider.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``, use
- :meth:`~esbonio.lsp.directives.Directives.add_feature` with a
- :class:`~esbonio.lsp.directives.DirectiveLanguageFeature` subclass instead.
-
- Parameters
- ----------
- provider:
- The provider to register.
- """
- warnings.warn(
- "ArgumentCompletion providers are deprecated in favour of "
- "DirectiveLanguageFeatures, this method will be removed in v1.0",
- DeprecationWarning,
- stacklevel=2,
- )
-
- name = provider.__class__.__name__
- key = f"{provider.__module__}.{name}.completion"
-
- # Automatically derive the feature definition from the provider.
- feature = type(
- f"{name}CompletionProvider",
- (DirectiveLanguageFeature,),
- {"complete_arguments": provider.complete_arguments},
- )()
-
- self._features[key] = feature
-
- def add_argument_definition_provider(self, provider: ArgumentDefinition) -> None:
- """Register an :class:`~esbonio.lsp.directives.ArgumentDefinition` provider.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``, use
- :meth:`~esbonio.lsp.directives.Directives.add_feature` with a
- :class:`~esbonio.lsp.directives.DirectiveLanguageFeature` subclass instead.
-
- Parameters
- ----------
- provider:
- The provider to register.
- """
- warnings.warn(
- "ArgumentDefinition providers are deprecated in favour of "
- "DirectiveLanguageFeatures, this method will be removed in v1.0",
- DeprecationWarning,
- stacklevel=2,
- )
-
- name = provider.__class__.__name__
- key = f"{provider.__module__}.{name}.definitions"
-
- # Automatically derive the feature definition from the provider.
- feature = type(
- f"{name}DefinitionProvider",
- (DirectiveLanguageFeature,),
- {"find_argument_definitions": provider.find_definitions},
- )()
-
- self._features[key] = feature
-
- def add_argument_link_provider(self, provider: ArgumentLink) -> None:
- """Register an :class:`~esbonio.lsp.directives.ArgumentLink` provider.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``, use
- :meth:`~esbonio.lsp.directives.Directives.add_feature` with a
- :class:`~esbonio.lsp.directives.DirectiveLanguageFeature` subclass instead.
-
- Parameters
- ----------
- provider:
- The provider to register.
- """
- warnings.warn(
- "ArgumentLink providers are deprecated in favour of "
- "DirectiveLanguageFeatures, this method will be removed in v1.0",
- DeprecationWarning,
- stacklevel=2,
- )
-
- name = provider.__class__.__name__
- key = f"{provider.__module__}.{name}.links"
-
- # Automatically derive the feature definition from the provider.
- feature = type(
- f"{name}LinkProvider",
- (DirectiveLanguageFeature,),
- {"resolve_argument_link": provider.resolve_link},
- )()
-
- self._features[key] = feature
-
- def add_documentation(self, documentation: Dict[str, Dict[str, Any]]) -> None:
- """Register directive documentation.
-
- ``documentation`` should be a dictionary with the following structure ::
-
- documentation = {
- "raw(docutils.parsers.rst.directives.misc.Raw)": {
- "is_markdown": true,
- "license": "https://...",
- "source": "https://...",
- "description": [
- "# .. raw::",
- "The raw directive is used for...",
- ...
- ]
- "options": {
- "file": "The file option allows...",
- ...
- }
- }
- }
-
- where the key has the form ``name(dotted_name)``. There are cases where a
- directive's implementation is not sufficient to uniquely identify it as
- multiple directives can be provided by a single class.
-
- This means the key has to be a combination of the ``name`` the user writes
- in a reStructuredText document and ``dotted_name`` is the fully qualified
- class name of the directive's implementation.
-
- .. note::
-
- If there is a clash with an existing key, the existing value will be
- overwritten with the new value.
-
- The values in this dictionary are themselves dictionaries with the following
- fields.
-
- ``description``
- A list of strings for the directive's main documentation.
-
- ``options``,
- A dictionary, with a field for the documentaton of each of the directive's
- options.
-
- ``is_markdown``
- A boolean flag used to indicate whether the ``description`` and ``options``
- are written in plain text or markdown.
-
- ``source``
- The url to the documentation's source
-
- ``license``
- The url to the documentation's license
-
- Parameters
- ----------
- documentation:
- The documentation to register.
- """
-
- for key, doc in documentation.items():
- description = doc.get("description", [])
-
- if not description:
- continue
-
- source = doc.get("source", "")
- if source:
- description.append(f"\n[Source]({source})")
-
- license = doc.get("license", "")
- if license:
- description.append(f"\n[License]({license})")
-
- doc["description"] = "\n".join(description)
- self._documentation[key] = doc
-
- def get_directives(self) -> Dict[str, Type[Directive]]:
- """Return a dictionary of all known directives."""
-
- directives = {}
-
- for name, feature in self._features.items():
- try:
- directives.update(feature.index_directives())
- except Exception:
- self.logger.error(
- "Unable to index directives, error in feature '%s'\n%s",
- name,
- traceback.format_exc(),
- )
-
- return directives
-
- def get_implementation(
- self, directive: str, domain: Optional[str]
- ) -> Optional[Type[Directive]]:
- """Return the implementation of a directive given its name
-
- Parameters
- ----------
- directive
- The name of the directive.
-
- domain
- The domain of the directive, if applicable.
- """
-
- if domain:
- name = f"{domain}:{directive}"
- else:
- name = directive
-
- for feature_name, feature in self._features.items():
- try:
- impl = feature.get_implementation(directive, domain)
- if impl is not None:
- return impl
- except Exception:
- self.logger.error(
- "Unable to get implementation for '%s', error in feature: '%s'\n%s",
- name,
- feature_name,
- traceback.format_exc(),
- )
-
- self.logger.debug(
- "Unable to get implementation for '%s', unknown directive", name
- )
- return None
-
- def suggest_directives(
- self, context: CompletionContext
- ) -> Iterable[Tuple[str, Type[Directive]]]:
- """Suggest directives that may be used, given a completion context.
-
- Parameters
- ----------
- context
- The CompletionContext.
- """
-
- for name, feature in self._features.items():
- try:
- yield from feature.suggest_directives(context)
- except Exception:
- self.logger.error(
- "Unable to suggest directives, error in feature: '%s'\n%s",
- name,
- traceback.format_exc(),
- )
-
- def suggest_options(
- self, context: CompletionContext, directive: str, domain: Optional[str]
- ) -> Iterable[str]:
- """Suggest directive options that may be used, given a completion context."""
-
- if domain:
- name = f"{domain}:{directive}"
- else:
- name = directive
-
- for feature_name, feature in self._features.items():
- try:
- yield from feature.suggest_options(context, directive, domain)
- except Exception:
- self.logger.error(
- "Unable to suggest options for directive '%s', error in feature: '%s'\n%s",
- name,
- feature_name,
- traceback.format_exc(),
- )
-
- completion_triggers = [DIRECTIVE, DIRECTIVE_OPTION]
- definition_triggers = [DIRECTIVE]
- hover_triggers = [DIRECTIVE]
- implementation_triggers = [DIRECTIVE]
-
- def completion_resolve(self, item: CompletionItem) -> CompletionItem:
- # We need extra info to know who to call.
- if not item.data:
- return item
-
- data = typing.cast(Dict, item.data)
- ctype = data.get("completion_type", "")
-
- if ctype == "directive":
- return self.completion_resolve_directive(item)
-
- if ctype == "directive_option":
- return self.completion_resolve_option(item)
-
- return item
-
- def complete(self, context: CompletionContext) -> List[CompletionItem]:
- # Do not suggest completions within the middle of Python code.
- if context.location == "py":
- return []
-
- groups = context.match.groupdict()
-
- # Are we completing a directive's options?
- if "directive" not in groups:
- return self.complete_options(context)
-
- # Are we completing the directive's argument?
- directive_end = context.match.span()[0] + len(groups["directive"])
- complete_directive = groups["directive"].endswith("::")
-
- if complete_directive and directive_end < context.position.character:
- return self.complete_arguments(context)
-
- return self.complete_directives(context)
-
- def complete_arguments(self, context: CompletionContext) -> List[CompletionItem]:
- arguments = []
- name = context.match.group("name")
- domain = context.match.group("domain") or ""
-
- for feature in self._features.values():
- arguments += feature.complete_arguments(context, domain, name) or []
-
- return arguments
-
- def complete_directives(self, context: CompletionContext) -> List[CompletionItem]:
- self.logger.debug("Completing directives")
-
- items = []
- for name, directive in self.suggest_directives(context):
- item = render_directive_completion(context, name, directive)
- if item is None:
- continue
-
- items.append(item)
-
- return items
-
- def completion_resolve_directive(self, item: CompletionItem) -> CompletionItem:
- # We need the detail field set to the implementation's fully qualified name.
- if not item.detail:
- return item
-
- documentation = self.get_documentation(item.label, item.detail)
- if not documentation:
- return item
-
- description = documentation.get("description", "")
- is_markdown = documentation.get("is_markdown", False)
- kind = MarkupKind.Markdown if is_markdown else MarkupKind.PlainText
-
- item.documentation = MarkupContent(kind=kind, value=description)
- return item
-
- def complete_options(self, context: CompletionContext) -> List[CompletionItem]:
- surrounding_directive = self._get_surrounding_directive(context)
- if not surrounding_directive:
- return []
-
- name = surrounding_directive.group("name")
- domain = surrounding_directive.group("domain")
- impl = self.get_implementation(name, domain)
- if impl is None:
- return []
-
- items = []
-
- for option in self.suggest_options(context, name, domain):
- item = render_directive_option_completion(context, option, name, impl)
- if item is None:
- continue
-
- items.append(item)
-
- return items
-
- def completion_resolve_option(self, item: CompletionItem) -> CompletionItem:
- # We need the detail field set to the implementation's fully qualified name.
- if not item.detail or not item.data:
- return item
-
- directive, option = item.detail.split(":")
- name = typing.cast(Dict, item.data).get("for_directive", "")
-
- documentation = self.get_documentation(name, directive)
- if not documentation:
- return item
-
- description = documentation.get("options", {}).get(option, None)
- if not description:
- return item
-
- source = documentation.get("source", "")
- license = documentation.get("license", "")
-
- if source:
- description += f"\n\n[Source]({source})"
-
- if license:
- description += f"\n\n[License]({license})"
-
- kind = MarkupKind.PlainText
- if documentation.get("is_markdown", False):
- kind = MarkupKind.Markdown
-
- item.documentation = MarkupContent(kind=kind, value=description)
- return item
-
- def definition(self, context: DefinitionContext) -> List[Location]:
- directive = context.match.group("name")
- domain = context.match.group("domain")
- argument = context.match.group("argument")
-
- if not argument:
- return []
-
- start = context.match.group(0).index(argument)
- end = start + len(argument)
-
- if start <= context.position.character <= end:
- return self.find_argument_definition(context, directive, domain, argument)
-
- return []
-
- def find_argument_definition(
- self,
- context: DefinitionContext,
- directive: str,
- domain: Optional[str],
- argument: str,
- ) -> List[Location]:
- definitions = []
-
- for feature_name, feature in self._features.items():
- try:
- definitions += (
- feature.find_argument_definitions(
- context, directive, domain, argument
- )
- or []
- )
- except Exception:
- self.logger.error(
- "Unable to find definitions of '%s' for directive '%s', "
- "error in feature: '%s'",
- argument,
- f"{domain}:{directive}" if domain else directive,
- feature_name,
- exc_info=True,
- )
-
- return definitions
-
- def resolve_argument_link(
- self, context: DocumentLinkContext, name: str, domain: str, argument: str
- ) -> Tuple[Optional[str], Optional[str]]:
- for feature_name, feature in self._features.items():
- try:
- target, tooltip = feature.resolve_argument_link(
- context, name, domain, argument
- )
-
- if target:
- return target, tooltip
- except Exception:
- self.logger.error(
- "Unable to resolve argument link '%s' for directive '%s', "
- "error in feature: '%s'",
- argument,
- f"{domain}:{name}" if domain else name,
- feature_name,
- exc_info=True,
- )
-
- return None, None
-
- def document_link(self, context: DocumentLinkContext) -> List[DocumentLink]:
- links = []
-
- for line, text in enumerate(context.doc.lines):
- for match in DIRECTIVE.finditer(text):
- argument = match.group("argument")
- if not argument:
- continue
-
- domain = match.group("domain")
- name = match.group("name")
-
- target, tooltip = self.resolve_argument_link(
- context, name, domain, argument
- )
- if not target:
- continue
-
- idx = match.group(0).index(argument)
- start = match.start() + idx
- end = start + len(argument)
-
- links.append(
- DocumentLink(
- target=target,
- tooltip=tooltip if context.tooltip_support else None,
- range=Range(
- start=Position(line=line, character=start),
- end=Position(line=line, character=end),
- ),
- )
- )
-
- return links
-
- def hover(self, context: HoverContext) -> str:
- if context.location not in {"rst", "docstring"}:
- return ""
-
- name = context.match.group("name")
- domain = context.match.group("domain")
-
- # Determine if the hover is on the .. directive:: itself, or within the argument
- # Be sure to include enough chars for the length of '::'!
- idx = context.position.character - context.match.start()
- prefix = context.match.group(0)[:idx]
-
- if "::" not in prefix:
- return self.hover_directive(context, name, domain)
-
- # TODO: Add extension points for directive arguments and options.
- return ""
-
- def hover_directive(
- self, context: HoverContext, name: str, domain: Optional[str]
- ) -> str:
- label = f"{domain}:{name}" if domain else name
- self.logger.debug("Calculating hover for directive '%s'", label)
-
- directive = self.get_implementation(name, domain)
- if not directive:
- return ""
-
- try:
- dotted_name = f"{directive.__module__}.{directive.__name__}"
- except AttributeError:
- dotted_name = f"{directive.__module__}.{directive.__class__.__name__}"
-
- documentation = self.get_documentation(label, dotted_name)
- if not documentation:
- return ""
-
- return documentation.get("description", "")
-
- def implementation(self, context: ImplementationContext) -> List[Location]:
- region = context.match.group("directive")
- name = context.match.group("name")
- domain = context.match.group("domain")
-
- start = context.match.group(0).index(region)
- end = start + len(region)
-
- if start <= context.position.character <= end:
- return self.find_directive_implementation(context, name, domain)
-
- return []
-
- def find_directive_implementation(
- self, context: ImplementationContext, name: str, domain: Optional[str]
- ) -> List[Location]:
- impl = self.get_implementation(name, domain)
- if impl is None:
- return []
-
- self.logger.debug(
- "Getting implementation of '%s' (%s)",
- f"{domain}:{name}" if domain else name,
- impl,
- )
- location = get_object_location(impl, self.logger)
- if location is None:
- return []
-
- return [location]
-
- def _get_surrounding_directive(
- self, context: CompletionContext
- ) -> Optional["re.Match"]:
- """Used to determine which directive we should be offering completions for.
-
- When suggestions should be generated this returns an :class:`python:re.Match`
- object representing the directive the options are associated with. In the
- case where suggestions should not be generated this will return ``None``
-
- Parameters
- ----------
- context:
- The completion context
- """
-
- match = context.match
- groups = match.groupdict()
- indent = groups["indent"]
-
- self.logger.debug("Match groups: %s", groups)
-
- # Search backwards so that we can determine the context for our completion
- linum = context.position.line - 1
- line = context.doc.lines[linum]
-
- while linum >= 0 and line.startswith(indent):
- linum -= 1
- line = context.doc.lines[linum]
-
- # Only offer completions if we're within a directive's option block
- directive = DIRECTIVE.match(line)
- self.logger.debug("Context line: %s", line)
- self.logger.debug("Context match: %s", directive)
-
- if not directive:
- return None
-
- # Now that we know we're in a directive's option block, is the completion
- # request coming from a valid position on the line?
- option = groups["option"]
- start = match.span()[0] + match.group(0).find(option)
- end = start + len(option) + 1
-
- if start <= context.position.character <= end:
- return directive
-
- return None
-
- def get_documentation(
- self, label: str, implementation: str
- ) -> Optional[Dict[str, Any]]:
- """Return the documentation for the given directive, if available.
-
- If documentation for the given ``label`` cannot be found, this function will also
- look for the label under the project's :confval:`sphinx:primary_domain` followed
- by the ``std`` domain.
-
- Parameters
- ----------
- label
- The name of the directive, as the user would type in an reStructuredText file.
-
- implementation
- The full dotted name of the directive's implementation.
- """
-
- key = f"{label}({implementation})"
- documentation = self._documentation.get(key, None)
- if documentation:
- return documentation
-
- if not isinstance(self.rst, SphinxLanguageServer) or not self.rst.app:
- return None
-
- # Nothing found, try the primary domain
- domain = self.rst.app.config.primary_domain
- key = f"{domain}:{label}({implementation})"
-
- documentation = self._documentation.get(key, None)
- if documentation:
- return documentation
-
- # Still nothing, try the standard domain
- key = f"std:{label}({implementation})"
-
- documentation = self._documentation.get(key, None)
- if documentation:
- return documentation
-
- return None
-
-
-def esbonio_setup(rst: RstLanguageServer):
- rst.add_feature(Directives(rst))
diff --git a/lib/esbonio/esbonio/lsp/directives/completions.py b/lib/esbonio/esbonio/lsp/directives/completions.py
deleted file mode 100644
index 54b4543fe..000000000
--- a/lib/esbonio/esbonio/lsp/directives/completions.py
+++ /dev/null
@@ -1,353 +0,0 @@
-import re
-from typing import Optional
-from typing import Type
-
-from docutils.parsers.rst import Directive
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import CompletionItemKind
-from lsprotocol.types import InsertTextFormat
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-from lsprotocol.types import TextEdit
-
-from esbonio.lsp import CompletionContext
-
-__all__ = ["render_directive_completion", "render_directive_option_completion"]
-
-
-WORD = re.compile("[a-zA-Z]+")
-
-
-def render_directive_completion(
- context: CompletionContext,
- name: str,
- directive: Type[Directive],
-) -> Optional[CompletionItem]:
- """Render the given directive as a ``CompletionItem`` according to the current
- context.
-
- Parameters
- ----------
- context
- The context in which the completion should be rendered.
-
- name
- The name of the directive, as it appears in an rst file.
-
- directive
- The class that implements the directive.
-
- Returns
- -------
- Optional[CompletionItem]
- The final completion item or ``None``.
- If ``None`` is returned, then the given completion should be skipped.
- """
-
- if context.config.preferred_insert_behavior == "insert":
- return _render_directive_with_insert_text(context, name, directive)
-
- return _render_directive_with_text_edit(context, name, directive)
-
-
-def render_directive_option_completion(
- context: CompletionContext,
- name: str,
- directive: str,
- implementation: Type[Directive],
-) -> Optional[CompletionItem]:
- """Render the given directive option as a ``CompletionItem`` according to the
- current context.
-
- Parameters
- ----------
- context
- The context in which the completion should be rendered.
-
- name
- The name of the option, as it appears in an rst file.
-
- directive
- The name of the directive, as it appears in an rst file.
-
- implementation
- The class implementing the directive.
-
- Returns
- -------
- Optional[CompletionItem]
- The final completion item or ``None``.
- If ``None`` is returned, the given completion should be skipped.
- """
-
- if context.config.preferred_insert_behavior == "insert":
- return _render_directive_option_with_insert_text(
- context, name, directive, implementation
- )
-
- return _render_directive_option_with_text_edit(
- context, name, directive, implementation
- )
-
-
-def _render_directive_with_insert_text(
- context: CompletionContext,
- name: str,
- directive: Type[Directive],
-) -> Optional[CompletionItem]:
- """Render a ``CompletionItem`` using ``insertText`` fields.
-
- This implements the ``insert`` behavior for directives.
- Parameters
- ----------
- context
- The context in which the completion is being generated.
-
- name
- The name of the directive, as it appears in an rst file.
-
- directive
- The class implementing the directive.
-
- """
- insert_text = f".. {name}::"
- user_text = context.match.group(0).strip()
-
- # Since we can't replace any existing text, it only makes sense
- # to offer completions that ailgn with what the user has already written.
- if not insert_text.startswith(user_text):
- return None
-
- # Except that's not entirely true... to quote the LSP spec. (emphasis added)
- #
- # > in the model the client should filter against what the user has already typed
- # > **using the word boundary rules of the language** (e.g. resolving the word
- # > under the cursor position). The reason for this mode is that it makes it
- # > extremely easy for a server to implement a basic completion list and get it
- # > filtered on the client.
- #
- # So in other words... if the cursor is inside a word, that entire word will be
- # replaced with what we have in `insert_text` so we need to be able to do something
- # like
- # .. -> image::
- # .. im -> image::
- #
- # .. -> code-block::
- # .. cod -> code-block::
- # .. code-bl -> block::
- #
- # .. -> c:function::
- # .. c -> c:function::
- # .. c: -> function::
- # .. c:fun -> function::
- #
- # And since the client is free to interpret this how it likes, it's unlikely we'll
- # be able to get this right in all cases for all clients. So for now this is going
- # to target Kate's interpretation since it currently does not support ``text_edit``
- # and it was the editor that prompted this to be implemented in the first place.
- #
- # See: https://github.com/swyddfa/esbonio/issues/471
-
- # If the existing text ends with a delimiter, then we should simply remove the
- # entire prefix
- if user_text.endswith((":", "-", " ")):
- start_index = len(user_text)
-
- # Look for groups of word chars, replace text until the start of the final group
- else:
- start_indices = [m.start() for m in WORD.finditer(user_text)] or [
- len(user_text)
- ]
- start_index = max(start_indices)
-
- item = _render_directive_common(name, directive)
- item.insert_text = insert_text[start_index:]
- return item
-
-
-def _render_directive_with_text_edit(
- context: CompletionContext,
- name: str,
- directive: Type[Directive],
-) -> Optional[CompletionItem]:
- """Render a directive's ``CompletionItem`` using the ``textEdit`` field.
-
- This implements the ``replace`` insert behavior for directives.
-
- Parameters
- ----------
- context
- The context in which the completion is being generated.
-
- name
- The name of the directive, as it appears in an rst file.
-
- directive
- The class implementing the directive.
-
- """
- match = context.match
-
- # Calculate the range of text the CompletionItems should edit.
- # If there is an existing argument to the directive, we should leave it untouched
- # otherwise, edit the whole line to insert any required arguments.
- start = match.span()[0] + match.group(0).find(".")
- include_argument = context.snippet_support
- end = match.span()[1]
-
- if match.group("argument"):
- include_argument = False
- end = match.span()[0] + match.group(0).find("::") + 2
-
- range_ = Range(
- start=Position(line=context.position.line, character=start),
- end=Position(line=context.position.line, character=end),
- )
-
- # 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, nargs + 1))
- else:
- args = ""
- insert_format = InsertTextFormat.PlainText
-
- insert_text = f".. {name}::{args}"
-
- item = _render_directive_common(name, directive)
- item.filter_text = insert_text
- item.text_edit = TextEdit(range=range_, new_text=insert_text)
- item.insert_text_format = insert_format
-
- return item
-
-
-def _render_directive_common(
- name: str,
- directive: Type[Directive],
-) -> CompletionItem:
- """Render the common fields of a directive's completion item."""
-
- try:
- dotted_name = f"{directive.__module__}.{directive.__name__}"
- except AttributeError:
- dotted_name = f"{directive.__module__}.{directive.__class__.__name__}"
-
- return CompletionItem(
- label=name,
- detail=dotted_name,
- kind=CompletionItemKind.Class,
- data={"completion_type": "directive"},
- )
-
-
-def _render_directive_option_with_insert_text(
- context: CompletionContext,
- name: str,
- directive: str,
- implementation: Type[Directive],
-) -> Optional[CompletionItem]:
- """Render a directive option's ``CompletionItem`` using the ``insertText`` field.
-
- This implements the ``insert`` insert behavior for directive options.
-
- Parameters
- ----------
- context
- The context in which the completion is being generated.
-
- name
- The name of the directive option, as it appears in an rst file.
-
- directive
- The name of the directive, as it appears in an rst file.
-
- implementation
- The class implementing the directive.
-
- """
-
- insert_text = f":{name}:"
- user_text = context.match.group(0).strip()
-
- if not insert_text.startswith(user_text):
- return None
-
- if user_text.endswith((":", "-", " ")):
- start_index = len(user_text)
-
- else:
- start_indices = [m.start() for m in WORD.finditer(user_text)] or [
- len(user_text)
- ]
- start_index = max(start_indices)
-
- item = _render_directive_option_common(name, directive, implementation)
- item.insert_text = insert_text[start_index:]
- return item
-
-
-def _render_directive_option_with_text_edit(
- context: CompletionContext,
- name: str,
- directive: str,
- implementation: Type[Directive],
-) -> CompletionItem:
- """Render a directive option's ``CompletionItem`` using the``textEdit`` field.
-
- This implements the ``replace`` insert behavior for directive options.
-
- Parameters
- ----------
- context
- The context in which the completion is being generated.
-
- name
- The name of the directive option, as it appears in an rst file.
-
- directive
- The name of the directive, as it appears in an rst file.
-
- implementation
- The class implementing the directive.
-
- """
-
- match = context.match
- groups = match.groupdict()
-
- option = groups["option"]
- start = match.span()[0] + match.group(0).find(option)
- end = start + len(option)
-
- range_ = Range(
- start=Position(line=context.position.line, character=start),
- end=Position(line=context.position.line, character=end),
- )
-
- insert_text = f":{name}:"
-
- item = _render_directive_option_common(name, directive, implementation)
- item.filter_text = insert_text
- item.text_edit = TextEdit(range=range_, new_text=insert_text)
-
- return item
-
-
-def _render_directive_option_common(
- name: str, directive: str, impl: Type[Directive]
-) -> CompletionItem:
- """Render the common fields of a directive option's completion item."""
-
- try:
- impl_name = f"{impl.__module__}.{impl.__name__}"
- except AttributeError:
- impl_name = f"{impl.__module__}.{impl.__class__.__name__}"
-
- return CompletionItem(
- label=name,
- detail=f"{impl_name}:{name}",
- kind=CompletionItemKind.Field,
- data={"completion_type": "directive_option", "for_directive": directive},
- )
diff --git a/lib/esbonio/esbonio/lsp/log.py b/lib/esbonio/esbonio/lsp/log.py
deleted file mode 100644
index ef7cad2c8..000000000
--- a/lib/esbonio/esbonio/lsp/log.py
+++ /dev/null
@@ -1,180 +0,0 @@
-import logging
-import pathlib
-import traceback
-import typing
-from typing import List
-from typing import Tuple
-
-import pygls.uris as uri
-from lsprotocol.types import Diagnostic
-from lsprotocol.types import DiagnosticSeverity
-from lsprotocol.types import DiagnosticTag
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-
-if typing.TYPE_CHECKING:
- from .rst import RstLanguageServer
- from .rst.config import ServerConfig
-
-
-LOG_NAMESPACE = "esbonio.lsp"
-LOG_LEVELS = {
- "debug": logging.DEBUG,
- "error": logging.ERROR,
- "info": logging.INFO,
-}
-
-
-class LogFilter(logging.Filter):
- """A log filter that accepts message from any of the listed logger names."""
-
- def __init__(self, names):
- self.names = names
-
- def filter(self, record):
- return any(record.name == name for name in self.names)
-
-
-class MemoryHandler(logging.Handler):
- """A logging handler that caches messages in memory."""
-
- def __init__(self):
- super().__init__()
- self.records: List[logging.LogRecord] = []
-
- def emit(self, record: logging.LogRecord) -> None:
- self.records.append(record)
-
-
-class LspHandler(logging.Handler):
- """A logging handler that will send log records to an LSP client."""
-
- def __init__(
- self, server: "RstLanguageServer", show_deprecation_warnings: bool = False
- ):
- super().__init__()
- self.server = server
- self.show_deprecation_warnings = show_deprecation_warnings
-
- def get_warning_path(self, warning: str) -> Tuple[str, List[str]]:
- """Determine the filepath that the warning was emitted from."""
-
- path, *parts = warning.split(":")
-
- # On windows the rest of the path will be in the first element of parts.
- if pathlib.Path(warning).drive:
- path += f":{parts.pop(0)}"
-
- return path, parts
-
- def handle_warning(self, record: logging.LogRecord):
- """Publish warnings to the client as diagnostics."""
-
- if not isinstance(record.args, tuple):
- self.server.logger.debug(
- "Unable to handle warning, expected tuple got: %s", record.args
- )
- return
-
- # The way warnings are logged is different in Python 3.11+
- if len(record.args) == 0:
- argument = record.msg
- else:
- argument = record.args[0] # type: ignore
-
- if not isinstance(argument, str):
- self.server.logger.debug(
- "Unable to handle warning, expected string got: %s", argument
- )
- return
-
- warning, *_ = argument.split("\n")
- path, (linenum, category, *msg) = self.get_warning_path(warning)
-
- category = category.strip()
- message = ":".join(msg).strip()
-
- try:
- line = int(linenum)
- except ValueError:
- line = 1
- self.server.logger.debug(
- "Unable to parse line number: '%s'\n%s", linenum, traceback.format_exc()
- )
-
- tags = []
- if category == "DeprecationWarning":
- tags.append(DiagnosticTag.Deprecated)
-
- diagnostic = Diagnostic(
- range=Range(
- start=Position(line=line - 1, character=0),
- end=Position(line=line, character=0),
- ),
- message=message,
- severity=DiagnosticSeverity.Warning,
- tags=tags,
- )
-
- self.server.add_diagnostics("esbonio", uri.from_fs_path(path), diagnostic)
- self.server.sync_diagnostics()
-
- def emit(self, record: logging.LogRecord) -> None:
- """Sends the record to the client."""
-
- # To avoid infinite recursions, it's simpler to just ignore all log records
- # coming from pygls...
- if "pygls" in record.name:
- return
-
- if record.name == "py.warnings":
- if not self.show_deprecation_warnings:
- return
-
- self.handle_warning(record)
-
- log = self.format(record).strip()
- self.server.show_message_log(log)
-
-
-def setup_logging(server: "RstLanguageServer", config: "ServerConfig"):
- """Setup logging to route log messages to the language client as
- ``window/logMessage`` messages.
-
- Parameters
- ----------
- server
- The server to use to send messages
-
- config
- The configuration to use
- """
-
- level = LOG_LEVELS[config.log_level]
-
- warnlog = logging.getLogger("py.warnings")
- logger = logging.getLogger(LOG_NAMESPACE)
- logger.setLevel(level)
-
- lsp_handler = LspHandler(server, config.show_deprecation_warnings)
- lsp_handler.setLevel(level)
-
- if len(config.log_filter) > 0:
- lsp_handler.addFilter(LogFilter(config.log_filter))
-
- formatter = logging.Formatter("[%(name)s] %(message)s")
- lsp_handler.setFormatter(formatter)
-
- # Look to see if there are any cached messages we should forward to the client.
- for handler in logger.handlers:
- if not isinstance(handler, MemoryHandler):
- continue
-
- for record in handler.records:
- if logger.isEnabledFor(record.levelno):
- lsp_handler.emit(record)
-
- logger.removeHandler(handler)
-
- logger.addHandler(lsp_handler)
- warnlog.addHandler(lsp_handler)
diff --git a/lib/esbonio/esbonio/lsp/py.typed b/lib/esbonio/esbonio/lsp/py.typed
deleted file mode 100644
index 8280d08cd..000000000
--- a/lib/esbonio/esbonio/lsp/py.typed
+++ /dev/null
@@ -1 +0,0 @@
-# esbonio.lsp: marker file for PEP 561
diff --git a/lib/esbonio/esbonio/lsp/roles/__init__.py b/lib/esbonio/esbonio/lsp/roles/__init__.py
deleted file mode 100644
index 6efd05033..000000000
--- a/lib/esbonio/esbonio/lsp/roles/__init__.py
+++ /dev/null
@@ -1,867 +0,0 @@
-"""Role support."""
-import typing
-import warnings
-from typing import Any
-from typing import Dict
-from typing import Iterable
-from typing import List
-from typing import Optional
-from typing import Protocol
-from typing import Tuple
-
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import DocumentLink
-from lsprotocol.types import Location
-from lsprotocol.types import MarkupContent
-from lsprotocol.types import MarkupKind
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-from lsprotocol.types import TextEdit
-
-from esbonio.lsp.rst import CompletionContext
-from esbonio.lsp.rst import DefinitionContext
-from esbonio.lsp.rst import DocumentLinkContext
-from esbonio.lsp.rst import HoverContext
-from esbonio.lsp.rst import ImplementationContext
-from esbonio.lsp.rst import LanguageFeature
-from esbonio.lsp.rst import RstLanguageServer
-from esbonio.lsp.sphinx import SphinxLanguageServer
-from esbonio.lsp.util.inspect import get_object_location
-from esbonio.lsp.util.patterns import DEFAULT_ROLE
-from esbonio.lsp.util.patterns import DIRECTIVE
-from esbonio.lsp.util.patterns import ROLE
-
-from .completions import render_role_completion
-
-
-class RoleLanguageFeature:
- """Base class for role language features."""
-
- def complete_targets(
- self, context: CompletionContext, name: str, domain: str
- ) -> List[CompletionItem]:
- """Return a list of completion items representing valid targets for the given
- role.
-
- Parameters
- ----------
- context
- The completion context
-
- name
- The name of the role to generate completion suggestions for.
-
- domain
- The name of the domain the role is a member of
- """
- return []
-
- def find_target_definitions(
- self, context: DefinitionContext, name: str, domain: str, label: str
- ) -> List[Location]:
- """Return a list of locations representing the definition of the given role
- target.
-
- Parameters
- ----------
- doc:
- The document containing the match
- match:
- The match object that triggered the definition request
- name:
- The name of the role
- domain:
- The domain the role is part of, if applicable.
- """
- return []
-
- def get_implementation(self, role: str, domain: str) -> Optional[Any]:
- """Return the implementation for the given role name.
-
- Parameters
- ----------
- role
- The name of the role
-
- domain
- The domain the role belongs to, if any
- """
- return self.index_roles().get(role, None)
-
- def index_roles(self) -> Dict[str, Any]:
- """Return all known roles."""
- return dict()
-
- def resolve_target_link(
- self, context: DocumentLinkContext, name: str, domain: Optional[str], label: str
- ) -> Tuple[Optional[str], Optional[str]]:
- """Return a link corresponding to the given target.
-
- Parameters
- ----------
- context
- The document link context
-
- domain
- The name (if applicable) of the domain the role is a member of
-
- name
- The name of the role to generate completion suggestions for.
-
- label
- The label of the target to provide the link for
- """
- return None, None
-
- def suggest_roles(self, context: CompletionContext) -> Iterable[Tuple[str, Any]]:
- """Suggest roles that may be used, given a completion context."""
- return self.index_roles().items()
-
-
-class TargetDefinition(Protocol):
- """A definition provider for role targets.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``, use a subclass of
- :class:`~esbonio.lsp.roles.RoleLanguageFeature` instead.
- """
-
- def find_definitions(
- self, context: DefinitionContext, name: str, domain: Optional[str]
- ) -> List[Location]:
- """Return a list of locations representing the definition of the given role
- target.
-
- Parameters
- ----------
- doc:
- The document containing the match
- match:
- The match object that triggered the definition request
- name:
- The name of the role
- domain:
- The domain the role is part of, if applicable.
- """
-
-
-class TargetCompletion(Protocol):
- """A completion provider for role targets.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``, use a subclass of
- :class:`~esbonio.lsp.roles.RoleLanguageFeature` instead.
- """
-
- def complete_targets(
- self, context: CompletionContext, name: str, domain: Optional[str]
- ) -> List[CompletionItem]:
- """Return a list of completion items representing valid targets for the given
- role.
-
- Parameters
- ----------
- context:
- The completion context
- domain:
- The name of the domain the role is a member of
- name:
- The name of the role to generate completion suggestions for.
- """
-
-
-class TargetLink(Protocol):
- """A document link provider for role targets.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``, use a subclass of
- :class:`~esbonio.lsp.roles.RoleLanguageFeature` instead.
- """
-
- def resolve_link(
- self, context: DocumentLinkContext, name: str, domain: Optional[str], label: str
- ) -> Tuple[Optional[str], Optional[str]]:
- """Return a link corresponding to the given target.
-
- Parameters
- ----------
- context
- The document link context
-
- domain
- The name (if applicable) of the domain the role is a member of
-
- name
- The name of the role to generate completion suggestions for.
-
- label
- The label of the target to provide the link for
- """
-
-
-class Roles(LanguageFeature):
- """Role support for the language server."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self._documentation: Dict[str, Dict[str, str]] = {}
- """Cache for documentation."""
-
- self._features: Dict[str, RoleLanguageFeature] = {}
- """Collection of registered features"""
-
- def add_feature(self, feature: RoleLanguageFeature):
- """Register a role language feature
-
- Parameters
- ----------
- feature
- The role language feature
- """
- key = f"{feature.__module__}.{feature.__class__.__name__}"
-
- # Create a unique key for this instance.
- if key in self._features:
- key += f".{len([k for k in self._features.keys() if k.startswith(key)])}"
-
- self._features[key] = feature
-
- def add_target_definition_provider(self, provider: TargetDefinition) -> None:
- """Register a :class:`~esbonio.lsp.roles.TargetDefinition` provider.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0`` use
- :meth:`~esbonio.lsp.roles.Roles.add_feature` with a
- :class:`~esbonio.lsp.roles.RoleLanguageFeature` subclass instead.
-
- Parameters
- ----------
- provider
- The provider to register
- """
-
- warnings.warn(
- "TargetDefinition providers are deprecated in favour of "
- "RoleLanguageFeatures, this method will be removed in v1.0",
- DeprecationWarning,
- stacklevel=2,
- )
-
- name = provider.__class__.__name__
- key = f"{provider.__module__}.{name}.definition"
-
- def find_target_definitions(self, context, name, domain, label):
- return provider.find_definitions(context, name, domain)
-
- feature = type(
- f"{name}TargetDefinitionProvider",
- (RoleLanguageFeature,),
- {"find_target_definitions": find_target_definitions},
- )()
-
- self._features[key] = feature
-
- def add_target_link_provider(self, provider: TargetLink) -> None:
- """Register a :class:`~esbonio.lsp.roles.TargetLink` provider.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0`` use
- :meth:`~esbonio.lsp.roles.Roles.add_feature` with a
- :class:`~esbonio.lsp.roles.RoleLanguageFeature` subclass instead.
-
- Parameters
- ----------
- provider
- The provider to register
- """
-
- warnings.warn(
- "TargetLink providers are deprecated in favour of "
- "RoleLanguageFeatures, this method will be removed in v1.0",
- DeprecationWarning,
- stacklevel=2,
- )
-
- name = provider.__class__.__name__
- key = f"{provider.__module__}.{name}.link"
-
- feature = type(
- f"{name}TargetLinkProvider",
- (RoleLanguageFeature,),
- {"resolve_target_link": provider.resolve_link},
- )()
-
- self._features[key] = feature
-
- def add_target_completion_provider(self, provider: TargetCompletion) -> None:
- """Register a :class:`~esbonio.lsp.roles.TargetCompletion` provider.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0`` use
- :meth:`~esbonio.lsp.roles.Roles.add_feature` with a
- :class:`~esbonio.lsp.roles.RoleLanguageFeature` subclass instead.
-
- Parameters
- ----------
- provider
- The provider to register
- """
-
- warnings.warn(
- "TargetCompletion providers are deprecated in favour of "
- "RoleLanguageFeatures, this method will be removed in v1.0",
- DeprecationWarning,
- stacklevel=2,
- )
-
- name = provider.__class__.__name__
- key = f"{provider.__module__}.{name}.completion"
-
- feature = type(
- f"{name}TargetCompletionProvider",
- (RoleLanguageFeature,),
- {"complete_targets": provider.complete_targets},
- )()
-
- self._features[key] = feature
-
- def add_documentation(self, documentation: Dict[str, Dict[str, Any]]) -> None:
- """Register role documentation.
-
- ``documentation`` should be a dictionary of the form ::
-
- documentation = {
- "raw(docutils.parsers.rst.roles.raw_role)": {
- "is_markdown": true,
- "license": "https://...",
- "source": "https://...",
- "description": [
- "# :raw:",
- "The raw role is used for...",
- ...
- ]
- }
- }
-
- where the key is of the form `name(dotted_name)`. There are cases where a role's
- implementation is not sufficient to uniquely identify it as multiple roles can
- be provided by a single class.
-
- This means the key has to be a combination of the ``name`` the user writes in
- an reStructuredText document and ``dotted_name`` is the fully qualified name of
- the role's implementation.
-
- .. note::
-
- If there is a clash with an existing key, the existing value will be
- overwritten with the new value.
-
- The values in this dictionary are themselves dictionaries with the following
- fields.
-
- ``description``
- A list of strings for the role's usage.
-
- ``is_markdown``
- A boolean flag used to indicate whether the ``description`` is written in
- plain text or markdown.
-
- ``source``
- The url to the documentation's source.
-
- ``license``
- The url to the documentation's license.
-
- Parameters
- ----------
- documentation:
- The documentation to register.
- """
-
- for key, doc in documentation.items():
- description = doc.get("description", [])
- if not description:
- continue
-
- source = doc.get("source", "")
- if source:
- description.append(f"\n[Source]({source})")
-
- license = doc.get("license", "")
- if license:
- description.append(f"\n[License]({license})")
-
- doc["description"] = "\n".join(description)
- self._documentation[key] = doc
-
- completion_triggers = [ROLE, DEFAULT_ROLE]
- definition_triggers = [ROLE]
- hover_triggers = [ROLE]
- implementation_triggers = [ROLE]
-
- def definition(self, context: DefinitionContext) -> List[Location]:
- domain = context.match.group("domain") or ""
- name = context.match.group("name")
- label = context.match.group("label")
-
- # Be sure to only match complete roles
- if not label or not context.match.group(0).endswith("`"):
- return []
-
- return self.find_target_definitions(context, name, domain, label)
-
- def find_target_definitions(
- self, context: DefinitionContext, name: str, domain: str, label: str
- ) -> List[Location]:
- definitions = []
-
- for feature_name, feature in self._features.items():
- try:
- definitions += feature.find_target_definitions(
- context, name, domain, label
- )
- except Exception:
- self.logger.error(
- "Unable to find definitions of '%s' for role ':%s:', "
- "error in feature: '%s'",
- label,
- f"{domain}:{name}" if domain else name,
- feature_name,
- exc_info=True,
- )
-
- return definitions
-
- def document_link(self, context: DocumentLinkContext) -> List[DocumentLink]:
- links = []
-
- for line, text in enumerate(context.doc.lines):
- for match in ROLE.finditer(text):
- label = match.group("label")
-
- # Be sure to only match complete roles
- if not label or not match.group(0).endswith("`"):
- continue
-
- domain = match.group("domain")
- name = match.group("name")
-
- target, tooltip = self.resolve_target_link(context, name, domain, label)
- if not target:
- continue
-
- idx = match.group(0).index(label)
- start = match.start() + idx
- end = start + len(label)
-
- link = DocumentLink(
- target=target,
- tooltip=tooltip if context.tooltip_support else None,
- range=Range(
- start=Position(line=line, character=start),
- end=Position(line=line, character=end),
- ),
- )
-
- links.append(link)
-
- return links
-
- def resolve_target_link(
- self, context: DocumentLinkContext, name: str, domain: str, label: str
- ) -> Tuple[Optional[str], Optional[str]]:
- """Resolve a given document link."""
-
- for feature_name, feature in self._features.items():
- try:
- target, tooltip = feature.resolve_target_link(
- context, name, domain, label
- )
-
- if target:
- return target, tooltip
- except Exception:
- self.logger.error(
- "Unable to resolve target link '%s' for role ':%s:', "
- "error in feature: '%s'",
- label,
- f"{domain}:{name}" if domain else name,
- feature_name,
- exc_info=True,
- )
-
- return None, None
-
- def complete(self, context: CompletionContext) -> List[CompletionItem]:
- """Generate completion suggestions relevant to the current context.
-
- This function is a little intense, but its sole purpose is to determine the
- context in which the completion request is being made and either return
- nothing, or the results of :meth:`~esbonio.lsp.roles.Roles.complete_roles` or
- :meth:`esbonio.lsp.roles.Roles.complete_targets` whichever is appropriate.
-
- Parameters
- ----------
- context:
- The context of the completion request.
- """
-
- # Do not suggest completions within the middle of Python code.
- if context.location == "py":
- return []
-
- groups = context.match.groupdict()
- target = groups["target"]
-
- # All text matched by the regex
- text = context.match.group(0)
- start, end = context.match.span()
-
- if target:
- target_index = start + text.find(target)
-
- # Only trigger target completions if the request was made from within
- # the target part of the role.
- if target_index <= context.position.character <= end:
- return self.complete_targets(context)
-
- # If there's no indent, then this can only be a role definition
- indent = context.match.group(1)
- if indent == "":
- return self.complete_roles(context)
-
- # Otherwise, search backwards until we find a blank line or an unindent
- # so that we can determine the appropriate context.
- linum = context.position.line - 1
-
- try:
- line = context.doc.lines[linum]
- except IndexError:
- return self.complete_roles(context)
-
- while linum >= 0 and line.startswith(indent):
- linum -= 1
- line = context.doc.lines[linum]
-
- # Unless we are within a directive's options block, we should offer role
- # suggestions
- if DIRECTIVE.match(line):
- return []
-
- return self.complete_roles(context)
-
- def completion_resolve(self, item: CompletionItem) -> CompletionItem:
- # We need extra info to know who to call
- if not item.data:
- return item
-
- data = typing.cast(Dict, item.data)
- ctype = data.get("completion_type", "")
-
- if ctype == "role":
- return self.completion_resolve_role(item)
-
- return item
-
- def suggest_roles(self, context: CompletionContext) -> Iterable[Tuple[str, Any]]:
- """Suggest roles that may be used, given a completion context.
-
- Parameters
- ----------
- context
- The completion context
- """
- for name, feature in self._features.items():
- try:
- yield from feature.suggest_roles(context)
- except Exception:
- self.logger.error(
- "Unable to suggest roles, error in feature: '%s'",
- name,
- exc_info=True,
- )
-
- def complete_roles(self, context: CompletionContext) -> List[CompletionItem]:
- items = []
-
- for name, role in self.suggest_roles(context):
- item = render_role_completion(context, name, role)
- if item is None:
- continue
-
- items.append(item)
-
- return items
-
- def completion_resolve_role(self, item: CompletionItem) -> CompletionItem:
- # We need the detail field set to the role implementation's fully qualified name
- if not item.detail:
- return item
-
- documentation = self.get_documentation(item.label, item.detail)
- if not documentation:
- return item
-
- description = documentation.get("description", "")
- is_markdown = documentation.get("is_markdown", False)
- kind = MarkupKind.Markdown if is_markdown else MarkupKind.PlainText
-
- item.documentation = MarkupContent(kind=kind, value=description)
- return item
-
- def suggest_targets(
- self, context: CompletionContext, name: str, domain: str
- ) -> List[CompletionItem]:
- targets = []
-
- for feature_name, feature in self._features.items():
- try:
- targets += feature.complete_targets(context, name, domain)
- except Exception:
- self.logger.error(
- "Unable to suggest targets for role ':%s:', error in feature: '%s'",
- f"{domain}:{name}" if domain else name,
- feature_name,
- exc_info=True,
- )
-
- return targets
-
- def complete_targets(self, context: CompletionContext) -> List[CompletionItem]:
- """Generate the list of role target completion suggestions."""
-
- groups = context.match.groupdict()
-
- # Handle the default role case.
- if "role" not in groups:
- domain, name = self.rst.get_default_role()
- if not name:
- return []
- else:
- name = groups["name"]
- domain = groups["domain"]
-
- domain = domain or ""
- name = name or ""
-
- # Only generate suggestions for "aliased" targets if the request comes from
- # within the <> chars.
- if groups["alias"]:
- text = context.match.group(0)
- start = context.match.span()[0] + text.find(groups["alias"])
- end = start + len(groups["alias"])
-
- if start <= context.position.character <= end:
- return []
-
- targets = []
-
- startchar = "<" if "<" in groups["target"] else "`"
- endchars = ">`" if "<" in groups["target"] else "`"
-
- start, end = context.match.span()
- start += context.match.group(0).index(startchar) + 1
- range_ = Range(
- start=Position(line=context.position.line, character=start),
- end=Position(line=context.position.line, character=end),
- )
- prefix = context.match.group(0)[start:]
- modifier = groups["modifier"] or ""
-
- for candidate in self.suggest_targets(context, name, domain):
- # Don't interfere with items that already carry a `text_edit`, allowing
- # some providers (like filepaths) to do something special.
- if not candidate.text_edit:
- new_text = candidate.insert_text or candidate.label
-
- # This is rather annoying, but `filter_text` needs to start with
- # the text we are going to replace, otherwise VSCode won't show our
- # suggestions!
- candidate.filter_text = f"{prefix}{new_text}"
-
- candidate.text_edit = TextEdit(
- range=range_, new_text=f"{modifier}{new_text}"
- )
- candidate.insert_text = None
-
- if not candidate.text_edit.new_text.endswith(endchars):
- candidate.text_edit.new_text += endchars
-
- targets.append(candidate)
-
- return targets
-
- def hover(self, context: HoverContext) -> str:
- if context.location not in {"rst", "docstring"}:
- return ""
-
- name = context.match.group("name")
- domain = context.match.group("domain")
-
- # Determine if the hover is on the :role: itself, or within the `target`.
- idx = context.position.character - context.match.start()
- prefix = context.match.group(0)[:idx]
-
- if "`" in prefix:
- return self.hover_target(context, name, domain)
-
- return self.hover_role(context, name, domain)
-
- def hover_role(self, context: HoverContext, name: str, domain: str) -> str:
- label = f"{domain}:{name}" if domain else name
- role = self.get_implementation(name, domain)
- if not role:
- return ""
-
- try:
- dotted_name = f"{role.__module__}.{role.__name__}"
- except AttributeError:
- dotted_name = f"{role.__module__}.{role.__class__.__name__}"
-
- documentation = self.get_documentation(label, dotted_name)
- if not documentation:
- return ""
-
- return documentation.get("description", "")
-
- def hover_target(
- self, context: HoverContext, name: str, domain: Optional[str]
- ) -> str:
- # TODO: Add extension point for providers to contribute hovers for a target.
- return ""
-
- def get_roles(self) -> Dict[str, Any]:
- """Return a dictionary of all known roles."""
-
- roles = {}
-
- for name, feature in self._features.items():
- self.logger.debug("calling '%s'", name)
- try:
- roles.update(feature.index_roles())
- except Exception:
- self.logger.error(
- "Unable to index roles, error in feature '%s'", name, exc_info=True
- )
-
- return roles
-
- def get_implementation(self, role: str, domain: str) -> Optional[Any]:
- """Return the implementation of a role given its name
-
- Parameters
- ----------
- role
- The name of the role.
-
- domain
- The domain of the role, if applicable.
- """
-
- if domain:
- name = f"{domain}:{role}"
- else:
- name = role
-
- for feature_name, feature in self._features.items():
- try:
- impl = feature.get_implementation(role, domain)
- if impl is not None:
- return impl
- except Exception:
- self.logger.error(
- "Unable to get implementation for ':%s:', error in feature: '%s'\n%s",
- name,
- feature_name,
- exc_info=True,
- )
-
- self.logger.debug("Unable to get implementation for ':%s:', unknown role", name)
- return None
-
- def implementation(self, context: ImplementationContext) -> List[Location]:
- region = context.match.group("role")
- name = context.match.group("name")
- domain = context.match.group("domain")
-
- start = context.match.start() + context.match.group(0).index(region)
- end = start + len(region)
-
- self.logger.debug("%s, %s, %s", region, name, domain)
- self.logger.debug("%s, %s", start, end)
-
- if start <= context.position.character <= end:
- return self.find_role_implementation(context, name, domain)
-
- return []
-
- def find_role_implementation(
- self, context: ImplementationContext, name: str, domain: str
- ) -> List[Location]:
- impl = self.get_implementation(name, domain)
- if impl is None:
- return []
-
- location = get_object_location(impl, self.logger)
- if location is not None:
- return [location]
-
- # Some roles are implemented as instances of some class
- location = get_object_location(impl.__class__, self.logger)
- if location is not None:
- return [location]
-
- return []
-
- def get_documentation(
- self, label: str, implementation: str
- ) -> Optional[Dict[str, Any]]:
- """Return the documentation for the given role, if available.
-
- If documentation for the given ``label`` cannot be found, this function will also
- look for the label under the project's :confval:`sphinx:primary_domain` followed
- by the ``std`` domain.
-
- Parameters
- ----------
- label:
- The name of the role, as the user would type in an reStructuredText file.
- implementation:
- The full dotted name of the role's implementation.
- """
-
- key = f"{label}({implementation})"
- documentation = self._documentation.get(key, None)
- if documentation:
- return documentation
-
- if not isinstance(self.rst, SphinxLanguageServer) or not self.rst.app:
- return None
-
- # Nothing found, try the primary domain
- domain = self.rst.app.config.primary_domain
- key = f"{domain}:{label}({implementation})"
-
- documentation = self._documentation.get(key, None)
- if documentation:
- return documentation
-
- # Still nothing, try the standard domain
- key = f"std:{label}({implementation})"
-
- documentation = self._documentation.get(key, None)
- if documentation:
- return documentation
-
- return None
-
-
-def esbonio_setup(rst: RstLanguageServer):
- rst.add_feature(Roles(rst))
diff --git a/lib/esbonio/esbonio/lsp/roles/completions.py b/lib/esbonio/esbonio/lsp/roles/completions.py
deleted file mode 100644
index 51178aa62..000000000
--- a/lib/esbonio/esbonio/lsp/roles/completions.py
+++ /dev/null
@@ -1,147 +0,0 @@
-import re
-from typing import Any
-from typing import Optional
-
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import CompletionItemKind
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-from lsprotocol.types import TextEdit
-
-from esbonio.lsp import CompletionContext
-
-__all__ = ["render_role_completion"]
-
-
-WORD = re.compile("[a-zA-Z]+")
-
-
-def render_role_completion(
- context: CompletionContext,
- name: str,
- role: Any,
-) -> Optional[CompletionItem]:
- """Render the given role as a ``CompletionItem`` according to the current
- context.
-
- Parameters
- ----------
- context
- The context in which the completion should be rendered.
-
- name
- The name of the role, as it appears in an rst file.
-
- role
- The implementation of the role.
-
- Returns
- -------
- Optional[CompletionItem]
- The final completion item or ``None``.
- If ``None``, then the given completion should be skipped.
- """
-
- if context.config.preferred_insert_behavior == "insert":
- return _render_role_with_insert_text(context, name, role)
-
- return _render_role_with_text_edit(context, name, role)
-
-
-def _render_role_with_insert_text(context, name, role):
- """Render a role's ``CompletionItem`` using the ``insertText`` field.
-
- This implements the ``insert`` insert behavior for roles.
-
- Parameters
- ----------
- context
- The context in which the completion is being generated.
-
- name
- The name of the role, as it appears in an rst file.
-
- role
- The implementation of the role.
- """
-
- insert_text = f":{name}:"
- user_text = context.match.group(0).strip()
-
- if not insert_text.startswith(user_text):
- return None
-
- # If the existing text ends with a delimiter, then we should simply remove the
- # entire prefix
- if user_text.endswith((":", "-", " ")):
- start_index = len(user_text)
-
- # Look for groups of word chars, replace text until the start of the final group
- else:
- start_indices = [m.start() for m in WORD.finditer(user_text)] or [
- len(user_text)
- ]
- start_index = max(start_indices)
-
- item = _render_role_common(name, role)
- item.insert_text = insert_text[start_index:]
- return item
-
-
-def _render_role_with_text_edit(
- context: CompletionContext, name: str, role: Any
-) -> Optional[CompletionItem]:
- """Render a role's ``CompletionItem`` using the ``textEdit`` field.
-
- This implements the ``replace`` insert behavior for roles.
-
- Parameters
- ----------
- context
- The context in which the completion is being generated.
-
- name
- The name of the role, as it appears in an rst file.
-
- role
- The implementation of the role.
- """
- match = context.match
- groups = match.groupdict()
- domain = groups["domain"] or ""
-
- if not name.startswith(domain):
- return None
-
- # Insert text starting from the starting ':' character of the role.
- start = match.span()[0] + match.group(0).find(":")
- end = start + len(groups["role"])
-
- range_ = Range(
- start=Position(line=context.position.line, character=start),
- end=Position(line=context.position.line, character=end),
- )
-
- insert_text = f":{name}:"
-
- item = _render_role_common(name, role)
- item.filter_text = insert_text
- item.text_edit = TextEdit(range=range_, new_text=insert_text)
-
- return item
-
-
-def _render_role_common(name: str, role: Any) -> CompletionItem:
- """Render the common fields of a role's completion item."""
-
- try:
- dotted_name = f"{role.__module__}.{role.__name__}"
- except AttributeError:
- dotted_name = f"{role.__module__}.{role.__class__.__name__}"
-
- return CompletionItem(
- label=name,
- kind=CompletionItemKind.Function,
- detail=f"{dotted_name}",
- data={"completion_type": "role"},
- )
diff --git a/lib/esbonio/esbonio/lsp/rst/__init__.py b/lib/esbonio/esbonio/lsp/rst/__init__.py
deleted file mode 100644
index aa02a288a..000000000
--- a/lib/esbonio/esbonio/lsp/rst/__init__.py
+++ /dev/null
@@ -1,879 +0,0 @@
-import collections
-import inspect
-import logging
-import pathlib
-import re
-import traceback
-import typing
-import warnings
-from typing import Any
-from typing import Callable
-from typing import Dict
-from typing import List
-from typing import Optional
-from typing import Tuple
-from typing import Type
-from typing import TypeVar
-
-import pygls.uris as Uri
-from docutils.parsers.rst import Directive
-from lsprotocol.converters import get_converter
-from lsprotocol.types import ClientCapabilities
-from lsprotocol.types import CodeAction
-from lsprotocol.types import CodeActionParams
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import CompletionItemTag
-from lsprotocol.types import DeleteFilesParams
-from lsprotocol.types import Diagnostic
-from lsprotocol.types import DidSaveTextDocumentParams
-from lsprotocol.types import DocumentLink
-from lsprotocol.types import InitializedParams
-from lsprotocol.types import InitializeParams
-from lsprotocol.types import Location
-from lsprotocol.types import MarkupKind
-from lsprotocol.types import Position
-from pygls import IS_WIN
-from pygls.capabilities import get_capability
-from pygls.server import LanguageServer
-from pygls.workspace import Document
-
-from esbonio.cli import setup_cli
-from esbonio.lsp.log import setup_logging
-
-from .config import InitializationOptions
-from .config import ServerCompletionConfig
-from .io import read_initial_doctree
-
-converter = get_converter()
-LF = TypeVar("LF", bound="LanguageFeature")
-TRIPLE_QUOTE = re.compile("(\"\"\"|''')")
-"""A regular expression matching the triple quotes used to delimit python docstrings."""
-
-# fmt: off
-# Order matters!
-DEFAULT_MODULES = [
- "esbonio.lsp.directives", # Generic directive support
- "esbonio.lsp.roles", # Generic roles support
- "esbonio.lsp.rst.directives", # Specialised support for docutils directives
- "esbonio.lsp.rst.roles", # Specialised support for docutils roles
-]
-"""The modules to load in the default configuration of the server."""
-# fmt: on
-
-
-class CompletionContext:
- """Captures the context within which a completion request has been made."""
-
- def __init__(
- self,
- *,
- doc: Document,
- location: str,
- match: "re.Match",
- position: Position,
- config: ServerCompletionConfig,
- capabilities: ClientCapabilities,
- ):
- self.doc: Document = doc
- """The document within which the completion request was made."""
-
- self.location: str = location
- """The location type where the request was made.
- See :meth:`~esbonio.lsp.rst.RstLanguageServer.get_location_type` for details."""
-
- self.match: "re.Match" = match
- """The match object describing the site of the completion request."""
-
- self.position: Position = position
- """The position at which the completion request was made."""
-
- self.config: ServerCompletionConfig = config
- """User supplied configuration options."""
-
- self._client_capabilities: ClientCapabilities = capabilities
-
- def __repr__(self):
- p = f"{self.position.line}:{self.position.character}"
- return (
- f"CompletionContext<{self.doc.uri}:{p} ({self.location}) -- {self.match}>"
- )
-
- @property
- def commit_characters_support(self) -> bool:
- """Indicates if the client supports commit characters."""
- return get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.commit_characters_support",
- False,
- )
-
- @property
- def deprecated_support(self) -> bool:
- """Indicates if the client supports the deprecated field on a
- ``CompletionItem``."""
- return get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.deprecated_support",
- False,
- )
-
- @property
- def documentation_formats(self) -> List[MarkupKind]:
- """The list of documentation formats supported by the client."""
- return get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.documentation_format",
- [],
- )
-
- @property
- def insert_replace_support(self) -> bool:
- """Indicates if the client supports ``InsertReplaceEdit``."""
- return get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.insert_replace_support",
- False,
- )
-
- @property
- def preselect_support(self) -> bool:
- """Indicates if the client supports the preselect field on a
- ``CompletionItem``."""
- return get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.preselect_support",
- False,
- )
-
- @property
- def snippet_support(self) -> bool:
- """Indicates if the client supports snippets"""
- return get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.snippet_support",
- False,
- )
-
- @property
- def supported_tags(self) -> List[CompletionItemTag]:
- """The list of ``CompletionItemTags`` supported by the client."""
- capabilities = get_capability(
- self._client_capabilities,
- "text_document.completion.completion_item.tag_support",
- None,
- )
-
- if not capabilities:
- return []
-
- return capabilities.value_set
-
-
-class DocumentLinkContext:
- """Captures the context within which a document link request has been made."""
-
- def __init__(self, *, doc: Document, capabilities: ClientCapabilities):
- self.doc = doc
- """The document within which the document link request was made."""
-
- self._client_capabilities = capabilities
-
- @property
- def tooltip_support(self) -> bool:
- """Indicates if the client supports tooltips."""
- return get_capability(
- self._client_capabilities,
- "text_document.document_link.tooltip_support",
- False,
- )
-
-
-class DefinitionContext:
- """A class that captures the context within which a definition request has been
- made."""
-
- def __init__(
- self, *, doc: Document, location: str, match: "re.Match", position: Position
- ):
- self.doc = doc
- """The document within which the definition request was made."""
-
- self.location = location
- """The location type where the request was made.
- See :meth:`~esbonio.lsp.rst.RstLanguageServer.get_location_type` for details."""
-
- self.match = match
- """The match object describing the site of the definition request."""
-
- self.position = position
- """The position at which the definition request was made."""
-
- def __repr__(self):
- p = f"{self.position.line}:{self.position.character}"
- return (
- f"DefinitionContext<{self.doc.uri}:{p} ({self.location}) -- {self.match}>"
- )
-
-
-class ImplementationContext:
- """A class that captures the context within which an implementation request has been
- made."""
-
- def __init__(
- self, *, doc: Document, location: str, match: "re.Match", position: Position
- ):
- self.doc = doc
- """The document within which the implementation request was made."""
-
- self.location = location
- """The location type where the request was made.
- See :meth:`~esbonio.lsp.rst.RstLanguageServer.get_location_type` for details."""
-
- self.match = match
- """The match object describing the site of the implementation request."""
-
- self.position = position
- """The position at which the implementation request was made."""
-
- def __repr__(self):
- p = f"{self.position.line}:{self.position.character}"
- return f"ImplementationContext<{self.doc.uri}:{p} ({self.location}) -- {self.match}>"
-
-
-class HoverContext:
- """A class that captures the context within a hover request has been made."""
-
- def __init__(
- self,
- *,
- doc: Document,
- location: str,
- match: "re.Match",
- position: Position,
- capabilities: ClientCapabilities,
- ):
- self.doc = doc
- self.location = location
- self.match = match
- self.position = position
- self._client_capabilities = capabilities
-
- def __repr__(self):
- p = f"{self.position.line}:{self.position.character}"
- return f"HoverContext<{self.doc.uri}:{p} ({self.location}) -- {self.match}>"
-
- @property
- def content_formats(self) -> List[MarkupKind]:
- """The list of content formats supported by the client."""
- return get_capability(
- self._client_capabilities, "text_document.hover.content_format", []
- )
-
-
-class LanguageFeature:
- """Base class for language features."""
-
- def __init__(self, rst: "RstLanguageServer"):
- self.rst = rst
- self.logger = rst.logger.getChild(self.__class__.__name__)
-
- def initialize(self, options: InitializeParams) -> None:
- """Called once when the server is first initialized."""
-
- def initialized(self, params: InitializedParams) -> None:
- """Called once upon receipt of the `initialized` notification from the client."""
-
- def on_shutdown(self, *args):
- """Called as the server is shutting down."""
-
- def save(self, params: DidSaveTextDocumentParams) -> None:
- """Called each time a document is saved."""
-
- def delete_files(self, params: DeleteFilesParams) -> None:
- """Called each time files are deleted."""
-
- def code_action(self, params: CodeActionParams) -> List[CodeAction]:
- """Called when code actions should be computed."""
- return []
-
- hover_triggers: List["re.Pattern"] = []
-
- def hover(self, context: HoverContext) -> str:
- """Called when request textDocument/hover is sent.
-
- This method shall return the contents value of textDocument/hover response.
-
- """
- return ""
-
- completion_triggers: List["re.Pattern"] = []
- """A list of regular expressions used to determine if the
- :meth`~esbonio.lsp.rst.LanguageFeature.complete` method should be called on the
- current line."""
-
- def complete(self, context: CompletionContext) -> List[CompletionItem]:
- """Called if any of the given ``completion_triggers`` match the current line.
-
- This method should return a list of ``CompletionItem`` objects.
-
- Parameters
- ----------
- context:
- The context of the completion request
- """
- return []
-
- def completion_resolve(self, item: CompletionItem) -> CompletionItem:
- """Called with a completion item the user has selected in the UI,
- allowing for additional details to be provided e.g. documentation.
-
- Parameters
- ----------
- item:
- The completion item to provide additional details for.
- """
- return item
-
- definition_triggers: List["re.Pattern"] = []
- """A list of regular expressions used to determine if the
- :meth:`~esbonio.lsp.rst.LanguageFeature.definition` method should be called."""
-
- def definition(self, context: DefinitionContext) -> List[Location]:
- """Called if any of the given ``definition_triggers`` match the current line.
-
- This method should return a list of ``Location`` objects.
-
- Parameters
- ----------
- context:
- The context of the definition request.
- """
- return []
-
- implementation_triggers: List["re.Pattern"] = []
- """A list of regular expressions used to determine if the
- :meth:`~esbonio.lsp.rst.LanguageFeature.implementation` method should be called."""
-
- def implementation(self, context: ImplementationContext) -> List[Location]:
- """Called if any of the given ``implementation_triggers`` match the current line.
-
- This method should return a list of ``Location`` objects.
-
- Parameters
- ----------
- context:
- The context of the implementation request.
- """
- return []
-
- def document_link(self, context: DocumentLinkContext) -> List[DocumentLink]:
- """Called whenever a ``textDocument/documentLink`` request is received."""
- return []
-
-
-class DiagnosticList(collections.UserList):
- """A list type dedicated to holding diagnostics.
-
- This is mainly to ensure that only one instance of a diagnostic ever gets
- reported.
- """
-
- def append(self, item: Diagnostic):
- if not isinstance(item, Diagnostic):
- raise TypeError("Expected Diagnostic")
-
- for existing in self.data:
- fields = [
- existing.range == item.range,
- existing.message == item.message,
- existing.severity == item.severity,
- existing.code == item.code,
- existing.source == item.source,
- ]
-
- if all(fields):
- # Item already added, nothing to do.
- return
-
- self.data.append(item)
-
-
-class RstLanguageServer(LanguageServer):
- """A generic reStructuredText language server."""
-
- def __init__(self, logger: Optional[logging.Logger] = None, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.logger = logger or logging.getLogger(__name__)
- """The base logger that should be used for all language sever log entries."""
-
- self.converter = self.lsp._converter
- """The cattrs converter instance we should use."""
-
- self.user_config: InitializationOptions = InitializationOptions()
- """The user's configuration."""
-
- self._diagnostics: Dict[Tuple[str, str], List[Diagnostic]] = {}
- """Where we store and manage diagnostics."""
-
- self._loaded_extensions: Dict[str, Any] = {}
- """Record of modules that have been loaded."""
-
- self._features: Dict[str, LanguageFeature] = {}
- """The collection of language features registered with the server."""
-
- @property
- def configuration(self) -> Dict[str, Any]:
- """Return the server's actual configuration."""
- return converter.unstructure(self.user_config)
-
- def initialize(self, params: InitializeParams):
- self.user_config = converter.structure(
- params.initialization_options or {}, InitializationOptions
- )
- setup_logging(self, self.user_config.server)
-
- def initialized(self, params: InitializedParams):
- pass
-
- def on_shutdown(self, *args):
- pass
-
- def save(self, params: DidSaveTextDocumentParams):
- pass
-
- def delete_files(self, params: DeleteFilesParams):
- pass
-
- def build(self, force_all: bool = False, filenames: Optional[List[str]] = None):
- pass
-
- def load_extension(self, name: str, setup: Callable):
- """Load the given setup function as an extension.
-
- If an extension with the given ``name`` already exists, the given setup function
- will be ignored.
-
- The ``setup`` function can declare dependencies in the form of type
- annotations.
-
- .. code-block:: python
-
- from esbonio.lsp.roles import Roles
- from esbonio.lsp.sphinx import SphinxLanguageServer
-
- def esbonio_setup(rst: SphinxLanguageServer, roles: Roles):
- ...
-
- In this example the setup function is requesting instances of the
- :class:`~esbonio.lsp.sphinx.SphinxLanguageServer` and the
- :class:`~esbonio.lsp.roles.Roles` language feature.
-
- Parameters
- ----------
- name
- The name to give the extension
-
- setup
- The setup function to call
- """
-
- if name in self._loaded_extensions:
- self.logger.debug("Skipping extension '%s', already loaded", name)
- return
-
- arguments = _get_setup_arguments(self, setup, name)
- if not arguments:
- return
-
- try:
- setup(**arguments)
-
- self.logger.debug("Loaded extension '%s'", name)
- self._loaded_extensions[name] = setup
- except Exception:
- self.logger.error(
- "Unable to load extension '%s'\n%s", name, traceback.format_exc()
- )
-
- def add_feature(self, feature: "LanguageFeature"):
- """Register a language feature with the server.
-
- Parameters
- ----------
- feature
- The language feature
- """
-
- key = f"{feature.__module__}.{feature.__class__.__name__}"
- self._features[key] = feature
-
- @typing.overload
- def get_feature(self, key: str) -> "Optional[LanguageFeature]":
- ...
-
- @typing.overload
- def get_feature(self, key: Type[LF]) -> Optional[LF]:
- ...
-
- def get_feature(self, key):
- """Returns the requested language feature if it exists, otherwise it returns
- ``None``.
-
- Parameters
- ----------
- key: str | Type[LanguageFeature]
- A feature can be referenced either by its class definition (preferred) or by
- a string representing the language feature's dotted name e.g.
- ``a.b.c.ClassName``.
-
- .. deprecated:: 0.14.0
-
- Passing a string ``key`` to this method is deprecated and will become an
- error in ``v1.0``.
- """
-
- if isinstance(key, str):
- warnings.warn(
- "Language features should be referenced by their class definition, "
- "this will become an error in v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- elif issubclass(key, LanguageFeature):
- key = f"{key.__module__}.{key.__name__}"
-
- else:
- raise TypeError("Expected language feature definition")
-
- return self._features.get(key, None)
-
- def get_doctree(
- self, *, docname: Optional[str] = None, uri: Optional[str] = None
- ) -> Optional[Any]:
- # Not currently implemented for vanilla docutils projects.
- return None
-
- def get_initial_doctree(self, uri: str) -> Optional[Any]:
- """Return the initial doctree corresponding to the specified document.
-
- An "initial" doctree can be thought of as the abstract syntax tree of a
- reStructuredText document. This method disables all role and directives
- from being executed, instead they are replaced with nodes that simply
- represent that they exist.
-
- Parameters
- ----------
- uri
- Returns the doctree that corresponds with the given uri.
- """
-
- doc = self.workspace.get_document(uri)
- loctype = self.get_location_type(doc, Position(line=1, character=0))
-
- if loctype != "rst":
- return None
-
- self.logger.debug("Getting initial doctree for: '%s'", Uri.to_fs_path(uri))
-
- try:
- return read_initial_doctree(doc, self.logger)
- except Exception:
- self.logger.error(traceback.format_exc())
- return None
-
- def get_directives(self) -> Dict[str, Directive]:
- """Return a dictionary of the known directives
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``.
- Use the :meth:`~esbonio.lsp.directives.Directives.get_directives` method
- instead.
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_directives() is deprecated and will be removed in v1.0."
- " Instead call the get_directives() method on the Directives language "
- "feature.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- feature = self.get_feature("esbonio.lsp.directives.Directives")
- if feature is None:
- return {}
-
- return feature.get_directives() # type: ignore
-
- def get_directive_options(self, name: str) -> Dict[str, Any]:
- """Return the options specification for the given directive.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_directive_options() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- directive = self.get_directives().get(name, None)
- if directive is None:
- return {}
-
- return directive.option_spec or {}
-
- def get_roles(self) -> Dict[str, Any]:
- """Return a dictionary of known roles.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``.
- Use the :meth:`~esbonio.lsp.roles.Roles.get_roles` method instead.
- """
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_roles() is deprecated and will be removed in v1.0. "
- "Instead call the get_roles() method on the Roles language "
- "feature.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- feature = self.get_feature("esbonio.lsp.roles.Roles")
- if feature is None:
- return {}
-
- return feature.get_roles() # type: ignore
-
- def get_default_role(self) -> Tuple[Optional[str], Optional[str]]:
- """Return the default role for the project."""
- return None, None
-
- def clear_diagnostics(self, source: str, uri: Optional[str] = None) -> None:
- """Clear diagnostics from the given source.
-
- Parameters
- ----------
- source:
- The source from which to clear diagnostics.
- uri:
- If given, clear diagnostics from within just this uri. Otherwise, all
- diagnostics from the given source are cleared.
- """
-
- if uri:
- uri = normalise_uri(uri)
-
- for key in self._diagnostics.keys():
- clear_source = source == key[0]
- clear_uri = uri == key[1] or uri is None
-
- if clear_source and clear_uri:
- self._diagnostics[key] = []
-
- def add_diagnostics(self, source: str, uri, diagnostic: Diagnostic):
- """Add a diagnostic to the given source and uri.
-
- Parameters
- ----------
- source
- The source the diagnostics are from
- uri
- The uri the diagnostics are associated with
- diagnostic
- The diagnostic to add
- """
- key = (source, normalise_uri(uri))
- self._diagnostics.setdefault(key, []).append(diagnostic)
-
- def set_diagnostics(
- self, source: str, uri: str, diagnostics: List[Diagnostic]
- ) -> None:
- """Set the diagnostics for the given source and uri.
-
- Parameters
- ----------
- source:
- The source the diagnostics are from
- uri:
- The uri the diagnostics are associated with
- diagnostics:
- The diagnostics themselves
- """
- uri = normalise_uri(uri)
- self._diagnostics[(source, uri)] = diagnostics
-
- def sync_diagnostics(self) -> None:
- """Update the client with the currently stored diagnostics."""
-
- uris = {uri for _, uri in self._diagnostics.keys()}
- diagnostics = {uri: DiagnosticList() for uri in uris}
-
- for (source, uri), diags in self._diagnostics.items():
- for diag in diags:
- diag.source = source
- diagnostics[uri].append(diag)
-
- for uri, diag_list in diagnostics.items():
- self.logger.debug("Publishing %d diagnostics for: %s", len(diag_list), uri)
- self.publish_diagnostics(uri, diag_list.data)
-
- def get_location_type(self, document: Document, position: Position) -> str:
- """Given a document and a position, return the type of location.
-
- Returns one of the following values:
-
- - ``rst``: Indicates that the position is within an reStructuredText document
- - ``py``: Indicates that the position is within code in a Python file
- - ``docstring``: Indicates that the position is within a docstring in a
- Python file.
-
- If the location type cannot be determined, this function will fall back to
- ``rst``.
-
- Parameters
- ----------
- doc
- The document associated with the given position
-
- position
- The position to determine the type of
- """
- doc = self.workspace.get_document(document.uri)
- fpath = pathlib.Path(Uri.to_fs_path(doc.uri))
-
- # Prefer the document's language_id, but fallback to file extensions
- loctype = getattr(doc, "language_id", None) or fpath.suffix
-
- if loctype in {".rst", "rst", "restructuredtext"}:
- return "rst"
-
- if loctype in {".py", "py", "python"}:
- # Let's count how many pairs of triple quotes are above us in the file
- # even => we're outside a docstring
- # odd => we're within a docstring
- source = self.text_to_position(doc, position)
- count = len(TRIPLE_QUOTE.findall(source))
- return "py" if count % 2 == 0 else "docstring"
-
- # Fallback to rst
- self.logger.debug("Unable to determine location type for uri: %s", doc.uri)
- return "rst"
-
- def line_at_position(self, doc: Document, position: Position) -> str:
- """Return the contents of the line corresponding to the given position.
-
- Parameters
- ----------
- doc:
- The document associated with the given position
- position:
- The position representing the line to retrieve
- """
-
- try:
- return doc.lines[position.line]
- except IndexError:
- return ""
-
- def line_to_position(self, doc: Document, position: Position) -> str:
- """Return the contents of the line up until the given position.
-
- Parameters
- ----------
- doc:
- The document associated with the given position.
- position:
- The position representing the line to retrieve.
- """
-
- line = self.line_at_position(doc, position)
- return line[: position.character]
-
- def preview(self, options: Dict[str, Any]) -> Dict[str, Any]:
- """Generate a preview of the documentation."""
- name = self.__class__.__name__
- self.show_message(
- f"Previews are not currently supported by {name} based servers"
- )
-
- return {}
-
- def text_to_position(self, doc: Document, position: Position) -> str:
- """Return the contents of the document up until the given position.
-
- Parameters
- ----------
- doc:
- The document associated with the given position
- position:
- The position representing the point at which to stop gathering text.
- """
- idx = doc.offset_at_position(position)
- return doc.source[:idx]
-
-
-def normalise_uri(uri: str) -> str:
- uri = Uri.from_fs_path(Uri.to_fs_path(uri))
-
- # Paths on windows are case insensitive.
- if IS_WIN:
- uri = uri.lower()
-
- return uri
-
-
-def _get_setup_arguments(
- server: RstLanguageServer, setup: Callable, modname: str
-) -> Optional[Dict[str, Any]]:
- """Given a setup function, try to construct the collection of arguments to pass to
- it.
- """
- annotations = typing.get_type_hints(setup)
- parameters = {
- p.name: annotations[p.name]
- for p in inspect.signature(setup).parameters.values()
- }
-
- args = {}
- for name, type_ in parameters.items():
- if issubclass(server.__class__, type_):
- args[name] = server
- continue
-
- if issubclass(type_, LanguageFeature):
- # Try and obtain an instance of the requested language feature.
- feature = server.get_feature(type_)
- if feature is not None:
- args[name] = feature
- continue
-
- server.logger.debug(
- "Skipping extension '%s', server missing requested feature: '%s'",
- modname,
- type_,
- )
- return None
-
- server.logger.error(
- "Skipping extension '%s', parameter '%s' has unsupported type: '%s'",
- modname,
- name,
- type_,
- )
- return None
-
- return args
-
-
-cli = setup_cli("esbonio.lsp.rst", "Esbonio's reStructuredText language server.")
-cli.set_defaults(modules=DEFAULT_MODULES)
-cli.set_defaults(server_cls=RstLanguageServer)
diff --git a/lib/esbonio/esbonio/lsp/rst/__main__.py b/lib/esbonio/esbonio/lsp/rst/__main__.py
deleted file mode 100644
index eb49a0162..000000000
--- a/lib/esbonio/esbonio/lsp/rst/__main__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import sys
-
-from esbonio.cli import main
-from esbonio.lsp.rst import cli
-
-sys.exit(main(cli))
diff --git a/lib/esbonio/esbonio/lsp/rst/config.py b/lib/esbonio/esbonio/lsp/rst/config.py
deleted file mode 100644
index 054576c79..000000000
--- a/lib/esbonio/esbonio/lsp/rst/config.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from typing import List
-from typing import Literal
-
-import attrs
-
-
-@attrs.define
-class ServerCompletionConfig:
- """Configuration options for the server that control completion behavior."""
-
- preferred_insert_behavior: Literal["insert", "replace"] = attrs.field(
- default="replace"
- )
- """This option indicates if the user prefers we use ``insertText`` or ``textEdit``
- when rendering ``CompletionItems``."""
-
-
-@attrs.define
-class ServerConfig:
- """Configuration options for the server."""
-
- completion: ServerCompletionConfig = attrs.field(factory=ServerCompletionConfig)
- """Configuration values that affect completion"""
-
- enable_scroll_sync: bool = attrs.field(default=False)
- """Enable custom transformation to add classes with line numbers"""
-
- enable_live_preview: bool = attrs.field(default=False)
- """Set it to True if you want to build Sphinx app on change event"""
-
- log_filter: List[str] = attrs.field(factory=list)
- """A list of logger names to restrict output to."""
-
- log_level: str = attrs.field(default="error")
- """The logging level of server messages to display."""
-
- show_deprecation_warnings: bool = attrs.field(default=False)
- """Developer flag to enable deprecation warnings."""
-
-
-@attrs.define
-class InitializationOptions:
- """The initialization options we can expect to receive from a client."""
-
- server: ServerConfig = attrs.field(factory=ServerConfig)
- """The ``esbonio.server.*`` namespace of options."""
diff --git a/lib/esbonio/esbonio/lsp/rst/directives.json b/lib/esbonio/esbonio/lsp/rst/directives.json
deleted file mode 100644
index ecafa98e0..000000000
--- a/lib/esbonio/esbonio/lsp/rst/directives.json
+++ /dev/null
@@ -1,2368 +0,0 @@
-{
- "sectnum(docutils.parsers.rst.directives.parts.Sectnum)": {
- "is_markdown": true,
- "description": [
- "## Automatic Section Numbering",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"sectnum\" or \"section-numbering\" (synonyms) |",
- "| Doctree Elements | [pending](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#pending), [generated](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#generated) |",
- "| Directive Arguments | None. |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | None. |",
- "| Configuration Setting | [sectnum_xform](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#sectnum-xform) |",
- "",
- "The \"sectnum\" (or \"section-numbering\") directive automatically numbers",
- "sections and subsections in a document (if not disabled by the",
- "`--no-section-numbering` command line option or the [sectnum_xform](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#sectnum-xform)",
- "configuration setting).",
- "",
- "Section numbers are of the \"multiple enumeration\" form, where each",
- "level has a number, separated by periods. For example, the title of section",
- "1, subsection 2, subsubsection 3 would have \"1.2.3\" prefixed.",
- "",
- "The \"sectnum\" directive does its work in two passes: the initial parse",
- "and a transform. During the initial parse, a \"pending\" element is",
- "generated which acts as a placeholder, storing any options internally.",
- "At a later stage in the processing, the \"pending\" element triggers a",
- "transform, which adds section numbers to titles. Section numbers are",
- "enclosed in a \"generated\" element, and titles have their \"auto\"",
- "attribute set to \"1\".",
- "",
- "The following options are recognized:",
- "",
- "`depth`: integer",
- "The number of section levels that are numbered by this directive.",
- "The default is unlimited depth.",
- "",
- "`prefix`: string",
- "An arbitrary string that is prefixed to the automatically",
- "generated section numbers. It may be something like \"3.2.\", which",
- "will produce \"3.2.1\", \"3.2.2\", \"3.2.2.1\", and so on. Note that",
- "any separating punctuation (in the example, a period, \".\") must be",
- "explicitly provided. The default is no prefix.",
- "",
- "`suffix`: string",
- "An arbitrary string that is appended to the automatically",
- "generated section numbers. The default is no suffix.",
- "",
- "`start`: integer",
- "The value that will be used for the first section number.",
- "Combined with `prefix`, this may be used to force the right",
- "numbering for a document split over several source files. The",
- "default is 1."
- ],
- "options": {
- "depth": "integer\nThe number of section levels that are numbered by this directive.\nThe default is unlimited depth.\n",
- "prefix": "string\nAn arbitrary string that is prefixed to the automatically\ngenerated section numbers. It may be something like \"3.2.\", which\nwill produce \"3.2.1\", \"3.2.2\", \"3.2.2.1\", and so on. Note that\nany separating punctuation (in the example, a period, \".\") must be\nexplicitly provided. The default is no prefix.\n",
- "suffix": "string\nAn arbitrary string that is appended to the automatically\ngenerated section numbers. The default is no suffix.\n",
- "start": "integer\nThe value that will be used for the first section number.\nCombined with `prefix`, this may be used to force the right\nnumbering for a document split over several source files. The\ndefault is 1.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#automatic-section-numbering",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "attention(docutils.parsers.rst.directives.admonitions.Attention)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#attention",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "caution(docutils.parsers.rst.directives.admonitions.Caution)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#caution",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "code(docutils.parsers.rst.directives.body.CodeBlock)": {
- "is_markdown": true,
- "description": [
- "## Code",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"code\" |",
- "| Doctree Element | [literal_block](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#literal-block), [inline elements](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#inline-elements) |",
- "| Directive Arguments | One, optional (formal language). |",
- "| Directive Options | name, class, number-lines. |",
- "| Directive Content | Becomes the body of the literal block. |",
- "| Configuration Setting | [syntax_highlight](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#syntax-highlight). |",
- "",
- "The \"code\" directive constructs a literal block. If the code language is",
- "specified, the content is parsed by the [Pygments](https://pygments.org/) syntax highlighter and",
- "tokens are stored in nested [inline elements](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#inline-elements) with class arguments",
- "according to their syntactic category. The actual highlighting requires",
- "a style-sheet (e.g. one [generated by Pygments](https://pygments.org/docs/cmdline/#generating-styles), see the",
- "[sandbox/stylesheets](https://docutils.sourceforge.io/sandbox/stylesheets/) for examples).",
- "",
- "The parsing can be turned off with the [syntax_highlight](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#syntax-highlight) configuration",
- "setting and command line option or by specifying the language as [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33)",
- "option instead of directive argument. This also avoids warnings",
- "when [Pygments](https://pygments.org/) is not installed or the language is not in the",
- "[supported languages and markup formats](https://pygments.org/languages/).",
- "",
- "For inline code, use the [\"code\" role](https:/docutils.sourceforge.io/docs/ref/rst/roles.html#code).",
- "",
- "The following options are recognized:",
- "",
- "`number-lines`: [integer] (start line number)",
- "Precede every line with a line number.",
- "The optional argument is the number of the first line (default 1).",
- "",
- "and the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name).",
- "",
- "`Example::`: ",
- "The content of the following directive",
- "",
- "```",
- ".. code:: python",
- "",
- " def my_function():",
- " \"just a test\"",
- " print 8/2",
- "```",
- "",
- "is parsed and marked up as Python source code."
- ],
- "options": {
- "number-lines": "[integer] (start line number)\nPrecede every line with a line number.\nThe optional argument is the number of the first line (default 1).\n",
- "Example::": "\nThe content of the following directive\n\n```\n.. code:: python\n\n def my_function():\n \"just a test\"\n print 8/2\n```\n\nis parsed and marked up as Python source code.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#code",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "compound(docutils.parsers.rst.directives.body.Compound)": {
- "is_markdown": true,
- "description": [
- "## Compound Paragraph",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"compound\" |",
- "| Doctree Element | [compound](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#compound) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "The \"compound\" directive is used to create a compound paragraph, which",
- "is a single logical paragraph containing multiple physical body",
- "elements such as simple paragraphs, literal blocks, tables, lists,",
- "etc., instead of directly containing text and inline elements. For",
- "example:",
- "",
- "```",
- ".. compound::",
- "",
- " The 'rm' command is very dangerous. If you are logged",
- " in as root and enter ::",
- "",
- " cd /",
- " rm -rf *",
- "",
- " you will erase the entire contents of your file system.",
- "```",
- "",
- "In the example above, a literal block is \"embedded\" within a sentence",
- "that begins in one physical paragraph and ends in another.",
- "",
- "The \"compound\" directive is not a generic block-level container",
- "like HTML's `
` element. Do not use it only to group a",
- "sequence of elements, or you may get unexpected results.",
- "",
- "If you need a generic block-level container, please use the",
- "[container](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#container) directive, described below.",
- "",
- "Compound paragraphs are typically rendered as multiple distinct text",
- "blocks, with the possibility of variations to emphasize their logical",
- "unity:",
- "- If paragraphs are rendered with a first-line indent, only the first",
- "physical paragraph of a compound paragraph should have that indent",
- "-- second and further physical paragraphs should omit the indents;",
- "- vertical spacing between physical elements may be reduced;",
- "- and so on."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#compound-paragraph",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "container(docutils.parsers.rst.directives.body.Container)": {
- "is_markdown": true,
- "description": [
- "## Container",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"container\" |",
- "| Doctree Element | [container](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#container) |",
- "| Directive Arguments | One or more, optional (class names). |",
- "| Directive Options | [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "The \"container\" directive surrounds its contents (arbitrary body",
- "elements) with a generic block-level \"container\" element. Combined",
- "with the optional \"[classes](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#classes)\" attribute argument(s), this is an",
- "extension mechanism for users & applications. For example:",
- "",
- "```",
- ".. container:: custom",
- "",
- " This paragraph might be rendered in a custom way.",
- "```",
- "",
- "Parsing the above results in the following pseudo-XML:",
- "",
- "```",
- "",
- " ",
- " This paragraph might be rendered in a custom way.",
- "```",
- "",
- "The \"container\" directive is the equivalent of HTML's `
`",
- "element. It may be used to group a sequence of elements for user- or",
- "application-specific purposes."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#container",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "csv-table(docutils.parsers.rst.directives.tables.CSVTable)": {
- "is_markdown": true,
- "description": [
- "## CSV Table",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"csv-table\" |",
- "| Doctree Element | [table](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#table) |",
- "| Directive Arguments | One, optional (table title). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | A CSV (comma-separated values) table. |",
- "",
- "The \"csv-table\" directive's \":file:\" and \":url:\" options represent",
- "a potential security holes. They can be disabled with the",
- "\"[file_insertion_enabled](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#file-insertion-enabled)\" runtime setting.",
- "",
- "The \"csv-table\" directive is used to create a table from CSV",
- "(comma-separated values) data. CSV is a common data format generated",
- "by spreadsheet applications and commercial databases. The data may be",
- "internal (an integral part of the document) or external (a separate",
- "file).",
- "- Block markup and inline markup within cells is supported. Line ends",
- "are recognized within cells.",
- "- There is no support for checking that the number of columns in each",
- "row is the same. The directive automatically adds empty entries at",
- "the end of short rows.",
- "Add \"strict\" option to verify input?",
- "Example:",
- "",
- "```",
- ".. csv-table:: Frozen Delights!",
- " :header: \"Treat\", \"Quantity\", \"Description\"",
- " :widths: 15, 10, 30",
- "",
- " \"Albatross\", 2.99, \"On a stick!\"",
- " \"Crunchy Frog\", 1.49, \"If we took the bones out, it wouldn't be",
- " crunchy, now would it?\"",
- " \"Gannet Ripple\", 1.99, \"On a stick!\"",
- "```",
- "",
- "The following options are recognized:",
- "",
- "`align`: \"left\", \"center\", or \"right\"",
- "The horizontal alignment of the table. (New in Docutils 0.13)",
- "",
- "`delim`: char | \"tab\" | \"space\" 4",
- "A one-character string5 used to separate fields.",
- "Defaults to `,` (comma). May be specified as a Unicode code",
- "point; see the [unicode](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#unicode) directive for syntax details.",
- "",
- "`encoding`: string",
- "The text encoding of the external CSV data (file or URL).",
- "Defaults to the document's [input_encoding](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#input-encoding).",
- "",
- "`escape`: char",
- "A one-character5 string used to escape the",
- "delimiter or quote characters. May be specified as a Unicode",
- "code point; see the [unicode](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#unicode) directive for syntax details. Used",
- "when the delimiter is used in an unquoted field, or when quote",
- "characters are used within a field. The default is to double-up",
- "the character, e.g. \"He said, \"\"Hi!\"\"\"",
- "Add another possible value, \"double\", to explicitly indicate",
- "the default case?",
- "`file`: string (newlines removed)",
- "The local filesystem path to a CSV data file.",
- "",
- "`header`: CSV data",
- "Supplemental data for the table header, added independently of and",
- "before any `header-rows` from the main CSV data. Must use the",
- "same CSV format as the main CSV data.",
- "",
- "`header-rows`: integer",
- "The number of rows of CSV data to use in the table header.",
- "Defaults to 0.",
- "",
- "`keepspace`: flag (empty)",
- "Treat whitespace immediately following the delimiter as",
- "significant. The default is to ignore such whitespace.",
- "",
- "`quote`: char",
- "A one-character string5 used to quote elements",
- "containing the delimiter or which start with the quote",
- "character. Defaults to `\"` (quote). May be specified as a",
- "Unicode code point; see the [unicode](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#unicode) directive for syntax",
- "details.",
- "",
- "`stub-columns`: integer",
- "The number of table columns to use as stubs (row titles, on the",
- "left). Defaults to 0.",
- "",
- "`url`: string (whitespace removed)",
- "An Internet URL reference to a CSV data file.",
- "",
- "`widths`: integer [integer...] or \"auto\"",
- "A list of relative column widths.",
- "The default is equal-width columns (100%/#columns).",
- "",
- "\"auto\" delegates the determination of column widths to the backend",
- "(LaTeX, the HTML browser, ...).",
- "",
- "`width`: [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units)",
- "Sets the width of the table to the specified length or percentage",
- "of the line width. If omitted, the renderer determines the width",
- "of the table based on its contents or the column `widths`.",
- "",
- "and the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name).",
- "4",
- "Whitespace delimiters are supported only for external",
- "CSV files.",
- "5",
- "With Python\u00a02, the values for the `delimiter`,",
- "`quote`, and `escape` options must be ASCII characters. (The csv",
- "module does not support Unicode and all non-ASCII characters are",
- "encoded as multi-byte utf-8 string). This limitation does not exist",
- "under Python\u00a03."
- ],
- "options": {
- "align": "\"left\", \"center\", or \"right\"\nThe horizontal alignment of the table. (New in Docutils 0.13)\n",
- "delim": "char | \"tab\" | \"space\" 4\nA one-character string5 used to separate fields.\nDefaults to `,` (comma). May be specified as a Unicode code\npoint; see the [unicode](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#unicode) directive for syntax details.\n",
- "encoding": "string\nThe text encoding of the external CSV data (file or URL).\nDefaults to the document's [input_encoding](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#input-encoding).\n",
- "escape": "char\nA one-character5 string used to escape the\ndelimiter or quote characters. May be specified as a Unicode\ncode point; see the [unicode](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#unicode) directive for syntax details. Used\nwhen the delimiter is used in an unquoted field, or when quote\ncharacters are used within a field. The default is to double-up\nthe character, e.g. \"He said, \"\"Hi!\"\"\"\nAdd another possible value, \"double\", to explicitly indicate\nthe default case?",
- "file": "string (newlines removed)\nThe local filesystem path to a CSV data file.\n",
- "header": "CSV data\nSupplemental data for the table header, added independently of and\nbefore any `header-rows` from the main CSV data. Must use the\nsame CSV format as the main CSV data.\n",
- "header-rows": "integer\nThe number of rows of CSV data to use in the table header.\nDefaults to 0.\n",
- "keepspace": "flag (empty)\nTreat whitespace immediately following the delimiter as\nsignificant. The default is to ignore such whitespace.\n",
- "quote": "char\nA one-character string5 used to quote elements\ncontaining the delimiter or which start with the quote\ncharacter. Defaults to `\"` (quote). May be specified as a\nUnicode code point; see the [unicode](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#unicode) directive for syntax\ndetails.\n",
- "stub-columns": "integer\nThe number of table columns to use as stubs (row titles, on the\nleft). Defaults to 0.\n",
- "url": "string (whitespace removed)\nAn Internet URL reference to a CSV data file.\n",
- "widths": "integer [integer...] or \"auto\"\nA list of relative column widths.\nThe default is equal-width columns (100%/#columns).\n\n\"auto\" delegates the determination of column widths to the backend\n(LaTeX, the HTML browser, ...).\n",
- "width": "[length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units)\nSets the width of the table to the specified length or percentage\nof the line width. If omitted, the renderer determines the width\nof the table based on its contents or the column `widths`.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#csv-table",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "danger(docutils.parsers.rst.directives.admonitions.Danger)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#danger",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "date(docutils.parsers.rst.directives.misc.Date)": {
- "is_markdown": true,
- "description": [
- "## Date",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"date\" |",
- "| Doctree Element | Text |",
- "| Directive Arguments | One, optional (date format). |",
- "| Directive Options | None. |",
- "| Directive Content | None. |",
- "",
- "The \"date\" directive generates the current local date and inserts it",
- "into the document as text. This directive may be used in substitution",
- "definitions only.",
- "",
- "The optional directive content is interpreted as the desired date",
- "format, using the same codes as Python's [time.strftime()](https://docs.python.org/3/library/time.html#time.strftime) function. The",
- "default format is \"%Y-%m-%d\" (ISO 8601 date), but time fields can also",
- "be used. Examples:",
- "",
- "```",
- ".. |date| date::",
- ".. |time| date:: %H:%M",
- "",
- "Today's date is |date|.",
- "",
- "This document was generated on |date| at |time|.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#date",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "default-role(docutils.parsers.rst.directives.misc.DefaultRole)": {
- "is_markdown": true,
- "description": [
- "## Setting the Default Interpreted Text Role",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"default-role\" |",
- "| Doctree Element | None; affects subsequent parsing. |",
- "| Directive Arguments | One, optional (new default role name). |",
- "| Directive Options | None. |",
- "| Directive Content | None. |",
- "",
- "The \"default-role\" directive sets the default interpreted text role,",
- "the role that is used for interpreted text without an explicit role.",
- "For example, after setting the default role like this:",
- "",
- "```",
- ".. default-role:: subscript",
- "```",
- "",
- "any subsequent use of implicit-role interpreted text in the document",
- "will use the \"subscript\" role:",
- "",
- "```",
- "An example of a `default` role.",
- "```",
- "",
- "This will be parsed into the following document tree fragment:",
- "",
- "```",
- "",
- " An example of a",
- " ",
- " default",
- " role.",
- "```",
- "",
- "Custom roles may be used (see the \"[role](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#role)\" directive above), but it",
- "must have been declared in a document before it can be set as the",
- "default role. See the [reStructuredText Interpreted Text Roles](https:/docutils.sourceforge.io/docs/ref/rst/roles.html)",
- "document for details of built-in roles.",
- "",
- "The directive may be used without an argument to restore the initial",
- "default interpreted text role, which is application-dependent. The",
- "initial default interpreted text role of the standard reStructuredText",
- "parser is \"title-reference\"."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#default-role",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "epigraph(docutils.parsers.rst.directives.body.Epigraph)": {
- "is_markdown": true,
- "description": [
- "## Epigraph",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"epigraph\" |",
- "| Doctree Element | [block_quote](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#block-quote) |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | Interpreted as the body of the block quote. |",
- "",
- "An epigraph is an apposite (suitable, apt, or pertinent) short",
- "inscription, often a quotation or poem, at the beginning of a document",
- "or section.",
- "",
- "The \"epigraph\" directive produces an \"epigraph\"-class block quote.",
- "For example, this input:",
- "",
- "```",
- ".. epigraph::",
- "",
- " No matter where you go, there you are.",
- "",
- " -- Buckaroo Banzai",
- "```",
- "",
- "becomes this document tree fragment:",
- "",
- "```",
- "",
- " ",
- " No matter where you go, there you are.",
- " ",
- " Buckaroo Banzai",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#epigraph",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "error(docutils.parsers.rst.directives.admonitions.Error)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#error",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "figure(docutils.parsers.rst.directives.images.Figure)": {
- "is_markdown": true,
- "description": [
- "## Figure",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"figure\" |",
- "| Doctree Elements | [figure](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#figure), [image](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#image), [caption](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#caption), [legend](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#legend) |",
- "| Directive Arguments | One, required (image URI). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | Interpreted as the figure caption and an optional",
- "legend. |",
- "",
- "A \"figure\" consists of [image](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#image) data (including [image options](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#image-options)), an optional",
- "caption (a single paragraph), and an optional legend (arbitrary body",
- "elements). For page-based output media, figures might float to a different",
- "position if this helps the page layout.",
- "",
- "```",
- ".. figure:: picture.png",
- " :scale: 50 %",
- " :alt: map to buried treasure",
- "",
- " This is the caption of the figure (a simple paragraph).",
- "",
- " The legend consists of all elements after the caption. In this",
- " case, the legend consists of this paragraph and the following",
- " table:",
- "",
- " +-----------------------+-----------------------+",
- " | Symbol | Meaning |",
- " +=======================+=======================+",
- " | .. image:: tent.png | Campground |",
- " +-----------------------+-----------------------+",
- " | .. image:: waves.png | Lake |",
- " +-----------------------+-----------------------+",
- " | .. image:: peak.png | Mountain |",
- " +-----------------------+-----------------------+",
- "```",
- "",
- "There must be blank lines before the caption paragraph and before the",
- "legend. To specify a legend without a caption, use an empty comment",
- "(\"..\") in place of the caption.",
- "",
- "The \"figure\" directive supports all of the options of the \"image\"",
- "directive (see [image options](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#image-options) above). These options (except",
- "\"align\") are passed on to the contained image.",
- "",
- "`align`: \"left\", \"center\", or \"right\"",
- "The horizontal alignment of the figure, allowing the image to",
- "float and have the text flow around it. The specific behavior",
- "depends upon the browser or rendering software used.",
- "",
- "In addition, the following options are recognized:",
- "",
- "`figwidth`: \"image\", [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units), or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units) of current line width",
- "The width of the figure.",
- "Limits the horizontal space used by the figure.",
- "A special value of \"image\" is allowed, in which case the",
- "included image's actual width is used (requires the [Python Imaging",
- "Library](https://pypi.org/project/Pillow/)). If the image file is not found or the required software is",
- "unavailable, this option is ignored.",
- "",
- "Sets the \"width\" attribute of the \"figure\" doctree element.",
- "",
- "This option does not scale the included image; use the \"width\"",
- "[image](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#image) option for that.",
- "",
- "```",
- "+---------------------------+",
- "| figure |",
- "| |",
- "|<------ figwidth --------->|",
- "| |",
- "| +---------------------+ |",
- "| | image | |",
- "| | | |",
- "| |<--- width --------->| |",
- "| +---------------------+ |",
- "| |",
- "|The figure's caption should|",
- "|wrap at this width. |",
- "+---------------------------+",
- "```",
- "",
- "`figclass`: text",
- "Set a [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute value on the figure element. See the",
- "[class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) directive below."
- ],
- "options": {
- "align": "\"left\", \"center\", or \"right\"\nThe horizontal alignment of the figure, allowing the image to\nfloat and have the text flow around it. The specific behavior\ndepends upon the browser or rendering software used.\n",
- "figwidth": "\"image\", [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units), or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units) of current line width\nThe width of the figure.\nLimits the horizontal space used by the figure.\nA special value of \"image\" is allowed, in which case the\nincluded image's actual width is used (requires the [Python Imaging\nLibrary](https://pypi.org/project/Pillow/)). If the image file is not found or the required software is\nunavailable, this option is ignored.\n\nSets the \"width\" attribute of the \"figure\" doctree element.\n\nThis option does not scale the included image; use the \"width\"\n[image](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#image) option for that.\n\n```\n+---------------------------+\n| figure |\n| |\n|<------ figwidth --------->|\n| |\n| +---------------------+ |\n| | image | |\n| | | |\n| |<--- width --------->| |\n| +---------------------+ |\n| |\n|The figure's caption should|\n|wrap at this width. |\n+---------------------------+\n```\n",
- "figclass": "text\nSet a [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute value on the figure element. See the\n[class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) directive below.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#figure",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "footer(docutils.parsers.rst.directives.parts.Footer)": {
- "is_markdown": true,
- "description": [
- "## Document Header & Footer",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"header\" and \"footer\" |",
- "| Doctree Elements | [decoration](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#decoration), header, footer |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "The \"header\" and \"footer\" directives create document decorations,",
- "useful for page navigation, notes, time/datestamp, etc. For example:",
- "",
- "```",
- ".. header:: This space for rent.",
- "```",
- "",
- "This will add a paragraph to the document header, which will appear at",
- "the top of the generated web page or at the top of every printed page.",
- "",
- "These directives may be used multiple times, cumulatively. There is",
- "currently support for only one header and footer.",
- "",
- "While it is possible to use the \"header\" and \"footer\" directives to",
- "create navigational elements for web pages, you should be aware",
- "that Docutils is meant to be used for document processing, and",
- "that a navigation bar is not typically part of a document.",
- "",
- "Thus, you may soon find Docutils' abilities to be insufficient for",
- "these purposes. At that time, you should consider using a",
- "documentation generator like [Sphinx](http://sphinx-doc.org/) rather than the \"header\" and",
- "\"footer\" directives.",
- "",
- "In addition to the use of these directives to populate header and",
- "footer content, content may also be added automatically by the",
- "processing system. For example, if certain runtime settings are",
- "enabled, the document footer is populated with processing information",
- "such as a datestamp, a link to [the Docutils website](https://docutils.sourceforge.io), etc."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#footer",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "header(docutils.parsers.rst.directives.parts.Header)": {
- "is_markdown": true,
- "description": [
- "## Document Header & Footer",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"header\" and \"footer\" |",
- "| Doctree Elements | [decoration](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#decoration), header, footer |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "The \"header\" and \"footer\" directives create document decorations,",
- "useful for page navigation, notes, time/datestamp, etc. For example:",
- "",
- "```",
- ".. header:: This space for rent.",
- "```",
- "",
- "This will add a paragraph to the document header, which will appear at",
- "the top of the generated web page or at the top of every printed page.",
- "",
- "These directives may be used multiple times, cumulatively. There is",
- "currently support for only one header and footer.",
- "",
- "While it is possible to use the \"header\" and \"footer\" directives to",
- "create navigational elements for web pages, you should be aware",
- "that Docutils is meant to be used for document processing, and",
- "that a navigation bar is not typically part of a document.",
- "",
- "Thus, you may soon find Docutils' abilities to be insufficient for",
- "these purposes. At that time, you should consider using a",
- "documentation generator like [Sphinx](http://sphinx-doc.org/) rather than the \"header\" and",
- "\"footer\" directives.",
- "",
- "In addition to the use of these directives to populate header and",
- "footer content, content may also be added automatically by the",
- "processing system. For example, if certain runtime settings are",
- "enabled, the document footer is populated with processing information",
- "such as a datestamp, a link to [the Docutils website](https://docutils.sourceforge.io), etc."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#header",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "highlights(docutils.parsers.rst.directives.body.Highlights)": {
- "is_markdown": true,
- "description": [
- "## Highlights",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"highlights\" |",
- "| Doctree Element | [block_quote](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#block-quote) |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | Interpreted as the body of the block quote. |",
- "",
- "Highlights summarize the main points of a document or section, often",
- "consisting of a list.",
- "",
- "The \"highlights\" directive produces a \"highlights\"-class block quote.",
- "See [Epigraph](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#epigraph) above for an analogous example."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#highlights",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "admonition(docutils.parsers.rst.directives.admonitions.Admonition)": {
- "is_markdown": true,
- "description": [
- "## Generic Admonition",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"admonition\" |",
- "| Doctree Elements | [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | One, required (admonition title) |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "This is a generic, titled admonition. The title may be anything the",
- "author desires.",
- "",
- "The author-supplied title is also used as a [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute value",
- "after being converted into a valid identifier form (down-cased;",
- "non-alphanumeric characters converted to single hyphens; \"admonition-\"",
- "prefixed). For example, this admonition:",
- "",
- "```",
- ".. admonition:: And, by the way...",
- "",
- " You can make up your own admonition too.",
- "```",
- "",
- "becomes the following document tree (pseudo-XML):",
- "",
- "```",
- "",
- " ",
- " ",
- " And, by the way...",
- " ",
- " You can make up your own admonition too.",
- "```",
- "",
- "The [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) option overrides the computed [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute",
- "value."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#generic-admonition",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "hint(docutils.parsers.rst.directives.admonitions.Hint)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#hint",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "image(docutils.parsers.rst.directives.images.Image)": {
- "is_markdown": true,
- "description": [
- "## Image",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"image\" |",
- "| Doctree Element | [image](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#image) |",
- "| Directive Arguments | One, required (image URI). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | None. |",
- "",
- "An \"image\" is a simple picture:",
- "",
- "```",
- ".. image:: picture.png",
- "```",
- "",
- "Inline images can be defined with an \"image\" directive in a [substitution",
- "definition](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#substitution-definitions)",
- "",
- "The URI for the image source file is specified in the directive",
- "argument. As with hyperlink targets, the image URI may begin on the",
- "same line as the explicit markup start and target name, or it may",
- "begin in an indented text block immediately following, with no",
- "intervening blank lines. If there are multiple lines in the link",
- "block, they are stripped of leading and trailing whitespace and joined",
- "together.",
- "",
- "Optionally, the image link block may contain a flat field list, the",
- "image options. For example:",
- "",
- "```",
- ".. image:: picture.jpeg",
- " :height: 100px",
- " :width: 200 px",
- " :scale: 50 %",
- " :alt: alternate text",
- " :align: right",
- "```",
- "",
- "The following options are recognized:",
- "",
- "`alt`: text",
- "Alternate text: a short description of the image, displayed by",
- "applications that cannot display images, or spoken by applications",
- "for visually impaired users.",
- "",
- "`height`: [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units)",
- "The desired height of the image.",
- "Used to reserve space or scale the image vertically. When the \"scale\"",
- "option is also specified, they are combined. For example, a height of",
- "200px and a scale of 50 is equivalent to a height of 100px with no scale.",
- "",
- "`width`: [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units) of the current line width",
- "The width of the image.",
- "Used to reserve space or scale the image horizontally. As with \"height\"",
- "above, when the \"scale\" option is also specified, they are combined.",
- "",
- "`scale`: integer percentage (the \"%\" symbol is optional)",
- "The uniform scaling factor of the image. The default is \"100\u00a0%\", i.e.",
- "no scaling.",
- "",
- "If no \"height\" or \"width\" options are specified, the Python",
- "Imaging Library (PIL/[Pillow](https://pypi.org/project/Pillow/)) may be used to determine them, if",
- "it is installed and the image file is available.",
- "",
- "`align`: \"top\", \"middle\", \"bottom\", \"left\", \"center\", or \"right\"",
- "The alignment of the image, equivalent to the HTML `` tag's",
- "deprecated \"align\" attribute or the corresponding \"vertical-align\" and",
- "\"text-align\" CSS properties.",
- "The values \"top\", \"middle\", and \"bottom\"",
- "control an image's vertical alignment (relative to the text",
- "baseline); they are only useful for inline images (substitutions).",
- "The values \"left\", \"center\", and \"right\" control an image's",
- "horizontal alignment, allowing the image to float and have the",
- "text flow around it. The specific behavior depends upon the",
- "browser or rendering software used.",
- "",
- "`target`: text (URI or reference name)",
- "Makes the image into a hyperlink reference (\"clickable\"). The",
- "option argument may be a URI (relative or absolute), or a",
- "[reference name](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names) with underscore suffix (e.g. ``a name`_`).",
- "",
- "and the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name)."
- ],
- "options": {
- "alt": "text\nAlternate text: a short description of the image, displayed by\napplications that cannot display images, or spoken by applications\nfor visually impaired users.\n",
- "height": "[length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units)\nThe desired height of the image.\nUsed to reserve space or scale the image vertically. When the \"scale\"\noption is also specified, they are combined. For example, a height of\n200px and a scale of 50 is equivalent to a height of 100px with no scale.\n",
- "width": "[length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units) of the current line width\nThe width of the image.\nUsed to reserve space or scale the image horizontally. As with \"height\"\nabove, when the \"scale\" option is also specified, they are combined.\n",
- "scale": "integer percentage (the \"%\" symbol is optional)\nThe uniform scaling factor of the image. The default is \"100\u00a0%\", i.e.\nno scaling.\n\nIf no \"height\" or \"width\" options are specified, the Python\nImaging Library (PIL/[Pillow](https://pypi.org/project/Pillow/)) may be used to determine them, if\nit is installed and the image file is available.\n",
- "align": "\"top\", \"middle\", \"bottom\", \"left\", \"center\", or \"right\"\nThe alignment of the image, equivalent to the HTML `` tag's\ndeprecated \"align\" attribute or the corresponding \"vertical-align\" and\n\"text-align\" CSS properties.\nThe values \"top\", \"middle\", and \"bottom\"\ncontrol an image's vertical alignment (relative to the text\nbaseline); they are only useful for inline images (substitutions).\nThe values \"left\", \"center\", and \"right\" control an image's\nhorizontal alignment, allowing the image to float and have the\ntext flow around it. The specific behavior depends upon the\nbrowser or rendering software used.\n",
- "target": "text (URI or reference name)\nMakes the image into a hyperlink reference (\"clickable\"). The\noption argument may be a URI (relative or absolute), or a\n[reference name](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names) with underscore suffix (e.g. ``a name`_`).\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#image",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "important(docutils.parsers.rst.directives.admonitions.Important)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#important",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "include(docutils.parsers.rst.directives.misc.Include)": {
- "is_markdown": true,
- "description": [
- "## Including an External Document Fragment",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"include\" |",
- "| Doctree Elements | Depend on data being included",
- "([literal_block](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#literal-block) with `code` or `literal` option). |",
- "| Directive Arguments | One, required (path to the file to include). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | None. |",
- "| Configuration Setting | [file_insertion_enabled](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#file-insertion-enabled) |",
- "",
- "The \"include\" directive represents a potential security hole. It",
- "can be disabled with the \"[file_insertion_enabled](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#file-insertion-enabled)\" runtime setting.",
- "",
- "The \"include\" directive reads a text file. The directive argument is",
- "the path to the file to be included, relative to the document containing",
- "the directive. Unless the options `literal`, `code`, or `parser`",
- "are given, the file is parsed in the current document's context at the",
- "point of the directive. For example:",
- "",
- "```",
- "This first example will be parsed at the document level, and can",
- "thus contain any construct, including section headers.",
- "",
- ".. include:: inclusion.txt",
- "",
- "Back in the main document.",
- "",
- " This second example will be parsed in a block quote context.",
- " Therefore it may only contain body elements. It may not",
- " contain section headers.",
- "",
- " .. include:: inclusion.txt",
- "```",
- "",
- "If an included document fragment contains section structure, the title",
- "adornments must match those of the master document.",
- "",
- "Standard data files intended for inclusion in reStructuredText",
- "documents are distributed with the Docutils source code, located in",
- "the \"docutils\" package in the `docutils/parsers/rst/include`",
- "directory. To access these files, use the special syntax for standard",
- "\"include\" data files, angle brackets around the file name:",
- "",
- "```",
- ".. include:: ",
- "```",
- "",
- "The current set of standard \"include\" data files consists of sets of",
- "substitution definitions. See [reStructuredText Standard Definition",
- "Files](https:/docutils.sourceforge.io/docs/ref/rst/definitions.html) for details.",
- "",
- "The following options are recognized:",
- "",
- "`start-line`: integer",
- "Only the content starting from this line will be included.",
- "(As usual in Python, the first line has index 0 and negative values",
- "count from the end.)",
- "",
- "`end-line`: integer",
- "Only the content up to (but excluding) this line will be included.",
- "",
- "`start-after`: text to find in the external data file",
- "Only the content after the first occurrence of the specified text",
- "will be included.",
- "",
- "`end-before`: text to find in the external data file",
- "Only the content before the first occurrence of the specified text",
- "(but after any `after` text) will be included.",
- "",
- "`parser`: parser name",
- "Parse the included content with the specified parser.",
- "(New in Docutils 0.17)",
- "",
- "`literal`: flag (empty)",
- "The entire included text is inserted into the document as a single",
- "literal block.",
- "",
- "`code`: [string] (formal language)",
- "The argument and the included content are passed to",
- "the [code](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#code) directive (useful for program listings).",
- "",
- "`number-lines`: [integer] (start line number)",
- "Precede every code line with a line number.",
- "The optional argument is the number of the first line (default 1).",
- "Works only with `code` or `literal`.",
- "",
- "`encoding`: string",
- "The text encoding of the external data file. Defaults to the",
- "document's [input_encoding](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#input-encoding).",
- "",
- "`tab-width`: integer",
- "Number of spaces for hard tab expansion.",
- "A negative value prevents expansion of hard tabs. Defaults to the",
- "[tab_width](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#tab-width) configuration setting.",
- "",
- "With `code` or `literal` the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and",
- "[name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) are recognized as well.",
- "",
- "Combining `start/end-line` and `start-after/end-before` is possible. The",
- "text markers will be searched in the specified lines (further limiting the",
- "included content)."
- ],
- "options": {
- "start-line": "integer\nOnly the content starting from this line will be included.\n(As usual in Python, the first line has index 0 and negative values\ncount from the end.)\n",
- "end-line": "integer\nOnly the content up to (but excluding) this line will be included.\n",
- "start-after": "text to find in the external data file\nOnly the content after the first occurrence of the specified text\nwill be included.\n",
- "end-before": "text to find in the external data file\nOnly the content before the first occurrence of the specified text\n(but after any `after` text) will be included.\n",
- "parser": "parser name\nParse the included content with the specified parser.\n(New in Docutils 0.17)\n",
- "literal": "flag (empty)\nThe entire included text is inserted into the document as a single\nliteral block.\n",
- "code": "[string] (formal language)\nThe argument and the included content are passed to\nthe [code](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#code) directive (useful for program listings).\n",
- "number-lines": "[integer] (start line number)\nPrecede every code line with a line number.\nThe optional argument is the number of the first line (default 1).\nWorks only with `code` or `literal`.\n",
- "encoding": "string\nThe text encoding of the external data file. Defaults to the\ndocument's [input_encoding](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#input-encoding).\n",
- "tab-width": "integer\nNumber of spaces for hard tab expansion.\nA negative value prevents expansion of hard tabs. Defaults to the\n[tab_width](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#tab-width) configuration setting.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#include",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "line-block(docutils.parsers.rst.directives.body.LineBlock)": {
- "is_markdown": true,
- "description": [
- "## Line Block",
- "## Deprecated",
- "",
- "The \"line-block\" directive is deprecated. Use the [line block",
- "syntax](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#line-blocks) instead.",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"line-block\" |",
- "| Doctree Element | [line_block](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#line-block) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Becomes the body of the line block. |",
- "",
- "The \"line-block\" directive constructs an element where line breaks and",
- "initial indentation is significant and inline markup is supported. It",
- "is equivalent to a [parsed literal block](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#parsed-literal-block) with different rendering:",
- "typically in an ordinary serif typeface instead of a",
- "typewriter/monospaced face, and not automatically indented. (Have the",
- "line-block directive begin a block quote to get an indented line",
- "block.) Line blocks are useful for address blocks and verse (poetry,",
- "song lyrics), where the structure of lines is significant. For",
- "example, here's a classic:",
- "",
- "```",
- "\"To Ma Own Beloved Lassie: A Poem on her 17th Birthday\", by",
- "Ewan McTeagle (for Lassie O'Shea):",
- "",
- " .. line-block::",
- "",
- " Lend us a couple of bob till Thursday.",
- " I'm absolutely skint.",
- " But I'm expecting a postal order and I can pay you back",
- " as soon as it comes.",
- " Love, Ewan.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#line-block",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "list-table(docutils.parsers.rst.directives.tables.ListTable)": {
- "is_markdown": true,
- "description": [
- "## List Table",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"list-table\" |",
- "| Doctree Element | [table](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#table) |",
- "| Directive Arguments | One, optional (table title). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | A uniform two-level bullet list. |",
- "",
- "(This is an initial implementation; [further ideas](https:/docutils.sourceforge.io/docs/ref/rst/../../dev/rst/alternatives.html#list-driven-tables) may be implemented",
- "in the future.)",
- "",
- "The \"list-table\" directive is used to create a table from data in a",
- "uniform two-level bullet list. \"Uniform\" means that each sublist",
- "(second-level list) must contain the same number of list items.",
- "",
- "Example:",
- "",
- "```",
- ".. list-table:: Frozen Delights!",
- " :widths: 15 10 30",
- " :header-rows: 1",
- "",
- " * - Treat",
- " - Quantity",
- " - Description",
- " * - Albatross",
- " - 2.99",
- " - On a stick!",
- " * - Crunchy Frog",
- " - 1.49",
- " - If we took the bones out, it wouldn't be",
- " crunchy, now would it?",
- " * - Gannet Ripple",
- " - 1.99",
- " - On a stick!",
- "```",
- "",
- "The following options are recognized:",
- "",
- "`align`: \"left\", \"center\", or \"right\"",
- "The horizontal alignment of the table.",
- "(New in Docutils 0.13)",
- "",
- "`header-rows`: integer",
- "The number of rows of list data to use in the table header.",
- "Defaults to 0.",
- "",
- "`stub-columns`: integer",
- "The number of table columns to use as stubs (row titles, on the",
- "left). Defaults to 0.",
- "",
- "`width`: [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units)",
- "Sets the width of the table to the specified length or percentage",
- "of the line width. If omitted, the renderer determines the width",
- "of the table based on its contents or the column `widths`.",
- "",
- "`widths`: integer [integer...] or \"auto\"",
- "A list of relative column widths.",
- "The default is equal-width columns (100%/#columns).",
- "",
- "\"auto\" delegates the determination of column widths to the backend",
- "(LaTeX, the HTML browser, ...).",
- "",
- "and the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name)."
- ],
- "options": {
- "align": "\"left\", \"center\", or \"right\"\nThe horizontal alignment of the table.\n(New in Docutils 0.13)\n",
- "header-rows": "integer\nThe number of rows of list data to use in the table header.\nDefaults to 0.\n",
- "stub-columns": "integer\nThe number of table columns to use as stubs (row titles, on the\nleft). Defaults to 0.\n",
- "width": "[length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units)\nSets the width of the table to the specified length or percentage\nof the line width. If omitted, the renderer determines the width\nof the table based on its contents or the column `widths`.\n",
- "widths": "integer [integer...] or \"auto\"\nA list of relative column widths.\nThe default is equal-width columns (100%/#columns).\n\n\"auto\" delegates the determination of column widths to the backend\n(LaTeX, the HTML browser, ...).\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#list-table",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "math(docutils.parsers.rst.directives.body.MathBlock)": {
- "is_markdown": true,
- "description": [
- "## Math",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"math\" |",
- "| Doctree Element | [math_block](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#math-block) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Becomes the body of the math block.",
- "(Content blocks separated by a blank line are put in",
- "adjacent math blocks.) |",
- "| Configuration Setting | [math_output](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#math-output) |",
- "",
- "The \"math\" directive inserts blocks with mathematical content",
- "(display formulas, equations) into the document. The input format is",
- "[LaTeX math syntax](https:/docutils.sourceforge.io/docs/ref/rst/../../ref/rst/mathematics.html) with support for Unicode symbols, for example:",
- "",
- "```",
- ".. math::",
- "",
- " \u03b1_t(i) = P(O_1, O_2, \u2026 O_t, q_t = S_i \u03bb)",
- "```",
- "",
- "Support is limited to a subset of LaTeX math by the conversion",
- "required for many output formats. For HTML, the [math_output](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#math-output)",
- "configuration setting (or the corresponding `--math-output`",
- "command line option) select between alternative output formats with",
- "different subsets of supported elements. If a writer does not",
- "support math typesetting, the content is inserted verbatim.",
- "",
- "For inline formulas, use the [\"math\" role](https:/docutils.sourceforge.io/docs/ref/rst/roles.html#math)."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#math",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "meta(docutils.parsers.rst.directives.html.Meta)": {
- "is_markdown": true,
- "description": [
- "## Metadata",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"meta\" |",
- "| Doctree Element | [meta](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#meta) |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | Must contain a flat field list. |",
- "",
- "The \"meta\" directive is used to specify metadata9 to be stored",
- "in, e.g., [HTML meta elements](https://html.spec.whatwg.org/multipage/semantics.html#the-meta-element) or as [ODT file properties](https://en.wikipedia.org/wiki/OpenDocument_technical_specification#Metadata). The",
- "LaTeX writer passes it to the `pdfinfo` option of the [hyperref](https://ctan.org/pkg/hyperref)",
- "package. If an output format does not support \"invisible\" metadata,",
- "content is silently dropped by the writer.",
- "",
- "Data from some [bibliographic fields](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#bibliographic-fields) is automatically",
- "extracted and stored as metadata, too. However, Bibliographic",
- "Fields are also displayed in the document's screen rendering or",
- "printout.",
- "",
- "For an \"invisible\" document title, see the [metadata document",
- "title](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#metadata-document-title) directive below.",
- "",
- "Within the directive block, a flat field list provides the syntax for",
- "metadata. The field name becomes the contents of the \"name\" attribute",
- "of the META tag, and the field body (interpreted as a single string",
- "without inline markup) becomes the contents of the \"content\"",
- "attribute. For example:",
- "",
- "```",
- ".. meta::",
- " :description: The reStructuredText plaintext markup language",
- " :keywords: plaintext, markup language",
- "```",
- "",
- "This would be converted to the following HTML:",
- "",
- "```",
- "",
- "",
- "```",
- "",
- "Support for other META attributes (\"http-equiv\", \"scheme\", \"lang\",",
- "\"dir\") are provided through field arguments, which must be of the form",
- "\"attr=value\":",
- "",
- "```",
- ".. meta::",
- " :description lang=en: An amusing story",
- " :description lang=fr: Une histoire amusante",
- "```",
- "",
- "And their HTML equivalents:",
- "",
- "```",
- "",
- "",
- "```",
- "",
- "Some META tags use an \"http-equiv\" attribute instead of the \"name\"",
- "attribute. To specify \"http-equiv\" META tags, simply omit the name:",
- "",
- "```",
- ".. meta::",
- " :http-equiv=Content-Type: text/html; charset=ISO-8859-1",
- "```",
- "",
- "HTML equivalent:",
- "",
- "```",
- "",
- "```",
- "9",
- "\"Metadata\" is data about data, in this case data about the",
- "document. Metadata is, e.g., used to describe and classify web",
- "pages in the World Wide Web, in a form that is easy for search",
- "engines to extract and collate."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#metadata",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "title(docutils.parsers.rst.directives.misc.Title)": {
- "is_markdown": true,
- "description": [
- "## Metadata Document Title",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"title\" |",
- "| Doctree Element | Sets the document's [title attribute](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title-attribute). |",
- "| Directive Arguments | One, required (the title text). |",
- "| Directive Options | None. |",
- "| Directive Content | None. |",
- "",
- "The \"title\" directive specifies the document title as metadata, which",
- "does not become part of the document body. It overrides the",
- "document-supplied [document title](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#document-title) and the [\"title\" configuration",
- "setting](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#title). For example, in HTML output the metadata document title",
- "appears in the title bar of the browser window."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#metadata-document-title",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "note(docutils.parsers.rst.directives.admonitions.Note)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#note",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "parsed-literal(docutils.parsers.rst.directives.body.ParsedLiteral)": {
- "is_markdown": true,
- "description": [
- "## Parsed Literal Block",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"parsed-literal\" |",
- "| Doctree Element | [literal_block](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#literal-block) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Becomes the body of the literal block. |",
- "",
- "Unlike an ordinary literal block, the \"parsed-literal\" directive",
- "constructs a literal block where the text is parsed for inline markup.",
- "It is equivalent to a [line block](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#line-block) with different rendering:",
- "typically in a typewriter/monospaced typeface, like an ordinary",
- "literal block. Parsed literal blocks are useful for adding hyperlinks",
- "to code examples.",
- "",
- "However, care must be taken with the text, because inline markup is",
- "recognized and there is no protection from parsing. Backslash-escapes",
- "may be necessary to prevent unintended parsing. And because the",
- "markup characters are removed by the parser, care must also be taken",
- "with vertical alignment. Parsed \"ASCII art\" is tricky, and extra",
- "whitespace may be necessary.",
- "",
- "For example, all the element names in this content model are links:",
- "",
- "```",
- ".. parsed-literal::",
- "",
- " ( (title_, subtitle_?)?,",
- " decoration_?,",
- " (docinfo_, transition_?)?,",
- " `%structure.model;`_ )",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#parsed-literal",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "pull-quote(docutils.parsers.rst.directives.body.PullQuote)": {
- "is_markdown": true,
- "description": [
- "## Pull-Quote",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"pull-quote\" |",
- "| Doctree Element | [block_quote](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#block-quote) |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | Interpreted as the body of the block quote. |",
- "",
- "A pull-quote is a small selection of text \"pulled out and quoted\",",
- "typically in a larger typeface. Pull-quotes are used to attract",
- "attention, especially in long articles.",
- "",
- "The \"pull-quote\" directive produces a \"pull-quote\"-class block quote.",
- "See [Epigraph](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#epigraph) above for an analogous example."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#pull-quote",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "raw(docutils.parsers.rst.directives.misc.Raw)": {
- "is_markdown": true,
- "description": [
- "## Raw Data Pass-Through",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"raw\" |",
- "| Doctree Element | [raw](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#raw) |",
- "| Directive Arguments | One or more, required (output format types). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | Stored verbatim, uninterpreted. None (empty) if a",
- "\"file\" or \"url\" option given. |",
- "| Configuration Setting | [raw_enabled](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#raw-enabled) |",
- "",
- "The \"raw\" directive represents a potential security hole. It can",
- "be disabled with the \"[raw_enabled](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#raw-enabled)\" or \"[file_insertion_enabled](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#file-insertion-enabled)\"",
- "runtime settings.",
- "",
- "The \"raw\" directive is a stop-gap measure allowing the author to",
- "bypass reStructuredText's markup. It is a \"power-user\" feature",
- "that should not be overused or abused. The use of \"raw\" ties",
- "documents to specific output formats and makes them less portable.",
- "",
- "If you often need to use the \"raw\" directive or a \"raw\"-derived",
- "interpreted text role, that is a sign either of overuse/abuse or",
- "that functionality may be missing from reStructuredText. Please",
- "describe your situation in a message to the [Docutils-users](https:/docutils.sourceforge.io/docs/ref/rst/../../user/mailing-lists.html#docutils-users) mailing",
- "list.",
- "",
- "The \"raw\" directive indicates non-reStructuredText data that is to be",
- "passed untouched to the Writer. The names of the output formats are",
- "given in the directive arguments. The interpretation of the raw data",
- "is up to the Writer. A Writer may ignore any raw output not matching",
- "its format.",
- "",
- "For example, the following input would be passed untouched by an HTML",
- "Writer:",
- "",
- "```",
- ".. raw:: html",
- "",
- " ",
- "```",
- "",
- "A LaTeX Writer could insert the following raw content into its",
- "output stream:",
- "",
- "```",
- ".. raw:: latex",
- "",
- " \\setlength{\\parindent}{0pt}",
- "```",
- "",
- "Raw data can also be read from an external file, specified in a",
- "directive option. In this case, the content block must be empty. For",
- "example:",
- "",
- "```",
- ".. raw:: html",
- " :file: inclusion.html",
- "```",
- "",
- "Inline equivalents of the \"raw\" directive can be defined via",
- "[custom interpreted text roles](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#custom-interpreted-text-roles) derived from the [\"raw\" role](https:/docutils.sourceforge.io/docs/ref/rst/roles.html#raw).",
- "",
- "The following options are recognized:",
- "",
- "`file`: string (newlines removed)",
- "The local filesystem path of a raw data file to be included.",
- "",
- "`url`: string (whitespace removed)",
- "An Internet URL reference to a raw data file to be included.",
- "",
- "`encoding`: string",
- "The text encoding of the external raw data (file or URL).",
- "Defaults to the document's encoding (if specified).",
- "",
- "and the common option [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33)."
- ],
- "options": {
- "file": "string (newlines removed)\nThe local filesystem path of a raw data file to be included.\n",
- "url": "string (whitespace removed)\nAn Internet URL reference to a raw data file to be included.\n",
- "encoding": "string\nThe text encoding of the external raw data (file or URL).\nDefaults to the document's encoding (if specified).\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#raw-directive",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "replace(docutils.parsers.rst.directives.misc.Replace)": {
- "is_markdown": true,
- "description": [
- "## Replacement Text",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"replace\" |",
- "| Doctree Element | Text & [inline elements](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#inline-elements) |",
- "| Directive Arguments | None. |",
- "| Directive Options | None. |",
- "| Directive Content | A single paragraph; may contain inline markup. |",
- "",
- "The \"replace\" directive is used to indicate replacement text for a",
- "substitution reference. It may be used within [substitution",
- "definitions](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#substitution-definitions) only. For example, this directive can be used to expand",
- "abbreviations:",
- "",
- "```",
- ".. |reST| replace:: reStructuredText",
- "",
- "Yes, |reST| is a long word, so I can't blame anyone for wanting to",
- "abbreviate it.",
- "```",
- "",
- "As reStructuredText doesn't support nested inline markup, the only way",
- "to create a reference with styled text is to use substitutions with",
- "the \"replace\" directive:",
- "",
- "```",
- "I recommend you try |Python|_.",
- "",
- ".. |Python| replace:: Python, *the* best language around",
- ".. _Python: https://www.python.org/",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#replace",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "role(docutils.parsers.rst.directives.misc.Role)": {
- "is_markdown": true,
- "description": [
- "## Custom Interpreted Text Roles",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"role\" |",
- "| Doctree Element | None; affects subsequent parsing. |",
- "| Directive Arguments | Two; one required (new [role name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#role-name)), one optional",
- "(base role name, in parentheses). |",
- "| Directive Options | Possible (depends on base role). |",
- "| Directive Content | depends on base role. |",
- "",
- "The \"role\" directive dynamically creates a custom [interpreted text",
- "role](https:/docutils.sourceforge.io/docs/ref/rst/roles.html) and registers it with the parser. This means that after",
- "declaring a role like this:",
- "",
- "```",
- ".. role:: custom",
- "```",
- "",
- "the document may use the new \"custom\" role:",
- "",
- "```",
- "An example of using :custom:`interpreted text`",
- "```",
- "",
- "This will be parsed into the following document tree fragment:",
- "",
- "```",
- "",
- " An example of using",
- " ",
- " interpreted text",
- "```",
- "",
- "The role must be declared in a document before it can be used.",
- "",
- "Role names are case insensitive and must conform to the rules of",
- "simple [reference names](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#reference-names) (but do not share a namespace with",
- "hyperlinks, footnotes, and citations).",
- "",
- "The new role may be based on an existing role, specified as a second",
- "argument in parentheses (whitespace optional):",
- "",
- "```",
- ".. role:: custom(emphasis)",
- "",
- ":custom:`text`",
- "```",
- "",
- "The parsed result is as follows:",
- "",
- "```",
- "",
- " ",
- " text",
- "```",
- "",
- "A special case is the [\"raw\" role](https:/docutils.sourceforge.io/docs/ref/rst/roles.html#raw): derived roles enable",
- "inline [raw data pass-through](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#raw-data-pass-through), e.g.:",
- "",
- "```",
- ".. role:: raw-role(raw)",
- " :format: html latex",
- "",
- ":raw-role:`raw text`",
- "```",
- "",
- "If no base role is explicitly specified, a generic custom role is",
- "automatically used. Subsequent interpreted text will produce an",
- "\"inline\" element with a [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute, as in the first example",
- "above.",
- "",
- "With most roles, the \":class:\" option can be used to set a \"classes\"",
- "attribute that is different from the role name. For example:",
- "",
- "```",
- ".. role:: custom",
- " :class: special",
- "",
- ":custom:`interpreted text`",
- "```",
- "",
- "This is the parsed result:",
- "",
- "```",
- "",
- " ",
- " interpreted text",
- "```",
- "",
- "The following option is recognized by the \"role\" directive for most",
- "base roles:",
- "",
- "`class`: text",
- "Set the [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute value on the element produced",
- "(`inline`, or element associated with a base class) when the",
- "custom interpreted text role is used. If no directive options are",
- "specified, a \"class\" option with the directive argument (role",
- "name) as the value is implied. See the [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) directive above.",
- "",
- "Specific base roles may support other options and/or directive",
- "content. See the [reStructuredText Interpreted Text Roles](https:/docutils.sourceforge.io/docs/ref/rst/roles.html) document",
- "for details."
- ],
- "options": {
- "class": "text\nSet the [\"classes\"](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#classes) attribute value on the element produced\n(`inline`, or element associated with a base class) when the\ncustom interpreted text role is used. If no directive options are\nspecified, a \"class\" option with the directive argument (role\nname) as the value is implied. See the [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) directive above.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#role",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "rubric(docutils.parsers.rst.directives.body.Rubric)": {
- "is_markdown": true,
- "description": [
- "## Rubric",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"rubric\" |",
- "| Doctree Element | [rubric](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#rubric) |",
- "| Directive Arguments | One, required (rubric text). |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | None. |",
- "",
- "rubric n. 1. a title, heading, or the like, in a manuscript,",
- "book, statute, etc., written or printed in red or otherwise",
- "distinguished from the rest of the text. ...",
- "Random House Webster's College Dictionary, 1991",
- "The \"rubric\" directive inserts a \"rubric\" element into the document",
- "tree. A rubric is like an informal heading that doesn't correspond to",
- "the document's structure."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#rubric",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "sidebar(docutils.parsers.rst.directives.body.Sidebar)": {
- "is_markdown": true,
- "description": [
- "## Sidebar",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"sidebar\" |",
- "| Doctree Element | [sidebar](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#sidebar) |",
- "| Directive Arguments | One, optional (sidebar title). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | Interpreted as the sidebar body. |",
- "",
- "Sidebars are like miniature, parallel documents that occur inside",
- "other documents, providing related or reference material. A sidebar",
- "is typically offset by a border and \"floats\" to the side of the page;",
- "the document's main text may flow around it. Sidebars can also be",
- "likened to super-footnotes; their content is outside of the flow of",
- "the document's main text.",
- "",
- "Sidebars may occur anywhere a section or transition may occur. Body",
- "elements (including sidebars) may not contain nested sidebars.",
- "",
- "The directive's sole argument is interpreted as the sidebar title,",
- "which may be followed by a subtitle option (see below); the next line",
- "must be blank. All subsequent lines make up the sidebar body,",
- "interpreted as body elements. For example:",
- "",
- "```",
- ".. sidebar:: Optional Sidebar Title",
- " :subtitle: Optional Sidebar Subtitle",
- "",
- " Subsequent indented lines comprise",
- " the body of the sidebar, and are",
- " interpreted as body elements.",
- "```",
- "",
- "The following options are recognized:",
- "",
- "`subtitle`: text",
- "The sidebar's subtitle.",
- "",
- "and the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name)."
- ],
- "options": {
- "subtitle": "text\nThe sidebar's subtitle.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#sidebar",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "table(docutils.parsers.rst.directives.tables.RSTTable)": {
- "is_markdown": true,
- "description": [
- "## Table",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"table\" |",
- "| Doctree Element | [table](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#table) |",
- "| Directive Arguments | One, optional (table title). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | A normal [reStructuredText table](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#tables). |",
- "",
- "The \"table\" directive is used to associate a",
- "title with a table or specify options, e.g.:",
- "",
- "```",
- ".. table:: Truth table for \"not\"",
- " :widths: auto",
- "",
- " ===== =====",
- " A not A",
- " ===== =====",
- " False True",
- " True False",
- " ===== =====",
- "```",
- "",
- "The following options are recognized:",
- "",
- "`align`: \"left\", \"center\", or \"right\"",
- "The horizontal alignment of the table (new in Docutils 0.13).",
- "",
- "`width`: [length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units)",
- "Sets the width of the table to the specified length or percentage",
- "of the line width. If omitted, the renderer determines the width",
- "of the table based on its contents or the column `widths`.",
- "",
- "`widths`: \"auto\", \"grid\", or a list of integers",
- "A list of relative column widths.",
- "The default is the width of the input columns (in characters).",
- "",
- "\"auto\" delegates the determination of column widths to the backend",
- "(LaTeX, the HTML browser, ...).",
- "",
- "\"grid\" restores the default, overriding a [table_style](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#table-style) or class",
- "value \"colwidths-auto\".",
- "",
- "Plus the common options [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33) and [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name)."
- ],
- "options": {
- "align": "\"left\", \"center\", or \"right\"\nThe horizontal alignment of the table (new in Docutils 0.13).\n",
- "width": "[length](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#length-units) or [percentage](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#percentage-units)\nSets the width of the table to the specified length or percentage\nof the line width. If omitted, the renderer determines the width\nof the table based on its contents or the column `widths`.\n",
- "widths": "\"auto\", \"grid\", or a list of integers\nA list of relative column widths.\nThe default is the width of the input columns (in characters).\n\n\"auto\" delegates the determination of column widths to the backend\n(LaTeX, the HTML browser, ...).\n\n\"grid\" restores the default, overriding a [table_style](https:/docutils.sourceforge.io/docs/ref/rst/../../user/config.html#table-style) or class\nvalue \"colwidths-auto\".\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#table",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "tip(docutils.parsers.rst.directives.admonitions.Tip)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#tip",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "topic(docutils.parsers.rst.directives.body.Topic)": {
- "is_markdown": true,
- "description": [
- "## Topic",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"topic\" |",
- "| Doctree Element | [topic](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#topic) |",
- "| Directive Arguments | One, required (topic title). |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as the topic body. |",
- "",
- "A topic is like a block quote with a title, or a self-contained",
- "section with no subsections. Use the \"topic\" directive to indicate a",
- "self-contained idea that is separate from the flow of the document.",
- "Topics may occur anywhere a section or transition may occur. Body",
- "elements and topics may not contain nested topics.",
- "",
- "The directive's sole argument is interpreted as the topic title; the",
- "next line must be blank. All subsequent lines make up the topic body,",
- "interpreted as body elements. For example:",
- "",
- "```",
- ".. topic:: Topic Title",
- "",
- " Subsequent indented lines comprise",
- " the body of the topic, and are",
- " interpreted as body elements.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#topic",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "unicode(docutils.parsers.rst.directives.misc.Unicode)": {
- "is_markdown": true,
- "description": [
- "## Unicode Character Codes",
- "",
- "| | |",
- "|-|-|",
- "| Directive Type | \"unicode\" |",
- "| Doctree Element | Text |",
- "| Directive Arguments | One or more, required (Unicode character codes,",
- "optional text, and comments). |",
- "| Directive Options | Possible (see below). |",
- "| Directive Content | None. |",
- "",
- "The \"unicode\" directive converts Unicode character codes (numerical",
- "values) to characters, and may be used in [substitution definitions](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#substitution-definitions)",
- "only.",
- "",
- "The arguments, separated by spaces, can be:",
- "- character codes as",
- "- decimal numbers or",
- "- hexadecimal numbers, prefixed by `0x`, `x`, `\\x`, `U+`,",
- "`u`, or `\\u` or as XML-style hexadecimal character entities,",
- "e.g. `ᨫ`",
- "- text, which is used as-is.",
- "",
- "Text following \" .. \" is a comment and is ignored. The spaces between",
- "the arguments are ignored and thus do not appear in the output.",
- "Hexadecimal codes are case-insensitive.",
- "",
- "For example, the following text:",
- "",
- "```",
- "Copyright |copy| 2003, |BogusMegaCorp (TM)| |---|",
- "all rights reserved.",
- "",
- ".. |copy| unicode:: 0xA9 .. copyright sign",
- ".. |BogusMegaCorp (TM)| unicode:: BogusMegaCorp U+2122",
- " .. with trademark sign",
- ".. |---| unicode:: U+02014 .. em dash",
- " :trim:",
- "```",
- "",
- "results in:",
- "",
- "Copyright \u00a9 2003, BogusMegaCorp\u2122\u2014all rights reserved.",
- "\u00a9BogusMegaCorp\u2122\u2014",
- "The following options are recognized:",
- "",
- "`ltrim`: flag (empty)",
- "Whitespace to the left of the substitution reference is removed.",
- "",
- "`rtrim`: flag (empty)",
- "Whitespace to the right of the substitution reference is removed.",
- "",
- "`trim`: flag (empty)",
- "Equivalent to `ltrim` plus `rtrim`; whitespace on both sides",
- "of the substitution reference is removed."
- ],
- "options": {
- "ltrim": "flag (empty)\nWhitespace to the left of the substitution reference is removed.\n",
- "rtrim": "flag (empty)\nWhitespace to the right of the substitution reference is removed.\n",
- "trim": "flag (empty)\nEquivalent to `ltrim` plus `rtrim`; whitespace on both sides\nof the substitution reference is removed.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#unicode",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "warning(docutils.parsers.rst.directives.admonitions.Warning)": {
- "is_markdown": true,
- "description": [
- "## Specific Admonitions",
- "",
- "| | |",
- "|-|-|",
- "| Directive Types | \"attention\", \"caution\", \"danger\", \"error\", \"hint\",",
- "\"important\", \"note\", \"tip\", \"warning\", \"admonition\" |",
- "| Doctree Elements | attention, caution, danger, error, hint, important,",
- "note, tip, warning, [admonition](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#admonition), [title](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#title) |",
- "| Directive Arguments | None. |",
- "| Directive Options | [class](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#id33), [name](https://docutils.sourceforge.io/docs/ref/rst/directives.txt#name) |",
- "| Directive Content | Interpreted as body elements. |",
- "",
- "Admonitions are specially marked \"topics\" that can appear anywhere an",
- "ordinary body element can. They contain arbitrary body elements.",
- "Typically, an admonition is rendered as an offset block in a document,",
- "sometimes outlined or shaded, with a title matching the admonition",
- "type. For example:",
- "",
- "```",
- ".. DANGER::",
- " Beware killer rabbits!",
- "```",
- "",
- "This directive might be rendered something like this:",
- "",
- "```",
- "+------------------------+",
- "| !DANGER! |",
- "| |",
- "| Beware killer rabbits! |",
- "+------------------------+",
- "```",
- "",
- "The following admonition directives have been implemented:",
- "- attention",
- "- caution",
- "- danger",
- "- error",
- "- hint",
- "- important",
- "- note",
- "- tip",
- "- warning",
- "",
- "Any text immediately following the directive indicator (on the same",
- "line and/or indented on following lines) is interpreted as a directive",
- "block and is parsed for normal body elements. For example, the",
- "following \"note\" admonition directive contains one paragraph and a",
- "bullet list consisting of two list items:",
- "",
- "```",
- ".. note:: This is a note admonition.",
- " This is the second line of the first paragraph.",
- "",
- " - The note contains all indented body elements",
- " following.",
- " - It includes this bullet list.",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/directives.html#warning",
- "license": "https://docutils.sourceforge.io/docs/"
- }
-}
diff --git a/lib/esbonio/esbonio/lsp/rst/directives.py b/lib/esbonio/esbonio/lsp/rst/directives.py
deleted file mode 100644
index 9b1b9e61d..000000000
--- a/lib/esbonio/esbonio/lsp/rst/directives.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import importlib
-import json
-from typing import Dict
-from typing import Optional
-from typing import Tuple
-from typing import Type
-from typing import Union
-
-from docutils.parsers.rst import Directive
-from docutils.parsers.rst import directives as docutils_directives
-
-from esbonio.lsp.directives import DirectiveLanguageFeature
-from esbonio.lsp.directives import Directives
-from esbonio.lsp.util import resources
-
-
-class Docutils(DirectiveLanguageFeature):
- """Support for docutils' built-in directives."""
-
- def __init__(self) -> None:
- self._directives: Optional[Dict[str, Type[Directive]]] = None
- """Cache for known directives."""
-
- @property
- def directives(self) -> Dict[str, Type[Directive]]:
- if self._directives is not None:
- return self._directives
-
- ignored_directives = ["restructuredtext-test-directive"]
- found_directives = {
- **docutils_directives._directive_registry,
- **docutils_directives._directives,
- }
-
- self._directives = {
- k: resolve_directive(v)
- for k, v in found_directives.items()
- if k not in ignored_directives
- }
-
- return self._directives
-
- def get_implementation(self, directive: str, domain: Optional[str]):
- if domain:
- return None
-
- return self.directives.get(directive, None)
-
- def index_directives(self) -> Dict[str, Type[Directive]]:
- return self.directives
-
-
-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)``
- so they need to be resolved manually.
- """
-
- if isinstance(directive, tuple):
- mod, cls = directive
-
- modulename = f"docutils.parsers.rst.directives.{mod}"
- module = importlib.import_module(modulename)
- return getattr(module, cls)
-
- return directive
-
-
-def esbonio_setup(directives: Directives):
- documentation = resources.read_string("esbonio.lsp.rst", "directives.json")
-
- directives.add_documentation(json.loads(documentation))
- directives.add_feature(Docutils())
diff --git a/lib/esbonio/esbonio/lsp/rst/io.py b/lib/esbonio/esbonio/lsp/rst/io.py
deleted file mode 100644
index 054438940..000000000
--- a/lib/esbonio/esbonio/lsp/rst/io.py
+++ /dev/null
@@ -1,222 +0,0 @@
-import logging
-import typing
-from typing import IO
-from typing import Any
-from typing import Callable
-from typing import Optional
-from typing import Type
-
-import pygls.uris as uri
-from docutils import nodes
-from docutils.core import Publisher
-from docutils.io import NullOutput
-from docutils.io import StringInput
-from docutils.parsers.rst import Directive
-from docutils.parsers.rst import Parser
-from docutils.parsers.rst import directives
-from docutils.parsers.rst import roles
-from docutils.readers.standalone import Reader
-from docutils.utils import Reporter
-from docutils.writers import Writer
-from pygls.workspace import Document
-from sphinx.environment import default_settings
-
-from esbonio.lsp.util.patterns import DIRECTIVE
-from esbonio.lsp.util.patterns import ROLE
-
-
-class a_directive(nodes.Element, nodes.Inline):
- """Represents a directive."""
-
-
-class a_role(nodes.Element):
- """Represents a role."""
-
-
-def dummy_role(name, rawtext, text, lineno, inliner, options={}, content=[]):
- node = a_role()
- node.line = lineno
-
- match = ROLE.match(rawtext)
- if match is None:
- node.attributes["text"] = rawtext
- else:
- node.attributes.update(match.groupdict())
- node.attributes["text"] = match.group(0)
-
- return [node], []
-
-
-class DummyDirective(Directive):
- has_content = True
-
- def run(self):
- node = a_directive()
- node.line = self.lineno
- parent = self.state.parent
- lines = self.block_text
-
- # substitution definitions require special handling
- if isinstance(parent, nodes.substitution_definition):
- lines = parent.rawsource
-
- text = lines.split("\n")[0]
- match = DIRECTIVE.match(text)
- if match:
- node.attributes.update(match.groupdict())
- node.attributes["text"] = match.group(0)
- else:
- self.state.reporter.warning(f"Unable to parse directive: '{text}'")
- node.attributes["text"] = text
-
- if self.content:
- # This is essentially what `nested_parse_with_titles` does in Sphinx.
- # But by passing the content_offset to state.nested_parse we ensure any line
- # numbers remain relative to the start of the current file.
- current_titles = self.state.memo.title_styles
- current_sections = self.state.memo.section_level
- self.state.memo.title_styles = []
- self.state.memo.section_level = 0
- try:
- self.state.nested_parse(
- self.content, self.content_offset, node, match_titles=1
- )
- finally:
- self.state.memo.title_styles = current_titles
- self.state.memo.section_level = current_sections
-
- return [node]
-
-
-class disable_roles_and_directives:
- """Disables all roles and directives from being expanded.
-
- The ``CustomReSTDispactcher`` from Sphinx is *very* cool.
- It provides a way to override the mechanism used to lookup roles and directives
- during parsing!
-
- It's perfect for temporarily replacing all role and directive implementations with
- dummy ones. Parsing an rst document with these dummy implementations effectively
- gives us something that could be called an abstract syntax tree.
-
- Unfortunately, it's only available in a relatively recent version of Sphinx (4.4)
- so we have to implement the same idea ourselves for now.
- """
-
- def __init__(self) -> None:
- self.directive_backup: Optional[Callable] = None
- self.role_backup: Optional[Callable] = None
-
- def __enter__(self) -> None:
- self.directive_backup = directives.directive
- self.role_backup = roles.role
-
- directives.directive = self.directive
- roles.role = self.role
-
- def __exit__(self, exc_type: Type[Exception], exc_value: Exception, traceback: Any):
- directives.directive = self.directive_backup # type: ignore
- roles.role = self.role_backup # type: ignore
-
- self.directive_backup = None
- self.role_backup = None
-
- def directive(self, directive_name, language_module, document):
- return DummyDirective, []
-
- def role(self, role_name, language_module, lineno, reporter):
- return dummy_role, []
-
-
-class DummyWriter(Writer):
- """A writer that doesn't do anything."""
-
- def translate(self):
- pass
-
-
-class LogStream:
- def __init__(self, logger: logging.Logger):
- self.logger = logger
-
- def write(self, text: str):
- self.logger.debug(text)
-
-
-class LogReporter(Reporter):
- """A docutils reporter that writes to the given logger."""
-
- def __init__(
- self,
- logger: logging.Logger,
- source: str,
- report_level: int,
- halt_level: int,
- debug: bool,
- error_handler: str,
- ) -> None:
- stream = typing.cast(IO, LogStream(logger))
- super().__init__(
- source, report_level, halt_level, stream, debug, error_handler=error_handler
- ) # type: ignore
-
-
-class InitialDoctreeReader(Reader):
- """A reader that replaces the default reporter with one compatible with esbonio's
- logging setup."""
-
- def __init__(self, logger: logging.Logger, *args, **kwargs):
- self.logger = logger
- super().__init__(*args, **kwargs)
-
- def new_document(self) -> nodes.document:
- document = super().new_document()
-
- reporter = document.reporter
- document.reporter = LogReporter(
- self.logger,
- reporter.source,
- reporter.report_level,
- reporter.halt_level,
- reporter.debug_flag,
- reporter.error_handler,
- )
-
- return document
-
-
-def read_initial_doctree(
- document: Document, logger: logging.Logger
-) -> Optional[nodes.document]:
- """Parse the given reStructuredText document into its "initial" doctree.
-
- An "initial" doctree can be thought of as the abstract syntax tree of a
- reStructuredText document. This method disables all role and directives
- from being executed, instead they are replaced with nodes that simply
- represent that they exist.
-
- Parameters
- ----------
- document
- The document containing the reStructuredText source.
-
- logger
- Logger to log debug info to.
- """
-
- parser = Parser()
- with disable_roles_and_directives():
- publisher = Publisher(
- reader=InitialDoctreeReader(logger),
- parser=parser,
- writer=DummyWriter(),
- source_class=StringInput,
- destination=NullOutput(),
- )
- publisher.process_programmatic_settings(None, default_settings, None)
- publisher.set_source(
- source=document.source, source_path=uri.to_fs_path(document.uri)
- )
- publisher.publish()
-
- return publisher.document
diff --git a/lib/esbonio/esbonio/lsp/rst/roles.json b/lib/esbonio/esbonio/lsp/rst/roles.json
deleted file mode 100644
index 23b69b1a8..000000000
--- a/lib/esbonio/esbonio/lsp/rst/roles.json
+++ /dev/null
@@ -1,448 +0,0 @@
-{
- "code(docutils.parsers.rst.roles.code_role)": {
- "is_markdown": true,
- "description": [
- "## `:code:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | None |",
- "| DTD Element | literal |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class), language |",
- "| Content | None. |",
- " |",
- "",
- "(New in Docutils 0.9.)",
- "",
- "The `code` role marks its content as code in a formal language.",
- "",
- "For syntax highlight of inline code, the [\"role\" directive](https:/docutils.sourceforge.io/docs/ref/rst/directives.html#role) can be used to",
- "build custom roles with the code language specified in the \"language\"",
- "option.",
- "",
- "For example, the following creates a LaTeX-specific \"latex\" role:",
- "",
- "```",
- ".. role:: latex(code)",
- " :language: latex",
- "```",
- "",
- "Content of the new role is parsed and tagged by the [Pygments](https://pygments.org/) syntax",
- "highlighter. See the [code directive](https:/docutils.sourceforge.io/docs/ref/rst/directives.html#code) for more info on parsing and display",
- "of code in reStructuredText.",
- "",
- "In addition to \"[class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class)\", the following option is recognized:",
- "",
- "`language`: text",
- "Name of the code's language.",
- "See [supported languages and markup formats](https://pygments.org/languages/) for recognized values."
- ],
- "options": {
- "language": "text\nName of the code's language.\nSee [supported languages and markup formats](https://pygments.org/languages/) for recognized values.\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#code",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "emphasis(docutils.parsers.rst.roles.GenericRole)": {
- "is_markdown": true,
- "description": [
- "## `:emphasis:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | None |",
- "| DTD Element | emphasis |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "Implements emphasis. These are equivalent:",
- "",
- "```",
- "*text*",
- ":emphasis:`text`",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#emphasis",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "literal(docutils.parsers.rst.roles.GenericRole)": {
- "is_markdown": true,
- "description": [
- "## `:literal:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | None |",
- "| DTD Element | literal |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "Implements inline literal text. These are equivalent:",
- "",
- "```",
- "``text``",
- ":literal:`text`",
- "```",
- "",
- "Care must be taken with backslash-escapes though. These are not",
- "equivalent:",
- "",
- "```",
- "``text \\ and \\ backslashes``",
- ":literal:`text \\ and \\ backslashes`",
- "```",
- "",
- "The backslashes in the first line are preserved (and do nothing),",
- "whereas the backslashes in the second line escape the following",
- "spaces."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#literal",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "math(docutils.parsers.rst.roles.math_role)": {
- "is_markdown": true,
- "description": [
- "## `:math:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | None |",
- "| DTD Element | math |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class) |",
- "| Content | None. |",
- " |",
- "",
- "(New in Docutils 0.8.)",
- "",
- "The `math` role marks its content as mathematical notation (inline",
- "formula).",
- "",
- "The input format is LaTeX math syntax without the \u201cmath delimiters\u201c",
- "(`$ $`), for example:",
- "",
- "```",
- "The area of a circle is :math:`A_\\text{c} = (\\pi/4) d^2`.",
- "```",
- "",
- "See the [math directive](https:/docutils.sourceforge.io/docs/ref/rst/directives.html#math) (producing display formulas) for more info",
- "on mathematical notation in reStructuredText."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#math",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "pep-reference(docutils.parsers.rst.roles.pep_reference_role)": {
- "is_markdown": true,
- "description": [
- "## `:pep-reference:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | `:PEP:` |",
- "| DTD Element | reference |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "The `:pep-reference:` role is used to create an HTTP reference to a",
- "PEP (Python Enhancement Proposal). The `:PEP:` alias is usually",
- "used. The content must be a number, for example:",
- "",
- "```",
- "See :PEP:`287` for more information about reStructuredText.",
- "```",
- "",
- "This is equivalent to:",
- "",
- "```",
- "See `PEP 287`__ for more information about reStructuredText.",
- "",
- "__ https://www.python.org/dev/peps/pep-0287",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#pep-reference",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "raw(docutils.parsers.rst.roles.raw_role)": {
- "is_markdown": true,
- "description": [
- "## `raw`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | None |",
- "| DTD Element | raw |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class), format |",
- "| Content | None |",
- " |",
- "",
- "The \"raw\" role is a stop-gap measure allowing the author to bypass",
- "reStructuredText's markup. It is a \"power-user\" feature that",
- "should not be overused or abused. The use of \"raw\" ties documents",
- "to specific output formats and makes them less portable.",
- "",
- "If you often need to use \"raw\"-derived interpreted text roles or",
- "the \"raw\" directive, that is a sign either of overuse/abuse or that",
- "functionality may be missing from reStructuredText. Please",
- "describe your situation in a message to the [Docutils-users](https:/docutils.sourceforge.io/docs/ref/rst/../../user/mailing-lists.html#docutils-user) mailing",
- "list.",
- "",
- "The \"raw\" role indicates non-reStructuredText data that is to be",
- "passed untouched to the Writer. It is the inline equivalent of the",
- "[\"raw\" directive](https:/docutils.sourceforge.io/docs/ref/rst/directives.html#raw-directive); see its documentation for details on the",
- "semantics.",
- "",
- "The \"raw\" role cannot be used directly. The [\"role\" directive](https:/docutils.sourceforge.io/docs/ref/rst/directives.html#role) must",
- "first be used to build custom roles based on the \"raw\" role. One or",
- "more formats (Writer names) must be provided in a \"format\" option.",
- "",
- "For example, the following creates an HTML-specific \"raw-html\" role:",
- "",
- "```",
- ".. role:: raw-html(raw)",
- " :format: html",
- "```",
- "",
- "This role can now be used directly to pass data untouched to the HTML",
- "Writer. For example:",
- "",
- "```",
- "If there just *has* to be a line break here,",
- ":raw-html:` `",
- "it can be accomplished with a \"raw\"-derived role.",
- "But the line block syntax should be considered first.",
- "```",
- "",
- "Roles based on \"raw\" should clearly indicate their origin, so",
- "they are not mistaken for reStructuredText markup. Using a \"raw-\"",
- "prefix for role names is recommended.",
- "",
- "In addition to \"[class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class)\", the following option is recognized:",
- "",
- "`format`: text",
- "One or more space-separated output format names (Writer names)."
- ],
- "options": {
- "format": "text\nOne or more space-separated output format names (Writer names).\n"
- },
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#raw",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "rfc-reference(docutils.parsers.rst.roles.rfc_reference_role)": {
- "is_markdown": true,
- "description": [
- "## `:rfc-reference:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | `:RFC:` |",
- "| DTD Element | reference |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "The `:rfc-reference:` role is used to create an HTTP reference to an",
- "RFC (Internet Request for Comments). The `:RFC:` alias is usually",
- "used. The content must be a number 1, for example:",
- "",
- "```",
- "See :RFC:`2822` for information about email headers.",
- "```",
- "",
- "This is equivalent to:",
- "",
- "```",
- "See `RFC 2822`__ for information about email headers.",
- "",
- "__ https://tools.ietf.org/html/rfc2822.html",
- "```",
- "1",
- "You can link to a specific section by saying",
- "`:rfc:`number#anchor``. (New in Docutils 0.15.)",
- "",
- "The anchor (anything following a `#`) is appended to",
- "the reference without any checks and not shown in the link text.",
- "",
- "It is recommended to use [hyperlink references](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#hyperlink-references) for",
- "anything more complex than a single RFC number."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#rfc-reference",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "strong(docutils.parsers.rst.roles.GenericRole)": {
- "is_markdown": true,
- "description": [
- "## `:strong:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | None |",
- "| DTD Element | strong |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "Implements strong emphasis. These are equivalent:",
- "",
- "```",
- "**text**",
- ":strong:`text`",
- "```"
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#strong",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "subscript(docutils.parsers.rst.roles.GenericRole)": {
- "is_markdown": true,
- "description": [
- "## `:subscript:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | `:sub:` |",
- "| DTD Element | subscript |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "Implements subscripts.",
- "",
- "Whitespace or punctuation is required around interpreted text, but",
- "often not desired with subscripts & superscripts.",
- "Backslash-escaped whitespace can be used; the whitespace will be",
- "removed from the processed document:",
- "",
- "```",
- "H\\ :sub:`2`\\ O",
- "E = mc\\ :sup:`2`",
- "```",
- "",
- "In such cases, readability of the plain text can be greatly",
- "improved with substitutions:",
- "",
- "```",
- "The chemical formula for pure water is |H2O|.",
- "",
- ".. |H2O| replace:: H\\ :sub:`2`\\ O",
- "```",
- "",
- "See [the reStructuredText spec](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html) for further information on",
- "[character-level markup](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#character-level-inline-markup) and [the substitution mechanism](https:/docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#substitution-references)."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#subscript",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "superscript(docutils.parsers.rst.roles.GenericRole)": {
- "is_markdown": true,
- "description": [
- "## `:superscript:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | `:sup:` |",
- "| DTD Element | superscript |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "Implements superscripts. See the tip in [:subscript:](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#subscript) above."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#superscript",
- "license": "https://docutils.sourceforge.io/docs/"
- },
- "title-reference(docutils.parsers.rst.roles.GenericRole)": {
- "is_markdown": true,
- "description": [
- "## `:title-reference:`",
- "",
- "| | |",
- "|-|-|",
- "| Aliases | `:title:`, `:t:`. |",
- "| DTD Element | title_reference |",
- "| Customization | ",
- "| | |",
- "|-|-|",
- "| Options | [class](https://docutils.sourceforge.io/docs/ref/rst/roles.txt#class). |",
- "| Content | None. |",
- " |",
- "",
- "The `:title-reference:` role is used to describe the titles of",
- "books, periodicals, and other materials. It is the equivalent of the",
- "HTML \"cite\" element, and it is expected that HTML writers will",
- "typically render \"title_reference\" elements using \"cite\".",
- "",
- "Since title references are typically rendered with italics, they are",
- "often marked up using `*emphasis*`, which is misleading and vague.",
- "The \"title_reference\" element provides accurate and unambiguous",
- "descriptive markup.",
- "",
- "Let's assume `:title-reference:` is the default interpreted text",
- "role (see below) for this example:",
- "",
- "```",
- "`Design Patterns` [GoF95]_ is an excellent read.",
- "```",
- "",
- "The following document fragment ([pseudo-XML](https:/docutils.sourceforge.io/docs/ref/rst/../doctree.html#pseudo-xml)) will result from",
- "processing:",
- "",
- "```",
- "",
- " ",
- " Design Patterns",
- "",
- " ",
- " GoF95",
- " is an excellent read.",
- "```",
- "",
- "`:title-reference:` is the default interpreted text role in the",
- "standard reStructuredText parser. This means that no explicit role is",
- "required. Applications of reStructuredText may designate a different",
- "default role, in which case the explicit `:title-reference:` role",
- "must be used to obtain a `title_reference` element."
- ],
- "options": {},
- "source": "https://docutils.sourceforge.io/docs/ref/rst/roles.html#title-reference",
- "license": "https://docutils.sourceforge.io/docs/"
- }
-}
diff --git a/lib/esbonio/esbonio/lsp/rst/roles.py b/lib/esbonio/esbonio/lsp/rst/roles.py
deleted file mode 100644
index d36201da8..000000000
--- a/lib/esbonio/esbonio/lsp/rst/roles.py
+++ /dev/null
@@ -1,50 +0,0 @@
-import json
-from typing import Any
-from typing import Dict
-from typing import Optional
-
-import docutils.parsers.rst.roles as docutils_roles
-
-from esbonio.lsp.roles import RoleLanguageFeature
-from esbonio.lsp.roles import Roles
-from esbonio.lsp.rst import RstLanguageServer
-from esbonio.lsp.util import resources
-
-
-class Docutils(RoleLanguageFeature):
- """Support for docutils' built-in roles."""
-
- def __init__(self) -> None:
- self._roles: Optional[Dict[str, Any]] = None
- """Cache for known roles."""
-
- @property
- def roles(self) -> Dict[str, Any]:
- if self._roles is not None:
- return self._roles
-
- found_roles = {**docutils_roles._roles, **docutils_roles._role_registry}
-
- self._roles = {
- k: v
- for k, v in found_roles.items()
- if v != docutils_roles.unimplemented_role
- }
-
- return self._roles
-
- def get_implementation(self, role: str, domain: str):
- if domain:
- return None
-
- return self.roles.get(role, None)
-
- def index_roles(self) -> Dict[str, Any]:
- return self.roles
-
-
-def esbonio_setup(rst: RstLanguageServer, roles: Roles):
- documentation = resources.read_string("esbonio.lsp.rst", "roles.json")
-
- roles.add_documentation(json.loads(documentation))
- roles.add_feature(Docutils())
diff --git a/lib/esbonio/esbonio/lsp/sphinx/__init__.py b/lib/esbonio/esbonio/lsp/sphinx/__init__.py
deleted file mode 100644
index 565f2114a..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/__init__.py
+++ /dev/null
@@ -1,851 +0,0 @@
-import json
-import logging
-import pathlib
-import platform
-import traceback
-import typing
-import warnings
-from functools import partial
-from multiprocessing import Process
-from multiprocessing import Queue
-from typing import IO
-from typing import Any
-from typing import Dict
-from typing import Iterator
-from typing import List
-from typing import Optional
-from typing import Tuple
-
-import pygls.uris as Uri
-from lsprotocol.types import DeleteFilesParams
-from lsprotocol.types import Diagnostic
-from lsprotocol.types import DiagnosticSeverity
-from lsprotocol.types import DidSaveTextDocumentParams
-from lsprotocol.types import InitializedParams
-from lsprotocol.types import InitializeParams
-from lsprotocol.types import MessageType
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-from lsprotocol.types import ShowDocumentParams
-from sphinx import __version__ as __sphinx_version__
-from sphinx.application import Sphinx
-from sphinx.domains import Domain
-from sphinx.errors import ConfigError
-from sphinx.util import console
-from sphinx.util import logging as sphinx_logging_module
-from sphinx.util.logging import NAMESPACE as SPHINX_LOG_NAMESPACE
-from sphinx.util.logging import VERBOSITY_MAP
-
-from esbonio.cli import setup_cli
-from esbonio.lsp.rst import RstLanguageServer
-from esbonio.lsp.sphinx.config import InitializationOptions
-from esbonio.lsp.sphinx.config import MissingConfigError
-from esbonio.lsp.sphinx.config import SphinxConfig
-from esbonio.lsp.sphinx.config import SphinxLogHandler
-from esbonio.lsp.sphinx.config import SphinxServerConfig
-from esbonio.lsp.sphinx.preview import make_preview_server
-from esbonio.lsp.sphinx.preview import start_preview_server
-
-from .line_number_transform import LineNumberTransform
-
-__all__ = [
- "InitializationOptions",
- "MissingConfigError",
- "SphinxConfig",
- "SphinxServerConfig",
- "SphinxLanguageServer",
-]
-
-IS_LINUX = platform.system() == "Linux"
-
-# fmt: off
-# Order matters!
-DEFAULT_MODULES = [
- "esbonio.lsp.directives", # Generic directive support
- "esbonio.lsp.roles", # Generic roles support
- "esbonio.lsp.rst.directives", # docutils directives
- "esbonio.lsp.rst.roles", # docutils roles
- "esbonio.lsp.sphinx.autodoc", # automodule, autoclass, etc.
- "esbonio.lsp.sphinx.codeblocks", # code-block, highlight, etc.
- "esbonio.lsp.sphinx.domains", # Sphinx domains
- "esbonio.lsp.sphinx.directives", # Sphinx directives
- "esbonio.lsp.sphinx.images", # image, figure etc
- "esbonio.lsp.sphinx.includes", # include, literal-include etc.
- "esbonio.lsp.sphinx.roles", # misc roles added by Sphinx e.g. :download:
-]
-"""The modules to load in the default configuration of the server."""
-# fmt: on
-
-
-class SphinxLanguageServer(RstLanguageServer):
- """A language server dedicated to working with Sphinx projects."""
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.app: Optional[Sphinx] = None
- """The Sphinx application instance."""
-
- self.sphinx_args: Dict[str, Any] = {}
- """The current Sphinx configuration will all variables expanded."""
-
- self.sphinx_log: Optional[SphinxLogHandler] = None
- """Logging handler for sphinx messages."""
-
- self.preview_process: Optional[Process] = None
- """The process hosting the preview server."""
-
- self.preview_port: Optional[int] = None
- """The port the preview server is running on."""
-
- self._role_target_types: Optional[Dict[str, List[str]]] = None
- """Cache for role target types."""
-
- self.file_list_pending_build_version_updates: List[Tuple[str, int]] = []
- """List of all the files that need an updated last_build_version"""
-
- @property
- def configuration(self) -> Dict[str, Any]:
- """Return the server's actual configuration."""
- config = super().configuration
- sphinx_config = SphinxConfig.from_arguments(sphinx_args=self.sphinx_args)
-
- if sphinx_config is None:
- self.logger.error("Unable to determine SphinxConfig!")
- return config
-
- if self.user_config is None:
- self.logger.error("Unable to determine user config!")
- return config
-
- # We always run Sphinx in "'-Q' mode", so we need to go back to the user's
- # config to get those values.
- sphinx_config.silent = self.user_config.sphinx.silent # type: ignore
- sphinx_config.quiet = self.user_config.sphinx.quiet # type: ignore
-
- # 'Make mode' isn't something that can be inferred from Sphinx args either.
- sphinx_config.make_mode = self.user_config.sphinx.make_mode # type: ignore
-
- config["sphinx"] = self.converter.unstructure(sphinx_config)
- config["sphinx"]["command"] = ["sphinx-build"] + sphinx_config.to_cli_args()
- config["sphinx"]["version"] = __sphinx_version__
-
- config["server"] = self.converter.unstructure(self.user_config.server)
-
- return config
-
- def initialize(self, params: InitializeParams):
- super().initialize(params)
- self.user_config = self.converter.structure(
- params.initialization_options or {}, InitializationOptions
- )
-
- def initialized(self, params: InitializedParams):
- self.app = self._initialize_sphinx()
- self.build()
-
- def _initialize_sphinx(self):
- try:
- return self.create_sphinx_app(self.user_config) # type: ignore
- except MissingConfigError:
- self.show_message(
- message="Unable to find your 'conf.py', features that depend on Sphinx will be unavailable",
- msg_type=MessageType.Warning,
- )
- self.send_notification(
- "esbonio/buildComplete",
- {
- "config": self.configuration,
- "error": True,
- "warnings": 0,
- },
- )
- except Exception as exc:
- self.logger.error(traceback.format_exc())
- uri, diagnostic = exception_to_diagnostic(exc)
- self.set_diagnostics("conf.py", uri, [diagnostic])
-
- self.sync_diagnostics()
- self.send_notification(
- "esbonio/buildComplete",
- {"config": self.configuration, "error": True, "warnings": 0},
- )
-
- def on_shutdown(self, *args):
- if self.preview_process:
- if not hasattr(self.preview_process, "kill"):
- self.preview_process.terminate()
- else:
- self.preview_process.kill()
-
- def save(self, params: DidSaveTextDocumentParams):
- super().save(params)
-
- filepath = Uri.to_fs_path(params.text_document.uri)
- if filepath.endswith("conf.py"):
- if self.app:
- conf_dir = pathlib.Path(self.app.confdir)
- else:
- # The user's config is currently broken... where should their conf.py be?
- if self.user_config is not None:
- config = typing.cast(InitializationOptions, self.user_config).sphinx
- else:
- config = SphinxConfig()
-
- conf_dir = config.resolve_conf_dir(
- self.workspace.root_uri
- ) or pathlib.Path(".")
-
- if str(conf_dir / "conf.py") == filepath:
- self.clear_diagnostics("conf.py")
- self.sync_diagnostics()
- self.app = self._initialize_sphinx()
-
- self.build()
-
- def delete_files(self, params: DeleteFilesParams):
- self.logger.debug("Deleted files: %s", params.files)
-
- # Files don't exist anymore, so diagnostics must be cleared.
- for file in params.files:
- self.clear_diagnostics("sphinx", file.uri)
-
- self.build()
-
- def build(
- self, force_all: bool = False, filenames: Optional[List[str]] = None
- ) -> None:
- """Trigger sphinx build. Force complete rebuild with flag or build only selected files in the list."""
- if not self.app:
- return
-
- self.logger.debug("Building...")
- self.send_notification("esbonio/buildStart", {})
- self.clear_diagnostics("sphinx-build")
- self.sync_diagnostics()
-
- # Reset the warnings counter
- self.app._warncount = 0
- error = False
-
- if self.sphinx_log is not None:
- self.sphinx_log.diagnostics = {}
-
- try:
- self.app.build(force_all, filenames)
- except Exception as exc:
- error = True
- self.logger.error(traceback.format_exc())
- uri, diagnostic = exception_to_diagnostic(exc)
- self.set_diagnostics("sphinx-build", uri, [diagnostic])
-
- if self.sphinx_log is not None:
- for doc, diagnostics in self.sphinx_log.diagnostics.items():
- self.logger.debug("Found %d problems for %s", len(diagnostics), doc)
- self.set_diagnostics("sphinx", doc, diagnostics)
-
- self.sync_diagnostics()
-
- self.send_notification(
- "esbonio/buildComplete",
- {
- "config": self.configuration,
- "error": error,
- "warnings": self.app._warncount,
- },
- )
-
- def cb_env_before_read_docs(self, app, env, docnames: List[str]):
- """Callback handling env-before-read-docs event."""
-
- # Determine if any unsaved files need to be added to the build list
- if self.user_config.server.enable_live_preview: # type: ignore
- is_building = set(docnames)
-
- for docname in env.found_docs - is_building:
- filepath = env.doc2path(docname, base=True)
- uri = Uri.from_fs_path(filepath)
-
- doc = self.workspace.get_document(uri)
- current_version = doc.version or 0
-
- last_build_version = getattr(doc, "last_build_version", 0)
- if last_build_version < current_version:
- docnames.append(docname)
-
- # Clear diagnostics for any to-be built files
- for docname in docnames:
- filepath = env.doc2path(docname, base=True)
- uri = Uri.from_fs_path(filepath)
- self.clear_diagnostics("sphinx", uri)
-
- doc = self.workspace.get_document(uri)
- current_version = doc.version or 0
- self.file_list_pending_build_version_updates.append((uri, current_version)) # type: ignore
-
- def cb_build_finished(self, app, exception):
- """Callback handling build-finished event."""
- if exception:
- self.file_list_pending_build_version_updates = []
- return
-
- for uri, updated_version in self.file_list_pending_build_version_updates:
- doc = self.workspace.get_document(uri)
- last_build_version = getattr(doc, "last_build_version", 0)
- if last_build_version < updated_version:
- doc.last_build_version = updated_version # type: ignore
-
- self.file_list_pending_build_version_updates = []
-
- def cb_source_read(self, app, docname, source):
- """Callback handling source_read event."""
-
- if not self.user_config.server.enable_live_preview: # type: ignore
- return
-
- filepath = app.env.doc2path(docname, base=True)
- uri = Uri.from_fs_path(filepath)
-
- doc = self.workspace.get_document(uri)
- source[0] = doc.source
-
- def create_sphinx_app(self, options: InitializationOptions) -> Optional[Sphinx]:
- """Create a Sphinx application instance with the given config."""
- sphinx = options.sphinx
- server = options.server
- self.logger.debug(
- "User Config %s", json.dumps(self.converter.unstructure(sphinx), indent=2)
- )
-
- # Until true multi-root support can be implemented let's try each workspace
- # folder and use the first valid configuration we can find.
- for folder_uri in self.workspace.folders.keys():
- self.logger.debug("Workspace Folder: '%s'", folder_uri)
-
- try:
- sphinx_config = sphinx.resolve(folder_uri)
- break
- except MissingConfigError:
- self.logger.debug(
- "No Sphinx conifg found in workspace folder: '%s'", folder_uri
- )
-
- # Not all clients use/support workspace folders, as a fallback, try the root_uri.
- else:
- self.logger.debug("Workspace root '%s'", self.workspace.root_uri)
- sphinx_config = sphinx.resolve(self.workspace.root_uri)
-
- self.sphinx_args = sphinx_config.to_application_args()
- self.logger.debug("Sphinx Args %s", json.dumps(self.sphinx_args, indent=2))
-
- # Override Sphinx's logging setup with our own.
- sphinx_logging_module.setup = partial(self._logging_setup, server, sphinx)
- app = Sphinx(**self.sphinx_args)
-
- self._load_sphinx_extensions(app)
- self._load_sphinx_config(app)
-
- if self.user_config.server.enable_scroll_sync: # type: ignore
- app.add_transform(LineNumberTransform)
-
- app.connect("env-before-read-docs", self.cb_env_before_read_docs)
-
- if self.user_config.server.enable_live_preview: # type: ignore
- app.connect("source-read", self.cb_source_read, priority=0)
- app.connect("build-finished", self.cb_build_finished)
-
- return app
-
- def _logging_setup(
- self,
- server: SphinxServerConfig,
- sphinx: SphinxConfig,
- app: Sphinx,
- status: IO,
- warning: IO,
- ):
- # Disable color escape codes in Sphinx's log messages
- console.nocolor()
-
- if not server.hide_sphinx_output and not sphinx.silent:
- sphinx_logger = logging.getLogger(SPHINX_LOG_NAMESPACE)
-
- # Be sure to remove any old handlers.
- for handler in sphinx_logger.handlers:
- if isinstance(handler, SphinxLogHandler):
- sphinx_logger.handlers.remove(handler)
-
- self.sphinx_log = SphinxLogHandler(app, self)
- sphinx_logger.addHandler(self.sphinx_log)
-
- if sphinx.quiet:
- level = logging.WARNING
- else:
- level = VERBOSITY_MAP[app.verbosity]
-
- sphinx_logger.setLevel(level)
- self.sphinx_log.setLevel(level)
-
- formatter = logging.Formatter("%(message)s")
- self.sphinx_log.setFormatter(formatter)
-
- def _load_sphinx_extensions(self, app: Sphinx):
- """Loop through each of Sphinx's extensions and see if any contain server
- functionality.
- """
-
- for name, ext in app.extensions.items():
- mod = ext.module
-
- setup = getattr(mod, "esbonio_setup", None)
- if setup is None:
- self.logger.debug(
- "Skipping extension '%s', missing 'esbonio_setup' fuction", name
- )
- continue
-
- self.load_extension(name, setup)
-
- def _load_sphinx_config(self, app: Sphinx):
- """Try and load the config as an server extension."""
-
- name = ""
-
- setup = app.config._raw_config.get("esbonio_setup", None)
- if not setup or not callable(setup):
- return
-
- self.load_extension(name, setup)
-
- def preview(self, options: Dict[str, Any]) -> Dict[str, Any]:
- if not self.app or not self.app.builder:
- return {}
-
- builder_name = self.app.builder.name
- if builder_name not in {"html"}:
- self.show_message(
- f"Previews are not currently supported for the '{builder_name}' builder."
- )
-
- return {}
-
- if not self.preview_process and IS_LINUX:
- self.logger.debug("Starting preview server.")
- server = make_preview_server(self.app.outdir) # type: ignore[arg-type]
- self.preview_port = server.server_port
-
- self.preview_process = Process(target=server.serve_forever, daemon=True)
- self.preview_process.start()
-
- if not self.preview_process and not IS_LINUX:
- self.logger.debug("Starting preview server")
-
- q: Queue = Queue()
- self.preview_process = Process(
- target=start_preview_server, args=(q, self.app.outdir), daemon=True
- )
- self.preview_process.start()
- self.preview_port = q.get()
-
- if options.get("show", True):
- self.show_document(
- ShowDocumentParams(
- uri=f"http://localhost:{self.preview_port}", external=True
- )
- )
-
- return {"port": self.preview_port}
-
- def get_doctree(
- self, *, docname: Optional[str] = None, uri: Optional[str] = None
- ) -> Optional[Any]:
- """Return the initial doctree corresponding to the specified document.
-
- The ``docname`` of a document is its path relative to the project's ``srcdir``
- minus the extension e.g. the docname of the file ``docs/lsp/features.rst``
- would be ``lsp/features``.
-
- Parameters
- ----------
- docname:
- Returns the doctree that corresponds with the given docname
- uri:
- Returns the doctree that corresponds with the given uri.
- """
-
- if self.app is None or self.app.env is None or self.app.builder is None:
- return None
-
- if uri is not None:
- fspath = Uri.to_fs_path(uri)
- docname = self.app.env.path2doc(fspath)
-
- if docname is None:
- return None
-
- try:
- return self.app.env.get_and_resolve_doctree(docname, self.app.builder)
- except FileNotFoundError:
- self.logger.debug("Could not find doctree for '%s'", docname)
- # self.logger.debug(traceback.format_exc())
- return None
-
- def get_domain(self, name: str) -> Optional[Domain]:
- """Return the domain with the given name.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``
-
- If a domain with the given name cannot be found, this method will return None.
-
- Parameters
- ----------
- name:
- The name of the domain
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_domains() is deprecated and will be removed in v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if self.app is None or self.app.env is None:
- return None
-
- domains = self.app.env.domains
- return domains.get(name, None)
-
- def get_domains(self) -> Iterator[Tuple[str, Domain]]:
- """Get all the domains registered with an applications.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``
-
- Returns a generator that iterates through all of an application's domains,
- taking into account configuration variables such as ``primary_domain``.
- Yielded values will be a tuple of the form ``(prefix, domain)`` where
-
- - ``prefix`` is the namespace that should be used when referencing items
- in the domain
- - ``domain`` is the domain object itself.
-
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_domains() is deprecated and will be removed in v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if self.app is None or self.app.env is None:
- return []
-
- domains = self.app.env.domains
- primary_domain = self.app.config.primary_domain
-
- for name, domain in domains.items():
- prefix = name
-
- # Items from the standard and primary domains don't require the namespace prefix
- if name == "std" or name == primary_domain:
- prefix = ""
-
- yield prefix, domain
-
- def get_directive_options(self, name: str) -> Dict[str, Any]:
- """Return the options specification for the given directive.
-
- .. deprecated:: 0.14.2
-
- This will be removed in ``v1.0``
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_directive_options() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- directive = self.get_directives().get(name, None)
- if directive is None:
- return {}
-
- options = directive.option_spec
-
- if name.startswith("auto") and self.app:
- self.logger.debug("Processing options for '%s' directive", name)
- name = name.replace("auto", "")
-
- self.logger.debug("Documenter name is '%s'", name)
- documenter = self.app.registry.documenters.get(name, None)
-
- if documenter is not None:
- options = documenter.option_spec
-
- return options or {}
-
- def get_default_role(self) -> Tuple[Optional[str], Optional[str]]:
- """Return the project's default role"""
-
- if not self.app:
- return None, None
-
- role = self.app.config.default_role
- if not role:
- return None, None
-
- if ":" in role:
- domain, name = role.split(":")
-
- if domain == self.app.config.primary_domain:
- domain = ""
-
- return domain, name
-
- return None, role
-
- def get_role_target_types(self, name: str, domain_name: str = "") -> List[str]:
- """Return a map indicating which object types a role is capable of linking
- with.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``
-
- For example
-
- .. code-block:: python
-
- {
- "func": ["function"],
- "class": ["class", "exception"]
- }
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_role_target_types() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- key = f"{domain_name}:{name}" if domain_name else name
-
- if self._role_target_types is not None:
- return self._role_target_types.get(key, [])
-
- self._role_target_types = {}
-
- for prefix, domain in self.get_domains():
- fmt = "{prefix}:{name}" if prefix else "{name}"
-
- for name, item_type in domain.object_types.items():
- for role in item_type.roles:
- role_key = fmt.format(name=role, prefix=prefix)
- target_types = self._role_target_types.get(role_key, list())
- target_types.append(name)
-
- self._role_target_types[role_key] = target_types
-
- types = self._role_target_types.get(key, [])
- self.logger.debug("Role '%s' targets object types '%s'", key, types)
-
- return types
-
- def get_role_targets(self, name: str, domain: str = "") -> List[tuple]:
- """Return a list of objects targeted by the given role.
-
- Parameters
- ----------
- name:
- The name of the role
- domain:
- The domain the role is a part of, if applicable.
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_role_targets() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- targets: List[tuple] = []
- domain_obj: Optional[Domain] = None
-
- if domain:
- domain_obj = self.get_domain(domain)
- else:
- std = self.get_domain("std")
- if std and name in std.roles:
- domain_obj = std
-
- elif self.app and self.app.config.primary_domain:
- domain_obj = self.get_domain(self.app.config.primary_domain)
-
- target_types = set(self.get_role_target_types(name, domain))
-
- if not domain_obj:
- self.logger.debug("Unable to find domain for role '%s:%s'", domain, name)
- return []
-
- for obj in domain_obj.get_objects():
- if obj[2] in target_types:
- targets.append(obj)
-
- return targets
-
- def get_intersphinx_projects(self) -> List[str]:
- """Return the list of configured intersphinx project names.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v.1.0``
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_intersphinx_projects() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if self.app is None:
- return []
-
- inv = getattr(self.app.env, "intersphinx_named_inventory", {})
- return list(inv.keys())
-
- def has_intersphinx_targets(
- self, project: str, name: str, domain: str = ""
- ) -> bool:
- """Return ``True`` if the given intersphinx project has targets targeted by the
- given role.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``
-
- Parameters
- ----------
- project:
- The project to check
- name:
- The name of the role
- domain:
- The domain the role is a part of, if applicable.
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.has_intersphinx_targets() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- targets = self.get_intersphinx_targets(project, name, domain)
-
- if len(targets) == 0:
- return False
-
- return any([len(items) > 0 for items in targets.values()])
-
- def get_intersphinx_targets(
- self, project: str, name: str, domain: str = ""
- ) -> Dict[str, Dict[str, tuple]]:
- """Return the intersphinx objects targeted by the given role.
-
- .. deprecated:: 0.15.0
-
- This will be removed in ``v1.0``
-
- Parameters
- ----------
- project:
- The project to return targets from
- name:
- The name of the role
- domain:
- The domain the role is a part of, if applicable.
- """
-
- clsname = self.__class__.__name__
- warnings.warn(
- f"{clsname}.get_intersphinx_targets() is deprecated and will be removed in "
- "v1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if self.app is None:
- return {}
-
- inv = getattr(self.app.env, "intersphinx_named_inventory", {})
- if project not in inv:
- return {}
-
- targets = {}
- inv = inv[project]
-
- for target_type in self.get_role_target_types(name, domain):
- explicit_domain = f"{domain}:{target_type}"
- if explicit_domain in inv:
- targets[target_type] = inv[explicit_domain]
- continue
-
- primary_domain = f'{self.app.config.primary_domain or ""}:{target_type}'
- if primary_domain in inv:
- targets[target_type] = inv[primary_domain]
- continue
-
- std_domain = f"std:{target_type}"
- if std_domain in inv:
- targets[target_type] = inv[std_domain]
-
- return targets
-
-
-def exception_to_diagnostic(exc: BaseException):
- """Convert an exception into a diagnostic we can send to the client."""
-
- # Config errors sometimes wrap the true cause of the problem
- if isinstance(exc, ConfigError) and exc.__cause__ is not None:
- exc = exc.__cause__
-
- if isinstance(exc, SyntaxError):
- path = pathlib.Path(exc.filename or "")
- line = (exc.lineno or 1) - 1
- else:
- tb = exc.__traceback__
- frame = traceback.extract_tb(tb)[-1]
- path = pathlib.Path(frame.filename)
- line = (frame.lineno or 1) - 1
-
- message = type(exc).__name__ if exc.args.count == 0 else exc.args[0]
-
- diagnostic = Diagnostic(
- range=Range(
- start=Position(line=line, character=0),
- end=Position(line=line + 1, character=0),
- ),
- message=message,
- severity=DiagnosticSeverity.Error,
- )
-
- return Uri.from_fs_path(str(path)), diagnostic
-
-
-cli = setup_cli("esbonio.lsp.sphinx", "Esbonio's Sphinx language server.")
-cli.set_defaults(modules=DEFAULT_MODULES)
-cli.set_defaults(server_cls=SphinxLanguageServer)
diff --git a/lib/esbonio/esbonio/lsp/sphinx/__main__.py b/lib/esbonio/esbonio/lsp/sphinx/__main__.py
deleted file mode 100644
index ff4219b5e..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/__main__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-import sys
-
-from esbonio.cli import main
-from esbonio.lsp.sphinx import cli
-
-sys.exit(main(cli))
diff --git a/lib/esbonio/esbonio/lsp/sphinx/autodoc.py b/lib/esbonio/esbonio/lsp/sphinx/autodoc.py
deleted file mode 100644
index b446899b3..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/autodoc.py
+++ /dev/null
@@ -1,35 +0,0 @@
-from typing import Iterable
-from typing import Optional
-
-from esbonio.lsp import CompletionContext
-from esbonio.lsp.directives import DirectiveLanguageFeature
-from esbonio.lsp.directives import Directives
-from esbonio.lsp.sphinx import SphinxLanguageServer
-
-
-class AutoDoc(DirectiveLanguageFeature):
- def __init__(self, rst: SphinxLanguageServer):
- self.rst = rst
-
- def suggest_options(
- self, context: CompletionContext, directive: str, domain: Optional[str]
- ) -> Iterable[str]:
- if self.rst.app is None or not directive.startswith("auto"):
- return []
-
- # The autoxxxx set of directives need special support as their options are
- # stored on "documenters" instead of the directive implementation itself.
- name = directive.replace("auto", "")
- documenter = self.rst.app.registry.documenters.get(name, None)
-
- if documenter is None:
- self.rst.logger.debug(
- "Unable to find documenter for directive: '%s'", directive
- )
- return []
-
- return documenter.option_spec.keys()
-
-
-def esbonio_setup(rst: SphinxLanguageServer, directives: Directives):
- directives.add_feature(AutoDoc(rst))
diff --git a/lib/esbonio/esbonio/lsp/sphinx/cli.py b/lib/esbonio/esbonio/lsp/sphinx/cli.py
deleted file mode 100644
index 1b77b4127..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/cli.py
+++ /dev/null
@@ -1,77 +0,0 @@
-"""Additional command line utilities for the SphinxLanguageServer."""
-import argparse
-import json
-import sys
-from typing import List
-
-from esbonio.cli import esbonio_converter
-from esbonio.lsp.sphinx import SphinxConfig
-
-
-def config_cmd(args, extra):
- if args.to_cli:
- config_to_cli(args.to_cli)
- return 0
-
- return cli_to_config(extra)
-
-
-def config_to_cli(config: str):
- converter = esbonio_converter()
- conf = converter.structure(json.loads(config), SphinxConfig)
- print(" ".join(conf.to_cli_args()))
- return 0
-
-
-def cli_to_config(cli_args: List[str]):
- conf = SphinxConfig.from_arguments(cli_args=cli_args)
- if conf is None:
- return 1
-
- converter = esbonio_converter()
- print(json.dumps(converter.unstructure(conf), indent=2))
- return 0
-
-
-cli = argparse.ArgumentParser(
- prog="esbonio-sphinx",
- description="Supporting commands and utilities for the SphinxLanguageServer.",
-)
-commands = cli.add_subparsers(title="commands")
-config = commands.add_parser(
- "config",
- usage="%(prog)s [--from-cli] -- ARGS",
- description="configuration options helper.",
-)
-config.set_defaults(run=config_cmd)
-
-mode = config.add_mutually_exclusive_group()
-mode.add_argument(
- "--from-cli",
- action="store_true",
- default=True,
- help="convert sphinx-build cli options to esbonio's initialization options.",
-)
-mode.add_argument(
- "--to-cli",
- help="convert esbonio's initialization options to sphinx-build options",
-)
-
-
-def main():
- try:
- idx = sys.argv.index("--")
- args, extra = sys.argv[1:idx], sys.argv[idx + 1 :]
- except ValueError:
- args, extra = sys.argv[1:], None
-
- parsed_args = cli.parse_args(args)
-
- if hasattr(parsed_args, "run"):
- return parsed_args.run(parsed_args, extra)
-
- cli.print_help()
-
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/lib/esbonio/esbonio/lsp/sphinx/codeblocks.py b/lib/esbonio/esbonio/lsp/sphinx/codeblocks.py
deleted file mode 100644
index bd7eb5746..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/codeblocks.py
+++ /dev/null
@@ -1,62 +0,0 @@
-"""Support for code-blocks and related directives."""
-import textwrap
-from typing import List
-
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import CompletionItemKind
-from lsprotocol.types import MarkupContent
-from lsprotocol.types import MarkupKind
-from pygments.lexers import get_all_lexers
-
-from esbonio.lsp.directives import Directives
-from esbonio.lsp.rst import CompletionContext
-from esbonio.lsp.sphinx import SphinxLanguageServer
-
-
-class CodeBlocks:
- def __init__(self, rst: SphinxLanguageServer):
- self.rst = rst
- self.logger = rst.logger.getChild(self.__class__.__name__)
- self._lexers: List[CompletionItem] = []
-
- @property
- def lexers(self) -> List[CompletionItem]:
- if len(self._lexers) == 0:
- self._index_lexers()
-
- return self._lexers
-
- def complete_arguments(
- self, context: CompletionContext, domain: str, name: str
- ) -> List[CompletionItem]:
- if name in {"code-block", "highlight"}:
- return self.lexers
-
- return []
-
- def _index_lexers(self):
- self._lexers = []
-
- for name, labels, files, mimes in get_all_lexers():
- for label in labels:
- documentation = f"""\
- ### {name}
-
- Filenames: {', '.join(files)}
-
- MIME Types: {', '.join(mimes)}
- """
-
- item = CompletionItem(
- label=label,
- kind=CompletionItemKind.Constant,
- documentation=MarkupContent(
- kind=MarkupKind.Markdown, value=textwrap.dedent(documentation)
- ),
- )
-
- self._lexers.append(item)
-
-
-def esbonio_setup(rst: SphinxLanguageServer, directives: Directives):
- directives.add_argument_completion_provider(CodeBlocks(rst))
diff --git a/lib/esbonio/esbonio/lsp/sphinx/config.py b/lib/esbonio/esbonio/lsp/sphinx/config.py
deleted file mode 100644
index b8ae5e7b8..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/config.py
+++ /dev/null
@@ -1,700 +0,0 @@
-import hashlib
-import inspect
-import logging
-import multiprocessing
-import os
-import pathlib
-import re
-import sys
-import traceback
-from types import ModuleType
-from typing import Any
-from typing import Dict
-from typing import List
-from typing import Literal
-from typing import Optional
-from typing import Tuple
-from typing import Union
-from unittest import mock
-
-import attrs
-import platformdirs
-import pygls.uris as Uri
-from lsprotocol.types import Diagnostic
-from lsprotocol.types import DiagnosticSeverity
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-from sphinx.application import Sphinx
-from sphinx.cmd.build import main as sphinx_build
-from sphinx.util.logging import OnceFilter
-from sphinx.util.logging import SphinxLogRecord
-from sphinx.util.logging import WarningLogRecordTranslator
-
-from esbonio.lsp.log import LOG_NAMESPACE
-from esbonio.lsp.log import LspHandler
-from esbonio.lsp.rst.config import ServerConfig
-
-PATH_VAR_PATTERN = re.compile(r"^\${(\w+)}/?.*")
-logger = logging.getLogger(LOG_NAMESPACE)
-
-
-class MissingConfigError(Exception):
- """Indicates that we couldn't locate the project's 'conf.py'"""
-
-
-@attrs.define
-class SphinxConfig:
- """Configuration values to pass to the Sphinx application instance."""
-
- build_dir: Optional[str] = attrs.field(default=None)
- """The directory to write build outputs into."""
-
- builder_name: str = attrs.field(default="html")
- """The currently used builder name."""
-
- conf_dir: Optional[str] = attrs.field(default=None)
- """The directory containing the project's ``conf.py``."""
-
- config_overrides: Dict[str, Any] = attrs.field(factory=dict)
- """Any overrides to configuration values."""
-
- doctree_dir: Optional[str] = attrs.field(default=None)
- """The directory to write doctrees into."""
-
- force_full_build: bool = attrs.field(default=False)
- """Force a full build on startup."""
-
- keep_going: bool = attrs.field(default=False)
- """Continue building when errors (from warnings) are encountered."""
-
- make_mode: bool = attrs.field(default=True)
- """Flag indicating if the server should align to "make mode" behavior."""
-
- num_jobs: Union[Literal["auto"], int] = attrs.field(default=1)
- """The number of jobs to use for parallel builds."""
-
- quiet: bool = attrs.field(default=False)
- """Hide standard Sphinx output messages"""
-
- silent: bool = attrs.field(default=False)
- """Hide all Sphinx output."""
-
- src_dir: Optional[str] = attrs.field(default=None)
- """The directory containing the project's source."""
-
- tags: List[str] = attrs.field(factory=list)
- """Tags to enable during a build."""
-
- verbosity: int = attrs.field(default=0)
- """The verbosity of Sphinx's output."""
-
- version: Optional[str] = attrs.field(default=None)
- """Sphinx's version number."""
-
- warning_is_error: bool = attrs.field(default=False)
- """Treat any warning as an error"""
-
- @property
- def parallel(self) -> int:
- """The parsed value of the ``num_jobs`` field."""
-
- if self.num_jobs == "auto":
- return multiprocessing.cpu_count()
-
- return self.num_jobs
-
- @classmethod
- def from_arguments(
- cls,
- *,
- cli_args: Optional[List[str]] = None,
- sphinx_args: Optional[Dict[str, Any]] = None,
- ) -> Optional["SphinxConfig"]:
- """Return the ``SphinxConfig`` instance that's equivalent to the given arguments.
-
- .. note::
-
- Only ``cli_args`` **or** ``sphinx_args`` may be given.
-
- .. warning::
-
- This method is unable to determine the value of the
- :obj:`SphinxConfig.make_mode` setting when passing ``sphinx_args``
-
-
- Parameters
- ----------
- cli_args
- The cli arguments you would normally pass to ``sphinx-build``
-
- sphinx_args:
- The arguments you would use to create a ``Sphinx`` application instance.
- """
-
- make_mode: bool = False
- neither_given = cli_args is None and sphinx_args is None
- both_given = cli_args is not None and sphinx_args is not None
- if neither_given or both_given:
- raise ValueError("You must pass either 'cli_args' or 'sphinx_args'")
-
- if cli_args is not None:
- # The easiest way to handle this is to just call sphinx-build but with
- # the Sphinx app object patched out - then we just use all the args it
- # was given!
- with mock.patch("sphinx.cmd.build.Sphinx") as m_Sphinx:
- sphinx_build(cli_args)
-
- if m_Sphinx.call_args is None:
- return None
-
- signature = inspect.signature(Sphinx)
- keys = signature.parameters.keys()
-
- values = m_Sphinx.call_args[0]
- sphinx_args = {k: v for k, v in zip(keys, values)}
-
- # `-M` has to be the first argument passed to `sphinx-build`
- # https://github.com/sphinx-doc/sphinx/blob/1222bed88eb29cde43a81dd208448dc903c53de2/sphinx/cmd/build.py#L287
- make_mode = cli_args[0] == "-M"
- if make_mode and sphinx_args["outdir"].endswith(sphinx_args["buildername"]):
- build_dir = pathlib.Path(sphinx_args["outdir"]).parts[:-1]
- sphinx_args["outdir"] = str(pathlib.Path(*build_dir))
-
- if sphinx_args is None:
- return None
-
- return cls(
- conf_dir=sphinx_args.get("confdir", None),
- config_overrides=sphinx_args.get("confoverrides", {}),
- build_dir=sphinx_args.get("outdir", None),
- builder_name=sphinx_args.get("buildername", "html"),
- doctree_dir=sphinx_args.get("doctreedir", None),
- force_full_build=sphinx_args.get("freshenv", False),
- keep_going=sphinx_args.get("keep_going", False),
- make_mode=make_mode,
- num_jobs=sphinx_args.get("parallel", 1),
- quiet=sphinx_args.get("status", 1) is None,
- silent=sphinx_args.get("warning", 1) is None,
- src_dir=sphinx_args.get("srcdir", None),
- tags=sphinx_args.get("tags", []),
- verbosity=sphinx_args.get("verbosity", 0),
- warning_is_error=sphinx_args.get("warningiserror", False),
- )
-
- def to_cli_args(self) -> List[str]:
- """Convert this into the equivalent ``sphinx-build`` cli arguments."""
-
- if self.make_mode:
- return self._build_make_cli_args()
-
- return self._build_cli_args()
-
- def _build_make_cli_args(self) -> List[str]:
- args = ["-M", self.builder_name]
- conf_dir = self.conf_dir or "${workspaceRoot}"
- src_dir = self.src_dir or conf_dir
-
- if self.build_dir is None:
- build_dir = pathlib.Path(src_dir, "_build")
- else:
- build_dir = pathlib.Path(self.build_dir)
-
- args += [src_dir, str(build_dir)]
-
- args += self._build_standard_args()
- default_dtree_dir = str(pathlib.Path(build_dir, "doctrees"))
- if self.doctree_dir is not None and self.doctree_dir != default_dtree_dir:
- args += ["-d", self.doctree_dir]
-
- return args
-
- def _build_cli_args(self) -> List[str]:
- args = ["-b", self.builder_name]
-
- conf_dir = self.conf_dir or "${workspaceRoot}"
- src_dir = self.src_dir or conf_dir
-
- build_dir = self.build_dir or pathlib.Path(src_dir, "_build")
- default_dtree_dir = str(pathlib.Path(build_dir, ".doctrees"))
-
- if self.doctree_dir is not None and self.doctree_dir != default_dtree_dir:
- args += ["-d", self.doctree_dir]
-
- args += self._build_standard_args()
- args += [src_dir, str(build_dir)]
- return args
-
- def _build_standard_args(self) -> List[str]:
- args: List[str] = []
-
- conf_dir = self.conf_dir or "${workspaceRoot}"
- src_dir = self.src_dir or self.conf_dir
-
- if conf_dir != src_dir:
- args += ["-c", conf_dir]
-
- if self.force_full_build:
- args += ["-E"]
-
- if self.parallel > 1:
- args += ["-j", str(self.num_jobs)]
-
- if self.silent:
- args += ["-Q"]
-
- if self.quiet and not self.silent:
- args += ["-q"]
-
- if self.warning_is_error:
- args += ["-W"]
-
- if self.keep_going:
- args += ["--keep-going"]
-
- if self.verbosity > 0:
- args += ["-" + ("v" * self.verbosity)]
-
- for key, value in self.config_overrides.items():
- if key == "nitpicky":
- args += ["-n"]
- continue
-
- if key.startswith("html_context."):
- char = "A"
- key = key.replace("html_context.", "")
- else:
- char = "D"
-
- args += [f"-{char}{key}={value}"]
-
- for tag in self.tags:
- args += ["-t", tag]
-
- return args
-
- def to_application_args(self) -> Dict[str, Any]:
- """Convert this into the equivalent Sphinx application arguments."""
-
- return {
- "buildername": self.builder_name,
- "confdir": self.conf_dir,
- "confoverrides": self.config_overrides,
- "doctreedir": self.doctree_dir,
- "freshenv": self.force_full_build,
- "keep_going": self.keep_going,
- "outdir": self.build_dir,
- "parallel": self.parallel,
- "srcdir": self.src_dir,
- "status": None,
- "tags": self.tags,
- "verbosity": self.verbosity,
- "warning": None,
- "warningiserror": self.warning_is_error,
- }
-
- def resolve(self, root_uri: str) -> "SphinxConfig":
- conf_dir = self.resolve_conf_dir(root_uri)
- if conf_dir is None:
- raise MissingConfigError()
-
- src_dir = self.resolve_src_dir(root_uri, str(conf_dir))
- build_dir = self.resolve_build_dir(root_uri, str(conf_dir))
- doctree_dir = self.resolve_doctree_dir(root_uri, str(conf_dir), str(build_dir))
-
- if self.make_mode:
- build_dir /= self.builder_name
-
- return SphinxConfig(
- conf_dir=str(conf_dir),
- config_overrides=self.config_overrides,
- build_dir=str(build_dir),
- builder_name=self.builder_name,
- doctree_dir=str(doctree_dir),
- force_full_build=self.force_full_build,
- keep_going=self.keep_going,
- make_mode=self.make_mode,
- num_jobs=self.num_jobs,
- quiet=self.quiet,
- silent=self.silent,
- src_dir=str(src_dir),
- tags=self.tags,
- verbosity=self.verbosity,
- warning_is_error=self.warning_is_error,
- )
-
- def resolve_build_dir(self, root_uri: str, actual_conf_dir: str) -> pathlib.Path:
- """Get the build dir to use based on the user's config.
-
- If nothing is specified in the given ``config``, this will choose a location
- within the user's cache dir (as determined by
- `platformdirs `). The directory name will be a hash
- derived from the given ``conf_dir`` for the project.
-
- Alternatively the user (or least language client) can override this by setting
- either an absolute path, or a path based on the following "variables".
-
- - ``${workspaceRoot}`` which expands to the workspace root as provided
- by the language client.
-
- - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
- multi-root support.
-
- - ``${confDir}`` which expands to the configured config dir.
-
- Parameters
- ----------
- root_uri
- The workspace root uri
-
- actual_conf_dir:
- The fully resolved conf dir for the project
- """
-
- if not self.build_dir:
- # Try to pick a sensible dir based on the project's location
- cache = platformdirs.user_cache_dir("esbonio", "swyddfa")
- project = hashlib.md5(str(actual_conf_dir).encode()).hexdigest()
-
- return pathlib.Path(cache) / project
-
- root_dir = Uri.to_fs_path(root_uri)
- match = PATH_VAR_PATTERN.match(self.build_dir)
-
- if match and match.group(1) in {"workspaceRoot", "workspaceFolder"}:
- build = pathlib.Path(self.build_dir).parts[1:]
- return pathlib.Path(root_dir, *build).resolve()
-
- if match and match.group(1) == "confDir":
- build = pathlib.Path(self.build_dir).parts[1:]
- return pathlib.Path(actual_conf_dir, *build).resolve()
-
- # Convert path to/from uri so that any path quirks from windows are
- # automatically handled
- build_uri = Uri.from_fs_path(self.build_dir)
- build_dir = Uri.to_fs_path(build_uri)
-
- # But make sure paths starting with '~' are not corrupted
- if build_dir.startswith("/~"):
- build_dir = build_dir.replace("/~", "~")
-
- # But make sure (windows) paths starting with '~' are not corrupted
- if build_dir.startswith("\\~"):
- build_dir = build_dir.replace("\\~", "~")
-
- return pathlib.Path(build_dir).expanduser()
-
- def resolve_doctree_dir(
- self, root_uri: str, actual_conf_dir: str, actual_build_dir: str
- ) -> pathlib.Path:
- """Get the directory to use for doctrees based on the user's config.
-
- If ``doctree_dir`` is not set, this method will follow what ``sphinx-build``
- does.
-
- - If ``make_mode`` is true, this will be set to ``${buildDir}/doctrees``
- - If ``make_mode`` is false, this will be set to ``${buildDir}/.doctrees``
-
- Otherwise, if ``doctree_dir`` is set the following "variables" are handled by
- this method.
-
- - ``${workspaceRoot}`` which expands to the workspace root as provided by the
- language client.
-
- - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
- multi-root support.
-
- - ``${confDir}`` which expands to the configured config dir.
-
- - ``${buildDir}`` which expands to the configured build dir.
-
- Parameters
- ----------
- root_uri
- The workspace root uri
-
- actual_conf_dir
- The fully resolved conf dir for the project
-
- actual_build_dir
- The fully resolved build dir for the project.
- """
-
- if self.doctree_dir is None:
- if self.make_mode:
- return pathlib.Path(actual_build_dir, "doctrees")
-
- return pathlib.Path(actual_build_dir, ".doctrees")
-
- root_dir = Uri.to_fs_path(root_uri)
- match = PATH_VAR_PATTERN.match(self.doctree_dir)
-
- if match and match.group(1) in {"workspaceRoot", "workspaceFolder"}:
- build = pathlib.Path(self.doctree_dir).parts[1:]
- return pathlib.Path(root_dir, *build).resolve()
-
- if match and match.group(1) == "confDir":
- build = pathlib.Path(self.doctree_dir).parts[1:]
- return pathlib.Path(actual_conf_dir, *build).resolve()
-
- if match and match.group(1) == "buildDir":
- build = pathlib.Path(self.doctree_dir).parts[1:]
- return pathlib.Path(actual_build_dir, *build).resolve()
-
- return pathlib.Path(self.doctree_dir).expanduser()
-
- def resolve_conf_dir(self, root_uri: str) -> Optional[pathlib.Path]:
- """Get the conf dir to use based on the user's config.
-
- If ``conf_dir`` is not set, this method will attempt to find it by searching
- within the ``root_uri`` for a ``conf.py`` file. If multiple files are found, the
- first one found will be chosen.
-
- If ``conf_dir`` is set the following "variables" are handled by this method
-
- - ``${workspaceRoot}`` which expands to the workspace root as provided by the
- language client.
-
- - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
- multi-root support.
-
- Parameters
- ----------
- root_uri
- The workspace root uri
- """
- root = Uri.to_fs_path(root_uri)
-
- if not self.conf_dir:
- ignore_paths = [".tox", "site-packages"]
-
- for candidate in pathlib.Path(root).glob("**/conf.py"):
- # Skip any files that obviously aren't part of the project
- if any(path in str(candidate) for path in ignore_paths):
- continue
-
- return candidate.parent
-
- # Nothing found
- return None
-
- match = PATH_VAR_PATTERN.match(self.conf_dir)
- if not match or match.group(1) not in {"workspaceRoot", "workspaceFolder"}:
- return pathlib.Path(self.conf_dir).expanduser()
-
- conf = pathlib.Path(self.conf_dir).parts[1:]
- return pathlib.Path(root, *conf).resolve()
-
- def resolve_src_dir(self, root_uri: str, actual_conf_dir: str) -> pathlib.Path:
- """Get the src dir to use based on the user's config.
-
- By default the src dir will be the same as the conf dir, but this can
- be overriden by setting the ``src_dir`` field.
-
- There are a number of "variables" that can be included in the path,
- currently we support
-
- - ``${workspaceRoot}`` which expands to the workspace root as provided
- by the language client.
-
- - ``${workspaceFolder}`` alias for ``${workspaceRoot}``, placeholder ready for
- multi-root support.
-
- - ``${confDir}`` which expands to the configured config dir.
-
- Parameters
- ----------
- root_uri
- The workspace root uri
-
- actual_conf_dir
- The fully resolved conf dir for the project
- """
-
- if not self.src_dir:
- return pathlib.Path(actual_conf_dir)
-
- src_dir = self.src_dir
- root_dir = Uri.to_fs_path(root_uri)
-
- match = PATH_VAR_PATTERN.match(src_dir)
- if match and match.group(1) in {"workspaceRoot", "workspaceFolder"}:
- src = pathlib.Path(src_dir).parts[1:]
- return pathlib.Path(root_dir, *src).resolve()
-
- if match and match.group(1) == "confDir":
- src = pathlib.Path(src_dir).parts[1:]
- return pathlib.Path(actual_conf_dir, *src).resolve()
-
- return pathlib.Path(src_dir).expanduser()
-
-
-@attrs.define
-class SphinxServerConfig(ServerConfig):
- """
- .. deprecated:: 0.12.0
-
- This will be removed in v1.0.
- Use :confval:`sphinx.quiet (boolean)` and :confval:`sphinx.silent (boolean)`
- options instead.
- """
-
- hide_sphinx_output: bool = attrs.field(default=False)
- """A flag to indicate if Sphinx build output should be omitted from the log."""
-
-
-@attrs.define
-class InitializationOptions:
- """The initialization options we can expect to receive from a client."""
-
- sphinx: SphinxConfig = attrs.field(factory=SphinxConfig)
- """The ``esbonio.sphinx.*`` namespace of options."""
-
- server: SphinxServerConfig = attrs.field(factory=SphinxServerConfig)
- """The ``esbonio.server.*`` namespace of options."""
-
-
-DIAGNOSTIC_SEVERITY = {
- logging.ERROR: DiagnosticSeverity.Error,
- logging.INFO: DiagnosticSeverity.Information,
- logging.WARNING: DiagnosticSeverity.Warning,
-}
-
-
-class SphinxLogHandler(LspHandler):
- """A logging handler that can extract errors from Sphinx's build output."""
-
- def __init__(self, app, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- self.app = app
- self.translator = WarningLogRecordTranslator(app)
- self.only_once = OnceFilter()
- self.diagnostics: Dict[str, List[Diagnostic]] = {}
-
- def get_location(self, location: str) -> Tuple[str, Optional[int]]:
- if not location:
- conf = pathlib.Path(self.app.confdir, "conf.py")
- return (Uri.from_fs_path(str(conf)), None)
-
- lineno = None
- path, parts = self.get_location_path(location)
-
- if len(parts) == 1:
- try:
- lineno = int(parts[0])
- except ValueError:
- pass
-
- if len(parts) == 2 and parts[0].startswith("docstring of "):
- target = parts[0].replace("docstring of ", "")
- lineno = self.get_docstring_location(target, parts[1])
-
- return (Uri.from_fs_path(path), lineno)
-
- def get_location_path(self, location: str) -> Tuple[str, List[str]]:
- """Determine the filepath from the given location."""
-
- if location.startswith("internal padding before "):
- location = location.replace("internal padding before ", "")
-
- if location.startswith("internal padding after "):
- location = location.replace("internal padding after ", "")
-
- path, *parts = location.split(":")
-
- # On windows the rest of the path will be the first element of parts
- if pathlib.Path(location).drive:
- path += f":{parts.pop(0)}"
-
- # Diagnostics in .. included:: files are reported relative to the process'
- # working directory, so ensure the path is absolute.
- path = os.path.abspath(path)
-
- return path, parts
-
- def get_docstring_location(self, target: str, offset: str) -> Optional[int]:
- # The containing module will be the longest substring we can find in target
- candidates = [m for m in sys.modules.keys() if target.startswith(m)] + [""]
- module = sys.modules.get(sorted(candidates, key=len, reverse=True)[0], None)
-
- if module is None:
- return None
-
- obj: Union[ModuleType, Any, None] = module
- dotted_name = target.replace(module.__name__ + ".", "")
-
- for name in dotted_name.split("."):
- obj = getattr(obj, name, None)
- if obj is None:
- return None
-
- try:
- _, line = inspect.getsourcelines(obj) # type: ignore
-
- # Correct off by one error for docstrings that don't start with a newline.
- nl = (obj.__doc__ or "").startswith("\n")
- return line + int(offset) - (not nl)
- except Exception:
- logger.debug(
- "Unable to determine diagnostic location\n%s", traceback.format_exc()
- )
- return None
-
- def emit(self, record: logging.LogRecord) -> None:
- conditions = [
- "sphinx" not in record.name,
- record.levelno not in {logging.WARNING, logging.ERROR},
- not self.translator,
- ]
-
- if any(conditions):
- # Log the record as normal
- super().emit(record)
- return
-
- # Only process errors/warnings once.
- if not self.only_once.filter(record):
- return
-
- # Let sphinx do what it does to warning/error messages
- self.translator.filter(record) # type: ignore
-
- loc = record.location if isinstance(record, SphinxLogRecord) else ""
- doc, lineno = self.get_location(loc)
- line = lineno or 1
- logger.debug("Reporting diagnostic at %s:%s", doc, line)
-
- try:
- # Not every message contains a string...
- if not isinstance(record.msg, str):
- message = str(record.msg)
- else:
- message = record.msg
-
- # Only attempt to format args if there are args to format
- if record.args is not None and len(record.args) > 0:
- message = message % record.args
-
- except Exception:
- message = str(record.msg)
- logger.error(
- "Unable to format diagnostic message: %s", traceback.format_exc()
- )
-
- diagnostic = Diagnostic(
- range=Range(
- start=Position(line=line - 1, character=0),
- end=Position(line=line, character=0),
- ),
- message=message,
- severity=DIAGNOSTIC_SEVERITY.get(
- record.levelno, DiagnosticSeverity.Warning
- ),
- )
-
- if doc not in self.diagnostics:
- self.diagnostics[doc] = [diagnostic]
- else:
- self.diagnostics[doc].append(diagnostic)
-
- super().emit(record)
diff --git a/lib/esbonio/esbonio/lsp/sphinx/directives.json b/lib/esbonio/esbonio/lsp/sphinx/directives.json
deleted file mode 100644
index 2ff971a57..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/directives.json
+++ /dev/null
@@ -1,2627 +0,0 @@
-{
- "c:alias(sphinx.domains.c.CAliasObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-alias",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:alias",
- "is_markdown": true,
- "description": [
- "Insert one or more alias declarations. Each entity can be specified",
- "as they can in the [c:any](https://www.sphinx-doc.org/en/master/_sources/usage/restructuredtext/domains.rst.txt#None) role.",
- "",
- "For example:",
- "",
- "```",
- ".. c:var:: int data",
- ".. c:function:: int f(double k)",
- "",
- ".. c:alias:: data",
- " f",
- "```",
- "",
- "becomes",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "Options",
- "",
- "Insert nested declarations as well, up to the total depth given.",
- "Use 0 for infinite depth and 1 for just the mentioned declaration.",
- "Defaults to 1.",
- "",
- "",
- "",
- "",
- "",
- "Skip the mentioned declarations and only render nested declarations.",
- "Requires `maxdepth` either 0 or at least 2."
- ],
- "options": {}
- },
- "c:enum(sphinx.domains.c.CEnumObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-enum",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:enum",
- "is_markdown": true,
- "description": [
- "Describes a C enum."
- ],
- "options": {}
- },
- "c:enumerator(sphinx.domains.c.CEnumeratorObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-enumerator",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:enumerator",
- "is_markdown": true,
- "description": [
- "Describes a C enumerator."
- ],
- "options": {}
- },
- "c:function(sphinx.domains.c.CFunctionObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-function",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:function",
- "is_markdown": true,
- "description": [
- "Describes a C function. The signature should be given as in C, e.g.:",
- "",
- "```",
- ".. c:function:: PyObject *PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)",
- "```",
- "",
- "Note that you don't have to backslash-escape asterisks in the signature, as",
- "it is not parsed by the reST inliner.",
- "",
- "In the description of a function you can use the following info fields",
- "(see also [info-field-lists](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists)).",
- "- `param`, `parameter`, `arg`, `argument`,",
- "Description of a parameter.",
- "- `type`: Type of a parameter,",
- "written as if passed to the [c:expr](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#role-c-expr) role.",
- "- `returns`, `return`: Description of the return value.",
- "- `rtype`: Return type,",
- "written as if passed to the [c:expr](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#role-c-expr) role.",
- "- `retval`, `retvals`: An alternative to `returns` for describing",
- "the result of the function.",
- "",
- "",
- "",
- "For example:",
- "",
- "```",
- ".. c:function:: PyObject *PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems)",
- "",
- " :param type: description of the first parameter.",
- " :param nitems: description of the second parameter.",
- " :returns: a result.",
- " :retval NULL: under some conditions.",
- " :retval NULL: under some other conditions as well.",
- "```",
- "",
- "which renders as",
- "",
- "** for some editors (e.g., vim) to stop bold-highlighting the source",
- "| | |",
- "|-|-|",
- "| param type | description of the first parameter. |",
- "| param nitems | description of the second parameter. |",
- "| returns | a result. |",
- "| retval NULL | under some conditions. |",
- "| retval NULL | under some other conditions as well. |"
- ],
- "options": {}
- },
- "c:macro(sphinx.domains.c.CMacroObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-macro",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:macro",
- "is_markdown": true,
- "description": [
- "Describes a C macro, i.e., a C-language `#define`, without the replacement",
- "text.",
- "",
- "In the description of a macro you can use the same info fields as for the",
- "[c:function](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-function) directive."
- ],
- "options": {}
- },
- "c:member(sphinx.domains.c.CMemberObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-member",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:member",
- "is_markdown": true,
- "description": [
- "Describes a C struct member or variable. Example signature:",
- "",
- "```",
- ".. c:member:: PyObject *PyTypeObject.tp_bases",
- "```",
- "",
- "The difference between the two directives is only cosmetic."
- ],
- "options": {}
- },
- "c:namespace(sphinx.domains.c.CNamespaceObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-namespace",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:namespace",
- "is_markdown": true,
- "description": [
- "Changes the current scope for the subsequent objects to the given scope, and",
- "resets the namespace directive stack. Note that nested scopes can be",
- "specified by separating with a dot, e.g.:",
- "",
- "```",
- ".. c:namespace:: Namespace1.Namespace2.SomeStruct.AnInnerStruct",
- "```",
- "",
- "All subsequent objects will be defined as if their name were declared with",
- "the scope prepended. The subsequent cross-references will be searched for",
- "starting in the current scope.",
- "",
- "Using `NULL` or `0` as the scope will change to global scope."
- ],
- "options": {}
- },
- "c:namespace-pop(sphinx.domains.c.CNamespacePopObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-namespace-pop",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:namespace-pop",
- "is_markdown": true,
- "description": [
- "Undo the previous `c:namespace-push` directive (not just pop a scope).",
- "For example, after:",
- "",
- "```",
- ".. c:namespace:: A.B",
- "",
- ".. c:namespace-push:: C.D",
- "",
- ".. c:namespace-pop::",
- "```",
- "",
- "the current scope will be `A.B` (not `A.B.C`).",
- "",
- "If no previous `c:namespace-push` directive has been used, but only a",
- "`c:namespace` directive, then the current scope will be reset to global",
- "scope. That is, `.. c:namespace:: A.B` is equivalent to:",
- "",
- "```",
- ".. c:namespace:: NULL",
- "",
- ".. c:namespace-push:: A.B",
- "```"
- ],
- "options": {}
- },
- "c:namespace-push(sphinx.domains.c.CNamespacePushObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-namespace-push",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:namespace-push",
- "is_markdown": true,
- "description": [
- "Change the scope relatively to the current scope. For example, after:",
- "",
- "```",
- ".. c:namespace:: A.B",
- "",
- ".. c:namespace-push:: C.D",
- "```",
- "",
- "the current scope will be `A.B.C.D`."
- ],
- "options": {}
- },
- "c:struct(sphinx.domains.c.CStructObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-struct",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:struct",
- "is_markdown": true,
- "description": [
- "Describes a C struct."
- ],
- "options": {}
- },
- "c:type(sphinx.domains.c.CTypeObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-type",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:type",
- "is_markdown": true,
- "description": [
- "Describes a C type, either as a typedef, or the alias for an unspecified",
- "type."
- ],
- "options": {}
- },
- "c:union(sphinx.domains.c.CUnionObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-union",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:union",
- "is_markdown": true,
- "description": [
- "Describes a C union."
- ],
- "options": {}
- },
- "c:var(sphinx.domains.c.CMemberObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-c-var",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "c:var",
- "is_markdown": true,
- "description": [
- "Describes a C struct member or variable. Example signature:",
- "",
- "```",
- ".. c:member:: PyObject *PyTypeObject.tp_bases",
- "```",
- "",
- "The difference between the two directives is only cosmetic."
- ],
- "options": {}
- },
- "cpp:alias(sphinx.domains.cpp.CPPAliasObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-alias",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:alias",
- "is_markdown": true,
- "description": [
- "Insert one or more alias declarations. Each entity can be specified",
- "as they can in the [cpp:any](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#role-cpp-any) role.",
- "If the name of a function is given (as opposed to the complete signature),",
- "then all overloads of the function will be listed.",
- "",
- "For example:",
- "",
- "```",
- ".. cpp:alias:: Data::a",
- " overload_example::C::f",
- "```",
- "",
- "becomes",
- "",
- "",
- "",
- "whereas:",
- "",
- "```",
- ".. cpp:alias:: void overload_example::C::f(double d) const",
- " void overload_example::C::f(double d)",
- "```",
- "",
- "becomes",
- "",
- "",
- "",
- "",
- "Options",
- "",
- "Insert nested declarations as well, up to the total depth given.",
- "Use 0 for infinite depth and 1 for just the mentioned declaration.",
- "Defaults to 1.",
- "",
- "",
- "",
- "",
- "",
- "Skip the mentioned declarations and only render nested declarations.",
- "Requires `maxdepth` either 0 or at least 2."
- ],
- "options": {}
- },
- "cpp:class(sphinx.domains.cpp.CPPClassObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-class",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:class",
- "is_markdown": true,
- "description": [
- "Describe a class/struct, possibly with specification of inheritance, e.g.,:",
- "",
- "```",
- ".. cpp:class:: MyClass : public MyBase, MyOtherBase",
- "```",
- "",
- "The difference between [cpp:class](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-class) and [cpp:struct](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-struct) is",
- "only cosmetic: the prefix rendered in the output, and the specifier shown",
- "in the index.",
- "",
- "The class can be directly declared inside a nested scope, e.g.,:",
- "",
- "```",
- ".. cpp:class:: OuterScope::MyClass : public MyBase, MyOtherBase",
- "```",
- "",
- "A class template can be declared:",
- "",
- "```",
- ".. cpp:class:: template std::array",
- "```",
- "",
- "or with a line break:",
- "",
- "```",
- ".. cpp:class:: template \\",
- " std::array",
- "```",
- "",
- "Full and partial template specialisations can be declared:",
- "",
- "```",
- ".. cpp:class:: template<> \\",
- " std::array",
- "",
- ".. cpp:class:: template \\",
- " std::array",
- "```"
- ],
- "options": {}
- },
- "cpp:concept(sphinx.domains.cpp.CPPConceptObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-concept",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:concept",
- "is_markdown": true,
- "description": [
- "The support for concepts is experimental. It is based on the",
- "current draft standard and the Concepts Technical Specification.",
- "The features may change as they evolve.",
- "",
- "Describe a concept. It must have exactly 1 template parameter list. The name",
- "may be a nested name. Example:",
- "",
- "```",
- ".. cpp:concept:: template std::Iterator",
- "",
- " Proxy to an element of a notional sequence that can be compared,",
- " indirected, or incremented.",
- "",
- " **Notation**",
- "",
- " .. cpp:var:: It r",
- "",
- " An lvalue.",
- "",
- " **Valid Expressions**",
- "",
- " - :cpp:expr:`*r`, when :cpp:expr:`r` is dereferenceable.",
- " - :cpp:expr:`++r`, with return type :cpp:expr:`It&`, when",
- " :cpp:expr:`r` is incrementable.",
- "```",
- "",
- "This will render as follows:",
- "",
- "",
- "Proxy to an element of a notional sequence that can be compared,",
- "indirected, or incremented.",
- "",
- "Notation",
- "",
- "",
- "An lvalue.",
- "",
- "",
- "Valid Expressions",
- "- `*r`, when `r` is dereferenceable.",
- "- `++r`, with return type `It&`, when `r`",
- "is incrementable."
- ],
- "options": {}
- },
- "cpp:enum(sphinx.domains.cpp.CPPEnumObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-enum",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:enum",
- "is_markdown": true,
- "description": [
- "Describe a (scoped) enum, possibly with the underlying type specified. Any",
- "enumerators declared inside an unscoped enum will be declared both in the",
- "enum scope and in the parent scope. Examples:",
- "",
- "```",
- ".. cpp:enum:: MyEnum",
- "",
- " An unscoped enum.",
- "",
- ".. cpp:enum:: MySpecificEnum : long",
- "",
- " An unscoped enum with specified underlying type.",
- "",
- ".. cpp:enum-class:: MyScopedEnum",
- "",
- " A scoped enum.",
- "",
- ".. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type",
- "",
- " A scoped enum with non-default visibility, and with a specified",
- " underlying type.",
- "```"
- ],
- "options": {}
- },
- "cpp:enum-class(sphinx.domains.cpp.CPPEnumObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-enum-class",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:enum-class",
- "is_markdown": true,
- "description": [
- "Describe a (scoped) enum, possibly with the underlying type specified. Any",
- "enumerators declared inside an unscoped enum will be declared both in the",
- "enum scope and in the parent scope. Examples:",
- "",
- "```",
- ".. cpp:enum:: MyEnum",
- "",
- " An unscoped enum.",
- "",
- ".. cpp:enum:: MySpecificEnum : long",
- "",
- " An unscoped enum with specified underlying type.",
- "",
- ".. cpp:enum-class:: MyScopedEnum",
- "",
- " A scoped enum.",
- "",
- ".. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type",
- "",
- " A scoped enum with non-default visibility, and with a specified",
- " underlying type.",
- "```"
- ],
- "options": {}
- },
- "cpp:enum-struct(sphinx.domains.cpp.CPPEnumObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-enum-struct",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:enum-struct",
- "is_markdown": true,
- "description": [
- "Describe a (scoped) enum, possibly with the underlying type specified. Any",
- "enumerators declared inside an unscoped enum will be declared both in the",
- "enum scope and in the parent scope. Examples:",
- "",
- "```",
- ".. cpp:enum:: MyEnum",
- "",
- " An unscoped enum.",
- "",
- ".. cpp:enum:: MySpecificEnum : long",
- "",
- " An unscoped enum with specified underlying type.",
- "",
- ".. cpp:enum-class:: MyScopedEnum",
- "",
- " A scoped enum.",
- "",
- ".. cpp:enum-struct:: protected MyScopedVisibilityEnum : std::underlying_type::type",
- "",
- " A scoped enum with non-default visibility, and with a specified",
- " underlying type.",
- "```"
- ],
- "options": {}
- },
- "cpp:enumerator(sphinx.domains.cpp.CPPEnumeratorObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-enumerator",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:enumerator",
- "is_markdown": true,
- "description": [
- "Describe an enumerator, optionally with its value defined, e.g.,:",
- "",
- "```",
- ".. cpp:enumerator:: MyEnum::myEnumerator",
- "",
- ".. cpp:enumerator:: MyEnum::myOtherEnumerator = 42",
- "```"
- ],
- "options": {}
- },
- "cpp:function(sphinx.domains.cpp.CPPFunctionObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-function",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:function",
- "is_markdown": true,
- "description": [
- "Describe a function or member function, e.g.,:",
- "",
- "```",
- ".. cpp:function:: bool myMethod(int arg1, std::string arg2)",
- "",
- " A function with parameters and types.",
- "",
- ".. cpp:function:: bool myMethod(int, double)",
- "",
- " A function with unnamed parameters.",
- "",
- ".. cpp:function:: const T &MyClass::operator[](std::size_t i) const",
- "",
- " An overload for the indexing operator.",
- "",
- ".. cpp:function:: operator bool() const",
- "",
- " A casting operator.",
- "",
- ".. cpp:function:: constexpr void foo(std::string &bar[2]) noexcept",
- "",
- " A constexpr function.",
- "",
- ".. cpp:function:: MyClass::MyClass(const MyClass&) = default",
- "",
- " A copy constructor with default implementation.",
- "```",
- "",
- "Function templates can also be described:",
- "",
- "```",
- ".. cpp:function:: template \\",
- " void print(U &&u)",
- "```",
- "",
- "and function template specialisations:",
- "",
- "```",
- ".. cpp:function:: template<> \\",
- " void print(int i)",
- "```"
- ],
- "options": {}
- },
- "cpp:member(sphinx.domains.cpp.CPPMemberObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-member",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:member",
- "is_markdown": true,
- "description": [
- "Describe a variable or member variable, e.g.,:",
- "",
- "```",
- ".. cpp:member:: std::string MyClass::myMember",
- "",
- ".. cpp:var:: std::string MyClass::myOtherMember[N][M]",
- "",
- ".. cpp:member:: int a = 42",
- "```",
- "",
- "Variable templates can also be described:",
- "",
- "```",
- ".. cpp:member:: template \\",
- " constexpr T pi = T(3.1415926535897932385)",
- "```"
- ],
- "options": {}
- },
- "cpp:namespace(sphinx.domains.cpp.CPPNamespaceObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-namespace",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:namespace",
- "is_markdown": true,
- "description": [
- "Changes the current scope for the subsequent objects to the given scope, and",
- "resets the namespace directive stack. Note that the namespace does not need",
- "to correspond to C++ namespaces, but can end in names of classes, e.g.,:",
- "",
- "```",
- ".. cpp:namespace:: Namespace1::Namespace2::SomeClass::AnInnerClass",
- "```",
- "",
- "All subsequent objects will be defined as if their name were declared with",
- "the scope prepended. The subsequent cross-references will be searched for",
- "starting in the current scope.",
- "",
- "Using `NULL`, `0`, or `nullptr` as the scope will change to global",
- "scope.",
- "",
- "A namespace declaration can also be templated, e.g.,:",
- "",
- "```",
- ".. cpp:class:: template \\",
- " std::vector",
- "",
- ".. cpp:namespace:: template std::vector",
- "",
- ".. cpp:function:: std::size_t size() const",
- "```",
- "",
- "declares `size` as a member function of the class template",
- "`std::vector`. Equivalently this could have been declared using:",
- "",
- "```",
- ".. cpp:class:: template \\",
- " std::vector",
- "",
- " .. cpp:function:: std::size_t size() const",
- "```",
- "",
- "or:",
- "",
- "```",
- ".. cpp:class:: template \\",
- " std::vector",
- "```"
- ],
- "options": {}
- },
- "cpp:namespace-pop(sphinx.domains.cpp.CPPNamespacePopObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-namespace-pop",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:namespace-pop",
- "is_markdown": true,
- "description": [
- "Undo the previous `cpp:namespace-push` directive (not just pop a scope).",
- "For example, after:",
- "",
- "```",
- ".. cpp:namespace:: A::B",
- "",
- ".. cpp:namespace-push:: C::D",
- "",
- ".. cpp:namespace-pop::",
- "```",
- "",
- "the current scope will be `A::B` (not `A::B::C`).",
- "",
- "If no previous `cpp:namespace-push` directive has been used, but only a",
- "`cpp:namespace` directive, then the current scope will be reset to global",
- "scope. That is, `.. cpp:namespace:: A::B` is equivalent to:",
- "",
- "```",
- ".. cpp:namespace:: nullptr",
- "",
- ".. cpp:namespace-push:: A::B",
- "```"
- ],
- "options": {}
- },
- "cpp:namespace-push(sphinx.domains.cpp.CPPNamespacePushObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-namespace-push",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:namespace-push",
- "is_markdown": true,
- "description": [
- "Change the scope relatively to the current scope. For example, after:",
- "",
- "```",
- ".. cpp:namespace:: A::B",
- "",
- ".. cpp:namespace-push:: C::D",
- "```",
- "",
- "the current scope will be `A::B::C::D`."
- ],
- "options": {}
- },
- "cpp:struct(sphinx.domains.cpp.CPPClassObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-struct",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:struct",
- "is_markdown": true,
- "description": [
- "Describe a class/struct, possibly with specification of inheritance, e.g.,:",
- "",
- "```",
- ".. cpp:class:: MyClass : public MyBase, MyOtherBase",
- "```",
- "",
- "The difference between [cpp:class](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-class) and [cpp:struct](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-struct) is",
- "only cosmetic: the prefix rendered in the output, and the specifier shown",
- "in the index.",
- "",
- "The class can be directly declared inside a nested scope, e.g.,:",
- "",
- "```",
- ".. cpp:class:: OuterScope::MyClass : public MyBase, MyOtherBase",
- "```",
- "",
- "A class template can be declared:",
- "",
- "```",
- ".. cpp:class:: template std::array",
- "```",
- "",
- "or with a line break:",
- "",
- "```",
- ".. cpp:class:: template \\",
- " std::array",
- "```",
- "",
- "Full and partial template specialisations can be declared:",
- "",
- "```",
- ".. cpp:class:: template<> \\",
- " std::array",
- "",
- ".. cpp:class:: template \\",
- " std::array",
- "```"
- ],
- "options": {}
- },
- "cpp:type(sphinx.domains.cpp.CPPTypeObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-type",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:type",
- "is_markdown": true,
- "description": [
- "Describe a type as in a typedef declaration, a type alias declaration, or",
- "simply the name of a type with unspecified type, e.g.,:",
- "",
- "```",
- ".. cpp:type:: std::vector MyList",
- "",
- " A typedef-like declaration of a type.",
- "",
- ".. cpp:type:: MyContainer::const_iterator",
- "",
- " Declaration of a type alias with unspecified type.",
- "",
- ".. cpp:type:: MyType = std::unordered_map",
- "",
- " Declaration of a type alias.",
- "```",
- "",
- "A type alias can also be templated:",
- "",
- "```",
- ".. cpp:type:: template \\",
- " MyContainer = std::vector",
- "```",
- "",
- "The example are rendered as follows.",
- "",
- "",
- "A typedef-like declaration of a type.",
- "",
- "",
- "",
- "Declaration of a type alias with unspecified type.",
- "",
- "",
- "",
- "Declaration of a type alias."
- ],
- "options": {}
- },
- "cpp:union(sphinx.domains.cpp.CPPUnionObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-union",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:union",
- "is_markdown": true,
- "description": [
- "Describe a union."
- ],
- "options": {}
- },
- "cpp:var(sphinx.domains.cpp.CPPMemberObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-cpp-var",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "cpp:var",
- "is_markdown": true,
- "description": [
- "Describe a variable or member variable, e.g.,:",
- "",
- "```",
- ".. cpp:member:: std::string MyClass::myMember",
- "",
- ".. cpp:var:: std::string MyClass::myOtherMember[N][M]",
- "",
- ".. cpp:member:: int a = 42",
- "```",
- "",
- "Variable templates can also be described:",
- "",
- "```",
- ".. cpp:member:: template \\",
- " constexpr T pi = T(3.1415926535897932385)",
- "```"
- ],
- "options": {}
- },
- "default-domain(sphinx.directives.DefaultDomain)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-default-domain",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "default-domain",
- "is_markdown": true,
- "description": [
- "Select a new default domain. While the [primary_domain](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-primary_domain) selects a",
- "global default, this only has an effect within the same file."
- ],
- "options": {}
- },
- "describe(sphinx.directives.ObjectDescription)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-describe",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "describe",
- "is_markdown": true,
- "description": [
- "This directive produces the same formatting as the specific ones provided by",
- "domains, but does not create index entries or cross-referencing targets.",
- "Example:",
- "",
- "```",
- ".. describe:: PAPER",
- "",
- " You can set this variable to select a paper size.",
- "```"
- ],
- "options": {}
- },
- "envvar(sphinx.domains.std.EnvVar)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-envvar",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "envvar",
- "is_markdown": true,
- "description": [
- "Describes an environment variable that the documented code or program uses",
- "or defines. Referenceable by [envvar](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-envvar)."
- ],
- "options": {}
- },
- "js:attribute(sphinx.domains.javascript.JSObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-attribute",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "js:attribute",
- "is_markdown": true,
- "description": [
- "Describes the attribute name of object."
- ],
- "options": {}
- },
- "js:class(sphinx.domains.javascript.JSConstructor)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-class",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "js:class",
- "is_markdown": true,
- "description": [
- "Describes a constructor that creates an object. This is basically like a",
- "function but will show up with a class prefix:",
- "",
- "```",
- ".. js:class:: MyAnimal(name[, age])",
- "",
- " :param string name: The name of the animal",
- " :param number age: an optional age for the animal",
- "```",
- "",
- "This is rendered as:",
- "",
- "",
- "| | |",
- "|-|-|",
- "| param string name | The name of the animal |",
- "| param number age | an optional age for the animal |"
- ],
- "options": {}
- },
- "js:data(sphinx.domains.javascript.JSObject)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-data",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "js:data",
- "is_markdown": true,
- "description": [
- "Describes a global variable or constant."
- ],
- "options": {}
- },
- "js:function(sphinx.domains.javascript.JSCallable)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-function",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "js:function",
- "is_markdown": true,
- "description": [
- "Describes a JavaScript function or method. If you want to describe",
- "arguments as optional use square brackets as [documented ](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#signatures)",
- "for Python signatures.",
- "",
- "You can use fields to give more details about arguments and their expected",
- "types, errors which may be thrown by the function, and the value being",
- "returned:",
- "",
- "```",
- ".. js:function:: $.getJSON(href, callback[, errback])",
- "",
- " :param string href: An URI to the location of the resource.",
- " :param callback: Gets called with the object.",
- " :param errback:",
- " Gets called in case the request fails. And a lot of other",
- " text so we need multiple lines.",
- " :throws SomeError: For whatever reason in that case.",
- " :returns: Something.",
- "```",
- "",
- "This is rendered as:",
- "",
- "",
- "| | |",
- "|-|-|",
- "| param string href | An URI to the location of the resource. |",
- "| param callback | Gets called with the object. |",
- "| param errback | Gets called in case the request fails. And a lot of other",
- "text so we need multiple lines. |",
- "| throws SomeError | For whatever reason in that case. |",
- "| returns | Something. |"
- ],
- "options": {}
- },
- "js:method(sphinx.domains.javascript.JSCallable)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-method",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "js:method",
- "is_markdown": true,
- "description": [
- "This directive is an alias for [js:function](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-function), however it describes",
- "a function that is implemented as a method on a class object."
- ],
- "options": {}
- },
- "js:module(sphinx.domains.javascript.JSModule)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-js-module",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "js:module",
- "is_markdown": true,
- "description": [
- "This directive sets the module name for object declarations that follow",
- "after. The module name is used in the global module index and in cross",
- "references. This directive does not create an object heading like",
- "[py:class](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-class) would, for example.",
- "",
- "By default, this directive will create a linkable entity and will cause an",
- "entry in the global module index, unless the `noindex` option is",
- "specified. If this option is specified, the directive will only update the",
- "current module name."
- ],
- "options": {}
- },
- "object(sphinx.directives.ObjectDescription)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-object",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "object",
- "is_markdown": true,
- "description": [
- "This directive produces the same formatting as the specific ones provided by",
- "domains, but does not create index entries or cross-referencing targets.",
- "Example:",
- "",
- "```",
- ".. describe:: PAPER",
- "",
- " You can set this variable to select a paper size.",
- "```"
- ],
- "options": {}
- },
- "option(sphinx.domains.std.Cmdoption)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-option",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "option",
- "is_markdown": true,
- "description": [
- "Describes a command line argument or switch. Option argument names should",
- "be enclosed in angle brackets. Examples:",
- "",
- "```",
- ".. option:: dest_dir",
- "",
- " Destination directory.",
- "",
- ".. option:: -m , --module ",
- "",
- " Run a module as a script.",
- "```",
- "",
- "The directive will create cross-reference targets for the given options,",
- "referenceable by [option](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-option) (in the example case, you'd use something",
- "like `:option:`dest_dir``, `:option:`-m``, or `:option:`--module``).",
- "",
- "`cmdoption` directive is a deprecated alias for the `option` directive."
- ],
- "options": {}
- },
- "program(sphinx.domains.std.Program)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-program",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "program",
- "is_markdown": true,
- "description": [
- "Like [py:currentmodule](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-currentmodule), this directive produces no output.",
- "Instead, it serves to notify Sphinx that all following [option](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-option)",
- "directives document options for the program called name.",
- "",
- "If you use [program](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-program), you have to qualify the references in your",
- "[option](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-option) roles by the program name, so if you have the following",
- "situation",
- "",
- "```",
- ".. program:: rm",
- "",
- ".. option:: -r",
- "",
- " Work recursively.",
- "",
- ".. program:: svn",
- "",
- ".. option:: -r ",
- "",
- " Specify the revision to work upon.",
- "```",
- "",
- "then `:option:`rm -r`` would refer to the first option, while",
- "`:option:`svn -r`` would refer to the second one.",
- "",
- "If `None` is passed to the argument, the directive will reset the",
- "current program name.",
- "",
- "The program name may contain spaces (in case you want to document",
- "subcommands like `svn add` and `svn commit` separately)."
- ],
- "options": {}
- },
- "py:attribute(sphinx.domains.python.PyAttribute)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-attribute",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:attribute",
- "is_markdown": true,
- "description": [
- "Describes an object data attribute. The description should include",
- "information about the type of the data to be expected and whether it may be",
- "changed directly.",
- "options",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "Describe the location where the object is defined if the object is",
- "imported from other modules"
- ],
- "options": {}
- },
- "py:class(sphinx.domains.python.PyClasslike)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-class",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:class",
- "is_markdown": true,
- "description": [
- "Describes a class. The signature can optionally include parentheses with",
- "parameters which will be shown as the constructor arguments. See also",
- "[signatures](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#signatures).",
- "",
- "Methods and attributes belonging to the class should be placed in this",
- "directive's body. If they are placed outside, the supplied name should",
- "contain the class name so that cross-references still work. Example:",
- "",
- "```",
- ".. py:class:: Foo",
- "",
- " .. py:method:: quux()",
- "",
- "-- or --",
- "",
- ".. py:class:: Bar",
- "",
- ".. py:method:: Bar.quux()",
- "```",
- "",
- "The first way is the preferred one.",
- "options",
- "",
- "Describe the location where the object is defined if the object is",
- "imported from other modules",
- "",
- "",
- "",
- "",
- "",
- "Indicate the class is a final class."
- ],
- "options": {}
- },
- "py:classmethod(sphinx.domains.python.PyClassMethod)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-classmethod",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:classmethod",
- "is_markdown": true,
- "description": [
- "Like [py:method](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-method), but indicates that the method is a class method."
- ],
- "options": {}
- },
- "py:currentmodule(sphinx.domains.python.PyCurrentModule)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-currentmodule",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:currentmodule",
- "is_markdown": true,
- "description": [
- "This directive tells Sphinx that the classes, functions etc. documented from",
- "here are in the given module (like [py:module](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-module)), but it will not",
- "create index entries, an entry in the Global Module Index, or a link target",
- "for [py:mod](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#role-py-mod). This is helpful in situations where documentation",
- "for things in a module is spread over multiple files or sections -- one",
- "location has the [py:module](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-module) directive, the others only",
- "[py:currentmodule](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-currentmodule)."
- ],
- "options": {}
- },
- "py:data(sphinx.domains.python.PyVariable)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-data",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:data",
- "is_markdown": true,
- "description": [
- "Describes global data in a module, including both variables and values used",
- "as \"defined constants.\" Class and object attributes are not documented",
- "using this environment.",
- "options",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "Describe the location where the object is defined if the object is",
- "imported from other modules"
- ],
- "options": {}
- },
- "py:decorator(sphinx.domains.python.PyDecoratorFunction)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-decorator",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:decorator",
- "is_markdown": true,
- "description": [
- "Describes a decorator function. The signature should represent the usage as",
- "a decorator. For example, given the functions",
- "",
- "```",
- "def removename(func):",
- " func.__name__ = ''",
- " return func",
- "",
- "def setnewname(name):",
- " def decorator(func):",
- " func.__name__ = name",
- " return func",
- " return decorator",
- "```",
- "",
- "the descriptions should look like this:",
- "",
- "```",
- ".. py:decorator:: removename",
- "",
- " Remove name of the decorated function.",
- "",
- ".. py:decorator:: setnewname(name)",
- "",
- " Set name of the decorated function to *name*.",
- "```",
- "",
- "(as opposed to `.. py:decorator:: removename(func)`.)",
- "",
- "There is no `py:deco` role to link to a decorator that is marked up with",
- "this directive; rather, use the [py:func](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#role-py-func) role."
- ],
- "options": {}
- },
- "py:decoratormethod(sphinx.domains.python.PyDecoratorMethod)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-decoratormethod",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:decoratormethod",
- "is_markdown": true,
- "description": [
- "Same as [py:decorator](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-decorator), but for decorators that are methods.",
- "",
- "Refer to a decorator method using the [py:meth](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#role-py-meth) role."
- ],
- "options": {}
- },
- "py:exception(sphinx.domains.python.PyClasslike)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-exception",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:exception",
- "is_markdown": true,
- "description": [
- "Describes an exception class. The signature can, but need not include",
- "parentheses with constructor arguments.",
- "options",
- "",
- "Indicate the class is a final class."
- ],
- "options": {}
- },
- "py:function(sphinx.domains.python.PyFunction)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-function",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:function",
- "is_markdown": true,
- "description": [
- "Describes a module-level function. The signature should include the",
- "parameters as given in the Python function definition, see [signatures](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#signatures).",
- "For example:",
- "",
- "```",
- ".. py:function:: Timer.repeat(repeat=3, number=1000000)",
- "```",
- "",
- "For methods you should use [py:method](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-method).",
- "",
- "The description normally includes information about the parameters required",
- "and how they are used (especially whether mutable objects passed as",
- "parameters are modified), side effects, and possible exceptions.",
- "",
- "This information can (in any `py` directive) optionally be given in a",
- "structured form, see [info-field-lists](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists).",
- "options",
- "",
- "Indicate the function is an async function.",
- "",
- "",
- "",
- "",
- "",
- "Describe the location where the object is defined if the object is",
- "imported from other modules"
- ],
- "options": {}
- },
- "py:method(sphinx.domains.python.PyMethod)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-method",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:method",
- "is_markdown": true,
- "description": [
- "Describes an object method. The parameters should not include the `self`",
- "parameter. The description should include similar information to that",
- "described for `function`. See also [signatures](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#signatures) and",
- "[info-field-lists](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#info-field-lists).",
- "options",
- "",
- "Indicate the method is an abstract method.",
- "",
- "",
- "",
- "",
- "",
- "Indicate the method is an async method.",
- "",
- "",
- "",
- "",
- "",
- "Describe the location where the object is defined if the object is",
- "imported from other modules",
- "",
- "",
- "",
- "",
- "",
- "Indicate the method is a class method.",
- "",
- "",
- "",
- "",
- "",
- "Indicate the class is a final method.",
- "",
- "",
- "",
- "",
- "",
- "Indicate the method is a property.",
- "",
- "",
- "",
- "",
- "Use [py:property](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-property) instead.",
- "",
- "",
- "",
- "",
- "Indicate the method is a static method."
- ],
- "options": {}
- },
- "py:module(sphinx.domains.python.PyModule)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-module",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:module",
- "is_markdown": true,
- "description": [
- "This directive marks the beginning of the description of a module (or package",
- "submodule, in which case the name should be fully qualified, including the",
- "package name). It does not create content (like e.g. [py:class](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-class)",
- "does).",
- "",
- "This directive will also cause an entry in the global module index.",
- "options",
- "",
- "Indicate platforms which the module is available (if it is available on",
- "all platforms, the option should be omitted). The keys are short",
- "identifiers; examples that are in use include \"IRIX\", \"Mac\", \"Windows\"",
- "and \"Unix\". It is important to use a key which has already been used when",
- "applicable.",
- "",
- "",
- "",
- "Consist of one sentence describing the module's purpose -- it is currently",
- "only used in the Global Module Index.",
- "",
- "",
- "",
- "Mark a module as deprecated; it will be designated as such in various",
- "locations then."
- ],
- "options": {}
- },
- "py:property(sphinx.domains.python.PyProperty)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-property",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:property",
- "is_markdown": true,
- "description": [
- "Describes an object property.",
- "",
- "",
- "options",
- "",
- "Indicate the property is abstract.",
- "",
- "",
- "",
- "Indicate the property is a classmethod.",
- "versionaddedd: 4.2"
- ],
- "options": {}
- },
- "py:staticmethod(sphinx.domains.python.PyStaticMethod)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-staticmethod",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "py:staticmethod",
- "is_markdown": true,
- "description": [
- "Like [py:method](https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-py-method), but indicates that the method is a static method."
- ],
- "options": {}
- },
- "rst:directive(sphinx.domains.rst.ReSTDirective)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-rst-directive",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "rst:directive",
- "is_markdown": true,
- "description": [
- "Describes a reST directive. The name can be a single directive name or",
- "actual directive syntax (.. prefix and :: suffix) with arguments that",
- "will be rendered differently. For example:",
- "",
- "```",
- ".. rst:directive:: foo",
- "",
- " Foo description.",
- "",
- ".. rst:directive:: .. bar:: baz",
- "",
- " Bar description.",
- "```",
- "",
- "will be rendered as:",
- "",
- "",
- "Foo description.",
- "",
- "",
- "",
- "Bar description."
- ],
- "options": {}
- },
- "rst:directive:option(sphinx.domains.rst.ReSTDirectiveOption)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-rst-directive-option",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "rst:directive:option",
- "is_markdown": true,
- "description": [
- "Describes an option for reST directive. The name can be a single option",
- "name or option name with arguments which separated with colon (`:`).",
- "For example:",
- "",
- "```",
- ".. rst:directive:: toctree",
- "",
- " .. rst:directive:option:: caption: caption of ToC",
- "",
- " .. rst:directive:option:: glob",
- "```",
- "",
- "will be rendered as:",
- "",
- "",
- "",
- "",
- "",
- "",
- "options",
- "",
- "Describe the type of option value.",
- "",
- "For example:",
- "",
- "```",
- ".. rst:directive:: toctree",
- "",
- " .. rst:directive:option:: maxdepth",
- " :type: integer or no value",
- "```"
- ],
- "options": {}
- },
- "rst:role(sphinx.domains.rst.ReSTRole)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#directive-rst-role",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "rst:role",
- "is_markdown": true,
- "description": [
- "Describes a reST role. For example:",
- "",
- "```",
- ".. rst:role:: foo",
- "",
- " Foo description.",
- "```",
- "",
- "will be rendered as:",
- "",
- "",
- "Foo description."
- ],
- "options": {}
- },
- "centered(sphinx.directives.other.Centered)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-centered",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "centered",
- "is_markdown": true,
- "description": [
- "This directive creates a centered boldfaced line of text. Use it as",
- "follows:",
- "",
- "```",
- ".. centered:: LICENSE AGREEMENT",
- "```"
- ],
- "options": {}
- },
- "code-block(sphinx.directives.code.CodeBlock)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "code-block",
- "is_markdown": true,
- "description": [
- "Example:",
- "",
- "```",
- ".. code-block:: ruby",
- "",
- " Some Ruby code.",
- "```",
- "",
- "The directive's alias name [sourcecode](https://www.sphinx-doc.org/en/master/_sources/usage/restructuredtext/directives.rst.txt#None) works as well. This",
- "directive takes a language name as an argument. It can be [any lexer alias",
- "supported by Pygments](https://pygments.org/docs/lexers/). If it is not",
- "given, the setting of [highlight](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-highlight) directive will be used.",
- "If not set, [highlight_language](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-highlight_language) will be used.",
- "",
- "",
- "options",
- "",
- "Enable to generate line numbers for the code block:",
- "",
- "```",
- ".. code-block:: ruby",
- " :linenos:",
- "",
- " Some more Ruby code.",
- "```",
- "",
- "",
- "",
- "Set the first line number of the code block. If present, `linenos`",
- "option is also automatically activated:",
- "",
- "```",
- ".. code-block:: ruby",
- " :lineno-start: 10",
- "",
- " Some more Ruby code, with line numbering starting at 10.",
- "```",
- "",
- "",
- "",
- "",
- "",
- "Emphasize particular lines of the code block:",
- "",
- "```",
- ".. code-block:: python",
- " :emphasize-lines: 3,5",
- "",
- " def some_function():",
- " interesting = False",
- " print 'This line is highlighted.'",
- " print 'This one is not...'",
- " print '...but this one is.'",
- "```",
- "",
- "",
- "",
- "",
- "",
- "rst:directive:option: force",
- ":type: no value",
- "",
- "Ignore minor errors on highlighting",
- "",
- ".. versionchanged:: 2.1",
- "",
- "Set a caption to the code block.",
- "",
- "",
- "",
- "",
- "",
- "Define implicit target name that can be referenced by using",
- "[ref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref). For example:",
- "",
- "```",
- ".. code-block:: python",
- " :caption: this.py",
- " :name: this-py",
- "",
- " print 'Explicit is better than implicit.'",
- "```",
- "",
- "In order to cross-reference a code-block using either the",
- "[ref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref) or the [numref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-numref) role, it is necessary",
- "that both name and caption be defined. The",
- "argument of name can then be given to [numref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-numref)",
- "to generate the cross-reference. Example:",
- "",
- "```",
- "See :numref:`this-py` for an example.",
- "```",
- "",
- "When using [ref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref), it is possible to generate a cross-reference",
- "with only name defined, provided an explicit title is",
- "given. Example:",
- "",
- "```",
- "See :ref:`this code snippet ` for an example.",
- "```",
- "",
- "",
- "",
- "",
- "",
- "Strip indentation characters from the code block. When number given,",
- "leading N characters are removed. When no argument given, leading spaces",
- "are removed via [textwrap.dedent()](https://www.sphinx-doc.org/en/master/_sources/usage/restructuredtext/directives.rst.txt#None). For example:",
- "",
- "```",
- ".. code-block:: ruby",
- " :linenos:",
- " :dedent: 4",
- "",
- " some ruby code",
- "```",
- "",
- "",
- "",
- "",
- "",
- "",
- "",
- "If given, minor errors on highlighting are ignored."
- ],
- "options": {}
- },
- "codeauthor(sphinx.directives.other.Author)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-codeauthor",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "codeauthor",
- "is_markdown": true,
- "description": [
- "The [codeauthor](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-codeauthor) directive, which can appear multiple times, names",
- "the authors of the described code, just like [sectionauthor](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-sectionauthor) names",
- "the author(s) of a piece of documentation. It too only produces output if",
- "the [show_authors](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-show_authors) configuration value is `True`."
- ],
- "options": {}
- },
- "deprecated(sphinx.domains.changeset.VersionChange)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-deprecated",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "deprecated",
- "is_markdown": true,
- "description": [
- "Similar to [versionchanged](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-versionchanged), but describes when the feature was",
- "deprecated. An explanation can also be given, for example to inform the",
- "reader what should be used instead. Example:",
- "",
- "```",
- ".. deprecated:: 3.1",
- " Use :func:`spam` instead.",
- "```"
- ],
- "options": {}
- },
- "glossary(sphinx.domains.std.Glossary)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-glossary",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "glossary",
- "is_markdown": true,
- "description": [
- "This directive must contain a reST definition-list-like markup with terms and",
- "definitions. The definitions will then be referenceable with the",
- "[term](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-term) role. Example:",
- "",
- "```",
- ".. glossary::",
- "",
- " environment",
- " A structure where information about all documents under the root is",
- " saved, and used for cross-referencing. The environment is pickled",
- " after the parsing stage, so that successive runs only need to read",
- " and parse new and changed documents.",
- "",
- " source directory",
- " The directory which, including its subdirectories, contains all",
- " source files for one Sphinx project.",
- "```",
- "",
- "In contrast to regular definition lists, multiple terms per entry are",
- "allowed, and inline markup is allowed in terms. You can link to all of the",
- "terms. For example:",
- "",
- "```",
- ".. glossary::",
- "",
- " term 1",
- " term 2",
- " Definition of both terms.",
- "```",
- "",
- "(When the glossary is sorted, the first term determines the sort order.)",
- "",
- "If you want to specify \"grouping key\" for general index entries, you can put",
- "a \"key\" as \"term : key\". For example:",
- "",
- "```",
- ".. glossary::",
- "",
- " term 1 : A",
- " term 2 : B",
- " Definition of both terms.",
- "```",
- "",
- "Note that \"key\" is used for grouping key as is.",
- "The \"key\" isn't normalized; key \"A\" and \"a\" become different groups.",
- "The whole characters in \"key\" is used instead of a first character; it is",
- "used for \"Combining Character Sequence\" and \"Surrogate Pairs\" grouping key.",
- "",
- "In i18n situation, you can specify \"localized term : key\" even if original",
- "text only have \"term\" part. In this case, translated \"localized term\" will be",
- "categorized in \"key\" group."
- ],
- "options": {}
- },
- "highlight(sphinx.directives.code.Highlight)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-highlight",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "highlight",
- "is_markdown": true,
- "description": [
- "Example:",
- "",
- "```",
- ".. highlight:: c",
- "```",
- "",
- "This language is used until the next `highlight` directive is encountered.",
- "As discussed previously, language can be any lexer alias supported by",
- "Pygments.",
- "options",
- "",
- "Enable to generate line numbers for code blocks.",
- "",
- "This option takes an optional number as threshold parameter. If any",
- "threshold given, the directive will produce line numbers only for the code",
- "blocks longer than N lines. If not given, line numbers will be produced",
- "for all of code blocks.",
- "",
- "Example:",
- "",
- "```",
- ".. highlight:: python",
- " :linenothreshold: 5",
- "```",
- "",
- "",
- "",
- "If given, minor errors on highlighting are ignored."
- ],
- "options": {}
- },
- "hlist(sphinx.directives.other.HList)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-hlist",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "hlist",
- "is_markdown": true,
- "description": [
- "This directive must contain a bullet list. It will transform it into a more",
- "compact list by either distributing more than one item horizontally, or",
- "reducing spacing between items, depending on the builder.",
- "",
- "For builders that support the horizontal distribution, there is a `columns`",
- "option that specifies the number of columns; it defaults to 2. Example:",
- "",
- "```",
- ".. hlist::",
- " :columns: 3",
- "",
- " * A list of",
- " * short items",
- " * that should be",
- " * displayed",
- " * horizontally",
- "```"
- ],
- "options": {}
- },
- "index(sphinx.domains.index.IndexDirective)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-index",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "index",
- "is_markdown": true,
- "description": [
- "This directive contains one or more index entries. Each entry consists of a",
- "type and a value, separated by a colon.",
- "",
- "For example:",
- "",
- "```",
- ".. index::",
- " single: execution; context",
- " module: __main__",
- " module: sys",
- " triple: module; search; path",
- "",
- "The execution context",
- "---------------------",
- "",
- "...",
- "```",
- "",
- "This directive contains five entries, which will be converted to entries in",
- "the generated index which link to the exact location of the index statement",
- "(or, in case of offline media, the corresponding page number).",
- "",
- "Since index directives generate cross-reference targets at their location in",
- "the source, it makes sense to put them before the thing they refer to --",
- "e.g. a heading, as in the example above.",
- "",
- "The possible entry types are:",
- "",
- "`single`: ",
- "Creates a single index entry. Can be made a subentry by separating the",
- "subentry text with a semicolon (this notation is also used below to",
- "describe what entries are created).",
- "",
- "`pair`: ",
- "`pair: loop; statement` is a shortcut that creates two index entries,",
- "namely `loop; statement` and `statement; loop`.",
- "",
- "`triple`: ",
- "Likewise, `triple: module; search; path` is a shortcut that creates",
- "three index entries, which are `module; search path`, `search; path,",
- "module` and `path; module search`.",
- "",
- "`see`: ",
- "`see: entry; other` creates an index entry that refers from `entry` to",
- "`other`.",
- "",
- "`seealso`: ",
- "Like `see`, but inserts \"see also\" instead of \"see\".",
- "",
- "`module, keyword, operator, object, exception, statement, builtin`: ",
- "These all create two index entries. For example, `module: hashlib`",
- "creates the entries `module; hashlib` and `hashlib; module`. (These",
- "are Python-specific and therefore deprecated.)",
- "",
- "You can mark up \"main\" index entries by prefixing them with an exclamation",
- "mark. The references to \"main\" entries are emphasized in the generated",
- "index. For example, if two pages contain",
- "",
- "```",
- ".. index:: Python",
- "```",
- "",
- "and one page contains",
- "",
- "```",
- ".. index:: ! Python",
- "```",
- "",
- "then the backlink to the latter page is emphasized among the three backlinks.",
- "",
- "For index directives containing only \"single\" entries, there is a shorthand",
- "notation:",
- "",
- "```",
- ".. index:: BNF, grammar, syntax, notation",
- "```",
- "",
- "This creates four index entries.",
- "",
- "",
- "options",
- "",
- "Define implicit target name that can be referenced by using",
- "[ref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref). For example:",
- "",
- "```",
- ".. index:: Python",
- " :name: py-index",
- "```"
- ],
- "options": {
- "single": "\nCreates a single index entry. Can be made a subentry by separating the\nsubentry text with a semicolon (this notation is also used below to\ndescribe what entries are created).\n",
- "pair": "\n`pair: loop; statement` is a shortcut that creates two index entries,\nnamely `loop; statement` and `statement; loop`.\n",
- "triple": "\nLikewise, `triple: module; search; path` is a shortcut that creates\nthree index entries, which are `module; search path`, `search; path,\nmodule` and `path; module search`.\n",
- "see": "\n`see: entry; other` creates an index entry that refers from `entry` to\n`other`.\n",
- "seealso": "\nLike `see`, but inserts \"see also\" instead of \"see\".\n",
- "module, keyword, operator, object, exception, statement, builtin": "\nThese all create two index entries. For example, `module: hashlib`\ncreates the entries `module; hashlib` and `hashlib; module`. (These\nare Python-specific and therefore deprecated.)\n"
- }
- },
- "literalinclude(sphinx.directives.code.LiteralInclude)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-literalinclude",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "literalinclude",
- "is_markdown": true,
- "description": [
- "Longer displays of verbatim text may be included by storing the example text",
- "in an external file containing only plain text. The file may be included",
- "using the `literalinclude` directive. 3 For example, to include the",
- "Python source file `example.py`, use:",
- "",
- "```",
- ".. literalinclude:: example.py",
- "```",
- "",
- "The file name is usually relative to the current file's path. However, if",
- "it is absolute (starting with `/`), it is relative to the top source",
- "directory.",
- "",
- "Additional options",
- "",
- "Like [code-block](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-code-block), the directive supports the `linenos` flag",
- "option to switch on line numbers, the `lineno-start` option to select the",
- "first line number, the `emphasize-lines` option to emphasize particular",
- "lines, the `name` option to provide an implicit target name, the",
- "`dedent` option to strip indentation characters for the code block, and a",
- "`language` option to select a language different from the current file's",
- "standard language. In addition, it supports the `caption` option; however,",
- "this can be provided with no argument to use the filename as the caption.",
- "Example with options:",
- "",
- "```",
- ".. literalinclude:: example.rb",
- " :language: ruby",
- " :emphasize-lines: 12,15-18",
- " :linenos:",
- "```",
- "",
- "Tabs in the input are expanded if you give a `tab-width` option with the",
- "desired tab width.",
- "",
- "Include files are assumed to be encoded in the [source_encoding](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-source_encoding).",
- "If the file has a different encoding, you can specify it with the",
- "`encoding` option:",
- "",
- "```",
- ".. literalinclude:: example.py",
- " :encoding: latin-1",
- "```",
- "",
- "The directive also supports including only parts of the file. If it is a",
- "Python module, you can select a class, function or method to include using",
- "the `pyobject` option:",
- "",
- "```",
- ".. literalinclude:: example.py",
- " :pyobject: Timer.start",
- "```",
- "",
- "This would only include the code lines belonging to the `start()` method",
- "in the `Timer` class within the file.",
- "",
- "Alternately, you can specify exactly which lines to include by giving a",
- "`lines` option:",
- "",
- "```",
- ".. literalinclude:: example.py",
- " :lines: 1,3,5-10,20-",
- "```",
- "",
- "This includes the lines 1, 3, 5 to 10 and lines 20 to the last line.",
- "",
- "Another way to control which part of the file is included is to use the",
- "`start-after` and `end-before` options (or only one of them). If",
- "`start-after` is given as a string option, only lines that follow the",
- "first line containing that string are included. If `end-before` is given",
- "as a string option, only lines that precede the first lines containing that",
- "string are included. The `start-at` and `end-at` options behave in a",
- "similar way, but the lines containing the matched string are included.",
- "",
- "`start-after`/`start-at` and `end-before`/`end-at` can have same string.",
- "`start-after`/`start-at` filter lines before the line that contains",
- "option string (`start-at` will keep the line). Then `end-before`/`end-at`",
- "filter lines after the line that contains option string (`end-at` will keep",
- "the line and `end-before` skip the first line).",
- "",
- "If you want to select only `[second-section]` of ini file like the",
- "following, you can use `:start-at: [second-section]` and",
- "`:end-before: [third-section]`:",
- "",
- "```",
- "[first-section]",
- "",
- "var_in_first=true",
- "",
- "[second-section]",
- "",
- "var_in_second=true",
- "",
- "[third-section]",
- "",
- "var_in_third=true",
- "```",
- "",
- "Useful cases of these option is working with tag comments.",
- "`:start-after: [initialized]` and `:end-before: [initialized]` options",
- "keep lines between comments:",
- "",
- "```",
- "if __name__ == \"__main__\":",
- " # [initialize]",
- " app.start(\":8000\")",
- " # [initialize]",
- "```",
- "",
- "When lines have been selected in any of the ways described above, the line",
- "numbers in `emphasize-lines` refer to those selected lines, counted",
- "consecutively starting at `1`.",
- "",
- "When specifying particular parts of a file to display, it can be useful to",
- "display the original line numbers. This can be done using the",
- "`lineno-match` option, which is however allowed only when the selection",
- "consists of contiguous lines.",
- "",
- "You can prepend and/or append a line to the included code, using the",
- "`prepend` and `append` option, respectively. This is useful e.g. for",
- "highlighting PHP code that doesn't include the `` markers.",
- "",
- "If you want to show the diff of the code, you can specify the old file by",
- "giving a `diff` option:",
- "",
- "```",
- ".. literalinclude:: example.py",
- " :diff: example.py.orig",
- "```",
- "",
- "This shows the diff between `example.py` and `example.py.orig` with",
- "unified diff format.",
- "",
- "A `force` option can ignore minor errors on highlighting."
- ],
- "options": {}
- },
- "math(sphinx.directives.patches.MathDirective)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-math",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "math",
- "is_markdown": true,
- "description": [
- "Directive for displayed math (math that takes the whole line for itself).",
- "",
- "The directive supports multiple equations, which should be separated by a",
- "blank line:",
- "",
- "```",
- ".. math::",
- "",
- " (a + b)^2 = a^2 + 2ab + b^2",
- "",
- " (a - b)^2 = a^2 - 2ab + b^2",
- "```",
- "",
- "In addition, each single equation is set within a `split` environment,",
- "which means that you can have multiple aligned lines in an equation,",
- "aligned at `&` and separated by `\\\\`:",
- "",
- "```",
- ".. math::",
- "",
- " (a + b)^2 &= (a + b)(a + b) \\\\",
- " &= a^2 + 2ab + b^2",
- "```",
- "",
- "For more details, look into the documentation of the [AmSMath LaTeX",
- "package](https://www.ams.org/publications/authors/tex/amslatex).",
- "",
- "When the math is only one line of text, it can also be given as a directive",
- "argument:",
- "",
- "```",
- ".. math:: (a + b)^2 = a^2 + 2ab + b^2",
- "```",
- "",
- "Normally, equations are not numbered. If you want your equation to get a",
- "number, use the `label` option. When given, it selects an internal label",
- "for the equation, by which it can be cross-referenced, and causes an equation",
- "number to be issued. See [eq](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-eq) for an example. The numbering",
- "style depends on the output format.",
- "",
- "There is also an option `nowrap` that prevents any wrapping of the given",
- "math in a math environment. When you give this option, you must make sure",
- "yourself that the math is properly set up. For example:",
- "",
- "```",
- ".. math::",
- " :nowrap:",
- "",
- " \\begin{eqnarray}",
- " y & = & ax^2 + bx + c \\\\",
- " f(x) & = & x^2 + 2xy + y^2",
- " \\end{eqnarray}",
- "```"
- ],
- "options": {}
- },
- "note(docutils.parsers.rst.directives.admonitions.Note)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-note",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "note",
- "is_markdown": true,
- "description": [
- "An especially important bit of information about an API that a user should be",
- "aware of when using whatever bit of API the note pertains to. The content of",
- "the directive should be written in complete sentences and include all",
- "appropriate punctuation.",
- "",
- "Example:",
- "",
- "```",
- ".. note::",
- "",
- " This function is not suitable for sending spam e-mails.",
- "```"
- ],
- "options": {}
- },
- "only(sphinx.directives.other.Only)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-only",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "only",
- "is_markdown": true,
- "description": [
- "Include the content of the directive only if the expression is true. The",
- "expression should consist of tags, like this:",
- "",
- "```",
- ".. only:: html and draft",
- "```",
- "",
- "Undefined tags are false, defined tags (via the `-t` command-line option or",
- "within `conf.py`, see [here ](https://www.sphinx-doc.org/en/master/usage/configuration.html#conf-tags)) are true. Boolean",
- "expressions, also using parentheses (like `html and (latex or draft)`) are",
- "supported.",
- "",
- "The format and the name of the current builder (`html`, `latex` or",
- "`text`) are always set as a tag 4. To make the distinction between",
- "format and name explicit, they are also added with the prefix `format_` and",
- "`builder_`, e.g. the epub builder defines the tags `html`, `epub`,",
- "`format_html` and `builder_epub`.",
- "",
- "These standard tags are set after the configuration file is read, so they",
- "are not available there.",
- "",
- "All tags must follow the standard Python identifier syntax as set out in",
- "the [Identifiers and keywords](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)",
- "documentation. That is, a tag expression may only consist of tags that",
- "conform to the syntax of Python variables. In ASCII, this consists of the",
- "uppercase and lowercase letters `A` through `Z`, the underscore `_`",
- "and, except for the first character, the digits `0` through `9`.",
- "",
- "",
- "",
- "",
- "",
- "This directive is designed to control only content of document. It could",
- "not control sections, labels and so on."
- ],
- "options": {}
- },
- "productionlist(sphinx.domains.std.ProductionList)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-productionlist",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "productionlist",
- "is_markdown": true,
- "description": [
- "This directive is used to enclose a group of productions. Each production",
- "is given on a single line and consists of a name, separated by a colon from",
- "the following definition. If the definition spans multiple lines, each",
- "continuation line must begin with a colon placed at the same column as in",
- "the first line.",
- "Blank lines are not allowed within `productionlist` directive arguments.",
- "",
- "The definition can contain token names which are marked as interpreted text",
- "(e.g., \"`sum ::= `integer` \"+\" `integer``\") -- this generates",
- "cross-references to the productions of these tokens. Outside of the",
- "production list, you can reference to token productions using",
- "[token](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-token).",
- "",
- "The productionGroup argument to [productionlist](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-productionlist) serves to",
- "distinguish different sets of production lists that belong to different",
- "grammars. Multiple production lists with the same productionGroup thus",
- "define rules in the same scope.",
- "",
- "Inside of the production list, tokens implicitly refer to productions",
- "from the current group. You can refer to the production of another",
- "grammar by prefixing the token with its group name and a colon, e.g,",
- "\"`otherGroup:sum`\". If the group of the token should not be shown in",
- "the production, it can be prefixed by a tilde, e.g.,",
- "\"`~otherGroup:sum`\". To refer to a production from an unnamed",
- "grammar, the token should be prefixed by a colon, e.g., \"`:sum`\".",
- "",
- "Outside of the production list,",
- "if you have given a productionGroup argument you must prefix the",
- "token name in the cross-reference with the group name and a colon,",
- "e.g., \"`myGroup:sum`\" instead of just \"`sum`\".",
- "If the group should not be shown in the title of the link either",
- "an explicit title can be given (e.g., \"`myTitle `\"),",
- "or the target can be prefixed with a tilde (e.g., \"`~myGroup:sum`\").",
- "",
- "Note that no further reST parsing is done in the production, so that you",
- "don't have to escape `*` or `|` characters."
- ],
- "options": {}
- },
- "rubric(docutils.parsers.rst.directives.body.Rubric)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-rubric",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "rubric",
- "is_markdown": true,
- "description": [
- "This directive creates a paragraph heading that is not used to create a",
- "table of contents node.",
- "",
- "If the title of the rubric is \"Footnotes\" (or the selected language's",
- "equivalent), this rubric is ignored by the LaTeX writer, since it is",
- "assumed to only contain footnote definitions and therefore would create an",
- "empty heading."
- ],
- "options": {}
- },
- "sectionauthor(sphinx.directives.other.Author)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-sectionauthor",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "sectionauthor",
- "is_markdown": true,
- "description": [
- "Identifies the author of the current section. The argument should include",
- "the author's name such that it can be used for presentation and email",
- "address. The domain name portion of the address should be lower case.",
- "Example:",
- "",
- "```",
- ".. sectionauthor:: Guido van Rossum ",
- "```",
- "",
- "By default, this markup isn't reflected in the output in any way (it helps",
- "keep track of contributions), but you can set the configuration value",
- "[show_authors](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-show_authors) to `True` to make them produce a paragraph in the",
- "output."
- ],
- "options": {}
- },
- "seealso(sphinx.directives.other.SeeAlso)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-seealso",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "seealso",
- "is_markdown": true,
- "description": [
- "Many sections include a list of references to module documentation or",
- "external documents. These lists are created using the [seealso](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-seealso)",
- "directive.",
- "",
- "The [seealso](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-seealso) directive is typically placed in a section just before",
- "any subsections. For the HTML output, it is shown boxed off from the main",
- "flow of the text.",
- "",
- "The content of the [seealso](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-seealso) directive should be a reST definition",
- "list. Example:",
- "",
- "```",
- ".. seealso::",
- "",
- " Module :py:mod:`zipfile`",
- " Documentation of the :py:mod:`zipfile` standard module.",
- "",
- " `GNU tar manual, Basic Tar Format `_",
- " Documentation for tar archive files, including GNU tar extensions.",
- "```",
- "",
- "There's also a \"short form\" allowed that looks like this:",
- "",
- "```",
- ".. seealso:: modules :py:mod:`zipfile`, :py:mod:`tarfile`",
- "```"
- ],
- "options": {}
- },
- "tabularcolumns(sphinx.directives.other.TabularColumns)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-tabularcolumns",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "tabularcolumns",
- "is_markdown": true,
- "description": [
- "This directive gives a \"column spec\" for the next table occurring in the",
- "source file. The spec is the second argument to the LaTeX `tabulary`",
- "package's environment (which Sphinx uses to translate tables). It can have",
- "values like",
- "",
- "```",
- "|l|l|l|",
- "```",
- "",
- "which means three left-adjusted, nonbreaking columns. For columns with",
- "longer text that should automatically be broken, use either the standard",
- "`p{width}` construct, or tabulary's automatic specifiers:",
- "",
- "`L`",
- "",
- "flush left column with automatic width",
- "",
- "`R`",
- "",
- "flush right column with automatic width",
- "",
- "`C`",
- "",
- "centered column with automatic width",
- "",
- "`J`",
- "",
- "justified column with automatic width",
- "",
- "The automatic widths of the `LRCJ` columns are attributed by `tabulary`",
- "in proportion to the observed shares in a first pass where the table cells",
- "are rendered at their natural \"horizontal\" widths.",
- "",
- "By default, Sphinx uses a table layout with `J` for every column.",
- "",
- "",
- "",
- "",
- "",
- "Sphinx actually uses `T` specifier having done `\\newcolumntype{T}{J}`.",
- "To revert to previous default, insert `\\newcolumntype{T}{L}` in the",
- "LaTeX preamble (see [latex_elements](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-latex_elements)).",
- "",
- "A frequent issue with tabulary is that columns with little contents are",
- "\"squeezed\". The minimal column width is a tabulary parameter called",
- "`\\tymin`. You may set it globally in the LaTeX preamble via",
- "`\\setlength{\\tymin}{40pt}` for example.",
- "",
- "Else, use the [tabularcolumns](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-tabularcolumns) directive with an explicit",
- "`p{40pt}` (for example) for that column. You may use also `l`",
- "specifier but this makes the task of setting column widths more difficult",
- "if some merged cell intersects that column.",
- "",
- "Tables with more than 30 rows are rendered using `longtable`, not",
- "`tabulary`, in order to allow pagebreaks. The `L`, `R`, ...",
- "specifiers do not work for these tables.",
- "",
- "Tables that contain list-like elements such as object descriptions,",
- "blockquotes or any kind of lists cannot be set out of the box with",
- "`tabulary`. They are therefore set with the standard LaTeX `tabular`",
- "(or `longtable`) environment if you don't give a `tabularcolumns`",
- "directive. If you do, the table will be set with `tabulary` but you",
- "must use the `p{width}` construct (or Sphinx's `\\X` and `\\Y`",
- "specifiers described below) for the columns containing these elements.",
- "",
- "Literal blocks do not work with `tabulary` at all, so tables containing",
- "a literal block are always set with `tabular`. The verbatim environment",
- "used for literal blocks only works in `p{width}` (and `\\X` or `\\Y`)",
- "columns, hence Sphinx generates such column specs for tables containing",
- "literal blocks.",
- "",
- "Since Sphinx 1.5, the `\\X{a}{b}` specifier is used (there is a backslash",
- "in the specifier letter). It is like `p{width}` with the width set to a",
- "fraction `a/b` of the current line width. You can use it in the",
- "[tabularcolumns](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-tabularcolumns) (it is not a problem if some LaTeX macro is also",
- "called `\\X`.)",
- "",
- "It is not needed for `b` to be the total number of columns, nor for the",
- "sum of the fractions of the `\\X` specifiers to add up to one. For example",
- "`|\\X{2}{5}|\\X{1}{5}|\\X{1}{5}|` is legitimate and the table will occupy",
- "80% of the line width, the first of its three columns having the same width",
- "as the sum of the next two.",
- "",
- "This is used by the `:widths:` option of the [table](https://docutils.sourceforge.io/docs/ref/rst/directives.html#table) directive.",
- "",
- "Since Sphinx 1.6, there is also the `\\Y{f}` specifier which admits a",
- "decimal argument, such has `\\Y{0.15}`: this would have the same effect as",
- "`\\X{3}{20}`.",
- "",
- "",
- "Merged cells from complex grid tables (either multi-row, multi-column, or",
- "both) now allow blockquotes, lists, literal blocks, ... as do regular",
- "cells.",
- "",
- "Sphinx's merged cells interact well with `p{width}`, `\\X{a}{b}`,",
- "`\\Y{f}` and tabulary's columns.",
- "",
- "",
- "[tabularcolumns](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-tabularcolumns) conflicts with `:widths:` option of table",
- "directives. If both are specified, `:widths:` option will be ignored."
- ],
- "options": {}
- },
- "toctree(sphinx.directives.other.TocTree)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-toctree",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "toctree",
- "is_markdown": true,
- "description": [
- "This directive inserts a \"TOC tree\" at the current location, using the",
- "individual TOCs (including \"sub-TOC trees\") of the documents given in the",
- "directive body. Relative document names (not beginning with a slash) are",
- "relative to the document the directive occurs in, absolute names are relative",
- "to the source directory. A numeric `maxdepth` option may be given to",
- "indicate the depth of the tree; by default, all levels are included. 1",
- "",
- "The representation of \"TOC tree\" is changed in each output format. The",
- "builders that output multiple files (ex. HTML) treat it as a collection of",
- "hyperlinks. On the other hand, the builders that output a single file (ex.",
- "LaTeX, man page, etc.) replace it with the content of the documents on the",
- "TOC tree.",
- "",
- "Consider this example (taken from the Python docs' library reference index):",
- "",
- "```",
- ".. toctree::",
- " :maxdepth: 2",
- "",
- " intro",
- " strings",
- " datatypes",
- " numeric",
- " (many more documents listed here)",
- "```",
- "",
- "This accomplishes two things:",
- "- Tables of contents from all those documents are inserted, with a maximum",
- "depth of two, that means one nested heading. `toctree` directives in",
- "those documents are also taken into account.",
- "- Sphinx knows the relative order of the documents `intro`,",
- "`strings` and so forth, and it knows that they are children of the shown",
- "document, the library index. From this information it generates \"next",
- "chapter\", \"previous chapter\" and \"parent chapter\" links.",
- "",
- "Entries",
- "",
- "Document titles in the [toctree](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-toctree) will be automatically read from the",
- "title of the referenced document. If that isn't what you want, you can",
- "specify an explicit title and target using a similar syntax to reST",
- "hyperlinks (and Sphinx's [cross-referencing syntax ](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#xref-syntax)). This",
- "looks like:",
- "",
- "```",
- ".. toctree::",
- "",
- " intro",
- " All about strings ",
- " datatypes",
- "```",
- "",
- "The second line above will link to the `strings` document, but will use the",
- "title \"All about strings\" instead of the title of the `strings` document.",
- "",
- "You can also add external links, by giving an HTTP URL instead of a document",
- "name.",
- "",
- "Section numbering",
- "",
- "If you want to have section numbers even in HTML output, give the",
- "toplevel toctree a `numbered` option. For example:",
- "",
- "```",
- ".. toctree::",
- " :numbered:",
- "",
- " foo",
- " bar",
- "```",
- "",
- "Numbering then starts at the heading of `foo`. Sub-toctrees are",
- "automatically numbered (don't give the `numbered` flag to those).",
- "",
- "Numbering up to a specific depth is also possible, by giving the depth as a",
- "numeric argument to `numbered`.",
- "",
- "Additional options",
- "",
- "You can use the `caption` option to provide a toctree caption and you can",
- "use the `name` option to provide an implicit target name that can be",
- "referenced by using [ref](https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref):",
- "",
- "```",
- ".. toctree::",
- " :caption: Table of Contents",
- " :name: mastertoc",
- "",
- " foo",
- "```",
- "",
- "If you want only the titles of documents in the tree to show up, not other",
- "headings of the same level, you can use the `titlesonly` option:",
- "",
- "```",
- ".. toctree::",
- " :titlesonly:",
- "",
- " foo",
- " bar",
- "```",
- "",
- "You can use \"globbing\" in toctree directives, by giving the `glob` flag",
- "option. All entries are then matched against the list of available",
- "documents, and matches are inserted into the list alphabetically. Example:",
- "",
- "```",
- ".. toctree::",
- " :glob:",
- "",
- " intro*",
- " recipe/*",
- " *",
- "```",
- "",
- "This includes first all documents whose names start with `intro`, then all",
- "documents in the `recipe` folder, then all remaining documents (except the",
- "one containing the directive, of course.) 2",
- "",
- "The special entry name `self` stands for the document containing the",
- "toctree directive. This is useful if you want to generate a \"sitemap\" from",
- "the toctree.",
- "",
- "You can use the `reversed` flag option to reverse the order of the entries",
- "in the list. This can be useful when using the `glob` flag option to",
- "reverse the ordering of the files. Example:",
- "",
- "```",
- ".. toctree::",
- " :glob:",
- " :reversed:",
- "",
- " recipe/*",
- "```",
- "",
- "You can also give a \"hidden\" option to the directive, like this:",
- "",
- "```",
- ".. toctree::",
- " :hidden:",
- "",
- " doc_1",
- " doc_2",
- "```",
- "",
- "This will still notify Sphinx of the document hierarchy, but not insert links",
- "into the document at the location of the directive -- this makes sense if you",
- "intend to insert these links yourself, in a different style, or in the HTML",
- "sidebar.",
- "",
- "In cases where you want to have only one top-level toctree and hide all other",
- "lower level toctrees you can add the \"includehidden\" option to the top-level",
- "toctree entry:",
- "",
- "```",
- ".. toctree::",
- " :includehidden:",
- "",
- " doc_1",
- " doc_2",
- "```",
- "",
- "All other toctree entries can then be eliminated by the \"hidden\" option.",
- "",
- "In the end, all documents in the [source directory](https://www.sphinx-doc.org/en/master/glossary.html#term-source-directory) (or subdirectories)",
- "must occur in some `toctree` directive; Sphinx will emit a warning if it",
- "finds a file that is not included, because that means that this file will not",
- "be reachable through standard navigation.",
- "",
- "Use [exclude_patterns](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-exclude_patterns) to explicitly exclude documents or",
- "directories from building completely. Use [the \"orphan\" metadata",
- "](https://www.sphinx-doc.org/en/master/usage/restructuredtext/field-lists.html#metadata) to let a document be built, but notify Sphinx that it is not",
- "reachable via a toctree.",
- "",
- "The \"root document\" (selected by [root_doc](https://www.sphinx-doc.org/en/master/usage/configuration.html#confval-root_doc)) is the \"root\" of the TOC",
- "tree hierarchy. It can be used as the documentation's main page, or as a",
- "\"full table of contents\" if you don't give a `maxdepth` option."
- ],
- "options": {}
- },
- "versionadded(sphinx.domains.changeset.VersionChange)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-versionadded",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "versionadded",
- "is_markdown": true,
- "description": [
- "This directive documents the version of the project which added the described",
- "feature to the library or C API. When this applies to an entire module, it",
- "should be placed at the top of the module section before any prose.",
- "",
- "The first argument must be given and is the version in question; you can add",
- "a second argument consisting of a brief explanation of the change.",
- "",
- "Example:",
- "",
- "```",
- ".. versionadded:: 2.5",
- " The *spam* parameter.",
- "```",
- "",
- "Note that there must be no blank line between the directive head and the",
- "explanation; this is to make these blocks visually continuous in the markup."
- ],
- "options": {}
- },
- "versionchanged(sphinx.domains.changeset.VersionChange)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-versionchanged",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "versionchanged",
- "is_markdown": true,
- "description": [
- "Similar to [versionadded](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-versionadded), but describes when and what changed in",
- "the named feature in some way (new parameters, changed side effects, etc.)."
- ],
- "options": {}
- },
- "warning(docutils.parsers.rst.directives.admonitions.Warning)": {
- "source": "https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-warning",
- "license": "https://github.com/sphinx-doc/sphinx/blob/4.x/LICENSE",
- "name": "warning",
- "is_markdown": true,
- "description": [
- "An important bit of information about an API that a user should be very aware",
- "of when using whatever bit of API the warning pertains to. The content of",
- "the directive should be written in complete sentences and include all",
- "appropriate punctuation. This differs from [note](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-note) in that it is",
- "recommended over [note](https://www.sphinx-doc.org/en/master/usage/restructuredtext/directives.html#directive-note) for information regarding security."
- ],
- "options": {}
- }
-}
diff --git a/lib/esbonio/esbonio/lsp/sphinx/directives.py b/lib/esbonio/esbonio/lsp/sphinx/directives.py
deleted file mode 100644
index 01c58d9ee..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/directives.py
+++ /dev/null
@@ -1,10 +0,0 @@
-import json
-
-from esbonio.lsp.directives import Directives
-from esbonio.lsp.sphinx import SphinxLanguageServer
-from esbonio.lsp.util import resources
-
-
-def esbonio_setup(rst: SphinxLanguageServer, directives: Directives):
- sphinx_docs = resources.read_string("esbonio.lsp.sphinx", "directives.json")
- directives.add_documentation(json.loads(sphinx_docs))
diff --git a/lib/esbonio/esbonio/lsp/sphinx/domains.py b/lib/esbonio/esbonio/lsp/sphinx/domains.py
deleted file mode 100644
index 582ed2823..000000000
--- a/lib/esbonio/esbonio/lsp/sphinx/domains.py
+++ /dev/null
@@ -1,631 +0,0 @@
-"""Support for Sphinx domains."""
-import pathlib
-from typing import Any
-from typing import Dict
-from typing import Iterable
-from typing import List
-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
-from docutils.parsers.rst import Directive
-from lsprotocol.types import CompletionItem
-from lsprotocol.types import CompletionItemKind
-from lsprotocol.types import Location
-from lsprotocol.types import Position
-from lsprotocol.types import Range
-from pygls.workspace import Document
-from sphinx.domains import Domain
-
-from esbonio.lsp import CompletionContext
-from esbonio.lsp import DefinitionContext
-from esbonio.lsp import DocumentLinkContext
-from esbonio.lsp.directives import DirectiveLanguageFeature
-from esbonio.lsp.directives import Directives
-from esbonio.lsp.roles import RoleLanguageFeature
-from esbonio.lsp.roles import Roles
-from esbonio.lsp.sphinx import SphinxLanguageServer
-
-TARGET_KINDS = {
- "attribute": CompletionItemKind.Field,
- "doc": CompletionItemKind.File,
- "class": CompletionItemKind.Class,
- "envvar": CompletionItemKind.Variable,
- "function": CompletionItemKind.Function,
- "method": CompletionItemKind.Method,
- "module": CompletionItemKind.Module,
- "term": CompletionItemKind.Text,
-}
-
-
-class DomainHelpers:
- """Common methods that work on domains."""
-
- rst: SphinxLanguageServer
-
- @property
- def domains(self) -> Dict[str, Domain]:
- """Return a dictionary of known domains."""
-
- if self.rst.app is None or self.rst.app.env is None:
- return dict()
-
- return self.rst.app.env.domains # type: ignore
-
- def get_default_domain(self, uri: str) -> Optional[str]:
- """Return the default domain for the given uri."""
-
- # TODO: Add support for .. default-domain::
- if self.rst.app is not None:
- return self.rst.app.config.primary_domain
-
- return None
-
-
-class DomainDirectives(DirectiveLanguageFeature, DomainHelpers):
- """Support for directives coming from Sphinx's domains."""
-
- def __init__(self, rst: SphinxLanguageServer):
- self.rst = rst
-
- self._directives: Optional[Dict[str, Type[Directive]]] = None
- """Cache for known directives."""
-
- @property
- def directives(self) -> Dict[str, Type[Directive]]:
- if self._directives is not None:
- return self._directives
-
- directives = {}
- for prefix, domain in self.domains.items():
- for name, directive in domain.directives.items():
- directives[f"{prefix}:{name}"] = directive
-
- self._directives = directives
- return self._directives
-
- def get_implementation(
- self, directive: str, domain: Optional[str]
- ) -> Optional[Type[Directive]]:
- if domain is not None:
- return self.directives.get(f"{domain}:{directive}", None)
-
- if self.rst.app is None:
- return None
-
- # Try the default domain
- primary_domain = self.rst.app.config.primary_domain
- impl = self.directives.get(f"{primary_domain}:{directive}", None)
- if impl is not None:
- return impl
-
- # Try the std domain
- return self.directives.get(f"std:{directive}", None)
-
- def index_directives(self) -> Dict[str, Type[Directive]]:
- return self.directives
-
- def suggest_directives(
- self, context: CompletionContext
- ) -> 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.
- items = self.directives.copy()
- primary_domain = self.get_default_domain(context.doc.uri)
-
- for key, directive in self.directives.items():
- if key.startswith("std:"):
- items[key.replace("std:", "")] = directive
- continue
-
- if primary_domain and key.startswith(f"{primary_domain}:"):
- items[key.replace(f"{primary_domain}:", "")] = directive
-
- return items.items()
-
- def suggest_options(
- self, context: CompletionContext, directive: str, domain: Optional[str]
- ) -> Iterable[str]:
- impl = self.get_implementation(directive, domain)
- if impl is None:
- return []
-
- option_spec = getattr(impl, "option_spec", {})
- return option_spec.keys()
-
-
-class DomainRoles(RoleLanguageFeature, DomainHelpers):
- """Support for roles coming from Sphinx's domains."""
-
- def __init__(self, rst: SphinxLanguageServer):
- self.rst = rst
-
- self._roles: Optional[Dict[str, Any]] = None
- """Cache for known roles."""
-
- self._role_target_types: Optional[Dict[str, List[str]]] = None
- """Cache for role target types."""
-
- @property
- def roles(self) -> Dict[str, Any]:
- if self._roles is not None:
- return self._roles
-
- roles = {}
- for prefix, domain in self.domains.items():
- for name, role in domain.roles.items():
- roles[f"{prefix}:{name}"] = role
-
- self._roles = roles
- return self._roles
-
- @property
- def role_target_types(self) -> Dict[str, List[str]]:
- if self._role_target_types is not None:
- return self._role_target_types
-
- self._role_target_types = {}
-
- for prefix, domain in self.domains.items():
- fmt = "{prefix}:{name}" if prefix else "{name}"
-
- for name, item_type in domain.object_types.items():
- for role in item_type.roles:
- role_key = fmt.format(name=role, prefix=prefix)
- target_types = self._role_target_types.get(role_key, list())
- target_types.append(name)
-
- self._role_target_types[role_key] = target_types
-
- return self._role_target_types
-
- def _get_role_target_types(self, name: str, domain: str = "") -> List[str]:
- """Return a list indicating which object types a role is capable of linking
- with.
- """
-
- if domain:
- return self.role_target_types.get(f"{domain}:{name}", [])
-
- # Try the primary domain
- if self.rst.app and self.rst.app.config.primary_domain:
- key = f"{self.rst.app.config.primary_domain}:{name}"
-
- if key in self.role_target_types:
- return self.role_target_types[key]
-
- # Finally try the standard domain
- return self.role_target_types.get(f"std:{name}", [])
-
- def _get_role_targets(self, name: str, domain: str = "") -> List[tuple]:
- """Return a list of objects targeted by the given role.
-
- Parameters
- ----------
- name:
- The name of the role
- domain:
- The domain the role is a part of, if applicable.
- """
-
- targets: List[tuple] = []
- domain_obj: Optional[Domain] = None
-
- if domain:
- domain_obj = self.domains.get(domain, None)
- else:
- std = self.domains.get("std", None)
- if std and name in std.roles:
- domain_obj = std
-
- elif self.rst.app and self.rst.app.config.primary_domain:
- domain_obj = self.domains.get(self.rst.app.config.primary_domain, None)
-
- target_types = set(self._get_role_target_types(name, domain))
-
- if not domain_obj:
- self.rst.logger.debug(
- "Unable to find domain for role '%s:%s'", domain, name
- )
- return []
-
- for obj in domain_obj.get_objects():
- if obj[2] in target_types:
- targets.append(obj)
-
- return targets
-
- def get_implementation(
- self, role: str, domain: Optional[str]
- ) -> Optional[Directive]:
- if domain is not None:
- return self.roles.get(f"{domain}:{role}", None)
-
- if self.rst.app is None:
- return None
-
- # Try the default domain
- primary_domain = self.rst.app.config.primary_domain
- impl = self.roles.get(f"{primary_domain}:{role}", None)
- if impl is not None:
- return impl
-
- # Try the std domain
- return self.roles.get(f"std:{role}", None)
-
- def index_roles(self) -> Dict[str, Any]:
- return self.roles
-
- def suggest_roles(self, context: CompletionContext) -> Iterable[Tuple[str, Any]]:
- # In addition to providing each role fully qulaified, we should provide a
- # suggestion for directives in the std and primary domains without the prefix.
- items = self.roles.copy()
- primary_domain = self.get_default_domain(context.doc.uri)
-
- for key, role in self.roles.items():
- if key.startswith("std:"):
- items[key.replace("std:", "")] = role
- continue
-
- if primary_domain and key.startswith(f"{primary_domain}:"):
- items[key.replace(f"{primary_domain}:", "")] = role
-
- return items.items()
-
- def complete_targets(
- self, context: CompletionContext, name: str, domain: str
- ) -> List[CompletionItem]:
- label = context.match.group("label")
-
- # Intersphinx targets contain ':' characters.
- if ":" in label:
- return []
-
- return [
- object_to_completion_item(obj)
- for obj in self._get_role_targets(name, domain)
- ]
-
- def resolve_target_link(
- self, context: DocumentLinkContext, name: str, domain: Optional[str], label: str
- ) -> Tuple[Optional[str], Optional[str]]:
- """``textDocument/documentLink`` support"""
-
- # Ignore intersphinx references.
- if ":" in label:
- return None, None
-
- # Other roles like :ref: do not make sense as the ``textDocument/documentLink``
- # api doesn't support specific locations like goto definition does.
- if (domain is not None and domain != "std") or name != "doc":
- return None, None
-
- return self.resolve_doc(context.doc, label), None
-
- def find_target_definitions(
- self, context: DefinitionContext, name: str, domain: str, label: str
- ) -> List[Location]:
- if not domain and name == "ref":
- return self.ref_definition(label)
-
- if not domain and name == "doc":
- return self.doc_definition(context.doc, label)
-
- return []
-
- def resolve_doc(self, doc: Document, label: str) -> Optional[str]:
- if self.rst.app is None:
- return None
-
- srcdir = self.rst.app.srcdir
- currentdir = pathlib.Path(Uri.to_fs_path(doc.uri)).parent
-
- if label.startswith("/"):
- path = pathlib.Path(srcdir, label[1:] + ".rst")
- else:
- path = pathlib.Path(currentdir, label + ".rst")
-
- if not path.exists():
- return None
-
- return Uri.from_fs_path(str(path))
-
- def doc_definition(self, doc: Document, label: str) -> List[Location]:
- """Goto definition implementation for ``:doc:`` targets"""
-
- uri = self.resolve_doc(doc, label)
- if not uri:
- return []
-
- return [
- Location(
- uri=uri,
- range=Range(
- start=Position(line=0, character=0),
- end=Position(line=1, character=0),
- ),
- )
- ]
-
- def ref_definition(self, label: str) -> List[Location]:
- """Goto definition implementation for ``:ref:`` targets"""
-
- if not self.rst.app or not self.rst.app.env:
- return []
-
- types = set(self._get_role_target_types("ref"))
- std = self.domains["std"]
- if std is None:
- return []
-
- docname = self.find_docname_for_label(label, std, types)
- if docname is None:
- return []
-
- path = self.rst.app.env.doc2path(docname)
- uri = Uri.from_fs_path(path)
-
- doctree = self.rst.get_initial_doctree(uri)
- if doctree is None:
- return []
-
- uri = None
- line = None
-
- for node in doctree.traverse(condition=nodes.target):
- if "refid" not in node:
- continue
-
- if doctree.nameids.get(label, "") == node["refid"]:
- uri = Uri.from_fs_path(node.source)
- line = node.line
- break
-
- if uri is None or line is None:
- return []
-
- return [
- Location(
- uri=uri,
- range=Range(
- start=Position(line=line - 1, character=0),
- end=Position(line=line, character=0),
- ),
- )
- ]
-
- def find_docname_for_label(
- self, label: str, domain: Domain, types: Optional[Set[str]] = None
- ) -> Optional[str]:
- """Given the label name and domain it belongs to, return the docname its
- definition resides in.
-
- Parameters
- ----------
- label
- The label to search for
-
- domain
- The domain to search within
-
- types
- A collection of object types that the label chould have.
- """
-
- docname = None
- types = types or set()
-
- # _, title, _, _, anchor, priority
- for name, _, type_, doc, _, _ in domain.get_objects():
- if types and type_ not in types:
- continue
-
- if name == label:
- docname = doc
- break
-
- return docname
-
-
-class Intersphinx(RoleLanguageFeature):
- def __init__(self, rst: SphinxLanguageServer, domain: DomainRoles):
- self.rst = rst
- self.domain = domain
-
- def complete_targets(
- self, context: CompletionContext, name: str, domain: str
- ) -> List[CompletionItem]:
- label = context.match.group("label")
-
- # Intersphinx targets contain ':' characters.
- if ":" in label:
- return self.complete_intersphinx_targets(name, domain, label)
-
- return self.complete_intersphinx_projects(name, domain)
-
- def complete_intersphinx_projects(
- self, name: str, domain: str
- ) -> List[CompletionItem]:
- items = []
- for project in self.get_intersphinx_projects():
- if not self.has_intersphinx_targets(project, name, domain):
- continue
-
- items.append(
- CompletionItem(
- label=project, detail="intersphinx", kind=CompletionItemKind.Module
- )
- )
-
- return items
-
- def complete_intersphinx_targets(
- self, name: str, domain: str, label: str
- ) -> List[CompletionItem]:
- items = []
- project, *_ = label.split(":")
- intersphinx_targets = self.get_intersphinx_targets(project, name, domain)
-
- for type_, targets in intersphinx_targets.items():
- items += [
- intersphinx_target_to_completion_item(project, label, target, type_)
- for label, target in targets.items()
- ]
-
- return items
-
- def resolve_target_link(
- self, context: DocumentLinkContext, name: str, domain: Optional[str], label: str
- ) -> Tuple[Optional[str], Optional[str]]:
- if not self.rst.app:
- return None, None
-
- project, *parts = label.split(":")
- label = ":".join(parts)
- targets = self.get_intersphinx_targets(project, name, domain or "")
-
- for _, items in targets.items():
- if label in items:
- source, version, url, display = items[label]
- name = label if display == "-" else display
- tooltip = f"{name} - {source} v{version}"
-
- return url, tooltip
-
- return None, None
-
- def get_intersphinx_projects(self) -> List[str]:
- """Return the list of configured intersphinx project names."""
-
- if self.rst.app is None:
- return []
-
- inv = getattr(self.rst.app.env, "intersphinx_named_inventory", {})
- return list(inv.keys())
-
- def has_intersphinx_targets(
- self, project: str, name: str, domain: str = ""
- ) -> bool:
- """Return ``True`` if the given intersphinx project has targets targeted by the
- given role.
-
- Parameters
- ----------
- project
- The project to check
-
- name
- The name of the role
-
- domain
- The domain the role is a part of, if applicable.
- """
- targets = self.get_intersphinx_targets(project, name, domain)
-
- if len(targets) == 0:
- return False
-
- return any([len(items) > 0 for items in targets.values()])
-
- def get_intersphinx_targets(
- self, project: str, name: str, domain: str = ""
- ) -> Dict[str, Dict[str, tuple]]:
- """Return the intersphinx objects targeted by the given role.
-
- Parameters
- ----------
- project
- The project to return targets from
-
- name
- The name of the role
-
- domain
- The domain the role is a part of, if applicable.
- """
-
- if self.rst.app is None:
- return {}
-
- inv = getattr(self.rst.app.env, "intersphinx_named_inventory", {})
- if project not in inv:
- return {}
-
- targets = {}
- inv = inv[project]
-
- for target_type in self.domain._get_role_target_types(name, domain):
- explicit_domain = f"{domain}:{target_type}"
- if explicit_domain in inv:
- targets[target_type] = inv[explicit_domain]
- continue
-
- primary_domain = f'{self.rst.app.config.primary_domain or ""}:{target_type}'
- if primary_domain in inv:
- targets[target_type] = inv[primary_domain]
- continue
-
- std_domain = f"std:{target_type}"
- if std_domain in inv:
- targets[target_type] = inv[std_domain]
-
- return targets
-
-
-def intersphinx_target_to_completion_item(
- project: str, label: str, target: tuple, type_: str
-) -> CompletionItem:
- # _. _. url, _
- source, version, _, display = target
-
- display_name = label if display == "-" else display
- completion_kind = ":".join(type_.split(":")[1:]) if ":" in type_ else type_
-
- if version:
- version = f" v{version}"
-
- return CompletionItem(
- label=label,
- detail=f"{display_name} - {source}{version}",
- kind=TARGET_KINDS.get(completion_kind, CompletionItemKind.Reference),
- insert_text=f"{project}:{label}",
- )
-
-
-def object_to_completion_item(object_: tuple) -> CompletionItem:
- # _, _, _, docname, anchor, priority
- name, display_name, type_, _, _, _ = object_
- insert_text = name
-
- key = type_.split(":")[1] if ":" in type_ else type_
- kind = TARGET_KINDS.get(key, CompletionItemKind.Reference)
-
- # ensure :doc: targets are inserted as an absolute path - that way the reference
- # will always work regardless of the file's location.
- if type_ == "doc":
- insert_text = f"/{name}"
-
- # :option: targets need to be inserted as `