@treedy/lsp-mcp 0.1.7 → 0.1.9
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.
- package/dist/bundled/pyright/dist/index.d.ts +2 -0
- package/dist/bundled/pyright/dist/index.js +1620 -0
- package/dist/bundled/pyright/dist/index.js.map +26 -0
- package/dist/bundled/pyright/dist/lsp/connection.d.ts +71 -0
- package/dist/bundled/pyright/dist/lsp/document-manager.d.ts +67 -0
- package/dist/bundled/pyright/dist/lsp/index.d.ts +3 -0
- package/dist/bundled/pyright/dist/lsp/types.d.ts +55 -0
- package/dist/bundled/pyright/dist/lsp-client.d.ts +55 -0
- package/dist/bundled/pyright/dist/tools/completions.d.ts +18 -0
- package/dist/bundled/pyright/dist/tools/definition.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/diagnostics.d.ts +12 -0
- package/dist/bundled/pyright/dist/tools/hover.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/references.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/rename.d.ts +18 -0
- package/dist/bundled/pyright/dist/tools/search.d.ts +20 -0
- package/dist/bundled/pyright/dist/tools/signature-help.d.ts +16 -0
- package/dist/bundled/pyright/dist/tools/status.d.ts +14 -0
- package/dist/bundled/pyright/dist/tools/symbols.d.ts +17 -0
- package/dist/bundled/pyright/dist/tools/update-document.d.ts +14 -0
- package/dist/bundled/pyright/dist/utils/position.d.ts +33 -0
- package/dist/bundled/pyright/package.json +54 -0
- package/dist/bundled/python/README.md +230 -0
- package/dist/bundled/python/pyproject.toml +61 -0
- package/dist/bundled/python/src/rope_mcp/__init__.py +3 -0
- package/dist/bundled/python/src/rope_mcp/config.py +444 -0
- package/dist/bundled/python/src/rope_mcp/lsp/__init__.py +15 -0
- package/dist/bundled/python/src/rope_mcp/lsp/client.py +863 -0
- package/dist/bundled/python/src/rope_mcp/lsp/types.py +83 -0
- package/dist/bundled/python/src/rope_mcp/pyright_client.py +147 -0
- package/dist/bundled/python/src/rope_mcp/rope_client.py +198 -0
- package/dist/bundled/python/src/rope_mcp/server.py +1217 -0
- package/dist/bundled/python/src/rope_mcp/tools/__init__.py +24 -0
- package/dist/bundled/python/src/rope_mcp/tools/change_signature.py +184 -0
- package/dist/bundled/python/src/rope_mcp/tools/completions.py +84 -0
- package/dist/bundled/python/src/rope_mcp/tools/definition.py +51 -0
- package/dist/bundled/python/src/rope_mcp/tools/diagnostics.py +18 -0
- package/dist/bundled/python/src/rope_mcp/tools/hover.py +49 -0
- package/dist/bundled/python/src/rope_mcp/tools/move.py +81 -0
- package/dist/bundled/python/src/rope_mcp/tools/references.py +60 -0
- package/dist/bundled/python/src/rope_mcp/tools/rename.py +61 -0
- package/dist/bundled/python/src/rope_mcp/tools/search.py +128 -0
- package/dist/bundled/python/src/rope_mcp/tools/symbols.py +118 -0
- package/dist/bundled/python/uv.lock +979 -0
- package/dist/bundled/typescript/dist/index.js +29772 -0
- package/dist/bundled/typescript/dist/index.js.map +211 -0
- package/dist/bundled/typescript/package.json +46 -0
- package/dist/bundled/vue/dist/index.d.ts +8 -0
- package/dist/bundled/vue/dist/index.js +21176 -0
- package/dist/bundled/vue/dist/ts-vue-service.d.ts +67 -0
- package/dist/bundled/vue/dist/vue-service.d.ts +160 -0
- package/dist/bundled/vue/package.json +45 -0
- package/dist/index.js +695 -352
- package/dist/index.js.map +6 -6
- package/package.json +1 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Tool implementations for Rope MCP Server."""
|
|
2
|
+
|
|
3
|
+
from .hover import get_hover
|
|
4
|
+
from .definition import get_definition
|
|
5
|
+
from .references import get_references
|
|
6
|
+
from .completions import get_completions
|
|
7
|
+
from .symbols import get_symbols
|
|
8
|
+
from .rename import do_rename
|
|
9
|
+
from .move import do_move
|
|
10
|
+
from .change_signature import do_change_signature, get_function_signature
|
|
11
|
+
from .search import get_search
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"get_hover",
|
|
15
|
+
"get_definition",
|
|
16
|
+
"get_references",
|
|
17
|
+
"get_completions",
|
|
18
|
+
"get_symbols",
|
|
19
|
+
"do_rename",
|
|
20
|
+
"do_move",
|
|
21
|
+
"do_change_signature",
|
|
22
|
+
"get_function_signature",
|
|
23
|
+
"get_search",
|
|
24
|
+
]
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""Change signature tool implementation - modify function parameters."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from rope.refactor.change_signature import ChangeSignature, ArgumentNormalizer
|
|
6
|
+
|
|
7
|
+
from ..rope_client import get_client
|
|
8
|
+
from ..lsp import refresh_lsp_documents
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def do_change_signature(
|
|
12
|
+
file: str,
|
|
13
|
+
line: int,
|
|
14
|
+
column: int,
|
|
15
|
+
new_params: Optional[list[str]] = None,
|
|
16
|
+
add_param: Optional[dict] = None,
|
|
17
|
+
remove_param: Optional[str] = None,
|
|
18
|
+
resources_only: bool = False,
|
|
19
|
+
) -> dict:
|
|
20
|
+
"""Change the signature of a function.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
file: Absolute path to the Python file
|
|
24
|
+
line: 1-based line number of the function
|
|
25
|
+
column: 1-based column number of the function
|
|
26
|
+
new_params: Complete new parameter list (reorder/rename), e.g. ["self", "b", "a"]
|
|
27
|
+
add_param: Add a parameter, e.g. {"name": "new_param", "default": "None", "index": 1}
|
|
28
|
+
remove_param: Name of parameter to remove
|
|
29
|
+
resources_only: If True, only return what would change without applying
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
Dict containing the changes made or error message
|
|
33
|
+
|
|
34
|
+
Examples:
|
|
35
|
+
# Reorder parameters: def foo(a, b) -> def foo(b, a)
|
|
36
|
+
change_signature(file, line, col, new_params=["self", "b", "a"])
|
|
37
|
+
|
|
38
|
+
# Add parameter: def foo(a) -> def foo(a, b=None)
|
|
39
|
+
change_signature(file, line, col, add_param={"name": "b", "default": "None"})
|
|
40
|
+
|
|
41
|
+
# Remove parameter: def foo(a, b) -> def foo(a)
|
|
42
|
+
change_signature(file, line, col, remove_param="b")
|
|
43
|
+
"""
|
|
44
|
+
client = get_client()
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
workspace = client.find_workspace_for_file(file)
|
|
48
|
+
project = client.get_project(workspace)
|
|
49
|
+
resource = client.get_resource(project, file)
|
|
50
|
+
source = resource.read()
|
|
51
|
+
offset = client.position_to_offset(source, line, column)
|
|
52
|
+
|
|
53
|
+
# Create change signature refactoring
|
|
54
|
+
changer = ChangeSignature(project, resource, offset)
|
|
55
|
+
|
|
56
|
+
# Get current signature info
|
|
57
|
+
signature = changer.get_args()
|
|
58
|
+
original_params = [arg[0] for arg in signature] # Extract param names
|
|
59
|
+
|
|
60
|
+
# Build the changers list
|
|
61
|
+
changers = []
|
|
62
|
+
|
|
63
|
+
if new_params is not None:
|
|
64
|
+
# Reorder/rename parameters
|
|
65
|
+
# ArgumentNormalizer reorders arguments to match new order
|
|
66
|
+
changers.append(ArgumentNormalizer(new_params)) # type: ignore[call-arg]
|
|
67
|
+
|
|
68
|
+
if add_param is not None:
|
|
69
|
+
# Add a new parameter
|
|
70
|
+
from rope.refactor.change_signature import ArgumentAdder
|
|
71
|
+
|
|
72
|
+
name = add_param.get("name")
|
|
73
|
+
default = add_param.get("default")
|
|
74
|
+
index = add_param.get("index")
|
|
75
|
+
# If index is None, append at the end
|
|
76
|
+
if index is None:
|
|
77
|
+
index = len(original_params)
|
|
78
|
+
changers.append(ArgumentAdder(index, name, default))
|
|
79
|
+
|
|
80
|
+
if remove_param is not None:
|
|
81
|
+
# Remove a parameter
|
|
82
|
+
from rope.refactor.change_signature import ArgumentRemover
|
|
83
|
+
|
|
84
|
+
# Find the index of the parameter to remove
|
|
85
|
+
try:
|
|
86
|
+
param_index = original_params.index(remove_param)
|
|
87
|
+
changers.append(ArgumentRemover(param_index))
|
|
88
|
+
except ValueError:
|
|
89
|
+
return {
|
|
90
|
+
"error": f"Parameter '{remove_param}' not found in function signature",
|
|
91
|
+
"current_params": original_params,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if not changers:
|
|
95
|
+
return {
|
|
96
|
+
"error": "No changes specified. Use new_params, add_param, or remove_param.",
|
|
97
|
+
"current_params": original_params,
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# Get the changes
|
|
101
|
+
changes = changer.get_changes(changers)
|
|
102
|
+
|
|
103
|
+
# Collect the changes to report
|
|
104
|
+
changed_files = []
|
|
105
|
+
for change in changes.get_changed_resources():
|
|
106
|
+
changed_files.append(change.real_path)
|
|
107
|
+
|
|
108
|
+
if resources_only:
|
|
109
|
+
return {
|
|
110
|
+
"preview": True,
|
|
111
|
+
"original_params": original_params,
|
|
112
|
+
"changed_files": changed_files,
|
|
113
|
+
"changes_count": len(changed_files),
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
# Apply the changes
|
|
117
|
+
project.do(changes)
|
|
118
|
+
|
|
119
|
+
# Refresh LSP documents so Pyright picks up the changes
|
|
120
|
+
refresh_lsp_documents(changed_files)
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
"success": True,
|
|
124
|
+
"original_params": original_params,
|
|
125
|
+
"changed_files": changed_files,
|
|
126
|
+
"changes_count": len(changed_files),
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
except Exception as e:
|
|
130
|
+
return {
|
|
131
|
+
"error": str(e),
|
|
132
|
+
"file": file,
|
|
133
|
+
"line": line,
|
|
134
|
+
"column": column,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def get_function_signature(file: str, line: int, column: int) -> dict:
|
|
139
|
+
"""Get the current signature of a function.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
file: Absolute path to the Python file
|
|
143
|
+
line: 1-based line number of the function
|
|
144
|
+
column: 1-based column number of the function
|
|
145
|
+
|
|
146
|
+
Returns:
|
|
147
|
+
Dict containing the function signature info
|
|
148
|
+
"""
|
|
149
|
+
client = get_client()
|
|
150
|
+
|
|
151
|
+
try:
|
|
152
|
+
workspace = client.find_workspace_for_file(file)
|
|
153
|
+
project = client.get_project(workspace)
|
|
154
|
+
resource = client.get_resource(project, file)
|
|
155
|
+
source = resource.read()
|
|
156
|
+
offset = client.position_to_offset(source, line, column)
|
|
157
|
+
|
|
158
|
+
# Create change signature refactoring to inspect signature
|
|
159
|
+
changer = ChangeSignature(project, resource, offset)
|
|
160
|
+
|
|
161
|
+
# Get current signature info
|
|
162
|
+
# Returns list of tuples: [(name, default_value), ...]
|
|
163
|
+
signature = changer.get_args()
|
|
164
|
+
|
|
165
|
+
params = []
|
|
166
|
+
for arg in signature:
|
|
167
|
+
param_info = {"name": arg[0]}
|
|
168
|
+
if len(arg) > 1 and arg[1] is not None:
|
|
169
|
+
param_info["default"] = arg[1]
|
|
170
|
+
params.append(param_info)
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
"params": params,
|
|
174
|
+
"param_names": [p["name"] for p in params],
|
|
175
|
+
"count": len(params),
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
except Exception as e:
|
|
179
|
+
return {
|
|
180
|
+
"error": str(e),
|
|
181
|
+
"file": file,
|
|
182
|
+
"line": line,
|
|
183
|
+
"column": column,
|
|
184
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Completions tool implementation - code completion."""
|
|
2
|
+
|
|
3
|
+
from rope.contrib import codeassist
|
|
4
|
+
|
|
5
|
+
from ..rope_client import get_client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_completions(file: str, line: int, column: int) -> dict:
|
|
9
|
+
"""Get code completion suggestions at the given position.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
file: Absolute path to the Python file
|
|
13
|
+
line: 1-based line number
|
|
14
|
+
column: 1-based column number
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Dict containing completion items or error message
|
|
18
|
+
"""
|
|
19
|
+
client = get_client()
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
workspace = client.find_workspace_for_file(file)
|
|
23
|
+
project = client.get_project(workspace)
|
|
24
|
+
resource = client.get_resource(project, file)
|
|
25
|
+
source = resource.read()
|
|
26
|
+
offset = client.position_to_offset(source, line, column)
|
|
27
|
+
|
|
28
|
+
proposals = codeassist.code_assist(project, source, offset, resource)
|
|
29
|
+
|
|
30
|
+
# Sort proposals by relevance
|
|
31
|
+
proposals = codeassist.sorted_proposals(proposals)
|
|
32
|
+
|
|
33
|
+
completions = []
|
|
34
|
+
for proposal in proposals:
|
|
35
|
+
# Use scope instead of deprecated kind property
|
|
36
|
+
scope = getattr(proposal, "scope", None) or getattr(proposal, "kind", "")
|
|
37
|
+
item = {
|
|
38
|
+
"label": proposal.name,
|
|
39
|
+
"kind": _get_completion_kind(scope),
|
|
40
|
+
"detail": proposal.type or "",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Add documentation if available
|
|
44
|
+
if hasattr(proposal, "get_doc") and callable(proposal.get_doc):
|
|
45
|
+
try:
|
|
46
|
+
doc = proposal.get_doc()
|
|
47
|
+
if doc:
|
|
48
|
+
item["documentation"] = doc
|
|
49
|
+
except Exception:
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
completions.append(item)
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
"completions": completions,
|
|
56
|
+
"count": len(completions),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
except Exception as e:
|
|
60
|
+
return {
|
|
61
|
+
"error": str(e),
|
|
62
|
+
"file": file,
|
|
63
|
+
"line": line,
|
|
64
|
+
"column": column,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _get_completion_kind(rope_kind: str) -> str:
|
|
69
|
+
"""Map Rope completion kinds to standard kinds."""
|
|
70
|
+
kind_map = {
|
|
71
|
+
"function": "Function",
|
|
72
|
+
"class": "Class",
|
|
73
|
+
"module": "Module",
|
|
74
|
+
"variable": "Variable",
|
|
75
|
+
"attribute": "Property",
|
|
76
|
+
"builtin": "Constant",
|
|
77
|
+
"parameter": "Variable",
|
|
78
|
+
"keyword": "Keyword",
|
|
79
|
+
"imported": "Module",
|
|
80
|
+
"instance": "Variable",
|
|
81
|
+
"local": "Variable",
|
|
82
|
+
"global": "Variable",
|
|
83
|
+
}
|
|
84
|
+
return kind_map.get(rope_kind, "Text")
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Definition tool implementation - go to definition."""
|
|
2
|
+
|
|
3
|
+
from rope.contrib import codeassist
|
|
4
|
+
|
|
5
|
+
from ..rope_client import get_client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_definition(file: str, line: int, column: int) -> dict:
|
|
9
|
+
"""Get the definition location for the symbol at the given position.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
file: Absolute path to the Python file
|
|
13
|
+
line: 1-based line number
|
|
14
|
+
column: 1-based column number
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Dict containing definition location or error message
|
|
18
|
+
"""
|
|
19
|
+
client = get_client()
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
workspace = client.find_workspace_for_file(file)
|
|
23
|
+
project = client.get_project(workspace)
|
|
24
|
+
resource = client.get_resource(project, file)
|
|
25
|
+
source = resource.read()
|
|
26
|
+
offset = client.position_to_offset(source, line, column)
|
|
27
|
+
|
|
28
|
+
location = codeassist.get_definition_location(project, source, offset, resource)
|
|
29
|
+
|
|
30
|
+
if location and location[0] is not None:
|
|
31
|
+
def_resource, def_line = location
|
|
32
|
+
def_path = def_resource.real_path if def_resource else file
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
"file": def_path,
|
|
36
|
+
"line": def_line or 1,
|
|
37
|
+
"column": 1, # Rope doesn't provide column info
|
|
38
|
+
}
|
|
39
|
+
else:
|
|
40
|
+
return {
|
|
41
|
+
"file": None,
|
|
42
|
+
"message": "No definition found at this position",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
except Exception as e:
|
|
46
|
+
return {
|
|
47
|
+
"error": str(e),
|
|
48
|
+
"file": file,
|
|
49
|
+
"line": line,
|
|
50
|
+
"column": column,
|
|
51
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Diagnostics tool implementation using Pyright."""
|
|
2
|
+
|
|
3
|
+
from ..pyright_client import get_pyright_client
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def get_diagnostics(path: str) -> dict:
|
|
7
|
+
"""Get diagnostics (type errors, warnings) for a file or directory.
|
|
8
|
+
|
|
9
|
+
This tool uses Pyright for type checking and analysis.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
path: Absolute path to a Python file or directory
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Dict containing diagnostics or error message
|
|
16
|
+
"""
|
|
17
|
+
client = get_pyright_client()
|
|
18
|
+
return client.get_diagnostics(path)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Hover tool implementation - get documentation at position."""
|
|
2
|
+
|
|
3
|
+
from rope.contrib import codeassist
|
|
4
|
+
|
|
5
|
+
from ..rope_client import get_client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_hover(file: str, line: int, column: int) -> dict:
|
|
9
|
+
"""Get documentation for the symbol at the given position.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
file: Absolute path to the Python file
|
|
13
|
+
line: 1-based line number
|
|
14
|
+
column: 1-based column number
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Dict containing documentation or error message
|
|
18
|
+
"""
|
|
19
|
+
client = get_client()
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
workspace = client.find_workspace_for_file(file)
|
|
23
|
+
project = client.get_project(workspace)
|
|
24
|
+
resource = client.get_resource(project, file)
|
|
25
|
+
source = resource.read()
|
|
26
|
+
offset = client.position_to_offset(source, line, column)
|
|
27
|
+
|
|
28
|
+
doc = codeassist.get_doc(project, source, offset, resource)
|
|
29
|
+
|
|
30
|
+
if doc:
|
|
31
|
+
return {
|
|
32
|
+
"contents": doc,
|
|
33
|
+
"file": file,
|
|
34
|
+
"line": line,
|
|
35
|
+
"column": column,
|
|
36
|
+
}
|
|
37
|
+
else:
|
|
38
|
+
return {
|
|
39
|
+
"contents": None,
|
|
40
|
+
"message": "No documentation available at this position",
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
except Exception as e:
|
|
44
|
+
return {
|
|
45
|
+
"error": str(e),
|
|
46
|
+
"file": file,
|
|
47
|
+
"line": line,
|
|
48
|
+
"column": column,
|
|
49
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Move tool implementation - move function/class to another module."""
|
|
2
|
+
|
|
3
|
+
from rope.refactor.move import MoveGlobal
|
|
4
|
+
|
|
5
|
+
from ..rope_client import get_client
|
|
6
|
+
from ..lsp import refresh_lsp_documents
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def do_move(
|
|
10
|
+
file: str, line: int, column: int, destination: str, resources_only: bool = False
|
|
11
|
+
) -> dict:
|
|
12
|
+
"""Move a function or class to another module.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
file: Absolute path to the Python file containing the symbol
|
|
16
|
+
line: 1-based line number of the symbol
|
|
17
|
+
column: 1-based column number of the symbol
|
|
18
|
+
destination: Destination module path (e.g., "mypackage.utils" or "utils.py")
|
|
19
|
+
resources_only: If True, only return what would change without applying
|
|
20
|
+
|
|
21
|
+
Returns:
|
|
22
|
+
Dict containing the changes made or error message
|
|
23
|
+
"""
|
|
24
|
+
client = get_client()
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
workspace = client.find_workspace_for_file(file)
|
|
28
|
+
project = client.get_project(workspace)
|
|
29
|
+
resource = client.get_resource(project, file)
|
|
30
|
+
source = resource.read()
|
|
31
|
+
offset = client.position_to_offset(source, line, column)
|
|
32
|
+
|
|
33
|
+
# Create move refactoring
|
|
34
|
+
mover = MoveGlobal(project, resource, offset)
|
|
35
|
+
|
|
36
|
+
# Get the destination resource
|
|
37
|
+
# Handle both module path (foo.bar) and file path (foo/bar.py)
|
|
38
|
+
if destination.endswith(".py"):
|
|
39
|
+
dest_resource = project.get_resource(destination)
|
|
40
|
+
else:
|
|
41
|
+
# Convert module path to file path
|
|
42
|
+
dest_path = destination.replace(".", "/") + ".py"
|
|
43
|
+
dest_resource = project.get_resource(dest_path)
|
|
44
|
+
|
|
45
|
+
# Get the changes
|
|
46
|
+
changes = mover.get_changes(dest_resource)
|
|
47
|
+
|
|
48
|
+
# Collect the changes to report
|
|
49
|
+
changed_files = []
|
|
50
|
+
for change in changes.get_changed_resources():
|
|
51
|
+
changed_files.append(change.real_path)
|
|
52
|
+
|
|
53
|
+
if resources_only:
|
|
54
|
+
return {
|
|
55
|
+
"preview": True,
|
|
56
|
+
"destination": destination,
|
|
57
|
+
"changed_files": changed_files,
|
|
58
|
+
"changes_count": len(changed_files),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
# Apply the changes
|
|
62
|
+
project.do(changes)
|
|
63
|
+
|
|
64
|
+
# Refresh LSP documents so Pyright picks up the changes
|
|
65
|
+
refresh_lsp_documents(changed_files)
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
"success": True,
|
|
69
|
+
"destination": destination,
|
|
70
|
+
"changed_files": changed_files,
|
|
71
|
+
"changes_count": len(changed_files),
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
except Exception as e:
|
|
75
|
+
return {
|
|
76
|
+
"error": str(e),
|
|
77
|
+
"file": file,
|
|
78
|
+
"line": line,
|
|
79
|
+
"column": column,
|
|
80
|
+
"destination": destination,
|
|
81
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""References tool implementation - find all references."""
|
|
2
|
+
|
|
3
|
+
from rope.contrib import findit
|
|
4
|
+
|
|
5
|
+
from ..rope_client import get_client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_references(file: str, line: int, column: int) -> dict:
|
|
9
|
+
"""Find all references to the symbol at the given position.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
file: Absolute path to the Python file
|
|
13
|
+
line: 1-based line number
|
|
14
|
+
column: 1-based column number
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Dict containing list of references or error message
|
|
18
|
+
"""
|
|
19
|
+
client = get_client()
|
|
20
|
+
|
|
21
|
+
try:
|
|
22
|
+
workspace = client.find_workspace_for_file(file)
|
|
23
|
+
project = client.get_project(workspace)
|
|
24
|
+
resource = client.get_resource(project, file)
|
|
25
|
+
source = resource.read()
|
|
26
|
+
offset = client.position_to_offset(source, line, column)
|
|
27
|
+
|
|
28
|
+
occurrences = findit.find_occurrences(
|
|
29
|
+
project, resource, offset, unsure=False, in_hierarchy=True
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
references = []
|
|
33
|
+
for occurrence in occurrences:
|
|
34
|
+
occ_resource = occurrence.resource
|
|
35
|
+
occ_offset = occurrence.offset
|
|
36
|
+
|
|
37
|
+
# Read source to convert offset to line/column
|
|
38
|
+
occ_source = occ_resource.read()
|
|
39
|
+
occ_line, occ_column = client.offset_to_position(occ_source, occ_offset)
|
|
40
|
+
|
|
41
|
+
references.append(
|
|
42
|
+
{
|
|
43
|
+
"file": occ_resource.real_path,
|
|
44
|
+
"line": occ_line,
|
|
45
|
+
"column": occ_column,
|
|
46
|
+
}
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
"references": references,
|
|
51
|
+
"count": len(references),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
except Exception as e:
|
|
55
|
+
return {
|
|
56
|
+
"error": str(e),
|
|
57
|
+
"file": file,
|
|
58
|
+
"line": line,
|
|
59
|
+
"column": column,
|
|
60
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Rename tool implementation - rename refactoring."""
|
|
2
|
+
|
|
3
|
+
from rope.refactor.rename import Rename
|
|
4
|
+
|
|
5
|
+
from ..rope_client import get_client
|
|
6
|
+
from ..lsp import refresh_lsp_documents
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def do_rename(file: str, line: int, column: int, new_name: str) -> dict:
|
|
10
|
+
"""Rename the symbol at the given position.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
file: Absolute path to the Python file
|
|
14
|
+
line: 1-based line number
|
|
15
|
+
column: 1-based column number
|
|
16
|
+
new_name: The new name for the symbol
|
|
17
|
+
|
|
18
|
+
Returns:
|
|
19
|
+
Dict containing the changes made or error message
|
|
20
|
+
"""
|
|
21
|
+
client = get_client()
|
|
22
|
+
|
|
23
|
+
try:
|
|
24
|
+
workspace = client.find_workspace_for_file(file)
|
|
25
|
+
project = client.get_project(workspace)
|
|
26
|
+
resource = client.get_resource(project, file)
|
|
27
|
+
source = resource.read()
|
|
28
|
+
offset = client.position_to_offset(source, line, column)
|
|
29
|
+
|
|
30
|
+
# Create rename refactoring
|
|
31
|
+
renamer = Rename(project, resource, offset)
|
|
32
|
+
|
|
33
|
+
# Get the changes
|
|
34
|
+
changes = renamer.get_changes(new_name)
|
|
35
|
+
|
|
36
|
+
# Collect the changes to report
|
|
37
|
+
changed_files = []
|
|
38
|
+
for change in changes.get_changed_resources():
|
|
39
|
+
changed_files.append(change.real_path)
|
|
40
|
+
|
|
41
|
+
# Apply the changes
|
|
42
|
+
project.do(changes)
|
|
43
|
+
|
|
44
|
+
# Refresh LSP documents so Pyright picks up the changes
|
|
45
|
+
refresh_lsp_documents(changed_files)
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"success": True,
|
|
49
|
+
"new_name": new_name,
|
|
50
|
+
"changed_files": changed_files,
|
|
51
|
+
"changes_count": len(changed_files),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
except Exception as e:
|
|
55
|
+
return {
|
|
56
|
+
"error": str(e),
|
|
57
|
+
"file": file,
|
|
58
|
+
"line": line,
|
|
59
|
+
"column": column,
|
|
60
|
+
"new_name": new_name,
|
|
61
|
+
}
|