Эх сурвалжийг харах

tools: add custom search utility and updated coding rules

unknown 20 цаг өмнө
parent
commit
5d8786fafd
2 өөрчлөгдсөн 98 нэмэгдсэн , 0 устгасан
  1. 5 0
      .gemini_rules.md
  2. 93 0
      tools/search.py

+ 5 - 0
.gemini_rules.md

@@ -7,6 +7,11 @@ Before any `git push` or claiming a task is "ready", the AI MUST:
 3. **Production Build**: Run `npm run build` or `vite build` to ensure the project compiles correctly and there are no circular dependencies or missing imports in the production bundle.
 4. **Local Verification**: If possible, verify the UI changes via screenshots or browser tools.
 
+## Search and Investigation
+- **ALWAYS** use `python tools/search.py "query"` instead of `grep` or `ripgrep` for searching code.
+- Example: `python tools/search.py "t(\"admin.tabs\"" --include .vue .ts`
+- This ensures consistent results across different operating systems and avoids shell escaping issues.
+
 ## Localization Rules
 - **NEVER** edit `en.admin.json`, `ru.json`, etc., directly.
 - **NEVER** edit `translations.admin.json` or `translations.user.json` directly.

+ 93 - 0
tools/search.py

@@ -0,0 +1,93 @@
+import os
+import sys
+import argparse
+import re
+
+def search(query, path='.', include=None, exclude=None, is_regex=False):
+    """
+    Search for a string or regex in files.
+    """
+    results = []
+    
+    # Compile regex if needed
+    if is_regex:
+        try:
+            pattern = re.compile(query)
+        except re.error as e:
+            print(f"Error: Invalid regex: {e}")
+            return
+    
+    for root, dirs, files in os.walk(path):
+        # Skip some common directories
+        if any(d in root for d in ['.git', 'node_modules', 'dist', '__pycache__', '.gemini']):
+            continue
+            
+        for file in files:
+            # Filter by extension
+            if include and not any(file.endswith(ext) for ext in include):
+                continue
+            if exclude and any(file.endswith(ext) for ext in exclude):
+                continue
+                
+            file_path = os.path.join(root, file)
+            try:
+                with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
+                    for i, line in enumerate(f, 1):
+                        found = False
+                        if is_regex:
+                            if pattern.search(line):
+                                found = True
+                        else:
+                            if query in line:
+                                found = True
+                                
+                        if found:
+                            results.append({
+                                'file': file_path,
+                                'line': i,
+                                'content': line.strip()
+                            })
+            except Exception as e:
+                # print(f"Error reading {file_path}: {e}")
+                continue
+                
+    return results
+
+def main():
+    # Force UTF-8 output for Windows
+    import io
+    if sys.stdout.encoding != 'utf-8':
+        sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
+
+    parser = argparse.ArgumentParser(description="Clean and reliable code search tool.")
+    parser.add_argument("query", help="String or regex to search for")
+    parser.add_argument("--path", default=".", help="Directory to search in")
+    parser.add_argument("--include", nargs="+", help="Only include files with these extensions (e.g. .vue .ts)")
+    parser.add_argument("--exclude", nargs="+", help="Exclude files with these extensions")
+    parser.add_argument("--regex", action="store_true", help="Treat query as a regular expression")
+    
+    args = parser.parse_args()
+    
+    # Standardize extensions to start with dot
+    include = [ext if ext.startswith('.') else f'.{ext}' for ext in args.include] if args.include else None
+    exclude = [ext if ext.startswith('.') else f'.{ext}' for ext in args.exclude] if args.exclude else None
+    
+    results = search(args.query, args.path, include, exclude, args.regex)
+    
+    if not results:
+        print("No results found.")
+        return
+        
+    # Group results by file
+    from collections import defaultdict
+    grouped = defaultdict(list)
+    for res in results:
+        grouped[res['file']].append(res)
+        
+    for file_path, matches in grouped.items():
+        print(f"\n\033[1;34m{file_path}\033[0m")
+        for m in matches:
+            print(f"  \033[1;32m{m['line']}:\033[0m {m['content']}")
+
+if __name__ == "__main__":
+    main()