mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-05 01:50:27 +08:00
feat: 添加多个 LSP 测试示例,包括能力测试、调用层次和原始 LSP 测试
This commit is contained in:
40
codex-lens/examples/debug_uri_format.py
Normal file
40
codex-lens/examples/debug_uri_format.py
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
"""Debug URI format issues."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
from urllib.parse import quote
|
||||||
|
|
||||||
|
def test_uri_formats():
|
||||||
|
"""Compare different URI formats."""
|
||||||
|
file_path = Path("D:/Claude_dms3/codex-lens/test_simple_function.py")
|
||||||
|
|
||||||
|
print("URI Format Comparison")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
# Method 1: Path.as_uri()
|
||||||
|
uri1 = file_path.resolve().as_uri()
|
||||||
|
print(f"1. Path.as_uri(): {uri1}")
|
||||||
|
|
||||||
|
# Method 2: Manual construction
|
||||||
|
uri2 = f"file:///{str(file_path.resolve()).replace(chr(92), '/')}"
|
||||||
|
print(f"2. Manual (forward /): {uri2}")
|
||||||
|
|
||||||
|
# Method 3: With quote
|
||||||
|
path_str = str(file_path.resolve()).replace(chr(92), '/')
|
||||||
|
uri3 = f"file:///{quote(path_str, safe='/:')}"
|
||||||
|
print(f"3. With quote: {uri3}")
|
||||||
|
|
||||||
|
# Method 4: Lowercase drive
|
||||||
|
path_lower = str(file_path.resolve()).replace(chr(92), '/')
|
||||||
|
if len(path_lower) > 1 and path_lower[1] == ':':
|
||||||
|
path_lower = path_lower[0].lower() + path_lower[1:]
|
||||||
|
uri4 = f"file:///{path_lower}"
|
||||||
|
print(f"4. Lowercase drive: {uri4}")
|
||||||
|
|
||||||
|
# What Pyright shows in logs
|
||||||
|
print(f"\n5. Pyright log format: file:///d%3A/Claude_dms3/codex-lens/...")
|
||||||
|
|
||||||
|
return uri1, uri4
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_uri_formats()
|
||||||
79
codex-lens/examples/test_lsp_capabilities.py
Normal file
79
codex-lens/examples/test_lsp_capabilities.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
"""Test LSP server capabilities."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
|
||||||
|
async def test_capabilities():
|
||||||
|
"""Test what capabilities Pyright provides."""
|
||||||
|
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens/src")
|
||||||
|
|
||||||
|
print("Testing LSP Capabilities")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
# Create LSP manager
|
||||||
|
manager = StandaloneLspManager(
|
||||||
|
workspace_root=str(workspace_root),
|
||||||
|
timeout=10.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start LSP manager
|
||||||
|
print("\n1. Starting LSP manager...")
|
||||||
|
await manager.start()
|
||||||
|
print(" [OK] LSP manager started")
|
||||||
|
|
||||||
|
# Get server state for Python
|
||||||
|
print("\n2. Getting Python server state...")
|
||||||
|
test_file = str(workspace_root / "codexlens/search/hybrid_search.py")
|
||||||
|
state = await manager._get_server(test_file)
|
||||||
|
|
||||||
|
if not state:
|
||||||
|
print(" [ERROR] Could not get server state!")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f" [OK] Server state obtained")
|
||||||
|
print(f" Initialized: {state.initialized}")
|
||||||
|
|
||||||
|
# Print capabilities
|
||||||
|
print("\n3. Server Capabilities:")
|
||||||
|
print("-"*80)
|
||||||
|
caps = state.capabilities
|
||||||
|
|
||||||
|
# Key capabilities to check
|
||||||
|
important_caps = [
|
||||||
|
"callHierarchyProvider",
|
||||||
|
"definitionProvider",
|
||||||
|
"referencesProvider",
|
||||||
|
"documentSymbolProvider",
|
||||||
|
"workspaceSymbolProvider",
|
||||||
|
"hoverProvider",
|
||||||
|
"completionProvider",
|
||||||
|
"signatureHelpProvider",
|
||||||
|
]
|
||||||
|
|
||||||
|
for cap in important_caps:
|
||||||
|
value = caps.get(cap)
|
||||||
|
status = "[YES]" if value else "[NO]"
|
||||||
|
print(f" {status} {cap}: {value}")
|
||||||
|
|
||||||
|
# Print all capabilities as JSON for reference
|
||||||
|
print("\n4. Full capabilities (formatted):")
|
||||||
|
print("-"*80)
|
||||||
|
print(json.dumps(caps, indent=2))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n[ERROR] Error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
print("\n5. Cleaning up...")
|
||||||
|
await manager.stop()
|
||||||
|
print(" [OK] LSP manager stopped")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_capabilities())
|
||||||
76
codex-lens/examples/test_lsp_references.py
Normal file
76
codex-lens/examples/test_lsp_references.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
"""Test LSP references as alternative to call hierarchy."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
|
||||||
|
async def test_references():
|
||||||
|
"""Test using references as alternative to call hierarchy."""
|
||||||
|
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens")
|
||||||
|
test_file = workspace_root / "test_simple_function.py"
|
||||||
|
|
||||||
|
print("Testing LSP References (Alternative)")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
manager = StandaloneLspManager(
|
||||||
|
workspace_root=str(workspace_root),
|
||||||
|
timeout=30.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("\n1. Starting LSP manager...")
|
||||||
|
await manager.start()
|
||||||
|
print(" [OK] Started")
|
||||||
|
|
||||||
|
# Wait for analysis
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
|
# Test references for hello_world function
|
||||||
|
print("\n2. Testing references for 'hello_world' (line 4)...")
|
||||||
|
refs = await manager.get_references(
|
||||||
|
file_path=str(test_file),
|
||||||
|
line=4,
|
||||||
|
character=5,
|
||||||
|
include_declaration=True,
|
||||||
|
)
|
||||||
|
print(f" Found: {len(refs)} references")
|
||||||
|
for ref in refs[:5]:
|
||||||
|
uri = ref.get('uri', '')
|
||||||
|
range_obj = ref.get('range', {})
|
||||||
|
start = range_obj.get('start', {})
|
||||||
|
print(f" - {uri.split('/')[-1]}:{start.get('line', 0)+1}")
|
||||||
|
|
||||||
|
# Test definition
|
||||||
|
print("\n3. Testing definition for 'hello_world' call (line 13)...")
|
||||||
|
defs = await manager.get_definition(
|
||||||
|
file_path=str(test_file),
|
||||||
|
line=13,
|
||||||
|
character=11,
|
||||||
|
)
|
||||||
|
print(f" Found: {len(defs)} definitions")
|
||||||
|
for d in defs:
|
||||||
|
uri = d.get('uri', '')
|
||||||
|
range_obj = d.get('range', {})
|
||||||
|
start = range_obj.get('start', {})
|
||||||
|
print(f" - {uri.split('/')[-1]}:{start.get('line', 0)+1}")
|
||||||
|
|
||||||
|
# Test document symbols
|
||||||
|
print("\n4. Testing document symbols...")
|
||||||
|
symbols = await manager.get_document_symbols(str(test_file))
|
||||||
|
print(f" Found: {len(symbols)} symbols")
|
||||||
|
for sym in symbols:
|
||||||
|
print(f" - {sym.get('name')} ({sym.get('kind')})")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n[ERROR] {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
print("\n5. Cleanup...")
|
||||||
|
await manager.stop()
|
||||||
|
print(" [OK] Done")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_references())
|
||||||
91
codex-lens/examples/test_lsp_tree.py
Normal file
91
codex-lens/examples/test_lsp_tree.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
"""Test LSP Association Tree building directly."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
from codexlens.search.association_tree import AssociationTreeBuilder
|
||||||
|
|
||||||
|
async def test_lsp_tree():
|
||||||
|
"""Test building LSP association tree for a known Python file."""
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens/src")
|
||||||
|
test_file = "codexlens/search/hybrid_search.py"
|
||||||
|
test_line = 115 # search() method definition
|
||||||
|
|
||||||
|
print(f"Testing LSP tree for: {test_file}:{test_line}")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
# Create LSP manager
|
||||||
|
manager = StandaloneLspManager(
|
||||||
|
workspace_root=str(workspace_root),
|
||||||
|
timeout=10.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start LSP manager
|
||||||
|
print("\n1. Starting LSP manager...")
|
||||||
|
await manager.start()
|
||||||
|
print(" [OK] LSP manager started")
|
||||||
|
|
||||||
|
# Test get_call_hierarchy_items directly
|
||||||
|
print(f"\n2. Testing get_call_hierarchy_items for {test_file}:{test_line}...")
|
||||||
|
items = await manager.get_call_hierarchy_items(
|
||||||
|
file_path=str(workspace_root / test_file),
|
||||||
|
line=test_line,
|
||||||
|
character=10,
|
||||||
|
)
|
||||||
|
print(f" Result: {len(items)} items")
|
||||||
|
if items:
|
||||||
|
for i, item in enumerate(items, 1):
|
||||||
|
print(f" {i}. {item.get('name')} ({item.get('kind')})")
|
||||||
|
print(f" URI: {item.get('uri')}")
|
||||||
|
print(f" Range: {item.get('range')}")
|
||||||
|
else:
|
||||||
|
print(" [WARN] No call hierarchy items returned!")
|
||||||
|
print(" This means either:")
|
||||||
|
print(" - The file/line doesn't contain a symbol")
|
||||||
|
print(" - LSP server doesn't support call hierarchy")
|
||||||
|
print(" - Pyright isn't running correctly")
|
||||||
|
|
||||||
|
# If we got items, try building a tree
|
||||||
|
if items:
|
||||||
|
print(f"\n3. Building association tree...")
|
||||||
|
builder = AssociationTreeBuilder(
|
||||||
|
lsp_manager=manager,
|
||||||
|
timeout=10.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
tree = await builder.build_tree(
|
||||||
|
seed_file_path=str(workspace_root / test_file),
|
||||||
|
seed_line=test_line,
|
||||||
|
seed_character=10,
|
||||||
|
max_depth=2,
|
||||||
|
expand_callers=True,
|
||||||
|
expand_callees=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f" Tree built successfully!")
|
||||||
|
print(f" - Roots: {len(tree.roots)}")
|
||||||
|
print(f" - Total nodes: {len(tree.node_list)}")
|
||||||
|
print(f" - Depth reached: {tree.depth_reached}")
|
||||||
|
|
||||||
|
if tree.node_list:
|
||||||
|
print(f"\n First 5 nodes:")
|
||||||
|
for i, node in enumerate(tree.node_list[:5], 1):
|
||||||
|
print(f" {i}. {node.item.name} @ {node.item.file_path}:{node.item.range.start_line}")
|
||||||
|
print(f" Depth: {node.depth}, Is cycle: {node.is_cycle}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n[ERROR] Error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
print("\n4. Cleaning up...")
|
||||||
|
await manager.stop()
|
||||||
|
print(" [OK] LSP manager stopped")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_lsp_tree())
|
||||||
104
codex-lens/examples/test_raw_lsp.py
Normal file
104
codex-lens/examples/test_raw_lsp.py
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
"""Raw LSP test with debug logging."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
|
||||||
|
# Enable debug logging
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
|
logger = logging.getLogger("codexlens.lsp")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
async def test_raw_lsp():
|
||||||
|
"""Test LSP with debug logging enabled."""
|
||||||
|
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens")
|
||||||
|
test_file = workspace_root / "test_simple_function.py"
|
||||||
|
|
||||||
|
print("Testing Raw LSP Call Hierarchy")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
# Create LSP manager
|
||||||
|
manager = StandaloneLspManager(
|
||||||
|
workspace_root=str(workspace_root),
|
||||||
|
timeout=30.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start LSP manager
|
||||||
|
print("\n1. Starting LSP manager...")
|
||||||
|
await manager.start()
|
||||||
|
print(" [OK] Started")
|
||||||
|
|
||||||
|
# Get server state
|
||||||
|
state = await manager._get_server(str(test_file))
|
||||||
|
if not state:
|
||||||
|
print(" [ERROR] No server state!")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f" Server initialized: {state.initialized}")
|
||||||
|
print(f" Call hierarchy supported: {state.capabilities.get('callHierarchyProvider')}")
|
||||||
|
|
||||||
|
# Open document
|
||||||
|
print("\n2. Opening document...")
|
||||||
|
await manager._open_document(state, str(test_file))
|
||||||
|
print(" [OK] Document opened")
|
||||||
|
|
||||||
|
# Wait a bit for Pyright to analyze
|
||||||
|
print("\n3. Waiting for analysis...")
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
print(" [OK] Waited 2 seconds")
|
||||||
|
|
||||||
|
# Try call hierarchy on main function (line 12)
|
||||||
|
print("\n4. Sending prepareCallHierarchy request...")
|
||||||
|
|
||||||
|
# Direct request using _send_request
|
||||||
|
params = {
|
||||||
|
"textDocument": {"uri": test_file.as_uri()},
|
||||||
|
"position": {"line": 11, "character": 4} # 0-indexed, "main" function
|
||||||
|
}
|
||||||
|
print(f" Params: {json.dumps(params, indent=2)}")
|
||||||
|
|
||||||
|
result = await manager._send_request(
|
||||||
|
state,
|
||||||
|
"textDocument/prepareCallHierarchy",
|
||||||
|
params,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\n5. Result: {result}")
|
||||||
|
print(f" Type: {type(result)}")
|
||||||
|
|
||||||
|
if result:
|
||||||
|
print(f" Items: {len(result)}")
|
||||||
|
for item in result:
|
||||||
|
print(f" - {item.get('name')}")
|
||||||
|
else:
|
||||||
|
print(" [WARN] No items returned")
|
||||||
|
print(" This could mean:")
|
||||||
|
print(" - Position doesn't point to a symbol")
|
||||||
|
print(" - Pyright hasn't finished analyzing")
|
||||||
|
print(" - Some other issue")
|
||||||
|
|
||||||
|
# Try with the higher-level API
|
||||||
|
print("\n6. Testing with get_call_hierarchy_items API...")
|
||||||
|
items = await manager.get_call_hierarchy_items(
|
||||||
|
file_path=str(test_file),
|
||||||
|
line=12,
|
||||||
|
character=5,
|
||||||
|
)
|
||||||
|
print(f" Result: {len(items)} items")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n[ERROR] Error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
print("\n7. Cleanup...")
|
||||||
|
await manager.stop()
|
||||||
|
print(" [OK] Done")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_raw_lsp())
|
||||||
96
codex-lens/examples/test_raw_response.py
Normal file
96
codex-lens/examples/test_raw_response.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
"""Test to see raw LSP response."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Patch the _process_messages to log the full response
|
||||||
|
async def patched_process_messages(self, language_id: str):
|
||||||
|
"""Patched version that logs full response."""
|
||||||
|
from codexlens.lsp.standalone_manager import logger
|
||||||
|
|
||||||
|
state = self._servers.get(language_id)
|
||||||
|
if not state:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
message = await state.message_queue.get()
|
||||||
|
msg_id = message.get("id")
|
||||||
|
method = message.get("method", "")
|
||||||
|
|
||||||
|
# Log FULL message for debugging
|
||||||
|
if msg_id is not None and not method:
|
||||||
|
print(f"\n>>> FULL RESPONSE (id={msg_id}):")
|
||||||
|
print(json.dumps(message, indent=2))
|
||||||
|
|
||||||
|
# Response handling
|
||||||
|
if msg_id is not None and not method:
|
||||||
|
if msg_id in state.pending_requests:
|
||||||
|
future = state.pending_requests.pop(msg_id)
|
||||||
|
if "error" in message:
|
||||||
|
print(f">>> ERROR in response: {message['error']}")
|
||||||
|
future.set_exception(
|
||||||
|
Exception(message["error"].get("message", "Unknown error"))
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
print(f">>> Result: {message.get('result')}")
|
||||||
|
future.set_result(message.get("result"))
|
||||||
|
else:
|
||||||
|
print(f">>> No pending request for id={msg_id}")
|
||||||
|
|
||||||
|
elif msg_id is not None and method:
|
||||||
|
await self._handle_server_request(state, message)
|
||||||
|
|
||||||
|
elif method:
|
||||||
|
pass # Skip notifications
|
||||||
|
|
||||||
|
state.message_queue.task_done()
|
||||||
|
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def test_raw():
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens")
|
||||||
|
test_file = workspace_root / "test_simple_function.py"
|
||||||
|
|
||||||
|
manager = StandaloneLspManager(workspace_root=str(workspace_root), timeout=30.0)
|
||||||
|
|
||||||
|
# Monkey-patch the method
|
||||||
|
import types
|
||||||
|
manager._process_messages = types.MethodType(patched_process_messages, manager)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("Starting LSP...")
|
||||||
|
await manager.start()
|
||||||
|
|
||||||
|
state = await manager._get_server(str(test_file))
|
||||||
|
await manager._open_document(state, str(test_file))
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
|
print("\nSending prepareCallHierarchy request...")
|
||||||
|
uri = test_file.resolve().as_uri()
|
||||||
|
params = {
|
||||||
|
"textDocument": {"uri": uri},
|
||||||
|
"position": {"line": 11, "character": 4}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Need to restart the message processor with our patched version
|
||||||
|
# Actually, the original is already running. Let's just send and see logs.
|
||||||
|
|
||||||
|
result = await manager._send_request(
|
||||||
|
state,
|
||||||
|
"textDocument/prepareCallHierarchy",
|
||||||
|
params
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"\nFinal result: {result}")
|
||||||
|
|
||||||
|
finally:
|
||||||
|
await manager.stop()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_raw())
|
||||||
87
codex-lens/examples/test_simple_call_hierarchy.py
Normal file
87
codex-lens/examples/test_simple_call_hierarchy.py
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
"""Test call hierarchy on a simple Python file."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from pathlib import Path
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
|
||||||
|
async def test_simple_call_hierarchy():
|
||||||
|
"""Test call hierarchy on test_simple_function.py."""
|
||||||
|
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens")
|
||||||
|
test_file = workspace_root / "test_simple_function.py"
|
||||||
|
|
||||||
|
print("Testing Call Hierarchy on Simple Function")
|
||||||
|
print("="*80)
|
||||||
|
print(f"File: {test_file}")
|
||||||
|
|
||||||
|
# Create LSP manager
|
||||||
|
manager = StandaloneLspManager(
|
||||||
|
workspace_root=str(workspace_root),
|
||||||
|
timeout=10.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start LSP manager
|
||||||
|
print("\n1. Starting LSP manager...")
|
||||||
|
await manager.start()
|
||||||
|
print(" [OK] LSP manager started")
|
||||||
|
|
||||||
|
# Test different function positions
|
||||||
|
test_cases = [
|
||||||
|
("hello_world", 4, 5, "def hello_world():"),
|
||||||
|
("greet", 8, 5, "def greet(name: str):"),
|
||||||
|
("main", 12, 5, "def main():"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for func_name, line, char, expected in test_cases:
|
||||||
|
print(f"\n2. Testing {func_name} at line {line}:")
|
||||||
|
print(f" Expected: {expected}")
|
||||||
|
|
||||||
|
items = await manager.get_call_hierarchy_items(
|
||||||
|
file_path=str(test_file),
|
||||||
|
line=line,
|
||||||
|
character=char,
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f" Result: {len(items)} items")
|
||||||
|
if items:
|
||||||
|
for i, item in enumerate(items, 1):
|
||||||
|
print(f" {i}. Name: {item.get('name')}")
|
||||||
|
print(f" Kind: {item.get('kind')}")
|
||||||
|
print(f" URI: {item.get('uri')}")
|
||||||
|
range_obj = item.get('range', {})
|
||||||
|
start = range_obj.get('start', {})
|
||||||
|
print(f" Line: {start.get('line', 0) + 1}")
|
||||||
|
|
||||||
|
# If we got items, try getting incoming/outgoing calls
|
||||||
|
print(f"\n Testing incoming/outgoing calls for {func_name}:")
|
||||||
|
first_item = items[0]
|
||||||
|
|
||||||
|
incoming = await manager.get_incoming_calls(first_item)
|
||||||
|
print(f" - Incoming calls: {len(incoming)}")
|
||||||
|
for call in incoming:
|
||||||
|
caller = call.get('from', {})
|
||||||
|
print(f" Called by: {caller.get('name')}")
|
||||||
|
|
||||||
|
outgoing = await manager.get_outgoing_calls(first_item)
|
||||||
|
print(f" - Outgoing calls: {len(outgoing)}")
|
||||||
|
for call in outgoing:
|
||||||
|
callee = call.get('to', {})
|
||||||
|
print(f" Calls: {callee.get('name')}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(f" [WARN] No call hierarchy items for {func_name}!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n[ERROR] Error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup
|
||||||
|
print("\n3. Cleaning up...")
|
||||||
|
await manager.stop()
|
||||||
|
print(" [OK] LSP manager stopped")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_simple_call_hierarchy())
|
||||||
98
codex-lens/examples/test_uri_consistency.py
Normal file
98
codex-lens/examples/test_uri_consistency.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
"""Test if URI inconsistency causes the issue."""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
from codexlens.lsp.standalone_manager import StandaloneLspManager
|
||||||
|
|
||||||
|
async def test_with_consistent_uri():
|
||||||
|
"""Test prepareCallHierarchy with different URI formats."""
|
||||||
|
|
||||||
|
workspace_root = Path("D:/Claude_dms3/codex-lens")
|
||||||
|
test_file = workspace_root / "test_simple_function.py"
|
||||||
|
resolved = test_file.resolve()
|
||||||
|
|
||||||
|
print("Testing URI Consistency")
|
||||||
|
print("="*80)
|
||||||
|
|
||||||
|
# Different URI formats to try
|
||||||
|
uri_standard = resolved.as_uri()
|
||||||
|
uri_lowercase = uri_standard.replace("file:///D:", "file:///d:")
|
||||||
|
|
||||||
|
print(f"Standard URI: {uri_standard}")
|
||||||
|
print(f"Lowercase URI: {uri_lowercase}")
|
||||||
|
|
||||||
|
manager = StandaloneLspManager(
|
||||||
|
workspace_root=str(workspace_root),
|
||||||
|
timeout=30.0,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
print("\n1. Starting LSP manager...")
|
||||||
|
await manager.start()
|
||||||
|
|
||||||
|
state = await manager._get_server(str(test_file))
|
||||||
|
if not state:
|
||||||
|
print(" [ERROR] No server state")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(" [OK] Server ready")
|
||||||
|
|
||||||
|
# Open document
|
||||||
|
print("\n2. Opening document...")
|
||||||
|
await manager._open_document(state, str(test_file))
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
print(" [OK] Document opened, waited 2s")
|
||||||
|
|
||||||
|
# Test 1: Standard URI (as_uri)
|
||||||
|
print("\n3. Test with standard URI...")
|
||||||
|
params1 = {
|
||||||
|
"textDocument": {"uri": uri_standard},
|
||||||
|
"position": {"line": 11, "character": 4} # main function
|
||||||
|
}
|
||||||
|
print(f" Params: {json.dumps(params1)}")
|
||||||
|
result1 = await manager._send_request(state, "textDocument/prepareCallHierarchy", params1)
|
||||||
|
print(f" Result: {result1}")
|
||||||
|
|
||||||
|
# Test 2: Lowercase drive letter
|
||||||
|
print("\n4. Test with lowercase drive letter URI...")
|
||||||
|
params2 = {
|
||||||
|
"textDocument": {"uri": uri_lowercase},
|
||||||
|
"position": {"line": 11, "character": 4}
|
||||||
|
}
|
||||||
|
print(f" Params: {json.dumps(params2)}")
|
||||||
|
result2 = await manager._send_request(state, "textDocument/prepareCallHierarchy", params2)
|
||||||
|
print(f" Result: {result2}")
|
||||||
|
|
||||||
|
# Test 3: Position at function name start
|
||||||
|
print("\n5. Test with position at 'def' keyword (char 0)...")
|
||||||
|
params3 = {
|
||||||
|
"textDocument": {"uri": uri_lowercase},
|
||||||
|
"position": {"line": 11, "character": 0}
|
||||||
|
}
|
||||||
|
result3 = await manager._send_request(state, "textDocument/prepareCallHierarchy", params3)
|
||||||
|
print(f" Result: {result3}")
|
||||||
|
|
||||||
|
# Test 4: Different positions on line 12 (1-indexed = line 11 0-indexed)
|
||||||
|
print("\n6. Testing different character positions on 'def main():'...")
|
||||||
|
for char in [0, 4, 5, 6, 7, 8]:
|
||||||
|
params = {
|
||||||
|
"textDocument": {"uri": uri_lowercase},
|
||||||
|
"position": {"line": 11, "character": char}
|
||||||
|
}
|
||||||
|
result = await manager._send_request(state, "textDocument/prepareCallHierarchy", params)
|
||||||
|
status = "OK" if result else "None"
|
||||||
|
print(f" char={char}: {status} - {result[:1] if result else '[]'}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"\n[ERROR] {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
print("\n7. Cleanup...")
|
||||||
|
await manager.stop()
|
||||||
|
print(" [OK]")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_with_consistent_uri())
|
||||||
19
codex-lens/test_simple_function.py
Normal file
19
codex-lens/test_simple_function.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
"""Simple test file with clear function definitions."""
|
||||||
|
|
||||||
|
def hello_world():
|
||||||
|
"""A simple function."""
|
||||||
|
return "Hello, World!"
|
||||||
|
|
||||||
|
def greet(name: str) -> str:
|
||||||
|
"""Greet someone by name."""
|
||||||
|
return f"Hello, {name}!"
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main function that calls other functions."""
|
||||||
|
msg = hello_world()
|
||||||
|
greeting = greet("Alice")
|
||||||
|
print(msg)
|
||||||
|
print(greeting)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user