Skip to content

Commit 9617190

Browse files
authored
Merge pull request #208 from mphe/fix_duplicated_caches
Fix multiple shapes sharing the same mesh cache after duplicate()
2 parents f6968a0 + 8a73fbc commit 9617190

81 files changed

Lines changed: 979 additions & 1877 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

addons/diagnosticlist/Diagnostic.gd

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,3 @@ func get_filename() -> StringName:
3030
if _filename.is_empty():
3131
_filename = StringName(res_uri.get_file())
3232
return _filename
33-
34-
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
uid://iepkcjoev3la
1+
uid://o35ee3po5en8

addons/diagnosticlist/DiagnosticProvider.gd

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ func refresh_diagnostics(force: bool = false) -> bool:
6666
# NOTE: We always have to do a full update, because a change in one file can cause errors in
6767
# other files, e.g. renaming an identifier.
6868

69+
DiagnosticList_Utils.log_debug("Provider: refresh_diagnostics()")
70+
6971
# Still waiting for results from the last call
7072
if _num_outstanding > 0:
7173
_dirty = false # Dirty will be reset anyway after update has been finished
@@ -125,6 +127,7 @@ func refresh_file_list() -> bool:
125127
cache.last_modified = last_modified
126128
cache.content = FileAccess.get_file_as_string(path)
127129
modified = true
130+
DiagnosticList_Utils.log_debug("Provider: file modification detected: %s" % path)
128131

129132
# One or more files were deleted
130133
if _file_cache.size() > _script_paths.size():
@@ -134,6 +137,7 @@ func refresh_file_list() -> bool:
134137
for path: String in _file_cache.keys():
135138
if not _script_paths.has(path):
136139
_file_cache.erase(path)
140+
DiagnosticList_Utils.log_debug("Provider: file deleted: %s" % path)
137141

138142
return modified
139143

@@ -143,8 +147,12 @@ func get_diagnostic_count(severity: DiagnosticList_Diagnostic.Severity) -> int:
143147
return _counts[severity]
144148

145149

146-
## Returns all diagnostics of the project
150+
## Returns all diagnostics of the project.
151+
## The list of diagnostics is grouped by file, i.e. all diagnostics belonging to the same file are
152+
## consecutive elements.
147153
func get_diagnostics() -> Array[DiagnosticList_Diagnostic]:
154+
# NOTE: The LSP server usually publishes diagnostics consecutively per file and not in random
155+
# order. Hence we do not need additional sorting to fulfill the contract of this method.
148156
return _diagnostics.duplicate()
149157

150158

@@ -191,6 +199,7 @@ func _mark_dirty() -> void:
191199

192200
func _on_sources_changed(_exist: bool) -> void:
193201
_mark_dirty()
202+
DiagnosticList_Utils.log_debug("Provider: on_sources_changed")
194203

195204

196205
func _on_script_classes_updated() -> void:
@@ -209,12 +218,13 @@ func _on_script_classes_updated() -> void:
209218
# Hence, when the signal arrives and the Godot window has focus, an update should be performed.
210219
if EditorInterface.get_base_control().get_window().has_focus():
211220
_mark_dirty()
221+
DiagnosticList_Utils.log_debug("Provider: on_script_classes_updated")
212222

213223

214224
func _on_publish_diagnostics(diagnostics: DiagnosticList_Diagnostic.Pack) -> void:
215225
# Ignore unexpected diagnostic updates
216226
if _num_outstanding == 0:
217-
_client.log_error("Received diagnostics without having them requested before")
227+
DiagnosticList_Utils.log_error("Received diagnostics without having them requested before")
218228
return
219229

220230
_diagnostics.append_array(diagnostics.diagnostics)
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
uid://c0fhe5ubxdqdu
1+
uid://dghjmk3ev0o15

addons/diagnosticlist/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Marvin Ewald
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

addons/diagnosticlist/LSPClient.gd

Lines changed: 45 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ signal on_publish_diagnostics(diagnostics: DiagnosticList_Diagnostic.Pack)
1414
signal on_jsonrpc_error(error: Dictionary)
1515

1616

17-
const ENABLE_DEBUG_LOG: bool = false
1817
const TICK_INTERVAL_SECONDS_MIN: float = 0.05
1918
const TICK_INTERVAL_SECONDS_MAX: float = 30.0
2019

