renpy-language-server 0.2.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.

Potentially problematic release.


This version of renpy-language-server might be problematic. Click here for more details.

Files changed (44) hide show
  1. renpy_language_server/__init__.py +6 -0
  2. renpy_language_server/__main__.py +5 -0
  3. renpy_language_server/analysis.py +230 -0
  4. renpy_language_server/assets.py +104 -0
  5. renpy_language_server/builtins.py +54 -0
  6. renpy_language_server/cli.py +190 -0
  7. renpy_language_server/code_actions.py +130 -0
  8. renpy_language_server/completion.py +1191 -0
  9. renpy_language_server/completion_data.py +74 -0
  10. renpy_language_server/dap.py +824 -0
  11. renpy_language_server/data/__init__.py +1 -0
  12. renpy_language_server/data/completion.json +756 -0
  13. renpy_language_server/data/renpy_api.json +8073 -0
  14. renpy_language_server/definition.py +77 -0
  15. renpy_language_server/diagnostics.py +895 -0
  16. renpy_language_server/docs.py +21 -0
  17. renpy_language_server/edits.py +70 -0
  18. renpy_language_server/folding.py +107 -0
  19. renpy_language_server/formatter.py +288 -0
  20. renpy_language_server/hover.py +238 -0
  21. renpy_language_server/index.py +1002 -0
  22. renpy_language_server/positions.py +28 -0
  23. renpy_language_server/py.typed +0 -0
  24. renpy_language_server/python_format.py +141 -0
  25. renpy_language_server/python_index.py +371 -0
  26. renpy_language_server/quotes.py +143 -0
  27. renpy_language_server/references.py +40 -0
  28. renpy_language_server/rename.py +293 -0
  29. renpy_language_server/resolve.py +807 -0
  30. renpy_language_server/scanner.py +86 -0
  31. renpy_language_server/semantic.py +488 -0
  32. renpy_language_server/server.py +770 -0
  33. renpy_language_server/settings.py +187 -0
  34. renpy_language_server/signature.py +371 -0
  35. renpy_language_server/spacing.py +261 -0
  36. renpy_language_server/strings.py +86 -0
  37. renpy_language_server/symbols.py +163 -0
  38. renpy_language_server/targets.py +51 -0
  39. renpy_language_server-0.2.0.dist-info/METADATA +434 -0
  40. renpy_language_server-0.2.0.dist-info/RECORD +44 -0
  41. renpy_language_server-0.2.0.dist-info/WHEEL +4 -0
  42. renpy_language_server-0.2.0.dist-info/entry_points.txt +3 -0
  43. renpy_language_server-0.2.0.dist-info/licenses/LICENSE +21 -0
  44. renpy_language_server-0.2.0.dist-info/licenses/NOTICE.md +41 -0
@@ -0,0 +1,130 @@
1
+ """Quick fixes for diagnostics that can be repaired without guessing."""
2
+
3
+ import re
4
+ from collections.abc import Sequence
5
+
6
+ from lsprotocol import types
7
+
8
+ from .diagnostics import COMPARISON, STRAY_DOLLAR, TABS, UNKNOWN_LABEL
9
+ from .index import utf16_length
10
+
11
+ _UNKNOWN_LABEL = re.compile(r"Unknown label '(.+)'\.")
12
+
13
+
14
+ def code_actions_for(
15
+ uri: str,
16
+ source: str,
17
+ requested: types.Range,
18
+ diagnostics: Sequence[types.Diagnostic],
19
+ indent: int = 4,
20
+ ) -> list[types.CodeAction]:
21
+ """Return quick fixes for diagnostics overlapping ``requested``."""
22
+ actions: list[types.CodeAction] = []
23
+ for diagnostic in diagnostics:
24
+ if not _overlaps(diagnostic.range, requested):
25
+ continue
26
+ action = _action(uri, source, diagnostic, indent)
27
+ if action is not None:
28
+ actions.append(action)
29
+ return actions
30
+
31
+
32
+ def _action(
33
+ uri: str,
34
+ source: str,
35
+ diagnostic: types.Diagnostic,
36
+ indent: int,
37
+ ) -> types.CodeAction | None:
38
+ code = diagnostic.code
39
+ if code == COMPARISON:
40
+ return _edit_action(
41
+ uri,
42
+ 'Replace "=" with "=="',
43
+ diagnostic,
44
+ diagnostic.range,
45
+ "==",
46
+ )
47
+ if code == STRAY_DOLLAR:
48
+ return _edit_action(
49
+ uri,
50
+ 'Remove stray "$"',
51
+ diagnostic,
52
+ diagnostic.range,
53
+ "",
54
+ )
55
+ if code == TABS:
56
+ tabs = _text_at(source, diagnostic.range)
57
+ if "\t" not in tabs:
58
+ return None
59
+ return _edit_action(
60
+ uri,
61
+ "Replace tabs with spaces",
62
+ diagnostic,
63
+ diagnostic.range,
64
+ " " * (indent * tabs.count("\t")),
65
+ )
66
+ if code == UNKNOWN_LABEL:
67
+ match = _UNKNOWN_LABEL.fullmatch(diagnostic.message)
68
+ if match is None:
69
+ return None
70
+ name = match.group(1)
71
+ if not name or name.startswith("."):
72
+ return None
73
+ return _edit_action(
74
+ uri,
75
+ f"Create label '{name}'",
76
+ diagnostic,
77
+ _end_of_document(source),
78
+ _new_label(source, name, indent),
79
+ )
80
+ return None
81
+
82
+
83
+ def _edit_action(
84
+ uri: str,
85
+ title: str,
86
+ diagnostic: types.Diagnostic,
87
+ range_: types.Range,
88
+ new_text: str,
89
+ ) -> types.CodeAction:
90
+ return types.CodeAction(
91
+ title=title,
92
+ kind=types.CodeActionKind.QuickFix,
93
+ diagnostics=[diagnostic],
94
+ edit=types.WorkspaceEdit(
95
+ changes={uri: [types.TextEdit(range=range_, new_text=new_text)]}
96
+ ),
97
+ )
98
+
99
+
100
+ def _new_label(source: str, name: str, indent: int) -> str:
101
+ separator = "" if not source or source.endswith("\n") else "\n"
102
+ return f"{separator}\nlabel {name}:\n{' ' * indent}return\n"
103
+
104
+
105
+ def _end_of_document(source: str) -> types.Range:
106
+ normalized = source.replace("\r\n", "\n").replace("\r", "\n")
107
+ lines = normalized.split("\n")
108
+ return types.Range(
109
+ start=types.Position(line=len(lines) - 1, character=utf16_length(lines[-1])),
110
+ end=types.Position(line=len(lines) - 1, character=utf16_length(lines[-1])),
111
+ )
112
+
113
+
114
+ def _text_at(source: str, range_: types.Range) -> str:
115
+ lines = source.replace("\r\n", "\n").replace("\r", "\n").split("\n")
116
+ if range_.start.line != range_.end.line:
117
+ return ""
118
+ if range_.start.line >= len(lines):
119
+ return ""
120
+ return lines[range_.start.line][range_.start.character : range_.end.character]
121
+
122
+
123
+ def _overlaps(left: types.Range, right: types.Range) -> bool:
124
+ return _position(left.start) <= _position(right.end) and _position(
125
+ right.start
126
+ ) <= _position(left.end)
127
+
128
+
129
+ def _position(position: types.Position) -> tuple[int, int]:
130
+ return position.line, position.character