jarvis-ai-assistant 0.7.0__py3-none-any.whl → 0.7.6__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.
Files changed (159) hide show
  1. jarvis/__init__.py +1 -1
  2. jarvis/jarvis_agent/__init__.py +243 -139
  3. jarvis/jarvis_agent/agent_manager.py +5 -10
  4. jarvis/jarvis_agent/builtin_input_handler.py +2 -6
  5. jarvis/jarvis_agent/config_editor.py +2 -7
  6. jarvis/jarvis_agent/event_bus.py +82 -12
  7. jarvis/jarvis_agent/file_context_handler.py +265 -15
  8. jarvis/jarvis_agent/file_methodology_manager.py +3 -4
  9. jarvis/jarvis_agent/jarvis.py +113 -98
  10. jarvis/jarvis_agent/language_extractors/__init__.py +57 -0
  11. jarvis/jarvis_agent/language_extractors/c_extractor.py +21 -0
  12. jarvis/jarvis_agent/language_extractors/cpp_extractor.py +21 -0
  13. jarvis/jarvis_agent/language_extractors/go_extractor.py +21 -0
  14. jarvis/jarvis_agent/language_extractors/java_extractor.py +84 -0
  15. jarvis/jarvis_agent/language_extractors/javascript_extractor.py +79 -0
  16. jarvis/jarvis_agent/language_extractors/python_extractor.py +21 -0
  17. jarvis/jarvis_agent/language_extractors/rust_extractor.py +21 -0
  18. jarvis/jarvis_agent/language_extractors/typescript_extractor.py +84 -0
  19. jarvis/jarvis_agent/language_support_info.py +486 -0
  20. jarvis/jarvis_agent/main.py +6 -12
  21. jarvis/jarvis_agent/memory_manager.py +7 -16
  22. jarvis/jarvis_agent/methodology_share_manager.py +10 -16
  23. jarvis/jarvis_agent/prompt_manager.py +1 -1
  24. jarvis/jarvis_agent/prompts.py +193 -171
  25. jarvis/jarvis_agent/protocols.py +8 -12
  26. jarvis/jarvis_agent/run_loop.py +77 -14
  27. jarvis/jarvis_agent/session_manager.py +2 -3
  28. jarvis/jarvis_agent/share_manager.py +12 -21
  29. jarvis/jarvis_agent/shell_input_handler.py +1 -2
  30. jarvis/jarvis_agent/task_analyzer.py +26 -4
  31. jarvis/jarvis_agent/task_manager.py +11 -27
  32. jarvis/jarvis_agent/tool_executor.py +2 -3
  33. jarvis/jarvis_agent/tool_share_manager.py +12 -24
  34. jarvis/jarvis_agent/web_server.py +55 -20
  35. jarvis/jarvis_c2rust/__init__.py +5 -5
  36. jarvis/jarvis_c2rust/cli.py +461 -499
  37. jarvis/jarvis_c2rust/collector.py +45 -53
  38. jarvis/jarvis_c2rust/constants.py +26 -0
  39. jarvis/jarvis_c2rust/library_replacer.py +264 -132
  40. jarvis/jarvis_c2rust/llm_module_agent.py +162 -190
  41. jarvis/jarvis_c2rust/loaders.py +207 -0
  42. jarvis/jarvis_c2rust/models.py +28 -0
  43. jarvis/jarvis_c2rust/optimizer.py +1592 -395
  44. jarvis/jarvis_c2rust/transpiler.py +1722 -1064
  45. jarvis/jarvis_c2rust/utils.py +385 -0
  46. jarvis/jarvis_code_agent/build_validation_config.py +2 -3
  47. jarvis/jarvis_code_agent/code_agent.py +394 -320
  48. jarvis/jarvis_code_agent/code_analyzer/__init__.py +3 -0
  49. jarvis/jarvis_code_agent/code_analyzer/build_validator/base.py +4 -0
  50. jarvis/jarvis_code_agent/code_analyzer/build_validator/cmake.py +17 -2
  51. jarvis/jarvis_code_agent/code_analyzer/build_validator/fallback.py +3 -0
  52. jarvis/jarvis_code_agent/code_analyzer/build_validator/go.py +36 -4
  53. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_gradle.py +9 -0
  54. jarvis/jarvis_code_agent/code_analyzer/build_validator/java_maven.py +9 -0
  55. jarvis/jarvis_code_agent/code_analyzer/build_validator/makefile.py +12 -1
  56. jarvis/jarvis_code_agent/code_analyzer/build_validator/nodejs.py +22 -5
  57. jarvis/jarvis_code_agent/code_analyzer/build_validator/python.py +57 -32
  58. jarvis/jarvis_code_agent/code_analyzer/build_validator/rust.py +62 -6
  59. jarvis/jarvis_code_agent/code_analyzer/build_validator/validator.py +8 -9
  60. jarvis/jarvis_code_agent/code_analyzer/context_manager.py +290 -5
  61. jarvis/jarvis_code_agent/code_analyzer/language_support.py +21 -0
  62. jarvis/jarvis_code_agent/code_analyzer/languages/__init__.py +21 -3
  63. jarvis/jarvis_code_agent/code_analyzer/languages/c_cpp_language.py +72 -4
  64. jarvis/jarvis_code_agent/code_analyzer/languages/go_language.py +35 -3
  65. jarvis/jarvis_code_agent/code_analyzer/languages/java_language.py +212 -0
  66. jarvis/jarvis_code_agent/code_analyzer/languages/javascript_language.py +254 -0
  67. jarvis/jarvis_code_agent/code_analyzer/languages/python_language.py +52 -2
  68. jarvis/jarvis_code_agent/code_analyzer/languages/rust_language.py +73 -1
  69. jarvis/jarvis_code_agent/code_analyzer/languages/typescript_language.py +280 -0
  70. jarvis/jarvis_code_agent/code_analyzer/llm_context_recommender.py +306 -152
  71. jarvis/jarvis_code_agent/code_analyzer/structured_code.py +556 -0
  72. jarvis/jarvis_code_agent/code_analyzer/symbol_extractor.py +193 -18
  73. jarvis/jarvis_code_agent/code_analyzer/tree_sitter_extractor.py +18 -8
  74. jarvis/jarvis_code_agent/lint.py +258 -27
  75. jarvis/jarvis_code_agent/utils.py +0 -1
  76. jarvis/jarvis_code_analysis/code_review.py +19 -24
  77. jarvis/jarvis_data/config_schema.json +53 -26
  78. jarvis/jarvis_git_squash/main.py +4 -5
  79. jarvis/jarvis_git_utils/git_commiter.py +44 -49
  80. jarvis/jarvis_mcp/sse_mcp_client.py +20 -27
  81. jarvis/jarvis_mcp/stdio_mcp_client.py +11 -12
  82. jarvis/jarvis_mcp/streamable_mcp_client.py +15 -14
  83. jarvis/jarvis_memory_organizer/memory_organizer.py +55 -74
  84. jarvis/jarvis_methodology/main.py +32 -48
  85. jarvis/jarvis_multi_agent/__init__.py +79 -61
  86. jarvis/jarvis_multi_agent/main.py +3 -7
  87. jarvis/jarvis_platform/base.py +469 -199
  88. jarvis/jarvis_platform/human.py +7 -8
  89. jarvis/jarvis_platform/kimi.py +30 -36
  90. jarvis/jarvis_platform/openai.py +65 -27
  91. jarvis/jarvis_platform/registry.py +26 -10
  92. jarvis/jarvis_platform/tongyi.py +24 -25
  93. jarvis/jarvis_platform/yuanbao.py +31 -42
  94. jarvis/jarvis_platform_manager/main.py +66 -77
  95. jarvis/jarvis_platform_manager/service.py +8 -13
  96. jarvis/jarvis_rag/cli.py +49 -51
  97. jarvis/jarvis_rag/embedding_manager.py +13 -18
  98. jarvis/jarvis_rag/llm_interface.py +8 -9
  99. jarvis/jarvis_rag/query_rewriter.py +10 -21
  100. jarvis/jarvis_rag/rag_pipeline.py +24 -27
  101. jarvis/jarvis_rag/reranker.py +4 -5
  102. jarvis/jarvis_rag/retriever.py +28 -30
  103. jarvis/jarvis_sec/__init__.py +220 -3520
  104. jarvis/jarvis_sec/agents.py +143 -0
  105. jarvis/jarvis_sec/analysis.py +276 -0
  106. jarvis/jarvis_sec/cli.py +29 -6
  107. jarvis/jarvis_sec/clustering.py +1439 -0
  108. jarvis/jarvis_sec/file_manager.py +427 -0
  109. jarvis/jarvis_sec/parsers.py +73 -0
  110. jarvis/jarvis_sec/prompts.py +268 -0
  111. jarvis/jarvis_sec/report.py +83 -4
  112. jarvis/jarvis_sec/review.py +453 -0
  113. jarvis/jarvis_sec/utils.py +499 -0
  114. jarvis/jarvis_sec/verification.py +848 -0
  115. jarvis/jarvis_sec/workflow.py +7 -0
  116. jarvis/jarvis_smart_shell/main.py +38 -87
  117. jarvis/jarvis_stats/cli.py +1 -1
  118. jarvis/jarvis_stats/stats.py +7 -7
  119. jarvis/jarvis_stats/storage.py +15 -21
  120. jarvis/jarvis_tools/clear_memory.py +3 -20
  121. jarvis/jarvis_tools/cli/main.py +20 -23
  122. jarvis/jarvis_tools/edit_file.py +1066 -0
  123. jarvis/jarvis_tools/execute_script.py +42 -21
  124. jarvis/jarvis_tools/file_analyzer.py +6 -9
  125. jarvis/jarvis_tools/generate_new_tool.py +11 -20
  126. jarvis/jarvis_tools/lsp_client.py +1552 -0
  127. jarvis/jarvis_tools/methodology.py +2 -3
  128. jarvis/jarvis_tools/read_code.py +1525 -87
  129. jarvis/jarvis_tools/read_symbols.py +2 -3
  130. jarvis/jarvis_tools/read_webpage.py +7 -10
  131. jarvis/jarvis_tools/registry.py +370 -181
  132. jarvis/jarvis_tools/retrieve_memory.py +20 -19
  133. jarvis/jarvis_tools/rewrite_file.py +105 -0
  134. jarvis/jarvis_tools/save_memory.py +3 -15
  135. jarvis/jarvis_tools/search_web.py +3 -7
  136. jarvis/jarvis_tools/sub_agent.py +17 -6
  137. jarvis/jarvis_tools/sub_code_agent.py +14 -16
  138. jarvis/jarvis_tools/virtual_tty.py +54 -32
  139. jarvis/jarvis_utils/clipboard.py +7 -10
  140. jarvis/jarvis_utils/config.py +98 -63
  141. jarvis/jarvis_utils/embedding.py +5 -5
  142. jarvis/jarvis_utils/fzf.py +8 -8
  143. jarvis/jarvis_utils/git_utils.py +81 -67
  144. jarvis/jarvis_utils/input.py +24 -49
  145. jarvis/jarvis_utils/jsonnet_compat.py +465 -0
  146. jarvis/jarvis_utils/methodology.py +33 -35
  147. jarvis/jarvis_utils/utils.py +245 -202
  148. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/METADATA +205 -70
  149. jarvis_ai_assistant-0.7.6.dist-info/RECORD +218 -0
  150. jarvis/jarvis_agent/edit_file_handler.py +0 -584
  151. jarvis/jarvis_agent/rewrite_file_handler.py +0 -141
  152. jarvis/jarvis_agent/task_planner.py +0 -496
  153. jarvis/jarvis_platform/ai8.py +0 -332
  154. jarvis/jarvis_tools/ask_user.py +0 -54
  155. jarvis_ai_assistant-0.7.0.dist-info/RECORD +0 -192
  156. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/WHEEL +0 -0
  157. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/entry_points.txt +0 -0
  158. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/licenses/LICENSE +0 -0
  159. {jarvis_ai_assistant-0.7.0.dist-info → jarvis_ai_assistant-0.7.6.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  import os
2
2
  import re
3
3
  from dataclasses import dataclass, field
4
- from typing import List, Optional, Set
4
+ from typing import Any, List, Optional, Set
5
5
 
6
6
  from .dependency_analyzer import DependencyGraph
7
7
  from .file_ignore import filter_walk_dirs
@@ -36,7 +36,9 @@ class ContextManager:
36
36
 
37
37
  def __init__(self, project_root: str):
38
38
  self.project_root = project_root
39
- self.symbol_table = SymbolTable()
39
+ # Create cache directory path relative to project root
40
+ cache_dir = os.path.join(project_root, ".jarvis", "symbol_cache")
41
+ self.symbol_table = SymbolTable(cache_dir)
40
42
  self.dependency_graph = DependencyGraph()
41
43
  self._file_cache: dict[str, str] = {} # Cache file contents
42
44
 
@@ -94,6 +96,10 @@ class ContextManager:
94
96
  """
95
97
  references: List[Reference] = []
96
98
 
99
+ # Check if file is stale and update if needed
100
+ if file_path and self.symbol_table.is_file_stale(file_path):
101
+ self._refresh_file_symbols(file_path)
102
+
97
103
  # Find symbol definitions
98
104
  symbols = self.symbol_table.find_symbol(symbol_name, file_path)
99
105
  if not symbols:
@@ -114,6 +120,10 @@ class ContextManager:
114
120
 
115
121
  # Search for references in each file
116
122
  for file_path_to_search in search_files:
123
+ # Check if file is stale and update if needed
124
+ if self.symbol_table.is_file_stale(file_path_to_search):
125
+ self._refresh_file_symbols(file_path_to_search)
126
+
117
127
  content = self._get_file_content(file_path_to_search)
118
128
  if not content:
119
129
  continue
@@ -158,6 +168,10 @@ class ContextManager:
158
168
  Returns:
159
169
  Symbol object if found, None otherwise
160
170
  """
171
+ # Check if file is stale and update if needed
172
+ if file_path and self.symbol_table.is_file_stale(file_path):
173
+ self._refresh_file_symbols(file_path)
174
+
161
175
  symbols = self.symbol_table.find_symbol(symbol_name, file_path)
162
176
  if symbols:
163
177
  # Return the first definition (could be enhanced to find the most relevant one)
@@ -186,6 +200,13 @@ class ContextManager:
186
200
  symbols = extractor.extract_symbols(file_path, content)
187
201
  for symbol in symbols:
188
202
  self.symbol_table.add_symbol(symbol)
203
+
204
+ # Update file modification time after extracting symbols
205
+ if os.path.exists(file_path):
206
+ try:
207
+ self.symbol_table._file_mtimes[file_path] = os.path.getmtime(file_path)
208
+ except Exception:
209
+ pass
189
210
 
190
211
  # 5. Analyze dependencies
191
212
  analyzer = get_dependency_analyzer(language)
@@ -196,6 +217,26 @@ class ContextManager:
196
217
  dep_path = self._resolve_dependency_path(file_path, dep.from_module)
197
218
  if dep_path:
198
219
  self.dependency_graph.add_dependency(file_path, dep_path)
220
+
221
+ # 6. Save updated symbols to cache
222
+ self.symbol_table.save_cache()
223
+
224
+ def _refresh_file_symbols(self, file_path: str):
225
+ """Refresh symbols for a file that has been modified externally.
226
+
227
+ This method is called when a file is detected to be stale (modified
228
+ outside of Jarvis's control).
229
+ """
230
+ if not os.path.exists(file_path):
231
+ return
232
+
233
+ try:
234
+ with open(file_path, 'r', encoding='utf-8', errors='replace') as f:
235
+ content = f.read()
236
+ self.update_context_for_file(file_path, content)
237
+ except Exception:
238
+ # If we can't read the file, skip refresh
239
+ pass
199
240
 
200
241
  def _get_file_content(self, file_path: str) -> Optional[str]:
201
242
  """Get file content, using cache if available."""
@@ -215,6 +256,9 @@ class ContextManager:
215
256
 
216
257
  def _find_current_scope(self, file_path: str, line_num: int) -> Optional[Symbol]:
217
258
  """Find the function or class that contains the given line."""
259
+ # Check if file is stale and update if needed
260
+ if self.symbol_table.is_file_stale(file_path):
261
+ self._refresh_file_symbols(file_path)
218
262
  symbols = self.symbol_table.get_file_symbols(file_path)
219
263
 
220
264
  # Find the innermost scope containing the line
@@ -232,7 +276,17 @@ class ContextManager:
232
276
  return current_scope
233
277
 
234
278
  def _find_used_symbols(self, file_path: str, content: str, line_start: int, line_end: int) -> List[Symbol]:
235
- """Find symbols used in the specified line range."""
279
+ """Find symbols used in the specified line range.
280
+
281
+ 改进版本:
282
+ 1. 区分定义和调用:检查符号是否在当前行范围内定义
283
+ 2. 获取定义位置:优先使用 LSP,如果不支持则使用 tree-sitter
284
+ 3. 为每个使用的符号添加定义位置信息
285
+ """
286
+ # Check if file is stale and update if needed
287
+ if self.symbol_table.is_file_stale(file_path):
288
+ self._refresh_file_symbols(file_path)
289
+
236
290
  # Extract the code in the range
237
291
  lines = content.split('\n')
238
292
  region_content = '\n'.join(lines[line_start-1:line_end])
@@ -240,19 +294,250 @@ class ContextManager:
240
294
  used_symbols: List[Symbol] = []
241
295
  all_symbols = self.symbol_table.get_file_symbols(file_path)
242
296
 
297
+ # 尝试获取 LSP 客户端(优先使用)
298
+ lsp_client = None
299
+ try:
300
+ from jarvis.jarvis_tools.lsp_client import LSPClientTool
301
+ lsp_client = LSPClientTool.get_client_for_file(file_path, self.project_root)
302
+ except Exception:
303
+ pass
304
+
305
+ # 尝试获取 tree-sitter 提取器(作为后备)
306
+ treesitter_extractor = None
307
+ try:
308
+ from jarvis.jarvis_code_agent.code_analyzer.language_support import (
309
+ detect_language,
310
+ get_symbol_extractor,
311
+ )
312
+ language = detect_language(file_path)
313
+ if language:
314
+ treesitter_extractor = get_symbol_extractor(language)
315
+ except Exception:
316
+ pass
317
+
318
+ # 用于跟踪已处理的符号,避免重复
319
+ processed_symbols = {} # {symbol_name: (symbol, is_definition, definition_location)}
320
+
243
321
  # Simple pattern matching to find symbol usage
244
322
  for symbol in all_symbols:
245
323
  if symbol.kind == 'import':
246
324
  continue
247
325
 
248
326
  pattern = r'\b' + re.escape(symbol.name) + r'\b'
249
- if re.search(pattern, region_content):
250
- used_symbols.append(symbol)
327
+ matches = list(re.finditer(pattern, region_content))
328
+ if not matches:
329
+ continue
330
+
331
+ # 检查符号是否在当前行范围内定义
332
+ is_definition_in_range = (
333
+ symbol.file_path == file_path and
334
+ symbol.line_start >= line_start and
335
+ symbol.line_start <= line_end
336
+ )
337
+
338
+ # 检查是否有调用(不在定义行的使用)
339
+ has_calls = False
340
+ call_line = None
341
+ call_column = None
342
+ for match in matches:
343
+ match_start = match.start()
344
+ match_line_in_region = region_content[:match_start].count('\n') + 1
345
+ match_line = line_start + match_line_in_region - 1
346
+
347
+ # 如果使用位置不在定义行,则认为是调用
348
+ if not is_definition_in_range or match_line != symbol.line_start:
349
+ has_calls = True
350
+ call_line = match_line
351
+ # 计算列号
352
+ line_start_pos = region_content[:match_start].rfind('\n') + 1
353
+ call_column = match_start - line_start_pos
354
+ break
355
+
356
+ # 处理定义
357
+ if is_definition_in_range:
358
+ symbol.is_definition = True
359
+ if symbol.name not in processed_symbols:
360
+ processed_symbols[symbol.name] = (symbol, True, None)
361
+
362
+ # 处理调用
363
+ if has_calls or not is_definition_in_range:
364
+ # 创建或更新引用符号
365
+ if symbol.name in processed_symbols:
366
+ existing_symbol, existing_is_def, existing_def_loc = processed_symbols[symbol.name]
367
+ # 如果已有定义,跳过;否则更新定义位置
368
+ if not existing_is_def and not existing_def_loc:
369
+ # 尝试获取定义位置
370
+ definition_location = self._find_definition_location(
371
+ symbol.name,
372
+ file_path,
373
+ call_line or line_start,
374
+ call_column or 0,
375
+ lsp_client,
376
+ treesitter_extractor,
377
+ content,
378
+ )
379
+
380
+ if definition_location:
381
+ processed_symbols[symbol.name] = (existing_symbol, False, definition_location)
382
+ else:
383
+ # 从符号表中查找
384
+ definition_symbols = self.symbol_table.find_symbol(symbol.name)
385
+ if definition_symbols:
386
+ def_symbol = definition_symbols[0]
387
+ definition_location = Symbol(
388
+ name=def_symbol.name,
389
+ kind=def_symbol.kind,
390
+ file_path=def_symbol.file_path,
391
+ line_start=def_symbol.line_start,
392
+ line_end=def_symbol.line_end,
393
+ signature=def_symbol.signature,
394
+ )
395
+ processed_symbols[symbol.name] = (existing_symbol, False, definition_location)
396
+ else:
397
+ # 创建新的引用符号
398
+ reference_symbol = Symbol(
399
+ name=symbol.name,
400
+ kind=symbol.kind,
401
+ file_path=file_path,
402
+ line_start=call_line or line_start,
403
+ line_end=call_line or line_start,
404
+ signature=symbol.signature,
405
+ docstring=symbol.docstring,
406
+ parent=symbol.parent,
407
+ is_definition=False,
408
+ )
409
+
410
+ # 尝试获取定义位置
411
+ definition_location = self._find_definition_location(
412
+ symbol.name,
413
+ file_path,
414
+ call_line or line_start,
415
+ call_column or 0,
416
+ lsp_client,
417
+ treesitter_extractor,
418
+ content,
419
+ )
420
+
421
+ if definition_location:
422
+ reference_symbol.definition_location = definition_location
423
+ else:
424
+ # 从符号表中查找
425
+ definition_symbols = self.symbol_table.find_symbol(symbol.name)
426
+ if definition_symbols:
427
+ def_symbol = definition_symbols[0]
428
+ reference_symbol.definition_location = Symbol(
429
+ name=def_symbol.name,
430
+ kind=def_symbol.kind,
431
+ file_path=def_symbol.file_path,
432
+ line_start=def_symbol.line_start,
433
+ line_end=def_symbol.line_end,
434
+ signature=def_symbol.signature,
435
+ )
436
+
437
+ processed_symbols[symbol.name] = (reference_symbol, False, reference_symbol.definition_location)
438
+
439
+ # 将处理后的符号添加到结果列表
440
+ for symbol, is_def, def_loc in processed_symbols.values():
441
+ if is_def:
442
+ symbol.is_definition = True
443
+ if def_loc:
444
+ symbol.definition_location = def_loc
445
+ used_symbols.append(symbol)
251
446
 
252
447
  return used_symbols
448
+
449
+ def _find_definition_location(
450
+ self,
451
+ symbol_name: str,
452
+ file_path: str,
453
+ line: int,
454
+ column: int,
455
+ lsp_client: Optional[Any],
456
+ treesitter_extractor: Optional[Any],
457
+ content: str,
458
+ ) -> Optional[Symbol]:
459
+ """查找符号的定义位置。
460
+
461
+ 优先使用 LSP,如果不支持则使用 tree-sitter。
462
+
463
+ Args:
464
+ symbol_name: 符号名称
465
+ file_path: 文件路径
466
+ line: 行号(1-based)
467
+ column: 列号(0-based)
468
+ lsp_client: LSP 客户端(可选)
469
+ treesitter_extractor: tree-sitter 提取器(可选)
470
+ content: 文件内容
471
+
472
+ Returns:
473
+ 定义位置的 Symbol 对象,如果找不到则返回 None
474
+ """
475
+ # 优先使用 LSP
476
+ if lsp_client:
477
+ try:
478
+ # LSP 使用 0-based 行号
479
+ definition = lsp_client.get_definition(file_path, line - 1, column)
480
+ if definition:
481
+ # 处理 LSP 返回的定义(可能是单个对象或列表)
482
+ if isinstance(definition, list):
483
+ if definition:
484
+ definition = definition[0]
485
+ else:
486
+ return None
487
+
488
+ # 解析 LSP 返回的定义位置
489
+ uri = definition.get("uri", "")
490
+ if uri.startswith("file://"):
491
+ def_file_path = uri[7:] # 移除 "file://" 前缀
492
+ else:
493
+ def_file_path = uri
494
+
495
+ range_info = definition.get("range", {})
496
+ start = range_info.get("start", {})
497
+ end = range_info.get("end", {})
498
+
499
+ # LSP 使用 0-based 行号,转换为 1-based
500
+ def_line_start = start.get("line", 0) + 1
501
+ def_line_end = end.get("line", 0) + 1
502
+
503
+ return Symbol(
504
+ name=symbol_name,
505
+ kind="", # LSP 可能不提供类型信息
506
+ file_path=def_file_path,
507
+ line_start=def_line_start,
508
+ line_end=def_line_end,
509
+ )
510
+ except Exception:
511
+ # LSP 失败,继续尝试 tree-sitter
512
+ pass
513
+
514
+ # 后备:使用 tree-sitter
515
+ if treesitter_extractor:
516
+ try:
517
+ # 从符号表中查找定义(tree-sitter 已经提取了符号)
518
+ definition_symbols = self.symbol_table.find_symbol(symbol_name)
519
+ if definition_symbols:
520
+ # 选择第一个定义(可以改进为选择最相关的)
521
+ def_symbol = definition_symbols[0]
522
+ return Symbol(
523
+ name=def_symbol.name,
524
+ kind=def_symbol.kind,
525
+ file_path=def_symbol.file_path,
526
+ line_start=def_symbol.line_start,
527
+ line_end=def_symbol.line_end,
528
+ signature=def_symbol.signature,
529
+ )
530
+ except Exception:
531
+ pass
532
+
533
+ return None
253
534
 
254
535
  def _find_imported_symbols(self, file_path: str) -> List[Symbol]:
255
536
  """Find all imported symbols in a file."""
537
+ # Check if file is stale and update if needed
538
+ if self.symbol_table.is_file_stale(file_path):
539
+ self._refresh_file_symbols(file_path)
540
+
256
541
  symbols = self.symbol_table.get_file_symbols(file_path)
257
542
  return [s for s in symbols if s.kind == 'import']
258
543
 
@@ -52,6 +52,27 @@ try:
52
52
  except (ImportError, RuntimeError):
53
53
  pass # 静默失败,tree-sitter可能不可用
54
54
 
55
+ # JavaScript语言支持(可选,需要tree-sitter)
56
+ try:
57
+ from .languages import JavaScriptLanguageSupport
58
+ register_language(JavaScriptLanguageSupport())
59
+ except (ImportError, RuntimeError):
60
+ pass # 静默失败,tree-sitter可能不可用
61
+
62
+ # TypeScript语言支持(可选,需要tree-sitter)
63
+ try:
64
+ from .languages import TypeScriptLanguageSupport
65
+ register_language(TypeScriptLanguageSupport())
66
+ except (ImportError, RuntimeError):
67
+ pass # 静默失败,tree-sitter可能不可用
68
+
69
+ # Java语言支持(可选,需要tree-sitter)
70
+ try:
71
+ from .languages import JavaLanguageSupport
72
+ register_language(JavaLanguageSupport())
73
+ except (ImportError, RuntimeError):
74
+ pass # 静默失败,tree-sitter可能不可用
75
+
55
76
 
56
77
  def detect_language(file_path: str) -> Optional[str]:
57
78
  """检测文件的编程语言。
@@ -12,20 +12,38 @@ __all__ = ['PythonLanguageSupport']
12
12
 
13
13
  # 尝试导入tree-sitter相关的语言支持
14
14
  try:
15
- from .rust_language import RustLanguageSupport
15
+ from .rust_language import RustLanguageSupport # noqa: F401
16
16
  __all__.append('RustLanguageSupport')
17
17
  except (ImportError, RuntimeError):
18
18
  pass
19
19
 
20
20
  try:
21
- from .go_language import GoLanguageSupport
21
+ from .go_language import GoLanguageSupport # noqa: F401
22
22
  __all__.append('GoLanguageSupport')
23
23
  except (ImportError, RuntimeError):
24
24
  pass
25
25
 
26
26
  try:
27
- from .c_cpp_language import CLanguageSupport, CppLanguageSupport
27
+ from .c_cpp_language import CLanguageSupport, CppLanguageSupport # noqa: F401
28
28
  __all__.extend(['CLanguageSupport', 'CppLanguageSupport'])
29
29
  except (ImportError, RuntimeError):
30
30
  pass
31
31
 
32
+ try:
33
+ from .javascript_language import JavaScriptLanguageSupport # noqa: F401
34
+ __all__.append('JavaScriptLanguageSupport')
35
+ except (ImportError, RuntimeError):
36
+ pass
37
+
38
+ try:
39
+ from .typescript_language import TypeScriptLanguageSupport # noqa: F401
40
+ __all__.append('TypeScriptLanguageSupport')
41
+ except (ImportError, RuntimeError):
42
+ pass
43
+
44
+ try:
45
+ from .java_language import JavaLanguageSupport # noqa: F401
46
+ __all__.append('JavaLanguageSupport')
47
+ except (ImportError, RuntimeError):
48
+ pass
49
+
@@ -15,7 +15,29 @@ from ..tree_sitter_extractor import TreeSitterExtractor
15
15
 
16
16
  # --- C/C++ Symbol Query ---
17
17
 
18
- C_CPP_SYMBOL_QUERY = """
18
+ # C语言查询(不包含class_specifier,因为C不支持class)
19
+ C_SYMBOL_QUERY = """
20
+ (function_declarator
21
+ declarator: (identifier) @function.name)
22
+
23
+ (struct_specifier
24
+ name: (type_identifier) @struct.name)
25
+
26
+ (union_specifier
27
+ name: (type_identifier) @union.name)
28
+
29
+ (enum_specifier
30
+ name: (type_identifier) @enum.name)
31
+
32
+ (preproc_def
33
+ name: (identifier) @macro.name)
34
+
35
+ (type_definition
36
+ declarator: (type_identifier) @typedef.name)
37
+ """
38
+
39
+ # C++语言查询(包含class_specifier)
40
+ CPP_SYMBOL_QUERY = """
19
41
  (function_declarator
20
42
  declarator: (identifier) @function.name)
21
43
 
@@ -30,6 +52,17 @@ C_CPP_SYMBOL_QUERY = """
30
52
 
31
53
  (enum_specifier
32
54
  name: (type_identifier) @enum.name)
55
+
56
+ (namespace_definition
57
+ name: (identifier)? @namespace.name)
58
+
59
+ (preproc_def
60
+ name: (identifier) @macro.name)
61
+
62
+ (type_definition
63
+ declarator: (type_identifier) @typedef.name)
64
+
65
+ (template_declaration) @template
33
66
  """
34
67
 
35
68
  # --- C/C++ Language Setup ---
@@ -55,7 +88,7 @@ class CSymbolExtractor(TreeSitterExtractor):
55
88
  def __init__(self):
56
89
  if not C_LANGUAGE:
57
90
  raise RuntimeError("C tree-sitter grammar not available.")
58
- super().__init__(C_LANGUAGE, C_CPP_SYMBOL_QUERY)
91
+ super().__init__(C_LANGUAGE, C_SYMBOL_QUERY)
59
92
 
60
93
  def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
61
94
  kind_map = {
@@ -63,6 +96,8 @@ class CSymbolExtractor(TreeSitterExtractor):
63
96
  "struct.name": "struct",
64
97
  "union.name": "union",
65
98
  "enum.name": "enum",
99
+ "macro.name": "macro",
100
+ "typedef.name": "typedef",
66
101
  }
67
102
  symbol_kind = kind_map.get(name)
68
103
  if not symbol_kind:
@@ -83,7 +118,7 @@ class CppSymbolExtractor(TreeSitterExtractor):
83
118
  def __init__(self):
84
119
  if not CPP_LANGUAGE:
85
120
  raise RuntimeError("C++ tree-sitter grammar not available.")
86
- super().__init__(CPP_LANGUAGE, C_CPP_SYMBOL_QUERY)
121
+ super().__init__(CPP_LANGUAGE, CPP_SYMBOL_QUERY)
87
122
 
88
123
  def _create_symbol_from_capture(self, node: Node, name: str, file_path: str) -> Optional[Symbol]:
89
124
  kind_map = {
@@ -92,13 +127,46 @@ class CppSymbolExtractor(TreeSitterExtractor):
92
127
  "class.name": "class",
93
128
  "union.name": "union",
94
129
  "enum.name": "enum",
130
+ "namespace.name": "namespace",
131
+ "macro.name": "macro",
132
+ "typedef.name": "typedef",
133
+ "template": "template",
95
134
  }
96
135
  symbol_kind = kind_map.get(name)
97
136
  if not symbol_kind:
98
137
  return None
99
138
 
139
+ # For anonymous namespaces, use a generated name
140
+ if name == "namespace.name":
141
+ symbol_name = node.text.decode('utf8') if node.text else "<anonymous_namespace>"
142
+ elif name == "template":
143
+ # For template declarations, extract the template name or use a generic name
144
+ # Try to find the function/class name after template
145
+ template_text = node.text.decode('utf8').strip()
146
+ # Extract template parameters and the following declaration
147
+ # This is a simplified extraction - in practice, you might want more sophisticated parsing
148
+ if 'template' in template_text:
149
+ # Try to extract the name after template<...>
150
+ parts = template_text.split('>', 1)
151
+ if len(parts) > 1:
152
+ # Look for function/class name in the second part
153
+ match = re.search(r'\b(function|class|struct)\s+(\w+)', parts[1])
154
+ if match:
155
+ symbol_name = f"template_{match.group(2)}"
156
+ else:
157
+ symbol_name = "template"
158
+ else:
159
+ symbol_name = "template"
160
+ else:
161
+ symbol_name = "template"
162
+ else:
163
+ symbol_name = node.text.decode('utf8')
164
+
165
+ if not symbol_name:
166
+ return None
167
+
100
168
  return Symbol(
101
- name=node.text.decode('utf8'),
169
+ name=symbol_name,
102
170
  kind=symbol_kind,
103
171
  file_path=file_path,
104
172
  line_start=node.start_point[0] + 1,
@@ -26,8 +26,16 @@ GO_SYMBOL_QUERY = """
26
26
  (type_spec
27
27
  name: (type_identifier) @type.name))