@@ -26,7 +25,14 @@ var _jsonrpc := JSONRPC.new()
2625
var _client := StreamPeerTCP.new()
2726
var _id: int = 0
2827
var _timer: Timer
29-
var _lsp_project_path: String = "" # Absolute project path reported by LS
28+
29+
## Absolute project path reported by LS.
30+
## Will be initialized when the LSP connection is initialized ( _initialize()) and changed by
31+
## changeWorkspace events.
32+
var _ls_project_path: String = ""
33+
34+
## Absolute path of the loaded project.
35+
var _project_path: String = ProjectSettings.globalize_path("res://").simplify_path()
3036

3137

3238
func _init(root: Node) -> void:
@@ -41,7 +47,7 @@ func _init(root: Node) -> void:
4147

4248

4349
func disconnect_lsp() -> void:
44-
log_debug("Disconnecting from LSP")
50+
DiagnosticList_Utils.log_debug("Disconnecting from LSP")
4551
_timer.stop()
4652
_client.disconnect_from_host()
4753

@@ -56,10 +62,11 @@ func connect_lsp() -> bool:
5662

5763
## Connect to the LSP server at the given host and port.
5864
func connect_lsp_at(host: String, port: int) -> bool:
65+
DiagnosticList_Utils.log_debug("Connecting to LSP at %s:%d" % [ host, port ])
5966
var err := _client.connect_to_host(host, port)
6067

6168
if err != OK:
62-
log_error("Failed to connect to LSP server: %s" % err)
69+
DiagnosticList_Utils.log_error("Failed to connect to LSP server: %s" % err)
6370
return false
6471

6572
# Enable processing
@@ -96,9 +103,11 @@ func update_diagnostics(res_path: String, content: String) -> void:
96103
})
97104

98105

99-
## Returns the absolute project path as reported by the LS.
100-
func get_project_path() -> String:
101-
return _lsp_project_path
106+
## Returns whether the root directory reported by the LS is the same as the project root.
107+
## If there is a mismatch, the LSP client is very likely connected to a different Godot instance
108+
## with a different project opened.
109+
func lsp_root_matches_project_root() -> bool:
110+
return _ls_project_path == _project_path
102111

103112

104113
func _reset_tick_interval() -> void:
@@ -118,10 +127,11 @@ func _on_tick() -> void:
118127
_update_tick_interval()
119128

120129
while _client.get_available_bytes():
130+
DiagnosticList_Utils.log_debug("Bytes available: %d" % _client.get_available_bytes())
121131
var json := _read_data()
122132

123133
if json:
124-
log_debug("Received message:\n%s" % json)
134+
DiagnosticList_Utils.log_debug("Received message:\n%s" % json)
125135

126136
_handle_response(json)
127137
_reset_tick_interval() # Reset timer interval whenever data arrived as there will likely be more data coming
@@ -139,14 +149,14 @@ func _update_status() -> bool:
139149
StreamPeerTCP.STATUS_NONE:
140150
return false
141151
StreamPeerTCP.STATUS_ERROR:
142-
log_error("StreamPeerTCP error")
152+
DiagnosticList_Utils.log_error("StreamPeerTCP error")
143153
return false
144154
StreamPeerTCP.STATUS_CONNECTING:
145155
pass
146156
StreamPeerTCP.STATUS_CONNECTED:
147157
# First time connected -> run initialization
148158
if last_status != status:
149-
log_debug("Connected to LSP")
159+
DiagnosticList_Utils.log_debug("Connected to LSP")
150160
on_connected.emit()
151161
_initialize()
152162

@@ -166,7 +176,7 @@ func _read_data() -> Dictionary:
166176
var json: Dictionary = JSON.parse_string(content)
167177

168178
if not json:
169-
log_error("Failed to parse JSON: %s" % content)
179+
DiagnosticList_Utils.log_error("Failed to parse JSON: %s" % content)
170180
return {}
171181

172182
return json
@@ -176,14 +186,16 @@ func _read_content(length: int) -> String:
176186
var data := _client.get_data(length)
177187

178188
if data[0] != OK:
179-
log_error("Failed to read content: %s" % error_string(data[0]))
189+
DiagnosticList_Utils.log_error("Failed to read content: %s" % error_string(data[0]))
180190
return ""
181191
else:
182192
var buf: PackedByteArray = data[1]
183193
return buf.get_string_from_utf8()
184194

185195

