home · contact · privacy
Add descriptors for "?" results on -m, -f, -s.
authorPlom Heller <plom@plomlompom.com>
Sun, 2 Aug 2026 18:55:18 +0000 (20:55 +0200)
committerPlom Heller <plom@plomlompom.com>
Sun, 2 Aug 2026 18:55:18 +0000 (20:55 +0200)
bricksplom.py

index 0169813ab81e33d02cfb338dc65825cf224ac600..6fd40aff591580629ce405e5657b4252a2570a38 100755 (executable)
@@ -46,7 +46,6 @@ BOX_PREFIX = 'box:'
 
 ARG_Q_MARK = '?'
 PARAM_Q_ID = f'id{CHAR_ATTR_EQ}'
-PARAM_Q_TEXT = f'text{CHAR_TEXTCONTAINS}'
 PARAM_Q_DELIMITERS = {CHAR_ATTR_EQ, CHAR_TEXTCONTAINS}
 TOK_SORT_BOX = 'box'
 TOK_SORT_ID = 'id'
@@ -58,6 +57,12 @@ LDRAW_MODES = {LDRAW_MODE_FILL_PATHS,
                LDRAW_MODE_VERIFY_PATHS,
                LDRAW_MODE_VERIFY_N_STUDS}
 
+ATTR_DESCS: dict[str, str] = {
+    'n_studs': 'number of studs',
+    'description': 'guesstimate what this be',
+    'ldraw': 'path of associated LDRAW file'
+}
+
 BrickListing = tuple[int, str, str]  # count, ID, comment
 PageColumn = tuple[BrickListing, ...]
 Page = tuple[PageColumn, ...]
@@ -153,25 +158,31 @@ class Lookupable:
     @classmethod
     def formatters(
             cls
-            ) -> dict[str, Callable[[Self], str]]:
+            ) -> dict[str, tuple[str, Callable[[Self], str]]]:
         'Available per-item string formatters.'
         formatters = {
-            'default': lambda item: item.show()
+            'default': (
+                'most commonly relevant infos',
+                lambda item: item.show())
             }
         if issubclass(cls, Textfiled):
-            formatters['raw'] = lambda item: item.raw()
+            formatters['raw'] = (
+                    'in source-file format',
+                    lambda item: item.raw())
         return formatters
 
     @classmethod
     def matchers(
             cls
-            ) -> dict[str, Callable[[Self, str], bool]]:
+            ) -> dict[str, tuple[str, Callable[[Self, str], bool]]]:
         'Available lookup matchers.'
         return {
-            PARAM_Q_ID: (lambda item, q_body:
-                         item.id_ == q_body),
-            PARAM_Q_TEXT: (lambda item, q_body:
-                           q_body.upper() in str(item).upper())
+            PARAM_Q_ID: (
+                'by ID of individual item',
+                lambda item, q_body: item.id_ == q_body),
+            f'text{CHAR_TEXTCONTAINS}': (
+                'text contained in item description',
+                lambda item, q_body: q_body.upper() in item.show().upper())
             }
 
     def match(
@@ -180,13 +191,15 @@ class Lookupable:
             query_body: str
             ) -> bool:
         'Return if self matches query.'
-        return self.matchers()[query_char](self, query_body)
+        return self.matchers()[query_char][1](self, query_body)
 
     @classmethod
     def _by_box_sorter(
             cls,
             to_id_of=''
-            ) -> Callable[['BricksDb', tuple[Self, ...]], tuple[Self, ...]]:
+            ) -> tuple[str,
+                       Callable[['BricksDb', tuple[Self, ...]],
+                                tuple[Self, ...]]]:
         def by_box(
                 db: 'BricksDb',
                 pre_sorted: tuple[Self, ...]
@@ -204,18 +217,20 @@ class Lookupable:
                         items += [to_move]
                         remains.remove(to_move)
             return tuple(items + remains)
-        return by_box
+        return 'by IDs of containing boxes', by_box
 
     @classmethod
     def sorters(
             cls
-            ) -> dict[str, Callable[['BricksDb', tuple[Self, ...]],
-                                    tuple[Self, ...]]]:
+            ) -> dict[str, tuple[str, Callable[['BricksDb', tuple[Self, ...]],
+                                               tuple[Self, ...]]]]:
         'Available sorters.'
         return {
-            TOK_SORT_ID: (lambda _, pre_sorted:
-                          tuple(sorted(pre_sorted,
-                                       key=lambda item: item.id_indented())))
+            TOK_SORT_ID: (
+                'by individual items\' IDs',
+                lambda _, pre_sorted:
+                tuple(sorted(pre_sorted,
+                             key=lambda item: item.id_indented())))
             }
 
 
