mirror of
https://github.com/littlefs-project/littlefs.git
synced 2025-12-01 12:20:02 +00:00
scripts: Tweaked how Attr handles indexed attrs
No more special indexed attrs at the top-level, now all attrs are indexed, even if assigned to a specific group. This just makes it so group-specific cycles are possible: $ ./scripts/treemap.py -Clfs.c=red -Clfs.c=green
This commit is contained in:
@ -162,46 +162,51 @@ class Attr:
|
|||||||
# include defaults?
|
# include defaults?
|
||||||
if (defaults is not None
|
if (defaults is not None
|
||||||
and not any(
|
and not any(
|
||||||
not isinstance(attr, tuple) or attr[0] is None
|
not isinstance(attr, tuple)
|
||||||
|
or attr[0] in {None, (), ('',)}
|
||||||
for attr in (attrs or []))):
|
for attr in (attrs or []))):
|
||||||
attrs = defaults + (attrs or [])
|
attrs = defaults + (attrs or [])
|
||||||
|
|
||||||
# normalize and split out keyed vs indexed attrs
|
# normalize
|
||||||
self.attrs = []
|
self.attrs = []
|
||||||
self.indexed = []
|
self.keyed = co.OrderedDict()
|
||||||
self.keyed = []
|
|
||||||
for attr in (attrs or []):
|
for attr in (attrs or []):
|
||||||
if not isinstance(attr, tuple):
|
if not isinstance(attr, tuple):
|
||||||
attr = (None, attr)
|
attr = ((), attr)
|
||||||
|
elif attr[0] in {None, (), ('',)}:
|
||||||
|
attr = ((), attr[1])
|
||||||
|
|
||||||
self.attrs.append(attr)
|
self.attrs.append(attr)
|
||||||
if attr[0] is None:
|
if attr[0] not in self.keyed:
|
||||||
self.indexed.append(attr[1])
|
self.keyed[attr[0]] = []
|
||||||
else:
|
self.keyed[attr[0]].append(attr[1])
|
||||||
self.keyed.append(attr)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Attr(%r)' % [
|
return 'Attr(%r)' % [
|
||||||
(','.join(key), a) if key is not None else a
|
(','.join(attr[0]), attr[1])
|
||||||
for key, a in self.attrs]
|
for attr in self.attrs]
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return it.cycle(self.indexed)
|
return it.cycle(self.keyed[()])
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.indexed)
|
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
# note this is not just the indexed attrs
|
|
||||||
return bool(self.attrs)
|
return bool(self.attrs)
|
||||||
|
|
||||||
def lookup(self, key):
|
def __getitem__(self, key):
|
||||||
|
if isinstance(key, tuple):
|
||||||
|
if len(key) > 0 and not isinstance(key[0], str):
|
||||||
|
i, key = key
|
||||||
|
else:
|
||||||
|
i, key = 0, key
|
||||||
|
else:
|
||||||
|
i, key = key, ()
|
||||||
|
|
||||||
# try to lookup by key
|
# try to lookup by key
|
||||||
best = None
|
best = None
|
||||||
for attr in self.keyed:
|
for ks, vs in self.keyed.items():
|
||||||
prefix = []
|
prefix = []
|
||||||
for i, k in enumerate(attr[0]):
|
for j, k in enumerate(ks):
|
||||||
if i < len(key) and (not k or key[i] == k):
|
if j < len(key) and (not k or key[j] == k):
|
||||||
prefix.append(k)
|
prefix.append(k)
|
||||||
else:
|
else:
|
||||||
prefix = None
|
prefix = None
|
||||||
@ -209,31 +214,11 @@ class Attr:
|
|||||||
|
|
||||||
if prefix is not None and (
|
if prefix is not None and (
|
||||||
best is None or len(prefix) >= len(best[0])):
|
best is None or len(prefix) >= len(best[0])):
|
||||||
best = (prefix, attr[1])
|
best = (prefix, vs)
|
||||||
|
|
||||||
if best is not None:
|
if best is not None:
|
||||||
return best[1]
|
# cycle based on index
|
||||||
else:
|
return best[1][i % len(best[1])]
|
||||||
return None
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if isinstance(key, tuple):
|
|
||||||
if len(key) > 0 and not isinstance(key[0], str):
|
|
||||||
i, key = key
|
|
||||||
else:
|
|
||||||
i, key = None, key
|
|
||||||
else:
|
|
||||||
i, key = key, None
|
|
||||||
|
|
||||||
# try to lookup by key
|
|
||||||
if key is not None:
|
|
||||||
attr = self.lookup(key)
|
|
||||||
if attr is not None:
|
|
||||||
return attr
|
|
||||||
|
|
||||||
# otherwise fallback to index
|
|
||||||
if i is not None and self.indexed:
|
|
||||||
return self.indexed[i % len(self.indexed)]
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -287,14 +272,16 @@ class Canvas:
|
|||||||
braille=False):
|
braille=False):
|
||||||
# scale if we're printing with dots or braille
|
# scale if we're printing with dots or braille
|
||||||
if braille:
|
if braille:
|
||||||
self.width = 2*width
|
xscale, yscale = 2, 4
|
||||||
self.height = 4*height
|
|
||||||
elif dots:
|
elif dots:
|
||||||
self.width = width
|
xscale, yscale = 1, 2
|
||||||
self.height = 2*height
|
|
||||||
else:
|
else:
|
||||||
self.width = width
|
xscale, yscale = 1, 1
|
||||||
self.height = height
|
|
||||||
|
self.width = xscale*width
|
||||||
|
self.height = yscale*height
|
||||||
|
self.xscale = xscale
|
||||||
|
self.yscale = yscale
|
||||||
self.color_ = color
|
self.color_ = color
|
||||||
self.dots = dots
|
self.dots = dots
|
||||||
self.braille = braille
|
self.braille = braille
|
||||||
@ -332,11 +319,9 @@ class Canvas:
|
|||||||
def point(self, x, y, *,
|
def point(self, x, y, *,
|
||||||
char=True,
|
char=True,
|
||||||
color=''):
|
color=''):
|
||||||
# scale if needed
|
# make sure non-bool chars map attrs to all points under char
|
||||||
if self.braille and char is not True and char is not False:
|
if not isinstance(char, bool):
|
||||||
xscale, yscale = 2, 4
|
xscale, yscale = self.xscale, self.yscale
|
||||||
elif self.dots and char is not True and char is not False:
|
|
||||||
xscale, yscale = 1, 2
|
|
||||||
else:
|
else:
|
||||||
xscale, yscale = 1, 1
|
xscale, yscale = 1, 1
|
||||||
|
|
||||||
@ -386,34 +371,21 @@ class Canvas:
|
|||||||
|
|
||||||
def label(self, x, y, label, width=None, height=None, *,
|
def label(self, x, y, label, width=None, height=None, *,
|
||||||
color=''):
|
color=''):
|
||||||
# scale if needed
|
|
||||||
if self.braille:
|
|
||||||
xscale, yscale = 2, 4
|
|
||||||
elif self.dots:
|
|
||||||
xscale, yscale = 1, 2
|
|
||||||
else:
|
|
||||||
xscale, yscale = 1, 1
|
|
||||||
|
|
||||||
x_ = x
|
x_ = x
|
||||||
y_ = y
|
y_ = y
|
||||||
for char in label:
|
for char in label:
|
||||||
if char == '\n':
|
if char == '\n':
|
||||||
x_ = x
|
x_ = x
|
||||||
y_ -= 1
|
y_ -= self.yscale
|
||||||
else:
|
else:
|
||||||
if ((width is None or x_ < x+width)
|
if ((width is None or x_ < x+width)
|
||||||
and (height is None or y_ > y-height)):
|
and (height is None or y_ > y-height)):
|
||||||
self.point(x_, y_, char=char, color=color)
|
self.point(x_, y_, char=char, color=color)
|
||||||
x_ += xscale
|
x_ += self.xscale
|
||||||
|
|
||||||
def draw(self, row):
|
def draw(self, row):
|
||||||
# scale if needed
|
# scale if needed
|
||||||
if self.braille:
|
xscale, yscale = self.xscale, self.yscale
|
||||||
xscale, yscale = 2, 4
|
|
||||||
elif self.dots:
|
|
||||||
xscale, yscale = 1, 2
|
|
||||||
else:
|
|
||||||
xscale, yscale = 1, 1
|
|
||||||
|
|
||||||
y = self.height//yscale-1 - row
|
y = self.height//yscale-1 - row
|
||||||
row_ = []
|
row_ = []
|
||||||
@ -726,13 +698,11 @@ def main(csv_paths, *,
|
|||||||
|
|
||||||
# what chars/colors/labels to use?
|
# what chars/colors/labels to use?
|
||||||
chars_ = []
|
chars_ = []
|
||||||
for char in chars:
|
for char in (chars or []):
|
||||||
if isinstance(char, tuple):
|
if isinstance(char, tuple):
|
||||||
for char_ in char[1]:
|
chars_.extend((char[0], c) for c in char[1])
|
||||||
chars_.append((char[0], char_))
|
|
||||||
else:
|
else:
|
||||||
for char_ in char:
|
chars_.extend(char)
|
||||||
chars_.append(char_)
|
|
||||||
chars_ = Attr(chars_, defaults=CHARS)
|
chars_ = Attr(chars_, defaults=CHARS)
|
||||||
|
|
||||||
colors_ = Attr(colors, defaults=COLORS)
|
colors_ = Attr(colors, defaults=COLORS)
|
||||||
@ -752,7 +722,7 @@ def main(csv_paths, *,
|
|||||||
elif height:
|
elif height:
|
||||||
height_ = height
|
height_ = height
|
||||||
else:
|
else:
|
||||||
height_ = shutil.get_terminal_size((80, 5))[1]
|
height_ = shutil.get_terminal_size((80, 5))[1] - 1
|
||||||
|
|
||||||
# first collect results from CSV files
|
# first collect results from CSV files
|
||||||
fields_, results = collect(csv_paths, defines)
|
fields_, results = collect(csv_paths, defines)
|
||||||
@ -847,7 +817,9 @@ def main(csv_paths, *,
|
|||||||
/ yscale)
|
/ yscale)
|
||||||
|
|
||||||
# create a canvas
|
# create a canvas
|
||||||
canvas = Canvas(width_, height_,
|
canvas = Canvas(
|
||||||
|
width_,
|
||||||
|
height_ - (1 if title or not no_header else 0),
|
||||||
color=color,
|
color=color,
|
||||||
dots=dots,
|
dots=dots,
|
||||||
braille=braille)
|
braille=braille)
|
||||||
@ -877,11 +849,6 @@ def main(csv_paths, *,
|
|||||||
width__ = tile.width
|
width__ = tile.width
|
||||||
height__ = tile.height
|
height__ = tile.height
|
||||||
|
|
||||||
# create space for header
|
|
||||||
if title is not None or not no_header:
|
|
||||||
y__ += 1
|
|
||||||
height__ -= min(1, height__)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# apply bottom padding
|
# apply bottom padding
|
||||||
if not tile.children:
|
if not tile.children:
|
||||||
@ -989,7 +956,7 @@ def main(csv_paths, *,
|
|||||||
print(stat_)
|
print(stat_)
|
||||||
|
|
||||||
# draw canvas
|
# draw canvas
|
||||||
for row in range(1 if title or not no_header else 0, height_):
|
for row in range(canvas.height//canvas.yscale):
|
||||||
line = canvas.draw(row)
|
line = canvas.draw(row)
|
||||||
print(line)
|
print(line)
|
||||||
|
|
||||||
@ -1028,8 +995,8 @@ if __name__ == "__main__":
|
|||||||
dest='labels',
|
dest='labels',
|
||||||
action='append',
|
action='append',
|
||||||
type=lambda x: (
|
type=lambda x: (
|
||||||
lambda key, v: (
|
lambda ks, v: (
|
||||||
tuple(k.strip() for k in key.split(',')),
|
tuple(k.strip() for k in ks.split(',')),
|
||||||
v.strip())
|
v.strip())
|
||||||
)(*x.split('=', 1))
|
)(*x.split('=', 1))
|
||||||
if '=' in x else x.strip(),
|
if '=' in x else x.strip(),
|
||||||
@ -1041,8 +1008,8 @@ if __name__ == "__main__":
|
|||||||
dest='chars',
|
dest='chars',
|
||||||
action='append',
|
action='append',
|
||||||
type=lambda x: (
|
type=lambda x: (
|
||||||
lambda key, v: (
|
lambda ks, v: (
|
||||||
tuple(k.strip() for k in key.split(',')),
|
tuple(k.strip() for k in ks.split(',')),
|
||||||
v.strip())
|
v.strip())
|
||||||
)(*x.split('=', 1))
|
)(*x.split('=', 1))
|
||||||
if '=' in x else x.strip(),
|
if '=' in x else x.strip(),
|
||||||
@ -1053,8 +1020,8 @@ if __name__ == "__main__":
|
|||||||
dest='colors',
|
dest='colors',
|
||||||
action='append',
|
action='append',
|
||||||
type=lambda x: (
|
type=lambda x: (
|
||||||
lambda key, v: (
|
lambda ks, v: (
|
||||||
tuple(k.strip() for k in key.split(',')),
|
tuple(k.strip() for k in ks.split(',')),
|
||||||
v.strip())
|
v.strip())
|
||||||
)(*x.split('=', 1))
|
)(*x.split('=', 1))
|
||||||
if '=' in x else x.strip(),
|
if '=' in x else x.strip(),
|
||||||
|
|||||||
@ -178,46 +178,51 @@ class Attr:
|
|||||||
# include defaults?
|
# include defaults?
|
||||||
if (defaults is not None
|
if (defaults is not None
|
||||||
and not any(
|
and not any(
|
||||||
not isinstance(attr, tuple) or attr[0] is None
|
not isinstance(attr, tuple)
|
||||||
|
or attr[0] in {None, (), ('',)}
|
||||||
for attr in (attrs or []))):
|
for attr in (attrs or []))):
|
||||||
attrs = defaults + (attrs or [])
|
attrs = defaults + (attrs or [])
|
||||||
|
|
||||||
# normalize and split out keyed vs indexed attrs
|
# normalize
|
||||||
self.attrs = []
|
self.attrs = []
|
||||||
self.indexed = []
|
self.keyed = co.OrderedDict()
|
||||||
self.keyed = []
|
|
||||||
for attr in (attrs or []):
|
for attr in (attrs or []):
|
||||||
if not isinstance(attr, tuple):
|
if not isinstance(attr, tuple):
|
||||||
attr = (None, attr)
|
attr = ((), attr)
|
||||||
|
elif attr[0] in {None, (), ('',)}:
|
||||||
|
attr = ((), attr[1])
|
||||||
|
|
||||||
self.attrs.append(attr)
|
self.attrs.append(attr)
|
||||||
if attr[0] is None:
|
if attr[0] not in self.keyed:
|
||||||
self.indexed.append(attr[1])
|
self.keyed[attr[0]] = []
|
||||||
else:
|
self.keyed[attr[0]].append(attr[1])
|
||||||
self.keyed.append(attr)
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return 'Attr(%r)' % [
|
return 'Attr(%r)' % [
|
||||||
(','.join(key), a) if key is not None else a
|
(','.join(attr[0]), attr[1])
|
||||||
for key, a in self.attrs]
|
for attr in self.attrs]
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return it.cycle(self.indexed)
|
return it.cycle(self.keyed[()])
|
||||||
|
|
||||||
def __len__(self):
|
|
||||||
return len(self.indexed)
|
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
# note this is not just the indexed attrs
|
|
||||||
return bool(self.attrs)
|
return bool(self.attrs)
|
||||||
|
|
||||||
def lookup(self, key):
|
def __getitem__(self, key):
|
||||||
|
if isinstance(key, tuple):
|
||||||
|
if len(key) > 0 and not isinstance(key[0], str):
|
||||||
|
i, key = key
|
||||||
|
else:
|
||||||
|
i, key = 0, key
|
||||||
|
else:
|
||||||
|
i, key = key, ()
|
||||||
|
|
||||||
# try to lookup by key
|
# try to lookup by key
|
||||||
best = None
|
best = None
|
||||||
for attr in self.keyed:
|
for ks, vs in self.keyed.items():
|
||||||
prefix = []
|
prefix = []
|
||||||
for i, k in enumerate(attr[0]):
|
for j, k in enumerate(ks):
|
||||||
if i < len(key) and (not k or key[i] == k):
|
if j < len(key) and (not k or key[j] == k):
|
||||||
prefix.append(k)
|
prefix.append(k)
|
||||||
else:
|
else:
|
||||||
prefix = None
|
prefix = None
|
||||||
@ -225,31 +230,11 @@ class Attr:
|
|||||||
|
|
||||||
if prefix is not None and (
|
if prefix is not None and (
|
||||||
best is None or len(prefix) >= len(best[0])):
|
best is None or len(prefix) >= len(best[0])):
|
||||||
best = (prefix, attr[1])
|
best = (prefix, vs)
|
||||||
|
|
||||||
if best is not None:
|
if best is not None:
|
||||||
return best[1]
|
# cycle based on index
|
||||||
else:
|
return best[1][i % len(best[1])]
|
||||||
return None
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
if isinstance(key, tuple):
|
|
||||||
if len(key) > 0 and not isinstance(key[0], str):
|
|
||||||
i, key = key
|
|
||||||
else:
|
|
||||||
i, key = None, key
|
|
||||||
else:
|
|
||||||
i, key = key, None
|
|
||||||
|
|
||||||
# try to lookup by key
|
|
||||||
if key is not None:
|
|
||||||
attr = self.lookup(key)
|
|
||||||
if attr is not None:
|
|
||||||
return attr
|
|
||||||
|
|
||||||
# otherwise fallback to index
|
|
||||||
if i is not None and self.indexed:
|
|
||||||
return self.indexed[i % len(self.indexed)]
|
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -908,8 +893,8 @@ if __name__ == "__main__":
|
|||||||
dest='labels',
|
dest='labels',
|
||||||
action='append',
|
action='append',
|
||||||
type=lambda x: (
|
type=lambda x: (
|
||||||
lambda key, v: (
|
lambda ks, v: (
|
||||||
tuple(k.strip() for k in key.split(',')),
|
tuple(k.strip() for k in ks.split(',')),
|
||||||
v.strip())
|
v.strip())
|
||||||
)(*x.split('=', 1))
|
)(*x.split('=', 1))
|
||||||
if '=' in x else x.strip(),
|
if '=' in x else x.strip(),
|
||||||
@ -921,8 +906,8 @@ if __name__ == "__main__":
|
|||||||
dest='colors',
|
dest='colors',
|
||||||
action='append',
|
action='append',
|
||||||
type=lambda x: (
|
type=lambda x: (
|
||||||
lambda key, v: (
|
lambda ks, v: (
|
||||||
tuple(k.strip() for k in key.split(',')),
|
tuple(k.strip() for k in ks.split(',')),
|
||||||
v.strip())
|
v.strip())
|
||||||
)(*x.split('=', 1))
|
)(*x.split('=', 1))
|
||||||
if '=' in x else x.strip(),
|
if '=' in x else x.strip(),
|
||||||
|
|||||||
Reference in New Issue
Block a user