Skip to content

Commit de2bd5f

Browse files
fix indentation
1 parent 1517c9c commit de2bd5f

4 files changed

Lines changed: 97 additions & 16 deletions

File tree

.github/workflows/pre-commit.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Pre-commit Checks
1+
# name: Pre-commit Checks
22

33
on:
44
push:

gdrepl/client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class client:
99
def __init__(self, host=HOST, port=PORT):
1010
try:
11-
self.ws = create_connection(f"ws://{host}:{port}", timeout=10)
11+
self.ws = create_connection(f"ws://{host}:{port}", timeout=30)
1212
except ConnectionRefusedError:
1313
print("Could not connect to server")
1414
exit(1)
@@ -27,7 +27,7 @@ def send(self, msg: str, get_response=True) -> str:
2727
try:
2828
resp = self.ws.recv()
2929
except WebSocketTimeoutException:
30-
return "Error: Server timeout (took longer than 10 seconds to respond)"
30+
return "Error: Server timeout (took longer than 30 seconds to respond)"
3131

3232
if isinstance(resp, bytes):
3333
resp = resp.decode()

gdrepl/gdserverv4.gd

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -114,17 +114,21 @@ class Session:
114114
var has_keyword = check_scope(line, i)
115115
var line_stripped = line.strip_edges()
116116

117-
# Skip print statements from previous executions to avoid repeated output
117+
# Replace print statements from previous executions with pass to avoid repeated output
118+
# while keeping control structure bodies valid
118119
var is_print_call = line_stripped.begins_with("print(") or line_stripped.begins_with("printerr(")
119-
if is_print_call:
120-
i += 1
121-
continue
122120

123121
# Inject stdout marker at the last scope index
124122
if i == last_index:
125123
var identation = " ".repeat(len(line.rstrip(" ")) - len(line.rstrip(" ").lstrip(" ")))
126124
_local += " " + identation + "print(\"" + STDOUT_MARKER_START + "\")" + "\n"
127-
_local += " " + line + "\n"
125+
126+
if is_print_call:
127+
# Replace with pass to keep control structures valid
128+
var indentation = " ".repeat(len(line) - len(line.lstrip(" \t")))
129+
_local += " " + indentation + "pass\n"
130+
else:
131+
_local += " " + line + "\n"
128132

129133
i += 1
130134

@@ -179,6 +183,55 @@ func print_script(script, session):
179183
print(script.source_code)
180184
print("-----------------------------------\n")
181185

186+
func needs_return(code: String) -> bool:
187+
# Smart return detection to avoid double script reload
188+
# Returns true if the last line is an expression that needs a return statement
189+
190+
if code.strip_edges().is_empty():
191+
return false
192+
193+
var lines = code.strip_edges().split("\n")
194+
var last_line = lines[-1].strip_edges()
195+
196+
# Empty line
197+
if last_line.is_empty():
198+
return false
199+
200+
# Lines ending with : are control flow statements (if, for, while, func, etc.)
201+
if last_line.ends_with(":"):
202+
return false
203+
204+
# Variable or constant declarations
205+
if last_line.begins_with("var ") or last_line.begins_with("const "):
206+
return false
207+
208+
# Control flow keywords
209+
var first_word = last_line.split(" ")[0].strip_edges()
210+
if first_word in keywords_local:
211+
return false
212+
213+
# Global scope keywords (func, class, etc.)
214+
if first_word in keywords_global:
215+
return false
216+
217+
# Continuation of previous line (indented)
218+
if lines[-1].begins_with(" ") or lines[-1].begins_with("\t"):
219+
return false
220+
221+
# Assignment detection using regex (better than string search)
222+
var regex = RegEx.new()
223+
# Match: word = value (but not ==, !=, <=, >=)
224+
regex.compile("^\\w+\\s*=\\s*[^=]")
225+
if regex.search(last_line):
226+
return false
227+
228+
# Known void function calls
229+
if last_line.begins_with("print(") or last_line.begins_with("printerr("):
230+
return false
231+
232+
# Default: assume it's an expression that needs return
233+
return true
234+
182235
func add_code(code: String, session: String = "main"):
183236
# Switch to global scope on keywords_global
184237
if code != main and code.strip_edges().split(" ")[0] in keywords_global:
@@ -217,19 +270,18 @@ func exec(input: String, session: String = "main") -> String:
217270
sessions[session].scope = Scope.Local
218271
return ""
219272

273+
# Smart detection: determine if we need return BEFORE compiling
274+
var use_return = needs_return(sessions[session].local)
275+
220276
var script = GDScript.new()
221-
script.source_code = sessions[session].code(true)
277+
script.source_code = sessions[session].code(use_return)
222278
print_script(script, session)
223279

280+
# Single reload with smart detection
224281
var err = script.reload()
225282
if err != OK:
226-
# Retry without return (handles void-returning functions like print())
227-
script.source_code = sessions[session].code(false)
228-
print_script(script, session)
229-
err = script.reload()
230-
if err != OK:
231-
sessions[session].dellast_local()
232-
return "Err: " + str(err)
283+
sessions[session].dellast_local()
284+
return "Err: " + str(err)
233285

234286
var obj = RefCounted.new()
235287
obj.set_script(script)

tests/test_e2e.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,35 @@ def test_no_repeated_output(self, repl):
217217
# Check that unique_test_string is NOT in the output we just received
218218
assert "unique_test_string" not in repl.before, "Print statement should not repeat"
219219

220+
def test_code_after_loop_execution(self, repl):
221+
"""Test that code can be executed after a for loop completes."""
222+
# Execute a for loop with print
223+
repl.sendline("for i in range(3):")
224+
repl.expect(r"\.\.\.", timeout=10)
225+
226+
repl.sendline(" print(i)")
227+
repl.expect(r"\.\.\.", timeout=10)
228+
229+
# Send empty line to finish the loop
230+
repl.sendline("")
231+
232+
# Should see output from the loop
233+
repl.expect("0", timeout=10)
234+
repl.expect("1", timeout=10)
235+
repl.expect("2", timeout=10)
236+
repl.expect(">>>", timeout=10)
237+
238+
# Now execute code after the loop - this should NOT fail with
239+
# "Expected indented block after 'for' block" error
240+
repl.sendline("42")
241+
repl.expect(r"-> 42", timeout=10)
242+
repl.expect(">>>", timeout=10)
243+
244+
# Try another expression to make sure state is clean
245+
repl.sendline("100 + 23")
246+
repl.expect(r"-> 123", timeout=10)
247+
repl.expect(">>>", timeout=10)
248+
220249

221250
@pytest.mark.slow
222251
class TestREPLPersistence:

0 commit comments

Comments
 (0)