16
16
from .constants import (
17
17
SETTINGS_DIR , CONFIG_FILE , INDEX_FILE , CACHE_FILE
18
18
)
19
+ from .search .base import SearchStrategy
20
+ from .search .ugrep import UgrepStrategy
21
+ from .search .ripgrep import RipgrepStrategy
22
+ from .search .ag import AgStrategy
23
+ from .search .grep import GrepStrategy
24
+ from .search .basic import BasicSearchStrategy
25
+
26
+
27
+ # Prioritized list of search strategies
28
+ SEARCH_STRATEGY_CLASSES = [
29
+ UgrepStrategy ,
30
+ RipgrepStrategy ,
31
+ AgStrategy ,
32
+ GrepStrategy ,
33
+ BasicSearchStrategy ,
34
+ ]
35
+
36
+
37
+ def _get_available_strategies () -> list [SearchStrategy ]:
38
+ """
39
+ Detect and return a list of available search strategy instances,
40
+ ordered by preference.
41
+ """
42
+ available = []
43
+ for strategy_class in SEARCH_STRATEGY_CLASSES :
44
+ try :
45
+ strategy = strategy_class ()
46
+ if strategy .is_available ():
47
+ available .append (strategy )
48
+ except Exception as e :
49
+ print (f"Error initializing strategy { strategy_class .__name__ } : { e } " )
50
+ return available
51
+
19
52
20
53
class ProjectSettings :
21
54
"""Class for managing project settings and index data"""
@@ -29,7 +62,8 @@ def __init__(self, base_path, skip_load=False):
29
62
"""
30
63
self .base_path = base_path
31
64
self .skip_load = skip_load
32
- self ._search_tools_cache = None # Lazy-loaded search tools configuration
65
+ self .available_strategies : list [SearchStrategy ] = []
66
+ self .refresh_available_strategies ()
33
67
34
68
# Ensure the base path of the temporary directory exists
35
69
try :
@@ -478,84 +512,31 @@ def get_stats(self):
478
512
}
479
513
480
514
def get_search_tools_config (self ):
481
- """Get search tools configuration with lazy loading.
482
-
483
- Returns:
484
- dict: Search tools configuration with preferred tool and available tools
485
- """
486
- if self ._search_tools_cache is None :
487
- print ("Detecting available search tools..." )
488
- self ._search_tools_cache = self ._detect_search_tools ()
489
- print (f"Search tools detected. Preferred: { self ._search_tools_cache .get ('preferred_tool' , 'basic' )} " )
490
-
491
- return self ._search_tools_cache
515
+ """Get the configuration of available search tools.
492
516
493
- def get_preferred_search_tool (self ):
494
- """Get the preferred search tool name.
495
-
496
517
Returns:
497
- str: Name of preferred search tool ('ripgrep', 'ag', 'grep', or 'basic')
518
+ dict: A dictionary containing the list of available tool names.
498
519
"""
499
- config = self .get_search_tools_config ()
500
- return config .get ('preferred_tool' , 'basic' )
520
+ return {
521
+ "available_tools" : [s .name for s in self .available_strategies ],
522
+ "preferred_tool" : self .get_preferred_search_tool ().name if self .available_strategies else None
523
+ }
524
+
525
+ def get_preferred_search_tool (self ) -> SearchStrategy | None :
526
+ """Get the preferred search tool based on availability and priority.
501
527
502
- def _detect_search_tools (self ):
503
- """Detect available search tools on the system.
504
-
505
528
Returns:
506
- dict: Configuration with available tools and preferred tool
529
+ SearchStrategy: An instance of the preferred search strategy, or None.
507
530
"""
508
- tools_info = {
509
- 'detected_at' : self ._get_timestamp (),
510
- 'available_tools' : {},
511
- 'preferred_tool' : 'basic'
512
- }
513
-
514
- # Check tools in priority order: ugrep > ripgrep > ag > grep
515
- search_tools = [
516
- ('ugrep' , 'ug' ),
517
- ('ripgrep' , 'rg' ),
518
- ('ag' , 'ag' ),
519
- ('grep' , 'grep' )
520
- ]
531
+ if not self .available_strategies :
532
+ self .refresh_available_strategies ()
521
533
522
- for tool_name , command in search_tools :
523
- is_available = self ._is_tool_available (command )
524
- tools_info ['available_tools' ][tool_name ] = is_available
525
-
526
- # Set the first available tool as preferred
527
- if is_available and tools_info ['preferred_tool' ] == 'basic' :
528
- tools_info ['preferred_tool' ] = tool_name
529
-
530
- return tools_info
534
+ return self .available_strategies [0 ] if self .available_strategies else None
531
535
532
- def _is_tool_available (self , command ):
533
- """Check if a search tool is available on the system.
534
-
535
- Args:
536
- command (str): Command to check (e.g., 'rg', 'ag', 'grep')
537
-
538
- Returns:
539
- bool: True if tool is available, False otherwise
536
+ def refresh_available_strategies (self ):
540
537
"""
541
- try :
542
- result = subprocess .run (
543
- [command , '--version' ],
544
- capture_output = True ,
545
- timeout = 3 ,
546
- check = False
547
- )
548
- return result .returncode == 0
549
- except (FileNotFoundError , subprocess .TimeoutExpired , OSError ):
550
- return False
551
-
552
- def refresh_search_tools (self ):
553
- """Manually refresh search tools detection.
554
-
555
- Returns:
556
- dict: Updated search tools configuration
538
+ Force a refresh of the available search tools list.
557
539
"""
558
- print ("Refreshing search tools detection..." )
559
- self ._search_tools_cache = self ._detect_search_tools ()
560
- print (f"Search tools refreshed. Preferred: { self ._search_tools_cache .get ('preferred_tool' , 'basic' )} " )
561
- return self ._search_tools_cache
540
+ print ("Refreshing available search strategies..." )
541
+ self .available_strategies = _get_available_strategies ()
542
+ print (f"Available strategies found: { [s .name for s in self .available_strategies ]} " )
0 commit comments