Replace yapf with black

This commit is contained in:
Regen
2020-08-22 14:34:31 +09:00
parent 5550cb259c
commit 01b1fac73e
14 changed files with 1064 additions and 626 deletions

View File

@@ -1,6 +1,6 @@
name: Tests name: Tests
on: [push, pull_request] on: [pull_request]
jobs: jobs:
build: build:

639
poetry.lock generated
View File

@@ -1,59 +1,104 @@
[[package]] [[package]]
name = "appdirs"
version = "1.4.4"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
category = "dev" category = "dev"
description = "Atomic file writes."
name = "atomicwrites"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.3.0"
[[package]]
category = "dev"
description = "Classes Without Boilerplate"
name = "attrs"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.3.0"
[[package]]
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 = "Code coverage measurement for Python"
name = "coverage"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "5.0"
[[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]] [[package]]
name = "atomicwrites"
version = "1.3.0"
description = "Atomic file writes."
category = "dev" category = "dev"
description = "the modular source code checker: pep8, pyflakes and co"
name = "flake8"
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.*"
[[package]]
name = "attrs"
version = "19.3.0"
description = "Classes Without Boilerplate"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.extras]
azure-pipelines = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "pytest-azurepipelines"]
dev = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "sphinx", "pre-commit"]
docs = ["sphinx", "zope.interface"]
tests = ["coverage", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"]
[[package]]
name = "black"
version = "19.10b0"
description = "The uncompromising code formatter."
category = "dev"
optional = false
python-versions = ">=3.6"
[package.extras]
d = ["aiohttp (>=3.3.2)", "aiohttp-cors"]
[package.dependencies]
appdirs = "*"
attrs = ">=18.1.0"
click = ">=6.5"
pathspec = ">=0.6,<1"
regex = "*"
toml = ">=0.9.4"
typed-ast = ">=1.4.0"
[[package]]
name = "click"
version = "7.1.2"
description = "Composable command line interface toolkit"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "colorama"
version = "0.4.1"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
marker = "sys_platform == \"win32\""
[[package]]
name = "coverage"
version = "5.0"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
[package.extras]
toml = ["toml"]
[[package]]
name = "entrypoints"
version = "0.3"
description = "Discover and load entry points from installed packages."
category = "dev"
optional = false
python-versions = ">=2.7"
[[package]]
name = "filelock"
version = "3.0.12"
description = "A platform independent file lock."
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "flake8"
version = "3.7.8" version = "3.7.8"
description = "the modular source code checker: pep8, pyflakes and co"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[package.dependencies] [package.dependencies]
entrypoints = ">=0.3.0,<0.4.0" entrypoints = ">=0.3.0,<0.4.0"
@@ -62,48 +107,61 @@ pycodestyle = ">=2.5.0,<2.6.0"
pyflakes = ">=2.1.0,<2.2.0" pyflakes = ">=2.1.0,<2.2.0"
[[package]] [[package]]
category = "dev"
description = "Read metadata from Python packages"
marker = "python_version < \"3.8\""
name = "importlib-metadata" name = "importlib-metadata"
version = "0.23"
description = "Read metadata from Python packages"
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 = "0.23" marker = "python_version < \"3.8\""
[package.extras]
docs = ["sphinx", "rst.linker"]
testing = ["packaging", "importlib-resources"]
[package.dependencies] [package.dependencies]
zipp = ">=0.5" zipp = ">=0.5"
[[package]] [[package]]
category = "dev"
description = "A Python utility / library to sort Python imports."
name = "isort" name = "isort"
version = "4.3.21"
description = "A Python utility / library to sort Python imports."
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 = "4.3.21"
[package.extras]
pipfile = ["pipreqs", "requirementslib"]
pyproject = ["toml"]
requirements = ["pipreqs", "pip-api"]
xdg_home = ["appdirs (>=1.4.0)"]
[[package]] [[package]]
category = "dev"
description = "McCabe checker, plugin for flake8"
name = "mccabe" name = "mccabe"
version = "0.6.1"
description = "McCabe checker, plugin for flake8"
category = "dev"
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" name = "more-itertools"
version = "7.2.0"
description = "More routines for operating on iterables, beyond itertools"
category = "dev"
optional = false optional = false
python-versions = ">=3.4" python-versions = ">=3.4"
version = "7.2.0"
[[package]] [[package]]
category = "dev"
description = "Optional static typing for Python"
name = "mypy" name = "mypy"
version = "0.740"
description = "Optional static typing for Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
version = "0.740"
[package.extras]
dmypy = ["psutil (>=4.0)"]
[package.dependencies] [package.dependencies]
mypy-extensions = ">=0.4.0,<0.5.0" mypy-extensions = ">=0.4.0,<0.5.0"
@@ -111,85 +169,104 @@ typed-ast = ">=1.4.0,<1.5.0"
typing-extensions = ">=3.7.4" typing-extensions = ">=3.7.4"
[[package]] [[package]]
category = "dev"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
name = "mypy-extensions" name = "mypy-extensions"
version = "0.4.3"
description = "Experimental type system extensions for programs checked with the mypy typechecker."
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "0.4.3"
[[package]] [[package]]
category = "dev"
description = "Core utilities for Python packages"
name = "packaging" name = "packaging"
version = "19.2"
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 = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "19.2"
[package.dependencies] [package.dependencies]
pyparsing = ">=2.0.2" pyparsing = ">=2.0.2"
six = "*" six = "*"
[[package]] [[package]]
name = "pathspec"
version = "0.8.0"
description = "Utility library for gitignore style pattern matching of file paths."
category = "dev" category = "dev"
description = "plugin and hook calling mechanisms for python" optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "pluggy" name = "pluggy"
version = "0.13.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 = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "0.13.0"
[package.extras]
dev = ["pre-commit", "tox"]
[package.dependencies] [package.dependencies]
[package.dependencies.importlib-metadata] [package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12" version = ">=0.12"
python = "<3.8"
[[package]] [[package]]
category = "dev"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
name = "py" name = "py"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "1.8.0" version = "1.8.0"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]] [[package]]
category = "dev"
description = "Python style guide checker"
name = "pycodestyle" name = "pycodestyle"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.5.0" version = "2.5.0"
description = "Python style guide checker"
[[package]] category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
[[package]]
name = "pyflakes"
version = "2.1.1"
description = "passive checker of Python programs"
category = "dev" category = "dev"
description = "passive checker of Python programs"
name = "pyflakes"
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 = "2.1.1"
[[package]] [[package]]
category = "main"
description = "a pythonic generic language server (pronounced like \"pie glass\")."
name = "pygls" name = "pygls"
version = "0.8.1"
description = "a pythonic generic language server (pronounced like \"pie glass\")."
category = "main"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "0.8.1"
[package.extras]
dev = ["bandit (1.6.0)", "flake8 (3.7.7)"]
docs = ["sphinx (2.0.1)", "sphinx-rtd-theme (0.4.3)"]
test = ["mock (3.0.5)", "pytest (4.5.0)", "pytest-asyncio (0.10.0)"]
[[package]] [[package]]
category = "main"
description = "Python parsing module"
name = "pyparsing" name = "pyparsing"
version = "2.4.2"
description = "Python parsing module"
category = "main"
optional = false optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
version = "2.4.2"
[[package]] [[package]]
category = "dev"
description = "pytest: simple powerful testing with Python"
name = "pytest" name = "pytest"
version = "5.2.1"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false optional = false
python-versions = ">=3.5" python-versions = ">=3.5"
version = "5.2.1"
[package.extras]
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
[package.dependencies] [package.dependencies]
atomicwrites = ">=1.0" atomicwrites = ">=1.0"
@@ -202,55 +279,70 @@ py = ">=1.5.0"
wcwidth = "*" wcwidth = "*"
[package.dependencies.importlib-metadata] [package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12" version = ">=0.12"
python = "<3.8"
[[package]] [[package]]
category = "dev"
description = "Pytest plugin for measuring coverage."
name = "pytest-cov" name = "pytest-cov"
version = "2.8.1"
description = "Pytest plugin for measuring coverage."
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 = "2.8.1"
[package.extras]
testing = ["fields", "hunter", "process-tests (2.0.2)", "six", "virtualenv"]
[package.dependencies] [package.dependencies]
coverage = ">=4.4" coverage = ">=4.4"
pytest = ">=3.6" pytest = ">=3.6"
[[package]] [[package]]
category = "dev"
description = "pytest plugin for test data directories and files"
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]]
name = "regex"
version = "2020.7.14"
description = "Alternative regular expression module, to replace re."
category = "dev" category = "dev"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "1.12.0"
[[package]]
category = "dev"
description = "Python Library for Tom's Obvious, Minimal Language"
name = "toml"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "0.10.0"
[[package]] [[package]]
name = "six"
version = "1.12.0"
description = "Python 2 and 3 compatibility utilities"
category = "dev" category = "dev"
description = "tox is a generic virtualenv management and test command line tool" optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
[[package]]
name = "toml"
version = "0.10.0"
description = "Python Library for Tom's Obvious, Minimal Language"
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "tox" name = "tox"
version = "3.14.0"
description = "tox is a generic virtualenv management and test command line tool"
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 = "3.14.0"
[package.extras]
docs = ["sphinx (>=2.0.0,<3)", "towncrier (>=18.5.0)", "pygments-github-lexers (>=0.0.5)", "sphinxcontrib-autoprogram (>=0.1.5)"]
testing = ["freezegun (>=0.3.11,<1)", "pathlib2 (>=2.3.3,<3)", "pytest (>=4.0.0,<6)", "pytest-cov (>=2.5.1,<3)", "pytest-mock (>=1.10.0,<2)", "pytest-xdist (>=1.22.2,<2)", "pytest-randomly (>=1.2.3,<2)", "flaky (>=3.4.0,<4)", "psutil (>=5.6.1,<6)"]
[package.dependencies] [package.dependencies]
filelock = ">=3.0.0,<4" filelock = ">=3.0.0,<4"
@@ -262,107 +354,304 @@ toml = ">=0.9.4"
virtualenv = ">=14.0.0" virtualenv = ">=14.0.0"
[package.dependencies.importlib-metadata] [package.dependencies.importlib-metadata]
python = "<3.8"
version = ">=0.12,<1" version = ">=0.12,<1"
python = "<3.8"
[[package]] [[package]]
category = "dev"
description = "a fork of Python 2 and 3 ast modules with type comment support"
name = "typed-ast" name = "typed-ast"
optional = false
python-versions = "*"
version = "1.4.0" version = "1.4.0"
description = "a fork of Python 2 and 3 ast modules with type comment support"
category = "dev"
optional = false
python-versions = "*"
[[package]] [[package]]
category = "dev"
description = "Type Hints for Python"
name = "typing" name = "typing"
version = "3.7.4.1"
description = "Type Hints for Python"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "3.7.4.1"
[[package]] [[package]]
category = "dev"
description = "Backported and Experimental Type Hints for Python 3.5+"
name = "typing-extensions" name = "typing-extensions"
version = "3.7.4"
description = "Backported and Experimental Type Hints for Python 3.5+"
category = "dev"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "3.7.4"
[package.dependencies] [package.dependencies]
typing = ">=3.7.4" typing = ">=3.7.4"
[[package]] [[package]]
category = "dev"
description = "Virtual Python Environment builder"
name = "virtualenv" name = "virtualenv"
version = "16.7.7"
description = "Virtual Python Environment builder"
category = "dev"
optional = false optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
version = "16.7.7"
[package.extras]
docs = ["sphinx (>=1.8.0,<2)", "towncrier (>=18.5.0)", "sphinx-rtd-theme (>=0.4.2,<1)"]
testing = ["pytest (>=4.0.0,<5)", "coverage (>=4.5.0,<5)", "pytest-timeout (>=1.3.0,<2)", "six (>=1.10.0,<2)", "pytest-xdist", "pytest-localserver", "pypiserver", "mock", "xonsh"]
[[package]] [[package]]
category = "dev"
description = "Measures number of Terminal column cells of wide-character codes"
name = "wcwidth" name = "wcwidth"
optional = false
python-versions = "*"
version = "0.1.7" version = "0.1.7"
description = "Measures number of Terminal column cells of wide-character codes"
[[package]]
category = "dev" category = "dev"
description = "A formatter for Python code."
name = "yapf"
optional = false optional = false
python-versions = "*" python-versions = "*"
version = "0.28.0"
[[package]] [[package]]
category = "dev"
description = "Backport of pathlib-compatible object wrapper for zip files"
marker = "python_version < \"3.8\""
name = "zipp" name = "zipp"
version = "0.6.0"
description = "Backport of pathlib-compatible object wrapper for zip files"
category = "dev"
optional = false optional = false
python-versions = ">=2.7" python-versions = ">=2.7"
version = "0.6.0" marker = "python_version < \"3.8\""
[package.extras]
docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"]
testing = ["pathlib2", "contextlib2", "unittest2"]
[package.dependencies] [package.dependencies]
more-itertools = "*" more-itertools = "*"
[metadata] [metadata]
content-hash = "284b539e6199a16441b6196fcbc38a374c886e328ae0c5e8bf07d0aaa47b0670" lock-version = "1.0"
python-versions = "^3.6" python-versions = "^3.6"
content-hash = "2a838d1a4c2f23e2510f2a83e999f268cddf10788031e911324496d6af70a1cc"
[metadata.hashes] [metadata.files]
atomicwrites = ["03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4", "75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"] appdirs = [
attrs = ["08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c", "f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"] {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
colorama = ["05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d", "f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"] {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
coverage = ["0cd13a6e98c37b510a2d34c8281d5e1a226aaf9b65b7d770ef03c63169965351", "1a4b6b6a2a3a6612e6361130c2cc3dc4378d8c221752b96167ccbad94b47f3cd", "2ee55e6dba516ddf6f484aa83ccabbb0adf45a18892204c23486938d12258cde", "3be5338a2eb4ef03c57f20917e1d12a1fd10e3853fed060b6d6b677cb3745898", "44b783b02db03c4777d8cf71bae19eadc171a6f2a96777d916b2c30a1eb3d070", "475bf7c4252af0a56e1abba9606f1e54127cdf122063095c75ab04f6f99cf45e", "47c81ee687eafc2f1db7f03fbe99aab81330565ebc62fb3b61edfc2216a550c8", "4a7f8e72b18f2aca288ff02255ce32cc830bc04d993efbc87abf6beddc9e56c0", "50197163a22fd17f79086e087a787883b3ec9280a509807daf158dfc2a7ded02", "56b13000acf891f700f5067512b804d1ec8c301d627486c678b903859d07f798", "79388ae29c896299b3567965dbcd93255f175c17c6c7bca38614d12718c47466", "79fd5d3d62238c4f583b75d48d53cdae759fe04d4fb18fe8b371d88ad2b6f8be", "7fe3e2fde2bf1d7ce25ebcd2d3de3650b8d60d9a73ce6dcef36e20191291613d", "81042a24f67b96e4287774014fa27220d8a4d91af1043389e4d73892efc89ac6", "81326f1095c53111f8afc95da281e1414185f4a538609a77ca50bdfa39a6c207", "8873dc0d8f42142ea9f20c27bbdc485190fff93823c6795be661703369e5877d", "88d2cbcb0a112f47eef71eb95460b6995da18e6f8ca50c264585abc2c473154b", "91f2491aeab9599956c45a77c5666d323efdec790bfe23fcceafcd91105d585a", "979daa8655ae5a51e8e7a24e7d34e250ae8309fd9719490df92cbb2fe2b0422b", "9c871b006c878a890c6e44a5b2f3c6291335324b298c904dc0402ee92ee1f0be", "a6d092545e5af53e960465f652e00efbf5357adad177b2630d63978d85e46a72", "b5ed7837b923d1d71c4f587ae1539ccd96bfd6be9788f507dbe94dab5febbb5d", "ba259f68250f16d2444cbbfaddaa0bb20e1560a4fdaad50bece25c199e6af864", "be1d89614c6b6c36d7578496dc8625123bda2ff44f224cf8b1c45b810ee7383f", "c1b030a79749aa8d1f1486885040114ee56933b15ccfc90049ba266e4aa2139f", "c95bb147fab76f2ecde332d972d8f4138b8f2daee6c466af4ff3b4f29bd4c19e", "d52c1c2d7e856cecc05aa0526453cb14574f821b7f413cc279b9514750d795c1", "d609a6d564ad3d327e9509846c2c47f170456344521462b469e5cb39e48ba31c", "e1bad043c12fb58e8c7d92b3d7f2f49977dcb80a08a6d1e7a5114a11bf819fca", "e5a675f6829c53c87d79117a8eb656cc4a5f8918185a32fc93ba09778e90f6db", "fec32646b98baf4a22fdceb08703965bd16dea09051fbeb31a04b5b6e72b846c"] ]
entrypoints = ["589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19", "c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"] atomicwrites = [
filelock = ["18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59", "929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"] {file = "atomicwrites-1.3.0-py2.py3-none-any.whl", hash = "sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4"},
flake8 = ["19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548", "8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"] {file = "atomicwrites-1.3.0.tar.gz", hash = "sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"},
importlib-metadata = ["aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", "d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"] ]
isort = ["54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", "6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"] attrs = [
mccabe = ["ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42", "dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"] {file = "attrs-19.3.0-py2.py3-none-any.whl", hash = "sha256:08a96c641c3a74e44eb59afb61a24f2cb9f4d7188748e76ba4bb5edfa3cb7d1c"},
more-itertools = ["409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", "92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"] {file = "attrs-19.3.0.tar.gz", hash = "sha256:f7b7ce16570fe9965acd6d30101a28f62fb4a7f9e926b3bbc9b61f8b04247e72"},
mypy = ["1521c186a3d200c399bd5573c828ea2db1362af7209b2adb1bb8532cea2fb36f", "31a046ab040a84a0fc38bc93694876398e62bc9f35eca8ccbf6418b7297f4c00", "3b1a411909c84b2ae9b8283b58b48541654b918e8513c20a400bb946aa9111ae", "48c8bc99380575deb39f5d3400ebb6a8a1cb5cc669bbba4d3bb30f904e0a0e7d", "540c9caa57a22d0d5d3c69047cc9dd0094d49782603eb03069821b41f9e970e9", "672e418425d957e276c291930a3921b4a6413204f53fe7c37cad7bc57b9a3391", "6ed3b9b3fdc7193ea7aca6f3c20549b377a56f28769783a8f27191903a54170f", "9371290aa2cad5ad133e4cdc43892778efd13293406f7340b9ffe99d5ec7c1d9", "ace6ac1d0f87d4072f05b5468a084a45b4eda970e4d26704f201e06d47ab2990", "b428f883d2b3fe1d052c630642cc6afddd07d5cd7873da948644508be3b9d4a7", "d5bf0e6ec8ba346a2cf35cb55bf4adfddbc6b6576fcc9e10863daa523e418dbb", "d7574e283f83c08501607586b3167728c58e8442947e027d2d4c7dcd6d82f453", "dc889c84241a857c263a2b1cd1121507db7d5b5f5e87e77147097230f374d10b", "f4748697b349f373002656bf32fede706a0e713d67bfdcf04edf39b1f61d46eb"] ]
mypy-extensions = ["090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d", "2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"] black = [
packaging = ["28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47", "d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"] {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"},
pluggy = ["0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6", "fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"] {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"},
py = ["64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa", "dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"] ]
pycodestyle = ["95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56", "e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"] click = [
pyflakes = ["17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0", "d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"] {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"},
pygls = ["3ee878a828b7bc0873a2ea44208d6846a91aa7dbbbdc052e7fe8cc689f6644fa", "780fd0c5ae95ad02ecaf70b071e43ff8ced8384b7d6bed19311a7b431d26fb88"] {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"},
pyparsing = ["6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80", "d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"] ]
pytest = ["7e4800063ccfc306a53c461442526c5571e1462f61583506ce97e4da6a1d88c8", "ca563435f4941d0cb34767301c27bc65c510cb82e90b9ecf9cb52dc2c63caaa0"] colorama = [
pytest-cov = ["cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b", "cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"] {file = "colorama-0.4.1-py2.py3-none-any.whl", hash = "sha256:f8ac84de7840f5b9c4e3347b3c1eaa50f7e49c2b07596221daec5edaabbd7c48"},
pytest-datadir = ["1847ed0efe0bc54cac40ab3fba6d651c2f03d18dd01f2a582979604d32e7621e", "d3af1e738df87515ee509d6135780f25a15959766d9c2b2dbe02bf4fb979cb18"] {file = "colorama-0.4.1.tar.gz", hash = "sha256:05eed71e2e327246ad6b38c540c4a3117230b19679b875190486ddd2d721422d"},
six = ["3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c", "d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"] ]
toml = ["229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c", "235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e", "f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"] coverage = [
tox = ["0bc216b6a2e6afe764476b4a07edf2c1dab99ed82bb146a1130b2e828f5bff5e", "c4f6b319c20ba4913dbfe71ebfd14ff95d1853c4231493608182f66e566ecfe1"] {file = "coverage-5.0-cp27-cp27m-macosx_10_12_x86_64.whl", hash = "sha256:9c871b006c878a890c6e44a5b2f3c6291335324b298c904dc0402ee92ee1f0be"},
typed-ast = ["1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161", "18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e", "262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e", "2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0", "354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c", "48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47", "4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631", "630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4", "66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34", "71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b", "7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2", "838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e", "95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a", "bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233", "cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1", "d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36", "d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d", "d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a", "fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66", "ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"] {file = "coverage-5.0-cp27-cp27m-macosx_10_13_intel.whl", hash = "sha256:e5a675f6829c53c87d79117a8eb656cc4a5f8918185a32fc93ba09778e90f6db"},
typing = ["91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23", "c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36", "f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"] {file = "coverage-5.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:81326f1095c53111f8afc95da281e1414185f4a538609a77ca50bdfa39a6c207"},
typing-extensions = ["2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95", "b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87", "d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"] {file = "coverage-5.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:8873dc0d8f42142ea9f20c27bbdc485190fff93823c6795be661703369e5877d"},
virtualenv = ["11cb4608930d5fd3afb545ecf8db83fa50e1f96fc4fca80c94b07d2c83146589", "d257bb3773e48cac60e475a19b608996c73f4d333b3ba2e4e57d5ac6134e0136"] {file = "coverage-5.0-cp27-cp27m-win32.whl", hash = "sha256:44b783b02db03c4777d8cf71bae19eadc171a6f2a96777d916b2c30a1eb3d070"},
wcwidth = ["3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", "f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"] {file = "coverage-5.0-cp27-cp27m-win_amd64.whl", hash = "sha256:d52c1c2d7e856cecc05aa0526453cb14574f821b7f413cc279b9514750d795c1"},
yapf = ["02ace10a00fa2e36c7ebd1df2ead91dbfbd7989686dc4ccbdc549e95d19f5780", "6f94b6a176a7c114cfa6bad86d40f259bbe0f10cf2fa7f2f4b3596fc5802a41b"] {file = "coverage-5.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:ba259f68250f16d2444cbbfaddaa0bb20e1560a4fdaad50bece25c199e6af864"},
zipp = ["3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e", "f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"] {file = "coverage-5.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:475bf7c4252af0a56e1abba9606f1e54127cdf122063095c75ab04f6f99cf45e"},
{file = "coverage-5.0-cp35-cp35m-macosx_10_12_x86_64.whl", hash = "sha256:91f2491aeab9599956c45a77c5666d323efdec790bfe23fcceafcd91105d585a"},
{file = "coverage-5.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:979daa8655ae5a51e8e7a24e7d34e250ae8309fd9719490df92cbb2fe2b0422b"},
{file = "coverage-5.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:1a4b6b6a2a3a6612e6361130c2cc3dc4378d8c221752b96167ccbad94b47f3cd"},
{file = "coverage-5.0-cp35-cp35m-win32.whl", hash = "sha256:56b13000acf891f700f5067512b804d1ec8c301d627486c678b903859d07f798"},
{file = "coverage-5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:81042a24f67b96e4287774014fa27220d8a4d91af1043389e4d73892efc89ac6"},
{file = "coverage-5.0-cp36-cp36m-macosx_10_13_x86_64.whl", hash = "sha256:fec32646b98baf4a22fdceb08703965bd16dea09051fbeb31a04b5b6e72b846c"},
{file = "coverage-5.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:7fe3e2fde2bf1d7ce25ebcd2d3de3650b8d60d9a73ce6dcef36e20191291613d"},
{file = "coverage-5.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:be1d89614c6b6c36d7578496dc8625123bda2ff44f224cf8b1c45b810ee7383f"},
{file = "coverage-5.0-cp36-cp36m-win32.whl", hash = "sha256:47c81ee687eafc2f1db7f03fbe99aab81330565ebc62fb3b61edfc2216a550c8"},
{file = "coverage-5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:3be5338a2eb4ef03c57f20917e1d12a1fd10e3853fed060b6d6b677cb3745898"},
{file = "coverage-5.0-cp37-cp37m-macosx_10_13_x86_64.whl", hash = "sha256:79388ae29c896299b3567965dbcd93255f175c17c6c7bca38614d12718c47466"},
{file = "coverage-5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4a7f8e72b18f2aca288ff02255ce32cc830bc04d993efbc87abf6beddc9e56c0"},
{file = "coverage-5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d609a6d564ad3d327e9509846c2c47f170456344521462b469e5cb39e48ba31c"},
{file = "coverage-5.0-cp37-cp37m-win32.whl", hash = "sha256:50197163a22fd17f79086e087a787883b3ec9280a509807daf158dfc2a7ded02"},
{file = "coverage-5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:b5ed7837b923d1d71c4f587ae1539ccd96bfd6be9788f507dbe94dab5febbb5d"},
{file = "coverage-5.0-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:c95bb147fab76f2ecde332d972d8f4138b8f2daee6c466af4ff3b4f29bd4c19e"},
{file = "coverage-5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:0cd13a6e98c37b510a2d34c8281d5e1a226aaf9b65b7d770ef03c63169965351"},
{file = "coverage-5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:88d2cbcb0a112f47eef71eb95460b6995da18e6f8ca50c264585abc2c473154b"},
{file = "coverage-5.0-cp38-cp38m-win32.whl", hash = "sha256:2ee55e6dba516ddf6f484aa83ccabbb0adf45a18892204c23486938d12258cde"},
{file = "coverage-5.0-cp38-cp38m-win_amd64.whl", hash = "sha256:a6d092545e5af53e960465f652e00efbf5357adad177b2630d63978d85e46a72"},
{file = "coverage-5.0-cp39-cp39m-win32.whl", hash = "sha256:79fd5d3d62238c4f583b75d48d53cdae759fe04d4fb18fe8b371d88ad2b6f8be"},
{file = "coverage-5.0-cp39-cp39m-win_amd64.whl", hash = "sha256:c1b030a79749aa8d1f1486885040114ee56933b15ccfc90049ba266e4aa2139f"},
{file = "coverage-5.0.tar.gz", hash = "sha256:e1bad043c12fb58e8c7d92b3d7f2f49977dcb80a08a6d1e7a5114a11bf819fca"},
]
entrypoints = [
{file = "entrypoints-0.3-py2.py3-none-any.whl", hash = "sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19"},
{file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"},
]
filelock = [
{file = "filelock-3.0.12-py3-none-any.whl", hash = "sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"},
{file = "filelock-3.0.12.tar.gz", hash = "sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59"},
]
flake8 = [
{file = "flake8-3.7.8-py2.py3-none-any.whl", hash = "sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"},
{file = "flake8-3.7.8.tar.gz", hash = "sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548"},
]
importlib-metadata = [
{file = "importlib_metadata-0.23-py2.py3-none-any.whl", hash = "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"},
{file = "importlib_metadata-0.23.tar.gz", hash = "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26"},
]
isort = [
{file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"},
{file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"},
]
mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
more-itertools = [
{file = "more-itertools-7.2.0.tar.gz", hash = "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832"},
{file = "more_itertools-7.2.0-py3-none-any.whl", hash = "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4"},
]
mypy = [
{file = "mypy-0.740-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:9371290aa2cad5ad133e4cdc43892778efd13293406f7340b9ffe99d5ec7c1d9"},
{file = "mypy-0.740-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b428f883d2b3fe1d052c630642cc6afddd07d5cd7873da948644508be3b9d4a7"},
{file = "mypy-0.740-cp35-cp35m-win_amd64.whl", hash = "sha256:ace6ac1d0f87d4072f05b5468a084a45b4eda970e4d26704f201e06d47ab2990"},
{file = "mypy-0.740-cp36-cp36m-macosx_10_6_x86_64.whl", hash = "sha256:d7574e283f83c08501607586b3167728c58e8442947e027d2d4c7dcd6d82f453"},
{file = "mypy-0.740-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d5bf0e6ec8ba346a2cf35cb55bf4adfddbc6b6576fcc9e10863daa523e418dbb"},
{file = "mypy-0.740-cp36-cp36m-win_amd64.whl", hash = "sha256:1521c186a3d200c399bd5573c828ea2db1362af7209b2adb1bb8532cea2fb36f"},
{file = "mypy-0.740-cp37-cp37m-macosx_10_6_x86_64.whl", hash = "sha256:dc889c84241a857c263a2b1cd1121507db7d5b5f5e87e77147097230f374d10b"},
{file = "mypy-0.740-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:6ed3b9b3fdc7193ea7aca6f3c20549b377a56f28769783a8f27191903a54170f"},
{file = "mypy-0.740-cp37-cp37m-win_amd64.whl", hash = "sha256:31a046ab040a84a0fc38bc93694876398e62bc9f35eca8ccbf6418b7297f4c00"},
{file = "mypy-0.740-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:672e418425d957e276c291930a3921b4a6413204f53fe7c37cad7bc57b9a3391"},
{file = "mypy-0.740-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:3b1a411909c84b2ae9b8283b58b48541654b918e8513c20a400bb946aa9111ae"},
{file = "mypy-0.740-cp38-cp38-win_amd64.whl", hash = "sha256:540c9caa57a22d0d5d3c69047cc9dd0094d49782603eb03069821b41f9e970e9"},
{file = "mypy-0.740-py3-none-any.whl", hash = "sha256:f4748697b349f373002656bf32fede706a0e713d67bfdcf04edf39b1f61d46eb"},
{file = "mypy-0.740.tar.gz", hash = "sha256:48c8bc99380575deb39f5d3400ebb6a8a1cb5cc669bbba4d3bb30f904e0a0e7d"},
]
mypy-extensions = [
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
]
packaging = [
{file = "packaging-19.2-py2.py3-none-any.whl", hash = "sha256:d9551545c6d761f3def1677baf08ab2a3ca17c56879e70fecba2fc4dde4ed108"},
{file = "packaging-19.2.tar.gz", hash = "sha256:28b924174df7a2fa32c1953825ff29c61e2f5e082343165438812f00d3a7fc47"},
]
pathspec = [
{file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"},
{file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"},
]
pluggy = [
{file = "pluggy-0.13.0-py2.py3-none-any.whl", hash = "sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6"},
{file = "pluggy-0.13.0.tar.gz", hash = "sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"},
]
py = [
{file = "py-1.8.0-py2.py3-none-any.whl", hash = "sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa"},
{file = "py-1.8.0.tar.gz", hash = "sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"},
]
pycodestyle = [
{file = "pycodestyle-2.5.0-py2.py3-none-any.whl", hash = "sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56"},
{file = "pycodestyle-2.5.0.tar.gz", hash = "sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"},
]
pyflakes = [
{file = "pyflakes-2.1.1-py2.py3-none-any.whl", hash = "sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0"},
{file = "pyflakes-2.1.1.tar.gz", hash = "sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"},
]
pygls = [
{file = "pygls-0.8.1-py3-none-any.whl", hash = "sha256:3ee878a828b7bc0873a2ea44208d6846a91aa7dbbbdc052e7fe8cc689f6644fa"},
{file = "pygls-0.8.1.tar.gz", hash = "sha256:780fd0c5ae95ad02ecaf70b071e43ff8ced8384b7d6bed19311a7b431d26fb88"},
]
pyparsing = [
{file = "pyparsing-2.4.2-py2.py3-none-any.whl", hash = "sha256:d9338df12903bbf5d65a0e4e87c2161968b10d2e489652bb47001d82a9b028b4"},
{file = "pyparsing-2.4.2.tar.gz", hash = "sha256:6f98a7b9397e206d78cc01df10131398f1c8b8510a2f4d97d9abd82e1aacdd80"},
]
pytest = [
{file = "pytest-5.2.1-py3-none-any.whl", hash = "sha256:7e4800063ccfc306a53c461442526c5571e1462f61583506ce97e4da6a1d88c8"},
{file = "pytest-5.2.1.tar.gz", hash = "sha256:ca563435f4941d0cb34767301c27bc65c510cb82e90b9ecf9cb52dc2c63caaa0"},
]
pytest-cov = [
{file = "pytest-cov-2.8.1.tar.gz", hash = "sha256:cc6742d8bac45070217169f5f72ceee1e0e55b0221f54bcf24845972d3a47f2b"},
{file = "pytest_cov-2.8.1-py2.py3-none-any.whl", hash = "sha256:cdbdef4f870408ebdbfeb44e63e07eb18bb4619fae852f6e760645fa36172626"},
]
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"},
]
regex = [
{file = "regex-2020.7.14-cp27-cp27m-win32.whl", hash = "sha256:e46d13f38cfcbb79bfdb2964b0fe12561fe633caf964a77a5f8d4e45fe5d2ef7"},
{file = "regex-2020.7.14-cp27-cp27m-win_amd64.whl", hash = "sha256:6961548bba529cac7c07af2fd4d527c5b91bb8fe18995fed6044ac22b3d14644"},
{file = "regex-2020.7.14-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c50a724d136ec10d920661f1442e4a8b010a4fe5aebd65e0c2241ea41dbe93dc"},
{file = "regex-2020.7.14-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8a51f2c6d1f884e98846a0a9021ff6861bdb98457879f412fdc2b42d14494067"},
{file = "regex-2020.7.14-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9c568495e35599625f7b999774e29e8d6b01a6fb684d77dee1f56d41b11b40cd"},
{file = "regex-2020.7.14-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:51178c738d559a2d1071ce0b0f56e57eb315bcf8f7d4cf127674b533e3101f88"},
{file = "regex-2020.7.14-cp36-cp36m-win32.whl", hash = "sha256:9eddaafb3c48e0900690c1727fba226c4804b8e6127ea409689c3bb492d06de4"},
{file = "regex-2020.7.14-cp36-cp36m-win_amd64.whl", hash = "sha256:14a53646369157baa0499513f96091eb70382eb50b2c82393d17d7ec81b7b85f"},
{file = "regex-2020.7.14-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:1269fef3167bb52631ad4fa7dd27bf635d5a0790b8e6222065d42e91bede4162"},
{file = "regex-2020.7.14-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d0a5095d52b90ff38592bbdc2644f17c6d495762edf47d876049cfd2968fbccf"},
{file = "regex-2020.7.14-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:4c037fd14c5f4e308b8370b447b469ca10e69427966527edcab07f52d88388f7"},
{file = "regex-2020.7.14-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bc3d98f621898b4a9bc7fecc00513eec8f40b5b83913d74ccb445f037d58cd89"},
{file = "regex-2020.7.14-cp37-cp37m-win32.whl", hash = "sha256:46bac5ca10fb748d6c55843a931855e2727a7a22584f302dd9bb1506e69f83f6"},
{file = "regex-2020.7.14-cp37-cp37m-win_amd64.whl", hash = "sha256:0dc64ee3f33cd7899f79a8d788abfbec168410be356ed9bd30bbd3f0a23a7204"},
{file = "regex-2020.7.14-cp38-cp38-manylinux1_i686.whl", hash = "sha256:5ea81ea3dbd6767873c611687141ec7b06ed8bab43f68fad5b7be184a920dc99"},
{file = "regex-2020.7.14-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bbb332d45b32df41200380fff14712cb6093b61bd142272a10b16778c418e98e"},
{file = "regex-2020.7.14-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:c11d6033115dc4887c456565303f540c44197f4fc1a2bfb192224a301534888e"},
{file = "regex-2020.7.14-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:75aaa27aa521a182824d89e5ab0a1d16ca207318a6b65042b046053cfc8ed07a"},
{file = "regex-2020.7.14-cp38-cp38-win32.whl", hash = "sha256:d6cff2276e502b86a25fd10c2a96973fdb45c7a977dca2138d661417f3728341"},
{file = "regex-2020.7.14-cp38-cp38-win_amd64.whl", hash = "sha256:7a2dd66d2d4df34fa82c9dc85657c5e019b87932019947faece7983f2089a840"},
{file = "regex-2020.7.14.tar.gz", hash = "sha256:3a3af27a8d23143c49a3420efe5b3f8cf1a48c6fc8bc6856b03f638abc1833bb"},
]
six = [
{file = "six-1.12.0-py2.py3-none-any.whl", hash = "sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c"},
{file = "six-1.12.0.tar.gz", hash = "sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"},
]
toml = [
{file = "toml-0.10.0-py2.7.egg", hash = "sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"},
{file = "toml-0.10.0-py2.py3-none-any.whl", hash = "sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e"},
{file = "toml-0.10.0.tar.gz", hash = "sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c"},
]
tox = [
{file = "tox-3.14.0-py2.py3-none-any.whl", hash = "sha256:0bc216b6a2e6afe764476b4a07edf2c1dab99ed82bb146a1130b2e828f5bff5e"},
{file = "tox-3.14.0.tar.gz", hash = "sha256:c4f6b319c20ba4913dbfe71ebfd14ff95d1853c4231493608182f66e566ecfe1"},
]
typed-ast = [
{file = "typed_ast-1.4.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:262c247a82d005e43b5b7f69aff746370538e176131c32dda9cb0f324d27141e"},
{file = "typed_ast-1.4.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:71211d26ffd12d63a83e079ff258ac9d56a1376a25bc80b1cdcdf601b855b90b"},
{file = "typed_ast-1.4.0-cp35-cp35m-win32.whl", hash = "sha256:630968c5cdee51a11c05a30453f8cd65e0cc1d2ad0d9192819df9978984529f4"},
{file = "typed_ast-1.4.0-cp35-cp35m-win_amd64.whl", hash = "sha256:ffde2fbfad571af120fcbfbbc61c72469e72f550d676c3342492a9dfdefb8f12"},
{file = "typed_ast-1.4.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4e0b70c6fc4d010f8107726af5fd37921b666f5b31d9331f0bd24ad9a088e631"},
{file = "typed_ast-1.4.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:bc6c7d3fa1325a0c6613512a093bc2a2a15aeec350451cbdf9e1d4bffe3e3233"},
{file = "typed_ast-1.4.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:cc34a6f5b426748a507dd5d1de4c1978f2eb5626d51326e43280941206c209e1"},
{file = "typed_ast-1.4.0-cp36-cp36m-win32.whl", hash = "sha256:d896919306dd0aa22d0132f62a1b78d11aaf4c9fc5b3410d3c666b818191630a"},
{file = "typed_ast-1.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:354c16e5babd09f5cb0ee000d54cfa38401d8b8891eefa878ac772f827181a3c"},
{file = "typed_ast-1.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95bd11af7eafc16e829af2d3df510cecfd4387f6453355188342c3e79a2ec87a"},
{file = "typed_ast-1.4.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:18511a0b3e7922276346bcb47e2ef9f38fb90fd31cb9223eed42c85d1312344e"},
{file = "typed_ast-1.4.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d7c45933b1bdfaf9f36c579671fec15d25b06c8398f113dab64c18ed1adda01d"},
{file = "typed_ast-1.4.0-cp37-cp37m-win32.whl", hash = "sha256:d755f03c1e4a51e9b24d899561fec4ccaf51f210d52abdf8c07ee2849b212a36"},
{file = "typed_ast-1.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:2b907eb046d049bcd9892e3076c7a6456c93a25bebfe554e931620c90e6a25b0"},
{file = "typed_ast-1.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fdc1c9bbf79510b76408840e009ed65958feba92a88833cdceecff93ae8fff66"},
{file = "typed_ast-1.4.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:7954560051331d003b4e2b3eb822d9dd2e376fa4f6d98fee32f452f52dd6ebb2"},
{file = "typed_ast-1.4.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:48e5b1e71f25cfdef98b013263a88d7145879fbb2d5185f2a0c79fa7ebbeae47"},
{file = "typed_ast-1.4.0-cp38-cp38-win32.whl", hash = "sha256:1170afa46a3799e18b4c977777ce137bb53c7485379d9706af8a59f2ea1aa161"},
{file = "typed_ast-1.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:838997f4310012cf2e1ad3803bce2f3402e9ffb71ded61b5ee22617b3a7f6b6e"},
{file = "typed_ast-1.4.0.tar.gz", hash = "sha256:66480f95b8167c9c5c5c87f32cf437d585937970f3fc24386f313a4c97b44e34"},
]
typing = [
{file = "typing-3.7.4.1-py2-none-any.whl", hash = "sha256:c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36"},
{file = "typing-3.7.4.1-py3-none-any.whl", hash = "sha256:f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"},
{file = "typing-3.7.4.1.tar.gz", hash = "sha256:91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23"},
]
typing-extensions = [
{file = "typing_extensions-3.7.4-py2-none-any.whl", hash = "sha256:b1edbbf0652660e32ae780ac9433f4231e7339c7f9a8057d0f042fcbcea49b87"},
{file = "typing_extensions-3.7.4-py3-none-any.whl", hash = "sha256:d8179012ec2c620d3791ca6fe2bf7979d979acdbef1fca0bc56b37411db682ed"},
{file = "typing_extensions-3.7.4.tar.gz", hash = "sha256:2ed632b30bb54fc3941c382decfd0ee4148f5c591651c9272473fea2c6397d95"},
]
virtualenv = [
{file = "virtualenv-16.7.7-py2.py3-none-any.whl", hash = "sha256:11cb4608930d5fd3afb545ecf8db83fa50e1f96fc4fca80c94b07d2c83146589"},
{file = "virtualenv-16.7.7.tar.gz", hash = "sha256:d257bb3773e48cac60e475a19b608996c73f4d333b3ba2e4e57d5ac6134e0136"},
]
wcwidth = [
{file = "wcwidth-0.1.7-py2.py3-none-any.whl", hash = "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c"},
{file = "wcwidth-0.1.7.tar.gz", hash = "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e"},
]
zipp = [
{file = "zipp-0.6.0-py2.py3-none-any.whl", hash = "sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"},
{file = "zipp-0.6.0.tar.gz", hash = "sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e"},
]

View File

@@ -26,11 +26,11 @@ pyparsing = "^2.4"
flake8 = "^3.7" flake8 = "^3.7"
mypy = "^0.740.0" mypy = "^0.740.0"
pytest = "^5.2" pytest = "^5.2"
yapf = "^0.28.0"
pytest-datadir = "^1.3" pytest-datadir = "^1.3"
tox = "^3.14" tox = "^3.14"
isort = "^4.3" isort = "^4.3"
pytest-cov = "^2.8" pytest-cov = "^2.8"
black = "^19.10b0"
[tool.poetry.scripts] [tool.poetry.scripts]
cmake-format = "cmake_language_server.formatter:main" cmake-format = "cmake_language_server.formatter:main"

View File

@@ -1 +1 @@
__version__ = '0.1.2' __version__ = "0.1.2"

View File

@@ -12,10 +12,10 @@ logger = logging.getLogger(__name__)
def _tidy_doc(doc: str) -> str: def _tidy_doc(doc: str) -> str:
doc = doc.strip() doc = doc.strip()
doc = re.sub(r':.+?:`(.+?)`', r'\1', doc) doc = re.sub(r":.+?:`(.+?)`", r"\1", doc)
doc = re.sub(r'``([^`]+)``', r'`\1`', doc) doc = re.sub(r"``([^`]+)``", r"`\1`", doc)
doc = doc.replace('\n', ' ') doc = doc.replace("\n", " ")
doc = doc.replace('. ', '. ') doc = doc.replace(". ", ". ")
return doc return doc
@@ -49,78 +49,82 @@ class API(object):
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, str(self._build)], proc = subprocess.run(
stdout=subprocess.PIPE, [self._cmake, str(self._build)],
stderr=subprocess.PIPE, stdout=subprocess.PIPE,
encoding='utf-8', stderr=subprocess.PIPE,
universal_newlines=True) 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' reply = self._build / ".cmake" / "api" / "v1" / "reply"
indices = sorted(reply.glob('index-*.json')) 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):
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):
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):
'''inspect generated list files''' """inspect generated list files"""
if not self._builtin_variables or self._generated_list_parsed: if not self._builtin_variables or self._generated_list_parsed:
return return
@@ -130,44 +134,46 @@ class API(object):
# inspect generated list files # inspect generated list files
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( p = subprocess.run(
[self._cmake, '-P', str(tmplist)], [self._cmake, "-P", str(tmplist)],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, stderr=subprocess.PIPE,
cwd=cmake_files['paths']['source'], cwd=cmake_files["paths"]["source"],
encoding='utf-8', encoding="utf-8",
universal_newlines=True) 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
@@ -177,12 +183,19 @@ 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()
@@ -190,81 +203,95 @@ endforeach()
self._parse_modules() self._parse_modules()
def _parse_commands(self) -> None: def _parse_commands(self) -> None:
p = subprocess.run([self._cmake, '--help-commands'], p = subprocess.run(
stdout=subprocess.PIPE, [self._cmake, "--help-commands"],
encoding='utf-8', 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+?
[\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'], p = subprocess.run(
stdout=subprocess.PIPE, [self._cmake, "--help-variables"],
encoding='utf-8', 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 = _tidy_doc(match.group('doc')) doc = _tidy_doc(match.group("doc"))
if variable == 'CMAKE_MATCH_<n>': 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: def _parse_modules(self) -> None:
p = subprocess.run([self._cmake, '--help-modules'], p = subprocess.run(
stdout=subprocess.PIPE, [self._cmake, "--help-modules"],
encoding='utf-8', 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<module>.+)\n (?P<module>.+)\n
-+\n+? -+\n+?
(?:(?P<header>\w[\w\s]+)\n\^+\n+?)? (?:(?P<header>\w[\w\s]+)\n\^+\n+?)?
(?P<doc>.(?:.|\n)+?\n\n) (?P<doc>.(?:.|\n)+?\n\n)
''', p.stdout + '\n\n', re.VERBOSE) """,
p.stdout + "\n\n",
re.VERBOSE,
)
self._builtin_modules.clear() self._builtin_modules.clear()
for match in matches: for match in matches:
module = match.group('module') module = match.group("module")
header = match.group('header') header = match.group("header")
doc = _tidy_doc(match.group('doc')) doc = _tidy_doc(match.group("doc"))
if header is not None and header != 'Overview': if header is not None and header != "Overview":
doc = '' doc = ""
self._builtin_modules[module] = doc self._builtin_modules[module] = doc
def get_command_doc(self, command: str) -> Optional[str]: def get_command_doc(self, command: str) -> Optional[str]:
@@ -281,28 +308,27 @@ 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]: def get_module_doc(self, module: str, package: bool) -> Optional[str]:
if package: if package:
return self._builtin_modules.get('Find' + module) return self._builtin_modules.get("Find" + module)
return self._builtin_modules.get(module) return self._builtin_modules.get(module)
def search_module(self, module: str, package: bool) -> List[str]: def search_module(self, module: str, package: bool) -> List[str]:
if package: if package:
module = 'Find' + module module = "Find" + module
return [ return [x[4:] for x in self._builtin_modules if x.startswith(module)]
x[4:] for x in self._builtin_modules if x.startswith(module)
]
return [ return [
x for x in self._builtin_modules x
if x.startswith(module) and not x.startswith('Find') 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]:
@@ -310,4 +336,4 @@ endforeach()
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 "...")

View File

@@ -7,39 +7,51 @@ class Formatter(object):
indnt: str indnt: str
lower_identifier: bool lower_identifier: bool
def __init__(self, indent=' ', lower_identifier=True): def __init__(self, indent=" ", lower_identifier=True):
self.indent = indent self.indent = indent
self.lower_identifier = lower_identifier self.lower_identifier = lower_identifier
def format(self, tokens: TokenList) -> str: def format(self, tokens: TokenList) -> str:
cmds: List[str] = [''] cmds: List[str] = [""]
indnet_level = 0 indnet_level = 0
for token in tokens: for token in tokens:
if isinstance(token, tuple): if isinstance(token, tuple):
raw_identifier = token[0] raw_identifier = token[0]
identifier = raw_identifier.lower() identifier = raw_identifier.lower()
if identifier in ('elseif', 'else', 'endif', 'endforeach', if identifier in (
'endwhile', 'endmacro', 'endfunction'): "elseif",
"else",
"endif",
"endforeach",
"endwhile",
"endmacro",
"endfunction",
):
if indnet_level > 0: if indnet_level > 0:
indnet_level -= 1 indnet_level -= 1
cmds[-1] = self.indent * indnet_level cmds[-1] = self.indent * indnet_level
cmds[-1] += (identifier cmds[-1] += identifier if self.lower_identifier else raw_identifier
if self.lower_identifier else raw_identifier)
args = self._format_args(token[1]) args = self._format_args(token[1])
if len(args) < 2: if len(args) < 2:
cmds[-1] += '(' + ''.join(args) + ')' cmds[-1] += "(" + "".join(args) + ")"
else: else:
cmds[-1] += '(\n' cmds[-1] += "(\n"
for arg in args: for arg in args:
cmds[-1] += self.indent * (indnet_level + cmds[-1] += self.indent * (indnet_level + 1) + arg + "\n"
1) + arg + '\n' cmds[-1] += self.indent * indnet_level + ")"
cmds[-1] += self.indent * indnet_level + ')' if identifier in (
if identifier in ('if', 'elseif', 'else', 'foreach', 'while', "if",
'macro', 'function'): "elseif",
"else",
"foreach",
"while",
"macro",
"function",
):
indnet_level += 1 indnet_level += 1
elif token == '\n': elif token == "\n":
cmds.append('') cmds.append("")
elif token[0] == '#': elif token[0] == "#":
if cmds[-1]: if cmds[-1]:
cmds[-1] += token cmds[-1] += token
else: else:
@@ -48,70 +60,67 @@ class Formatter(object):
cmds[-1] += token cmds[-1] += token
cmds = self._strip_line(cmds) cmds = self._strip_line(cmds)
return '\n'.join(cmds) + '\n' return "\n".join(cmds) + "\n"
def _format_args(self, args: List[str]) -> List[str]: def _format_args(self, args: List[str]) -> List[str]:
lines = [''] lines = [""]
for i in range(len(args)): for i in range(len(args)):
arg = args[i] arg = args[i]
if arg[0] == '#': if arg[0] == "#":
lines[-1] += arg lines[-1] += arg
elif arg[0] == '\n': elif arg[0] == "\n":
lines.append('') lines.append("")
elif arg.isspace(): elif arg.isspace():
if lines[-1]: if lines[-1]:
if i + 1 < len(args) and args[i + 1][0] == '#': if i + 1 < len(args) and args[i + 1][0] == "#":
lines[-1] += arg lines[-1] += arg
else: else:
lines[-1] += ' ' lines[-1] += " "
else: else:
lines[-1] += arg lines[-1] += arg
return self._strip_line(lines) return self._strip_line(lines)
def _strip_line(self, lines: List[str]) -> List[str]: def _strip_line(self, lines: List[str]) -> List[str]:
'''Delete empty lines at the start/end of the input''' """Delete empty lines at the start/end of the input"""
ret: List[str] = [] ret: List[str] = []
for line in lines: for line in lines:
line = line.rstrip() line = line.rstrip()
if line != '' or len(ret) > 0: if line != "" or len(ret) > 0:
ret.append(line) ret.append(line)
while ret and ret[-1] == '': while ret and ret[-1] == "":
del ret[-1] del ret[-1]
return ret return ret
def main(args: List[str] = None): def main(args: List[str] = None):
import sys
from argparse import ArgumentParser from argparse import ArgumentParser
from difflib import unified_diff from difflib import unified_diff
from pathlib import Path from pathlib import Path
import sys
from . import __version__ from . import __version__
from .parser import ListParser from .parser import ListParser
parser = ArgumentParser( parser = ArgumentParser(
description='Format CMake list files.', description="Format CMake list files.",
epilog=''' epilog="""
If no arguments are specified, it formats the code from If no arguments are specified, it formats the code from
standard input and writes the result to the standard output.''', standard input and writes the result to the standard output.""",
) )
parser.add_argument('lists', type=Path, nargs='*', help='CMake list files') parser.add_argument("lists", type=Path, nargs="*", help="CMake list files")
group = parser.add_mutually_exclusive_group() group = parser.add_mutually_exclusive_group()
group.add_argument('-i', group.add_argument("-i", "--inplace", action="store_true", help="inplace edit")
'--inplace', group.add_argument("-d", "--diff", action="store_true", help="show diff")
action='store_true', parser.add_argument(
help='inplace edit') "--version", action="version", version=f"%(prog)s {__version__}"
group.add_argument('-d', '--diff', action='store_true', help='show diff') )
parser.add_argument('--version',
action='version',
version=f'%(prog)s {__version__}')
args = parser.parse_args(args) args = parser.parse_args(args)
if not args.lists and args.inplace: if not args.lists and args.inplace:
print('error: cannot use -i when no arguments are specified.', print("error: cannot use -i when no arguments are specified.", file=sys.stderr)
file=sys.stderr)
return return
if not args.lists: if not args.lists:
args.lists.append(None) args.lists.append(None)
@@ -120,7 +129,7 @@ def main(args: List[str] = None):
formatter = Formatter() formatter = Formatter()
for listpath in args.lists: for listpath in args.lists:
if listpath is None: if listpath is None:
listpath = '(stdin)' listpath = "(stdin)"
content = sys.stdin.read() content = sys.stdin.read()
else: else:
with listpath.open() as fp: with listpath.open() as fp:
@@ -130,14 +139,18 @@ def main(args: List[str] = None):
if args.inplace: if args.inplace:
if not remain: if not remain:
with listpath.open('w') as fp: with listpath.open("w") as fp:
fp.write(formatted) fp.write(formatted)
elif args.diff: elif args.diff:
diff = unified_diff(content.splitlines(True), diff = unified_diff(
formatted.splitlines(True), str(listpath), content.splitlines(True),
str(listpath), '(before formatting)', formatted.splitlines(True),
'(after formatting)') str(listpath),
diffstr = ''.join(diff) str(listpath),
print(diffstr, end='') "(before formatting)",
"(after formatting)",
)
diffstr = "".join(diff)
print(diffstr, end="")
else: else:
print(formatted, end='') print(formatted, end="")

View File

@@ -11,8 +11,8 @@ class ListParser(object):
_parser: pp.ParserElement _parser: pp.ParserElement
def __init__(self): def __init__(self):
newline = '\n' newline = "\n"
space_plus = pp.Regex('[ \t]+') space_plus = pp.Regex("[ \t]+")
space_star = pp.Optional(space_plus) space_star = pp.Optional(space_plus)
quoted_element = pp.Regex(r'[^\\"]|\\[^A-Za-z0-9]|\\[trn]') quoted_element = pp.Regex(r'[^\\"]|\\[^A-Za-z0-9]|\\[trn]')
@@ -22,10 +22,10 @@ class ListParser(object):
def action_bracket_open(tokens: pp.ParseResults): def action_bracket_open(tokens: pp.ParseResults):
nonlocal bracket_content nonlocal bracket_content
marker = ']' + '=' * (len(tokens[0]) - 2) + ']' marker = "]" + "=" * (len(tokens[0]) - 2) + "]"
bracket_content <<= pp.SkipTo(marker, include=True) bracket_content <<= pp.SkipTo(marker, include=True)
bracket_open = pp.Regex(r'\[=*\[').setParseAction(action_bracket_open) bracket_open = pp.Regex(r"\[=*\[").setParseAction(action_bracket_open)
bracket_argument = pp.Combine(bracket_open + bracket_content) bracket_argument = pp.Combine(bracket_open + bracket_content)
unquoted_element = pp.Regex(r'[^\s()#"\\]|\\[^A-Za-z0-9]|\\[trn]') unquoted_element = pp.Regex(r'[^\s()#"\\]|\\[^A-Za-z0-9]|\\[trn]')
@@ -33,25 +33,29 @@ class ListParser(object):
argument = bracket_argument | quoted_argument | unquoted_argument argument = bracket_argument | quoted_argument | unquoted_argument
line_comment = pp.Combine('#' + ~bracket_open + line_comment = pp.Combine("#" + ~bracket_open + pp.SkipTo(pp.LineEnd()))
pp.SkipTo(pp.LineEnd())) bracket_comment = pp.Combine("#" + bracket_argument)
bracket_comment = pp.Combine('#' + bracket_argument) line_ending = (
line_ending = (space_star + space_star
pp.ZeroOrMore(bracket_comment + space_star) + + pp.ZeroOrMore(bracket_comment + space_star)
pp.Optional(line_comment) + (newline | pp.lineEnd)) + pp.Optional(line_comment)
+ (newline | pp.lineEnd)
)
identifier = pp.Word(pp.alphas + '_', pp.alphanums + '_') identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_")
arguments = pp.Forward() arguments = pp.Forward()
arguments << pp.ZeroOrMore(argument | line_ending | space_plus arguments << pp.ZeroOrMore(
| '(' + arguments + ')').leaveWhitespace() argument | line_ending | space_plus | "(" + arguments + ")"
).leaveWhitespace()
arguments = pp.Group(arguments) arguments = pp.Group(arguments)
PAREN_L, PAREN_R = map(pp.Suppress, '()') PAREN_L, PAREN_R = map(pp.Suppress, "()")
command_invocation = ( command_invocation = (
identifier + space_star.suppress() + PAREN_L + arguments + identifier + space_star.suppress() + PAREN_L + arguments + PAREN_R
PAREN_R).setParseAction(lambda t: (t[0], t[1].asList())) ).setParseAction(lambda t: (t[0], t[1].asList()))
file_element = (space_star + command_invocation + line_ending file_element = (
| line_ending).leaveWhitespace() space_star + command_invocation + line_ending | line_ending
).leaveWhitespace()
file = pp.ZeroOrMore(file_element) file = pp.ZeroOrMore(file_element)
self._parser = file self._parser = file

View File

@@ -3,14 +3,31 @@ import re
from pathlib import Path from pathlib import Path
from typing import List, Optional, Tuple from typing import List, Optional, Tuple
from pygls.features import (COMPLETION, FORMATTING, HOVER, INITIALIZE, from pygls.features import (
INITIALIZED, TEXT_DOCUMENT_DID_SAVE) COMPLETION,
FORMATTING,
HOVER,
INITIALIZE,
INITIALIZED,
TEXT_DOCUMENT_DID_SAVE,
)
from pygls.server import LanguageServer from pygls.server import LanguageServer
from pygls.types import (CompletionItem, CompletionItemKind, CompletionList, from pygls.types import (
CompletionParams, CompletionTriggerKind, CompletionItem,
DocumentFormattingParams, Hover, InitializeParams, CompletionItemKind,
MarkupContent, MarkupKind, Position, Range, CompletionList,
TextDocumentPositionParams, TextEdit) CompletionParams,
CompletionTriggerKind,
DocumentFormattingParams,
Hover,
InitializeParams,
MarkupContent,
MarkupKind,
Position,
Range,
TextDocumentPositionParams,
TextEdit,
)
from .api import API from .api import API
from .formatter import Formatter from .formatter import Formatter
@@ -33,32 +50,34 @@ class CMakeLanguageServer(LanguageServer):
def initialize(params: InitializeParams): def initialize(params: InitializeParams):
opts = params.initializationOptions opts = params.initializationOptions
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()
trigger_characters = ['{', '('] trigger_characters = ["{", "("]
@self.feature(COMPLETION, trigger_characters=trigger_characters) @self.feature(COMPLETION, trigger_characters=trigger_characters)
def completions(params: CompletionParams): def completions(params: CompletionParams):
if (hasattr(params, 'context') and params.context.triggerKind == if (
CompletionTriggerKind.TriggerCharacter): hasattr(params, "context")
token = '' and params.context.triggerKind == CompletionTriggerKind.TriggerCharacter
):
token = ""
trigger = params.context.triggerCharacter trigger = params.context.triggerCharacter
else: else:
line = self._cursor_line(params.textDocument.uri, line = self._cursor_line(params.textDocument.uri, params.position)
params.position)
idx = params.position.character - 1 idx = params.position.character - 1
if 0 <= idx < len(line) and line[idx] in trigger_characters: if 0 <= idx < len(line) and line[idx] in trigger_characters:
token = '' token = ""
trigger = line[idx] trigger = line[idx]
else: else:
word = self._cursor_word(params.textDocument.uri, word = self._cursor_word(
params.position, False) params.textDocument.uri, params.position, False
token = '' if word is None else word[0] )
token = "" if word is None else word[0]
trigger = None trigger = None
items: List[CompletionItem] = [] items: List[CompletionItem] = []
@@ -66,46 +85,60 @@ class CMakeLanguageServer(LanguageServer):
if trigger is None: 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, x,
documentation=self._api.get_command_doc(x), CompletionItemKind.Function,
insert_text=x) for x in commands) documentation=self._api.get_command_doc(x),
insert_text=x,
)
for x in commands
)
if trigger is None or trigger == '{': 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, x,
documentation=self._api.get_variable_doc(x), CompletionItemKind.Variable,
insert_text=x) for x in variables) documentation=self._api.get_variable_doc(x),
insert_text=x,
)
for x in variables
)
if trigger is None: if trigger is None:
targets = self._api.search_target(token) targets = self._api.search_target(token)
items.extend( items.extend(
CompletionItem(x, CompletionItemKind.Class, insert_text=x) CompletionItem(x, CompletionItemKind.Class, insert_text=x)
for x in targets) for x in targets
)
if trigger == '(': if trigger == "(":
func = self._cursor_function(params.textDocument.uri, func = self._cursor_function(params.textDocument.uri, params.position)
params.position)
if func is not None: if func is not None:
func = func.lower() func = func.lower()
if func == 'include': if func == "include":
modules = self._api.search_module(token, False) modules = self._api.search_module(token, False)
items.extend( items.extend(
CompletionItem(x, CompletionItem(
CompletionItemKind.Module, x,
documentation=self._api. CompletionItemKind.Module,
get_module_doc(x, False), documentation=self._api.get_module_doc(x, False),
insert_text=x) for x in modules) insert_text=x,
elif func == 'find_package': )
for x in modules
)
elif func == "find_package":
modules = self._api.search_module(token, True) modules = self._api.search_module(token, True)
items.extend( items.extend(
CompletionItem(x, CompletionItem(
CompletionItemKind.Module, x,
documentation=self._api. CompletionItemKind.Module,
get_module_doc(x, True), documentation=self._api.get_module_doc(x, True),
insert_text=x) for x in modules) insert_text=x,
)
for x in modules
)
return CompletionList(False, items) return CompletionList(False, items)
@@ -115,20 +148,16 @@ class CMakeLanguageServer(LanguageServer):
content = doc.source content = doc.source
tokens, remain = self._parser.parse(content) tokens, remain = self._parser.parse(content)
if remain: if remain:
self.show_message('CMake parser failed') self.show_message("CMake parser failed")
return None return None
formatted = Formatter().format(tokens) formatted = Formatter().format(tokens)
lines = content.count('\n') lines = content.count("\n")
return [ return [TextEdit(Range(Position(0, 0), Position(lines + 1, 0)), formatted)]
TextEdit(Range(Position(0, 0), Position(lines + 1, 0)),
formatted)
]
@self.feature(HOVER) @self.feature(HOVER)
def hover(params: TextDocumentPositionParams): def hover(params: TextDocumentPositionParams):
word = self._cursor_word(params.textDocument.uri, params.position, word = self._cursor_word(params.textDocument.uri, params.position, True)
True)
if not word: if not word:
return None return None
@@ -154,43 +183,46 @@ class CMakeLanguageServer(LanguageServer):
def _cursor_function(self, uri: str, position: Position) -> Optional[str]: def _cursor_function(self, uri: str, position: Position) -> Optional[str]:
doc = self.workspace.get_document(uri) doc = self.workspace.get_document(uri)
lines = doc.source.split('\n')[:position.line + 1] lines = doc.source.split("\n")[: position.line + 1]
lines[-1] = lines[-1][:position.character - 1].strip() lines[-1] = lines[-1][: position.character - 1].strip()
words = re.split(r'[\s\n()]+', '\n'.join(lines)) words = re.split(r"[\s\n()]+", "\n".join(lines))
return words[-1] if words else None return words[-1] if words else None
def _cursor_line(self, uri: str, position: Position) -> str: 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]
return line return line
def _cursor_word(self, def _cursor_word(
uri: str, self, uri: str, position: Position, include_all: bool = True
position: Position, ) -> Optional[Tuple[str, Range]]:
include_all: bool = True) -> Optional[Tuple[str, Range]]:
line = self._cursor_line(uri, position) line = self._cursor_line(uri, position)
cursor = position.character cursor = position.character
for m in re.finditer(r'\w+', line): for m in re.finditer(r"\w+", line):
end = m.end() if include_all else cursor end = m.end() if include_all else cursor
if m.start() <= cursor <= m.end(): if m.start() <= cursor <= m.end():
word = (line[m.start():end], word = (
Range(Position(position.line, m.start()), line[m.start() : end],
Position(position.line, end))) Range(
Position(position.line, m.start()), Position(position.line, end)
),
)
return word return word
return None return None
def main(args=None): def main(args=None):
from argparse import ArgumentParser from argparse import ArgumentParser
from . import __version__ from . import __version__
parser = ArgumentParser(description='CMake Language Server') parser = ArgumentParser(description="CMake Language Server")
parser.add_argument('--version', parser.add_argument(
action='version', "--version", action="version", version=f"%(prog)s {__version__}"
version=f'%(prog)s {__version__}') )
args = parser.parse_args(args) args = parser.parse_args(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()

View File

@@ -14,18 +14,20 @@ from cmake_language_server.server import CMakeLanguageServer
@pytest.fixture() @pytest.fixture()
def cmake_build(shared_datadir): def cmake_build(shared_datadir):
source = shared_datadir / 'cmake' source = shared_datadir / "cmake"
build = source / 'build' build = source / "build"
build.mkdir() build.mkdir()
p = run(['cmake', str(source)], p = run(
cwd=build, ["cmake", str(source)],
stdout=PIPE, cwd=build,
stderr=PIPE, stdout=PIPE,
universal_newlines=True) stderr=PIPE,
universal_newlines=True,
)
if p.returncode != 0: if p.returncode != 0:
logging.error('env:\n' + pprint.pformat(os.environ)) logging.error("env:\n" + pprint.pformat(os.environ))
logging.error('stdout:\n' + p.stdout) logging.error("stdout:\n" + p.stdout)
logging.error('stderr:\n' + p.stderr) logging.error("stderr:\n" + p.stderr)
raise RuntimeError("CMake failed") raise RuntimeError("CMake failed")
yield build yield build
@@ -40,7 +42,7 @@ def client_server():
# disable `close()` to avoid error messages # disable `close()` to avoid error messages
close = ls.loop.close close = ls.loop.close
ls.loop.close = lambda: None ls.loop.close = lambda: None
ls.start_io(os.fdopen(fdr, 'rb'), os.fdopen(fdw, 'wb')) ls.start_io(os.fdopen(fdr, "rb"), os.fdopen(fdw, "wb"))
ls.loop.close = close ls.loop.close = close
server = CMakeLanguageServer(asyncio.new_event_loop()) server = CMakeLanguageServer(asyncio.new_event_loop())

View File

@@ -4,109 +4,115 @@ from cmake_language_server.api import API
def test_query_with_cache(cmake_build): def test_query_with_cache(cmake_build):
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):
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):
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):
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()
import platform import platform
system = platform.system() system = platform.system()
if system == 'Linux': if system == "Linux":
assert 'GNU' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID') assert "GNU" in api.get_variable_doc("CMAKE_CXX_COMPILER_ID")
elif system == 'Windows': elif system == "Windows":
assert 'MSVC' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID') assert "MSVC" in api.get_variable_doc("CMAKE_CXX_COMPILER_ID")
elif system == 'Darwin': elif system == "Darwin":
assert 'Clang' in api.get_variable_doc('CMAKE_CXX_COMPILER_ID') assert "Clang" in api.get_variable_doc("CMAKE_CXX_COMPILER_ID")
else: else:
raise RuntimeError('Unexpected system') raise RuntimeError("Unexpected system")
def test_parse_commands(cmake_build): def test_parse_commands(cmake_build):
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(
universal_newlines=True, ["cmake", "--help-command-list"],
stdout=subprocess.PIPE, universal_newlines=True,
stderr=subprocess.PIPE) stdout=subprocess.PIPE,
commands = p.stdout.strip().split('\n') stderr=subprocess.PIPE,
)
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') assert "break()" in api.get_command_doc("break")
assert api.get_command_doc('not_existing_command') is None assert api.get_command_doc("not_existing_command") is None
def test_parse_variables(cmake_build): def test_parse_variables(cmake_build):
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(
universal_newlines=True, ["cmake", "--help-variable-list"],
stdout=subprocess.PIPE, universal_newlines=True,
stderr=subprocess.PIPE) stdout=subprocess.PIPE,
variables = p.stdout.strip().split('\n') stderr=subprocess.PIPE,
)
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): def test_parse_modules(cmake_build):
api = API('cmake', cmake_build) api = API("cmake", cmake_build)
api.parse_doc() api.parse_doc()
p = subprocess.run(['cmake', '--help-module-list'], p = subprocess.run(
universal_newlines=True, ["cmake", "--help-module-list"],
stdout=subprocess.PIPE, universal_newlines=True,
stderr=subprocess.PIPE) stdout=subprocess.PIPE,
modules = p.stdout.strip().split('\n') stderr=subprocess.PIPE,
)
modules = p.stdout.strip().split("\n")
for module in modules: for module in modules:
if module.startswith('Find'): if module.startswith("Find"):
assert api.get_module_doc(module[4:], assert (
True) is not None, f'{module} not found' api.get_module_doc(module[4:], True) is not None
), f"{module} not found"
else: else:
assert api.get_module_doc(module, assert api.get_module_doc(module, False) is not None, f"{module} not found"
False) is not None, f'{module} not found'
assert api.get_module_doc('GoogleTest', False) is not None assert api.get_module_doc("GoogleTest", False) is not None
assert api.get_module_doc('GoogleTest', True) is None assert api.get_module_doc("GoogleTest", True) is None
assert api.search_module('GoogleTest', False) == ['GoogleTest'] assert api.search_module("GoogleTest", False) == ["GoogleTest"]
assert api.search_module('GoogleTest', True) == [] assert api.search_module("GoogleTest", True) == []
assert api.get_module_doc('Boost', False) is None assert api.get_module_doc("Boost", False) is None
assert api.get_module_doc('Boost', True) is not None assert api.get_module_doc("Boost", True) is not None
assert api.search_module('Boost', False) == [] assert api.search_module("Boost", False) == []
assert api.search_module('Boost', True) == ['Boost'] assert api.search_module("Boost", True) == ["Boost"]

