@@ -708,12 +708,15 @@ def find_by_name(
708708 # Search all
709709 funcs = code_finder .find_by_function_name (name , fuzzy_search = False )
710710 classes = code_finder .find_by_class_name (name , fuzzy_search = False )
711+ variables = code_finder .find_by_variable_name (name )
711712
712713 for f in funcs : f ['type' ] = 'Function'
713714 for c in classes : c ['type' ] = 'Class'
715+ for v in variables : v ['type' ] = 'Variable'
714716
715717 results .extend (funcs )
716718 results .extend (classes )
719+ results .extend (variables )
717720
718721 elif type .lower () == 'function' :
719722 results = code_finder .find_by_function_name (name , fuzzy_search = False )
@@ -723,6 +726,10 @@ def find_by_name(
723726 results = code_finder .find_by_class_name (name , fuzzy_search = False )
724727 for r in results : r ['type' ] = 'Class'
725728
729+ elif type .lower () == 'variable' :
730+ results = code_finder .find_by_variable_name (name )
731+ for r in results : r ['type' ] = 'Variable'
732+
726733 elif type .lower () == 'file' :
727734 # Quick query for file
728735 with db_manager .get_driver ().session () as session :
@@ -780,7 +787,7 @@ def find_by_pattern(
780787 if not case_sensitive :
781788 query = """
782789 MATCH (n)
783- WHERE (n:Function OR n:Class OR n:Module) AND toLower(n.name) CONTAINS toLower($pattern)
790+ WHERE (n:Function OR n:Class OR n:Module OR n:Variable ) AND toLower(n.name) CONTAINS toLower($pattern)
784791 RETURN
785792 labels(n)[0] as type,
786793 n.name as name,
@@ -793,7 +800,7 @@ def find_by_pattern(
793800 else :
794801 query = """
795802 MATCH (n)
796- WHERE (n:Function OR n:Class OR n:Module) AND n.name CONTAINS $pattern
803+ WHERE (n:Function OR n:Class OR n:Module OR n:Variable ) AND n.name CONTAINS $pattern
797804 RETURN
798805 labels(n)[0] as type,
799806 n.name as name,
@@ -882,6 +889,194 @@ def find_by_type(
882889 finally :
883890 db_manager .close_driver ()
884891
892+ @find_app .command ("variable" )
893+ def find_by_variable (
894+ name : str = typer .Argument (..., help = "Variable name to search for" )
895+ ):
896+ """
897+ Find variables by name.
898+
899+ Examples:
900+ cgc find variable MAX_RETRIES
901+ cgc find variable config
902+ """
903+ _load_credentials ()
904+ services = _initialize_services ()
905+ if not all (services ):
906+ return
907+ db_manager , graph_builder , code_finder = services
908+
909+ try :
910+ results = code_finder .find_by_variable_name (name )
911+
912+ if not results :
913+ console .print (f"[yellow]No variables found with name '{ name } '[/yellow]" )
914+ return
915+
916+ table = Table (show_header = True , header_style = "bold magenta" , box = box .ROUNDED )
917+ table .add_column ("Name" , style = "cyan" )
918+ table .add_column ("File" , style = "dim" , overflow = "fold" )
919+ table .add_column ("Line" , style = "green" , justify = "right" )
920+ table .add_column ("Context" , style = "yellow" )
921+
922+ for res in results :
923+ table .add_row (
924+ res .get ('name' , '' ),
925+ res .get ('file_path' , '' ),
926+ str (res .get ('line_number' , '' )),
927+ res .get ('context' , '' ) or 'module'
928+ )
929+
930+ console .print (f"[cyan]Found { len (results )} variable(s) named '{ name } ':[/cyan]" )
931+ console .print (table )
932+ finally :
933+ db_manager .close_driver ()
934+
935+ @find_app .command ("content" )
936+ def find_by_content_search (
937+ query : str = typer .Argument (..., help = "Text to search for in source code and docstrings" )
938+ ):
939+ """
940+ Search code content (source and docstrings) using full-text index.
941+
942+ Examples:
943+ cgc find content "error 503"
944+ cgc find content "TODO: refactor"
945+ """
946+ _load_credentials ()
947+ services = _initialize_services ()
948+ if not all (services ):
949+ return
950+ db_manager , graph_builder , code_finder = services
951+
952+ try :
953+ try :
954+ results = code_finder .find_by_content (query )
955+ except Exception as e :
956+ error_msg = str (e ).lower ()
957+ if 'fulltext' in error_msg or 'db.index.fulltext' in error_msg :
958+ console .print ("\n [bold red]❌ Full-text search is not supported on FalkorDB[/bold red]\n " )
959+ console .print ("[yellow]💡 You have two options:[/yellow]\n " )
960+ console .print (" 1. [cyan]Switch to Neo4j:[/cyan]" )
961+ console .print (f" [dim]cgc --database neo4j find content \" { query } \" [/dim]\n " )
962+ console .print (" 2. [cyan]Use pattern search instead:[/cyan]" )
963+ console .print (f" [dim]cgc find pattern \" { query } \" [/dim]" )
964+ console .print (" [dim](searches in names only, not source code)[/dim]\n " )
965+ return
966+ else :
967+ # Re-raise if it's a different error
968+ raise
969+
970+ if not results :
971+ console .print (f"[yellow]No content matches found for '{ query } '[/yellow]" )
972+ return
973+
974+ table = Table (show_header = True , header_style = "bold magenta" , box = box .ROUNDED )
975+ table .add_column ("Name" , style = "cyan" )
976+ table .add_column ("Type" , style = "blue" )
977+ table .add_column ("File" , style = "dim" , overflow = "fold" )
978+ table .add_column ("Line" , style = "green" , justify = "right" )
979+
980+ for res in results :
981+ table .add_row (
982+ res .get ('name' , '' ),
983+ res .get ('type' , 'Unknown' ),
984+ res .get ('file_path' , '' ),
985+ str (res .get ('line_number' , '' ))
986+ )
987+
988+ console .print (f"[cyan]Found { len (results )} content match(es) for '{ query } ':[/cyan]" )
989+ console .print (table )
990+ finally :
991+ db_manager .close_driver ()
992+
993+ @find_app .command ("decorator" )
994+ def find_by_decorator_search (
995+ decorator : str = typer .Argument (..., help = "Decorator name to search for" ),
996+ file : Optional [str ] = typer .Option (None , "--file" , "-f" , help = "Specific file path" )
997+ ):
998+ """
999+ Find functions with a specific decorator.
1000+
1001+ Examples:
1002+ cgc find decorator app.route
1003+ cgc find decorator test --file tests/test_main.py
1004+ """
1005+ _load_credentials ()
1006+ services = _initialize_services ()
1007+ if not all (services ):
1008+ return
1009+ db_manager , graph_builder , code_finder = services
1010+
1011+ try :
1012+ results = code_finder .find_functions_by_decorator (decorator , file )
1013+
1014+ if not results :
1015+ console .print (f"[yellow]No functions found with decorator '@{ decorator } '[/yellow]" )
1016+ return
1017+
1018+ table = Table (show_header = True , header_style = "bold magenta" , box = box .ROUNDED )
1019+ table .add_column ("Function" , style = "cyan" )
1020+ table .add_column ("File" , style = "dim" , overflow = "fold" )
1021+ table .add_column ("Line" , style = "green" , justify = "right" )
1022+ table .add_column ("Decorators" , style = "yellow" )
1023+
1024+ for res in results :
1025+ decorators_str = ", " .join (res .get ('decorators' , []))
1026+ table .add_row (
1027+ res .get ('function_name' , '' ),
1028+ res .get ('file_path' , '' ),
1029+ str (res .get ('line_number' , '' )),
1030+ decorators_str
1031+ )
1032+
1033+ console .print (f"[cyan]Found { len (results )} function(s) with decorator '@{ decorator } ':[/cyan]" )
1034+ console .print (table )
1035+ finally :
1036+ db_manager .close_driver ()
1037+
1038+ @find_app .command ("argument" )
1039+ def find_by_argument_search (
1040+ argument : str = typer .Argument (..., help = "Argument/parameter name to search for" ),
1041+ file : Optional [str ] = typer .Option (None , "--file" , "-f" , help = "Specific file path" )
1042+ ):
1043+ """
1044+ Find functions that take a specific argument/parameter.
1045+
1046+ Examples:
1047+ cgc find argument password
1048+ cgc find argument user_id --file src/auth.py
1049+ """
1050+ _load_credentials ()
1051+ services = _initialize_services ()
1052+ if not all (services ):
1053+ return
1054+ db_manager , graph_builder , code_finder = services
1055+
1056+ try :
1057+ results = code_finder .find_functions_by_argument (argument , file )
1058+
1059+ if not results :
1060+ console .print (f"[yellow]No functions found with argument '{ argument } '[/yellow]" )
1061+ return
1062+
1063+ table = Table (show_header = True , header_style = "bold magenta" , box = box .ROUNDED )
1064+ table .add_column ("Function" , style = "cyan" )
1065+ table .add_column ("File" , style = "dim" , overflow = "fold" )
1066+ table .add_column ("Line" , style = "green" , justify = "right" )
1067+
1068+ for res in results :
1069+ table .add_row (
1070+ res .get ('function_name' , '' ),
1071+ res .get ('file_path' , '' ),
1072+ str (res .get ('line_number' , '' ))
1073+ )
1074+
1075+ console .print (f"[cyan]Found { len (results )} function(s) with argument '{ argument } ':[/cyan]" )
1076+ console .print (table )
1077+ finally :
1078+ db_manager .close_driver ()
1079+
8851080
8861081# ============================================================================
8871082# ANALYZE COMMAND GROUP - Code Analysis & Relationships
@@ -1232,6 +1427,114 @@ def analyze_dead_code(
12321427 finally :
12331428 db_manager .close_driver ()
12341429
1430+ @analyze_app .command ("overrides" )
1431+ def analyze_overrides (
1432+ function_name : str = typer .Argument (..., help = "Function/method name to find implementations of" )
1433+ ):
1434+ """
1435+ Find all implementations of a function across different classes.
1436+
1437+ Useful for finding polymorphic implementations and method overrides.
1438+
1439+ Example:
1440+ cgc analyze overrides area
1441+ cgc analyze overrides process
1442+ """
1443+ _load_credentials ()
1444+ services = _initialize_services ()
1445+ if not all (services ):
1446+ return
1447+ db_manager , graph_builder , code_finder = services
1448+
1449+ try :
1450+ results = code_finder .find_function_overrides (function_name )
1451+
1452+ if not results :
1453+ console .print (f"[yellow]No implementations found for function '{ function_name } '[/yellow]" )
1454+ return
1455+
1456+ table = Table (show_header = True , header_style = "bold magenta" , box = box .ROUNDED )
1457+ table .add_column ("Class" , style = "cyan" )
1458+ table .add_column ("Function" , style = "green" )
1459+ table .add_column ("File" , style = "dim" , overflow = "fold" )
1460+ table .add_column ("Line" , style = "yellow" , justify = "right" )
1461+
1462+ for res in results :
1463+ table .add_row (
1464+ res .get ('class_name' , '' ),
1465+ res .get ('function_name' , '' ),
1466+ res .get ('class_file_path' , '' ),
1467+ str (res .get ('function_line_number' , '' ))
1468+ )
1469+
1470+ console .print (f"\n [bold cyan]Found { len (results )} implementation(s) of '{ function_name } ':[/bold cyan]" )
1471+ console .print (table )
1472+ finally :
1473+ db_manager .close_driver ()
1474+
1475+ @analyze_app .command ("variable" )
1476+ def analyze_variable_usage (
1477+ variable_name : str = typer .Argument (..., help = "Variable name to analyze" )
1478+ ):
1479+ """
1480+ Analyze where a variable is defined and used across the codebase.
1481+
1482+ Shows all instances of the variable and their scope (function, class, module).
1483+
1484+ Example:
1485+ cgc analyze variable MAX_RETRIES
1486+ cgc analyze variable config
1487+ """
1488+ _load_credentials ()
1489+ services = _initialize_services ()
1490+ if not all (services ):
1491+ return
1492+ db_manager , graph_builder , code_finder = services
1493+
1494+ try :
1495+ # Get variable usage scope
1496+ scope_results = code_finder .find_variable_usage_scope (variable_name )
1497+ instances = scope_results .get ('instances' , [])
1498+
1499+ if not instances :
1500+ console .print (f"[yellow]No instances found for variable '{ variable_name } '[/yellow]" )
1501+ return
1502+
1503+ console .print (f"\n [bold cyan]Variable '{ variable_name } ' Usage Analysis:[/bold cyan]\n " )
1504+
1505+ # Group by scope type
1506+ by_scope = {}
1507+ for inst in instances :
1508+ scope_type = inst .get ('scope_type' , 'unknown' )
1509+ if scope_type not in by_scope :
1510+ by_scope [scope_type ] = []
1511+ by_scope [scope_type ].append (inst )
1512+
1513+ # Display by scope
1514+ for scope_type , items in by_scope .items ():
1515+ console .print (f"[bold yellow]{ scope_type .upper ()} Scope ({ len (items )} instance(s)):[/bold yellow]" )
1516+
1517+ table = Table (show_header = True , header_style = "bold magenta" , box = box .ROUNDED )
1518+ table .add_column ("Scope Name" , style = "cyan" )
1519+ table .add_column ("File" , style = "dim" , overflow = "fold" )
1520+ table .add_column ("Line" , style = "green" , justify = "right" )
1521+ table .add_column ("Value" , style = "yellow" )
1522+
1523+ for item in items :
1524+ table .add_row (
1525+ item .get ('scope_name' , '' ),
1526+ item .get ('file_path' , '' ),
1527+ str (item .get ('line_number' , '' )),
1528+ str (item .get ('variable_value' , '' ))[:50 ] if item .get ('variable_value' ) else '-'
1529+ )
1530+
1531+ console .print (table )
1532+ console .print ()
1533+
1534+ console .print (f"[dim]Total: { len (instances )} instance(s) across { len (by_scope )} scope type(s)[/dim]" )
1535+ finally :
1536+ db_manager .close_driver ()
1537+
12351538
12361539# ============================================================================
12371540# QUERY COMMAND - Raw Cypher Queries
0 commit comments