Browse Source
- new commandcomplete.test (6 tests, green 9.0.3 + 8.7): punk::lib::system::incomplete pure-function characterization - the info-complete quoting quirk (a quoted word with unbalanced braces e.g set x "{*}{" is complete standalone but needs extra closers inside a proc body; the pending-opener stack { " { " shrinks per typed closer), single openers, tabs in open braces, escapes, and an incomplete<->info-complete parity property over a case battery
- goals/G-044 detail: the user-specified preserve-list any repl refactor must honour (info-complete parity + quirk, closing-prompt hints incl the accepted single-candidate limitation pinned-not-fixed, raw-mode colour staging in-progress vs submitted, literal tab acceptance with raw-mode marker edit smarts, dim space dots display-only never leaking into submitted strings/history, up/down navigation of MULTILINE editbuf history with recalled entries editable) + testability findings: class_editbuf is console-coupled at its core (add_chunk renders via overtype::renderline against live terminal metrics - cursor-position size probing, DECRQPSR tabstops) so items 3-6 are not unit-characterizable until a console seam exists - G-001 (pluggable console backends / ::opunk::Console test double) is the enabling refactor, not just a feature goal
- goals/G-020 detail: repl interactive-behaviour verification recorded as a driving use case (near-term windows harness: keystroke injection + capture) pending the durable pseudoconsole expect-alternative
Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
4 changed files with 175 additions and 1 deletions
@ -0,0 +1,124 @@ |
|||||||
|
package require tcltest |
||||||
|
|
||||||
|
package require punk::lib |
||||||
|
|
||||||
|
#Characterization of punk::lib::system::incomplete - the repl's command-completeness / |
||||||
|
#continuation engine (added 2026-07-11 at the user's direction, ahead of any repl |
||||||
|
#refactor goals). Given a partial command string it returns the stack of pending |
||||||
|
#"openers" awaiting closure ({} when the command is complete per [info complete]). |
||||||
|
#The repl uses this for: |
||||||
|
# - deciding whether to evaluate or wait for continuation lines (info complete parity, |
||||||
|
# including Tcl's quoting-rules quirk: a quoted word containing unbalanced braces is |
||||||
|
# complete STANDALONE but inside a braced context (e.g a proc body) brace counting |
||||||
|
# applies, so extra closing characters must be typed - surprising but correct Tcl) |
||||||
|
# - the closing-prompt hints in line and raw mode (the stack top is what the >{ / >" |
||||||
|
# continuation hints render). Known, accepted limitation: when more than one closer |
||||||
|
# candidate exists the repl expresses only one - pinned here as current behaviour, |
||||||
|
# not a fix target. |
||||||
|
# |
||||||
|
#These are PURE function tests runnable under plain tclsh. The raw-mode editbuf side |
||||||
|
#(tab ⇥ markers, dim space dots, colour staging, history navigation) is currently |
||||||
|
#console-coupled (class_editbuf add_chunk renders via overtype::renderline against live |
||||||
|
#terminal metrics) and needs a console seam (G-001) or pseudoconsole harness before it |
||||||
|
#can be characterized - see goals/G-044 detail notes. |
||||||
|
# |
||||||
|
#NOTE: the deliberately-unbalanced case strings cannot appear as braced literals in |
||||||
|
#this (or any) tcl file - they are built from escaped fragments. |
||||||
|
|
||||||
|
namespace eval ::testspace { |
||||||
|
namespace import ::tcltest::* |
||||||
|
variable common { |
||||||
|
set result "" |
||||||
|
} |
||||||
|
|
||||||
|
variable Q "\"" |
||||||
|
variable OB "\{" |
||||||
|
variable CB "\}" |
||||||
|
|
||||||
|
#the user-reported scenario: works standalone, needs extra closers inside a proc body |
||||||
|
variable standalone "set x ${Q}${OB}*${CB}${OB}${Q}" |
||||||
|
variable inproc "proc j ${OB}${CB} ${OB}\n set x ${Q}${OB}*${CB}${OB}${Q}" |
||||||
|
|
||||||
|
test commandcomplete_standalone_quoted_braces {a quoted word containing unbalanced braces is a complete command standalone}\ |
||||||
|
-setup $common -body { |
||||||
|
variable standalone |
||||||
|
lappend result [info complete $standalone] |
||||||
|
lappend result [punk::lib::system::incomplete $standalone] |
||||||
|
}\ |
||||||
|
-cleanup { |
||||||
|
}\ |
||||||
|
-result [list 1 {}] |
||||||
|
|
||||||
|
test commandcomplete_inproc_progression {the same line inside a proc body needs extra closers - the pending-opener stack shrinks as each is typed}\ |
||||||
|
-setup $common -body { |
||||||
|
variable inproc |
||||||
|
variable Q |
||||||
|
variable CB |
||||||
|
set s $inproc |
||||||
|
lappend result [info complete $s] [punk::lib::system::incomplete $s] |
||||||
|
append s "\n${CB}" |
||||||
|
lappend result [info complete $s] [punk::lib::system::incomplete $s] |
||||||
|
append s "\n${Q}" |
||||||
|
lappend result [info complete $s] [punk::lib::system::incomplete $s] |
||||||
|
append s "\n${CB}" |
||||||
|
lappend result [info complete $s] [punk::lib::system::incomplete $s] |
||||||
|
}\ |
||||||
|
-cleanup { |
||||||
|
}\ |
||||||
|
-result [list 0 [list \{ \" \{ \"] 0 [list \{ \"] 0 [list \{] 1 {}] |
||||||
|
|
||||||
|
test commandcomplete_single_openers {unterminated quote, brace and bracket each report their single pending opener}\ |
||||||
|
-setup $common -body { |
||||||
|
variable Q |
||||||
|
variable OB |
||||||
|
lappend result [punk::lib::system::incomplete "puts ${Q}hello"] |
||||||
|
lappend result [punk::lib::system::incomplete "puts ${OB}hello"] |
||||||
|
lappend result [punk::lib::system::incomplete "puts \[clock seconds"] |
||||||
|
}\ |
||||||
|
-cleanup { |
||||||
|
}\ |
||||||
|
-result [list [list \"] [list \{] [list \[]] |
||||||
|
|
||||||
|
test commandcomplete_tab_in_open_brace {literal tabs inside an open braced context do not disturb the pending-opener stack}\ |
||||||
|
-setup $common -body { |
||||||
|
variable OB |
||||||
|
lappend result [punk::lib::system::incomplete "set z ${OB}\n line1\ttabbed"] |
||||||
|
}\ |
||||||
|
-cleanup { |
||||||
|
}\ |
||||||
|
-result [list [list \{]] |
||||||
|
|
||||||
|
test commandcomplete_escapes {backslash-escaped braces and quotes do not open/close contexts}\ |
||||||
|
-setup $common -body { |
||||||
|
variable Q |
||||||
|
lappend result [info complete "puts \\${Q}"] [punk::lib::system::incomplete "puts \\${Q}"] |
||||||
|
lappend result [info complete "puts \\\{"] [punk::lib::system::incomplete "puts \\\{"] |
||||||
|
#an escaped quote inside an open quoted word leaves the quote pending |
||||||
|
lappend result [punk::lib::system::incomplete "puts ${Q}a\\${Q}b"] |
||||||
|
}\ |
||||||
|
-cleanup { |
||||||
|
}\ |
||||||
|
-result [list 1 {} 1 {} [list \"]] |
||||||
|
|
||||||
|
test commandcomplete_parity_with_info_complete {incomplete returns the empty list exactly when info complete reports true (property over the case battery)}\ |
||||||
|
-setup $common -body { |
||||||
|
variable Q |
||||||
|
variable OB |
||||||
|
variable CB |
||||||
|
variable standalone |
||||||
|
variable inproc |
||||||
|
set battery [list {puts hello} $standalone $inproc "$inproc\n${CB}" "$inproc\n${CB}\n${Q}" "$inproc\n${CB}\n${Q}\n${CB}" "puts ${Q}hello" "puts ${OB}hello" "puts \[clock seconds" "set z ${OB}\n line1\ttabbed" "puts \\${Q}" "if ${OB}1${CB} ${OB}\n puts ok\n${CB}"] |
||||||
|
set mismatches [list] |
||||||
|
foreach c $battery { |
||||||
|
set emptystack [expr {[llength [punk::lib::system::incomplete $c]] == 0}] |
||||||
|
if {$emptystack != [info complete $c]} { |
||||||
|
lappend mismatches $c |
||||||
|
} |
||||||
|
} |
||||||
|
lappend result $mismatches |
||||||
|
}\ |
||||||
|
-cleanup { |
||||||
|
}\ |
||||||
|
-result [list {}] |
||||||
|
} |
||||||
|
tcltest::cleanupTests ;#needed to produce test summary line. |
||||||
Loading…
Reference in new issue