18
18
19
19
class TalkPipeDoc :
20
20
"""Represents a single TalkPipe component (class or function)."""
21
-
22
- def __init__ (self , name : str , chatterlang_name : str , doc_type : str ,
23
- module : str , base_classes : List [str ], docstring : str ,
21
+
22
+ def __init__ (self , name : str , chatterlang_names : List [ str ] , doc_type : str ,
23
+ module : str , base_classes : List [str ], docstring : str ,
24
24
parameters : Dict [str , str ]):
25
25
self .name = name
26
- self .chatterlang_name = chatterlang_name
26
+ self .chatterlang_names = chatterlang_names # List of all names for this component
27
+ self .primary_name = chatterlang_names [0 ] # Primary name for display
27
28
self .doc_type = doc_type # 'Source', 'Segment', 'Field Segment'
28
29
self .module = module
29
30
self .base_classes = base_classes
30
31
self .docstring = docstring
31
32
self .parameters = parameters
32
33
34
+ @property
35
+ def chatterlang_name (self ):
36
+ """Backward compatibility property."""
37
+ return self .primary_name
38
+
39
+ @property
40
+ def all_names_display (self ):
41
+ """Display string showing all names."""
42
+ return ", " .join (self .chatterlang_names )
43
+
33
44
34
45
class TalkPipeBrowser :
35
46
"""Interactive terminal browser for TalkPipe documentation."""
36
-
47
+
37
48
def __init__ (self ):
38
- self .components : Dict [str , TalkPipeDoc ] = {}
49
+ self .components : Dict [str , TalkPipeDoc ] = {} # Maps primary name to component
50
+ self .name_to_primary : Dict [str , str ] = {} # Maps any name to primary name
39
51
self .modules : Dict [str , List [str ]] = {}
40
52
self .load_components ()
41
53
@@ -44,23 +56,38 @@ def _extract_parameters(self, cls: type) -> Dict[str, str]:
44
56
return extract_parameters_dict (cls )
45
57
46
58
def load_components (self ):
47
- """Load all components from the plugin system."""
59
+ """Load all components from the plugin system, grouping multiple names for the same class ."""
48
60
load_plugins () # Ensure plugins are loaded
49
-
61
+
62
+ # Group components by class to consolidate multiple names
63
+ class_to_names = {}
64
+ class_to_type = {}
65
+
50
66
# Load sources
51
67
for chatterlang_name , cls in input_registry .all .items ():
52
- component_info = extract_component_info (chatterlang_name , cls , "Source" )
53
- if component_info :
54
- self ._load_component_from_info (component_info )
55
-
68
+ if cls not in class_to_names :
69
+ class_to_names [cls ] = []
70
+ class_to_type [cls ] = "Source"
71
+ class_to_names [cls ].append (chatterlang_name )
72
+
56
73
# Load segments
57
74
for chatterlang_name , cls in segment_registry .all .items ():
58
- component_type = detect_component_type (cls , "Segment" )
59
- component_info = extract_component_info (chatterlang_name , cls , component_type )
75
+ if cls not in class_to_names :
76
+ class_to_names [cls ] = []
77
+ class_to_type [cls ] = detect_component_type (cls , "Segment" )
78
+ class_to_names [cls ].append (chatterlang_name )
79
+
80
+ # Create consolidated components
81
+ for cls , names in class_to_names .items ():
82
+ # Sort names to ensure consistent primary name selection
83
+ names .sort ()
84
+ primary_name = names [0 ]
85
+
86
+ component_info = extract_component_info (primary_name , cls , class_to_type [cls ])
60
87
if component_info :
61
- self ._load_component_from_info (component_info )
88
+ self ._load_component_from_info (component_info , names )
62
89
63
- def _load_component_from_info (self , component_info ):
90
+ def _load_component_from_info (self , component_info , all_names : List [ str ] ):
64
91
"""Load a single component from ComponentInfo into the browser."""
65
92
try :
66
93
# Convert parameters from ParamSpec list to dict for browser compatibility
@@ -100,20 +127,26 @@ def _load_component_from_info(self, component_info):
100
127
# Create component
101
128
component = TalkPipeDoc (
102
129
name = component_info .name ,
103
- chatterlang_name = component_info . chatterlang_name ,
130
+ chatterlang_names = all_names ,
104
131
doc_type = component_info .component_type ,
105
132
module = component_info .module ,
106
133
base_classes = component_info .base_classes ,
107
134
docstring = component_info .docstring ,
108
135
parameters = parameters
109
136
)
110
-
111
- self .components [component_info .chatterlang_name ] = component
137
+
138
+ # Store component under primary name
139
+ primary_name = all_names [0 ]
140
+ self .components [primary_name ] = component
141
+
142
+ # Map all names to the primary name for lookup
143
+ for name in all_names :
144
+ self .name_to_primary [name ] = primary_name
112
145
113
146
# Group by module
114
147
if component_info .module not in self .modules :
115
148
self .modules [component_info .module ] = []
116
- self .modules [component_info .module ].append (component_info . chatterlang_name )
149
+ self .modules [component_info .module ].append (primary_name )
117
150
118
151
except Exception as e :
119
152
print (f"Warning: Failed to load component { component_info .chatterlang_name } : { e } " )
@@ -223,24 +256,29 @@ def _list_module_components(self, module_name: str):
223
256
type_icon = "🔧"
224
257
else :
225
258
type_icon = "⚙️"
226
- print (f"{ type_icon } { comp .chatterlang_name :<20 } ({ comp .name } )" )
259
+ print (f"{ type_icon } { comp .all_names_display :<30 } ({ comp .name } )" )
227
260
print ()
228
261
229
262
def _show_component (self , component_name : str ):
230
263
"""Show detailed information about a component."""
231
- # Try exact match first
232
- component = self .components .get (component_name )
233
-
234
- # If not found, try case-insensitive search
264
+ # Try exact match using name lookup
265
+ primary_name = self .name_to_primary .get (component_name )
266
+ component = None
267
+
268
+ if primary_name :
269
+ component = self .components .get (primary_name )
270
+
271
+ # If not found, try case-insensitive search in all names
235
272
if not component :
236
- matches = [name for name in self .components .keys ()
273
+ matches = [name for name in self .name_to_primary .keys ()
237
274
if name .lower () == component_name .lower ()]
238
275
if matches :
239
- component = self .components [matches [0 ]]
276
+ primary_name = self .name_to_primary [matches [0 ]]
277
+ component = self .components [primary_name ]
240
278
241
279
# If still not found, suggest similar names
242
280
if not component :
243
- similar = [name for name in self .components .keys ()
281
+ similar = [name for name in self .name_to_primary .keys ()
244
282
if component_name .lower () in name .lower ()]
245
283
if similar :
246
284
print (f"Component '{ component_name } ' not found. Did you mean:" )
@@ -252,7 +290,7 @@ def _show_component(self, component_name: str):
252
290
253
291
# Display component details
254
292
print (f"\n { '=' * 60 } " )
255
- print (f"📋 { component .chatterlang_name } " )
293
+ print (f"📋 { component .all_names_display } " )
256
294
print (f"{ '=' * 60 } " )
257
295
print (f"Class/Function: { component .name } " )
258
296
print (f"Type: { component .doc_type } " )
@@ -281,11 +319,12 @@ def _search_components(self, search_term: str):
281
319
"""Search for components by name or description."""
282
320
search_lower = search_term .lower ()
283
321
matches = []
284
-
322
+
285
323
for comp_name , component in self .components .items ():
286
- # Search in chatterlang name, class name, and docstring
287
- if (search_lower in comp_name .lower () or
288
- search_lower in component .name .lower () or
324
+ # Search in all chatterlang names, class name, and docstring
325
+ name_match = any (search_lower in name .lower () for name in component .chatterlang_names )
326
+ if (name_match or
327
+ search_lower in component .name .lower () or
289
328
search_lower in component .docstring .lower ()):
290
329
matches .append (component )
291
330
@@ -296,14 +335,14 @@ def _search_components(self, search_term: str):
296
335
print (f"\n Search Results for '{ search_term } ' ({ len (matches )} found):" )
297
336
print ("-" * 60 )
298
337
299
- for component in sorted (matches , key = lambda x : x .chatterlang_name ):
338
+ for component in sorted (matches , key = lambda x : x .primary_name ):
300
339
if component .doc_type == "Source" :
301
340
type_icon = "🔌"
302
341
elif component .doc_type == "Field Segment" :
303
342
type_icon = "🔧"
304
343
else :
305
344
type_icon = "⚙️"
306
- print (f"{ type_icon } { component .chatterlang_name :<20 } ({ component .module } )" )
345
+ print (f"{ type_icon } { component .all_names_display :<30 } ({ component .module } )" )
307
346
308
347
# Show brief description
309
348
if component .docstring :
0 commit comments