View File

@@ -15,50 +15,57 @@ def make_formatter_test(liststr: str, expect: str):
return test return test
test_command = make_formatter_test('a()', 'a()\n') test_command = make_formatter_test("a()", "a()\n")
test_command_tolower = make_formatter_test('A()', 'a()\n') test_command_tolower = make_formatter_test("A()", "a()\n")
test_remove_space = make_formatter_test(''' test_remove_space = make_formatter_test(
"""
#a #a
b ( c ) # d b ( c ) # d
''', '''\ """,
"""\
#a #a
b(c) # d b(c) # d
''') """,
)
test_indent_if = make_formatter_test( test_indent_if = make_formatter_test(
''' """
if() if()
a() # a a() # a
else() else()
# b # b
b() b()
endif() endif()
''', '''\ """,
"""\
if() if()
a() # a a() # a
else() else()
# b # b
b() b()
endif() endif()
''') """,
)
test_indent_if_nested = make_formatter_test( test_indent_if_nested = make_formatter_test(
''' """
if() if()
if() if()
a() a()
b() b()
endif() endif()
endif() endif()
''', '''\ """,
"""\
if() if()
if() if()
a() a()
b() b()
endif() endif()
endif() endif()
''') """,
test_argument = make_formatter_test('a( b c d)', 'a(b c d)\n') )
test_argument = make_formatter_test("a( b c d)", "a(b c d)\n")
test_argument_multiline = make_formatter_test( test_argument_multiline = make_formatter_test(
''' """
if() if()
a(b c a(b c
d # e d # e
@@ -66,7 +73,8 @@ f
# g # g
) # h ) # h
endif() endif()
''', '''\ """,
"""\
if() if()
a( a(
b c b c
@@ -75,7 +83,8 @@ if()
# g # g
) # h ) # h
endif() endif()
''') """,
)
@contextmanager @contextmanager
@@ -87,70 +96,70 @@ def mock_stdin(buf: str):
def test_main_stdin(capsys): def test_main_stdin(capsys):
with mock_stdin(' a()'): with mock_stdin(" a()"):
main([]) main([])
captured = capsys.readouterr() captured = capsys.readouterr()
assert captured.out == 'a()\n' assert captured.out == "a()\n"
assert captured.err == '' assert captured.err == ""
def test_main_stdin_diff(capsys): def test_main_stdin_diff(capsys):
with mock_stdin(' a()'): with mock_stdin(" a()"):
main(['-d']) main(["-d"])
captured = capsys.readouterr() captured = capsys.readouterr()
assert '- a()' in captured.out assert "- a()" in captured.out
assert '+a()' in captured.out assert "+a()" in captured.out
assert captured.err == '' assert captured.err == ""
def test_main_file_1(capsys, tmp_path): def test_main_file_1(capsys, tmp_path):
testfile1 = tmp_path / 'list1.cmake' testfile1 = tmp_path / "list1.cmake"
with testfile1.open('w') as fp: with testfile1.open("w") as fp:
fp.write(' a()') fp.write(" a()")
main([str(testfile1)]) main([str(testfile1)])
captured = capsys.readouterr() captured = capsys.readouterr()
assert captured.out == 'a()\n' assert captured.out == "a()\n"
assert captured.err == '' assert captured.err == ""
def test_main_file_2(capsys, tmp_path): def test_main_file_2(capsys, tmp_path):
testfile1 = tmp_path / 'list1.cmake' testfile1 = tmp_path / "list1.cmake"
with testfile1.open('w') as fp: with testfile1.open("w") as fp:
fp.write(' a()') fp.write(" a()")
testfile2 = tmp_path / 'list2.cmake' testfile2 = tmp_path / "list2.cmake"
with testfile2.open('w') as fp: with testfile2.open("w") as fp:
fp.write(' b()') fp.write(" b()")
main([str(testfile1), str(testfile2)]) main([str(testfile1), str(testfile2)])
captured = capsys.readouterr() captured = capsys.readouterr()
assert captured.out == 'a()\nb()\n' assert captured.out == "a()\nb()\n"
assert captured.err == '' assert captured.err == ""
def test_main_inplace(capsys, tmp_path): def test_main_inplace(capsys, tmp_path):
testfile1 = tmp_path / 'list1.cmake' testfile1 = tmp_path / "list1.cmake"
with testfile1.open('w') as fp: with testfile1.open("w") as fp:
fp.write(' a()') fp.write(" a()")
main(['-i', str(testfile1)]) main(["-i", str(testfile1)])
captured = capsys.readouterr() captured = capsys.readouterr()
assert captured.out == '' assert captured.out == ""
assert captured.err == '' assert captured.err == ""
with testfile1.open() as fp: with testfile1.open() as fp:
content = fp.read() content = fp.read()
assert content == 'a()\n' assert content == "a()\n"
def test_main_diff(capsys, tmp_path): def test_main_diff(capsys, tmp_path):
testfile1 = tmp_path / 'list1.cmake' testfile1 = tmp_path / "list1.cmake"
with testfile1.open('w') as fp: with testfile1.open("w") as fp:
fp.write(' a()') fp.write(" a()")
main(['-d', str(testfile1)]) main(["-d", str(testfile1)])
captured = capsys.readouterr() captured = capsys.readouterr()
assert str(testfile1) in captured.out assert str(testfile1) in captured.out
assert '- a()' in captured.out assert "- a()" in captured.out
assert '+a()' in captured.out assert "+a()" in captured.out
assert captured.err == '' assert captured.err == ""

View File

@@ -3,9 +3,9 @@ from typing import List
from cmake_language_server.parser import ListParser, TokenType from cmake_language_server.parser import ListParser, TokenType
def make_parser_test(liststr: str, def make_parser_test(
expect_token: List[TokenType], liststr: str, expect_token: List[TokenType], expect_remain: str = ""
expect_remain: str = ''): ):
def test(): def test():
actual_token, actual_remain = ListParser().parse(liststr) actual_token, actual_remain = ListParser().parse(liststr)
assert actual_token == expect_token assert actual_token == expect_token
@@ -14,51 +14,70 @@ def make_parser_test(liststr: str,
return test return test
test_command_no_args = make_parser_test('a()', [('a', [])]) test_command_no_args = make_parser_test("a()", [("a", [])])
test_command_space = 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 = make_parser_test("a(b)", [("a", ["b"])])
test_command_arg_space = 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_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 = make_parser_test("a((b))", [("a", ["(", "b", ")"])])
test_command_arg_paren_paren = make_parser_test( test_command_arg_paren_paren = make_parser_test(
'a(((b)))', [('a', ['(', '(', 'b', ')', ')'])]) "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")', test_command_arg_quote = make_parser_test(r'a("b\"")', [("a", [r'"b\""'])])
[('a', ['"\\\n"'])]) test_command_arg_quote_cont = make_parser_test('a("\\\n")', [("a", ['"\\\n"'])])
test_command_arg_quo_multiline = make_parser_test('''a("b test_command_arg_quo_multiline = make_parser_test(
"""a("b
c c
")''', [('a', ['"b\nc\n"'])]) ")""",
test_command_arg_bracket_0 = make_parser_test('a([[b]])', [('a', ['[[b]]'])]) [("a", ['"b\nc\n"'])],
test_command_arg_bracket_1 = make_parser_test('a([=[b]=])', )
[('a', ['[=[b]=]'])]) test_command_arg_bracket_0 = make_parser_test("a([[b]])", [("a", ["[[b]]"])])
test_command_arg_space = make_parser_test('a ( b )', [('a', [' ', 'b', ' '])]) test_command_arg_bracket_1 = make_parser_test("a([=[b]=])", [("a", ["[=[b]=]"])])
test_command_arg_multi = make_parser_test('a(b c)', [('a', ['b', ' ', 'c'])]) test_command_arg_space = make_parser_test("a ( b )", [("a", [" ", "b", " "])])
test_command_multielement = make_parser_test('''a( test_command_arg_multi = make_parser_test("a(b c)", [("a", ["b", " ", "c"])])
test_command_multielement = make_parser_test(
"""a(
b b
c # c c # c
)''', [('a', ['\n', ' ', 'b', '\n', ' ', 'c', ' ', '# c', '\n'])]) )""",
test_line_comment = make_parser_test('a() # b # c', [("a", ["\n", " ", "b", "\n", " ", "c", " ", "# c", "\n"])],
[('a', []), ' ', '# b # c']) )
test_bracket_comment = make_parser_test('#[[a]]#[[b]]', ['#[[a]]', '#[[b]]']) test_line_comment = make_parser_test("a() # b # c", [("a", []), " ", "# b # c"])
test_bracket_comment_nested = make_parser_test('#[=[[[a]]]=]', test_bracket_comment = make_parser_test("#[[a]]#[[b]]", ["#[[a]]", "#[[b]]"])
['#[=[[[a]]]=]']) test_bracket_comment_nested = make_parser_test("#[=[[[a]]]=]", ["#[=[[[a]]]=]"])
test_bracket_comment_multiline = make_parser_test('#[[\na\nb\nc\n]]', test_bracket_comment_multiline = make_parser_test(
['#[[\na\nb\nc\n]]']) "#[[\na\nb\nc\n]]", ["#[[\na\nb\nc\n]]"]
test_if_block = make_parser_test('''if() )
test_if_block = make_parser_test(
"""if()
a() a()
else() else()
b() b()
endif()''', [('if', []), '\n', ' ', ('a', []), '\n', ('else', []), '\n', ' ', endif()""",
('b', []), '\n', ('endif', [])]) [
("if", []),
"\n",
" ",
("a", []),
"\n",
("else", []),
"\n",
" ",
("b", []),
"\n",
("endif", []),
],
)
test_comment_multi_linecomment = make_parser_test( test_comment_multi_linecomment = make_parser_test(
'''a()# a """a()# a
b() # b b() # b
c() # c''', [('a', []), '# a', '\n', ('b', []), ' ', '# b', '\n', c() # c""",
('c', []), ' ', '# c']) [("a", []), "# a", "\n", ("b", []), " ", "# b", "\n", ("c", []), " ", "# c"],
)
test_incomplete_id = make_parser_test('a', [], 'a') test_incomplete_id = make_parser_test("a", [], "a")
test_incomplete_command = make_parser_test('a(', [], 'a(') test_incomplete_command = make_parser_test("a(", [], "a(")
test_incomplete_id_after_command = make_parser_test('a()\nb', test_incomplete_id_after_command = make_parser_test("a()\nb", [("a", []), "\n"], "b")
[('a', []), '\n'], 'b')
test_incomplete_command_after_command = make_parser_test( test_incomplete_command_after_command = make_parser_test(
'a()\nb(c', [('a', []), '\n'], 'b(c') "a()\nb(c", [("a", []), "\n"], "b(c"
)

