Skip to content

Commit 7b922d3

Browse files
committed
Highlight keyword arguments in python call
1 parent 8047086 commit 7b922d3

File tree

5 files changed

+39
-6
lines changed

5 files changed

+39
-6
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ hi semshiGlobal ctermfg=214 guifg=#ffaf00
7777
hi semshiImported ctermfg=214 guifg=#ffaf00 cterm=bold gui=bold
7878
hi semshiParameter ctermfg=75 guifg=#5fafff
7979
hi semshiParameterUnused ctermfg=117 guifg=#87d7ff cterm=underline gui=underline
80+
hi semshiKeywordArgument ctermfg=180 guifg=#eea583
8081
hi semshiFree ctermfg=218 guifg=#ffafd7
8182
hi semshiBuiltin ctermfg=207 guifg=#ff5fff
8283
hi semshiAttribute ctermfg=49 guifg=#00ffaf

plugin/semshi.vim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ function! semshi#init()
9595
hi def semshiImported ctermfg=214 guifg=#ffaf00 cterm=bold gui=bold
9696
hi def semshiParameter ctermfg=75 guifg=#5fafff
9797
hi def semshiParameterUnused ctermfg=117 guifg=#87d7ff cterm=underline gui=underline
98+
hi def semshiKeywordArgument ctermfg=180 guifg=#eea583
9899
hi def semshiFree ctermfg=218 guifg=#ffafd7
99100
hi def semshiBuiltin ctermfg=207 guifg=#ff5fff
100101
hi def semshiAttribute ctermfg=49 guifg=#00ffaf

rplugin/python3/semshi/node.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def group(s):
1616
GLOBAL = group('global')
1717
PARAMETER = group('parameter')
1818
PARAMETER_UNUSED = group('parameterUnused')
19+
KEYWORD = group('keywordArgument')
1920
SELF = group('self')
2021
IMPORTED = group('imported')
2122
LOCAL = group('local')

rplugin/python3/semshi/visitor.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from token import NAME, OP
66
from tokenize import tokenize
77

8-
from .node import ATTRIBUTE, IMPORTED, PARAMETER_UNUSED, SELF, Node
8+
from .node import ATTRIBUTE, IMPORTED, PARAMETER_UNUSED, SELF, KEYWORD, Node
99
from .util import debug_time
1010

1111
# Node types which introduce a new scope
@@ -89,6 +89,8 @@ def visit(self, node):
8989
self._visit_except(node)
9090
elif type_ in (ast.Import, ast.ImportFrom):
9191
self._visit_import(node)
92+
elif type_ is ast.keyword:
93+
self._visit_keyword(node)
9294
elif type_ is ast.arg:
9395
self._visit_arg(node)
9496
elif type_ in FUNCTION_BLOCKS:
@@ -99,7 +101,7 @@ def visit(self, node):
99101
elif type_ in (ast.Global, ast.Nonlocal):
100102
keyword = 'global' if type_ is ast.Global else 'nonlocal'
101103
self._visit_global_nonlocal(node, keyword)
102-
elif type_ is ast.keyword:
104+
else:
103105
pass
104106

105107
if type_ in (ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef):
@@ -203,6 +205,24 @@ def _visit_class_meta(self, node):
203205
self.visit(keyword)
204206
del node.keywords
205207

208+
def _visit_keyword(self, node: ast.keyword):
209+
"""Visit keyword argument in a function call."""
210+
if node.arg:
211+
# keyword=argument: highlight keyword
212+
try:
213+
lineno = node.lineno
214+
col_offset = node.col_offset
215+
except AttributeError:
216+
# Python <= 3.7 does not have node.lineno, etc. No highlight
217+
return
218+
self.nodes.append(Node(
219+
node.arg, lineno, col_offset, self._cur_env,
220+
hl_group=KEYWORD
221+
))
222+
else:
223+
# This is probably (**kwargs), do nothing
224+
pass
225+
206226
def _visit_args(self, node):
207227
"""Visit function arguments."""
208228
# We'd want to visit args.posonlyargs, but it appears an internal bug

test/test_parser.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pytest
77

88
from semshi import parser
9-
from semshi.node import (ATTRIBUTE, BUILTIN, FREE, GLOBAL, IMPORTED, LOCAL,
9+
from semshi.node import (ATTRIBUTE, BUILTIN, FREE, GLOBAL, IMPORTED, KEYWORD, LOCAL,
1010
PARAMETER, PARAMETER_UNUSED, SELF, UNRESOLVED, Node,
1111
group)
1212
from semshi.parser import Parser, UnparsableError
@@ -173,7 +173,7 @@ def func2(j=k):
173173
''')
174174
root = make_tree(names)
175175
assert root['names'] == [
176-
'e', 'h', 'func', 'k', 'func2', 'func', 'x', 'p', 'z'
176+
'e', 'h', 'func', 'k', 'func2', 'func', 'x', 'y', 'p', 'z'
177177
]
178178
assert root['listcomp']['names'] == ['g', 'g']
179179
assert root['func']['names'] == ['a', 'b', 'c', 'd', 'f', 'i']
@@ -189,7 +189,7 @@ def f():
189189
a
190190
''')
191191
root = make_tree(names)
192-
assert root['names'] == ['a', 'A', 'x', 'z']
192+
assert root['names'] == ['a', 'A', 'x', 'y', 'z']
193193

194194

195195
def test_import_scopes_and_positions():
@@ -483,7 +483,7 @@ async def C():
483483
''')
484484
root = make_tree(names)
485485
assert root['names'] == [
486-
'd1', 'a', 'c', 'A', 'd2', 'x', 'z', 'B', 'd3', 'C'
486+
'd1', 'a', 'b', 'c', 'A', 'd2', 'x', 'y', 'z', 'B', 'd3', 'C'
487487
]
488488

489489
def test_global_builtin():
@@ -827,6 +827,16 @@ def test_posonlyargs_with_annotation():
827827
assert [n.hl_group for n in names] == [MODULE_FUNC, UNRESOLVED, PARAMETER_UNUSED]
828828

829829

830+
def test_keyword_arguments():
831+
names = parse('foo(x, y, kwarg1=z, bar=dict(value=1))')
832+
assert [n.name for n in names] == [
833+
'foo', 'x', 'y', 'kwarg1', 'z', 'bar', 'dict', 'value',
834+
]
835+
for n in names:
836+
if n.name == 'kwarg1' or n.name == 'value':
837+
assert n.hl_group == KEYWORD
838+
839+
830840
@pytest.mark.skipif('sys.version_info < (3, 8)')
831841
@pytest.mark.parametrize("enable_pep563", (False, True))
832842
def test_postponed_evaluation_of_annotations_pep563(enable_pep563):

0 commit comments

Comments
 (0)