@@ -250,8 +265,9 @@ class BrickColor(Textfiled, Lookupable):
     @classmethod
     def sorters(
             cls
-            ) -> dict[str, Callable[['BricksDb', tuple[Self, ...]],
-                                    tuple[Self, ...]]]:
+            ) -> dict[str, tuple[str,
+                                 Callable[['BricksDb', tuple[Self, ...]],
+                                          tuple[Self, ...]]]]:
         return super().sorters() | {TOK_SORT_BOX: cls._by_box_sorter('color')}
 
     def raw(
@@ -305,17 +321,17 @@ class BrickDesign(Textfiled, Lookupable):
     @classmethod
     def matchers(
             cls
-            ) -> dict[str, Callable[[Self, str], bool]]:
+            ) -> dict[str, tuple[str, Callable[[Self, str], bool]]]:
         def attr_matcher(
                 attr_name: str
-                ) -> Callable[[Self, str], bool]:
+                ) -> tuple[str, Callable[[Self, str], bool]]:
             def match(
                     item: Self,
                     q_body: str
                     ) -> bool:
                 assert q_body.isdigit()
                 return getattr(item, attr_name) == int(q_body)
-            return match
+            return 'by ' + ATTR_DESCS[attr_name], match
         return super().matchers() | {
             f'{attr_name}{CHAR_ATTR_EQ}': attr_matcher(attr_name)
             for attr_name, attr_type in BrickDesignData.__annotations__.items()
@@ -324,18 +340,20 @@ class BrickDesign(Textfiled, Lookupable):
     @classmethod
     def sorters(
             cls
-            ) -> dict[str, Callable[['BricksDb', tuple[Self, ...]],
-                                    tuple[Self, ...]]]:
+            ) -> dict[str, tuple[str,
+                                 Callable[['BricksDb', tuple[Self, ...]],
+                                          tuple[Self, ...]]]]:
         def attr_sorter(
                 attr_name: str,
-                ) -> Callable[[BricksDb, tuple[Self, ...]], tuple[Self, ...]]:
+                ) -> tuple[str, Callable[[BricksDb, tuple[Self, ...]],
+                                         tuple[Self, ...]]]:
             def f_sort(
                     _: BricksDb,
                     pre_sorted: tuple[Self, ...]
                     ) -> tuple[Self, ...]:
                 return tuple(sorted(pre_sorted,
                                     key=lambda item: getattr(item, attr_name)))
-            return f_sort
+            return 'by ' + ATTR_DESCS[attr_name], f_sort
         return super().sorters()\
             | {TOK_SORT_BOX: cls._by_box_sorter('design')}\
             | {attr_name: attr_sorter(attr_name)
@@ -415,8 +433,8 @@ class Brick(Textfiled, WithDb, Lookupable):
     @classmethod
     def sorters(
             cls
-            ) -> dict[str, Callable[['BricksDb', tuple[Self, ...]],
-                                    tuple[Self, ...]]]:
+            ) -> dict[str, tuple[str, Callable[['BricksDb', tuple[Self, ...]],
+                                               tuple[Self, ...]]]]:
         return super().sorters() | {TOK_SORT_BOX: cls._by_box_sorter()}
 
     @classmethod
@@ -537,15 +555,6 @@ class BrickSet(Textfiled, WithDb, Lookupable):
             ) -> str:
         return f'{self.id_} {self._is_in_str} {self.description}'
 
-    @classmethod
-    def matchers(
-            cls
-            ) -> dict[str, Callable[[Self, str], bool]]:
-        return super().matchers() | {
-            PARAM_Q_TEXT: (lambda item, q_body:
-                           q_body.upper() in item.show().upper())
-            }
-
     def _format_paginated(
             self,
             format_line: Callable[[int, str, str], str]
@@ -823,19 +832,21 @@ class BricksDb:
                 match_val = match_by[idx+1:]
                 break
         cls = self.lookupables[table_name]
-        for arg_key, keys in [(arg, m().keys())
-                              for arg, m in ((match_key, cls.matchers),
-                                             (sort_by, cls.sorters),
-                                             (formatter, cls.formatters))]:
+        for arg_key, x_ers in [(arg, m())
+                               for arg, m in ((match_key, cls.matchers),
+                                              (sort_by, cls.sorters),
+                                              (formatter, cls.formatters))]:
+            keys = x_ers.keys()
             if arg_key == ARG_Q_MARK:
-                return CHAR_NEWLINE.join(keys)
+                return CHAR_NEWLINE.join([f'{key} – {x_ers[key][0]}'
+                                          for key in sorted(keys)])
             assert (not arg_key) or arg_key in keys, (arg_key, keys)
         items = tuple(getattr(self, table_name).values())
         if items and sort_by:
-            items = cls.sorters()[sort_by](self, items)
+            items = cls.sorters()[sort_by][1](self, items)
         if items and match_by:
             items = tuple(x for x in items if x.match(match_key, match_val))
-        return CHAR_NEWLINE.join([cls.formatters()[formatter](item)
+        return CHAR_NEWLINE.join([cls.formatters()[formatter][1](item)
                                   for item in items])