diff --git a/docs/_images/lsp_auto_ids.gif b/docs/_images/lsp_auto_ids.gif deleted file mode 100644 index f6c73f4ba..000000000 Binary files a/docs/_images/lsp_auto_ids.gif and /dev/null differ diff --git a/docs/_images/lsp_directive_snippets_inside_eval_rst_block_markdown.gif b/docs/_images/lsp_directive_snippets_inside_eval_rst_block_markdown.gif deleted file mode 100644 index a95ea7c3a..000000000 Binary files a/docs/_images/lsp_directive_snippets_inside_eval_rst_block_markdown.gif and /dev/null differ diff --git a/docs/_images/lsp_directive_snippets_markdown.gif b/docs/_images/lsp_directive_snippets_markdown.gif deleted file mode 100644 index 8eaf7da09..000000000 Binary files a/docs/_images/lsp_directive_snippets_markdown.gif and /dev/null differ diff --git a/docs/_images/lsp_goto.gif b/docs/_images/lsp_goto.gif deleted file mode 100644 index abf216487..000000000 Binary files a/docs/_images/lsp_goto.gif and /dev/null differ diff --git a/docs/_images/lsp_id_selection.gif b/docs/_images/lsp_id_selection.gif deleted file mode 100644 index 7539f1410..000000000 Binary files a/docs/_images/lsp_id_selection.gif and /dev/null differ diff --git a/docs/_images/lsp_need_role_need_suggestion_markdown.gif b/docs/_images/lsp_need_role_need_suggestion_markdown.gif deleted file mode 100644 index e70f9d18b..000000000 Binary files a/docs/_images/lsp_need_role_need_suggestion_markdown.gif and /dev/null differ diff --git a/docs/_images/lsp_preview.gif b/docs/_images/lsp_preview.gif deleted file mode 100644 index 3f7760252..000000000 Binary files a/docs/_images/lsp_preview.gif and /dev/null differ diff --git a/docs/_images/lsp_snippets.gif b/docs/_images/lsp_snippets.gif deleted file mode 100644 index 579be4c45..000000000 Binary files a/docs/_images/lsp_snippets.gif and /dev/null differ diff --git a/docs/changelog.rst b/docs/changelog.rst index ad61c2f62..1636e1267 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -26,6 +26,11 @@ Released: under development (`#912 `_) * Bugfix: Supports "None" body in Github services. (`#903 `_) +* Removed esbonio for :ref:`ide`. +* Removed configuration option **needs_ide_snippets_id** to support custom need ID for :ref:`ide` snippets. +* Removed configuration **needs_ide_directive_snippets** to support custom directive snippets for IDE features. +* Provided new IDE support option: VsCode extension + `Sphinx-Needs-VsCode `_. 1.2.2 ----- @@ -163,14 +168,14 @@ Released: 22.09.2022 * Improvement: Added `filter` function for :ref:`needuml`. * Improvement: Renamed jinja function `need` to `flow` for :ref:`needuml`. * Improvement: Added directive :ref:`needarch`. -* Improvement: Added configuration option :ref:`needs_ide_snippets_id` to support custom need ID for :ref:`ide` snippets. +* Improvement: Added configuration option **needs_ide_snippets_id** to support custom need ID for :ref:`ide` snippets. * Improvement: Provides jinja function :ref:`needarch_jinja_import` for :ref:`needarch` to execute :ref:`needuml_jinja_uml` automatically for all the links defined in the need :ref:`need_links` options. -* Improvement: Added configuration :ref:`needs_ide_directive_snippets` to support custom directive snippets for IDE features. +* Improvement: Added configuration **needs_ide_directive_snippets** to support custom directive snippets for IDE features. (`#640 `_) * Bugfix: Updated pip install URLs in Dockerfile. (`#673 `_) -* Improvement: Providing IDE features support for :ref:`ide_myst`. +* Improvement: Providing IDE features support for **ide_myst**. 1.0.1 ----- diff --git a/docs/configuration.rst b/docs/configuration.rst index c8a060b05..2ecf8e377 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -1197,91 +1197,6 @@ The ID length must be at least 3 characters. If you change the regular expression, you should also set :ref:`needs_id_required` so that authors are forced to set an valid ID. -.. _needs_ide_snippets_id: - -needs_ide_snippets_id -~~~~~~~~~~~~~~~~~~~~~ - -A jinja-string defines a custom need ID for :ref:`ide` snippets. - -Default value: ``""`` - -``needs_ide_snippets_id`` provides two jinja functions to generate need ID: - - * ``from_title()``: replaces all whitespaces with `_` and converts all to lowevercase from need title - * ``random()``: generates a random string - -It also supports Pre/Postfix. - -If ``needs_ide_snippets_id`` is not configured or empty, then a random string will be generated for :ref:`ide` snippets id. - -**Example**: -{% raw %} - -.. code-block:: python - - needs_ide_snippets_id = "{{random()}}" - -or - -.. code-block:: python - - needs_ide_snippets_id = "Test_{{random()}}_Test" - -or - -.. code-block:: python - - needs_ide_snippets_id = "{{from_title()}}" - -or - -.. code-block:: python - - needs_ide_snippets_id = "TEST_{{from_title()}}_TEST" - -{% endraw %} - -.. _needs_ide_directive_snippets: - -needs_ide_directive_snippets -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Allows to define customized directive snippets for :ref:`ide`. - -Default value: ``{}`` - -In your **conf.py** file, use it like this: - -.. code-block:: python - - needs_ide_directive_snippets = { - "req": """\ - .. req:: REQ Example - :id: ID - :status: - :custom_option_1: - - random content. - """, - "test": """\ - .. test:: Test Title - :id: TEST_ - :status: open - :custom_option: something - - test directive content. - """, - } - -If ``needs_ide_directive_snippets`` is not configured or empty, the default directive snippets -will be used. - -.. hint:: - - The snippets are not automatically synced with the need definitions in **conf.py** and it is - up to the user to keep them in sync. - .. _needs_functions: needs_functions diff --git a/docs/contributing.rst b/docs/contributing.rst index 0c32d2fee..4e6777650 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -181,102 +181,6 @@ The tag must follow the format: ``[0-9].[0-9]+.[0-9]``. Otherwise the release jo The release jobs will build the source and wheel distribution and try to upload them to ``test.pypi.org`` and ``pypy.org``. -Debugging Sphinx-Needs Language Server features ------------------------------------------------ -Sphinx-Needs provides some language server functions for the `Esbonio Language Server `_. - -The complete functionality can used in VsCode by using the extension -`vscode-restructuredtext `_. -The whole configuration is done automatically and Sphinx-Needs features gets loaded, if the Sphinx-Needs extension -is part of ´extensions` variable inside `conf.py`. - -Debugging -~~~~~~~~~ -Most information is coming from https://docs.restructuredtext.net/articles/development.html. - -1. Check out the source code of all the following projects: - - * *vscode-restructuredtext*: links... - * *esbonio* - -2. Follow https://docs.restructuredtext.net/articles/development.html to install all dependencies, compile it and get - the Development host running in VsCode. - -3. Create a test folder inside the project with a Sphinx projects using Sphinx-Needs, for example under **/docs** by using - ``sphinx-quickstart``. - -4. Add the following to **docs/.vscode/settings.json**: - - .. code-block:: - - { - "esbonio.server.sourceFolder": "/Path/to/checked_out/esbonio/lib/esbonio", # absolute path - "esbonio.server.debugLaunch": true, - "esbonio.server.logLevel": "debug", - } - -5. Add the args ``${workspaceFolder}/docs`` to configuration *Launch Extension* in **.vscode/launch.json** like this: - - .. code-block:: - - { - "name": "Launch Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceRoot}", - "${workspaceFolder}/docs", - ], - "sourceMaps": true, - "outFiles": ["${workspaceRoot}/out/extension.js"], - "preLaunchTask": "watch" - }, - -6. Test it by pressing F5 (running the preconfigured tasks *Launch Extension*) - - * In the opened *extensionDevelopmentHost* instance, select the correct Python interpreter. e.g. vscode-restructuredtext/.venv/bin/python - -7. Open another instance of VsCode for the checked out esbonio folder. -8. Add this to **.vscode/launch.json** under ``configurations``: - - .. code-block:: - - { - "name": "Python: Remote Attach", - "type": "python", - "request": "attach", - "connect": { - "host": "localhost", - "port": 5678 - }, - "pathMappings": [ - { - "localRoot": "${workspaceFolder}/lib/esbonio", - "remoteRoot": "." - } - ] - }, - -9. Test it by running the new task *Python: Remote Attach*. For this the task *Launch Extension* from - VsCode-restructuredText Extension must be already running, as this one starts a python debug server. - -10. Now you set set breakpoints anywhere in the esbonio code. - - -Debugging Sphinx-Needs functions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To debugging Sphinx-Needs Language Server functions, you can repeat the steps 7-10 from above with the Sphinx-Needs -repository. - -Note: - -* For step 8: adapt the localRoot path accordingly, e.g. "${workspaceFolder}/../esbonio/lib/esbonio" - -* If it doesn't stop at breakpoints, set a breakpoint at **sphinx_needs/__init__.py**, where you import `esbonio_setup`. - When debugger stops there, choose **step into** to continue debug. - .. Include our contributors and maintainers. .. include:: ../AUTHORS diff --git a/docs/ide/index.rst b/docs/ide/index.rst index c8b33280d..fc2de276a 100644 --- a/docs/ide/index.rst +++ b/docs/ide/index.rst @@ -3,170 +3,13 @@ IDE Support =========== -.. _lsp_features: +The `Sphinx-Needs `_ ecosystem provides IDE support to enhance user's experience +of editing, navigating. -Features --------- +.. _ide_vscode: -The following features are supported when using an `Esbonio `_ based IDE -extension, like VsCode extension `reStructuredText `_, -in your **Sphinx-Needs** project. +Visula Studio Code +------------------ -.. grid:: - - .. grid-item-card:: Auto-generated IDs - :img-bottom: /_images/lsp_auto_ids.gif - - .. grid-item-card:: Snippets - :img-bottom: /_images/lsp_snippets.gif - -.. grid:: - - .. grid-item:: - - .. card:: ID Selection - :width: 75% - :img-bottom: /_images/lsp_id_selection.gif - - .. card:: Goto Definition - :width: 75% - :img-bottom: /_images/lsp_goto.gif - - .. card:: Need Preview - :width: 100% - :img-bottom: /_images/lsp_preview.gif - -.. _ide_installation: - -Installation ------------- - -VsCode -~~~~~~ - -The VsCode extension `reStructuredText `_ supports all the Sphinx-Needs -language features and is available at `Visual Studio Marketplace `_. - -To install and configure this extension, see details in -`How to install reStructuredText from Marketplace `_ and - -`How to use it `_. - -.. _ide_usage: - -Usage ------ - -To use all the Sphinx-Needs language featues, - -#. Install IDE extension or plugin, see current supported IDE extension in :ref:`ide_installation`. - -#. Build `needs.json` file in your Sphinx-Needs project: - - * automatically build `needs.json` if configure `needs_build_json = True` in conf.py. See details in :ref:`needs_build_json`. - * manually build `needs.json` using `sphinx-build -b needs source_dir build_dir`. See details in :ref:`builders`. - -Auto-generated need IDs -~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: /_images/lsp_auto_ids.gif - :align: center - -Type ``:`` in the line directly below a need directive like ``.. req::`` and select ``:id:`` in the IntelliSense interface. - -.. hint:: - - * If needls can't detect the type of the need it will just output `ID`. - * The ID is calculated using a hash function of the current user, doc URI, line number and the need prefix (e.g.). - To lower the risk of ID conflicts further a pseudo-randomization is part of the ID generation.s - -Predefined Snippets -~~~~~~~~~~~~~~~~~~~ - -.. image:: /_images/lsp_snippets.gif - :align: center - -Type ``..`` and choose to auto-complete the directive in the IntelliSense interface. - -ID Selection -~~~~~~~~~~~~ - -.. image:: /_images/lsp_id_selection.gif - :align: center - -#. After `:need:` role or `:links:` option type `->` which triggers the auto-completion of needs -#. Select a need type from the IntelliSense dialog (use arrow keys) - - * Type `>` again to trigger the doc completion (file in which needs are specified) - * Type `/` to complete the doc path, continue until the doc path is completed to a `*.rst` file - * Type `>` to trigger completion of a specfic need by ID, expand the completion item info to see the content of the selected need - -Goto Definition for need IDs -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: /_images/lsp_goto.gif - :align: center - -Move cursor to a need ID and hit `F12` - -Alternatively right click on a need ID and choose "Go to Definition" from the context menu - -Need information on mouse hover -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. image:: /_images/lsp_preview.gif - :align: center - -Move the mouse cursor over any need ID - -.. _ide_myst: - -MyST/Markdown -------------- - -Directives and roles can be used in `MyST `_ in -this `Syntax `_. - -All the above IDE :ref:`lsp_features` can also be supported for MyST/Markdown. - -Usage -~~~~~ - -* Install MyST Parser using pip. - - .. code-block:: python - - pip install myst-parser - -* Enable and active the MyST Parser extension in your Sphinx-Needs project by simply adding the following in your `conf.py` file: - - .. code-block:: python - - extensions = ["sphinx_needs", "myst_parser"] - - source_suffix = [".rst", ".md"] - -* All the above IDE :ref:`lsp_features` are supported and used the same way like editing in rst files from above :ref:`ide_usage`, - when you editing your markdown files. e.g. `myfile.md`: - - * Directive snippets and role completion will be automatically translated into MyST/Markdown supported syntax style, see the following :ref:`ide_myst_example` - -.. _ide_myst_example: - -Example -~~~~~~~ - -Directive snippets - -.. image:: /_images/lsp_directive_snippets_markdown.gif - :align: center - -Directive snippets used inside `{eval-rst}` block - -.. image:: /_images/lsp_directive_snippets_inside_eval_rst_block_markdown.gif - :align: center - -Role need completion - -.. image:: /_images/lsp_need_role_need_suggestion_markdown.gif - :align: center +VsCode extension `Sphinx-Needs-VsCode `_ provides +support for Sphinx-Needs. See more details in the `Documentation `_. diff --git a/docs/requirements.txt b/docs/requirements.txt index a13591993..d08b317e5 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -7,5 +7,4 @@ sphinxcontrib-programoutput sphinx-design click tabulate -sphinx-immaterial==0.11.2 -esbonio>=0.13.0 \ No newline at end of file +sphinx-immaterial==0.11.2 \ No newline at end of file diff --git a/noxfile.py b/noxfile.py index f69c57bd7..01c35262a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,8 +14,6 @@ TEST_DEPENDENCIES = [ "pytest", "pytest-xdist", - "pytest_lsp", - "myst-parser", "responses", "lxml", "pyparsing!=3.0.4", diff --git a/poetry.lock b/poetry.lock index 83f6d6be0..e2a68f25a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -12,18 +12,6 @@ files = [ {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, ] -[[package]] -name = "appdirs" -version = "1.4.4" -description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, - {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, -] - [[package]] name = "attrs" version = "22.2.0" @@ -296,29 +284,6 @@ files = [ [package.dependencies] docutils = ">=0.14" -[[package]] -name = "esbonio" -version = "0.14.1" -description = "A Language Server for Sphinx projects." -category = "main" -optional = false -python-versions = "*" -files = [ - {file = "esbonio-0.14.1-py3-none-any.whl", hash = "sha256:b83f415070068b396fceb16cff7abf1979e81dea4aadd57daedd6223e45bf795"}, - {file = "esbonio-0.14.1.tar.gz", hash = "sha256:edbeeb22022472d936769f9fc58b96372f71ae2b490f6d4d12b2f7587cb75051"}, -] - -[package.dependencies] -appdirs = "*" -pygls = ">=0.11.0" -pyspellchecker = "*" -sphinx = "*" -typing-extensions = "*" - -[package.extras] -debug = ["lsp-devtools"] -dev = ["black", "flake8", "lsp-devtools", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-lsp", "pytest-timeout", "tox", "types-appdirs", "types-docutils", "types-pygments"] - [[package]] name = "exceptiongroup" version = "1.1.0" @@ -393,14 +358,14 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "identify" -version = "2.5.17" +version = "2.5.18" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.17-py2.py3-none-any.whl", hash = "sha256:7d526dd1283555aafcc91539acc061d8f6f59adb0a7bba462735b0a318bff7ed"}, - {file = "identify-2.5.17.tar.gz", hash = "sha256:93cc61a861052de9d4c541a7acb7e3dcc9c11b398a2144f6e52ae5285f5f4f06"}, + {file = "identify-2.5.18-py2.py3-none-any.whl", hash = "sha256:93aac7ecf2f6abf879b8f29a8002d3c6de7086b8c28d88e1ad15045a15ab63f9"}, + {file = "identify-2.5.18.tar.gz", hash = "sha256:89e144fa560cc4cffb6ef2ab5e9fb18ed9f9b3cb054384bab4b95c12f6c309fe"}, ] [package.extras] @@ -857,26 +822,6 @@ pillow = ">=6.2.0" pyparsing = ">=2.2.1" python-dateutil = ">=2.7" -[[package]] -name = "mdit-py-plugins" -version = "0.3.3" -description = "Collection of plugins for markdown-it-py" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "mdit-py-plugins-0.3.3.tar.gz", hash = "sha256:5cfd7e7ac582a594e23ba6546a2f406e94e42eb33ae596d0734781261c251260"}, - {file = "mdit_py_plugins-0.3.3-py3-none-any.whl", hash = "sha256:36d08a29def19ec43acdcd8ba471d3ebab132e7879d442760d963f19913e04b9"}, -] - -[package.dependencies] -markdown-it-py = ">=1.0.0,<3.0.0" - -[package.extras] -code-style = ["pre-commit"] -rtd = ["attrs", "myst-parser (>=0.16.1,<0.17.0)", "sphinx-book-theme (>=0.1.0,<0.2.0)"] -testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] - [[package]] name = "mdurl" version = "0.1.2" @@ -994,33 +939,6 @@ files = [ {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, ] -[[package]] -name = "myst-parser" -version = "0.18.1" -description = "An extended commonmark compliant parser, with bridges to docutils & sphinx." -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "myst-parser-0.18.1.tar.gz", hash = "sha256:79317f4bb2c13053dd6e64f9da1ba1da6cd9c40c8a430c447a7b146a594c246d"}, - {file = "myst_parser-0.18.1-py3-none-any.whl", hash = "sha256:61b275b85d9f58aa327f370913ae1bec26ebad372cc99f3ab85c8ec3ee8d9fb8"}, -] - -[package.dependencies] -docutils = ">=0.15,<0.20" -jinja2 = "*" -markdown-it-py = ">=1.0.0,<3.0.0" -mdit-py-plugins = ">=0.3.1,<0.4.0" -pyyaml = "*" -sphinx = ">=4,<6" -typing-extensions = "*" - -[package.extras] -code-style = ["pre-commit (>=2.12,<3.0)"] -linkify = ["linkify-it-py (>=1.0,<2.0)"] -rtd = ["ipython", "sphinx-book-theme", "sphinx-design", "sphinxcontrib.mermaid (>=0.7.1,<0.8.0)", "sphinxext-opengraph (>=0.6.3,<0.7.0)", "sphinxext-rediraffe (>=0.2.7,<0.3.0)"] -testing = ["beautifulsoup4", "coverage[toml]", "pytest (>=6,<7)", "pytest-cov", "pytest-param-files (>=0.3.4,<0.4.0)", "pytest-regressions", "sphinx (<5.2)", "sphinx-pytest"] - [[package]] name = "nodeenv" version = "1.7.0" @@ -1273,78 +1191,57 @@ files = [ [[package]] name = "pydantic" -version = "1.9.2" +version = "1.10.5" description = "Data validation and settings management using python type hints" -category = "main" -optional = false -python-versions = ">=3.6.1" +category = "dev" +optional = true +python-versions = ">=3.7" files = [ - {file = "pydantic-1.9.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c9e04a6cdb7a363d7cb3ccf0efea51e0abb48e180c0d31dca8d247967d85c6e"}, - {file = "pydantic-1.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fafe841be1103f340a24977f61dee76172e4ae5f647ab9e7fd1e1fca51524f08"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afacf6d2a41ed91fc631bade88b1d319c51ab5418870802cedb590b709c5ae3c"}, - {file = "pydantic-1.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ee0d69b2a5b341fc7927e92cae7ddcfd95e624dfc4870b32a85568bd65e6131"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ff68fc85355532ea77559ede81f35fff79a6a5543477e168ab3a381887caea76"}, - {file = "pydantic-1.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c0f5e142ef8217019e3eef6ae1b6b55f09a7a15972958d44fbd228214cede567"}, - {file = "pydantic-1.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:615661bfc37e82ac677543704437ff737418e4ea04bef9cf11c6d27346606044"}, - {file = "pydantic-1.9.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:328558c9f2eed77bd8fffad3cef39dbbe3edc7044517f4625a769d45d4cf7555"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bd446bdb7755c3a94e56d7bdfd3ee92396070efa8ef3a34fab9579fe6aa1d84"}, - {file = "pydantic-1.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e0b214e57623a535936005797567231a12d0da0c29711eb3514bc2b3cd008d0f"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d8ce3fb0841763a89322ea0432f1f59a2d3feae07a63ea2c958b2315e1ae8adb"}, - {file = "pydantic-1.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b34ba24f3e2d0b39b43f0ca62008f7ba962cff51efa56e64ee25c4af6eed987b"}, - {file = "pydantic-1.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:84d76ecc908d917f4684b354a39fd885d69dd0491be175f3465fe4b59811c001"}, - {file = "pydantic-1.9.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4de71c718c9756d679420c69f216776c2e977459f77e8f679a4a961dc7304a56"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5803ad846cdd1ed0d97eb00292b870c29c1f03732a010e66908ff48a762f20e4"}, - {file = "pydantic-1.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8c5360a0297a713b4123608a7909e6869e1b56d0e96eb0d792c27585d40757f"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:cdb4272678db803ddf94caa4f94f8672e9a46bae4a44f167095e4d06fec12979"}, - {file = "pydantic-1.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:19b5686387ea0d1ea52ecc4cffb71abb21702c5e5b2ac626fd4dbaa0834aa49d"}, - {file = "pydantic-1.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:32e0b4fb13ad4db4058a7c3c80e2569adbd810c25e6ca3bbd8b2a9cc2cc871d7"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91089b2e281713f3893cd01d8e576771cd5bfdfbff5d0ed95969f47ef6d676c3"}, - {file = "pydantic-1.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e631c70c9280e3129f071635b81207cad85e6c08e253539467e4ead0e5b219aa"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b3946f87e5cef3ba2e7bd3a4eb5a20385fe36521d6cc1ebf3c08a6697c6cfb3"}, - {file = "pydantic-1.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5565a49effe38d51882cb7bac18bda013cdb34d80ac336428e8908f0b72499b0"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:bd67cb2c2d9602ad159389c29e4ca964b86fa2f35c2faef54c3eb28b4efd36c8"}, - {file = "pydantic-1.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4aafd4e55e8ad5bd1b19572ea2df546ccace7945853832bb99422a79c70ce9b8"}, - {file = "pydantic-1.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:d70916235d478404a3fa8c997b003b5f33aeac4686ac1baa767234a0f8ac2326"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0ca86b525264daa5f6b192f216a0d1e860b7383e3da1c65a1908f9c02f42801"}, - {file = "pydantic-1.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1061c6ee6204f4f5a27133126854948e3b3d51fcc16ead2e5d04378c199b2f44"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e78578f0c7481c850d1c969aca9a65405887003484d24f6110458fb02cca7747"}, - {file = "pydantic-1.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5da164119602212a3fe7e3bc08911a89db4710ae51444b4224c2382fd09ad453"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ead3cd020d526f75b4188e0a8d71c0dbbe1b4b6b5dc0ea775a93aca16256aeb"}, - {file = "pydantic-1.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7d0f183b305629765910eaad707800d2f47c6ac5bcfb8c6397abdc30b69eeb15"}, - {file = "pydantic-1.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1a68f4f65a9ee64b6ccccb5bf7e17db07caebd2730109cb8a95863cfa9c4e55"}, - {file = "pydantic-1.9.2-py3-none-any.whl", hash = "sha256:78a4d6bdfd116a559aeec9a4cfe77dda62acc6233f8b56a716edad2651023e5e"}, - {file = "pydantic-1.9.2.tar.gz", hash = "sha256:8cb0bc509bfb71305d7a59d00163d5f9fc4530f0881ea32c74ff4f74c85f3d3d"}, + {file = "pydantic-1.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5920824fe1e21cbb3e38cf0f3dd24857c8959801d1031ce1fac1d50857a03bfb"}, + {file = "pydantic-1.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3bb99cf9655b377db1a9e47fa4479e3330ea96f4123c6c8200e482704bf1eda2"}, + {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2185a3b3d98ab4506a3f6707569802d2d92c3a7ba3a9a35683a7709ea6c2aaa2"}, + {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f582cac9d11c227c652d3ce8ee223d94eb06f4228b52a8adaafa9fa62e73d5c9"}, + {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c9e5b778b6842f135902e2d82624008c6a79710207e28e86966cd136c621bfee"}, + {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72ef3783be8cbdef6bca034606a5de3862be6b72415dc5cb1fb8ddbac110049a"}, + {file = "pydantic-1.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:45edea10b75d3da43cfda12f3792833a3fa70b6eee4db1ed6aed528cef17c74e"}, + {file = "pydantic-1.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63200cd8af1af2c07964546b7bc8f217e8bda9d0a2ef0ee0c797b36353914984"}, + {file = "pydantic-1.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:305d0376c516b0dfa1dbefeae8c21042b57b496892d721905a6ec6b79494a66d"}, + {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd326aff5d6c36f05735c7c9b3d5b0e933b4ca52ad0b6e4b38038d82703d35b"}, + {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bb0452d7b8516178c969d305d9630a3c9b8cf16fcf4713261c9ebd465af0d73"}, + {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9a9d9155e2a9f38b2eb9374c88f02fd4d6851ae17b65ee786a87d032f87008f8"}, + {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f836444b4c5ece128b23ec36a446c9ab7f9b0f7981d0d27e13a7c366ee163f8a"}, + {file = "pydantic-1.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:8481dca324e1c7b715ce091a698b181054d22072e848b6fc7895cd86f79b4449"}, + {file = "pydantic-1.10.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:87f831e81ea0589cd18257f84386bf30154c5f4bed373b7b75e5cb0b5d53ea87"}, + {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ce1612e98c6326f10888df951a26ec1a577d8df49ddcaea87773bfbe23ba5cc"}, + {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58e41dd1e977531ac6073b11baac8c013f3cd8706a01d3dc74e86955be8b2c0c"}, + {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6a4b0aab29061262065bbdede617ef99cc5914d1bf0ddc8bcd8e3d7928d85bd6"}, + {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:36e44a4de37b8aecffa81c081dbfe42c4d2bf9f6dff34d03dce157ec65eb0f15"}, + {file = "pydantic-1.10.5-cp37-cp37m-win_amd64.whl", hash = "sha256:261f357f0aecda005934e413dfd7aa4077004a174dafe414a8325e6098a8e419"}, + {file = "pydantic-1.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b429f7c457aebb7fbe7cd69c418d1cd7c6fdc4d3c8697f45af78b8d5a7955760"}, + {file = "pydantic-1.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:663d2dd78596c5fa3eb996bc3f34b8c2a592648ad10008f98d1348be7ae212fb"}, + {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51782fd81f09edcf265823c3bf43ff36d00db246eca39ee765ef58dc8421a642"}, + {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c428c0f64a86661fb4873495c4fac430ec7a7cef2b8c1c28f3d1a7277f9ea5ab"}, + {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:76c930ad0746c70f0368c4596020b736ab65b473c1f9b3872310a835d852eb19"}, + {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3257bd714de9db2102b742570a56bf7978e90441193acac109b1f500290f5718"}, + {file = "pydantic-1.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:f5bee6c523d13944a1fdc6f0525bc86dbbd94372f17b83fa6331aabacc8fd08e"}, + {file = "pydantic-1.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:532e97c35719f137ee5405bd3eeddc5c06eb91a032bc755a44e34a712420daf3"}, + {file = "pydantic-1.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ca9075ab3de9e48b75fa8ccb897c34ccc1519177ad8841d99f7fd74cf43be5bf"}, + {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd46a0e6296346c477e59a954da57beaf9c538da37b9df482e50f836e4a7d4bb"}, + {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3353072625ea2a9a6c81ad01b91e5c07fa70deb06368c71307529abf70d23325"}, + {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3f9d9b2be177c3cb6027cd67fbf323586417868c06c3c85d0d101703136e6b31"}, + {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b473d00ccd5c2061fd896ac127b7755baad233f8d996ea288af14ae09f8e0d1e"}, + {file = "pydantic-1.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:5f3bc8f103b56a8c88021d481410874b1f13edf6e838da607dcb57ecff9b4594"}, + {file = "pydantic-1.10.5-py3-none-any.whl", hash = "sha256:7c5b94d598c90f2f46b3a983ffb46ab806a67099d118ae0da7ef21a2a4033b28"}, + {file = "pydantic-1.10.5.tar.gz", hash = "sha256:9e337ac83686645a46db0e825acceea8e02fca4062483f40e9ae178e8bd1103a"}, ] [package.dependencies] -typing-extensions = ">=3.7.4.3" +typing-extensions = ">=4.2.0" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pygls" -version = "0.12.2" -description = "a pythonic generic language server (pronounced like \"pie glass\")." -category = "main" -optional = false -python-versions = "<4,>=3.7" -files = [ - {file = "pygls-0.12.2-py3-none-any.whl", hash = "sha256:ad83aea5c45c915b6b0b47ef0faca3c3b4778d087110c8e912da14b9f1c9f9d7"}, - {file = "pygls-0.12.2.tar.gz", hash = "sha256:48465ba74a32d50fbc110111ee0b60721c169f5bd9d8eedc582931ff765d6bc6"}, -] - -[package.dependencies] -pydantic = ">=1.9.1,<1.10" -typeguard = ">=2.10.0,<3" - -[package.extras] -dev = ["bandit (==1.7.4)", "flake8 (==4.0.1)", "mypy (==0.961)"] -docs = ["sphinx (==5.0.1)", "sphinx-rtd-theme (==1.0.0)"] -test = ["mock (==4.0.3)", "pytest (==7.1.2)", "pytest-asyncio (==0.18.3)"] -ws = ["websockets (>=10.0.0,<11.0.0)"] - [[package]] name = "pygments" version = "2.14.0" @@ -1412,18 +1309,6 @@ files = [ {file = "pyrsistent-0.19.3.tar.gz", hash = "sha256:1a2994773706bbb4995c31a97bc94f1418314923bd1048c6d964837040376440"}, ] -[[package]] -name = "pyspellchecker" -version = "0.7.1" -description = "Pure python spell checker based on work by Peter Norvig" -category = "main" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyspellchecker-0.7.1-py3-none-any.whl", hash = "sha256:9fac7e3abf2a11eb1660906dc513bc9f92bd49795f136bb1a56ac1f59f5498b0"}, - {file = "pyspellchecker-0.7.1.tar.gz", hash = "sha256:ed46a7218a363ef1a348fac14c9fef95b0aca5daa7744389d70843fcc0961b31"}, -] - [[package]] name = "pytest" version = "7.2.1" @@ -1449,26 +1334,6 @@ tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] -[[package]] -name = "pytest-asyncio" -version = "0.20.3" -description = "Pytest support for asyncio" -category = "dev" -optional = false -python-versions = ">=3.7" -files = [ - {file = "pytest-asyncio-0.20.3.tar.gz", hash = "sha256:83cbf01169ce3e8eb71c6c278ccb0574d1a7a3bb8eaaf5e50e0ad342afb33b36"}, - {file = "pytest_asyncio-0.20.3-py3-none-any.whl", hash = "sha256:f129998b209d04fcc65c96fc85c11e5316738358909a8399e93be553d7656442"}, -] - -[package.dependencies] -pytest = ">=6.1.0" -typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} - -[package.extras] -docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] -testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] - [[package]] name = "pytest-benchmark" version = "4.0.0" @@ -1490,28 +1355,6 @@ aspect = ["aspectlib"] elasticsearch = ["elasticsearch"] histogram = ["pygal", "pygaljs"] -[[package]] -name = "pytest-lsp" -version = "0.1.3" -description = "Pytest plugin for end-to-end testing of language servers" -category = "dev" -optional = false -python-versions = "*" -files = [ - {file = "pytest-lsp-0.1.3.tar.gz", hash = "sha256:5b14e1f46ded5b21b3631d6e1ee7e4c20de137a8d36d18e518b28947579436d6"}, - {file = "pytest_lsp-0.1.3-py3-none-any.whl", hash = "sha256:eb7883f04b834a04249c912d0c94fedc60bd41dd9cd674c40395f27cbb3d7e15"}, -] - -[package.dependencies] -appdirs = "*" -importlib-resources = {version = "*", markers = "python_version < \"3.9\""} -pygls = ">=0.11.0,<1.0" -pytest = "*" -pytest-asyncio = "*" - -[package.extras] -dev = ["black", "flake8", "mypy", "pre-commit", "pytest-cov", "pytest-timeout", "tox", "types-appdirs"] - [[package]] name = "pytest-xdist" version = "3.2.0" @@ -1712,14 +1555,14 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.2.0" +version = "67.3.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.2.0-py3-none-any.whl", hash = "sha256:16ccf598aab3b506593c17378473978908a2734d7336755a8769b480906bec1c"}, - {file = "setuptools-67.2.0.tar.gz", hash = "sha256:b440ee5f7e607bb8c9de15259dba2583dd41a38879a7abc1d43a71c59524da48"}, + {file = "setuptools-67.3.2-py3-none-any.whl", hash = "sha256:bb6d8e508de562768f2027902929f8523932fcd1fb784e6d573d2cafac995a48"}, + {file = "setuptools-67.3.2.tar.gz", hash = "sha256:95f00380ef2ffa41d9bba85d95b27689d923c93dfbafed4aecd7cf988a25e012"}, ] [package.extras] @@ -2010,44 +1853,28 @@ files = [ {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] -[[package]] -name = "typeguard" -version = "2.13.3" -description = "Run-time type checker for Python" -category = "main" -optional = false -python-versions = ">=3.5.3" -files = [ - {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"}, - {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"}, -] - -[package.extras] -doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["mypy", "pytest", "typing-extensions"] - [[package]] name = "types-docutils" -version = "0.19.1.3" +version = "0.19.1.4" description = "Typing stubs for docutils" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-docutils-0.19.1.3.tar.gz", hash = "sha256:36fe30de56f1ece1a9f7a990d47daa781b5af831d2b3f2dcb7dfd01b857cc3d4"}, - {file = "types_docutils-0.19.1.3-py3-none-any.whl", hash = "sha256:d608e6b91ccf0e8e01c586a0af5b0e0462382d3be65b734af82d40c9d010735d"}, + {file = "types-docutils-0.19.1.4.tar.gz", hash = "sha256:1b64b21b609ff1fc7791d3d930f14b56b36ad09029fd97e45e34cc889d671b5f"}, + {file = "types_docutils-0.19.1.4-py3-none-any.whl", hash = "sha256:870d71f3663141f67a3c59d26d2c54a8c478c842208bb0b345fbf6036f49f561"}, ] [[package]] name = "types-requests" -version = "2.28.11.12" +version = "2.28.11.13" description = "Typing stubs for requests" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-requests-2.28.11.12.tar.gz", hash = "sha256:fd530aab3fc4f05ee36406af168f0836e6f00f1ee51a0b96b7311f82cb675230"}, - {file = "types_requests-2.28.11.12-py3-none-any.whl", hash = "sha256:dbc2933635860e553ffc59f5e264264981358baffe6342b925e3eb8261f866ee"}, + {file = "types-requests-2.28.11.13.tar.gz", hash = "sha256:3fd332842e8759ea5f7eb7789df8aa772ba155216ccf10ef4aa3b0e5b42e1b46"}, + {file = "types_requests-2.28.11.13-py3-none-any.whl", hash = "sha256:94896f6f8e9f3db11e422c6e3e4abbc5d7ccace853eac74b23bdd65eeee3cdee"}, ] [package.dependencies] @@ -2070,38 +1897,38 @@ types-docutils = "*" [[package]] name = "types-toml" -version = "0.10.8.3" +version = "0.10.8.4" description = "Typing stubs for toml" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-toml-0.10.8.3.tar.gz", hash = "sha256:f37244eff4cd7eace9cb70d0bac54d3eba77973aa4ef26c271ac3d1c6503a48e"}, - {file = "types_toml-0.10.8.3-py3-none-any.whl", hash = "sha256:a2286a053aea6ab6ff814659272b1d4a05d86a1dd52b807a87b23511993b46c5"}, + {file = "types-toml-0.10.8.4.tar.gz", hash = "sha256:c8748dd225b28eb80ce712e2d7d61b57599815e7b48d07ef53df51ed148fa6b1"}, + {file = "types_toml-0.10.8.4-py3-none-any.whl", hash = "sha256:306b1bb8b5bbc5f1b60387dbcc4b489e79f8490ce20e93af5f422a68b470d94b"}, ] [[package]] name = "types-urllib3" -version = "1.26.25.5" +version = "1.26.25.6" description = "Typing stubs for urllib3" category = "dev" optional = false python-versions = "*" files = [ - {file = "types-urllib3-1.26.25.5.tar.gz", hash = "sha256:5630e578246d170d91ebe3901788cd28d53c4e044dc2e2488e3b0d55fb6895d8"}, - {file = "types_urllib3-1.26.25.5-py3-none-any.whl", hash = "sha256:e8f25c8bb85cde658c72ee931e56e7abd28803c26032441eea9ff4a4df2b0c31"}, + {file = "types-urllib3-1.26.25.6.tar.gz", hash = "sha256:35586727cbd7751acccf2c0f34a88baffc092f435ab62458f10776466590f2d5"}, + {file = "types_urllib3-1.26.25.6-py3-none-any.whl", hash = "sha256:a6c23c41bd03e542eaee5423a018f833077b51c4bf9ceb5aa544e12b812d5604"}, ] [[package]] name = "typing-extensions" -version = "4.4.0" +version = "4.5.0" description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"}, - {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"}, + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, ] [[package]] @@ -2145,14 +1972,14 @@ test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess [[package]] name = "zipp" -version = "3.12.1" +version = "3.13.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.12.1-py3-none-any.whl", hash = "sha256:6c4fe274b8f85ec73c37a8e4e3fa00df9fb9335da96fb789e3b96b318e5097b3"}, - {file = "zipp-3.12.1.tar.gz", hash = "sha256:a3cac813d40993596b39ea9e93a18e8a2076d5c378b8bc88ec32ab264e04ad02"}, + {file = "zipp-3.13.0-py3-none-any.whl", hash = "sha256:e8b2a36ea17df80ffe9e2c4fda3f693c3dad6df1697d3cd3af232db680950b0b"}, + {file = "zipp-3.13.0.tar.gz", hash = "sha256:23f70e964bc11a34cef175bc90ba2914e1e4545ea1e3e2f67c079671883f9cb6"}, ] [package.extras] @@ -2166,4 +1993,4 @@ immaterial = [] [metadata] lock-version = "2.0" python-versions = ">=3.7.0,<4.0" -content-hash = "dbc8aff4a94d21cac3bf7813266c9d851d2c4cd1bd709fe7db689c60782746bc" +content-hash = "27f4d83ca2c7761c9440fc0979fe8975749d3b2ce6ff44c276fa9b2948f8deb8" diff --git a/pyproject.toml b/pyproject.toml index 56ac50761..a5283157f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,8 +41,6 @@ requests-file = "^1.5.1" # external links requests = "^2.25.1" # external_links jsonschema = ">=3.2.0" # needsimport schema validation sphinx-data-viewer = "^0.1.1" # needservice debug output -esbonio = ">=0.11.3" # IDE language features -pygls = "*" # esbonio dependency [tool.poetry.dev-dependencies] sphinxcontrib-plantuml = "^0" @@ -51,8 +49,6 @@ pre-commit = "^2" lxml = "^4.6.5" pytest = "^7" pytest-xdist="*" # parallelisation -pytest_lsp="*" -myst-parser="^0.18.0" responses = "^0.22.0" requests-mock = ">=1.9.3" tabulate = "^0.9.0" diff --git a/sphinx_needs/__init__.py b/sphinx_needs/__init__.py index 9431a31e8..61e4c9f42 100644 --- a/sphinx_needs/__init__.py +++ b/sphinx_needs/__init__.py @@ -1,2 +1 @@ -from sphinx_needs.lsp.esbonio import esbonio_setup # noqa: F401 from sphinx_needs.needs import setup # noqa: F401 diff --git a/sphinx_needs/lsp/__init__.py b/sphinx_needs/lsp/__init__.py deleted file mode 100644 index 38685332d..000000000 --- a/sphinx_needs/lsp/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -# -------------------------------------------------------------------------- -# Licensed under the MIT license. -# See License.txt in the project root for further license information. -# -------------------------------------------------------------------------- diff --git a/sphinx_needs/lsp/esbonio.py b/sphinx_needs/lsp/esbonio.py deleted file mode 100644 index 237291e57..000000000 --- a/sphinx_needs/lsp/esbonio.py +++ /dev/null @@ -1,647 +0,0 @@ -"""Suport Sphinx-Needs language features.""" -import getpass -import os -import re -import typing -from hashlib import blake2b -from pathlib import Path -from typing import List, Optional, Tuple, Union - -from esbonio.lsp import LanguageFeature -from esbonio.lsp.rst import CompletionContext, DefinitionContext, HoverContext -from esbonio.lsp.sphinx import SphinxLanguageServer -from jinja2 import BaseLoader, Environment -from packaging import version -from pygls import __version__ - -if version.parse(__version__) < version.parse("1.0"): - from pygls.lsp.types import ( - CompletionItem, - CompletionItemKind, - InsertTextFormat, - Location, - Position, - Range, - TextEdit, - ) -else: - from lsprotocol.types import ( # type: ignore[no-redef] - CompletionItem, - CompletionItemKind, - InsertTextFormat, - Location, - Position, - Range, - TextEdit, - ) - -from sphinx.application import Sphinx - -from sphinx_needs.lsp.needs_store import NeedsStore - - -def get_needs_json(app: Sphinx) -> Optional[Path]: - """ - Get the location of needs.json. - """ - - needs_json = None - # check if needs.json is built automatically during each sphinx-build, - # which requres needs_build_json = True in conf.py - outdir = Path(app.outdir) - if getattr(app.config, "needs_build_json", False): - needs_json = outdir / "needs.json" - else: - # needs.json is manually built, need to check directory buildDir - # check buildDir/needs.json, e,g, _build/needs.json, when user using: sphinx-build -b needs srcdir buiddir - if app.builder and hasattr(app.builder, "name"): - curr_builder = app.builder.name - builddir = Path(app.outdir[: -len(curr_builder)]) - needs_json = builddir / "needs.json" - - return needs_json - - -class NeedlsFeatures(LanguageFeature): - """Sphinx-Needs features support for the language server.""" - - def __init__(self, rst: SphinxLanguageServer) -> None: - super().__init__(rst) - self.needs_store = NeedsStore() - - # Open-Needs-IDE language features completion triggers: '>', '/', ':', '.' - completion_triggers = [re.compile(r"(>)|(\.\.)|(:)|(\/)")] - - def complete(self, context: CompletionContext) -> List[CompletionItem]: - - if isinstance(self.rst, SphinxLanguageServer) and self.rst.app: - # get and check needs.json path - needs_json = get_needs_json(self.rst.app) - if not (needs_json and needs_json.exists()): - self.logger.warning(f"needs.json {needs_json} not exists. No Sphinx-Needs language features activated.") - return [] - - # load needs.json - self.needs_store.load_needs(needs_json) - - # check and set conf.py path - conf_py_path = Path(self.rst.app.srcdir) / "conf.py" - self.needs_store.set_conf_py(conf_py_path) - # set declared need types - self.needs_store.set_declared_types() - - self.logger.debug(f"NeedsStore needs: {self.needs_store.needs}") - # check if needs initialzed - if not self.needs_store.needs_initialized: - return [] - - lines, word = get_lines_and_word(self, context) - line_number = context.position.line - if line_number >= len(lines): - self.logger.info(f"line {line_number} is empty, no completion trigger characters detected") - return [] - line = lines[line_number] - - # if word starts with '->' or ':need:->', complete_need_link - if word.startswith("->") or word.startswith(":need:`->") or word.startswith("{need}`->"): - new_word = word.replace(":need:`->", "->") - if new_word != "->": - new_word = word.replace("{need}`->", "->") - new_word = new_word.replace("`", "") # in case need:`->...>...` - return complete_need_link(self, context, lines, line, new_word) - - # if word starts with ':', complete_role_or_option - if word.startswith(":"): - return complete_role_or_option(self, context, lines, word) - - # if word starts with '..', complete_directive - if word.startswith(".."): - return complete_directive(self, context, lines, word) - - return [] - - return [] - - hover_triggers = [re.compile(r".*")] - - def hover(self, context: HoverContext) -> str: - """Return textDocument/hover response value.""" - self.logger.debug(f"hover params: {context}") - - if isinstance(self.rst, SphinxLanguageServer) and self.rst.app: - # get and check needs.json path - needs_json = get_needs_json(self.rst.app) - if not (needs_json and needs_json.exists()): - self.logger.warning(f"needs.json {needs_json} not exists. No Sphinx-Needs language features activated.") - return "" - - # load needs.json - self.needs_store.load_needs(needs_json) - - try: - need_id = get_need_type_and_id(self, context)[1] - except IndexError: - return "" - if not need_id: - return "" - - try: - title = self.needs_store.needs[need_id]["title"] - description = self.needs_store.needs[need_id]["description"] - hover_value = f"**{title}**\n\n```\n{description}\n```" - return hover_value - except KeyError: - # need is not in the database - return "" - return "" - - definition_triggers = [re.compile(r".*")] - - def definition(self, context: DefinitionContext) -> List[Location]: - """Return location of definition of a need.""" - if isinstance(self.rst, SphinxLanguageServer) and self.rst.app: - # get and check needs.json path - needs_json = get_needs_json(self.rst.app) - if not (needs_json and needs_json.exists()): - self.logger.warning(f"needs.json {needs_json} not exists. No Sphinx-Needs language features activated.") - return [] - - # load needs.json - self.needs_store.load_needs(needs_json) - - if not self.needs_store.is_setup(): - return [] - - need_type, need_id = get_need_type_and_id(self, context) - - # get need defining doc - try: - need = self.needs_store.needs[need_id] - except KeyError: - return [] - - doc_path = Path(self.rst.app.srcdir) / typing.cast(str, need["docname"]) - if doc_path.with_suffix(".rst").exists(): - doc_path = doc_path.with_suffix(".rst") - elif doc_path.with_suffix(".rest").exists(): - doc_path = doc_path.with_suffix(".rest") - elif doc_path.with_suffix(".md").exists(): - doc_path = doc_path.with_suffix(".md") - else: - return [] - - # get the need definition position (line, col) from file - with open(doc_path) as file: - source_lines = file.readlines() - # get the line number - line_count = 0 - line_no = None - pattern = f":id: {need_id}" - for line in source_lines: - if pattern in line: - line_no = line_count - break - line_count = line_count + 1 - if not line_no: - return [] - - # get line of directive (e.g., .. req::) - line_directive = None - directive_patterns = [f".. {need_type}::", f"```{{{need_type}}}"] - for line_count in range(line_no - 1, -1, -1): - if any(dp in source_lines[line_count] for dp in directive_patterns): - line_directive = line_count - break - if not line_directive: - return [] - - pos = Position(line=line_directive, character=0) - return [Location(uri=doc_path.as_uri(), range=Range(start=pos, end=pos))] - return [] - - -def col_to_word_index(col: int, words: List[str]) -> int: - """Return the index of a word in a list of words for a given line character column.""" - length = 0 - index = 0 - for word in words: - length = length + len(word) - if col <= length + index: - return index - index = index + 1 - return index - 1 - - -def get_lines(ls: NeedlsFeatures, params: Union[CompletionContext, DefinitionContext, HoverContext]) -> List[str]: - """Get all text lines in the current document.""" - text_doc = params.doc - ls.logger.debug(f"text_doc: {text_doc}") - source = text_doc.source - return source.splitlines() - - -def get_word(ls: NeedlsFeatures, params: Union[CompletionContext, DefinitionContext, HoverContext]) -> str: - """Return the word in a line of text at a character position.""" - line_no, col = params.position - lines = get_lines(ls, params) - if line_no >= len(lines): - return "" - line = lines[line_no] - words = line.split() - index = col_to_word_index(col, words) - word: str = words[index] - return word - - -def get_lines_and_word(ls: NeedlsFeatures, params: CompletionContext) -> Tuple[List[str], str]: - return (get_lines(ls, params), get_word(ls, params)) - - -def get_need_type_and_id( - ls: NeedlsFeatures, params: Union[DefinitionContext, HoverContext] -) -> Tuple[Optional[str], Optional[str]]: - """Return tuple (need_type, need_id) for a given document position.""" - word = get_word(ls, params) - for need in ls.needs_store.needs.values(): - if need["id"] in word: - return (need["type"], need["id"]) - return (None, None) - - -def doc_completion_items(ls: NeedlsFeatures, docs: List[str], doc_pattern: str) -> List[CompletionItem]: - """Return completion items for a given doc pattern.""" - - # calc all doc paths that start with the given pattern - all_paths = [doc for doc in docs if doc.startswith(doc_pattern)] - - if len(all_paths) == 0: - return [] - - # leave if there is just one path - if len(all_paths) == 1: - insert_text = all_paths[0][len(doc_pattern) :] - return [ - CompletionItem( - label=insert_text, - insert_text=insert_text, - kind=CompletionItemKind.File, - detail="needs doc", - ) - ] - - # look at increasingly longer paths - # stop if there are at least two options - max_path_length = max(path.count("/") for path in all_paths) - current_path_length = doc_pattern.count("/") - - if max_path_length == current_path_length == 0: - sub_paths = all_paths - return [ - CompletionItem(label=sub_path, kind=CompletionItemKind.File, detail="path to needs doc") - for sub_path in sub_paths - ] - - # create list that contains only paths up to current path length - sub_paths = [] - for path in all_paths: - if path.count("/") >= current_path_length: - new_path = "/".join(path.split("/")[current_path_length : current_path_length + 1]) - if new_path not in sub_paths: - sub_paths.append(new_path) - sub_paths.sort() - - items = [] - for sub_path in sub_paths: - if sub_path.find(".rst") > -1 or sub_path.find(".md") > -1: - kind = CompletionItemKind.File - else: - kind = CompletionItemKind.Folder - items.append(CompletionItem(label=sub_path, kind=kind, detail="path to needs doc")) - return items - - -def complete_need_link( - ls: NeedlsFeatures, params: CompletionContext, lines: List[str], line: str, word: str -) -> List[CompletionItem]: - # specify the need type, e.g., - # ->req - if word.count(">") == 1: - return [CompletionItem(label=need_type, detail="need type") for need_type in ls.needs_store.types] - - word_parts = word.split(">") - - # specify doc in which need is specified, e.g., - # ->req>fusion/index.rst - if word.count(">") == 2: - requested_type = word_parts[1] # e.g., req, test, ... - if requested_type in ls.needs_store.types: - return doc_completion_items(ls, ls.needs_store.docs_per_type[requested_type], word_parts[2]) - - # specify the exact need, e.g., - # ->req>fusion/index.rst>REQ_001 - if word.count(">") == 3: - requested_type = word_parts[1] # e.g., req, test, ... - requested_doc = word_parts[2] # [0:-4] # without `.rst` file extension - if requested_doc in ls.needs_store.needs_per_doc: - substitution = word[word.find("->") :] - start_char = line.find(substitution) - line_number = params.position.line - return [ - CompletionItem( - label=need["id"], - insert_text=need["id"], - documentation=need["description"], - detail=need["title"], - additional_text_edits=[ - TextEdit( - range=Range( - start=Position(line=line_number, character=start_char), - end=Position( - line=line_number, - character=start_char + len(substitution), - ), - ), - new_text="", - ) - ], - ) - for need in ls.needs_store.needs_per_doc[requested_doc] - if need["type"] == requested_type - ] - - return [] - - -def generate_hash(user_name: str, doc_uri: str, need_prefix: str, line_number: int) -> str: - salt = os.urandom(blake2b.SALT_SIZE) # pylint: disable=no-member - return blake2b( - f"{user_name}{doc_uri}{need_prefix}{line_number}".encode(), - digest_size=4, - salt=salt, - ).hexdigest() - - -class JinjaHelperFunction: - """ - Jinja helper functions. - """ - - def __init__( - self, ls: NeedlsFeatures, params: CompletionContext, lines: List[str], need_type: Optional[str] = None - ) -> None: - self.ls = ls - self.params = params - self.lines = lines - self.need_type = need_type - - def random(self) -> str: - """Generate a random need ID including hash suffix..""" - - user_name = getpass.getuser() - doc_uri = self.params.doc.uri - line_number = self.params.position.line - - need_type = self.need_type - if not need_type: - match = re.search(".. ([a-z]+)::", self.lines[line_number - 1]) - # Check for MyST/Markdown style - if not match and self.params.doc.filename.endswith(".md"): - match = re.search("```{([a-z]+)}", self.lines[line_number - 1]) - - if match: - need_type = match.group(1) - if not need_type: - return "ID" - else: - return "ID" - - need_prefix = need_type.upper() - - hash_part = generate_hash(user_name, doc_uri, need_prefix, line_number) - need_id = need_prefix + "_" + hash_part - # re-generate hash if ID is already in use - while need_id in self.ls.needs_store.needs: - hash_part = generate_hash(user_name, doc_uri, need_prefix, line_number) - need_id = need_prefix + "_" + hash_part - return need_id - - def from_title(self) -> str: - """Generate a need ID from title.""" - - # default id from title if not exists - id_from_title = "title" - line_number = self.params.position.line - match = re.search(r".. ([a-z]+):: ([\w\s]+)", self.lines[line_number - 1]) - # check for MyST/Markdown style - if not match and self.params.doc.filename.endswith(".md"): - match = re.search(r"```{([a-z]+)} ([\w\s]+)", self.lines[line_number - 1]) - - if match: - matched_title = match.group(2) - if matched_title: - id_from_title = matched_title.rstrip().replace(" ", "_").lower() - else: - # check if previous line is empty, which means it's not used in directives - if not self.lines[line_number - 1]: - id_from_title = "ID" - - return id_from_title - - -def generate_need_id( - ls: NeedlsFeatures, params: CompletionContext, lines: List[str], need_type: Optional[str] = None -) -> str: - """Generate a need ID.""" - - # check custom id from conf.py - if isinstance(ls.rst, SphinxLanguageServer) and ls.rst.app: - custom_snippets_id = ls.rst.app.config.needs_ide_snippets_id - - if not custom_snippets_id: - # default to generate random need ID - custom_snippets_id = "{{random()}}" - - # handled by jinja - templ = Environment(loader=BaseLoader()).from_string(custom_snippets_id) - - jinja_util = JinjaHelperFunction(ls, params, lines, need_type) - data = {"random": jinja_util.random, "from_title": jinja_util.from_title} - need_id = templ.render(**data) - - return need_id - - -def found_eval_rst_block(lines: List[str], params: CompletionContext) -> bool: - # check if current line inside {eval-rst} block - # ```{eval-rst} - # - # ``` - found_eval_rst = False - # check if used in MyST/Markdown file - if not params.doc.filename.endswith(".md"): - return found_eval_rst - - curr_line_no = params.position.line - if curr_line_no > 0: - # check if open block {eval-rst} exits - cnt_block_eval_rst = 0 - cnt = 0 - for line in lines[:curr_line_no]: - if line.startswith("```"): - cnt += 1 - if line.startswith("```{eval-rst}"): - cnt_block_eval_rst += 1 - - # check if opened block {eval-rst} exists - if cnt % 2 != 0 and cnt_block_eval_rst % 2 != 0: - found_eval_rst = True - - return found_eval_rst - - -def calc_snippets_completion_item_text_edit(params: CompletionContext, lines: List[str], word: str) -> TextEdit: - line_number = params.position.line - substitution = word[word.find("..") :] - start_char = lines[line_number].find(substitution) - - text_edit = TextEdit( - range=Range( - start=Position(line=line_number, character=start_char), - end=Position( - line=line_number, - character=start_char + len(substitution), - ), - ), - new_text="", - ) - return text_edit - - -def complete_directive( - ls: NeedlsFeatures, params: CompletionContext, lines: List[str], word: str -) -> List[CompletionItem]: - # need_type ~ req, work, act, ... - items = [] - - # calculate completion item text edits - text_edit = calc_snippets_completion_item_text_edit(params, lines, word) - - # check custom directive snippets from conf.py - if isinstance(ls.rst, SphinxLanguageServer) and ls.rst.app: - custom_directive_snippets = ls.rst.app.config.needs_ide_directive_snippets - - for need_type, title in ls.needs_store.declared_types.items(): - # calculate directive snippets completion label - label = f".. {need_type}::" - if params.doc.filename.endswith(".md") and not found_eval_rst_block(lines, params): - # adapte label for MyST/Markdwon - label = f"md:.. {need_type}::" - - if custom_directive_snippets and need_type in custom_directive_snippets: - # use custom snippets - custom_text = custom_directive_snippets[need_type] - items.append( - CompletionItem( - label=label, - detail=title, - insert_text=custom_text, - insert_text_format=InsertTextFormat.Snippet, - kind=CompletionItemKind.Snippet, - additional_text_edits=[text_edit], - ) - ) - elif params.doc.filename.endswith(".md") and not found_eval_rst_block(lines, params): - # support for MySt/Markdown file - md_text = ( - "```{" + need_type + "} " + "${1:title}\n" - ":id: ${2:" + generate_need_id(ls, params, lines, need_type=need_type) + "}\n" - ":status: open\n\n" - "${3:content}.\n" - "```$0" - ) - md_detail = "Markdown directive snippet" - items.append( - CompletionItem( - label=label, - detail=md_detail, - insert_text=md_text, - insert_text_format=InsertTextFormat.Snippet, - kind=CompletionItemKind.Snippet, - additional_text_edits=[text_edit], - ) - ) - else: - text = ( - " " + need_type + ":: ${1:title}\n" - "\t:id: ${2:" + generate_need_id(ls, params, lines, need_type=need_type) + "}\n" - "\t:status: open\n\n" - "\t${3:content}.\n$0" - ) - items.append( - CompletionItem( - label=label, - detail=title, - insert_text=text, - insert_text_format=InsertTextFormat.Snippet, - kind=CompletionItemKind.Snippet, - ) - ) - - return items - - -def complete_role_or_option( - ls: NeedlsFeatures, params: CompletionContext, lines: List[str], word: str -) -> List[CompletionItem]: - # Calculate need role snippet for MySt/Markdown and rst - if params.doc.filename.endswith(".md"): - # support MyST/Markdown - # in MySz/Markdowm file, role looks like, e.g. {need}`content` - # triggered like noraml rst by :, replaced with markdown style - line_number = params.position.line - substitution = word[word.find(":") :] - start_char = lines[line_number].find(substitution) - need_role_item = CompletionItem( - label="md::need:", - detail="Markdown need role", - insert_text="{need}`${1:ID}`$0", - insert_text_format=InsertTextFormat.Snippet, - kind=CompletionItemKind.Snippet, - additional_text_edits=[ - TextEdit( - range=Range( - start=Position(line=line_number, character=start_char), - end=Position( - line=line_number, - character=start_char + len(substitution), - ), - ), - new_text="", - ) - ], - ) - else: - need_role_item = CompletionItem( - label=":need:", - detail="need role", - insert_text="need:`${1:ID}` $0", - insert_text_format=InsertTextFormat.Snippet, - kind=CompletionItemKind.Snippet, - ) - - return [ - CompletionItem( - label=":id:", - detail="needs option", - insert_text="id: ${1:" + generate_need_id(ls, params, lines) + "}\n$0", - insert_text_format=InsertTextFormat.Snippet, - kind=CompletionItemKind.Snippet, - ), - need_role_item, - ] - - -def esbonio_setup(rst: SphinxLanguageServer) -> None: - rst.logger.debug("Starting register Sphinx-Needs language features...") - needls_features = NeedlsFeatures(rst) - rst.add_feature(needls_features) diff --git a/sphinx_needs/lsp/exceptions.py b/sphinx_needs/lsp/exceptions.py deleted file mode 100644 index cb73aa331..000000000 --- a/sphinx_needs/lsp/exceptions.py +++ /dev/null @@ -1,2 +0,0 @@ -class NeedlsConfigException(BaseException): - """Errors in used configuration""" diff --git a/sphinx_needs/lsp/needs_store.py b/sphinx_needs/lsp/needs_store.py deleted file mode 100644 index 91c7fa36a..000000000 --- a/sphinx_needs/lsp/needs_store.py +++ /dev/null @@ -1,110 +0,0 @@ -# -------------------------------------------------------------------------- -# Licensed under the MIT license. -# See License.txt in the project root for further license information. -# -------------------------------------------------------------------------- - -import importlib.util -import json -import logging -import os -import sys -from contextlib import contextmanager -from pathlib import Path -from typing import Any, Dict, Generator, List, Optional - -from sphinx_needs.lsp.exceptions import NeedlsConfigException - - -@contextmanager -def set_directory(path: Path) -> Generator[None, None, None]: - origin = Path().cwd() - try: - os.chdir(path) - yield - finally: - os.chdir(origin) - - -class NeedsStore: - """Abstraction of needs database.""" - - def __init__(self) -> None: - self.docs_per_type: Dict[str, List[str]] = {} # key: need type, val: list of doc names (str) - self.needs_per_doc: Dict[Optional[str], List[Dict[Optional[str], Any]]] = {} # key: docname; val: list of needs - self.types: List[str] = [] # list of need types actually defined in needs.json - self.declared_types: Dict[str, str] = {} # types declared in conf.py: {'need directive': 'need title'} - self.needs: Dict[Optional[str], Dict[Optional[str], Any]] = {} - self.needs_initialized: bool = False - self.conf_py_path: Path = Path() - - def is_setup(self) -> bool: - """Return True if database is ready for use.""" - - return self.needs_initialized - - def set_conf_py(self, conf_py: Path) -> None: - if not conf_py.exists(): - raise FileNotFoundError(f"Given custom configuration file {conf_py} not found.") - self.conf_py_path = conf_py - - def set_declared_types(self) -> None: - module_name = "conf" - conf_py = self.conf_py_path - with set_directory(conf_py.parent): - logging.info(f"Loading need_types from {conf_py.name}...") - - spec = importlib.util.spec_from_file_location(module_name, conf_py) - if spec is None: - raise ImportError(f"Created module spec {spec} from {conf_py.name} not exists.") - - module = importlib.util.module_from_spec(spec) - sys.modules[module_name] = module - - if spec.loader: - try: - spec.loader.exec_module(module) - except Exception as e: - logging.error(f"Failed to exccute module {module} -> {e}") - else: - raise ImportError(f"Python ModuleSpec Loader{spec.loader} not found.") - - need_types = getattr(module, "needs_types", []) - if not need_types: - raise NeedlsConfigException(f"No 'need_types' defined on {conf_py.name}") - - self.declared_types = {} - for item in need_types: - self.declared_types[item["directive"]] = item["title"] - - def load_needs(self, json_file: Path) -> None: - - self.docs_per_type = {} - self.needs_per_doc = {} - self.types = [] - self.needs = {} - - with open(json_file, encoding="utf-8") as file: - needs_json = json.load(file) - - versions = needs_json["versions"] - # get the latest version - version = versions[sorted(versions)[-1]] - - self.needs = version["needs"] - - for need in self.needs.values(): - need_type = need["type"] - docname = need["docname"] + need["doctype"] - - if need_type not in self.docs_per_type: - self.types.append(need_type) - self.docs_per_type[need_type] = [] - - if docname not in self.docs_per_type[need_type]: - self.docs_per_type[need_type].append(docname) - - if docname not in self.needs_per_doc: - self.needs_per_doc[docname] = [] - self.needs_per_doc[docname].append(need) - - self.needs_initialized = True diff --git a/sphinx_needs/needs.py b/sphinx_needs/needs.py index f0e74846b..72870180d 100644 --- a/sphinx_needs/needs.py +++ b/sphinx_needs/needs.py @@ -163,8 +163,6 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_config_value("needs_id_prefix_specs", "", "html", types=[str]) app.add_config_value("needs_id_length", 5, "html", types=[int]) app.add_config_value("needs_id_from_title", False, "html", types=[bool]) - app.add_config_value("needs_ide_snippets_id", "", "html", types=[str]) - app.add_config_value("needs_ide_directive_snippets", {}, "html", types=[dict]) app.add_config_value("needs_specs_show_needlist", False, "html", types=[bool]) app.add_config_value("needs_id_required", False, "html", types=[bool]) app.add_config_value( diff --git a/tests/test_lsp/doc_example_lsp/Makefile b/tests/test_lsp/doc_example_lsp/Makefile deleted file mode 100644 index d4bb2cbb9..000000000 --- a/tests/test_lsp/doc_example_lsp/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tests/test_lsp/doc_example_lsp/conf.py b/tests/test_lsp/doc_example_lsp/conf.py deleted file mode 100644 index c6b43c0f1..000000000 --- a/tests/test_lsp/doc_example_lsp/conf.py +++ /dev/null @@ -1,62 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = "Test Env" -copyright = "2022, open-needs community" -author = "open-needs community" - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx_needs"] - -needs_types = [ - {"directive": "req", "title": "Requirement", "prefix": "R_", "color": "#BFD8D2", "style": "node"}, - {"directive": "spec", "title": "Specification", "prefix": "S_", "color": "#FEDCD2", "style": "node"}, - {"directive": "impl", "title": "Implementation", "prefix": "I_", "color": "#DF744A", "style": "node"}, - {"directive": "test", "title": "Test Case", "prefix": "T_", "color": "#DCB239", "style": "node"}, - # Kept for backwards compatibility - {"directive": "need", "title": "Need", "prefix": "N_", "color": "#9856a5", "style": "node"}, -] - -needs_build_json = True - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ["_static"] diff --git a/tests/test_lsp/doc_example_lsp/index.rst b/tests/test_lsp/doc_example_lsp/index.rst deleted file mode 100644 index 02e1ba4cd..000000000 --- a/tests/test_lsp/doc_example_lsp/index.rst +++ /dev/null @@ -1,31 +0,0 @@ -Test-Env project -================ - -Just a test project for tests (tataaaa!). - - -Needs ------ - - -.. req:: First requirement - :id: REQ_1 - :status: open - - Requirement content - - -.. spec:: First specification - :id: SPEC_1 - :status: open - - Specification content - - -:need:`REQ_1` - -:need:`->` - -:need:`->req>` - -:need:`->req>index.rst>` diff --git a/tests/test_lsp/doc_example_lsp/make.bat b/tests/test_lsp/doc_example_lsp/make.bat deleted file mode 100644 index 8084272b4..000000000 --- a/tests/test_lsp/doc_example_lsp/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/tests/test_lsp/doc_lsp_custom_directive_snippets/Makefile b/tests/test_lsp/doc_lsp_custom_directive_snippets/Makefile deleted file mode 100644 index d4bb2cbb9..000000000 --- a/tests/test_lsp/doc_lsp_custom_directive_snippets/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tests/test_lsp/doc_lsp_custom_directive_snippets/conf.py b/tests/test_lsp/doc_lsp_custom_directive_snippets/conf.py deleted file mode 100644 index 9eff52b56..000000000 --- a/tests/test_lsp/doc_lsp_custom_directive_snippets/conf.py +++ /dev/null @@ -1,95 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = "Test Env" -copyright = "2022, open-needs community" -author = "open-needs community" - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx_needs"] - -needs_types = [ - {"directive": "req", "title": "Requirement", "prefix": "R_", "color": "#BFD8D2", "style": "node"}, - {"directive": "spec", "title": "Specification", "prefix": "S_", "color": "#FEDCD2", "style": "node"}, - {"directive": "impl", "title": "Implementation", "prefix": "I_", "color": "#DF744A", "style": "node"}, - {"directive": "test", "title": "Test Case", "prefix": "T_", "color": "#DCB239", "style": "node"}, - # Kept for backwards compatibility - {"directive": "need", "title": "Need", "prefix": "N_", "color": "#9856a5", "style": "node"}, -] - -needs_build_json = True - -# custom IDE directive snippets per need_type -needs_ide_directive_snippets = { - "req": """\ -.. req:: REQ Example - :id: ID - :status: - :custom_option_1: - - random content. -""", - "test": """\ -.. test:: Test Title - :id: TEST_ - :status: open - :custom_option: something - - test directive content. -""", -} - -# Or maybe define like this -# needs_ide_directive_snippets = [ -# { -# "need_type": "req", -# "title": "My Custom req title", -# "options": { -# "id": "REQ_", -# "status": "open", -# }, -# "content": "My req snippets content." -# }, -# ] - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ["_static"] diff --git a/tests/test_lsp/doc_lsp_custom_directive_snippets/index.rst b/tests/test_lsp/doc_lsp_custom_directive_snippets/index.rst deleted file mode 100644 index 02e1ba4cd..000000000 --- a/tests/test_lsp/doc_lsp_custom_directive_snippets/index.rst +++ /dev/null @@ -1,31 +0,0 @@ -Test-Env project -================ - -Just a test project for tests (tataaaa!). - - -Needs ------ - - -.. req:: First requirement - :id: REQ_1 - :status: open - - Requirement content - - -.. spec:: First specification - :id: SPEC_1 - :status: open - - Specification content - - -:need:`REQ_1` - -:need:`->` - -:need:`->req>` - -:need:`->req>index.rst>` diff --git a/tests/test_lsp/doc_lsp_custom_directive_snippets/make.bat b/tests/test_lsp/doc_lsp_custom_directive_snippets/make.bat deleted file mode 100644 index 8084272b4..000000000 --- a/tests/test_lsp/doc_lsp_custom_directive_snippets/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/Makefile b/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/Makefile deleted file mode 100644 index d4bb2cbb9..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/conf.py b/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/conf.py deleted file mode 100644 index cb80c8af5..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/conf.py +++ /dev/null @@ -1,65 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = "Test Env" -copyright = "2022, open-needs community" -author = "open-needs community" - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx_needs"] - -needs_types = [ - {"directive": "req", "title": "Requirement", "prefix": "R_", "color": "#BFD8D2", "style": "node"}, - {"directive": "spec", "title": "Specification", "prefix": "S_", "color": "#FEDCD2", "style": "node"}, - {"directive": "impl", "title": "Implementation", "prefix": "I_", "color": "#DF744A", "style": "node"}, - {"directive": "test", "title": "Test Case", "prefix": "T_", "color": "#DCB239", "style": "node"}, - # Kept for backwards compatibility - {"directive": "need", "title": "Need", "prefix": "N_", "color": "#9856a5", "style": "node"}, -] - -needs_build_json = True - -# Add custom need ID for snippets -needs_ide_snippets_id = "TEST_{{from_title()}}_TEST" - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ["_static"] diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/index.rst b/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/index.rst deleted file mode 100644 index 02e1ba4cd..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/index.rst +++ /dev/null @@ -1,31 +0,0 @@ -Test-Env project -================ - -Just a test project for tests (tataaaa!). - - -Needs ------ - - -.. req:: First requirement - :id: REQ_1 - :status: open - - Requirement content - - -.. spec:: First specification - :id: SPEC_1 - :status: open - - Specification content - - -:need:`REQ_1` - -:need:`->` - -:need:`->req>` - -:need:`->req>index.rst>` diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/make.bat b/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/make.bat deleted file mode 100644 index 8084272b4..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_from_title/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/Makefile b/tests/test_lsp/doc_lsp_custom_need_id_generate_random/Makefile deleted file mode 100644 index d4bb2cbb9..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/conf.py b/tests/test_lsp/doc_lsp_custom_need_id_generate_random/conf.py deleted file mode 100644 index 4f5e2ec2e..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/conf.py +++ /dev/null @@ -1,65 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = "Test Env" -copyright = "2022, open-needs community" -author = "open-needs community" - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx_needs"] - -needs_types = [ - {"directive": "req", "title": "Requirement", "prefix": "R_", "color": "#BFD8D2", "style": "node"}, - {"directive": "spec", "title": "Specification", "prefix": "S_", "color": "#FEDCD2", "style": "node"}, - {"directive": "impl", "title": "Implementation", "prefix": "I_", "color": "#DF744A", "style": "node"}, - {"directive": "test", "title": "Test Case", "prefix": "T_", "color": "#DCB239", "style": "node"}, - # Kept for backwards compatibility - {"directive": "need", "title": "Need", "prefix": "N_", "color": "#9856a5", "style": "node"}, -] - -needs_build_json = True - -# Add custom need ID for snippets -needs_ide_snippets_id = "Test_{{random()}}_Test" - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ["_static"] diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/index.rst b/tests/test_lsp/doc_lsp_custom_need_id_generate_random/index.rst deleted file mode 100644 index 02e1ba4cd..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/index.rst +++ /dev/null @@ -1,31 +0,0 @@ -Test-Env project -================ - -Just a test project for tests (tataaaa!). - - -Needs ------ - - -.. req:: First requirement - :id: REQ_1 - :status: open - - Requirement content - - -.. spec:: First specification - :id: SPEC_1 - :status: open - - Specification content - - -:need:`REQ_1` - -:need:`->` - -:need:`->req>` - -:need:`->req>index.rst>` diff --git a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/make.bat b/tests/test_lsp/doc_lsp_custom_need_id_generate_random/make.bat deleted file mode 100644 index 8084272b4..000000000 --- a/tests/test_lsp/doc_lsp_custom_need_id_generate_random/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/tests/test_lsp/doc_lsp_support_MyST/Makefile b/tests/test_lsp/doc_lsp_support_MyST/Makefile deleted file mode 100644 index d4bb2cbb9..000000000 --- a/tests/test_lsp/doc_lsp_support_MyST/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/tests/test_lsp/doc_lsp_support_MyST/conf.py b/tests/test_lsp/doc_lsp_support_MyST/conf.py deleted file mode 100644 index 9a91c2ddd..000000000 --- a/tests/test_lsp/doc_lsp_support_MyST/conf.py +++ /dev/null @@ -1,64 +0,0 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - - -# -- Project information ----------------------------------------------------- - -project = "Test Env" -copyright = "2022, open-needs community" -author = "open-needs community" - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = ["sphinx_needs", "myst_parser"] - -source_suffix = [".rst", ".md"] - -needs_types = [ - {"directive": "req", "title": "Requirement", "prefix": "R_", "color": "#BFD8D2", "style": "node"}, - {"directive": "spec", "title": "Specification", "prefix": "S_", "color": "#FEDCD2", "style": "node"}, - {"directive": "impl", "title": "Implementation", "prefix": "I_", "color": "#DF744A", "style": "node"}, - {"directive": "test", "title": "Test Case", "prefix": "T_", "color": "#DCB239", "style": "node"}, - # Kept for backwards compatibility - {"directive": "need", "title": "Need", "prefix": "N_", "color": "#9856a5", "style": "node"}, -] - -needs_build_json = True - -# Add any paths that contain templates here, relative to this directory. -templates_path = ["_templates"] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme = "alabaster" - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -# html_static_path = ["_static"] diff --git a/tests/test_lsp/doc_lsp_support_MyST/index.rst b/tests/test_lsp/doc_lsp_support_MyST/index.rst deleted file mode 100644 index 1f527651b..000000000 --- a/tests/test_lsp/doc_lsp_support_MyST/index.rst +++ /dev/null @@ -1,29 +0,0 @@ -Test-Env project -================ - -Just a test project for tests (tataaaa!). - - -Needs ------ - - -.. req:: First requirement - :id: REQ_1 - :status: open - - Requirement content - - -.. spec:: First specification - :id: SPEC_1 - :status: open - - Specification content - - -.. toctree:: - :maxdepth: 2 - - myfile.md - md_subfolder/MySecond.md diff --git a/tests/test_lsp/doc_lsp_support_MyST/make.bat b/tests/test_lsp/doc_lsp_support_MyST/make.bat deleted file mode 100644 index 8084272b4..000000000 --- a/tests/test_lsp/doc_lsp_support_MyST/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.https://www.sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/tests/test_lsp/doc_lsp_support_MyST/md_subfolder/MySecond.md b/tests/test_lsp/doc_lsp_support_MyST/md_subfolder/MySecond.md deleted file mode 100644 index 0b8389974..000000000 --- a/tests/test_lsp/doc_lsp_support_MyST/md_subfolder/MySecond.md +++ /dev/null @@ -1,15 +0,0 @@ -# Markdown file in subfolder - -```{req} Sub MD Req title -:id: REQ_3 -:status: open - -MD in Subfolder with some req content. -``` - -```{spec} Sub MD Spec title -:id: SPEC_3 -:status: open - -MD in Subfolder with some spec content. -``` diff --git a/tests/test_lsp/doc_lsp_support_MyST/myfile.md b/tests/test_lsp/doc_lsp_support_MyST/myfile.md deleted file mode 100644 index 2c6b882df..000000000 --- a/tests/test_lsp/doc_lsp_support_MyST/myfile.md +++ /dev/null @@ -1,48 +0,0 @@ -# My Markdown file example title - -Some **text**! - -```{eval-rst} -.. req:: MD REQ Title - :id: REQ_2 - :status: open - - some stuff from md req. -``` - -```{spec} MD SPEC title -:id: SPEC_2 -:status: open - -MD Spec test content. -``` - -:need:`SPEC_2` - -:need:`REQ_3` - -:need:`REQ_1` - -:need:`->` - -:need:`->req>` - -:need:`->req>myfile.md>` - -:need:`->req>md_subfolder/` - -:need:`->req>md_subfolder/MySecond.md>` - -{need}`->` - -{need}`->req>` - -{need}`->req>myfile.md>` - -{need}`->req>md_subfolder/` - -{need}`->req>md_subfolder/MySecond.md>` - -:need - -.. req diff --git a/tests/test_lsp/test_lsp.py b/tests/test_lsp/test_lsp.py deleted file mode 100644 index 5e16134b3..000000000 --- a/tests/test_lsp/test_lsp.py +++ /dev/null @@ -1,332 +0,0 @@ -"""Test Sphinx-Needs language features.""" - -import os -import sys - -import pytest -import pytest_lsp -from packaging import version -from pygls import __version__ - -if version.parse(__version__) < version.parse("1.0"): - from pygls.lsp.types import MarkupContent, MarkupKind, Position, Range -else: - from lsprotocol.types import MarkupContent, MarkupKind, Position, Range - -TEST_DOC_ROOT_URI = os.path.join("file://", os.path.abspath(os.path.dirname(__file__)), "doc_example_lsp") -TEST_FILE_URI = os.path.join(TEST_DOC_ROOT_URI, "index.rst") - - -@pytest_lsp.fixture( - config=pytest_lsp.ClientServerConfig(server_command=[sys.executable, "-m", "esbonio"], root_uri=TEST_DOC_ROOT_URI), -) -async def client(): - pass - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_need_directive_role_completion(client): - # check needs directive completion - need_directive_result = await client.completion_request(uri=TEST_FILE_URI, line=10, character=3) - assert len(need_directive_result.items) > 0 - - req_idx = None - spec_idx = None - impl_idx = None - test_idx = None - need_idx = None - needarch_idx = None - needlist_idx = None - needimport_idx = None - for index, item in enumerate(need_directive_result.items): - if item.label == "req": - req_idx = index - elif item.label == "spec": - spec_idx = index - elif item.label == "impl": - impl_idx = index - elif item.label == "test": - test_idx = index - elif item.label == "need": - need_idx = index - elif item.label == "needarch": - needarch_idx = index - elif item.label == "needlist": - needlist_idx = index - elif item.label == "needimport": - needimport_idx = index - - # check user in conf.py defined need directive req exists - assert req_idx is not None - need_req = need_directive_result.items[req_idx] - assert need_req.label == "req" - assert need_req.filter_text == ".. req::" - assert need_req.detail == "sphinx_needs.directives.need.NeedDirective" - assert need_req.kind == 7 # CompletionItemKind.Class - assert need_req.insert_text_format == 1 # InsertTextFormat.PlainText - assert need_req.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_req.data["completion_type"] == "directive" - - # check user in conf.py need directive spec exists - assert spec_idx is not None - need_spec = need_directive_result.items[spec_idx] - assert need_spec.label == "spec" - assert need_spec.filter_text == ".. spec::" - assert need_spec.detail == "sphinx_needs.directives.need.NeedDirective" - assert need_spec.kind == 7 # CompletionItemKind.Class - assert need_spec.insert_text_format == 1 # InsertTextFormat.PlainText - assert need_spec.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_spec.data["completion_type"] == "directive" - - # check other in conf.py defined need directives also exist - assert impl_idx is not None - need_impl = need_directive_result.items[impl_idx] - assert need_impl.label == "impl" - assert need_impl.filter_text == ".. impl::" - assert need_impl.detail == "sphinx_needs.directives.need.NeedDirective" - - assert test_idx is not None - need_test = need_directive_result.items[test_idx] - assert need_test.label == "test" - assert need_test.filter_text == ".. test::" - assert need_test.detail == "sphinx_needs.directives.need.NeedDirective" - - assert need_idx is not None - need_need = need_directive_result.items[need_idx] - assert need_need.label == "need" - assert need_need.filter_text == ".. need::" - assert need_need.detail == "sphinx_needs.directives.need.NeedDirective" - - # check Sphinx-Needs default supported derectives exist - assert needarch_idx is not None - need_needarch = need_directive_result.items[needarch_idx] - assert need_needarch.label == "needarch" - assert need_needarch.filter_text == ".. needarch::" - assert need_needarch.detail == "sphinx_needs.directives.needuml.NeedarchDirective" - assert need_needarch.kind == 7 # CompletionItemKind.Class - assert need_needarch.insert_text_format == 1 # InsertTextFormat.PlainText - assert need_needarch.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_needarch.data["completion_type"] == "directive" - - assert needlist_idx is not None - need_needlist = need_directive_result.items[needlist_idx] - assert need_needlist.label == "needlist" - assert need_needlist.filter_text == ".. needlist::" - assert need_needlist.detail == "sphinx_needs.directives.needlist.NeedlistDirective" - assert need_needlist.kind == 7 # CompletionItemKind.Class - assert need_needlist.insert_text_format == 1 # InsertTextFormat.PlainText - assert need_needlist.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_needlist.data["completion_type"] == "directive" - - assert needimport_idx is not None - need_needimport = need_directive_result.items[needimport_idx] - assert need_needimport.label == "needimport" - assert need_needimport.filter_text == ".. needimport::" - assert need_needimport.detail == "sphinx_needs.directives.needimport.NeedimportDirective" - - # check need options for need directive req - need_req_options_result = await client.completion_request(uri=TEST_FILE_URI, line=11, character=3) - assert len(need_req_options_result.items) > 0 - - req_id_idx = None - req_status_idx = None - for index, item in enumerate(need_req_options_result.items): - if item.label == "id": - req_id_idx = index - elif item.label == "status": - req_status_idx = index - - # check need directive option id exists - assert req_id_idx is not None - need_req_option_id = need_req_options_result.items[req_id_idx] - assert need_req_option_id.label == "id" - assert need_req_option_id.filter_text == ":id:" - assert need_req_option_id.detail == "sphinx_needs.directives.need.NeedDirective:id" - assert need_req_option_id.kind == 5 # CompletionItemKind.Field - assert need_req_option_id.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_req_option_id.data["completion_type"] == "directive_option" - assert need_req_option_id.data["for_directive"] == "req" - - # check need directive option status exists - assert req_status_idx is not None - need_req_option_status = need_req_options_result.items[req_status_idx] - assert need_req_option_status.label == "status" - assert need_req_option_status.detail == "sphinx_needs.directives.need.NeedDirective:status" - assert need_req_option_status.kind == 5 # CompletionItemKind.Field - assert need_req_option_status.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_req_option_status.data["completion_type"] == "directive_option" - assert need_req_option_status.data["for_directive"] == "req" - - # check need options for need directive spec - need_spec_options_result = await client.completion_request(uri=TEST_FILE_URI, line=18, character=3) - assert len(need_spec_options_result.items) > 0 - - spec_id_idx = None - spec_status_idx = None - for index, item in enumerate(need_spec_options_result.items): - if item.label == "id": - spec_id_idx = index - elif item.label == "status": - spec_status_idx = index - - assert spec_id_idx is not None - need_spec_option_id = need_spec_options_result.items[spec_id_idx] - assert need_spec_option_id.label == "id" - assert need_spec_option_id.filter_text == ":id:" - assert need_spec_option_id.detail == "sphinx_needs.directives.need.NeedDirective:id" - assert need_spec_option_id.kind == 5 # CompletionItemKind.Field - assert need_spec_option_id.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_spec_option_id.data["completion_type"] == "directive_option" - assert need_spec_option_id.data["for_directive"] == "spec" - - assert spec_status_idx is not None - need_spec_option_status = need_spec_options_result.items[spec_status_idx] - assert need_spec_option_status.label == "status" - assert need_spec_option_status.filter_text == ":status:" - assert need_spec_option_status.detail == "sphinx_needs.directives.need.NeedDirective:status" - assert need_spec_option_status.kind == 5 # CompletionItemKind.Field - assert need_spec_option_status.data["source_feature"] == "esbonio.lsp.directives.Directives" - assert need_spec_option_status.data["completion_type"] == "directive_option" - assert need_spec_option_status.data["for_directive"] == "spec" - - # check need role completion - need_role_result = await client.completion_request(uri=TEST_FILE_URI, line=24, character=1) - assert len(need_role_result.items) > 0 - - need_role_idx = None - for index, item in enumerate(need_role_result.items): - if item.label == ":need:": - need_role_idx = index - - assert need_role_idx is not None - need_role_need = need_role_result.items[need_role_idx] - assert need_role_need.label == ":need:" - assert need_role_need.detail == "need role" - assert need_role_need.insert_text == "need:`${1:ID}` $0" - assert need_role_need.insert_text_format == 2 # InsertTextFormat.Snippet - assert need_role_need.kind == 15 # CompletionItemKind.Snippet - assert need_role_need.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_need_auto_generated_id_completion(client): - # check needs option id snippet, auto-generated need IDs, e.g. :id: REQ_e0bafd9b - need_req_options_result = await client.completion_request(uri=TEST_FILE_URI, line=11, character=3) - - option_id_idx = None - for index, item in enumerate(need_req_options_result.items): - if item.label == ":id:": - option_id_idx = index - - assert option_id_idx is not None - needs_option_id = need_req_options_result.items[option_id_idx] - assert needs_option_id.label == ":id:" - assert needs_option_id.detail == "needs option" - assert needs_option_id.insert_text.startswith("id: ${1:REQ_") - assert needs_option_id.insert_text.endswith("}\n$0") - assert needs_option_id.insert_text_format == 2 # InsertTextFormat.Snippet - assert needs_option_id.kind == 15 # CompletionItemKind.Snippet - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_need_directive_snippets_completion(client): - # check need directive snippets completion - need_directive_snippets = await client.completion_request(uri=TEST_FILE_URI, line=10, character=2) - assert len(need_directive_snippets.items) > 0 - - req_idx = None - for index, item in enumerate(need_directive_snippets.items): - if item.label == ".. req::": - req_idx = index - assert req_idx is not None - - need_directive_snippets_req = need_directive_snippets.items[req_idx] - assert need_directive_snippets_req.label == ".. req::" - assert need_directive_snippets_req.detail == "Requirement" - assert need_directive_snippets_req.insert_text.startswith(" req:: ${1:title}\n\t:id: ${2:REQ_") - assert need_directive_snippets_req.insert_text.endswith("}\n\t:status: open\n\n\t${3:content}.\n$0") - assert need_directive_snippets_req.insert_text_format == 2 # InsertTextFormat.Snippet - assert need_directive_snippets_req.kind == 15 # CompletionItemKind.Snippet - assert need_directive_snippets_req.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_need_id_selection_completion(client): - # check need ID selection completion for need type, e.g. :need:`->` - id_selection_need_type_result = await client.completion_request(uri=TEST_FILE_URI, line=26, character=9) - assert len(id_selection_need_type_result.items) == 2 - assert id_selection_need_type_result.items[0].label == "req" - assert id_selection_need_type_result.items[0].detail == "need type" - assert id_selection_need_type_result.items[1].label == "spec" - assert id_selection_need_type_result.items[1].detail == "need type" - - # check need ID selection completion for need file, e.g. :need:`->req>` - id_selection_need_file_result = await client.completion_request(uri=TEST_FILE_URI, line=28, character=13) - assert len(id_selection_need_file_result.items) == 1 - id_selection_need_file = id_selection_need_file_result.items[0] - assert id_selection_need_file.label == "index.rst" - assert id_selection_need_file.detail == "needs doc" - assert id_selection_need_file.insert_text == "index.rst" - assert id_selection_need_file.kind == 17 # CompletionItemKind.File - assert id_selection_need_file.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - # check need ID selection completion for need ID, e.g. :need:`->req>index.rst>` - id_selection_need_id_result = await client.completion_request(uri=TEST_FILE_URI, line=30, character=23) - assert len(id_selection_need_id_result.items) == 1 - id_selection_need_id = id_selection_need_id_result.items[0] - assert id_selection_need_id.label == "REQ_1" - assert id_selection_need_id.insert_text == "REQ_1" - assert id_selection_need_id.detail == "First requirement" - assert id_selection_need_id.documentation == "Requirement content" - assert id_selection_need_id.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_goto_definition(client): - # check goto defintion results - location_result = await client.definition_request(uri=TEST_FILE_URI, position=Position(line=24, character=8)) - defined_location = location_result[0] - - assert defined_location.range - assert type(defined_location.range) == Range - - # check defintion location range, e.g. for :need:`REQ_1` at line 25, go to definiton for REQ_1 will - # jump to begining of the definition of REQ_1, which is at line 11, character 0 - assert defined_location.range.start.line == 10 - assert defined_location.range.start.character == 0 - assert defined_location.range.end.line == 10 - assert defined_location.range.end.character == 0 - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_hover(client): - # check hover results - hover_directive_result = await client.hover_request(uri=TEST_FILE_URI, position=Position(line=18, character=9)) - assert type(hover_directive_result.contents) == MarkupContent - assert type(hover_directive_result.contents.kind) == MarkupKind - assert hover_directive_result.contents.kind == "markdown" # MarkupKind.Markdown - assert hover_directive_result.contents.value == "**First specification**\n\n```\nSpecification content\n```" - - hover_role_result = await client.hover_request(uri=TEST_FILE_URI, position=Position(line=24, character=8)) - assert type(hover_role_result.contents) == MarkupContent - assert type(hover_role_result.contents.kind) == MarkupKind - assert hover_role_result.contents.kind == "markdown" # MarkupKind.Markdown - assert hover_role_result.contents.value == "\n**First requirement**\n\n```\nRequirement content\n```" diff --git a/tests/test_lsp/test_lsp_custom_directive_snippets.py b/tests/test_lsp/test_lsp_custom_directive_snippets.py deleted file mode 100644 index 09941a70c..000000000 --- a/tests/test_lsp/test_lsp_custom_directive_snippets.py +++ /dev/null @@ -1,88 +0,0 @@ -"""Test Sphinx-Needs language features for custom directive snippets.""" - -import os -import sys - -import pytest -import pytest_lsp -from packaging import version -from pygls import __version__ - -TEST_DOC_ROOT_URI = os.path.join( - "file://", os.path.abspath(os.path.dirname(__file__)), "doc_lsp_custom_directive_snippets" -) -TEST_FILE_URI = os.path.join(TEST_DOC_ROOT_URI, "index.rst") -CONF_PY_CUSTOM_DIRECTIVE_SNIPPETS_REQ = """\ -.. req:: REQ Example - :id: ID - :status: - :custom_option_1: - - random content. -""" -CONF_PY_CUSTOM_DIRECTIVE_SNIPPETS_TEST = """\ -.. test:: Test Title - :id: TEST_ - :status: open - :custom_option: something - - test directive content. -""" - - -@pytest_lsp.fixture( - config=pytest_lsp.ClientServerConfig(server_command=[sys.executable, "-m", "esbonio"], root_uri=TEST_DOC_ROOT_URI), -) -async def client(): - pass - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_custom_directive_snippets(client): - # check need custom directive snippets completion - need_custom_directive_snippets = await client.completion_request(uri=TEST_FILE_URI, line=10, character=2) - assert need_custom_directive_snippets - - req_snippet_idx = None - test_snippet_idx = None - spec_snippet_idx = None - for index, item in enumerate(need_custom_directive_snippets.items): - if item.label == ".. req::": - req_snippet_idx = index - elif item.label == ".. test::": - test_snippet_idx = index - elif item.label == ".. spec::": - spec_snippet_idx = index - - # check custom directive snippets - assert req_snippet_idx is not None - need_custom_directive_snippets_req = need_custom_directive_snippets.items[req_snippet_idx] - assert need_custom_directive_snippets_req.label == ".. req::" - assert need_custom_directive_snippets_req.detail == "Requirement" - assert need_custom_directive_snippets_req.insert_text == CONF_PY_CUSTOM_DIRECTIVE_SNIPPETS_REQ - assert need_custom_directive_snippets_req.insert_text_format == 2 # InsertTextFormat.Snippet - assert need_custom_directive_snippets_req.kind == 15 # CompletionItemKind.Snippet - assert need_custom_directive_snippets_req.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - assert test_snippet_idx is not None - need_custom_directive_snippets_test = need_custom_directive_snippets.items[test_snippet_idx] - assert need_custom_directive_snippets_test.label == ".. test::" - assert need_custom_directive_snippets_test.detail == "Test Case" - assert need_custom_directive_snippets_test.insert_text == CONF_PY_CUSTOM_DIRECTIVE_SNIPPETS_TEST - assert need_custom_directive_snippets_test.insert_text_format == 2 # nsertTextFormat.Snippet - assert need_custom_directive_snippets_test.kind == 15 # CompletionItemKind.Snippet - assert need_custom_directive_snippets_test.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - # check default directive snippets - assert spec_snippet_idx is not None - need_custom_directive_snippets_spec = need_custom_directive_snippets.items[spec_snippet_idx] - assert need_custom_directive_snippets_spec.label == ".. spec::" - assert need_custom_directive_snippets_spec.detail == "Specification" - assert need_custom_directive_snippets_spec.insert_text.startswith(" spec:: ${1:title}\n\t:id: ${2:SPEC_") - assert need_custom_directive_snippets_spec.insert_text.endswith("}\n\t:status: open\n\n\t${3:content}.\n$0") - assert need_custom_directive_snippets_spec.insert_text_format == 2 # InsertTextFormat.Snippet - assert need_custom_directive_snippets_spec.kind == 15 # CompletionItemKind.Snippet - assert need_custom_directive_snippets_spec.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" diff --git a/tests/test_lsp/test_lsp_custom_need_id_generate_from_title.py b/tests/test_lsp/test_lsp_custom_need_id_generate_from_title.py deleted file mode 100644 index b2336b92e..000000000 --- a/tests/test_lsp/test_lsp_custom_need_id_generate_from_title.py +++ /dev/null @@ -1,60 +0,0 @@ -"""Test Sphinx-Needs language features for custom need ID generation with from_title().""" - -import os -import sys - -import pytest -import pytest_lsp -from packaging import version -from pygls import __version__ - -TEST_DOC_ROOT_URI = os.path.join( - "file://", os.path.abspath(os.path.dirname(__file__)), "doc_lsp_custom_need_id_generate_from_title" -) -TEST_FILE_URI = os.path.join(TEST_DOC_ROOT_URI, "index.rst") - - -@pytest_lsp.fixture( - config=pytest_lsp.ClientServerConfig(server_command=[sys.executable, "-m", "esbonio"], root_uri=TEST_DOC_ROOT_URI), -) -async def client(): - pass - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_directive_snippets_with_custom_need_id_generate_from_title(client): - need_directive_snippets = await client.completion_request(uri=TEST_FILE_URI, line=10, character=2) - assert len(need_directive_snippets.items) > 0 - - req_snippet_idx = None - for index, item in enumerate(need_directive_snippets.items): - if item.label == ".. req::": - req_snippet_idx = index - - assert req_snippet_idx is not None - need_directive_snippets_req = need_directive_snippets.items[req_snippet_idx] - assert need_directive_snippets_req.label == ".. req::" - assert need_directive_snippets_req.detail == "Requirement" - assert need_directive_snippets_req.insert_text.startswith(" req:: ${1:title}\n\t:id: ${2:TEST_ID_TEST") - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_id_auto_generation_with_custom_id_generate_from_title(client): - need_req_options_result = await client.completion_request(uri=TEST_FILE_URI, line=11, character=3) - - option_id_idx = None - for index, item in enumerate(need_req_options_result.items): - if item.label == ":id:": - option_id_idx = index - - assert option_id_idx is not None - needs_option_id = need_req_options_result.items[option_id_idx] - assert needs_option_id.label == ":id:" - assert needs_option_id.detail == "needs option" - assert needs_option_id.insert_text.startswith("id: ${1:TEST_first_requirement_TEST") diff --git a/tests/test_lsp/test_lsp_custom_need_id_generate_random.py b/tests/test_lsp/test_lsp_custom_need_id_generate_random.py deleted file mode 100644 index 28fa23260..000000000 --- a/tests/test_lsp/test_lsp_custom_need_id_generate_random.py +++ /dev/null @@ -1,62 +0,0 @@ -"""Test Sphinx-Needs language features for custom need ID generation with random().""" - -import os -import sys - -import pytest -import pytest_lsp -from packaging import version -from pygls import __version__ - -TEST_DOC_ROOT_URI = os.path.join( - "file://", os.path.abspath(os.path.dirname(__file__)), "doc_lsp_custom_need_id_generate_random" -) -TEST_FILE_URI = os.path.join(TEST_DOC_ROOT_URI, "index.rst") - - -@pytest_lsp.fixture( - config=pytest_lsp.ClientServerConfig(server_command=[sys.executable, "-m", "esbonio"], root_uri=TEST_DOC_ROOT_URI), -) -async def client(): - pass - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_directive_snippets_with_custom_need_id_generate_random(client): - need_directive_snippets = await client.completion_request(uri=TEST_FILE_URI, line=10, character=2) - assert len(need_directive_snippets.items) > 0 - - req_snippet_idx = None - for index, item in enumerate(need_directive_snippets.items): - if item.label == ".. req::": - req_snippet_idx = index - - assert req_snippet_idx is not None - need_directive_snippets_req = need_directive_snippets.items[req_snippet_idx] - assert need_directive_snippets_req.label == ".. req::" - assert need_directive_snippets_req.detail == "Requirement" - assert need_directive_snippets_req.insert_text.startswith(" req:: ${1:title}\n\t:id: ${2:Test_REQ_") - assert "_Test" in need_directive_snippets_req.insert_text - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_id_auto_generation_with_custom_id_generate_random(client): - need_req_options_result = await client.completion_request(uri=TEST_FILE_URI, line=11, character=3) - - option_id_idx = None - for index, item in enumerate(need_req_options_result.items): - if item.label == ":id:": - option_id_idx = index - - assert option_id_idx is not None - needs_option_id = need_req_options_result.items[option_id_idx] - assert needs_option_id.label == ":id:" - assert needs_option_id.detail == "needs option" - assert needs_option_id.insert_text.startswith("id: ${1:Test_REQ_") - assert needs_option_id.insert_text.endswith("_Test}\n$0") diff --git a/tests/test_lsp/test_lsp_support_MyST.py b/tests/test_lsp/test_lsp_support_MyST.py deleted file mode 100644 index 328e98b6e..000000000 --- a/tests/test_lsp/test_lsp_support_MyST.py +++ /dev/null @@ -1,308 +0,0 @@ -"""Test Sphinx-Needs language features MyST/Markdown support.""" - -import os -import sys - -import pytest -import pytest_lsp -from packaging import version -from pygls import __version__ - -if version.parse(__version__) < version.parse("1.0"): - from pygls.lsp.types import MarkupContent, MarkupKind, Position, Range -else: - from lsprotocol.types import MarkupContent, MarkupKind, Position, Range - -TEST_DOC_ROOT_URI = os.path.join("file://", os.path.abspath(os.path.dirname(__file__)), "doc_lsp_support_MyST") -TEST_MD_FILE_URI = os.path.join(TEST_DOC_ROOT_URI, "myfile.md") - - -@pytest_lsp.fixture( - config=pytest_lsp.ClientServerConfig(server_command=[sys.executable, "-m", "esbonio"], root_uri=TEST_DOC_ROOT_URI), -) -async def client(): - pass - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_goto_definition_support_for_myst(client): - # Check Goto Defintion support for MySt/Markdown file, e.g. myfile.md - goto_md = await client.definition_request(uri=TEST_MD_FILE_URI, position=Position(line=19, character=8)) - goto_md_location = goto_md[0] - - assert goto_md_location.range - assert type(goto_md_location.range) == Range - - # check defintion location range, e.g. location of SPEC_2 - assert goto_md_location.range.start.line == 12 - assert goto_md_location.range.start.character == 0 - assert goto_md_location.range.end.line == 12 - assert goto_md_location.range.end.character == 0 - - # Check Goto defintion jump location in another markdown file, e.g. md_subfolder/MySecond.md - goto_md_subfolder = await client.definition_request(uri=TEST_MD_FILE_URI, position=Position(line=21, character=8)) - goto_md_subfolder_location = goto_md_subfolder[0] - - assert goto_md_subfolder_location.range - assert type(goto_md_subfolder_location.range) == Range - - # check defintion location range, e.g. location of REQ_3 - assert goto_md_subfolder_location.uri.endswith("MySecond.md") - assert goto_md_subfolder_location.range.start.line == 2 - assert goto_md_subfolder_location.range.start.character == 0 - assert goto_md_subfolder_location.range.end.line == 2 - assert goto_md_subfolder_location.range.end.character == 0 - - # Check Goto definition jump location in another rst file, e.g. index.rst - goto_rst = await client.definition_request(uri=TEST_MD_FILE_URI, position=Position(line=23, character=8)) - goto_rst_location = goto_rst[0] - - assert goto_rst_location.range - assert type(goto_rst_location.range) == Range - - # check defintion location range, e.g. location of REQ_1 - assert goto_rst_location.uri.endswith("index.rst") - assert goto_rst_location.range.start.line == 10 - assert goto_rst_location.range.start.character == 0 - assert goto_rst_location.range.end.line == 10 - assert goto_rst_location.range.end.character == 0 - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_hover_support_for_myst(client): - # Check Hover support for MyST/Markdown file - hover_directive_result = await client.hover_request(uri=TEST_MD_FILE_URI, position=Position(line=6, character=9)) - assert type(hover_directive_result.contents) == MarkupContent - assert type(hover_directive_result.contents.kind) == MarkupKind - assert hover_directive_result.contents.kind == "markdown" # MarkupKind.Markdown - assert hover_directive_result.contents.value == "**MD REQ Title**\n\n```\nsome stuff from md req.\n```" - - # Check Hover support for need in another markdown file, e.g. REQ_3 - hover_directive_another_file = await client.hover_request( - uri=TEST_MD_FILE_URI, position=Position(line=21, character=8) - ) - assert type(hover_directive_another_file.contents) == MarkupContent - assert type(hover_directive_another_file.contents.kind) == MarkupKind - assert hover_directive_another_file.contents.kind == "markdown" # MarkupKind.Markdown - assert ( - hover_directive_another_file.contents.value - == "\n**Sub MD Req title**\n\n```\nMD in Subfolder with some req content.\n```" - ) - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_id_selection_completion_support_for_myst(client): - # Check ID selection completion support for MyST/Markdown file - # 1. for rst/Sphinx style: :need:`->` - # 2. for MyST/Markdown style: {need}`->` - - # check need type suggestion for :need:`->` - need_type_rst = await client.completion_request(uri=TEST_MD_FILE_URI, line=25, character=9) - assert len(need_type_rst.items) == 2 - assert need_type_rst.items[0].label == "req" - assert need_type_rst.items[0].detail == "need type" - assert need_type_rst.items[1].label == "spec" - assert need_type_rst.items[1].detail == "need type" - - # check need file path suggestion for :need:`->req>` - need_file_path_rst = await client.completion_request(uri=TEST_MD_FILE_URI, line=27, character=13) - assert len(need_file_path_rst.items) == 3 - - need_file_path_rst_option_1 = need_file_path_rst.items[0] - assert need_file_path_rst_option_1.label == "index.rst" - assert need_file_path_rst_option_1.detail == "path to needs doc" - assert need_file_path_rst_option_1.kind == 17 # CompletionItemKind.File - assert need_file_path_rst_option_1.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - need_file_path_rst_option_2 = need_file_path_rst.items[1] - assert need_file_path_rst_option_2.label == "md_subfolder" - assert need_file_path_rst_option_2.kind == 19 # CompletionItemKind.Folder - - need_file_path_rst_option_3 = need_file_path_rst.items[2] - assert need_file_path_rst_option_3.label == "myfile.md" - assert need_file_path_rst_option_3.kind == 17 # CompletionItemKind.File - - # check need file path suggestion containing subfolder for :need:`->req>md_subfolder/` - need_file_path_subfolder_rst = await client.completion_request(uri=TEST_MD_FILE_URI, line=31, character=26) - assert len(need_file_path_subfolder_rst.items) == 1 - assert need_file_path_subfolder_rst.items[0].label == "MySecond.md" - assert need_file_path_subfolder_rst.items[0].detail == "needs doc" - assert need_file_path_subfolder_rst.items[0].insert_text == "MySecond.md" - assert need_file_path_subfolder_rst.items[0].kind == 17 # CompletionItemKind.File - - # check need ID suggestion for :need:`->req>md_subfolder/MySecond.md>` - need_id_rst = await client.completion_request(uri=TEST_MD_FILE_URI, line=33, character=38) - assert len(need_id_rst.items) == 1 - assert need_id_rst.items[0].label == "REQ_3" - assert need_id_rst.items[0].insert_text == "REQ_3" - assert need_id_rst.items[0].detail == "Sub MD Req title" - assert need_id_rst.items[0].documentation == "MD in Subfolder with some req content." - - # check need type suggestion for {need}`->` - need_type_md = await client.completion_request(uri=TEST_MD_FILE_URI, line=35, character=9) - assert len(need_type_md.items) == 2 - assert need_type_md.items[0].label == "req" - assert need_type_md.items[0].detail == "need type" - assert need_type_md.items[1].label == "spec" - assert need_type_md.items[1].detail == "need type" - - # check need file path suggestion for {need}`->req>` - need_file_path_md = await client.completion_request(uri=TEST_MD_FILE_URI, line=37, character=13) - assert len(need_file_path_md.items) == 3 - - need_file_path_md_option_1 = need_file_path_md.items[0] - assert need_file_path_md_option_1.label == "index.rst" - assert need_file_path_md_option_1.detail == "path to needs doc" - assert need_file_path_md_option_1.kind == 17 # CompletionItemKind.File - assert need_file_path_md_option_1.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - need_file_path_md_option_2 = need_file_path_md.items[1] - assert need_file_path_md_option_2.label == "md_subfolder" - assert need_file_path_md_option_2.kind == 19 # CompletionItemKind.Folder - - need_file_path_md_option_3 = need_file_path_md.items[2] - assert need_file_path_md_option_3.label == "myfile.md" - assert need_file_path_md_option_3.kind == 17 # CompletionItemKind.File - - # check need ID suggestion for :need:`->req>myfile.md>` - need_id_md = await client.completion_request(uri=TEST_MD_FILE_URI, line=29, character=23) - assert len(need_id_md.items) == 1 - need_id_md_result = need_id_md.items[0] - assert need_id_md_result.label == "REQ_2" - assert need_id_md_result.insert_text == "REQ_2" - assert need_id_md_result.detail == "MD REQ Title" - assert need_id_md_result.documentation == "some stuff from md req." - assert need_id_md_result.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_need_directive_snippets_completion_for_myst(client): - # Check need directive snippets support for MyST/Markdown - needs_directive_snippets_suggestion = await client.completion_request(uri=TEST_MD_FILE_URI, line=47, character=2) - assert needs_directive_snippets_suggestion.items - - req_md_idx = None - spec_md_idx = None - for index, item in enumerate(needs_directive_snippets_suggestion.items): - if item.label == "md:.. req::": - req_md_idx = index - elif item.label == "md:.. spec::": - spec_md_idx = index - - assert req_md_idx is not None - needs_directive_req_md = needs_directive_snippets_suggestion.items[req_md_idx] - assert needs_directive_req_md.label == "md:.. req::" - assert needs_directive_req_md.detail == "Markdown directive snippet" - assert needs_directive_req_md.insert_text.startswith("```{req} ${1:title}\n:id: ${2:REQ_") - assert needs_directive_req_md.insert_text.endswith("}\n:status: open\n\n${3:content}.\n```$0") - assert needs_directive_req_md.insert_text_format == 2 # InsertTextFormat.Snippet - assert needs_directive_req_md.kind == 15 # CompletionItemKind.Snippet - assert needs_directive_req_md.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - assert spec_md_idx is not None - needs_directive_spec_md = needs_directive_snippets_suggestion.items[spec_md_idx] - assert needs_directive_spec_md.label == "md:.. spec::" - assert needs_directive_spec_md.detail == "Markdown directive snippet" - assert needs_directive_spec_md.insert_text.startswith("```{spec} ${1:title}\n:id: ${2:SPEC_") - assert needs_directive_spec_md.insert_text.endswith("}\n:status: open\n\n${3:content}.\n```$0") - assert needs_directive_spec_md.insert_text_format == 2 # InsertTextFormat.Snippet - assert needs_directive_spec_md.kind == 15 # CompletionItemKind.Snippet - assert needs_directive_spec_md.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - # check need directive snippets inside block {eval-rst} - needs_directive_snippets_inside_eval_rst_suggestion = await client.completion_request( - uri=TEST_MD_FILE_URI, line=5, character=2 - ) - assert needs_directive_snippets_inside_eval_rst_suggestion.items - - req_md_in_eval_rst_idx = None - spec_md_in_eval_rst_idx = None - for index, item in enumerate(needs_directive_snippets_inside_eval_rst_suggestion.items): - if item.label == ".. req::": - req_md_in_eval_rst_idx = index - elif item.label == ".. spec::": - spec_md_in_eval_rst_idx = index - - assert req_md_in_eval_rst_idx is not None - needs_directive_req_md_inside_eval_rst = needs_directive_snippets_inside_eval_rst_suggestion.items[ - req_md_in_eval_rst_idx - ] - assert needs_directive_req_md_inside_eval_rst.label == ".. req::" - assert needs_directive_req_md_inside_eval_rst.detail == "Requirement" - assert needs_directive_req_md_inside_eval_rst.insert_text.startswith(" req:: ${1:title}\n\t:id: ${2:REQ_") - assert needs_directive_req_md_inside_eval_rst.insert_text.endswith("}\n\t:status: open\n\n\t${3:content}.\n$0") - assert needs_directive_req_md_inside_eval_rst.insert_text_format == 2 # InsertTextFormat.Snippet - assert needs_directive_req_md_inside_eval_rst.kind == 15 # CompletionItemKind.Snippet - assert needs_directive_req_md_inside_eval_rst.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - assert spec_md_in_eval_rst_idx is not None - needs_directive_spec_md_inside_eval_rst = needs_directive_snippets_inside_eval_rst_suggestion.items[ - spec_md_in_eval_rst_idx - ] - assert needs_directive_spec_md_inside_eval_rst.label == ".. spec::" - assert needs_directive_spec_md_inside_eval_rst.detail == "Specification" - assert needs_directive_spec_md_inside_eval_rst.insert_text.startswith(" spec:: ${1:title}\n\t:id: ${2:SPEC_") - assert needs_directive_spec_md_inside_eval_rst.insert_text.endswith("}\n\t:status: open\n\n\t${3:content}.\n$0") - assert needs_directive_spec_md_inside_eval_rst.insert_text_format == 2 # InsertTextFormat.Snippet - assert needs_directive_spec_md_inside_eval_rst.kind == 15 # CompletionItemKind.Snippet - assert needs_directive_spec_md_inside_eval_rst.data["source_feature"] == "sphinx_needs.lsp.esbonio.NeedlsFeatures" - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_needs_option_id_completion_for_myst(client): - # Needs option id suggestion is the same for MyST/Markdown as for rst/Sphinx file, e.g. :id: - needs_option_suggestion = await client.completion_request(uri=TEST_MD_FILE_URI, line=13, character=1) - assert needs_option_suggestion.items - - option_id_idx = None - for index, item in enumerate(needs_option_suggestion.items): - if item.label == ":id:": - option_id_idx = index - - assert option_id_idx is not None - needs_option_id = needs_option_suggestion.items[option_id_idx] - assert needs_option_id.label == ":id:" - assert needs_option_id.detail == "needs option" - assert needs_option_id.insert_text.startswith("id: ${1:SPEC_") - assert needs_option_id.insert_text.endswith("}\n$0") - assert needs_option_id.insert_text_format == 2 # InsertTextFormat.Snippet - assert needs_option_id.kind == 15 # CompletionItemKind.Snippet - - -@pytest.mark.skipif( - version.parse(__version__) >= version.parse("1.0"), reason="Esbonio version >=0.16.0 using pygls >= 1.0 not tested." -) -@pytest.mark.asyncio -async def test_lsp_need_role_need_completion_for_myst(client): - # Need role need support for MyST/Markdown file - # Same usage like rst file, but will be adapted to MyST/Markdown style, which isinsert {need}`` instead of :need: - need_role_need_suggestion = await client.completion_request(uri=TEST_MD_FILE_URI, line=45, character=1) - assert need_role_need_suggestion.items - - need_role_idx = None - for index, item in enumerate(need_role_need_suggestion.items): - if item.label == "md::need:": - need_role_idx = index - - assert need_role_idx is not None - need_role_need = need_role_need_suggestion.items[need_role_idx] - assert need_role_need.label == "md::need:" - assert need_role_need.detail == "Markdown need role" - assert need_role_need.insert_text == "{need}`${1:ID}`$0" - assert need_role_need.insert_text_format == 2 # InsertTextFormat.Snippet - assert need_role_need.kind == 15 # CompletionItemKind.Snippet