Initial commit
This commit is contained in:
116
src/cmake_language_server/formatter.py
Normal file
116
src/cmake_language_server/formatter.py
Normal file
@@ -0,0 +1,116 @@
|
||||
from typing import List
|
||||
|
||||
from .parser import TokenList
|
||||
|
||||
|
||||
class Formatter(object):
|
||||
indnt: str
|
||||
lower_identifier: bool
|
||||
|
||||
def __init__(self, indent=' ', lower_identifier=True):
|
||||
self.indent = indent
|
||||
self.lower_identifier = lower_identifier
|
||||
|
||||
def format(self, tokens: TokenList) -> str:
|
||||
cmds: List[str] = ['']
|
||||
indnet_level = 0
|
||||
for token in tokens:
|
||||
if isinstance(token, tuple):
|
||||
raw_identifier = token[0]
|
||||
identifier = raw_identifier.lower()
|
||||
if identifier in ('elseif', 'else', 'endif', 'endforeach',
|
||||
'endwhile', 'endmacro', 'endfunction'):
|
||||
if indnet_level > 0:
|
||||
indnet_level -= 1
|
||||
cmds[-1] = self.indent * indnet_level
|
||||
cmds[-1] += (identifier
|
||||
if self.lower_identifier else raw_identifier)
|
||||
args = self._format_args(token[1])
|
||||
if len(args) < 2:
|
||||
cmds[-1] += '(' + ''.join(args) + ')'
|
||||
else:
|
||||
cmds[-1] += '(\n'
|
||||
for arg in args:
|
||||
cmds[-1] += self.indent * (indnet_level +
|
||||
1) + arg + '\n'
|
||||
cmds[-1] += self.indent * indnet_level + ')'
|
||||
if identifier in ('if', 'elseif', 'else', 'foreach', 'while',
|
||||
'macro', 'function'):
|
||||
indnet_level += 1
|
||||
elif token == '\n':
|
||||
cmds.append('')
|
||||
elif token[0] == '#':
|
||||
if cmds[-1]:
|
||||
cmds[-1] += token
|
||||
else:
|
||||
cmds[-1] = self.indent * indnet_level + token
|
||||
elif cmds[-1]:
|
||||
cmds[-1] += token
|
||||
|
||||
cmds = self._strip_line(cmds)
|
||||
return '\n'.join(cmds) + '\n'
|
||||
|
||||
def _format_args(self, args: List[str]) -> List[str]:
|
||||
lines = ['']
|
||||
for i in range(len(args)):
|
||||
arg = args[i]
|
||||
if arg[0] == '#':
|
||||
lines[-1] += arg
|
||||
elif arg[0] == '\n':
|
||||
lines.append('')
|
||||
elif arg.isspace():
|
||||
if lines[-1]:
|
||||
if i + 1 < len(args) and args[i + 1][0] == '#':
|
||||
lines[-1] += arg
|
||||
else:
|
||||
lines[-1] += ' '
|
||||
else:
|
||||
lines[-1] += arg
|
||||
|
||||
return self._strip_line(lines)
|
||||
|
||||
def _strip_line(self, lines: List[str]) -> List[str]:
|
||||
'''Delete empty lines at the start/end of the input'''
|
||||
|
||||
ret: List[str] = []
|
||||
for line in lines:
|
||||
line = line.rstrip()
|
||||
if line != '' or len(ret) > 0:
|
||||
ret.append(line)
|
||||
while ret and ret[-1] == '':
|
||||
del ret[-1]
|
||||
return ret
|
||||
|
||||
|
||||
def main(args: List[str] = None):
|
||||
from pathlib import Path
|
||||
from argparse import ArgumentParser
|
||||
from .parser import ListParser
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('lists', type=Path, nargs='*', help='CMake list files')
|
||||
parser.add_argument('-i',
|
||||
'--inplace',
|
||||
action='store_true',
|
||||
help='inplace edit')
|
||||
|
||||
args = parser.parse_args(args)
|
||||
|
||||
list_parser = ListParser()
|
||||
formatter = Formatter()
|
||||
for listpath in args.lists:
|
||||
with listpath.open() as fp:
|
||||
content = fp.read()
|
||||
tokens, remain = list_parser.parse(content)
|
||||
if remain:
|
||||
if args.inplace:
|
||||
pass
|
||||
else:
|
||||
print(content, end='')
|
||||
else:
|
||||
formated = formatter.format(tokens)
|
||||
if args.inplace:
|
||||
with listpath.open('w') as fp:
|
||||
fp.write(formated)
|
||||
else:
|
||||
print(formated, end='')
|
||||
Reference in New Issue
Block a user