codegraph-nav 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- codegraph_nav/__init__.py +194 -0
- codegraph_nav/ast_grep_analyzer.py +448 -0
- codegraph_nav/cli.py +223 -0
- codegraph_nav/code_navigator.py +1328 -0
- codegraph_nav/code_search.py +1009 -0
- codegraph_nav/colors.py +209 -0
- codegraph_nav/completions.py +354 -0
- codegraph_nav/dart_analyzer.py +301 -0
- codegraph_nav/dependency_graph.py +814 -0
- codegraph_nav/domain/__init__.py +20 -0
- codegraph_nav/domain/routes.py +337 -0
- codegraph_nav/domain/schemas.py +229 -0
- codegraph_nav/domain/tags.py +87 -0
- codegraph_nav/exporters.py +563 -0
- codegraph_nav/go_analyzer.py +273 -0
- codegraph_nav/graph/__init__.py +72 -0
- codegraph_nav/graph/builder.py +409 -0
- codegraph_nav/graph/communities.py +402 -0
- codegraph_nav/graph/flows.py +311 -0
- codegraph_nav/graph/query.py +380 -0
- codegraph_nav/graph/schema.py +266 -0
- codegraph_nav/graph/search.py +257 -0
- codegraph_nav/graph/store.py +517 -0
- codegraph_nav/hints.py +195 -0
- codegraph_nav/import_resolver.py +891 -0
- codegraph_nav/js_ts_analyzer.py +564 -0
- codegraph_nav/line_reader.py +664 -0
- codegraph_nav/mcp/__init__.py +39 -0
- codegraph_nav/mcp/__main__.py +5 -0
- codegraph_nav/mcp/server.py +2228 -0
- codegraph_nav/py.typed +2 -0
- codegraph_nav/ruby_analyzer.py +259 -0
- codegraph_nav/rust_analyzer.py +379 -0
- codegraph_nav/token_efficient_renderer.py +743 -0
- codegraph_nav/watcher.py +382 -0
- codegraph_nav-0.1.0.dist-info/METADATA +487 -0
- codegraph_nav-0.1.0.dist-info/RECORD +41 -0
- codegraph_nav-0.1.0.dist-info/WHEEL +5 -0
- codegraph_nav-0.1.0.dist-info/entry_points.txt +4 -0
- codegraph_nav-0.1.0.dist-info/licenses/LICENSE +21 -0
- codegraph_nav-0.1.0.dist-info/top_level.txt +1 -0
codegraph_nav/colors.py
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Terminal color utilities for Code Navigator.
|
|
3
|
+
|
|
4
|
+
Provides ANSI color support with automatic detection of terminal capabilities.
|
|
5
|
+
Respects the NO_COLOR environment variable (https://no-color.org/).
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
>>> from codegraph_nav.colors import Colors
|
|
9
|
+
>>> c = Colors()
|
|
10
|
+
>>> print(c.green("Success!"))
|
|
11
|
+
>>> print(c.cyan("Line 42"))
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
import threading
|
|
17
|
+
|
|
18
|
+
__version__ = "0.1.0"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class Colors:
|
|
22
|
+
"""ANSI color utility class with automatic terminal detection.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
enabled: Whether colors are enabled (auto-detected or manually set).
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
>>> c = Colors()
|
|
29
|
+
>>> print(c.green("found") + " in " + c.cyan("file.py"))
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
# ANSI escape codes
|
|
33
|
+
RESET = "\033[0m"
|
|
34
|
+
BOLD = "\033[1m"
|
|
35
|
+
DIM = "\033[2m"
|
|
36
|
+
|
|
37
|
+
# Foreground colors
|
|
38
|
+
BLACK = "\033[30m"
|
|
39
|
+
RED = "\033[31m"
|
|
40
|
+
GREEN = "\033[32m"
|
|
41
|
+
YELLOW = "\033[33m"
|
|
42
|
+
BLUE = "\033[34m"
|
|
43
|
+
MAGENTA = "\033[35m"
|
|
44
|
+
CYAN = "\033[36m"
|
|
45
|
+
WHITE = "\033[37m"
|
|
46
|
+
|
|
47
|
+
# Bright foreground colors
|
|
48
|
+
BRIGHT_BLACK = "\033[90m"
|
|
49
|
+
BRIGHT_RED = "\033[91m"
|
|
50
|
+
BRIGHT_GREEN = "\033[92m"
|
|
51
|
+
BRIGHT_YELLOW = "\033[93m"
|
|
52
|
+
BRIGHT_BLUE = "\033[94m"
|
|
53
|
+
BRIGHT_MAGENTA = "\033[95m"
|
|
54
|
+
BRIGHT_CYAN = "\033[96m"
|
|
55
|
+
BRIGHT_WHITE = "\033[97m"
|
|
56
|
+
|
|
57
|
+
def __init__(self, enabled: bool | None = None):
|
|
58
|
+
"""Initialize Colors with optional override.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
enabled: Force colors on/off. If None, auto-detect.
|
|
62
|
+
"""
|
|
63
|
+
if enabled is not None:
|
|
64
|
+
self.enabled = enabled
|
|
65
|
+
else:
|
|
66
|
+
self.enabled = self._should_enable_colors()
|
|
67
|
+
|
|
68
|
+
def _should_enable_colors(self) -> bool:
|
|
69
|
+
"""Determine if colors should be enabled based on environment."""
|
|
70
|
+
# Respect NO_COLOR environment variable (https://no-color.org/)
|
|
71
|
+
if os.environ.get("NO_COLOR"):
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
# Check FORCE_COLOR for explicit enable
|
|
75
|
+
if os.environ.get("FORCE_COLOR"):
|
|
76
|
+
return True
|
|
77
|
+
|
|
78
|
+
# Check if stdout is a TTY
|
|
79
|
+
if not hasattr(sys.stdout, "isatty") or not sys.stdout.isatty():
|
|
80
|
+
return False
|
|
81
|
+
|
|
82
|
+
# Check TERM environment variable
|
|
83
|
+
term = os.environ.get("TERM", "")
|
|
84
|
+
if term == "dumb":
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
# Windows: check for Windows Terminal or newer cmd
|
|
88
|
+
if sys.platform == "win32":
|
|
89
|
+
# Windows Terminal and modern Windows 10+ support ANSI
|
|
90
|
+
return (
|
|
91
|
+
os.environ.get("WT_SESSION") # Windows Terminal
|
|
92
|
+
or os.environ.get("ANSICON") # ANSICON
|
|
93
|
+
or "256color" in term
|
|
94
|
+
or os.environ.get("TERM_PROGRAM") == "vscode"
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
return True
|
|
98
|
+
|
|
99
|
+
def _colorize(self, text: str, color: str) -> str:
|
|
100
|
+
"""Apply color to text if colors are enabled."""
|
|
101
|
+
if not self.enabled:
|
|
102
|
+
return text
|
|
103
|
+
return f"{color}{text}{self.RESET}"
|
|
104
|
+
|
|
105
|
+
# Basic colors
|
|
106
|
+
def red(self, text: str) -> str:
|
|
107
|
+
"""Red text (errors, warnings)."""
|
|
108
|
+
return self._colorize(text, self.RED)
|
|
109
|
+
|
|
110
|
+
def green(self, text: str) -> str:
|
|
111
|
+
"""Green text (success, found items)."""
|
|
112
|
+
return self._colorize(text, self.GREEN)
|
|
113
|
+
|
|
114
|
+
def yellow(self, text: str) -> str:
|
|
115
|
+
"""Yellow text (context, warnings)."""
|
|
116
|
+
return self._colorize(text, self.YELLOW)
|
|
117
|
+
|
|
118
|
+
def blue(self, text: str) -> str:
|
|
119
|
+
"""Blue text."""
|
|
120
|
+
return self._colorize(text, self.BLUE)
|
|
121
|
+
|
|
122
|
+
def magenta(self, text: str) -> str:
|
|
123
|
+
"""Magenta text (types, decorators)."""
|
|
124
|
+
return self._colorize(text, self.MAGENTA)
|
|
125
|
+
|
|
126
|
+
def cyan(self, text: str) -> str:
|
|
127
|
+
"""Cyan text (line numbers, file paths)."""
|
|
128
|
+
return self._colorize(text, self.CYAN)
|
|
129
|
+
|
|
130
|
+
def white(self, text: str) -> str:
|
|
131
|
+
"""White text."""
|
|
132
|
+
return self._colorize(text, self.WHITE)
|
|
133
|
+
|
|
134
|
+
# Bright colors
|
|
135
|
+
def bright_green(self, text: str) -> str:
|
|
136
|
+
"""Bright green text."""
|
|
137
|
+
return self._colorize(text, self.BRIGHT_GREEN)
|
|
138
|
+
|
|
139
|
+
def bright_yellow(self, text: str) -> str:
|
|
140
|
+
"""Bright yellow text."""
|
|
141
|
+
return self._colorize(text, self.BRIGHT_YELLOW)
|
|
142
|
+
|
|
143
|
+
def bright_cyan(self, text: str) -> str:
|
|
144
|
+
"""Bright cyan text."""
|
|
145
|
+
return self._colorize(text, self.BRIGHT_CYAN)
|
|
146
|
+
|
|
147
|
+
# Styles
|
|
148
|
+
def bold(self, text: str) -> str:
|
|
149
|
+
"""Bold text."""
|
|
150
|
+
return self._colorize(text, self.BOLD)
|
|
151
|
+
|
|
152
|
+
def dim(self, text: str) -> str:
|
|
153
|
+
"""Dim text (less prominent)."""
|
|
154
|
+
return self._colorize(text, self.DIM)
|
|
155
|
+
|
|
156
|
+
# Combined styles
|
|
157
|
+
def success(self, text: str) -> str:
|
|
158
|
+
"""Success message (bold green)."""
|
|
159
|
+
if not self.enabled:
|
|
160
|
+
return text
|
|
161
|
+
return f"{self.BOLD}{self.GREEN}{text}{self.RESET}"
|
|
162
|
+
|
|
163
|
+
def error(self, text: str) -> str:
|
|
164
|
+
"""Error message (bold red)."""
|
|
165
|
+
if not self.enabled:
|
|
166
|
+
return text
|
|
167
|
+
return f"{self.BOLD}{self.RED}{text}{self.RESET}"
|
|
168
|
+
|
|
169
|
+
def warning(self, text: str) -> str:
|
|
170
|
+
"""Warning message (yellow)."""
|
|
171
|
+
return self.yellow(text)
|
|
172
|
+
|
|
173
|
+
def info(self, text: str) -> str:
|
|
174
|
+
"""Info message (cyan)."""
|
|
175
|
+
return self.cyan(text)
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
# Global instance for convenience (thread-safe singleton)
|
|
179
|
+
_colors = None
|
|
180
|
+
_colors_lock = threading.Lock()
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def get_colors(no_color: bool = False) -> Colors:
|
|
184
|
+
"""Get a Colors instance, optionally disabling colors.
|
|
185
|
+
|
|
186
|
+
Thread-safe singleton pattern: the global instance is created once
|
|
187
|
+
and reused across all threads.
|
|
188
|
+
|
|
189
|
+
Args:
|
|
190
|
+
no_color: If True, return a new disabled Colors instance
|
|
191
|
+
(not cached, allows per-call override).
|
|
192
|
+
|
|
193
|
+
Returns:
|
|
194
|
+
Colors instance configured appropriately.
|
|
195
|
+
"""
|
|
196
|
+
global _colors
|
|
197
|
+
|
|
198
|
+
# For no_color=True, always return a fresh disabled instance
|
|
199
|
+
# This allows callers to override colors on a per-call basis
|
|
200
|
+
if no_color:
|
|
201
|
+
return Colors(enabled=False)
|
|
202
|
+
|
|
203
|
+
# Double-checked locking pattern for thread-safe lazy initialization
|
|
204
|
+
if _colors is None:
|
|
205
|
+
with _colors_lock:
|
|
206
|
+
# Check again inside the lock (another thread may have initialized)
|
|
207
|
+
if _colors is None:
|
|
208
|
+
_colors = Colors()
|
|
209
|
+
return _colors
|
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Shell completion scripts generator for Code Navigator.
|
|
3
|
+
|
|
4
|
+
Generates bash and zsh completion scripts that provide autocompletion
|
|
5
|
+
for codegraph-nav commands and symbol names from the code map.
|
|
6
|
+
|
|
7
|
+
Example:
|
|
8
|
+
# Generate bash completion
|
|
9
|
+
$ codegraph-nav completion bash > ~/.bash_completion.d/codegraph-nav
|
|
10
|
+
|
|
11
|
+
# Generate zsh completion
|
|
12
|
+
$ codegraph-nav completion zsh > ~/.zfunc/_codegraph_nav
|
|
13
|
+
|
|
14
|
+
# Source directly (bash)
|
|
15
|
+
$ eval "$(codegraph-nav completion bash)"
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
__version__ = "0.1.0"
|
|
22
|
+
|
|
23
|
+
BASH_COMPLETION_TEMPLATE = """# Bash completion for codegraph-nav
|
|
24
|
+
# Generated by codegraph-nav
|
|
25
|
+
|
|
26
|
+
_codegraph_completions() {
|
|
27
|
+
local cur prev words cword
|
|
28
|
+
_init_completion || return
|
|
29
|
+
|
|
30
|
+
local commands="map search read stats completion watch export"
|
|
31
|
+
local map_opts="-o --output -i --ignore --incremental --git-only --use-gitignore --compact --no-color -h --help"
|
|
32
|
+
local search_opts="-m --map -t --type -f --file --files --structure --deps --stats --check-stale --warn-stale --since-commit -l --limit --no-fuzzy --compact -o --output --no-color -h --help"
|
|
33
|
+
local read_opts="-c --context --symbol -r --root --compact -o --output --no-color -h --help"
|
|
34
|
+
local export_opts="-m --map -f --format -o --output --no-color -h --help"
|
|
35
|
+
local watch_opts="-o --output -i --ignore --git-only --use-gitignore --compact --no-color --debounce -h --help"
|
|
36
|
+
local completion_opts="bash zsh"
|
|
37
|
+
local types="function class method interface struct trait enum type"
|
|
38
|
+
|
|
39
|
+
case "${cword}" in
|
|
40
|
+
1)
|
|
41
|
+
COMPREPLY=($(compgen -W "${commands}" -- "${cur}"))
|
|
42
|
+
return
|
|
43
|
+
;;
|
|
44
|
+
esac
|
|
45
|
+
|
|
46
|
+
case "${words[1]}" in
|
|
47
|
+
map)
|
|
48
|
+
if [[ "${cur}" == -* ]]; then
|
|
49
|
+
COMPREPLY=($(compgen -W "${map_opts}" -- "${cur}"))
|
|
50
|
+
else
|
|
51
|
+
_filedir -d
|
|
52
|
+
fi
|
|
53
|
+
;;
|
|
54
|
+
search)
|
|
55
|
+
case "${prev}" in
|
|
56
|
+
-t|--type)
|
|
57
|
+
COMPREPLY=($(compgen -W "${types}" -- "${cur}"))
|
|
58
|
+
;;
|
|
59
|
+
-m|--map)
|
|
60
|
+
_filedir json
|
|
61
|
+
;;
|
|
62
|
+
-o|--output)
|
|
63
|
+
COMPREPLY=($(compgen -W "json table" -- "${cur}"))
|
|
64
|
+
;;
|
|
65
|
+
*)
|
|
66
|
+
if [[ "${cur}" == -* ]]; then
|
|
67
|
+
COMPREPLY=($(compgen -W "${search_opts}" -- "${cur}"))
|
|
68
|
+
else
|
|
69
|
+
# Try to complete symbol names from codegraph-nav
|
|
70
|
+
_codegraph_complete_symbols
|
|
71
|
+
fi
|
|
72
|
+
;;
|
|
73
|
+
esac
|
|
74
|
+
;;
|
|
75
|
+
read)
|
|
76
|
+
if [[ "${cur}" == -* ]]; then
|
|
77
|
+
COMPREPLY=($(compgen -W "${read_opts}" -- "${cur}"))
|
|
78
|
+
else
|
|
79
|
+
_filedir
|
|
80
|
+
fi
|
|
81
|
+
;;
|
|
82
|
+
stats)
|
|
83
|
+
if [[ "${cur}" == -* ]]; then
|
|
84
|
+
COMPREPLY=($(compgen -W "-m --map --compact -o --output --no-color -h --help" -- "${cur}"))
|
|
85
|
+
fi
|
|
86
|
+
;;
|
|
87
|
+
completion)
|
|
88
|
+
COMPREPLY=($(compgen -W "${completion_opts}" -- "${cur}"))
|
|
89
|
+
;;
|
|
90
|
+
watch)
|
|
91
|
+
if [[ "${cur}" == -* ]]; then
|
|
92
|
+
COMPREPLY=($(compgen -W "${watch_opts}" -- "${cur}"))
|
|
93
|
+
else
|
|
94
|
+
_filedir -d
|
|
95
|
+
fi
|
|
96
|
+
;;
|
|
97
|
+
export)
|
|
98
|
+
case "${prev}" in
|
|
99
|
+
-f|--format)
|
|
100
|
+
COMPREPLY=($(compgen -W "markdown html graphviz" -- "${cur}"))
|
|
101
|
+
;;
|
|
102
|
+
-m|--map)
|
|
103
|
+
_filedir json
|
|
104
|
+
;;
|
|
105
|
+
-o|--output)
|
|
106
|
+
_filedir
|
|
107
|
+
;;
|
|
108
|
+
*)
|
|
109
|
+
if [[ "${cur}" == -* ]]; then
|
|
110
|
+
COMPREPLY=($(compgen -W "${export_opts}" -- "${cur}"))
|
|
111
|
+
fi
|
|
112
|
+
;;
|
|
113
|
+
esac
|
|
114
|
+
;;
|
|
115
|
+
esac
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
_codegraph_complete_symbols() {
|
|
119
|
+
# Try to read symbols from .codegraph.json in current directory
|
|
120
|
+
local mapfile=".codegraph.json"
|
|
121
|
+
if [[ -f "${mapfile}" ]]; then
|
|
122
|
+
local symbols=$(python3 -c "
|
|
123
|
+
import json
|
|
124
|
+
try:
|
|
125
|
+
with open('${mapfile}') as f:
|
|
126
|
+
data = json.load(f)
|
|
127
|
+
symbols = set()
|
|
128
|
+
for file_info in data.get('files', {}).values():
|
|
129
|
+
for sym in file_info.get('symbols', []):
|
|
130
|
+
symbols.add(sym['name'])
|
|
131
|
+
print(' '.join(sorted(symbols)[:50]))
|
|
132
|
+
except (OSError, json.JSONDecodeError, KeyError, TypeError):
|
|
133
|
+
pass
|
|
134
|
+
" 2>/dev/null)
|
|
135
|
+
COMPREPLY=($(compgen -W "${symbols}" -- "${cur}"))
|
|
136
|
+
fi
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
complete -F _codegraph_completions codegraph-nav
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
ZSH_COMPLETION_TEMPLATE = """#compdef codegraph-nav
|
|
143
|
+
# Zsh completion for codegraph-nav
|
|
144
|
+
# Generated by codegraph-nav
|
|
145
|
+
|
|
146
|
+
_codegraph_nav() {
|
|
147
|
+
local -a commands
|
|
148
|
+
commands=(
|
|
149
|
+
'map:Generate a code map of a codebase'
|
|
150
|
+
'search:Search for symbols in the code map'
|
|
151
|
+
'read:Read specific lines from files'
|
|
152
|
+
'stats:Show codebase statistics'
|
|
153
|
+
'completion:Generate shell completion script'
|
|
154
|
+
'watch:Watch for changes and auto-update map'
|
|
155
|
+
'export:Export code map to different formats'
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
local -a types
|
|
159
|
+
types=(function class method interface struct trait enum type)
|
|
160
|
+
|
|
161
|
+
local -a formats
|
|
162
|
+
formats=(markdown html graphviz)
|
|
163
|
+
|
|
164
|
+
_arguments -C \\
|
|
165
|
+
'1:command:->command' \\
|
|
166
|
+
'*::arg:->args'
|
|
167
|
+
|
|
168
|
+
case "$state" in
|
|
169
|
+
command)
|
|
170
|
+
_describe -t commands 'codegraph-nav command' commands
|
|
171
|
+
;;
|
|
172
|
+
args)
|
|
173
|
+
case "$words[1]" in
|
|
174
|
+
map)
|
|
175
|
+
_arguments \\
|
|
176
|
+
'1:path:_files -/' \\
|
|
177
|
+
'-o[Output file path]:file:_files' \\
|
|
178
|
+
'--output[Output file path]:file:_files' \\
|
|
179
|
+
'*-i[Patterns to ignore]:pattern:' \\
|
|
180
|
+
'*--ignore[Patterns to ignore]:pattern:' \\
|
|
181
|
+
'--incremental[Only update changed files]' \\
|
|
182
|
+
'--git-only[Only scan git-tracked files]' \\
|
|
183
|
+
'--use-gitignore[Use .gitignore patterns]' \\
|
|
184
|
+
'--compact[Output compact JSON]' \\
|
|
185
|
+
'--no-color[Disable colored output]' \\
|
|
186
|
+
'(-h --help)'{-h,--help}'[Show help]'
|
|
187
|
+
;;
|
|
188
|
+
search)
|
|
189
|
+
_arguments \\
|
|
190
|
+
'1:query:_codegraph_symbols' \\
|
|
191
|
+
'-m[Path to code map]:file:_files -g "*.json"' \\
|
|
192
|
+
'--map[Path to code map]:file:_files -g "*.json"' \\
|
|
193
|
+
'-t[Filter by symbol type]:type:(${types})' \\
|
|
194
|
+
'--type[Filter by symbol type]:type:(${types})' \\
|
|
195
|
+
'-f[Filter by file pattern]:pattern:' \\
|
|
196
|
+
'--file[Filter by file pattern]:pattern:' \\
|
|
197
|
+
'--files[Search for files instead of symbols]' \\
|
|
198
|
+
'--structure[Show structure of a file]:file:_files' \\
|
|
199
|
+
'--deps[Show dependencies of a symbol]:symbol:_codegraph_symbols' \\
|
|
200
|
+
'--stats[Show codebase statistics]' \\
|
|
201
|
+
'--check-stale[Check if files have changed]' \\
|
|
202
|
+
'--warn-stale[Warn if files are stale]' \\
|
|
203
|
+
'--since-commit[Show changes since commit]:commit:' \\
|
|
204
|
+
'-l[Maximum results]:number:' \\
|
|
205
|
+
'--limit[Maximum results]:number:' \\
|
|
206
|
+
'--no-fuzzy[Disable fuzzy matching]' \\
|
|
207
|
+
'--compact[Output compact JSON]' \\
|
|
208
|
+
'-o[Output format]:format:(json table)' \\
|
|
209
|
+
'--output[Output format]:format:(json table)' \\
|
|
210
|
+
'--no-color[Disable colored output]' \\
|
|
211
|
+
'(-h --help)'{-h,--help}'[Show help]'
|
|
212
|
+
;;
|
|
213
|
+
read)
|
|
214
|
+
_arguments \\
|
|
215
|
+
'1:file:_files' \\
|
|
216
|
+
'2:lines:' \\
|
|
217
|
+
'-c[Context lines]:number:' \\
|
|
218
|
+
'--context[Context lines]:number:' \\
|
|
219
|
+
'--symbol[Read entire symbol]' \\
|
|
220
|
+
'-r[Root path]:path:_files -/' \\
|
|
221
|
+
'--root[Root path]:path:_files -/' \\
|
|
222
|
+
'--compact[Output compact JSON]' \\
|
|
223
|
+
'-o[Output format]:format:(json code)' \\
|
|
224
|
+
'--output[Output format]:format:(json code)' \\
|
|
225
|
+
'--no-color[Disable colored output]' \\
|
|
226
|
+
'(-h --help)'{-h,--help}'[Show help]'
|
|
227
|
+
;;
|
|
228
|
+
stats)
|
|
229
|
+
_arguments \\
|
|
230
|
+
'-m[Path to code map]:file:_files -g "*.json"' \\
|
|
231
|
+
'--map[Path to code map]:file:_files -g "*.json"' \\
|
|
232
|
+
'--compact[Output compact JSON]' \\
|
|
233
|
+
'-o[Output format]:format:(json table)' \\
|
|
234
|
+
'--output[Output format]:format:(json table)' \\
|
|
235
|
+
'--no-color[Disable colored output]' \\
|
|
236
|
+
'(-h --help)'{-h,--help}'[Show help]'
|
|
237
|
+
;;
|
|
238
|
+
completion)
|
|
239
|
+
_arguments '1:shell:(bash zsh)'
|
|
240
|
+
;;
|
|
241
|
+
watch)
|
|
242
|
+
_arguments \\
|
|
243
|
+
'1:path:_files -/' \\
|
|
244
|
+
'-o[Output file path]:file:_files' \\
|
|
245
|
+
'--output[Output file path]:file:_files' \\
|
|
246
|
+
'*-i[Patterns to ignore]:pattern:' \\
|
|
247
|
+
'*--ignore[Patterns to ignore]:pattern:' \\
|
|
248
|
+
'--git-only[Only scan git-tracked files]' \\
|
|
249
|
+
'--use-gitignore[Use .gitignore patterns]' \\
|
|
250
|
+
'--compact[Output compact JSON]' \\
|
|
251
|
+
'--no-color[Disable colored output]' \\
|
|
252
|
+
'--debounce[Debounce time in seconds]:seconds:' \\
|
|
253
|
+
'(-h --help)'{-h,--help}'[Show help]'
|
|
254
|
+
;;
|
|
255
|
+
export)
|
|
256
|
+
_arguments \\
|
|
257
|
+
'-m[Path to code map]:file:_files -g "*.json"' \\
|
|
258
|
+
'--map[Path to code map]:file:_files -g "*.json"' \\
|
|
259
|
+
'-f[Export format]:format:(${formats})' \\
|
|
260
|
+
'--format[Export format]:format:(${formats})' \\
|
|
261
|
+
'-o[Output file]:file:_files' \\
|
|
262
|
+
'--output[Output file]:file:_files' \\
|
|
263
|
+
'--no-color[Disable colored output]' \\
|
|
264
|
+
'(-h --help)'{-h,--help}'[Show help]'
|
|
265
|
+
;;
|
|
266
|
+
esac
|
|
267
|
+
;;
|
|
268
|
+
esac
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
_codegraph_symbols() {
|
|
272
|
+
local mapfile=".codegraph.json"
|
|
273
|
+
if [[ -f "$mapfile" ]]; then
|
|
274
|
+
local -a symbols
|
|
275
|
+
symbols=(${(f)"$(python3 -c "
|
|
276
|
+
import json
|
|
277
|
+
try:
|
|
278
|
+
with open('$mapfile') as f:
|
|
279
|
+
data = json.load(f)
|
|
280
|
+
symbols = set()
|
|
281
|
+
for file_info in data.get('files', {}).values():
|
|
282
|
+
for sym in file_info.get('symbols', []):
|
|
283
|
+
symbols.add(sym['name'])
|
|
284
|
+
print('\\n'.join(sorted(symbols)[:100]))
|
|
285
|
+
except (OSError, json.JSONDecodeError, KeyError, TypeError):
|
|
286
|
+
pass
|
|
287
|
+
" 2>/dev/null)"})
|
|
288
|
+
_describe -t symbols 'symbol' symbols
|
|
289
|
+
fi
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
_codegraph_nav "$@"
|
|
293
|
+
"""
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def generate_bash_completion() -> str:
|
|
297
|
+
"""Generate bash completion script.
|
|
298
|
+
|
|
299
|
+
Returns:
|
|
300
|
+
Bash completion script as a string.
|
|
301
|
+
"""
|
|
302
|
+
return BASH_COMPLETION_TEMPLATE
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
def generate_zsh_completion() -> str:
|
|
306
|
+
"""Generate zsh completion script.
|
|
307
|
+
|
|
308
|
+
Returns:
|
|
309
|
+
Zsh completion script as a string.
|
|
310
|
+
"""
|
|
311
|
+
return ZSH_COMPLETION_TEMPLATE
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def get_symbols_from_map(map_path: str, limit: int = 100) -> list[str]:
|
|
315
|
+
"""Extract symbol names from a code map for completion.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
map_path: Path to the .codegraph.json file.
|
|
319
|
+
limit: Maximum number of symbols to return.
|
|
320
|
+
|
|
321
|
+
Returns:
|
|
322
|
+
List of symbol names.
|
|
323
|
+
"""
|
|
324
|
+
try:
|
|
325
|
+
with open(map_path, encoding="utf-8") as f:
|
|
326
|
+
data = json.load(f)
|
|
327
|
+
|
|
328
|
+
symbols = set()
|
|
329
|
+
for file_info in data.get("files", {}).values():
|
|
330
|
+
for sym in file_info.get("symbols", []):
|
|
331
|
+
symbols.add(sym["name"])
|
|
332
|
+
if len(symbols) >= limit:
|
|
333
|
+
break
|
|
334
|
+
if len(symbols) >= limit:
|
|
335
|
+
break
|
|
336
|
+
|
|
337
|
+
return sorted(symbols)[:limit]
|
|
338
|
+
except Exception:
|
|
339
|
+
return []
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def run_completion(shell: str) -> None:
|
|
343
|
+
"""Generate and print completion script for the specified shell.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
shell: Shell type ('bash' or 'zsh').
|
|
347
|
+
"""
|
|
348
|
+
if shell == "bash":
|
|
349
|
+
print(generate_bash_completion())
|
|
350
|
+
elif shell == "zsh":
|
|
351
|
+
print(generate_zsh_completion())
|
|
352
|
+
else:
|
|
353
|
+
print(f"Unknown shell: {shell}. Supported: bash, zsh", file=sys.stderr)
|
|
354
|
+
sys.exit(1)
|