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 +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:
doc = doc.strip()
doc = re.sub(r':.+?:`(.+?)`', r'\1', doc)
doc = re.sub(r'``([^`]+)``', r'`\1`', doc)
doc = doc.replace('\n', ' ')
doc = doc.replace('. ', '. ')
doc = re.sub(r":.+?:`(.+?)`", r"\1", doc)
doc = re.sub(r"``([^`]+)``", r"`\1`", doc)
doc = doc.replace("\n", " ")
doc = doc.replace(". ", ". ")
return doc
@@ -49,78 +49,82 @@ class API(object):
return False
self.query_json.parent.mkdir(parents=True, exist_ok=True)
with self.query_json.open('w') as fp:
fp.write('''\
with self.query_json.open("w") as fp:
fp.write(
"""\
{
"requests": [
{"kind": "codemodel", "version": 2},
{"kind": "cache", "version": 2},
{"kind": "cmakeFiles", "version": 1}
]
}''')
}"""
)
proc = subprocess.run([self._cmake, str(self._build)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='utf-8',
universal_newlines=True)
proc = subprocess.run(
[self._cmake, str(self._build)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding="utf-8",
universal_newlines=True,
)
self.query_json.unlink()
self.query_json.parent.rmdir()
if proc.returncode != 0:
logging.error(
f'cmake exited with {proc.returncode}: {proc.stderr}')
logging.error(f"cmake exited with {proc.returncode}: {proc.stderr}")
return False
return True
def read_reply(self) -> bool:
reply = self._build / '.cmake' / 'api' / 'v1' / 'reply'
indices = sorted(reply.glob('index-*.json'))
reply = self._build / ".cmake" / "api" / "v1" / "reply"
indices = sorted(reply.glob("index-*.json"))
if not indices:
logger.error('no reply')
logger.error("no reply")
return False
with indices[-1].open() as fp:
index = json.load(fp)
try:
responses = index['reply'][f'client-{self._uuid}']['query.json'][
'responses']
responses = index["reply"][f"client-{self._uuid}"]["query.json"][
"responses"
]
except KeyError:
logger.error('no rensponse')
logger.error("no rensponse")
return False
for response in responses:
if response['kind'] == 'codemodel':
self._read_codemodel(reply / response['jsonFile'])
elif response['kind'] == 'cache':
self._read_cache(reply / response['jsonFile'])
elif response['kind'] == 'cmakeFiles':
self._read_cmake_files(reply / response['jsonFile'])
if response["kind"] == "codemodel":
self._read_codemodel(reply / response["jsonFile"])
elif response["kind"] == "cache":
self._read_cache(reply / response["jsonFile"])
elif response["kind"] == "cmakeFiles":
self._read_cmake_files(reply / response["jsonFile"])
return True
def _read_codemodel(self, codemodelpath: Path):
with (codemodelpath).open() as fp:
codemodel = json.load(fp)
config = codemodel['configurations'][0]
self._targets[:] = [x['name'] for x in config['targets']]
config = codemodel["configurations"][0]
self._targets[:] = [x["name"] for x in config["targets"]]
def _read_cache(self, cachepath: Path):
with cachepath.open() as fp:
cache = json.load(fp)
self._cached_variables.clear()
for entry in cache['entries']:
name = entry['name']
value = self._truncate_variable(entry['value'])
properties = {x['name']: x['value'] for x in entry['properties']}
helpstring = properties.get('HELPSTRING', '')
for entry in cache["entries"]:
name = entry["name"]
value = self._truncate_variable(entry["value"])
properties = {x["name"]: x["value"] for x in entry["properties"]}
helpstring = properties.get("HELPSTRING", "")
doc = []
if helpstring:
doc.append(helpstring)
if value:
doc.append(f'`{value}`')
self._cached_variables[name] = '\n\n'.join(doc)
doc.append(f"`{value}`")
self._cached_variables[name] = "\n\n".join(doc)
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:
return
@@ -130,44 +134,46 @@ class API(object):
# inspect generated list files
with tempfile.TemporaryDirectory() as tmpdirname:
tmplist = Path(tmpdirname) / 'dump.cmake'
with tmplist.open('w') as fp:
for listfile in cmake_files['inputs']:
if not listfile.get('isGenerated', False):
tmplist = Path(tmpdirname) / "dump.cmake"
with tmplist.open("w") as fp:
for listfile in cmake_files["inputs"]:
if not listfile.get("isGenerated", False):
continue
path = listfile['path']
fp.write(f'include({path})\n')
fp.write('''
path = listfile["path"]
fp.write(f"include({path})\n")
fp.write(
"""
get_cmake_property(variables VARIABLES)
foreach (variable ${variables})
message("${variable}=${${variable}}")
endforeach()
''')
"""
)
p = subprocess.run(
[self._cmake, '-P', str(tmplist)],
[self._cmake, "-P", str(tmplist)],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=cmake_files['paths']['source'],
encoding='utf-8',
universal_newlines=True)
cwd=cmake_files["paths"]["source"],
encoding="utf-8",
universal_newlines=True,
)
if p.returncode != 0:
return
for line in p.stderr.split('\n'):
for line in p.stderr.split("\n"):
line = line.strip()
if not line:
continue
k, v = line.split('=', 1)
if k.startswith('CMAKE_ARG'):
k, v = line.split("=", 1)
if k.startswith("CMAKE_ARG"):
continue
v = self._truncate_variable(v)
if k in self._builtin_variables:
self._builtin_variables[k] += f'\n\n`{v}`'
self._builtin_variables[k] += f"\n\n`{v}`"
else:
for pattern, doc in self._builtin_variable_template.items(
):
for pattern, doc in self._builtin_variable_template.items():
if pattern.fullmatch(k):
self._builtin_variables[k] = f'{doc}\n\n`{v}`'
self._builtin_variables[k] = f"{doc}\n\n`{v}`"
break
else:
# ignore variable with no document
@@ -177,12 +183,19 @@ endforeach()
@property
def query_json(self) -> Path:
return (self._build / '.cmake' / 'api' / 'v1' / 'query' /
f'client-{self._uuid}' / 'query.json')
return (
self._build
/ ".cmake"
/ "api"
/ "v1"
/ "query"
/ f"client-{self._uuid}"
/ "query.json"
)
@property
def cmake_cache(self) -> Path:
return self._build / 'CMakeCache.txt'
return self._build / "CMakeCache.txt"
def parse_doc(self) -> None:
self._parse_commands()
@@ -190,81 +203,95 @@ endforeach()
self._parse_modules()
def _parse_commands(self) -> None:
p = subprocess.run([self._cmake, '--help-commands'],
stdout=subprocess.PIPE,
encoding='utf-8',
universal_newlines=True)
p = subprocess.run(
[self._cmake, "--help-commands"],
stdout=subprocess.PIPE,
encoding="utf-8",
universal_newlines=True,
)
if p.returncode != 0:
return
matches = re.finditer(
r'''
r"""
(?P<command>.+)\n
-+\n+?
[\s\S]*?
(?P<signature>(?P=command)\s*\([^)]*\))
''', p.stdout, re.VERBOSE)
""",
p.stdout,
re.VERBOSE,
)
self._builtin_commands.clear()
for match in matches:
command = match.group('command')
signature = match.group('signature')
signature = re.sub(r'^ ', r'', signature, flags=re.MULTILINE)
self._builtin_commands[
command] = '```cmake\n' + signature + '\n```'
command = match.group("command")
signature = match.group("signature")
signature = re.sub(r"^ ", r"", signature, flags=re.MULTILINE)
self._builtin_commands[command] = "```cmake\n" + signature + "\n```"
def _parse_variables(self) -> None:
p = subprocess.run([self._cmake, '--help-variables'],
stdout=subprocess.PIPE,
encoding='utf-8',
universal_newlines=True)
p = subprocess.run(
[self._cmake, "--help-variables"],
stdout=subprocess.PIPE,
encoding="utf-8",
universal_newlines=True,
)
if p.returncode != 0:
return
matches = re.finditer(
r'''
r"""
(?P<variable>.+)\n
-+\n\n
(?P<doc>[\s\S]+?)(?:\n\n|$)
''', p.stdout, re.VERBOSE)
""",
p.stdout,
re.VERBOSE,
)
self._builtin_variables.clear()
for match in matches:
variable = match.group('variable')
doc = _tidy_doc(match.group('doc'))
if variable == 'CMAKE_MATCH_<n>':
variable = match.group("variable")
doc = _tidy_doc(match.group("doc"))
if variable == "CMAKE_MATCH_<n>":
for i in range(10):
self._builtin_variables[f'CMAKE_MATCH_{i}'] = doc
elif '<' in variable:
variable = re.sub(r'<[^>]+>', r'[^_]+', variable)
self._builtin_variables[f"CMAKE_MATCH_{i}"] = doc
elif "<" in variable:
variable = re.sub(r"<[^>]+>", r"[^_]+", variable)
pattern = re.compile(variable)
self._builtin_variable_template[pattern] = doc
else:
self._builtin_variables[variable] = doc
def _parse_modules(self) -> None:
p = subprocess.run([self._cmake, '--help-modules'],
stdout=subprocess.PIPE,
encoding='utf-8',
universal_newlines=True)
p = subprocess.run(
[self._cmake, "--help-modules"],
stdout=subprocess.PIPE,
encoding="utf-8",
universal_newlines=True,
)
if p.returncode != 0:
return
matches = re.finditer(
r'''
r"""
(?P<module>.+)\n
-+\n+?
(?:(?P<header>\w[\w\s]+)\n\^+\n+?)?
(?P<doc>.(?:.|\n)+?\n\n)
''', p.stdout + '\n\n', re.VERBOSE)
""",
p.stdout + "\n\n",
re.VERBOSE,
)
self._builtin_modules.clear()
for match in matches:
module = match.group('module')
header = match.group('header')
doc = _tidy_doc(match.group('doc'))
if header is not None and header != 'Overview':
doc = ''
module = match.group("module")
header = match.group("header")
doc = _tidy_doc(match.group("doc"))
if header is not None and header != "Overview":
doc = ""
self._builtin_modules[module] = doc
def get_command_doc(self, command: str) -> Optional[str]:
@@ -281,28 +308,27 @@ endforeach()
return self._builtin_variables.get(variable)
def search_variable(self, variable: str) -> List[str]:
cached = frozenset(x for x in self._cached_variables
if x.startswith(variable))
builtin = frozenset(x for x in self._builtin_variables
if x.startswith(variable))
cached = frozenset(x for x in self._cached_variables if x.startswith(variable))
builtin = frozenset(
x for x in self._builtin_variables if x.startswith(variable)
)
return list(cached | builtin)
def get_module_doc(self, module: str, package: bool) -> Optional[str]:
if package:
return self._builtin_modules.get('Find' + module)
return self._builtin_modules.get("Find" + module)
return self._builtin_modules.get(module)
def search_module(self, module: str, package: bool) -> List[str]:
if package:
module = 'Find' + module
return [
x[4:] for x in self._builtin_modules if x.startswith(module)
]
module = "Find" + module
return [x[4:] for x in self._builtin_modules if x.startswith(module)]
return [
x for x in self._builtin_modules
if x.startswith(module) and not x.startswith('Find')
x
for x in self._builtin_modules
if x.startswith(module) and not x.startswith("Find")
]
def search_target(self, target: str) -> List[str]:
@@ -310,4 +336,4 @@ endforeach()
def _truncate_variable(self, v: str) -> str:
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
lower_identifier: bool
def __init__(self, indent=' ', lower_identifier=True):
def __init__(self, indent=" ", lower_identifier=True):
self.indent = indent
self.lower_identifier = lower_identifier
def format(self, tokens: TokenList) -> str:
cmds: List[str] = ['']
cmds: List[str] = [""]
indnet_level = 0
for token in tokens:
if isinstance(token, tuple):
raw_identifier = token[0]
identifier = raw_identifier.lower()
if identifier in ('elseif', 'else', 'endif', 'endforeach',
'endwhile', 'endmacro', 'endfunction'):
if identifier in (
"elseif",
"else",
"endif",
"endforeach",
"endwhile",
"endmacro",
"endfunction",
):
if indnet_level > 0:
indnet_level -= 1
cmds[-1] = self.indent * indnet_level
cmds[-1] += (identifier
if self.lower_identifier else raw_identifier)
cmds[-1] += identifier if self.lower_identifier else raw_identifier
args = self._format_args(token[1])
if len(args) < 2:
cmds[-1] += '(' + ''.join(args) + ')'
cmds[-1] += "(" + "".join(args) + ")"
else:
cmds[-1] += '(\n'
cmds[-1] += "(\n"
for arg in args:
cmds[-1] += self.indent * (indnet_level +
1) + arg + '\n'
cmds[-1] += self.indent * indnet_level + ')'
if identifier in ('if', 'elseif', 'else', 'foreach', 'while',
'macro', 'function'):
cmds[-1] += self.indent * (indnet_level + 1) + arg + "\n"
cmds[-1] += self.indent * indnet_level + ")"
if identifier in (
"if",
"elseif",
"else",
"foreach",
"while",
"macro",
"function",
):
indnet_level += 1
elif token == '\n':
cmds.append('')
elif token[0] == '#':
elif token == "\n":
cmds.append("")
elif token[0] == "#":
if cmds[-1]:
cmds[-1] += token
else:
@@ -48,70 +60,67 @@ class Formatter(object):
cmds[-1] += token
cmds = self._strip_line(cmds)
return '\n'.join(cmds) + '\n'
return "\n".join(cmds) + "\n"
def _format_args(self, args: List[str]) -> List[str]:
lines = ['']
lines = [""]
for i in range(len(args)):
arg = args[i]
if arg[0] == '#':
if arg[0] == "#":
lines[-1] += arg
elif arg[0] == '\n':
lines.append('')
elif arg[0] == "\n":
lines.append("")
elif arg.isspace():
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
else:
lines[-1] += ' '
lines[-1] += " "
else:
lines[-1] += arg
return self._strip_line(lines)
def _strip_line(self, lines: List[str]) -> List[str]:
'''Delete empty lines at the start/end of the input'''
"""Delete empty lines at the start/end of the input"""
ret: List[str] = []
for line in lines:
line = line.rstrip()
if line != '' or len(ret) > 0:
if line != "" or len(ret) > 0:
ret.append(line)
while ret and ret[-1] == '':
while ret and ret[-1] == "":
del ret[-1]
return ret
def main(args: List[str] = None):
import sys
from argparse import ArgumentParser
from difflib import unified_diff
from pathlib import Path
import sys
from . import __version__
from .parser import ListParser
parser = ArgumentParser(
description='Format CMake list files.',
epilog='''
description="Format CMake list files.",
epilog="""
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.add_argument('-i',
'--inplace',
action='store_true',
help='inplace edit')
group.add_argument('-d', '--diff', action='store_true', help='show diff')
parser.add_argument('--version',
action='version',
version=f'%(prog)s {__version__}')
group.add_argument("-i", "--inplace", action="store_true", help="inplace edit")
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)
if not args.lists and args.inplace:
print('error: cannot use -i when no arguments are specified.',
file=sys.stderr)
print("error: cannot use -i when no arguments are specified.", file=sys.stderr)
return
if not args.lists:
args.lists.append(None)
@@ -120,7 +129,7 @@ def main(args: List[str] = None):
formatter = Formatter()
for listpath in args.lists:
if listpath is None:
listpath = '(stdin)'
listpath = "(stdin)"
content = sys.stdin.read()
else:
with listpath.open() as fp:
@@ -130,14 +139,18 @@ def main(args: List[str] = None):
if args.inplace:
if not remain:
with listpath.open('w') as fp:
with listpath.open("w") as fp:
fp.write(formatted)
elif args.diff:
diff = unified_diff(content.splitlines(True),
formatted.splitlines(True), str(listpath),
str(listpath), '(before formatting)',
'(after formatting)')
diffstr = ''.join(diff)
print(diffstr, end='')
diff = unified_diff(
content.splitlines(True),
formatted.splitlines(True),
str(listpath),
str(listpath),
"(before formatting)",
"(after formatting)",
)
diffstr = "".join(diff)
print(diffstr, end="")
else:
print(formatted, end='')
print(formatted, end="")

View File

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

View File

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