1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
#!/usr/bin/env python3
import json
import os
import sys
PERMITTED_MAPS = ['map', 'shift_map', 'alt_map', 'altgr_map', 'shift_altgr_map']
REQUIRED_MAPS = ['map', 'shift_map', 'alt_map']
# See Userland/Libraries/LibKeyboard/CharacterMapFile.cpp
# and Userland/Libraries/LibKeyboard/CharacterMap.cpp.
GOOD_MAP_LENGTHS = {90, 128}
def report(filename, problem):
"""Print a lint problem to stdout.
Args:
filename (str): keymap file name
problem (str): problem message
"""
print('{}: {}'.format(filename, problem))
def validate_single_map(filename, mapname, values):
"""Validate a key map.
Args:
filename (str): keymap file name
mapname (str): map name (altgr_map, alt_map, shift_altgr_map)
values (list): key values
Returns:
bool: key map is valid
"""
all_good = True
if not isinstance(values, list):
report(filename, '"{}" is not an array'.format(mapname))
return False # Cannot continue other checks
if not any(values):
report(filename, 'no values set in {}'.format(mapname))
all_good = False
for i, c in enumerate(values):
if len(c) > 1:
report(filename, 'more than one character ("{}") for charmap index {} of {}'.format(c, i, mapname))
all_good = False
if len(values) == 0:
report(filename, 'map {} is empty.'.format(mapname))
all_good = False
if len(values) not in GOOD_MAP_LENGTHS:
report(filename, 'length {} of map {} is suspicious. Off-by-one?'.format(len(values), mapname))
all_good = False
return all_good
def validate_fullmap(filename, fullmap):
"""Validate a full key map for all map names (including maps for key modifiers).
Args:
filename (str): keymap file name
fullmap (dict): key mappings
Returns:
bool: keymap file contains valid key mappings
"""
all_good = True
if not isinstance(fullmap, dict):
report(filename, 'is not an object')
return False # Cannot continue other checks
for name, map_ in fullmap.items():
if name not in PERMITTED_MAPS:
report(filename, 'contains unknown entry {}'.format(name))
all_good = False
all_good &= validate_single_map(filename, name, map_)
for name in REQUIRED_MAPS:
if name not in fullmap:
report(filename, 'map {} is missing'.format(name))
all_good = False
if 'altgr_map' in fullmap and 'alt_map' in fullmap and fullmap['altgr_map'] == fullmap['alt_map']:
report(filename, 'altgr_map is identical to alt_map. Remove altgr_map for the same effect.')
report(filename, '(Or add new characters!)')
all_good = False
if 'shift_altgr_map' in fullmap and 'alt_map' in fullmap and fullmap['shift_altgr_map'] == fullmap['alt_map']:
report(filename, 'shift_altgr_map is identical to alt_map. Remove shift_altgr_map for the same effect.')
report(filename, '(Or add new characters!)')
all_good = False
return all_good
def run_with(filenames):
"""Check list of keymap files for errors.
Args:
filenames (list): keymap files to check
Returns:
bool: All keymap files are valid
"""
passed = 0
for filename in filenames:
with open(filename, 'r') as fp:
fullmap = json.load(fp)
if validate_fullmap(filename, fullmap):
passed += 1
print('{} out of {} keymaps passed.'.format(passed, len(filenames)))
return passed == len(filenames)
def list_files_here():
"""Retrieve a list of all '.json' files in the working directory.
Returns:
list: JSON file names
"""
filelist = []
for filename in os.listdir():
if filename.endswith('.json'):
filelist.append(filename)
else:
report(filename, 'weird filename (ignored)')
# Files are in "filesystem" order. Sort them for slightly more
# aesthetically pleasing output.
filelist.sort()
return filelist
def run_here():
"""Check all keymap files in the working directory for errors.
Returns:
bool: All keymap files are valid
"""
return run_with(list_files_here())
if __name__ == '__main__':
os.chdir(os.path.dirname(__file__) + "/../Base/res/keymaps/")
if not run_here():
sys.exit(1)
|