186196
func _read_header() -> String:
197+
DiagnosticList_Utils.log_debug("reading header")
198+
187199
var buf := PackedByteArray()
188200
var char_r := "\r".unicode_at(0)
189201
var char_n := "\n".unicode_at(0)
@@ -192,7 +204,7 @@ func _read_header() -> String:
192204
var data := _client.get_data(1)
193205

194206
if data[0] != OK:
195-
log_error("Failed to read header: %s" % error_string(data[0]))
207+
DiagnosticList_Utils.log_error("Failed to read header: %s" % error_string(data[0]))
196208
return ""
197209
else:
198210
buf.push_back(data[1][0])
@@ -221,20 +233,22 @@ func _handle_response(json: Dictionary) -> void:
221233

222234
# Project path
223235
"gdscript_client/changeWorkspace":
224-
_lsp_project_path = str(json["params"]["path"]).simplify_path()
236+
_ls_project_path = str(json["params"]["path"]).simplify_path()
237+
DiagnosticList_Utils.log_debug("Change Workspace: %s" % _ls_project_path)
225238
return
226239

227240
# Initialization response
228241
if json.get("id") == 0:
242+
DiagnosticList_Utils.log_debug("LSP initialized")
229243
_send_notification("initialized", {})
230244
on_initialized.emit()
231245
return
232246

233247
# JSON-RPC error
234248
if json.has("error"):
235249
var error: Dictionary = json["error"]
236-
log_error("JSON-RPC Error: %s" % error)
237-
log_error("This is likely a bug in the plugin. Consider submitting a bug report on GitHub.")
250+
DiagnosticList_Utils.log_error("JSON-RPC Error: %s" % error)
251+
DiagnosticList_Utils.log_error("This is likely a bug in the plugin. Consider submitting a bug report on GitHub.")
238252
on_jsonrpc_error.emit(error)
239253

240254

@@ -275,14 +289,24 @@ func _send(json: Dictionary) -> void:
275289
var content_bytes := content.to_utf8_buffer()
276290
var header := "Content-Length: %s\r\n\r\n" % len(content_bytes)
277291
var header_bytes := header.to_ascii_buffer()
278-
log_debug("Sending message (length: %s): %s" % [ len(content_bytes), content ])
279-
_client.put_data(header_bytes + content_bytes)
292+
DiagnosticList_Utils.log_debug("Sending message (length: %s): %s" % [ len(content_bytes), content ])
293+
var err := _client.put_data(header_bytes + content_bytes)
294+
295+
if err != OK:
296+
DiagnosticList_Utils.log_error("Failed to send: %s" % error_string(err))
297+
280298
_reset_tick_interval() # Reset the timer interval because we are expecting a response
281299

282300