View File

@@ -2,14 +2,27 @@ from concurrent import futures
from pathlib import Path from pathlib import Path
from typing import Optional from typing import Optional
from pygls.features import (COMPLETION, FORMATTING, HOVER, INITIALIZE, from pygls.features import (
TEXT_DOCUMENT_DID_OPEN) COMPLETION,
FORMATTING,
HOVER,
INITIALIZE,
TEXT_DOCUMENT_DID_OPEN,
)
from pygls.server import LanguageServer from pygls.server import LanguageServer
from pygls.types import (CompletionContext, CompletionParams, from pygls.types import (
CompletionTriggerKind, DidOpenTextDocumentParams, CompletionContext,
DocumentFormattingParams, FormattingOptions, CompletionParams,
InitializeParams, Position, TextDocumentIdentifier, CompletionTriggerKind,
TextDocumentItem, TextDocumentPositionParams) DidOpenTextDocumentParams,
DocumentFormattingParams,
FormattingOptions,
InitializeParams,
Position,
TextDocumentIdentifier,
TextDocumentItem,
TextDocumentPositionParams,
)
CALL_TIMEOUT = 2 CALL_TIMEOUT = 2
@@ -21,8 +34,9 @@ def _init(client: LanguageServer, root: Path):
client.lsp.send_request( client.lsp.send_request(
INITIALIZE, INITIALIZE,
InitializeParams( InitializeParams(
process_id=1234, root_uri=root.as_uri(), process_id=1234, root_uri=root.as_uri(), capabilities=None
capabilities=None)).result(timeout=CALL_TIMEOUT) ),
).result(timeout=CALL_TIMEOUT)
except futures.TimeoutError: except futures.TimeoutError:
retry -= 1 retry -= 1
else: else:
@@ -36,23 +50,24 @@ def _open(client: LanguageServer, path: Path, text: Optional[str] = None):
client.lsp.notify( client.lsp.notify(
TEXT_DOCUMENT_DID_OPEN, TEXT_DOCUMENT_DID_OPEN,
DidOpenTextDocumentParams( DidOpenTextDocumentParams(TextDocumentItem(path.as_uri(), "cmake", 1, text)),
TextDocumentItem(path.as_uri(), 'cmake', 1, text))) )
def _test_completion(client_server, datadir, content: str, def _test_completion(
context: Optional[CompletionContext]): client_server, datadir, content: str, context: Optional[CompletionContext]
):
client, server = client_server client, server = client_server
_init(client, datadir) _init(client, datadir)
path = datadir / 'CMakeLists.txt' path = datadir / "CMakeLists.txt"
_open(client, path, content) _open(client, path, content)
params = CompletionParams(TextDocumentIdentifier(path.as_uri()), params = CompletionParams(
Position(0, len(content)), context) TextDocumentIdentifier(path.as_uri()), Position(0, len(content)), context
)
if context is None: if context is None:
# some clients do not send context # some clients do not send context
del params.context del params.context
return client.lsp.send_request(COMPLETION, return client.lsp.send_request(COMPLETION, params).result(timeout=CALL_TIMEOUT)
params).result(timeout=CALL_TIMEOUT)
def test_initialize(client_server, datadir): def test_initialize(client_server, datadir):
@@ -65,72 +80,83 @@ def test_initialize(client_server, datadir):
def test_completions_invoked(client_server, datadir): def test_completions_invoked(client_server, datadir):
response = _test_completion( response = _test_completion(
client_server, datadir, 'projec', client_server,
CompletionContext(CompletionTriggerKind.Invoked)) datadir,
item = next(filter(lambda x: x.label == 'project', response.items), None) "projec",
CompletionContext(CompletionTriggerKind.Invoked),
)
item = next(filter(lambda x: x.label == "project", response.items), None)
assert item is not None assert item is not None
assert '<PROJECT-NAME>' in item.documentation assert "<PROJECT-NAME>" in item.documentation
def test_completions_nocontext(client_server, datadir): def test_completions_nocontext(client_server, datadir):
response = _test_completion(client_server, datadir, 'projec', None) response = _test_completion(client_server, datadir, "projec", None)
item = next(filter(lambda x: x.label == 'project', response.items), None) item = next(filter(lambda x: x.label == "project", response.items), None)
assert item is not None assert item is not None
assert '<PROJECT-NAME>' in item.documentation assert "<PROJECT-NAME>" in item.documentation
def test_completions_triggercharacter_variable(client_server, datadir): def test_completions_triggercharacter_variable(client_server, datadir):
response = _test_completion( response = _test_completion(
client_server, datadir, '${', client_server,
CompletionContext(CompletionTriggerKind.TriggerCharacter, '{')) datadir,
assert 'PROJECT_VERSION' in [x.label for x in response.items] "${",
CompletionContext(CompletionTriggerKind.TriggerCharacter, "{"),
)
assert "PROJECT_VERSION" in [x.label for x in response.items]
response_nocontext = _test_completion(client_server, datadir, '${', None) response_nocontext = _test_completion(client_server, datadir, "${", None)
assert response == response_nocontext assert response == response_nocontext
def test_completions_triggercharacter_module(client_server, datadir): def test_completions_triggercharacter_module(client_server, datadir):
response = _test_completion( response = _test_completion(
client_server, datadir, 'include(', client_server,
CompletionContext(CompletionTriggerKind.TriggerCharacter, '(')) datadir,
assert 'GoogleTest' in [x.label for x in response.items] "include(",
CompletionContext(CompletionTriggerKind.TriggerCharacter, "("),
)
assert "GoogleTest" in [x.label for x in response.items]
response_nocontext = _test_completion(client_server, datadir, 'include(', response_nocontext = _test_completion(client_server, datadir, "include(", None)
None)
assert response == response_nocontext assert response == response_nocontext
def test_completions_triggercharacter_package(client_server, datadir): def test_completions_triggercharacter_package(client_server, datadir):
response = _test_completion( response = _test_completion(
client_server, datadir, 'find_package(', client_server,
CompletionContext(CompletionTriggerKind.TriggerCharacter, '(')) datadir,
assert 'Boost' in [x.label for x in response.items] "find_package(",
CompletionContext(CompletionTriggerKind.TriggerCharacter, "("),
)
assert "Boost" in [x.label for x in response.items]
response_nocontext = _test_completion(client_server, datadir, response_nocontext = _test_completion(client_server, datadir, "find_package(", None)
'find_package(', None)
assert response == response_nocontext assert response == response_nocontext
def test_formatting(client_server, datadir): def test_formatting(client_server, datadir):
client, server = client_server client, server = client_server
_init(client, datadir) _init(client, datadir)
path = datadir / 'CMakeLists.txt' path = datadir / "CMakeLists.txt"
_open(client, path, 'a ( b c ) ') _open(client, path, "a ( b c ) ")
response = client.lsp.send_request( response = client.lsp.send_request(
FORMATTING, FORMATTING,
DocumentFormattingParams(TextDocumentIdentifier(path.as_uri()), DocumentFormattingParams(
FormattingOptions( TextDocumentIdentifier(path.as_uri()), FormattingOptions(2, True)
2, True))).result(timeout=CALL_TIMEOUT) ),
assert response[0].newText == 'a(b c)\n' ).result(timeout=CALL_TIMEOUT)
assert response[0].newText == "a(b c)\n"
def test_hover(client_server, datadir): def test_hover(client_server, datadir):
client, server = client_server client, server = client_server
_init(client, datadir) _init(client, datadir)
path = datadir / 'CMakeLists.txt' path = datadir / "CMakeLists.txt"
_open(client, path, 'project()') _open(client, path, "project()")
response = client.lsp.send_request( response = client.lsp.send_request(
HOVER, HOVER,
TextDocumentPositionParams(TextDocumentIdentifier(path.as_uri()), TextDocumentPositionParams(TextDocumentIdentifier(path.as_uri()), Position()),
Position())).result(timeout=CALL_TIMEOUT) ).result(timeout=CALL_TIMEOUT)
assert '<PROJECT-NAME>' in response.contents.value assert "<PROJECT-NAME>" in response.contents.value

14
tox.ini
View File

@@ -1,3 +1,15 @@
[isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 0
use_parentheses = True
ensure_newline_before_comments = True
line_length = 88
[flake8]
max-line-length = 88
extend-ignore = E203, W503
[tox] [tox]
isolated_build = True isolated_build = True
skipsdist = True skipsdist = True
@@ -21,6 +33,6 @@ commands =
[testenv:lint] [testenv:lint]
commands = commands =
poetry run isort -c -rc src tests poetry run isort -c -rc src tests
poetry run yapf -d -r src tests poetry run black --diff src tests
poetry run flake8 src tests poetry run flake8 src tests
poetry run mypy src tests poetry run mypy src tests