Compare commits
73 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
981150e308 | ||
|
|
6de2cc3867 | ||
|
|
1fefcb4cba | ||
|
|
f0cfa8b13f | ||
|
|
722dae419e | ||
|
|
6a3140f105 | ||
|
|
4dec2f5afa | ||
|
|
9f7754f0e6 | ||
|
|
9630b96935 | ||
|
|
76e34ae628 | ||
|
|
cbb6bdd1ae | ||
|
|
a5af5b505f | ||
|
|
4d120a6a98 | ||
|
|
6e839f7675 | ||
|
|
cade1e2c45 | ||
|
|
d16d3b24ef | ||
|
|
4be7657edb | ||
|
|
040f0b9f0c | ||
|
|
ef2c31c6a3 | ||
|
|
87879ee5df | ||
|
|
01b1fac73e | ||
|
|
5550cb259c | ||
|
|
466c5b7bcc | ||
|
|
0ec120f391 | ||
|
|
5d916b6989 | ||
|
|
1c606ee8a8 | ||
|
|
cdb62adce3 | ||
|
|
6ac3b1d17f | ||
|
|
ce2c3a21db | ||
|
|
3697fae2d3 | ||
|
|
48d5980a36 | ||
|
|
e07b3242c8 | ||
|
|
2d36887b26 | ||
|
|
67aced6544 | ||
|
|
3c171b9e25 | ||
|
|
c8c284e061 | ||
|
|
6bf08e0f14 | ||
|
|
40d93525d9 | ||
|
|
f8136d6dbc | ||
|
|
5af6555d3c | ||
|
|
310c449250 | ||
|
|
bd4f357e59 | ||
|
|
02ae7c4a7c | ||
|
|
6e03b145ba | ||
|
|
b3123db464 | ||
|
|
7d85c2c8dd | ||
|
|
b08dc91e53 | ||
|
|
894b38d55d | ||
|
|
cc9877adbe | ||
|
|
66af586b2a | ||
|
|
c870e3d512 | ||
|
|
9e6fc1a277 | ||
|
|
79864d24ee | ||
|
|
6f93218462 | ||
|
|
600659fe81 | ||
|
|
af59e9b3f6 | ||
|
|
39aa03cd55 | ||
|
|
8d5c6b588c | ||
|
|
b2d8e66ef1 | ||
|
|
4624bdf4e8 | ||
|
|
6628dfe5d0 | ||
|
|
e73b0bab0f | ||
|
|
06f7a4669d | ||
|
|
1a8267bb74 | ||
|
|
9670ecfb59 | ||
|
|
3b8c225d06 | ||
|
|
ff727b7793 | ||
|
|
1ac3bf421d | ||
|
|
7919cf5025 | ||
|
|
b4dd6c840d | ||
|
|
0021c07b56 | ||
|
|
5e2736a710 | ||
|
|
f89f0d6b56 |
12
.editorconfig
Normal file
12
.editorconfig
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
insert_final_newline = true
|
||||||
|
end_of_line = lf
|
||||||
|
|
||||||
|
[*.{yml,yaml}]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
poetry.lock linguist-generated=true
|
||||||
42
.github/workflows/tests.yml
vendored
42
.github/workflows/tests.yml
vendored
@@ -1,35 +1,45 @@
|
|||||||
name: Tests
|
name: Tests
|
||||||
|
|
||||||
on: [push]
|
on: [pull_request]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
env:
|
|
||||||
CMAKE_VERSION: 3.14.7
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-18.04]
|
python: ["3.7", "3.8", "3.9", "3.10"]
|
||||||
python: [3.6, 3.7, 3.8]
|
os: [ubuntu-18.04, windows-2019]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
- name: Cache .tox
|
|
||||||
uses: actions/cache@v1
|
|
||||||
with:
|
|
||||||
path: .tox
|
|
||||||
key: ${{ runner.OS }}-tox-${{ hashFiles('poetry.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.OS }}-tox-
|
|
||||||
- name: Set up Python ${{ matrix.python }}
|
- name: Set up Python ${{ matrix.python }}
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python }}
|
python-version: ${{ matrix.python }}
|
||||||
|
- name: Setup VC
|
||||||
|
uses: ilammy/msvc-dev-cmd@v1
|
||||||
|
if: contains(matrix.os, 'windows')
|
||||||
|
- name: Install CMake
|
||||||
|
if: contains(matrix.os, 'ubuntu')
|
||||||
|
run: |
|
||||||
|
CMAKE_VERSION=3.17.3
|
||||||
|
curl -sSL https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.tar.gz | tar xz
|
||||||
|
sudo cp -rT cmake-$CMAKE_VERSION-Linux-x86_64 /usr/local
|
||||||
|
rm -rf cmake-$CMAKE_VERSION-Linux-x86_64
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
curl -sSL https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-Linux-x86_64.tar.gz | tar xz
|
cmake --version
|
||||||
python -m pip install --upgrade setuptools pip wheel
|
python -m pip install --upgrade setuptools pip wheel
|
||||||
python -m pip install poetry tox-gh-actions
|
python -m pip install poetry tox-gh-actions
|
||||||
- name: Test with tox
|
- name: Test with tox
|
||||||
run: |
|
run: |
|
||||||
export PATH=$GITHUB_WORKSPACE/cmake-$CMAKE_VERSION-Linux-x86_64/bin:$PATH
|
|
||||||
tox
|
tox
|
||||||
|
env:
|
||||||
|
os: ${{ matrix.os }}
|
||||||
|
- name: Upload coverage reports to Codecov
|
||||||
|
uses: codecov/codecov-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
|
flags: unittests
|
||||||
|
name: Python ${{ matrix.python }} on ${{ matrix.os }}
|
||||||
|
fail_ci_if_error: false
|
||||||
|
|||||||
129
.gitignore
vendored
129
.gitignore
vendored
@@ -1,133 +1,4 @@
|
|||||||
### https://raw.github.com/github/gitignore/cb0c6ef7ac68f2300409ee85501d9ad432cb4c7e/Python.gitignore
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.py[cod]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
pip-wheel-metadata/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
.tox/
|
||||||
.nox/
|
|
||||||
.coverage
|
.coverage
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
coverage.xml
|
||||||
*.cover
|
|
||||||
*.py,cover
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
.python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
#Pipfile.lock
|
|
||||||
|
|
||||||
# pyflow
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
[style]
|
|
||||||
based_on_style = pep8
|
|
||||||
43
README.md
43
README.md
@@ -1,5 +1,9 @@
|
|||||||
# cmake-language-server
|
# cmake-language-server
|
||||||
|
[](https://pypi.org/project/cmake-language-server)
|
||||||
|
[](https://aur.archlinux.org/packages/cmake-language-server/)
|
||||||
[](https://github.com/regen100/cmake-language-server/actions)
|
[](https://github.com/regen100/cmake-language-server/actions)
|
||||||
|
[](https://codecov.io/gh/regen100/cmake-language-server)
|
||||||
|
[](https://github.com/regen100/cmake-language-server/blob/master/LICENSE)
|
||||||
|
|
||||||
CMake LSP Implementation.
|
CMake LSP Implementation.
|
||||||
|
|
||||||
@@ -8,21 +12,26 @@ Alpha Stage, work in progress.
|
|||||||
## Features
|
## Features
|
||||||
- [x] Builtin command completion
|
- [x] Builtin command completion
|
||||||
- [x] Documentation for commands and variables on hover
|
- [x] Documentation for commands and variables on hover
|
||||||
- [x] Formatting
|
- [x] Formatting (by [`cmake-format`](https://github.com/cheshirekow/cmake_format))
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
|
|
||||||
- cmake-language-server: LSP server
|
- `cmake-language-server`: LSP server
|
||||||
- cmake-format: CLI frontend for formatting
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Clients
|
```bash
|
||||||
|
$ pip install cmake-language-server
|
||||||
|
```
|
||||||
|
|
||||||
- Neovim ([neoclide/coc.nvim][coc.nvim])
|
### Tested Clients
|
||||||
|
|
||||||
|
- Neovim ([neoclide/coc.nvim][coc.nvim], [prabirshrestha/vim-lsp][vim-lsp])
|
||||||
|
|
||||||
#### Neovim
|
#### Neovim
|
||||||
|
|
||||||
|
##### coc.nvim
|
||||||
|
|
||||||
```jsonc
|
```jsonc
|
||||||
"languageserver": {
|
"languageserver": {
|
||||||
"cmake": {
|
"cmake": {
|
||||||
@@ -38,5 +47,29 @@ Alpha Stage, work in progress.
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### vim-lsp
|
||||||
|
|
||||||
|
```vim
|
||||||
|
if executable('cmake-language-server')
|
||||||
|
au User lsp_setup call lsp#register_server({
|
||||||
|
\ 'name': 'cmake',
|
||||||
|
\ 'cmd': {server_info->['cmake-language-server']},
|
||||||
|
\ 'root_uri': {server_info->lsp#utils#path_to_uri(lsp#utils#find_nearest_parent_file_directory(lsp#utils#get_buffer_path(), 'build/'))},
|
||||||
|
\ 'whitelist': ['cmake'],
|
||||||
|
\ 'initialization_options': {
|
||||||
|
\ 'buildDirectory': 'build',
|
||||||
|
\ }
|
||||||
|
\})
|
||||||
|
endif
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
* `buildDirectory`
|
||||||
|
This language server uses CMake's file API to get cached variables.
|
||||||
|
The API communicates using `<buildDirectory>/.cmake/api/`.
|
||||||
|
`buildDirectory` is relative path to the root uri of the workspace.
|
||||||
|
To configure the build tree, you need to run the cmake command such as `cmake .. -DFOO=bar`.
|
||||||
|
|
||||||
|
|
||||||
[coc.nvim]: https://github.com/neoclide/coc.nvim
|
[coc.nvim]: https://github.com/neoclide/coc.nvim
|
||||||
|
[vim-lsp]: https://github.com/prabirshrestha/vim-lsp
|
||||||
|
|||||||
7
codecov.yml
Normal file
7
codecov.yml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
threshold: 10%
|
||||||
|
patch:
|
||||||
|
default: off
|
||||||
6
mypy.ini
6
mypy.ini
@@ -1,6 +0,0 @@
|
|||||||
[mypy]
|
|
||||||
ignore_missing_imports = True
|
|
||||||
allow_redefinition = True
|
|
||||||
|
|
||||||
[mypy-re.Scanner]
|
|
||||||
ignore_errors = True
|
|
||||||
598
poetry.lock
generated
598
poetry.lock
generated
@@ -1,346 +1,424 @@
|
|||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "Atomic file writes."
|
|
||||||
name = "atomicwrites"
|
name = "atomicwrites"
|
||||||
|
version = "1.4.0"
|
||||||
|
description = "Atomic file writes."
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
version = "1.3.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "Classes Without Boilerplate"
|
|
||||||
name = "attrs"
|
name = "attrs"
|
||||||
|
version = "21.4.0"
|
||||||
|
description = "Classes Without Boilerplate"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
version = "19.3.0"
|
|
||||||
|
[package.extras]
|
||||||
|
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
|
||||||
|
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||||
|
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||||
|
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
name = "cmakelang"
|
||||||
|
version = "0.6.13"
|
||||||
|
description = "Language tools for cmake (format, lint, etc)"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Cross-platform colored terminal text."
|
|
||||||
marker = "sys_platform == \"win32\""
|
|
||||||
name = "colorama"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "0.4.1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Discover and load entry points from installed packages."
|
|
||||||
name = "entrypoints"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7"
|
|
||||||
version = "0.3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "A platform independent file lock."
|
|
||||||
name = "filelock"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "3.0.12"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "the modular source code checker: pep8, pyflakes and co"
|
|
||||||
name = "flake8"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "3.7.8"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
entrypoints = ">=0.3.0,<0.4.0"
|
six = ">=1.13.0"
|
||||||
mccabe = ">=0.6.0,<0.7.0"
|
|
||||||
pycodestyle = ">=2.5.0,<2.6.0"
|
[package.extras]
|
||||||
pyflakes = ">=2.1.0,<2.2.0"
|
yaml = ["pyyaml (>=5.3)"]
|
||||||
|
html-gen = ["jinja2 (==2.10.3)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.4"
|
||||||
|
description = "Cross-platform colored terminal text."
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Read metadata from Python packages"
|
optional = false
|
||||||
marker = "python_version < \"3.8\""
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coverage"
|
||||||
|
version = "6.2"
|
||||||
|
description = "Code coverage measurement for Python"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
toml = ["tomli"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
name = "importlib-metadata"
|
name = "importlib-metadata"
|
||||||
|
version = "4.8.3"
|
||||||
|
description = "Read metadata from Python packages"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7,!=3.0,!=3.1,!=3.2,!=3.3"
|
python-versions = ">=3.6"
|
||||||
version = "0.23"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
|
typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
||||||
zipp = ">=0.5"
|
zipp = ">=0.5"
|
||||||
|
|
||||||
[[package]]
|
[package.extras]
|
||||||
category = "dev"
|
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||||
description = "A Python utility / library to sort Python imports."
|
perf = ["ipython"]
|
||||||
name = "isort"
|
testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "4.3.21"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
name = "iniconfig"
|
||||||
|
version = "1.1.1"
|
||||||
|
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "McCabe checker, plugin for flake8"
|
|
||||||
name = "mccabe"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = "*"
|
||||||
version = "0.6.1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "More routines for operating on iterables, beyond itertools"
|
|
||||||
name = "more-itertools"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.4"
|
|
||||||
version = "7.2.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Optional static typing for Python"
|
|
||||||
name = "mypy"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "0.740"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
mypy-extensions = ">=0.4.0,<0.5.0"
|
|
||||||
typed-ast = ">=1.4.0,<1.5.0"
|
|
||||||
typing-extensions = ">=3.7.4"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
|
||||||
name = "mypy-extensions"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.4.3"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Core utilities for Python packages"
|
|
||||||
name = "packaging"
|
name = "packaging"
|
||||||
|
version = "21.3"
|
||||||
|
description = "Core utilities for Python packages"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=3.6"
|
||||||
version = "19.2"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pyparsing = ">=2.0.2"
|
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||||
six = "*"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "plugin and hook calling mechanisms for python"
|
|
||||||
name = "pluggy"
|
name = "pluggy"
|
||||||
|
version = "1.0.0"
|
||||||
|
description = "plugin and hook calling mechanisms for python"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=3.6"
|
||||||
version = "0.13.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
[package.dependencies.importlib-metadata]
|
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||||
python = "<3.8"
|
|
||||||
version = ">=0.12"
|
[package.extras]
|
||||||
|
dev = ["pre-commit", "tox"]
|
||||||
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
|
||||||
name = "py"
|
name = "py"
|
||||||
optional = false
|
version = "1.11.0"
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||||
version = "1.8.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "Python style guide checker"
|
|
||||||
name = "pycodestyle"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
version = "2.5.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "passive checker of Python programs"
|
|
||||||
name = "pyflakes"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
|
||||||
version = "2.1.1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
name = "pydantic"
|
||||||
|
version = "1.9.1"
|
||||||
|
description = "Data validation and settings management using python type hints"
|
||||||
category = "main"
|
category = "main"
|
||||||
description = "a pythonic generic language server (pronounced like \"pie glass\")."
|
|
||||||
name = "pygls"
|
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.6.1"
|
||||||
version = "0.8.1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "main"
|
|
||||||
description = "Python parsing module"
|
|
||||||
name = "pyparsing"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
|
||||||
version = "2.4.2"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "pytest: simple powerful testing with Python"
|
|
||||||
name = "pytest"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
version = "5.2.1"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
atomicwrites = ">=1.0"
|
typing-extensions = ">=3.7.4.3"
|
||||||
attrs = ">=17.4.0"
|
|
||||||
colorama = "*"
|
|
||||||
more-itertools = ">=4.0.0"
|
|
||||||
packaging = "*"
|
|
||||||
pluggy = ">=0.12,<1.0"
|
|
||||||
py = ">=1.5.0"
|
|
||||||
wcwidth = "*"
|
|
||||||
|
|
||||||
[package.dependencies.importlib-metadata]
|
[package.extras]
|
||||||
python = "<3.8"
|
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||||
version = ">=0.12"
|
email = ["email-validator (>=1.0.3)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
name = "pygls"
|
||||||
|
version = "0.12"
|
||||||
|
description = "a pythonic generic language server (pronounced like \"pie glass\")."
|
||||||
|
category = "main"
|
||||||
|
optional = false
|
||||||
|
python-versions = "<3.11,>=3.7"
|
||||||
|
|
||||||
|
[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 = "pyparsing"
|
||||||
|
version = "3.0.7"
|
||||||
|
description = "Python parsing module"
|
||||||
category = "dev"
|
category = "dev"
|
||||||
description = "pytest plugin for test data directories and files"
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
diagrams = ["jinja2", "railroad-diagrams"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest"
|
||||||
|
version = "6.2.5"
|
||||||
|
description = "pytest: simple powerful testing with Python"
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=3.6"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
|
||||||
|
attrs = ">=19.2.0"
|
||||||
|
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||||
|
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||||
|
iniconfig = "*"
|
||||||
|
packaging = "*"
|
||||||
|
pluggy = ">=0.12,<2.0"
|
||||||
|
py = ">=1.8.2"
|
||||||
|
toml = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pytest-cov"
|
||||||
|
version = "2.12.1"
|
||||||
|
description = "Pytest plugin for measuring coverage."
|
||||||
|
category = "dev"
|
||||||
|
optional = false
|
||||||
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||||
|
|
||||||
|
[package.dependencies]
|
||||||
|
coverage = ">=5.2.1"
|
||||||
|
pytest = ">=4.6"
|
||||||
|
toml = "*"
|
||||||
|
|
||||||
|
[package.extras]
|
||||||
|
testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
name = "pytest-datadir"
|
name = "pytest-datadir"
|
||||||
|
version = "1.3.1"
|
||||||
|
description = "pytest plugin for test data directories and files"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||||
version = "1.3.1"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.dependencies]
|
||||||
pytest = ">=2.7.0"
|
pytest = ">=2.7.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "Python 2 and 3 compatibility utilities"
|
|
||||||
name = "six"
|
name = "six"
|
||||||
|
version = "1.16.0"
|
||||||
|
description = "Python 2 and 3 compatibility utilities"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
|
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
version = "1.12.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
|
||||||
name = "toml"
|
name = "toml"
|
||||||
|
version = "0.10.2"
|
||||||
|
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||||
|
category = "dev"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||||
version = "0.10.0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
name = "typeguard"
|
||||||
description = "tox is a generic virtualenv management and test command line tool"
|
version = "2.13.3"
|
||||||
name = "tox"
|
description = "Run-time type checker for Python"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
python-versions = ">=3.5.3"
|
||||||
version = "3.14.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.extras]
|
||||||
filelock = ">=3.0.0,<4"
|
doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
|
||||||
packaging = ">=14"
|
test = ["pytest", "typing-extensions", "mypy"]
|
||||||
pluggy = ">=0.12.0,<1"
|
|
||||||
py = ">=1.4.17,<2"
|
|
||||||
six = ">=1.0.0,<2"
|
|
||||||
toml = ">=0.9.4"
|
|
||||||
virtualenv = ">=14.0.0"
|
|
||||||
|
|
||||||
[package.dependencies.importlib-metadata]
|
|
||||||
python = "<3.8"
|
|
||||||
version = ">=0.12,<1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
|
||||||
name = "typed-ast"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "1.4.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Type Hints for Python"
|
|
||||||
name = "typing"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "3.7.4.1"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.5+"
|
|
||||||
name = "typing-extensions"
|
name = "typing-extensions"
|
||||||
|
version = "4.1.1"
|
||||||
|
description = "Backported and Experimental Type Hints for Python 3.6+"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = "*"
|
python-versions = ">=3.6"
|
||||||
version = "3.7.4"
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
typing = ">=3.7.4"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
category = "dev"
|
|
||||||
description = "Virtual Python Environment builder"
|
|
||||||
name = "virtualenv"
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
|
|
||||||
version = "16.7.7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Measures number of Terminal column cells of wide-character codes"
|
|
||||||
name = "wcwidth"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.1.7"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "A formatter for Python code."
|
|
||||||
name = "yapf"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
version = "0.28.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
category = "dev"
|
|
||||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
|
||||||
marker = "python_version < \"3.8\""
|
|
||||||
name = "zipp"
|
name = "zipp"
|
||||||
|
version = "3.6.0"
|
||||||
|
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||||
|
category = "main"
|
||||||
optional = false
|
optional = false
|
||||||
python-versions = ">=2.7"
|
python-versions = ">=3.6"
|
||||||
version = "0.6.0"
|
|
||||||
|
|
||||||
[package.dependencies]
|
[package.extras]
|
||||||
more-itertools = "*"
|
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||||
|
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
content-hash = "2fa2f64a1c51f6312594f611baa29f434f3a8ede16543988ac0d76a6de587c7f"
|
lock-version = "1.1"
|
||||||
python-versions = "^3.6"
|
python-versions = "^3.7,<3.11"
|
||||||
|
content-hash = "611ecc79e7246a5e3136e80b2b5937ee5a097866faaa2ad251e5143985c267a9"
|
||||||
|
|
||||||
[metadata.hashes]
|
[metadata.files]
|
||||||
atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"]
|
atomicwrites = [
|
||||||
attrs = ["08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"]
|
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
||||||
colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"]
|
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
||||||
entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"]
|
]
|
||||||
filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"]
|
attrs = [
|
||||||
flake8 = ["19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", "8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"]
|
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
|
||||||
importlib-metadata = ["aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", "d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"]
|
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
|
||||||
isort = ["54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", "6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"]
|
]
|
||||||
mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"]
|
cmakelang = [
|
||||||
more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"]
|
{file = "cmakelang-0.6.13-py3-none-any.whl", hash = "sha256:764b9467195c7c36453d60a829f30229720d26c7dffd41cb516b99bd9c7daf4e"},
|
||||||
mypy = ["1521c186a3d200c399bd5573c828ea2db1362af7209b2adb1bb8532cea2fb36f", "31a046ab040a84a0fc38bc93694876398e62bc9f35eca8ccbf6418b7297f4c00", "3b1a411909c84b2ae9b8283b58b48541654b918e8513c20a400bb946aa9111ae", "48c8bc99380575deb39f5d3400ebb6a8a1cb5cc669bbba4d3bb30f904e0a0e7d", "540c9caa57a22d0d5d3c69047cc9dd0094d49782603eb03069821b41f9e970e9", "672e418425d957e276c291930a3921b4a6413204f53fe7c37cad7bc57b9a3391", "6ed3b9b3fdc7193ea7aca6f3c20549b377a56f28769783a8f27191903a54170f", "9371290aa2cad5ad133e4cdc43892778efd13293406f7340b9ffe99d5ec7c1d9", "ace6ac1d0f87d4072f05b5468a084a45b4eda970e4d26704f201e06d47ab2990", "b428f883d2b3fe1d052c630642cc6afddd07d5cd7873da948644508be3b9d4a7", "d5bf0e6ec8ba346a2cf35cb55bf4adfddbc6b6576fcc9e10863daa523e418dbb", "d7574e283f83c08501607586b3167728c58e8442947e027d2d4c7dcd6d82f453", "dc889c84241a857c263a2b1cd1121507db7d5b5f5e87e77147097230f374d10b", "f4748697b349f373002656bf32fede706a0e713d67bfdcf04edf39b1f61d46eb"]
|
{file = "cmakelang-0.6.13.tar.gz", hash = "sha256:03982e87b00654d024d73ef972d9d9bb0e5726cdb6b8a424a15661fb6278e67f"},
|
||||||
mypy-extensions = ["090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", "2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"]
|
]
|
||||||
packaging = ["28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", "d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"]
|
colorama = [
|
||||||
pluggy = ["0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", "fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"]
|
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||||
py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"]
|
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||||
pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"]
|
]
|
||||||
pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"]
|
coverage = [
|
||||||
pygls = ["3ee878a828b7bc0873a2ea44208d6846a91aa7dbbbdc052e7fe8cc689f6644fa", "780fd0c5ae95ad02ecaf70b071e43ff8ced8384b7d6bed19311a7b431d26fb88"]
|
{file = "coverage-6.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6dbc1536e105adda7a6312c778f15aaabe583b0e9a0b0a324990334fd458c94b"},
|
||||||
pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"]
|
{file = "coverage-6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:174cf9b4bef0db2e8244f82059a5a72bd47e1d40e71c68ab055425172b16b7d0"},
|
||||||
pytest = ["7e4800063ccfc306a53c461442526c5571e1462f61583506ce97e4da6a1d88c8", "ca563435f4941d0cb34767301c27bc65c510cb82e90b9ecf9cb52dc2c63caaa0"]
|
{file = "coverage-6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b8c845527eae547a2a6617d336adc56394050c3ed8a6918683646328fbb6da"},
|
||||||
pytest-datadir = ["1847ed0efe0bc54cac40ab3fba6d651c2f03d18dd01f2a582979604d32e7621e", "d3af1e738df87515ee509d6135780f25a15959766d9c2b2dbe02bf4fb979cb18"]
|
{file = "coverage-6.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c7912d1526299cb04c88288e148c6c87c0df600eca76efd99d84396cfe00ef1d"},
|
||||||
six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"]
|
{file = "coverage-6.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5d2033d5db1d58ae2d62f095e1aefb6988af65b4b12cb8987af409587cc0739"},
|
||||||
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"]
|
{file = "coverage-6.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3feac4084291642165c3a0d9eaebedf19ffa505016c4d3db15bfe235718d4971"},
|
||||||
tox = ["0bc216b6a2e6afe764476b4a07edf2c1dab99ed82bb146a1130b2e828f5bff5e", "c4f6b319c20ba4913dbfe71ebfd14ff95d1853c4231493608182f66e566ecfe1"]
|
{file = "coverage-6.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:276651978c94a8c5672ea60a2656e95a3cce2a3f31e9fb2d5ebd4c215d095840"},
|
||||||
typed-ast = ["1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", "18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", "838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"]
|
{file = "coverage-6.2-cp310-cp310-win32.whl", hash = "sha256:f506af4f27def639ba45789fa6fde45f9a217da0be05f8910458e4557eed020c"},
|
||||||
typing = ["91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23", "c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36", "f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"]
|
{file = "coverage-6.2-cp310-cp310-win_amd64.whl", hash = "sha256:3f7c17209eef285c86f819ff04a6d4cbee9b33ef05cbcaae4c0b4e8e06b3ec8f"},
|
||||||
typing-extensions = ["2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", "b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", "d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"]
|
{file = "coverage-6.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:13362889b2d46e8d9f97c421539c97c963e34031ab0cb89e8ca83a10cc71ac76"},
|
||||||
virtualenv = ["11cb4608930d5fd3afb545ecf8db83fa50e1f96fc4fca80c94b07d2c83146589", "d257bb3773e48cac60e475a19b608996c73f4d333b3ba2e4e57d5ac6134e0136"]
|
{file = "coverage-6.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:22e60a3ca5acba37d1d4a2ee66e051f5b0e1b9ac950b5b0cf4aa5366eda41d47"},
|
||||||
wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"]
|
{file = "coverage-6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b637c57fdb8be84e91fac60d9325a66a5981f8086c954ea2772efe28425eaf64"},
|
||||||
yapf = ["02ace10a00fa2e36c7ebd1df2ead91dbfbd7989686dc4ccbdc549e95d19f5780", "6f94b6a176a7c114cfa6bad86d40f259bbe0f10cf2fa7f2f4b3596fc5802a41b"]
|
{file = "coverage-6.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f467bbb837691ab5a8ca359199d3429a11a01e6dfb3d9dcc676dc035ca93c0a9"},
|
||||||
zipp = ["3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", "f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"]
|
{file = "coverage-6.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2641f803ee9f95b1f387f3e8f3bf28d83d9b69a39e9911e5bfee832bea75240d"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1219d760ccfafc03c0822ae2e06e3b1248a8e6d1a70928966bafc6838d3c9e48"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9a2b5b52be0a8626fcbffd7e689781bf8c2ac01613e77feda93d96184949a98e"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:8e2c35a4c1f269704e90888e56f794e2d9c0262fb0c1b1c8c4ee44d9b9e77b5d"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:5d6b09c972ce9200264c35a1d53d43ca55ef61836d9ec60f0d44273a31aa9f17"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:e3db840a4dee542e37e09f30859f1612da90e1c5239a6a2498c473183a50e781"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-win32.whl", hash = "sha256:4e547122ca2d244f7c090fe3f4b5a5861255ff66b7ab6d98f44a0222aaf8671a"},
|
||||||
|
{file = "coverage-6.2-cp36-cp36m-win_amd64.whl", hash = "sha256:01774a2c2c729619760320270e42cd9e797427ecfddd32c2a7b639cdc481f3c0"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb8b8ee99b3fffe4fd86f4c81b35a6bf7e4462cba019997af2fe679365db0c49"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:619346d57c7126ae49ac95b11b0dc8e36c1dd49d148477461bb66c8cf13bb521"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0a7726f74ff63f41e95ed3a89fef002916c828bb5fcae83b505b49d81a066884"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cfd9386c1d6f13b37e05a91a8583e802f8059bebfccde61a418c5808dea6bbfa"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:17e6c11038d4ed6e8af1407d9e89a2904d573be29d51515f14262d7f10ef0a64"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c254b03032d5a06de049ce8bca8338a5185f07fb76600afff3c161e053d88617"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:dca38a21e4423f3edb821292e97cec7ad38086f84313462098568baedf4331f8"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-win32.whl", hash = "sha256:600617008aa82032ddeace2535626d1bc212dfff32b43989539deda63b3f36e4"},
|
||||||
|
{file = "coverage-6.2-cp37-cp37m-win_amd64.whl", hash = "sha256:bf154ba7ee2fd613eb541c2bc03d3d9ac667080a737449d1a3fb342740eb1a74"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f9afb5b746781fc2abce26193d1c817b7eb0e11459510fba65d2bd77fe161d9e"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:edcada2e24ed68f019175c2b2af2a8b481d3d084798b8c20d15d34f5c733fa58"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a9c8c4283e17690ff1a7427123ffb428ad6a52ed720d550e299e8291e33184dc"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f614fc9956d76d8a88a88bb41ddc12709caa755666f580af3a688899721efecd"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9365ed5cce5d0cf2c10afc6add145c5037d3148585b8ae0e77cc1efdd6aa2953"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8bdfe9ff3a4ea37d17f172ac0dff1e1c383aec17a636b9b35906babc9f0f5475"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:63c424e6f5b4ab1cf1e23a43b12f542b0ec2e54f99ec9f11b75382152981df57"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-win32.whl", hash = "sha256:49dbff64961bc9bdd2289a2bda6a3a5a331964ba5497f694e2cbd540d656dc1c"},
|
||||||
|
{file = "coverage-6.2-cp38-cp38-win_amd64.whl", hash = "sha256:9a29311bd6429be317c1f3fe4bc06c4c5ee45e2fa61b2a19d4d1d6111cb94af2"},
|
||||||
|
{file = "coverage-6.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03b20e52b7d31be571c9c06b74746746d4eb82fc260e594dc662ed48145e9efd"},
|
||||||
|
{file = "coverage-6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:215f8afcc02a24c2d9a10d3790b21054b58d71f4b3c6f055d4bb1b15cecce685"},
|
||||||
|
{file = "coverage-6.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:a4bdeb0a52d1d04123b41d90a4390b096f3ef38eee35e11f0b22c2d031222c6c"},
|
||||||
|
{file = "coverage-6.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c332d8f8d448ded473b97fefe4a0983265af21917d8b0cdcb8bb06b2afe632c3"},
|
||||||
|
{file = "coverage-6.2-cp39-cp39-win32.whl", hash = "sha256:6e1394d24d5938e561fbeaa0cd3d356207579c28bd1792f25a068743f2d5b282"},
|
||||||
|
{file = "coverage-6.2-cp39-cp39-win_amd64.whl", hash = "sha256:86f2e78b1eff847609b1ca8050c9e1fa3bd44ce755b2ec30e70f2d3ba3844644"},
|
||||||
|
{file = "coverage-6.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:5829192582c0ec8ca4a2532407bc14c2f338d9878a10442f5d03804a95fac9de"},
|
||||||
|
{file = "coverage-6.2.tar.gz", hash = "sha256:e2cad8093172b7d1595b4ad66f24270808658e11acf43a8f95b41276162eb5b8"},
|
||||||
|
]
|
||||||
|
importlib-metadata = [
|
||||||
|
{file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
|
||||||
|
{file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
|
||||||
|
]
|
||||||
|
iniconfig = [
|
||||||
|
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||||
|
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||||
|
]
|
||||||
|
packaging = [
|
||||||
|
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||||
|
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||||
|
]
|
||||||
|
pluggy = [
|
||||||
|
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||||
|
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||||
|
]
|
||||||
|
py = [
|
||||||
|
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||||
|
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||||
|
]
|
||||||
|
pydantic = [
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8098a724c2784bf03e8070993f6d46aa2eeca031f8d8a048dff277703e6e193"},
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c320c64dd876e45254bdd350f0179da737463eea41c43bacbee9d8c9d1021f11"},
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18f3e912f9ad1bdec27fb06b8198a2ccc32f201e24174cec1b3424dda605a310"},
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c11951b404e08b01b151222a1cb1a9f0a860a8153ce8334149ab9199cd198131"},
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8bc541a405423ce0e51c19f637050acdbdf8feca34150e0d17f675e72d119580"},
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e565a785233c2d03724c4dc55464559639b1ba9ecf091288dd47ad9c629433bd"},
|
||||||
|
{file = "pydantic-1.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a4a88dcd6ff8fd47c18b3a3709a89adb39a6373f4482e04c1b765045c7e282fd"},
|
||||||
|
{file = "pydantic-1.9.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:447d5521575f18e18240906beadc58551e97ec98142266e521c34968c76c8761"},
|
||||||
|
{file = "pydantic-1.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:985ceb5d0a86fcaa61e45781e567a59baa0da292d5ed2e490d612d0de5796918"},
|
||||||
|
{file = "pydantic-1.9.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:059b6c1795170809103a1538255883e1983e5b831faea6558ef873d4955b4a74"},
|
||||||
|
{file = "pydantic-1.9.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:d12f96b5b64bec3f43c8e82b4aab7599d0157f11c798c9f9c528a72b9e0b339a"},
|
||||||
|
{file = "pydantic-1.9.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:ae72f8098acb368d877b210ebe02ba12585e77bd0db78ac04a1ee9b9f5dd2166"},
|
||||||
|
{file = "pydantic-1.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:79b485767c13788ee314669008d01f9ef3bc05db9ea3298f6a50d3ef596a154b"},
|
||||||
|
{file = "pydantic-1.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:494f7c8537f0c02b740c229af4cb47c0d39840b829ecdcfc93d91dcbb0779892"},
|
||||||
|
{file = "pydantic-1.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0f047e11febe5c3198ed346b507e1d010330d56ad615a7e0a89fae604065a0e"},
|
||||||
|
{file = "pydantic-1.9.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:969dd06110cb780da01336b281f53e2e7eb3a482831df441fb65dd30403f4608"},
|
||||||
|
{file = "pydantic-1.9.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:177071dfc0df6248fd22b43036f936cfe2508077a72af0933d0c1fa269b18537"},
|
||||||
|
{file = "pydantic-1.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9bcf8b6e011be08fb729d110f3e22e654a50f8a826b0575c7196616780683380"},
|
||||||
|
{file = "pydantic-1.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a955260d47f03df08acf45689bd163ed9df82c0e0124beb4251b1290fa7ae728"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9ce157d979f742a915b75f792dbd6aa63b8eccaf46a1005ba03aa8a986bde34a"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0bf07cab5b279859c253d26a9194a8906e6f4a210063b84b433cf90a569de0c1"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d93d4e95eacd313d2c765ebe40d49ca9dd2ed90e5b37d0d421c597af830c195"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1542636a39c4892c4f4fa6270696902acb186a9aaeac6f6cf92ce6ae2e88564b"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a9af62e9b5b9bc67b2a195ebc2c2662fdf498a822d62f902bf27cccb52dbbf49"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fe4670cb32ea98ffbf5a1262f14c3e102cccd92b1869df3bb09538158ba90fe6"},
|
||||||
|
{file = "pydantic-1.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:9f659a5ee95c8baa2436d392267988fd0f43eb774e5eb8739252e5a7e9cf07e0"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b83ba3825bc91dfa989d4eed76865e71aea3a6ca1388b59fc801ee04c4d8d0d6"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1dd8fecbad028cd89d04a46688d2fcc14423e8a196d5b0a5c65105664901f810"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02eefd7087268b711a3ff4db528e9916ac9aa18616da7bca69c1871d0b7a091f"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7eb57ba90929bac0b6cc2af2373893d80ac559adda6933e562dcfb375029acee"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4ce9ae9e91f46c344bec3b03d6ee9612802682c1551aaf627ad24045ce090761"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:72ccb318bf0c9ab97fc04c10c37683d9eea952ed526707fabf9ac5ae59b701fd"},
|
||||||
|
{file = "pydantic-1.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:61b6760b08b7c395975d893e0b814a11cf011ebb24f7d869e7118f5a339a82e1"},
|
||||||
|
{file = "pydantic-1.9.1-py3-none-any.whl", hash = "sha256:4988c0f13c42bfa9ddd2fe2f569c9d54646ce84adc5de84228cfe83396f3bd58"},
|
||||||
|
{file = "pydantic-1.9.1.tar.gz", hash = "sha256:1ed987c3ff29fff7fd8c3ea3a3ea877ad310aae2ef9889a119e22d3f2db0691a"},
|
||||||
|
]
|
||||||
|
pygls = [
|
||||||
|
{file = "pygls-0.12-py3-none-any.whl", hash = "sha256:93f8cd9458edb0cb8524588affa0f5fd7f75a4cdb5e2d450437b913e657df65b"},
|
||||||
|
{file = "pygls-0.12.tar.gz", hash = "sha256:452586db4e153f67d3e0505ceb98234e2cf1425c882f089fd458271a721b7809"},
|
||||||
|
]
|
||||||
|
pyparsing = [
|
||||||
|
{file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"},
|
||||||
|
{file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"},
|
||||||
|
]
|
||||||
|
pytest = [
|
||||||
|
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||||
|
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
|
||||||
|
]
|
||||||
|
pytest-cov = [
|
||||||
|
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
|
||||||
|
{file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
|
||||||
|
]
|
||||||
|
pytest-datadir = [
|
||||||
|
{file = "pytest-datadir-1.3.1.tar.gz", hash = "sha256:d3af1e738df87515ee509d6135780f25a15959766d9c2b2dbe02bf4fb979cb18"},
|
||||||
|
{file = "pytest_datadir-1.3.1-py2.py3-none-any.whl", hash = "sha256:1847ed0efe0bc54cac40ab3fba6d651c2f03d18dd01f2a582979604d32e7621e"},
|
||||||
|
]
|
||||||
|
six = [
|
||||||
|
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||||
|
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||||
|
]
|
||||||
|
toml = [
|
||||||
|
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||||
|
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||||
|
]
|
||||||
|
typeguard = [
|
||||||
|
{file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"},
|
||||||
|
{file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"},
|
||||||
|
]
|
||||||
|
typing-extensions = [
|
||||||
|
{file = "typing_extensions-4.1.1-py3-none-any.whl", hash = "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2"},
|
||||||
|
{file = "typing_extensions-4.1.1.tar.gz", hash = "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42"},
|
||||||
|
]
|
||||||
|
zipp = [
|
||||||
|
{file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
|
||||||
|
{file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "cmake-language-server"
|
name = "cmake-language-server"
|
||||||
version = "0.1.0"
|
version = "0.1.6"
|
||||||
description = "CMake LSP Implementation"
|
description = "CMake LSP Implementation"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = ["regen"]
|
authors = ["regen"]
|
||||||
@@ -18,23 +18,34 @@ classifiers = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.6"
|
python = "^3.7,<3.11"
|
||||||
pygls = "^0.8.1"
|
pygls = "^0.12"
|
||||||
pyparsing = "^2.4"
|
importlib-metadata = {version = "^4.8", python = "<3.8"}
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
flake8 = "^3.7"
|
pytest = "^6.2"
|
||||||
mypy = "^0.740.0"
|
|
||||||
pytest = "^5.2"
|
|
||||||
yapf = "^0.28.0"
|
|
||||||
pytest-datadir = "^1.3"
|
pytest-datadir = "^1.3"
|
||||||
tox = "^3.14"
|
pytest-cov = "^2.11"
|
||||||
isort = "^4.3"
|
cmakelang = "^0.6.13"
|
||||||
|
|
||||||
[tool.poetry.scripts]
|
[tool.poetry.scripts]
|
||||||
cmake-format = "cmake_language_server.formatter:main"
|
|
||||||
cmake-language-server = "cmake_language_server.server:main"
|
cmake-language-server = "cmake_language_server.server:main"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry>=0.12"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
build-backend = "poetry.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[tool.pysen]
|
||||||
|
version = "0.10"
|
||||||
|
|
||||||
|
[tool.pysen.lint]
|
||||||
|
enable_black = true
|
||||||
|
enable_flake8 = true
|
||||||
|
enable_isort = true
|
||||||
|
enable_mypy = true
|
||||||
|
mypy_preset = "strict"
|
||||||
|
line_length = 88
|
||||||
|
py_version = "py37"
|
||||||
|
|
||||||
|
[[tool.pysen.lint.mypy_targets]]
|
||||||
|
paths = ["."]
|
||||||
|
|||||||
@@ -1 +1,6 @@
|
|||||||
__version__ = '0.1.0'
|
try:
|
||||||
|
import importlib.metadata as importlib_metadata
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
import importlib_metadata
|
||||||
|
|
||||||
|
__version__ = importlib_metadata.version(__name__)
|
||||||
|
|||||||
@@ -10,13 +10,23 @@ from typing import Dict, List, Optional, Pattern
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _tidy_doc(doc: str) -> str:
|
||||||
|
doc = doc.strip()
|
||||||
|
doc = re.sub(r":.+?:`(.+?)`", r"\1", doc)
|
||||||
|
doc = re.sub(r"``([^`]+)``", r"`\1`", doc)
|
||||||
|
doc = doc.replace("\n", " ")
|
||||||
|
doc = doc.replace(". ", ". ")
|
||||||
|
return doc
|
||||||
|
|
||||||
|
|
||||||
class API(object):
|
class API(object):
|
||||||
_cmake: str
|
_cmake: str
|
||||||
_build: Path
|
_build: Path
|
||||||
_uuid: uuid.UUID
|
_uuid: uuid.UUID
|
||||||
_builtin_commands: Dict[str, str]
|
_builtin_commands: Dict[str, str]
|
||||||
_builtin_variables: Dict[str, str]
|
_builtin_variables: Dict[str, str]
|
||||||
_builtin_variable_template: Dict[Pattern, str]
|
_builtin_variable_template: Dict[Pattern[str], str]
|
||||||
|
_builtin_modules: Dict[str, str]
|
||||||
_targets: List[str]
|
_targets: List[str]
|
||||||
_cached_variables: Dict[str, str]
|
_cached_variables: Dict[str, str]
|
||||||
_generated_list_parsed: bool
|
_generated_list_parsed: bool
|
||||||
@@ -29,86 +39,103 @@ class API(object):
|
|||||||
self._builtin_commands = {}
|
self._builtin_commands = {}
|
||||||
self._builtin_variables = {}
|
self._builtin_variables = {}
|
||||||
self._builtin_variable_template = {}
|
self._builtin_variable_template = {}
|
||||||
|
self._builtin_modules = {}
|
||||||
self._targets = []
|
self._targets = []
|
||||||
self._cached_variables = {}
|
self._cached_variables = {}
|
||||||
self._generated_list_parsed = False
|
self._generated_list_parsed = False
|
||||||
|
|
||||||
def query(self) -> bool:
|
def query(self) -> bool:
|
||||||
|
"""Use CMake's file API to get JSON information about the build tree
|
||||||
|
|
||||||
|
Generates a JSON request file for the current build tree and runs
|
||||||
|
CMake on the build tree. Deletes the request file immediately
|
||||||
|
after.
|
||||||
|
"""
|
||||||
if not self.cmake_cache.exists():
|
if not self.cmake_cache.exists():
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.query_json.parent.mkdir(parents=True, exist_ok=True)
|
self.query_json.parent.mkdir(parents=True, exist_ok=True)
|
||||||
with self.query_json.open('w') as fp:
|
with self.query_json.open("w") as fp:
|
||||||
fp.write('''\
|
fp.write(
|
||||||
|
"""\
|
||||||
{
|
{
|
||||||
"requests": [
|
"requests": [
|
||||||
{"kind": "codemodel", "version": 2},
|
{"kind": "codemodel", "version": 2},
|
||||||
{"kind": "cache", "version": 2},
|
{"kind": "cache", "version": 2},
|
||||||
{"kind": "cmakeFiles", "version": 1}
|
{"kind": "cmakeFiles", "version": 1}
|
||||||
]
|
]
|
||||||
}''')
|
}"""
|
||||||
|
)
|
||||||
|
|
||||||
proc = subprocess.run([self._cmake, self._build],
|
proc = subprocess.run(
|
||||||
universal_newlines=True,
|
[self._cmake, str(self._build)],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE,
|
||||||
|
encoding="utf-8",
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
self.query_json.unlink()
|
self.query_json.unlink()
|
||||||
self.query_json.parent.rmdir()
|
self.query_json.parent.rmdir()
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
logging.error(
|
logging.error(f"cmake exited with {proc.returncode}: {proc.stderr}")
|
||||||
f'cmake exited with {proc.returncode}: {proc.stderr}')
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def read_reply(self) -> bool:
|
def read_reply(self) -> bool:
|
||||||
reply = self._build / '.cmake' / 'api' / 'v1' / 'reply'
|
"""Reads the CMake file API reply file and updates internal state
|
||||||
indices = sorted(reply.glob('index-*.json'))
|
|
||||||
|
Reads the result of the previous query file and updates
|
||||||
|
the targets, the cache entries and the cmake files.
|
||||||
|
"""
|
||||||
|
reply = self._build / ".cmake" / "api" / "v1" / "reply"
|
||||||
|
indices = sorted(reply.glob("index-*.json"))
|
||||||
if not indices:
|
if not indices:
|
||||||
logger.error('no reply')
|
logger.error("no reply")
|
||||||
return False
|
return False
|
||||||
with indices[-1].open() as fp:
|
with indices[-1].open() as fp:
|
||||||
index = json.load(fp)
|
index = json.load(fp)
|
||||||
try:
|
try:
|
||||||
responses = index['reply'][f'client-{self._uuid}']['query.json'][
|
responses = index["reply"][f"client-{self._uuid}"]["query.json"][
|
||||||
'responses']
|
"responses"
|
||||||
|
]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
logger.error('no rensponse')
|
logger.error("no rensponse")
|
||||||
return False
|
return False
|
||||||
for response in responses:
|
for response in responses:
|
||||||
if response['kind'] == 'codemodel':
|
if response["kind"] == "codemodel":
|
||||||
self._read_codemodel(reply / response['jsonFile'])
|
self._read_codemodel(reply / response["jsonFile"])
|
||||||
elif response['kind'] == 'cache':
|
elif response["kind"] == "cache":
|
||||||
self._read_cache(reply / response['jsonFile'])
|
self._read_cache(reply / response["jsonFile"])
|
||||||
elif response['kind'] == 'cmakeFiles':
|
elif response["kind"] == "cmakeFiles":
|
||||||
self._read_cmake_files(reply / response['jsonFile'])
|
self._read_cmake_files(reply / response["jsonFile"])
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _read_codemodel(self, codemodelpath: Path):
|
def _read_codemodel(self, codemodelpath: Path) -> None:
|
||||||
with (codemodelpath).open() as fp:
|
with (codemodelpath).open() as fp:
|
||||||
codemodel = json.load(fp)
|
codemodel = json.load(fp)
|
||||||
config = codemodel['configurations'][0]
|
config = codemodel["configurations"][0]
|
||||||
self._targets[:] = [x['name'] for x in config['targets']]
|
self._targets[:] = [x["name"] for x in config["targets"]]
|
||||||
|
|
||||||
def _read_cache(self, cachepath: Path):
|
def _read_cache(self, cachepath: Path) -> None:
|
||||||
with cachepath.open() as fp:
|
with cachepath.open() as fp:
|
||||||
cache = json.load(fp)
|
cache = json.load(fp)
|
||||||
self._cached_variables.clear()
|
self._cached_variables.clear()
|
||||||
for entry in cache['entries']:
|
for entry in cache["entries"]:
|
||||||
name = entry['name']
|
name = entry["name"]
|
||||||
value = self._truncate_variable(entry['value'])
|
value = self._truncate_variable(entry["value"])
|
||||||
properties = {x['name']: x['value'] for x in entry['properties']}
|
properties = {x["name"]: x["value"] for x in entry["properties"]}
|
||||||
helpstring = properties.get('HELPSTRING', '')
|
helpstring = properties.get("HELPSTRING", "")
|
||||||
doc = []
|
doc = []
|
||||||
if helpstring:
|
if helpstring:
|
||||||
doc.append(helpstring)
|
doc.append(helpstring)
|
||||||
if value:
|
if value:
|
||||||
doc.append(f'`{value}`')
|
doc.append(f"`{value}`")
|
||||||
self._cached_variables[name] = '\n\n'.join(doc)
|
self._cached_variables[name] = "\n\n".join(doc)
|
||||||
|
|
||||||
def _read_cmake_files(self, jsonpath: Path):
|
def _read_cmake_files(self, jsonpath: Path) -> None:
|
||||||
'''inspect generated list files'''
|
"""inspect CMake list files that are used during build generation"""
|
||||||
|
|
||||||
if not self._builtin_variables or self._generated_list_parsed:
|
if not self._builtin_variables or self._generated_list_parsed:
|
||||||
return
|
return
|
||||||
@@ -116,44 +143,48 @@ class API(object):
|
|||||||
with jsonpath.open() as fp:
|
with jsonpath.open() as fp:
|
||||||
cmake_files = json.load(fp)
|
cmake_files = json.load(fp)
|
||||||
|
|
||||||
# inspect generated list files
|
# Inspect generated list files: Get the values of variables in each script
|
||||||
with tempfile.TemporaryDirectory() as tmpdirname:
|
with tempfile.TemporaryDirectory() as tmpdirname:
|
||||||
tmplist = Path(tmpdirname) / 'dump.cmake'
|
tmplist = Path(tmpdirname) / "dump.cmake"
|
||||||
with tmplist.open('w') as fp:
|
with tmplist.open("w") as fp:
|
||||||
for listfile in cmake_files['inputs']:
|
for listfile in cmake_files["inputs"]:
|
||||||
if not listfile.get('isGenerated', False):
|
if not listfile.get("isGenerated", False):
|
||||||
continue
|
continue
|
||||||
path = listfile['path']
|
path = listfile["path"]
|
||||||
fp.write(f'include({path})\n')
|
fp.write(f"include({path})\n")
|
||||||
fp.write('''
|
fp.write(
|
||||||
|
"""
|
||||||
get_cmake_property(variables VARIABLES)
|
get_cmake_property(variables VARIABLES)
|
||||||
foreach (variable ${variables})
|
foreach (variable ${variables})
|
||||||
message("${variable}=${${variable}}")
|
message("${variable}=${${variable}}")
|
||||||
endforeach()
|
endforeach()
|
||||||
''')
|
"""
|
||||||
p = subprocess.run([self._cmake, '-P', tmplist],
|
)
|
||||||
cwd=cmake_files['paths']['source'],
|
p = subprocess.run(
|
||||||
universal_newlines=True,
|
[self._cmake, "-P", str(tmplist)],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE,
|
||||||
|
cwd=cmake_files["paths"]["source"],
|
||||||
|
encoding="utf-8",
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
for line in p.stderr.split('\n'):
|
for line in p.stderr.split("\n"):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
k, v = line.split('=', 1)
|
k, v = line.split("=", 1)
|
||||||
if k.startswith('CMAKE_ARG'):
|
if k.startswith("CMAKE_ARG"):
|
||||||
continue
|
continue
|
||||||
v = self._truncate_variable(v)
|
v = self._truncate_variable(v)
|
||||||
if k in self._builtin_variables:
|
if k in self._builtin_variables:
|
||||||
self._builtin_variables[k] += f'\n\n`{v}`'
|
self._builtin_variables[k] += f"\n\n`{v}`"
|
||||||
else:
|
else:
|
||||||
for pattern, doc in self._builtin_variable_template.items(
|
for pattern, doc in self._builtin_variable_template.items():
|
||||||
):
|
|
||||||
if pattern.fullmatch(k):
|
if pattern.fullmatch(k):
|
||||||
self._builtin_variables[k] = f'{doc}\n\n`{v}`'
|
self._builtin_variables[k] = f"{doc}\n\n`{v}`"
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# ignore variable with no document
|
# ignore variable with no document
|
||||||
@@ -163,72 +194,132 @@ endforeach()
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def query_json(self) -> Path:
|
def query_json(self) -> Path:
|
||||||
return (self._build / '.cmake' / 'api' / 'v1' / 'query' /
|
return (
|
||||||
f'client-{self._uuid}' / 'query.json')
|
self._build
|
||||||
|
/ ".cmake"
|
||||||
|
/ "api"
|
||||||
|
/ "v1"
|
||||||
|
/ "query"
|
||||||
|
/ f"client-{self._uuid}"
|
||||||
|
/ "query.json"
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cmake_cache(self) -> Path:
|
def cmake_cache(self) -> Path:
|
||||||
return self._build / 'CMakeCache.txt'
|
return self._build / "CMakeCache.txt"
|
||||||
|
|
||||||
def parse_doc(self) -> None:
|
def parse_doc(self) -> None:
|
||||||
self._parse_commands()
|
self._parse_commands()
|
||||||
self._parse_variables()
|
self._parse_variables()
|
||||||
|
self._parse_modules()
|
||||||
|
|
||||||
def _parse_commands(self) -> None:
|
def _parse_commands(self) -> None:
|
||||||
p = subprocess.run([self._cmake, '--help-commands'],
|
"""Load docs for builtin cmake functions
|
||||||
|
|
||||||
|
Loads the documentation for builtin cmake functions from the result
|
||||||
|
of `$ cmake --help-commands`.
|
||||||
|
"""
|
||||||
|
p = subprocess.run(
|
||||||
|
[self._cmake, "--help-commands"],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
universal_newlines=True)
|
encoding="utf-8",
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
matches = re.finditer(
|
matches = re.finditer(
|
||||||
r'''
|
r"""
|
||||||
(?P<command>.+)\n
|
(?P<command>.+)\n
|
||||||
-+\n\n
|
-+\n+?
|
||||||
[\s\S]*?
|
[\s\S]*?
|
||||||
(?P<signature>\ (?P=command)\s*\([^)]*\))
|
(?P<signature>(?P=command)\s*\([^)]*\))
|
||||||
''', p.stdout, re.VERBOSE)
|
""",
|
||||||
|
p.stdout,
|
||||||
|
re.VERBOSE,
|
||||||
|
)
|
||||||
self._builtin_commands.clear()
|
self._builtin_commands.clear()
|
||||||
for match in matches:
|
for match in matches:
|
||||||
command = match.group('command')
|
command = match.group("command")
|
||||||
signature = match.group('signature')
|
signature = match.group("signature")
|
||||||
signature = re.sub(r'^ ', r'', signature, flags=re.MULTILINE)
|
signature = re.sub(r"^ ", r"", signature, flags=re.MULTILINE)
|
||||||
self._builtin_commands[
|
self._builtin_commands[command] = "```cmake\n" + signature + "\n```"
|
||||||
command] = '```cmake\n' + signature + '\n```'
|
|
||||||
|
|
||||||
def _parse_variables(self) -> None:
|
def _parse_variables(self) -> None:
|
||||||
p = subprocess.run([self._cmake, '--help-variables'],
|
"""Load docs for builtin cmake variables
|
||||||
|
|
||||||
|
Loads the documentation for builtin cmake variables from
|
||||||
|
the result of `$ cmake --help-variables`.
|
||||||
|
"""
|
||||||
|
p = subprocess.run(
|
||||||
|
[self._cmake, "--help-variables"],
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
universal_newlines=True)
|
encoding="utf-8",
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
|
||||||
if p.returncode != 0:
|
if p.returncode != 0:
|
||||||
return
|
return
|
||||||
|
|
||||||
matches = re.finditer(
|
matches = re.finditer(
|
||||||
r'''
|
r"""
|
||||||
(?P<variable>.+)\n
|
(?P<variable>.+)\n
|
||||||
-+\n\n
|
-+\n\n
|
||||||
(?P<doc>[\s\S]+?)(?:\n\n|$)
|
(?P<doc>[\s\S]+?)(?:\n\n|$)
|
||||||
''', p.stdout, re.VERBOSE)
|
""",
|
||||||
|
p.stdout,
|
||||||
|
re.VERBOSE,
|
||||||
|
)
|
||||||
self._builtin_variables.clear()
|
self._builtin_variables.clear()
|
||||||
for match in matches:
|
for match in matches:
|
||||||
variable = match.group('variable')
|
variable = match.group("variable")
|
||||||
doc = match.group('doc')
|
doc = _tidy_doc(match.group("doc"))
|
||||||
doc = re.sub(r':.+:`(.+)`', r'\1', doc)
|
if variable == "CMAKE_MATCH_<n>":
|
||||||
doc = re.sub(r'``(.+)``', r'`\1`', doc)
|
|
||||||
doc = doc.replace('\n', ' ')
|
|
||||||
doc = doc.replace('. ', '. ')
|
|
||||||
if variable == 'CMAKE_MATCH_<n>':
|
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
self._builtin_variables[f'CMAKE_MATCH_{i}'] = doc
|
self._builtin_variables[f"CMAKE_MATCH_{i}"] = doc
|
||||||
elif '<' in variable:
|
elif "<" in variable:
|
||||||
variable = re.sub(r'<[^>]+>', r'[^_]+', variable)
|
variable = re.sub(r"<[^>]+>", r"[^_]+", variable)
|
||||||
pattern = re.compile(variable)
|
pattern = re.compile(variable)
|
||||||
self._builtin_variable_template[pattern] = doc
|
self._builtin_variable_template[pattern] = doc
|
||||||
else:
|
else:
|
||||||
self._builtin_variables[variable] = doc
|
self._builtin_variables[variable] = doc
|
||||||
|
|
||||||
|
def _parse_modules(self) -> None:
|
||||||
|
"""Loads docs for all modules in the cmake distribution
|
||||||
|
|
||||||
|
Loads the documentation for cmake modules included in the
|
||||||
|
distribution from the result of `$ cmake --help-modules`.
|
||||||
|
"""
|
||||||
|
p = subprocess.run(
|
||||||
|
[self._cmake, "--help-modules"],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
encoding="utf-8",
|
||||||
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if p.returncode != 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
matches = re.finditer(
|
||||||
|
r"""
|
||||||
|
(?P<module>.+)\n
|
||||||
|
-+\n+?
|
||||||
|
(?:(?P<header>\w[\w\s]+)\n\^+\n+?)?
|
||||||
|
(?P<doc>(?:.|\n)*?\n\n)
|
||||||
|
""",
|
||||||
|
p.stdout + "\n\n",
|
||||||
|
re.VERBOSE,
|
||||||
|
)
|
||||||
|
self._builtin_modules.clear()
|
||||||
|
for match in matches:
|
||||||
|
module = match.group("module")
|
||||||
|
header = match.group("header")
|
||||||
|
doc = _tidy_doc(match.group("doc"))
|
||||||
|
if header != "Overview":
|
||||||
|
doc = ""
|
||||||
|
self._builtin_modules[module] = doc
|
||||||
|
|
||||||
def get_command_doc(self, command: str) -> Optional[str]:
|
def get_command_doc(self, command: str) -> Optional[str]:
|
||||||
return self._builtin_commands.get(command)
|
return self._builtin_commands.get(command)
|
||||||
|
|
||||||
@@ -243,15 +334,32 @@ endforeach()
|
|||||||
return self._builtin_variables.get(variable)
|
return self._builtin_variables.get(variable)
|
||||||
|
|
||||||
def search_variable(self, variable: str) -> List[str]:
|
def search_variable(self, variable: str) -> List[str]:
|
||||||
cached = frozenset(x for x in self._cached_variables
|
cached = frozenset(x for x in self._cached_variables if x.startswith(variable))
|
||||||
if x.startswith(variable))
|
builtin = frozenset(
|
||||||
builtin = frozenset(x for x in self._builtin_variables
|
x for x in self._builtin_variables if x.startswith(variable)
|
||||||
if x.startswith(variable))
|
)
|
||||||
return list(cached | builtin)
|
return list(cached | builtin)
|
||||||
|
|
||||||
|
def get_module_doc(self, module: str, package: bool) -> Optional[str]:
|
||||||
|
if package:
|
||||||
|
return self._builtin_modules.get("Find" + module)
|
||||||
|
|
||||||
|
return self._builtin_modules.get(module)
|
||||||
|
|
||||||
|
def search_module(self, module: str, package: bool) -> List[str]:
|
||||||
|
if package:
|
||||||
|
module = "Find" + module
|
||||||
|
return [x[4:] for x in self._builtin_modules if x.startswith(module)]
|
||||||
|
|
||||||
|
return [
|
||||||
|
x
|
||||||
|
for x in self._builtin_modules
|
||||||
|
if x.startswith(module) and not x.startswith("Find")
|
||||||
|
]
|
||||||
|
|
||||||
def search_target(self, target: str) -> List[str]:
|
def search_target(self, target: str) -> List[str]:
|
||||||
return [x for x in self._targets if x.startswith(target)]
|
return [x for x in self._targets if x.startswith(target)]
|
||||||
|
|
||||||
def _truncate_variable(self, v: str) -> str:
|
def _truncate_variable(self, v: str) -> str:
|
||||||
width = 70
|
width = 70
|
||||||
return v[:width] + (v[width:] and '...')
|
return v[:width] + (v[width:] and "...")
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
from typing import List
|
|
||||||
|
|
||||||
from .parser import TokenList
|
|
||||||
|
|
||||||
|
|
||||||
class Formatter(object):
|
|
||||||
indnt: str
|
|
||||||
lower_identifier: bool
|
|
||||||
|
|
||||||
def __init__(self, indent=' ', lower_identifier=True):
|
|
||||||
self.indent = indent
|
|
||||||
self.lower_identifier = lower_identifier
|
|
||||||
|
|
||||||
def format(self, tokens: TokenList) -> str:
|
|
||||||
cmds: List[str] = ['']
|
|
||||||
indnet_level = 0
|
|
||||||
for token in tokens:
|
|
||||||
if isinstance(token, tuple):
|
|
||||||
raw_identifier = token[0]
|
|
||||||
identifier = raw_identifier.lower()
|
|
||||||
if identifier in ('elseif', 'else', 'endif', 'endforeach',
|
|
||||||
'endwhile', 'endmacro', 'endfunction'):
|
|
||||||
if indnet_level > 0:
|
|
||||||
indnet_level -= 1
|
|
||||||
cmds[-1] = self.indent * indnet_level
|
|
||||||
cmds[-1] += (identifier
|
|
||||||
if self.lower_identifier else raw_identifier)
|
|
||||||
args = self._format_args(token[1])
|
|
||||||
if len(args) < 2:
|
|
||||||
cmds[-1] += '(' + ''.join(args) + ')'
|
|
||||||
else:
|
|
||||||
cmds[-1] += '(\n'
|
|
||||||
for arg in args:
|
|
||||||
cmds[-1] += self.indent * (indnet_level +
|
|
||||||
1) + arg + '\n'
|
|
||||||
cmds[-1] += self.indent * indnet_level + ')'
|
|
||||||
if identifier in ('if', 'elseif', 'else', 'foreach', 'while',
|
|
||||||
'macro', 'function'):
|
|
||||||
indnet_level += 1
|
|
||||||
elif token == '\n':
|
|
||||||
cmds.append('')
|
|
||||||
elif token[0] == '#':
|
|
||||||
if cmds[-1]:
|
|
||||||
cmds[-1] += token
|
|
||||||
else:
|
|
||||||
cmds[-1] = self.indent * indnet_level + token
|
|
||||||
elif cmds[-1]:
|
|
||||||
cmds[-1] += token
|
|
||||||
|
|
||||||
cmds = self._strip_line(cmds)
|
|
||||||
return '\n'.join(cmds) + '\n'
|
|
||||||
|
|
||||||
def _format_args(self, args: List[str]) -> List[str]:
|
|
||||||
lines = ['']
|
|
||||||
for i in range(len(args)):
|
|
||||||
arg = args[i]
|
|
||||||
if arg[0] == '#':
|
|
||||||
lines[-1] += arg
|
|
||||||
elif arg[0] == '\n':
|
|
||||||
lines.append('')
|
|
||||||
elif arg.isspace():
|
|
||||||
if lines[-1]:
|
|
||||||
if i + 1 < len(args) and args[i + 1][0] == '#':
|
|
||||||
lines[-1] += arg
|
|
||||||
else:
|
|
||||||
lines[-1] += ' '
|
|
||||||
else:
|
|
||||||
lines[-1] += arg
|
|
||||||
|
|
||||||
return self._strip_line(lines)
|
|
||||||
|
|
||||||
def _strip_line(self, lines: List[str]) -> List[str]:
|
|
||||||
'''Delete empty lines at the start/end of the input'''
|
|
||||||
|
|
||||||
ret: List[str] = []
|
|
||||||
for line in lines:
|
|
||||||
line = line.rstrip()
|
|
||||||
if line != '' or len(ret) > 0:
|
|
||||||
ret.append(line)
|
|
||||||
while ret and ret[-1] == '':
|
|
||||||
del ret[-1]
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
def main(args: List[str] = None):
|
|
||||||
from pathlib import Path
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
from .parser import ListParser
|
|
||||||
from difflib import unified_diff
|
|
||||||
|
|
||||||
parser = ArgumentParser()
|
|
||||||
parser.add_argument('lists', type=Path, nargs='*', help='CMake list files')
|
|
||||||
parser.add_argument('-i',
|
|
||||||
'--inplace',
|
|
||||||
action='store_true',
|
|
||||||
help='inplace edit')
|
|
||||||
parser.add_argument('-d', '--diff', action='store_true', help='show diff')
|
|
||||||
|
|
||||||
args = parser.parse_args(args)
|
|
||||||
|
|
||||||
list_parser = ListParser()
|
|
||||||
formatter = Formatter()
|
|
||||||
for listpath in args.lists:
|
|
||||||
with listpath.open() as fp:
|
|
||||||
content = fp.read()
|
|
||||||
tokens, remain = list_parser.parse(content)
|
|
||||||
formatted = content if remain else formatter.format(tokens)
|
|
||||||
|
|
||||||
if args.inplace:
|
|
||||||
if not remain:
|
|
||||||
with listpath.open('w') as fp:
|
|
||||||
fp.write(formatted)
|
|
||||||
else:
|
|
||||||
if args.diff:
|
|
||||||
diff = unified_diff(content.splitlines(True),
|
|
||||||
formatted.splitlines(True), str(listpath),
|
|
||||||
str(listpath), '(before formatting)',
|
|
||||||
'(after formatting)')
|
|
||||||
diffstr = ''.join(diff)
|
|
||||||
if diffstr:
|
|
||||||
print(diffstr, end='')
|
|
||||||
else:
|
|
||||||
print(formatted, end='')
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
from typing import List, Tuple, Union
|
|
||||||
|
|
||||||
import pyparsing as pp
|
|
||||||
|
|
||||||
CommandTokenType = Tuple[str, List[str]]
|
|
||||||
TokenType = Union[str, CommandTokenType]
|
|
||||||
TokenList = List[TokenType]
|
|
||||||
|
|
||||||
|
|
||||||
class ListParser(object):
|
|
||||||
_parser: pp.ParserElement
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
newline = '\n'
|
|
||||||
space_plus = pp.Regex('[ \t]+')
|
|
||||||
space_star = pp.Optional(space_plus)
|
|
||||||
|
|
||||||
quoted_element = pp.Regex(r'[^\\"]|\\[^A-Za-z0-9]|\\[trn]')
|
|
||||||
quoted_argument = pp.Combine('"' + pp.ZeroOrMore(quoted_element) + '"')
|
|
||||||
|
|
||||||
bracket_content = pp.Forward()
|
|
||||||
|
|
||||||
def action_bracket_open(tokens: pp.ParseResults):
|
|
||||||
nonlocal bracket_content
|
|
||||||
marker = ']' + '=' * (len(tokens[0]) - 2) + ']'
|
|
||||||
bracket_content <<= pp.SkipTo(marker, include=True)
|
|
||||||
|
|
||||||
bracket_open = pp.Regex(r'\[=*\[').setParseAction(action_bracket_open)
|
|
||||||
bracket_argument = pp.Combine(bracket_open + bracket_content)
|
|
||||||
|
|
||||||
unquoted_element = pp.Regex(r'[^\s()#"\\]|\\[^A-Za-z0-9]|\\[trn]')
|
|
||||||
unquoted_argument = pp.Combine(pp.OneOrMore(unquoted_element))
|
|
||||||
|
|
||||||
argument = bracket_argument | quoted_argument | unquoted_argument
|
|
||||||
|
|
||||||
line_comment = pp.Combine('#' + ~bracket_open +
|
|
||||||
pp.SkipTo(pp.LineEnd()))
|
|
||||||
bracket_comment = pp.Combine('#' + bracket_argument)
|
|
||||||
line_ending = (space_star +
|
|
||||||
pp.ZeroOrMore(bracket_comment + space_star) +
|
|
||||||
pp.Optional(line_comment) + (newline | pp.lineEnd))
|
|
||||||
|
|
||||||
identifier = pp.Word(pp.alphas + '_', pp.alphanums + '_')
|
|
||||||
arguments = pp.Forward()
|
|
||||||
arguments << pp.ZeroOrMore(argument | line_ending | space_plus
|
|
||||||
| '(' + arguments + ')').leaveWhitespace()
|
|
||||||
arguments = pp.Group(arguments)
|
|
||||||
PAREN_L, PAREN_R = map(pp.Suppress, '()')
|
|
||||||
command_invocation = (
|
|
||||||
identifier + space_star.suppress() + PAREN_L + arguments +
|
|
||||||
PAREN_R).setParseAction(lambda t: (t[0], t[1].asList()))
|
|
||||||
|
|
||||||
file_element = (space_star + command_invocation + line_ending
|
|
||||||
| line_ending).leaveWhitespace()
|
|
||||||
file = pp.ZeroOrMore(file_element)
|
|
||||||
|
|
||||||
self._parser = file
|
|
||||||
|
|
||||||
def parse(self, liststr: str) -> Tuple[TokenList, str]:
|
|
||||||
for t, s, e in self._parser.scanString(liststr, maxMatches=1):
|
|
||||||
if s == 0:
|
|
||||||
return t.asList(), liststr[e:]
|
|
||||||
return [], liststr
|
|
||||||
@@ -1,138 +1,259 @@
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Tuple
|
from typing import Any, Callable, List, Optional, Tuple
|
||||||
|
|
||||||
from pygls.features import (COMPLETION, FORMATTING, HOVER, INITIALIZE,
|
from pygls.lsp.methods import (
|
||||||
INITIALIZED, TEXT_DOCUMENT_DID_SAVE)
|
COMPLETION,
|
||||||
|
FORMATTING,
|
||||||
|
HOVER,
|
||||||
|
INITIALIZE,
|
||||||
|
INITIALIZED,
|
||||||
|
TEXT_DOCUMENT_DID_SAVE,
|
||||||
|
)
|
||||||
|
from pygls.lsp.types import (
|
||||||
|
CompletionItem,
|
||||||
|
CompletionItemKind,
|
||||||
|
CompletionList,
|
||||||
|
CompletionOptions,
|
||||||
|
CompletionParams,
|
||||||
|
CompletionTriggerKind,
|
||||||
|
DocumentFormattingParams,
|
||||||
|
Hover,
|
||||||
|
InitializeParams,
|
||||||
|
MarkupContent,
|
||||||
|
MarkupKind,
|
||||||
|
Position,
|
||||||
|
Range,
|
||||||
|
TextDocumentPositionParams,
|
||||||
|
TextDocumentSaveRegistrationOptions,
|
||||||
|
TextEdit,
|
||||||
|
)
|
||||||
from pygls.server import LanguageServer
|
from pygls.server import LanguageServer
|
||||||
from pygls.types import (CompletionItem, CompletionItemKind, CompletionList,
|
|
||||||
CompletionParams, CompletionTriggerKind,
|
|
||||||
DocumentFormattingParams, Hover, InitializeParams,
|
|
||||||
MarkupContent, MarkupKind, Position, Range,
|
|
||||||
TextDocumentPositionParams, TextEdit)
|
|
||||||
|
|
||||||
from .api import API
|
from .api import API
|
||||||
from .formatter import Formatter
|
|
||||||
from .parser import ListParser
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CMakeLanguageServer(LanguageServer):
|
class CMakeLanguageServer(LanguageServer):
|
||||||
_parser: ListParser
|
_api: Optional[API]
|
||||||
_api: API
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, *args: Any) -> None:
|
||||||
super().__init__()
|
super().__init__(*args)
|
||||||
|
|
||||||
self._parser = ListParser()
|
|
||||||
self._api = None
|
self._api = None
|
||||||
|
|
||||||
@self.feature(INITIALIZE)
|
@self.feature(INITIALIZE)
|
||||||
def initialize(params: InitializeParams):
|
def initialize(params: InitializeParams) -> None:
|
||||||
opts = params.initializationOptions
|
opts = params.initialization_options
|
||||||
|
|
||||||
cmake = getattr(opts, 'cmakeExecutable', 'cmake')
|
cmake = getattr(opts, "cmakeExecutable", "cmake")
|
||||||
builddir = getattr(opts, 'buildDirectory', '')
|
builddir = getattr(opts, "buildDirectory", "")
|
||||||
logging.info(f'cmakeExecutable={cmake}, buildDirectory={builddir}')
|
logging.info(f"cmakeExecutable={cmake}, buildDirectory={builddir}")
|
||||||
|
|
||||||
self._api = API(cmake, Path(builddir))
|
self._api = API(cmake, Path(builddir))
|
||||||
self._api.parse_doc()
|
self._api.parse_doc()
|
||||||
|
|
||||||
@self.feature(COMPLETION, trigger_characters=['{'])
|
trigger_characters = ["{", "("]
|
||||||
def completions(params: CompletionParams):
|
|
||||||
if (params.context.triggerKind ==
|
@self.feature(
|
||||||
CompletionTriggerKind.TriggerCharacter):
|
COMPLETION, CompletionOptions(trigger_characters=trigger_characters)
|
||||||
token = ''
|
)
|
||||||
trigger = params.context.triggerCharacter
|
def completions(params: CompletionParams) -> CompletionList:
|
||||||
|
assert self._api is not None
|
||||||
|
|
||||||
|
if (
|
||||||
|
params.context is not None
|
||||||
|
and params.context.trigger_kind
|
||||||
|
== CompletionTriggerKind.TriggerCharacter
|
||||||
|
):
|
||||||
|
token = ""
|
||||||
|
trigger = params.context.trigger_character
|
||||||
else:
|
else:
|
||||||
ret = self.cursor_word(params.textDocument.uri,
|
line = self._cursor_line(params.text_document.uri, params.position)
|
||||||
params.position, False)
|
idx = params.position.character - 1
|
||||||
if not ret:
|
if 0 <= idx < len(line) and line[idx] in trigger_characters:
|
||||||
return None
|
token = ""
|
||||||
token = ret[0]
|
trigger = line[idx]
|
||||||
|
else:
|
||||||
|
word = self._cursor_word(
|
||||||
|
params.text_document.uri, params.position, False
|
||||||
|
)
|
||||||
|
token = "" if word is None else word[0]
|
||||||
trigger = None
|
trigger = None
|
||||||
|
|
||||||
items: List[CompletionItem] = []
|
items: List[CompletionItem] = []
|
||||||
|
|
||||||
if trigger != '{':
|
if trigger is None:
|
||||||
commands = self._api.search_command(token)
|
commands = self._api.search_command(token)
|
||||||
items.extend(
|
items.extend(
|
||||||
CompletionItem(x,
|
CompletionItem(
|
||||||
CompletionItemKind.Function,
|
label=x,
|
||||||
documentation=self._api.get_command_doc(x))
|
kind=CompletionItemKind.Function,
|
||||||
for x in commands)
|
documentation=self._api.get_command_doc(x),
|
||||||
|
insert_text=x,
|
||||||
|
)
|
||||||
|
for x in commands
|
||||||
|
)
|
||||||
|
|
||||||
|
if trigger is None or trigger == "{":
|
||||||
variables = self._api.search_variable(token)
|
variables = self._api.search_variable(token)
|
||||||
items.extend(
|
items.extend(
|
||||||
CompletionItem(x,
|
CompletionItem(
|
||||||
CompletionItemKind.Variable,
|
label=x,
|
||||||
documentation=self._api.get_variable_doc(x))
|
kind=CompletionItemKind.Variable,
|
||||||
for x in variables)
|
documentation=self._api.get_variable_doc(x),
|
||||||
|
insert_text=x,
|
||||||
|
)
|
||||||
|
for x in variables
|
||||||
|
)
|
||||||
|
|
||||||
if trigger != '{':
|
if trigger is None:
|
||||||
targets = self._api.search_target(token)
|
targets = self._api.search_target(token)
|
||||||
items.extend(
|
items.extend(
|
||||||
CompletionItem(x, CompletionItemKind.Class)
|
CompletionItem(
|
||||||
for x in targets)
|
label=x, kind=CompletionItemKind.Class, insert_text=x
|
||||||
|
)
|
||||||
|
for x in targets
|
||||||
|
)
|
||||||
|
|
||||||
return CompletionList(False, items)
|
if trigger == "(":
|
||||||
|
func = self._cursor_function(params.text_document.uri, params.position)
|
||||||
|
if func is not None:
|
||||||
|
func = func.lower()
|
||||||
|
if func == "include":
|
||||||
|
modules = self._api.search_module(token, False)
|
||||||
|
items.extend(
|
||||||
|
CompletionItem(
|
||||||
|
label=x,
|
||||||
|
kind=CompletionItemKind.Module,
|
||||||
|
documentation=self._api.get_module_doc(x, False),
|
||||||
|
insert_text=x,
|
||||||
|
)
|
||||||
|
for x in modules
|
||||||
|
)
|
||||||
|
elif func == "find_package":
|
||||||
|
modules = self._api.search_module(token, True)
|
||||||
|
items.extend(
|
||||||
|
CompletionItem(
|
||||||
|
label=x,
|
||||||
|
kind=CompletionItemKind.Module,
|
||||||
|
documentation=self._api.get_module_doc(x, True),
|
||||||
|
insert_text=x,
|
||||||
|
)
|
||||||
|
for x in modules
|
||||||
|
)
|
||||||
|
|
||||||
|
return CompletionList(is_incomplete=False, items=items)
|
||||||
|
|
||||||
|
if shutil.which("cmake-format") is not None:
|
||||||
|
|
||||||
@self.feature(FORMATTING)
|
@self.feature(FORMATTING)
|
||||||
def formatting(params: DocumentFormattingParams):
|
def formatting(
|
||||||
doc = self.workspace.get_document(params.textDocument.uri)
|
params: DocumentFormattingParams,
|
||||||
|
) -> Optional[List[TextEdit]]:
|
||||||
|
doc = self.workspace.get_document(params.text_document.uri)
|
||||||
content = doc.source
|
content = doc.source
|
||||||
tokens, remain = self._parser.parse(content)
|
formatted = subprocess.check_output(
|
||||||
if remain:
|
["cmake-format", "-"],
|
||||||
self.show_message('CMake parser failed')
|
cwd=str(Path(doc.path).parent),
|
||||||
return None
|
input=content,
|
||||||
|
universal_newlines=True,
|
||||||
formatted = Formatter().format(tokens)
|
)
|
||||||
lines = content.count('\n')
|
lines = content.count("\n")
|
||||||
return [
|
return [
|
||||||
TextEdit(Range(Position(0, 0), Position(lines + 1, 0)),
|
TextEdit(
|
||||||
formatted)
|
range=Range(
|
||||||
|
start=Position(line=0, character=0),
|
||||||
|
end=Position(line=lines + 1, character=0),
|
||||||
|
),
|
||||||
|
new_text=formatted,
|
||||||
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
@self.feature(HOVER)
|
@self.feature(HOVER)
|
||||||
def hover(params: TextDocumentPositionParams):
|
def hover(params: TextDocumentPositionParams) -> Optional[Hover]:
|
||||||
ret = self.cursor_word(params.textDocument.uri, params.position)
|
assert self._api is not None
|
||||||
if not ret:
|
api = self._api
|
||||||
|
|
||||||
|
word = self._cursor_word(params.text_document.uri, params.position, True)
|
||||||
|
if not word:
|
||||||
return None
|
return None
|
||||||
doc = self._api.get_command_doc(ret[0].lower())
|
|
||||||
if not doc:
|
candidates: List[Callable[[str], Optional[str]]] = [
|
||||||
doc = self._api.get_variable_doc(ret[0])
|
lambda x: api.get_command_doc(x.lower()),
|
||||||
if not doc:
|
lambda x: api.get_variable_doc(x),
|
||||||
|
lambda x: api.get_module_doc(x, False),
|
||||||
|
lambda x: api.get_module_doc(x, True),
|
||||||
|
]
|
||||||
|
for c in candidates:
|
||||||
|
doc = c(word[0])
|
||||||
|
if doc is None:
|
||||||
|
continue
|
||||||
|
return Hover(
|
||||||
|
contents=MarkupContent(kind=MarkupKind.Markdown, value=doc),
|
||||||
|
range=word[1],
|
||||||
|
)
|
||||||
return None
|
return None
|
||||||
return Hover(MarkupContent(MarkupKind.Markdown, doc), ret[1])
|
|
||||||
|
|
||||||
@self.thread()
|
@self.thread()
|
||||||
@self.feature(TEXT_DOCUMENT_DID_SAVE, includeText=False)
|
@self.feature(
|
||||||
|
TEXT_DOCUMENT_DID_SAVE,
|
||||||
|
TextDocumentSaveRegistrationOptions(include_text=False),
|
||||||
|
)
|
||||||
@self.feature(INITIALIZED)
|
@self.feature(INITIALIZED)
|
||||||
def run_cmake(*args):
|
def run_cmake(*args: Any) -> None:
|
||||||
|
assert self._api is not None
|
||||||
|
|
||||||
if self._api.query():
|
if self._api.query():
|
||||||
self._api.read_reply()
|
self._api.read_reply()
|
||||||
|
|
||||||
def cursor_word(self,
|
def _cursor_function(self, uri: str, position: Position) -> Optional[str]:
|
||||||
uri: str,
|
doc = self.workspace.get_document(uri)
|
||||||
position: Position,
|
lines = doc.source.split("\n")[: position.line + 1]
|
||||||
include_all: bool = True) -> Optional[Tuple[str, Range]]:
|
lines[-1] = lines[-1][: position.character - 1].strip()
|
||||||
|
words = re.split(r"[\s\n()]+", "\n".join(lines))
|
||||||
|
return words[-1] if words else None
|
||||||
|
|
||||||
|
def _cursor_line(self, uri: str, position: Position) -> str:
|
||||||
doc = self.workspace.get_document(uri)
|
doc = self.workspace.get_document(uri)
|
||||||
content = doc.source
|
content = doc.source
|
||||||
line = content.split('\n')[position.line]
|
line = content.split("\n")[position.line]
|
||||||
cursor = position.character
|
return str(line)
|
||||||
for m in re.finditer(r'\w+', line):
|
|
||||||
if m.start() <= cursor <= m.end():
|
|
||||||
end = m.end() if include_all else cursor
|
|
||||||
return (line[m.start():end],
|
|
||||||
Range(Position(position.line, m.start()),
|
|
||||||
Position(position.line, end)))
|
|
||||||
|
|
||||||
|
def _cursor_word(
|
||||||
|
self, uri: str, position: Position, include_all: bool = True
|
||||||
|
) -> Optional[Tuple[str, Range]]:
|
||||||
|
line = self._cursor_line(uri, position)
|
||||||
|
cursor = position.character
|
||||||
|
for m in re.finditer(r"\w+", line):
|
||||||
|
end = m.end() if include_all else cursor
|
||||||
|
if m.start() <= cursor <= m.end():
|
||||||
|
word = (
|
||||||
|
line[m.start() : end],
|
||||||
|
Range(
|
||||||
|
start=Position(line=position.line, character=m.start()),
|
||||||
|
end=Position(line=position.line, character=end),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return word
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main() -> None:
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
|
||||||
|
from . import __version__
|
||||||
|
|
||||||
|
parser = ArgumentParser(description="CMake Language Server")
|
||||||
|
parser.add_argument(
|
||||||
|
"--version", action="version", version=f"%(prog)s {__version__}"
|
||||||
|
)
|
||||||
|
parser.parse_args()
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
logging.getLogger('pygls').setLevel(logging.WARNING)
|
logging.getLogger("pygls").setLevel(logging.WARNING)
|
||||||
CMakeLanguageServer().start_io()
|
CMakeLanguageServer().start_io() # type: ignore
|
||||||
|
|||||||
@@ -1,16 +1,62 @@
|
|||||||
|
import asyncio
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import pprint
|
||||||
|
from pathlib import Path
|
||||||
|
from subprocess import PIPE, run
|
||||||
|
from threading import Thread
|
||||||
|
from typing import Iterable, Tuple
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from cmake_language_server.server import CMakeLanguageServer
|
||||||
|
from pygls.lsp.methods import EXIT
|
||||||
|
from pygls.server import LanguageServer
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def cmake_build(shared_datadir):
|
def cmake_build(shared_datadir: Path) -> Iterable[Path]:
|
||||||
from subprocess import run, PIPE
|
source = shared_datadir / "cmake"
|
||||||
source = shared_datadir / 'cmake'
|
build = source / "build"
|
||||||
build = source / 'build'
|
|
||||||
build.mkdir()
|
build.mkdir()
|
||||||
run(['cmake', source],
|
p = run(
|
||||||
check=True,
|
["cmake", str(source)],
|
||||||
cwd=build,
|
cwd=build,
|
||||||
stdout=PIPE,
|
stdout=PIPE,
|
||||||
stderr=PIPE,
|
stderr=PIPE,
|
||||||
universal_newlines=True)
|
universal_newlines=True,
|
||||||
|
)
|
||||||
|
if p.returncode != 0:
|
||||||
|
logging.error("env:\n" + pprint.pformat(os.environ))
|
||||||
|
logging.error("stdout:\n" + p.stdout)
|
||||||
|
logging.error("stderr:\n" + p.stderr)
|
||||||
|
raise RuntimeError("CMake failed")
|
||||||
yield build
|
yield build
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def client_server() -> Iterable[Tuple[LanguageServer, CMakeLanguageServer]]:
|
||||||
|
c2s_r, c2s_w = os.pipe()
|
||||||
|
s2c_r, s2c_w = os.pipe()
|
||||||
|
|
||||||
|
def start(ls: LanguageServer, fdr: int, fdw: int) -> None:
|
||||||
|
# TODO: better patch is needed
|
||||||
|
# disable `close()` to avoid error messages
|
||||||
|
close = ls.loop.close
|
||||||
|
ls.loop.close = lambda: None # type: ignore
|
||||||
|
ls.start_io(os.fdopen(fdr, "rb"), os.fdopen(fdw, "wb")) # type: ignore
|
||||||
|
ls.loop.close = close # type: ignore
|
||||||
|
|
||||||
|
server = CMakeLanguageServer(asyncio.new_event_loop())
|
||||||
|
server_thread = Thread(target=start, args=(server, c2s_r, s2c_w))
|
||||||
|
server_thread.start()
|
||||||
|
|
||||||
|
client = LanguageServer(asyncio.new_event_loop())
|
||||||
|
client_thread = Thread(target=start, args=(client, s2c_r, c2s_w))
|
||||||
|
client_thread.start()
|
||||||
|
|
||||||
|
yield client, server
|
||||||
|
|
||||||
|
client.send_notification(EXIT)
|
||||||
|
server.send_notification(EXIT)
|
||||||
|
server_thread.join()
|
||||||
|
client_thread.join()
|
||||||
|
|||||||
@@ -1,75 +1,122 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from cmake_language_server.api import API
|
from cmake_language_server.api import API
|
||||||
|
|
||||||
|
|
||||||
def test_query_with_cache(cmake_build):
|
def test_query_with_cache(cmake_build: Path) -> None:
|
||||||
api = API('cmake', cmake_build)
|
api = API("cmake", cmake_build)
|
||||||
assert api.query()
|
assert api.query()
|
||||||
|
|
||||||
query = cmake_build / '.cmake' / 'api' / 'v1' / 'query'
|
query = cmake_build / ".cmake" / "api" / "v1" / "query"
|
||||||
assert query.exists()
|
assert query.exists()
|
||||||
|
|
||||||
reply = cmake_build / '.cmake' / 'api' / 'v1' / 'reply'
|
reply = cmake_build / ".cmake" / "api" / "v1" / "reply"
|
||||||
assert reply.exists()
|
assert reply.exists()
|
||||||
|
|
||||||
|
|
||||||
def test_query_without_cache(cmake_build):
|
def test_query_without_cache(cmake_build: Path) -> None:
|
||||||
api = API('cmake', cmake_build)
|
api = API("cmake", cmake_build)
|
||||||
(cmake_build / 'CMakeCache.txt').unlink()
|
(cmake_build / "CMakeCache.txt").unlink()
|
||||||
|
|
||||||
assert not api.query()
|
assert not api.query()
|
||||||
|
|
||||||
|
|
||||||
def test_read_variable(cmake_build):
|
def test_read_variable(cmake_build: Path) -> None:
|
||||||
api = API('cmake', cmake_build)
|
api = API("cmake", cmake_build)
|
||||||
assert api.query()
|
assert api.query()
|
||||||
assert api.read_reply()
|
assert api.read_reply()
|
||||||
|
|
||||||
assert api.get_variable_doc('testproject_BINARY_DIR')
|
assert api.get_variable_doc("testproject_BINARY_DIR")
|
||||||
|
|
||||||
|
|
||||||
def test_read_cmake_files(cmake_build):
|
def test_read_cmake_files(cmake_build: Path) -> None:
|
||||||
api = API('cmake', cmake_build)
|
api = API("cmake", cmake_build)
|
||||||
api.parse_doc()
|
api.parse_doc()
|
||||||
assert api.query()
|
assert api.query()
|
||||||
api.read_reply()
|
api.read_reply()
|
||||||
|
|
||||||
assert 'GNU' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID')
|
import platform
|
||||||
|
|
||||||
|
system = platform.system()
|
||||||
|
cxx = api.get_variable_doc("CMAKE_CXX_COMPILER_ID")
|
||||||
|
assert cxx is not None
|
||||||
|
if system == "Linux":
|
||||||
|
assert "GNU" in cxx
|
||||||
|
elif system == "Windows":
|
||||||
|
assert "MSVC" in cxx
|
||||||
|
elif system == "Darwin":
|
||||||
|
assert "Clang" in cxx
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Unexpected system")
|
||||||
|
|
||||||
|
|
||||||
def test_parse_commands(cmake_build):
|
def test_parse_commands(cmake_build: Path) -> None:
|
||||||
api = API('cmake', cmake_build)
|
api = API("cmake", cmake_build)
|
||||||
api.parse_doc()
|
api.parse_doc()
|
||||||
|
|
||||||
p = subprocess.run(['cmake', '--help-command-list'],
|
p = subprocess.run(
|
||||||
|
["cmake", "--help-command-list"],
|
||||||
universal_newlines=True,
|
universal_newlines=True,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE,
|
||||||
commands = p.stdout.strip().split('\n')
|
)
|
||||||
|
commands = p.stdout.strip().split("\n")
|
||||||
|
|
||||||
for command in commands:
|
for command in commands:
|
||||||
assert api.get_command_doc(command) is not None, f'{command} not found'
|
assert api.get_command_doc(command) is not None, f"{command} not found"
|
||||||
|
|
||||||
assert 'break()' in api.get_command_doc('break')
|
break_doc = api.get_command_doc("break")
|
||||||
assert api.get_command_doc('not_existing_command') is None
|
assert break_doc is not None and "break()" in break_doc
|
||||||
|
assert api.get_command_doc("not_existing_command") is None
|
||||||
|
|
||||||
|
|
||||||
def test_parse_variables(cmake_build):
|
def test_parse_variables(cmake_build: Path) -> None:
|
||||||
api = API('cmake', cmake_build)
|
api = API("cmake", cmake_build)
|
||||||
api.parse_doc()
|
api.parse_doc()
|
||||||
|
|
||||||
p = subprocess.run(['cmake', '--help-variable-list'],
|
p = subprocess.run(
|
||||||
|
["cmake", "--help-variable-list"],
|
||||||
universal_newlines=True,
|
universal_newlines=True,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE,
|
||||||
variables = p.stdout.strip().split('\n')
|
)
|
||||||
|
variables = p.stdout.strip().split("\n")
|
||||||
|
|
||||||
for variable in variables:
|
for variable in variables:
|
||||||
if '<' in variable:
|
if "<" in variable:
|
||||||
continue
|
continue
|
||||||
assert api.get_variable_doc(
|
assert api.get_variable_doc(variable) is not None, f"{variable} not found"
|
||||||
variable) is not None, f'{variable} not found'
|
|
||||||
|
|
||||||
assert api.get_variable_doc('BUILD_SHARED_LIBS') is not None
|
assert api.get_variable_doc("BUILD_SHARED_LIBS") is not None
|
||||||
assert api.get_variable_doc('not_existing_variable') is None
|
assert api.get_variable_doc("not_existing_variable") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_modules(cmake_build: Path) -> None:
|
||||||
|
api = API("cmake", cmake_build)
|
||||||
|
api.parse_doc()
|
||||||
|
|
||||||
|
p = subprocess.run(
|
||||||
|
["cmake", "--help-module-list"],
|
||||||
|
universal_newlines=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
)
|
||||||
|
modules = p.stdout.strip().split("\n")
|
||||||
|
|
||||||
|
for module in modules:
|
||||||
|
if module.startswith("Find"):
|
||||||
|
assert (
|
||||||
|
api.get_module_doc(module[4:], True) is not None
|
||||||
|
), f"{module} not found"
|
||||||
|
else:
|
||||||
|
assert api.get_module_doc(module, False) is not None, f"{module} not found"
|
||||||
|
|
||||||
|
assert api.get_module_doc("GoogleTest", False) is not None
|
||||||
|
assert api.get_module_doc("GoogleTest", True) is None
|
||||||
|
assert api.search_module("GoogleTest", False) == ["GoogleTest"]
|
||||||
|
assert api.search_module("GoogleTest", True) == []
|
||||||
|
assert api.get_module_doc("Boost", False) is None
|
||||||
|
assert api.get_module_doc("Boost", True) is not None
|
||||||
|
assert api.search_module("Boost", False) == []
|
||||||
|
assert api.search_module("Boost", True) == ["Boost"]
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
from cmake_language_server.formatter import Formatter
|
|
||||||
from cmake_language_server.parser import ListParser
|
|
||||||
|
|
||||||
|
|
||||||
def make_formatter_test(liststr: str, expect: str):
|
|
||||||
def test():
|
|
||||||
tokens, remain = ListParser().parse(liststr)
|
|
||||||
actual = Formatter().format(tokens)
|
|
||||||
assert actual == expect
|
|
||||||
|
|
||||||
return test
|
|
||||||
|
|
||||||
|
|
||||||
test_command = make_formatter_test('a()', 'a()\n')
|
|
||||||
test_command_tolower = make_formatter_test('A()', 'a()\n')
|
|
||||||
test_remove_space = make_formatter_test('''
|
|
||||||
#a
|
|
||||||
b ( c ) # d
|
|
||||||
''', '''\
|
|
||||||
#a
|
|
||||||
b(c) # d
|
|
||||||
''')
|
|
||||||
test_indent_if = make_formatter_test(
|
|
||||||
'''
|
|
||||||
if()
|
|
||||||
a() # a
|
|
||||||
else()
|
|
||||||
# b
|
|
||||||
b()
|
|
||||||
endif()
|
|
||||||
''', '''\
|
|
||||||
if()
|
|
||||||
a() # a
|
|
||||||
else()
|
|
||||||
# b
|
|
||||||
b()
|
|
||||||
endif()
|
|
||||||
''')
|
|
||||||
test_indent_if_nested = make_formatter_test(
|
|
||||||
'''
|
|
||||||
if()
|
|
||||||
if()
|
|
||||||
a()
|
|
||||||
b()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
''', '''\
|
|
||||||
if()
|
|
||||||
if()
|
|
||||||
a()
|
|
||||||
b()
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
''')
|
|
||||||
test_argument = make_formatter_test('a( b c d)', 'a(b c d)\n')
|
|
||||||
test_argument_multiline = make_formatter_test(
|
|
||||||
'''
|
|
||||||
if()
|
|
||||||
a(b c
|
|
||||||
d # e
|
|
||||||
f
|
|
||||||
# g
|
|
||||||
) # h
|
|
||||||
endif()
|
|
||||||
''', '''\
|
|
||||||
if()
|
|
||||||
a(
|
|
||||||
b c
|
|
||||||
d # e
|
|
||||||
f
|
|
||||||
# g
|
|
||||||
) # h
|
|
||||||
endif()
|
|
||||||
''')
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
from typing import List
|
|
||||||
|
|
||||||
from cmake_language_server.parser import ListParser, TokenType
|
|
||||||
|
|
||||||
|
|
||||||
def make_parser_test(liststr: str,
|
|
||||||
expect_token: List[TokenType],
|
|
||||||
expect_remain: str = ''):
|
|
||||||
def test():
|
|
||||||
actual_token, actual_remain = ListParser().parse(liststr)
|
|
||||||
assert actual_token == expect_token
|
|
||||||
assert actual_remain == expect_remain
|
|
||||||
|
|
||||||
return test
|
|
||||||
|
|
||||||
|
|
||||||
test_command_no_args = make_parser_test('a()', [('a', [])])
|
|
||||||
test_command_space = make_parser_test(' a ()', [' ', ('a', [])])
|
|
||||||
test_command_arg = make_parser_test('a(b)', [('a', ['b'])])
|
|
||||||
test_command_arg_space = make_parser_test('a ( b )', [('a', ['b'])])
|
|
||||||
test_command_arg_escape = make_parser_test(r'a(\n\")', [('a', [r'\n\"'])])
|
|
||||||
test_command_arg_paren = make_parser_test('a((b))', [('a', ['(', 'b', ')'])])
|
|
||||||
test_command_arg_paren_paren = make_parser_test(
|
|
||||||
'a(((b)))', [('a', ['(', '(', 'b', ')', ')'])])
|
|
||||||
test_command_arg_quote = make_parser_test(r'a("b\"")', [('a', [r'"b\""'])])
|
|
||||||
test_command_arg_quote_cont = make_parser_test('a("\\\n")',
|
|
||||||
[('a', ['"\\\n"'])])
|
|
||||||
test_command_arg_quo_multiline = make_parser_test('''a("b
|
|
||||||
c
|
|
||||||
")''', [('a', ['"b\nc\n"'])])
|
|
||||||
test_command_arg_bracket_0 = make_parser_test('a([[b]])', [('a', ['[[b]]'])])
|
|
||||||
test_command_arg_bracket_1 = make_parser_test('a([=[b]=])',
|
|
||||||
[('a', ['[=[b]=]'])])
|
|
||||||
test_command_arg_space = make_parser_test('a ( b )', [('a', [' ', 'b', ' '])])
|
|
||||||
test_command_arg_multi = make_parser_test('a(b c)', [('a', ['b', ' ', 'c'])])
|
|
||||||
test_command_multielement = make_parser_test('''a(
|
|
||||||
b
|
|
||||||
c # c
|
|
||||||
)''', [('a', ['\n', ' ', 'b', '\n', ' ', 'c', ' ', '# c', '\n'])])
|
|
||||||
test_line_comment = make_parser_test('a() # b # c',
|
|
||||||
[('a', []), ' ', '# b # c'])
|
|
||||||
test_bracket_comment = make_parser_test('#[[a]]#[[b]]', ['#[[a]]', '#[[b]]'])
|
|
||||||
test_bracket_comment_nested = make_parser_test('#[=[[[a]]]=]',
|
|
||||||
['#[=[[[a]]]=]'])
|
|
||||||
test_bracket_comment_multiline = make_parser_test('#[[\na\nb\nc\n]]',
|
|
||||||
['#[[\na\nb\nc\n]]'])
|
|
||||||
test_if_block = make_parser_test('''if()
|
|
||||||
a()
|
|
||||||
else()
|
|
||||||
b()
|
|
||||||
endif()''', [('if', []), '\n', ' ', ('a', []), '\n', ('else', []), '\n', ' ',
|
|
||||||
('b', []), '\n', ('endif', [])])
|
|
||||||
test_comment_multi_linecomment = make_parser_test(
|
|
||||||
'''a()# a
|
|
||||||
b() # b
|
|
||||||
c() # c''', [('a', []), '# a', '\n', ('b', []), ' ', '# b', '\n',
|
|
||||||
('c', []), ' ', '# c'])
|
|
||||||
|
|
||||||
test_incomplete_id = make_parser_test('a', [], 'a')
|
|
||||||
test_incomplete_command = make_parser_test('a(', [], 'a(')
|
|
||||||
test_incomplete_id_after_command = make_parser_test('a()\nb',
|
|
||||||
[('a', []), '\n'], 'b')
|
|
||||||
test_incomplete_command_after_command = make_parser_test(
|
|
||||||
'a()\nb(c', [('a', []), '\n'], 'b(c')
|
|
||||||
205
tests/test_server.py
Normal file
205
tests/test_server.py
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
from concurrent import futures
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, Optional, Tuple
|
||||||
|
|
||||||
|
from cmake_language_server.server import CMakeLanguageServer
|
||||||
|
from pygls.lsp.methods import (
|
||||||
|
COMPLETION,
|
||||||
|
FORMATTING,
|
||||||
|
HOVER,
|
||||||
|
INITIALIZE,
|
||||||
|
TEXT_DOCUMENT_DID_OPEN,
|
||||||
|
)
|
||||||
|
from pygls.lsp.types import (
|
||||||
|
ClientCapabilities,
|
||||||
|
CompletionContext,
|
||||||
|
CompletionParams,
|
||||||
|
CompletionTriggerKind,
|
||||||
|
DidOpenTextDocumentParams,
|
||||||
|
DocumentFormattingParams,
|
||||||
|
FormattingOptions,
|
||||||
|
InitializeParams,
|
||||||
|
Position,
|
||||||
|
TextDocumentIdentifier,
|
||||||
|
TextDocumentItem,
|
||||||
|
TextDocumentPositionParams,
|
||||||
|
)
|
||||||
|
from pygls.server import LanguageServer
|
||||||
|
|
||||||
|
CALL_TIMEOUT = 2
|
||||||
|
|
||||||
|
|
||||||
|
def _init(client: LanguageServer, root: Path) -> None:
|
||||||
|
retry = 3
|
||||||
|
while retry > 0:
|
||||||
|
try:
|
||||||
|
client.lsp.send_request(
|
||||||
|
INITIALIZE,
|
||||||
|
InitializeParams(
|
||||||
|
process_id=1234,
|
||||||
|
root_uri=root.as_uri(),
|
||||||
|
capabilities=ClientCapabilities(),
|
||||||
|
),
|
||||||
|
).result(timeout=CALL_TIMEOUT)
|
||||||
|
except futures.TimeoutError:
|
||||||
|
retry -= 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def _open(client: LanguageServer, path: Path, text: Optional[str] = None) -> None:
|
||||||
|
if text is None:
|
||||||
|
with open(path) as fp:
|
||||||
|
text = fp.read()
|
||||||
|
|
||||||
|
client.lsp.notify(
|
||||||
|
TEXT_DOCUMENT_DID_OPEN,
|
||||||
|
DidOpenTextDocumentParams(
|
||||||
|
text_document=TextDocumentItem(
|
||||||
|
uri=path.as_uri(), language_id="cmake", version=1, text=text
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _test_completion(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer],
|
||||||
|
datadir: Path,
|
||||||
|
content: str,
|
||||||
|
context: Optional[CompletionContext],
|
||||||
|
) -> Dict[str, Any]:
|
||||||
|
client, server = client_server
|
||||||
|
_init(client, datadir)
|
||||||
|
path = datadir / "CMakeLists.txt"
|
||||||
|
_open(client, path, content)
|
||||||
|
params = CompletionParams(
|
||||||
|
text_document=TextDocumentIdentifier(uri=path.as_uri()),
|
||||||
|
position=Position(line=0, character=len(content)),
|
||||||
|
context=context,
|
||||||
|
)
|
||||||
|
if context is None:
|
||||||
|
# some clients do not send context
|
||||||
|
del params.context
|
||||||
|
ret = client.lsp.send_request(COMPLETION, params).result(timeout=CALL_TIMEOUT)
|
||||||
|
assert isinstance(ret, dict)
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
def test_initialize(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
client, server = client_server
|
||||||
|
|
||||||
|
assert server._api is None
|
||||||
|
_init(client, datadir)
|
||||||
|
assert server._api is not None
|
||||||
|
|
||||||
|
|
||||||
|
def test_completions_invoked(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
response = _test_completion(
|
||||||
|
client_server,
|
||||||
|
datadir,
|
||||||
|
"projec",
|
||||||
|
CompletionContext(trigger_kind=CompletionTriggerKind.Invoked),
|
||||||
|
)
|
||||||
|
item = next(filter(lambda x: x["label"] == "project", response["items"]), None)
|
||||||
|
assert item is not None
|
||||||
|
assert isinstance(item["documentation"], str)
|
||||||
|
assert "<PROJECT-NAME>" in item["documentation"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_completions_nocontext(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
response = _test_completion(client_server, datadir, "projec", None)
|
||||||
|
item = next(filter(lambda x: x["label"] == "project", response["items"]), None)
|
||||||
|
assert item is not None
|
||||||
|
assert isinstance(item["documentation"], str)
|
||||||
|
assert "<PROJECT-NAME>" in item["documentation"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_completions_triggercharacter_variable(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
response = _test_completion(
|
||||||
|
client_server,
|
||||||
|
datadir,
|
||||||
|
"${",
|
||||||
|
CompletionContext(
|
||||||
|
trigger_kind=CompletionTriggerKind.TriggerCharacter, trigger_character="{"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert "PROJECT_VERSION" in [x["label"] for x in response["items"]]
|
||||||
|
|
||||||
|
response_nocontext = _test_completion(client_server, datadir, "${", None)
|
||||||
|
assert response == response_nocontext
|
||||||
|
|
||||||
|
|
||||||
|
def test_completions_triggercharacter_module(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
response = _test_completion(
|
||||||
|
client_server,
|
||||||
|
datadir,
|
||||||
|
"include(",
|
||||||
|
CompletionContext(
|
||||||
|
trigger_kind=CompletionTriggerKind.TriggerCharacter, trigger_character="("
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert "GoogleTest" in [x["label"] for x in response["items"]]
|
||||||
|
|
||||||
|
response_nocontext = _test_completion(client_server, datadir, "include(", None)
|
||||||
|
assert response == response_nocontext
|
||||||
|
|
||||||
|
|
||||||
|
def test_completions_triggercharacter_package(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
response = _test_completion(
|
||||||
|
client_server,
|
||||||
|
datadir,
|
||||||
|
"find_package(",
|
||||||
|
CompletionContext(
|
||||||
|
trigger_kind=CompletionTriggerKind.TriggerCharacter, trigger_character="("
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assert "Boost" in [x["label"] for x in response["items"]]
|
||||||
|
|
||||||
|
response_nocontext = _test_completion(client_server, datadir, "find_package(", None)
|
||||||
|
assert response == response_nocontext
|
||||||
|
|
||||||
|
|
||||||
|
def test_formatting(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
client, server = client_server
|
||||||
|
_init(client, datadir)
|
||||||
|
path = datadir / "CMakeLists.txt"
|
||||||
|
_open(client, path, "a ( b c ) ")
|
||||||
|
response = client.lsp.send_request(
|
||||||
|
FORMATTING,
|
||||||
|
DocumentFormattingParams(
|
||||||
|
text_document=TextDocumentIdentifier(uri=path.as_uri()),
|
||||||
|
options=FormattingOptions(tab_size=2, insert_spaces=True),
|
||||||
|
),
|
||||||
|
).result(timeout=CALL_TIMEOUT)
|
||||||
|
assert response[0]["newText"] == "a(b c)\n"
|
||||||
|
|
||||||
|
|
||||||
|
def test_hover(
|
||||||
|
client_server: Tuple[LanguageServer, CMakeLanguageServer], datadir: Path
|
||||||
|
) -> None:
|
||||||
|
client, server = client_server
|
||||||
|
_init(client, datadir)
|
||||||
|
path = datadir / "CMakeLists.txt"
|
||||||
|
_open(client, path, "project()")
|
||||||
|
response = client.lsp.send_request(
|
||||||
|
HOVER,
|
||||||
|
TextDocumentPositionParams(
|
||||||
|
text_document=TextDocumentIdentifier(uri=path.as_uri()),
|
||||||
|
position=Position(line=0, character=0),
|
||||||
|
),
|
||||||
|
).result(timeout=CALL_TIMEOUT)
|
||||||
|
assert "<PROJECT-NAME>" in response["contents"]["value"]
|
||||||
34
tox.ini
34
tox.ini
@@ -1,27 +1,37 @@
|
|||||||
[tox]
|
[tox]
|
||||||
isolated_build = True
|
isolated_build = True
|
||||||
skipsdist = True
|
skipsdist = True
|
||||||
envlist = py36, py37, py38, lint
|
envlist = py{36,37,38,39,310}-{linux,windows}
|
||||||
|
|
||||||
[gh-actions]
|
[gh-actions]
|
||||||
python =
|
python =
|
||||||
3.6: py36
|
3.7: py37
|
||||||
3.7: py37, lint
|
|
||||||
3.8: py38
|
3.8: py38
|
||||||
|
3.9: py39
|
||||||
|
3.10: py310
|
||||||
|
|
||||||
|
[gh-actions:env]
|
||||||
|
os =
|
||||||
|
ubuntu-18.04: linux
|
||||||
|
windows-2019: windows
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
whitelist_externals = poetry
|
allowlist_externals =
|
||||||
|
poetry
|
||||||
|
git
|
||||||
skip_install = true
|
skip_install = true
|
||||||
|
passenv = *
|
||||||
commands_pre =
|
commands_pre =
|
||||||
poetry install
|
poetry install
|
||||||
commands =
|
commands =
|
||||||
poetry run pytest -sv tests
|
pytest --cov-report=term --cov-report=xml --cov=src -sv tests
|
||||||
|
|
||||||
[testenv:lint]
|
pip install "pysen[lint]"
|
||||||
whitelist_externals = poetry
|
pip install "black>=22.3.0"
|
||||||
skip_install = true
|
pysen run format
|
||||||
|
git diff --exit-code --ignore-submodules
|
||||||
|
pysen run lint
|
||||||
|
|
||||||
|
[testenv:py310-windows]
|
||||||
commands =
|
commands =
|
||||||
poetry run isort -c -rc src tests
|
pytest --cov-report=term --cov-report=xml --cov=src -sv tests
|
||||||
poetry run yapf -d -r src tests
|
|
||||||
poetry run flake8
|
|
||||||
poetry run mypy src tests
|
|
||||||
|
|||||||
Reference in New Issue
Block a user