283301
func _initialize() -> void:
302+
# Comply with LSP, try to initialize root directory to the current project root.
303+
# Godot will likely ignore it and send a changeWorkspace event anyway.
304+
_ls_project_path = _project_path
305+
284306
_send_request("initialize", {
285307
"processId": null,
308+
"rootPath": _ls_project_path,
309+
"rootUri": _res_path_to_lsp_uri("res://"),
286310
"capabilities": {
287311
"textDocument": {
288312
"publishDiagnostics": {},
@@ -292,16 +316,10 @@ func _initialize() -> void:
292316

293317

294318
func _res_path_to_lsp_uri(res_path: String) -> String:
319+
# NOTE: No need to manually call uri_encode() as JSONRPC seems to do that automatically
320+
# TODO: Consider using the builtin parsing functionality of JSONRPC instead of doing it manually
295321
return URI_PREFIX + ProjectSettings.globalize_path(res_path).simplify_path()
296322

297323

298324
func _lsp_uri_to_res_path(lsp_uri: String) -> String:
299-
return ProjectSettings.localize_path(lsp_uri.replace(URI_PREFIX, ""))
300-
301-
302-
func log_debug(text: String) -> void:
303-
if ENABLE_DEBUG_LOG:
304-
print("[DiagnosticList] ", text)
305-
306-
func log_error(text: String) -> void:
307-
push_error("[DiagnosticList] ", text)
325+
return ProjectSettings.localize_path(lsp_uri.trim_prefix(URI_PREFIX).uri_decode())
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
uid://dijchaojix40h
1+
uid://ppx5ro6gy6ro

addons/diagnosticlist/Panel.gd

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ var _provider: DiagnosticList_DiagnosticProvider
4444
## Alternative to _ready(). This will be called by plugin.gd to ensure the code in here only runs
4545
## when this script is loaded as part of the plugin and not while editing the scene.
4646
func _plugin_ready() -> void:
47+
DiagnosticList_Utils.log_debug("Panel _plugin_ready()")
48+
4749
for i in len(_filter_buttons):
4850
var btn: Button = _filter_buttons[i]
4951
var severity := _severity_settings[i]
@@ -85,6 +87,8 @@ func _plugin_ready() -> void:
8587

8688
## Called by plugin.gd when the LSPClient is ready
8789
func start(provider: DiagnosticList_DiagnosticProvider) -> void:
90+
DiagnosticList_Utils.log_debug("Panel start()")
91+
8892
_provider = provider
8993

9094
# Now that it is safe to do stuff, connect all the signals
@@ -104,18 +108,19 @@ func start(provider: DiagnosticList_DiagnosticProvider) -> void:
104108
_start_stop_auto_refresh()
105109

106110
# If connected to a LS of a different Godot instance, show a warning
107-
if provider.get_lsp_client().get_project_path() != ProjectSettings.globalize_path("res://").simplify_path():
111+
if not provider.get_lsp_client().lsp_root_matches_project_root():
108112
_multiple_instances_alert.popup_centered()
109113

110114

111115
func refresh() -> void:
112-
# NOTE: This list is sorted by file name as LSP publishes diagnostics per file
113-
# This is important as the group-by-file implementation relies on it.
116+
DiagnosticList_Utils.log_debug("Panel refresh()")
117+
118+
# NOTE: This list is grouped by file name. This is important as the group-by-file implementation relies on it.
114119
var diagnostics := _provider.get_diagnostics()
115120
var group_by_file := _cb_group_by_file.button_pressed
116121

117122
if not group_by_file:
118-
diagnostics.sort_custom(_sort_by_severity)
123+
diagnostics.sort_custom(DiagnosticList_Utils.sort_by_severity)
119124

120125
# Show refresh time
121126
_set_status_string("Up-to-date", true)
@@ -154,12 +159,6 @@ func _set_status_string(text: String, with_last_time: bool) -> void:
154159
_label_refresh_time.text = text
155160

156161

157-
func _sort_by_severity(a: DiagnosticList_Diagnostic, b: DiagnosticList_Diagnostic) -> bool:
158-
if a.severity == b.severity:
159-
return a.res_uri < b.res_uri
160-
return a.severity < b.severity
161-
162-
163162
func _create_entry(diag: DiagnosticList_Diagnostic, parent: TreeItem) -> void:
164163
var entry: TreeItem = _error_list_tree.create_item(parent)
165164
var severity_setting := _severity_settings[diag.severity]
@@ -174,6 +173,8 @@ func _create_entry(diag: DiagnosticList_Diagnostic, parent: TreeItem) -> void:
174173

175174

176175
func _update_diagnostics(force: bool) -> void:
176+
DiagnosticList_Utils.log_debug("Panel _update_diagnostics()")
177+
177178
if _provider.is_updating() or _provider.refresh_diagnostics(force):
178179
_set_status_string("Updating...", false)
179180
else:

addons/diagnosticlist/Panel.gd.uid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
uid://btyk17v3aai46
1+
uid://b3dpnradvv4q5

addons/diagnosticlist/Panel.tscn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[gd_scene load_steps=2 format=3 uid="uid://tsfsnxbfcax6"]
22

3-
[ext_resource type="Script" uid="uid://btyk17v3aai46" path="res://addons/diagnosticlist/Panel.gd" id="1_fewy8"]
3+
[ext_resource type="Script" uid="uid://b3dpnradvv4q5" path="res://addons/diagnosticlist/Panel.gd" id="1_fewy8"]
44

55
[node name="DiagnosticsPanel" type="Control"]
66
custom_minimum_size = Vector2(250, 225)
@@ -42,8 +42,8 @@ text = "Auto-Refresh"
4242

4343
[node name="btn_refresh_errors" type="Button" parent="HBoxContainer/VBoxContainer"]
4444
unique_name_in_owner = true
45+
auto_translate_mode = 2
4546
layout_mode = 2
46-
auto_translate = false
4747
text = "Refresh"
4848

4949
[node name="HSeparator" type="HSeparator" parent="HBoxContainer/VBoxContainer"]

0 commit comments

Comments
 (0)