28
28
 
29
- (interface_declaration
30
- name: (type_identifier) @interface.name)
29
+ (type_declaration
30
+ (type_spec
31
+ name: (type_identifier) @interface.name
32
+ type: (interface_type)))
33
+
34
+ (const_declaration) @const
35
+
36
+ (var_declaration) @var
37
+
38
+ (struct_type) @struct
31
39
  """
32
40
 
33
41
  # --- Go Language Setup ---
@@ -56,14 +64,38 @@ class GoSymbolExtractor(TreeSitterExtractor):
56
64
  "method.name": "method",
57
65
  "type.name": "type",
58
66
  "interface.name": "interface",
67
+ "const": "const",
68
+ "var": "var",
69
+ "struct": "struct",
59
70
  }
60
71
 
61
72
  symbol_kind = kind_map.get(name)
62
73
  if not symbol_kind:
63
74
  return None
64
75
 
76
+ # For const/var/struct, extract the first identifier as name
77
+ if symbol_kind in ("const", "var", "struct"):
78
+ # Try to find the first identifier in the declaration
79
+ node_text = node.text.decode('utf8').strip()
80
+ # Extract first identifier after const/var/struct keyword
81
+ if symbol_kind == "const":
82
+ match = re.search(r'const\s+(\w+)', node_text)
83
+ elif symbol_kind == "var":
84
+ match = re.search(r'var\s+(\w+)', node_text)
85
+ else: # struct
86
+ # For struct, try to find struct name or use a generic name
87
+ match = re.search(r'struct\s+(\w+)', node_text)
88
+
89
+ if match:
90
+ symbol_name = match.group(1)
91
+ else:
92
+ # Fallback: use the kind as name
93
+ symbol_name = symbol_kind
94
+ else:
95
+ symbol_name = node.text.decode('utf8')
96
+
65
97
  return Symbol(
66
- name=node.text.decode('utf8'),
98
+ name=symbol_name,
67
99
  kind=symbol_kind,
68
100
  file_path=file_path,
69
101
  line_start=node.start_point[0] + 1,