Browse Source

punk::repl 0.4.0: launch-time console selection (G-001)

repl::init -console <spec> selects the console the repl reads/writes (any
punk::console::console_spec_resolve form); repl::start's inchan is now
optional, defaulting to the selected console's input. Per-repl channel state
(conin/conout/conerr) routes rputs (stdout/stderr mapped per-repl) and
doprompt; for a foreign console the code interp's stdout/stderr are diverted
via shellfilter 'var' junction stacks and emitted to the console after each
run (repltype punk/0). New helpers console_is_default/console_at_eof/
console_get_size dispatch eof/size to the selected ::opunk::Console object's
(possibly overridden) methods. Process-console behaviours (tcl_interactive
prompt gating, stdin reopen on eof, raw-mode re-enable, windows utf-16be
line re-decode experiment, mode-line on exit) now apply only to the default
console. Default stdin/stdout behaviour unchanged. Also fixes rputs pseudo-
channel mapping in the 3-arg -nonewline form (mapped value previously
written over the -nonewline flag).

Assisted-by: harness=claude; primary-model=claude-fable-5; api-location=anthropic.com
master
Julian Noble 4 days ago
parent
commit
ab75a78b06
  1. 1
      src/modules/punk/AGENTS.md
  2. 282
      src/modules/punk/repl-999999.0a1.0.tm
  3. 3
      src/modules/punk/repl-buildversion.txt

1
src/modules/punk/AGENTS.md

@ -28,6 +28,7 @@ Source of truth for all modules under the `punk::*` namespace. This is the prima
## Work Guidance
- New modules under `punk::*` should be created as `<subpath>/<modulename>-999999.0a1.0.tm` following the namespace-to-path convention.
- punk::repl supports launch-time console selection (G-001): `repl::init -console <spec>` (any `punk::console::console_spec_resolve` spec form) selects the console the repl reads/writes; `repl::start`'s input channel argument is optional and defaults to the selected console's input. Repl output flows through per-repl channel state (`repl::conin/conout/conerr` - rputs maps stdout/stderr per-repl, conerr==conout for a foreign console pending G-011), the code interp's stdout/stderr are diverted via shellfilter `var` junction stacks and emitted to the console after each run (repltype punk/0 only so far), and eof/size/capability questions go through `repl::console_at_eof`/`repl::console_get_size` which dispatch to the selected `::opunk::Console` object's (possibly overridden) methods. Process-console behaviours (tcl_interactive prompt gating, stdin reopen on eof, raw-mode re-enable) apply only when no foreign console is selected. Tests: `src/tests/modules/punk/repl/testsuites/repl/consolebackends.test` (child-process drivers - a repl cannot run inside the shared testinterp; see the suite header).
- punk::console uses the documented `-console` convention throughout: a `-console` value may be a 2-element {in out} channel list, an anchored `opunk::console` instance name, or an `::opunk::Console` object value (resolved via `punk::console::console_spec_resolve`). Query functions use the hybrid pattern (legacy trailing positional spec also accepted, parsed by `punk::console::internal::hybrid_console_spec`) - new query procs must follow it, with tests (see `src/tests/modules/punk/console/testsuites/console/queryprocs.test`). PUNKARGS definitions include the `-console` option via the shared fragments `::punk::console::argdoc::console_opts` (query/set functions) or `::punk::console::argdoc::console_emit_opts` (emit functions) rather than duplicating the option text; never re-add a `-minsize 2` constraint to `-console` (it rejects instance-name specs). The internal `get_size_using_*` size mechanisms deliberately remain canonical-pair positional (always fed by `get_size`).
- punk::console emit-side functions (the `punk::console::ansi::*` emit wrappers, mouse/paste toggles, `vt52`, `set_tabstop_width`, `titleset`, top-level `move`, and the width-test probes) accept an optional trailing `-console <consolespec>` pair, parsed manually for performance by `punk::console::internal::opt_console_out`/`opt_console_channels` (`_var` variants for procs whose args-tail also carries row/col/data triples). Each carries a documentation-only PUNKARGS definition that includes the shared `::punk::console::argdoc::console_emit_opts` fragment via `punk::args::resolved_def`; keep manual parsing and PUNKARGS synchronized. New emit procs must follow this pattern. Tests live in `src/tests/modules/punk/console/testsuites/console/emitconsole.test`.
- punk::console terminal-property facts (is_vt52, tabwidth, cell_size, last_da1_result, grapheme_cluster_support, check::has_bug_*) are per-console: read/write them via `punk::console::console_fact_get`/`console_fact_set`, keyed by canonical {in out} channel pair. The store is tsv-backed (G-007) so all threads read the same values: the process-default console `{stdin stdout}` keeps the legacy namespace variables (`::punk::console::is_vt52`, `tabwidth`, ...) as its authoritative local storage with write traces mirroring into tsv `punk_console_facts` (so existing external readers and direct writers keep working); non-default consoles store facts only in tsv with an owner-qualified key. Do not bypass the helpers for non-default consoles; use `console_fact_clear` (not direct store manipulation) to reset facts in tests. `ansi_wanted`/`colour_disabled` (string-generation gates), `ansi_available` and raw-mode state are deliberately process-global (rationale documented at the fact store in the module). Tests live in `src/tests/modules/punk/console/testsuites/console/consolefacts.test`.

282
src/modules/punk/repl-999999.0a1.0.tm

@ -157,6 +157,29 @@ namespace eval repl {
}
variable codethread_cond
# -- G-001 selected console --
#repl_console: the ::opunk::Console (subclass) object value selected via 'repl::init -console <spec>',
#or "" when the repl runs on the process-default console (legacy stdin/stdout/stderr behaviour).
#conin/conout/conerr: the channels this repl reads from and writes to. For a selected foreign console,
#conin/conout come from the console's in/out slots and conerr is the same channel as conout
#(a single terminal stream - optional per-console err channels are G-011's concern, not G-001's).
variable repl_console
if {![info exists repl_console]} {
set repl_console ""
}
variable conin
if {![info exists conin]} {
set conin stdin
}
variable conout
if {![info exists conout]} {
set conout stdout
}
variable conerr
if {![info exists conerr]} {
set conerr stderr
}
variable screen_last_chars "" ;#a small sliding append buffer for last char of any screen output to detect \n vs string
variable screen_last_char_list [list]
@ -473,11 +496,20 @@ proc punk::repl::get_prompt_config {} {
return [list resultprompt $resultprompt nlprompt $nlprompt infoprompt $infoprompt debugprompt $debugprompt]
}
proc repl::start {inchan args} {
proc repl::start {args} {
#debug only - we need clean output for 'exec' to succeed without forcing use of -ignorestderr.
#puts stderr "-->repl::start $inchan $args"
#puts stderr "-->repl::start $args"
#flush stderr
#G-001: inchan is optional - when omitted (or the args begin with an option) the input
#defaults to the console selected at repl::init (conin - process stdin when no -console given).
variable conin
if {[llength $args] && ![string match -* [lindex $args 0]]} {
set args [lassign $args inchan]
} else {
set inchan $conin
}
upvar ::punk::console::input_chunks_waiting input_chunks_waiting
if {![info exists input_chunks_waiting($inchan)]} {
set input_chunks_waiting($inchan) [list]
@ -564,7 +596,13 @@ proc repl::start {inchan args} {
# ---
if {$::punk::console::ansi_wanted == 2} {
if {[::punk::console::test_can_ansi]} {
variable repl_console
if {![console_is_default] && $repl_console ne ""} {
#foreign console: never emit a probe to the process console - settle from the
#console object's (possibly overridden) can_respond.
#(ansi_wanted is deliberately process-global - scoped console state is G-008)
set ::punk::console::ansi_wanted [expr {[::opunk::Console::can_respond $repl_console] ? 1 : -1}]
} elseif {[::punk::console::test_can_ansi]} {
set ::punk::console::ansi_wanted 1
} else {
set ::punk::console::ansi_wanted -1
@ -629,7 +667,9 @@ proc repl::start {inchan args} {
thread::cond destroy $codethread_cond ;#race if we destroy cond before child thread has exited - as it can send a -async quit
set codethread ""
set codethread_cond ""
if {[console_is_default]} {
punk::console::mode line ;#review - revert to line mode on final exit - but we may be exiting a nested repl
}
set donevalue [set [namespace current]::done]
#e.g
# "eof stdin"
@ -845,13 +885,86 @@ proc repl::newout2 {} {
}
#--------------------------------------
# -- G-001 selected-console helpers --
namespace eval repl::argdoc {
lappend PUNKARGS [list {
@id -id ::repl::console_is_default
@cmd -name "repl::console_is_default"\
-summary\
"Whether this repl runs on the process-default console."\
-help\
"Returns 1 when no foreign console was selected at repl::init
(conin/conout are the process stdin/stdout), 0 when the repl
reads/writes a selected ::opunk::Console backend's channels.
Legacy process-console behaviours (prompt gating on
tcl_interactive, stdin reopen on eof, raw-mode re-enable)
apply only when this returns 1."
@values -min 0 -max 0
}]
}
proc repl::console_is_default {} {
variable conin
variable conout
expr {$conin eq "stdin" && $conout eq "stdout"}
}
namespace eval repl::argdoc {
lappend PUNKARGS [list {
@id -id ::repl::console_at_eof
@cmd -name "repl::console_at_eof"\
-summary\
"eof state of the repl input, answered by the selected console object when present."\
-help\
"For a repl started with a selected ::opunk::Console backend this dispatches
to the console object's (possibly overridden) at_eof method - e.g a tk-widget
backend answers from its backend eof marker rather than any channel state.
Otherwise (or for a non-console input channel) plain chan eof is used."
@values -min 1 -max 1
inputchan -type string -help\
"the repl input channel being read"
}]
}
proc repl::console_at_eof {inputchan} {
variable repl_console
variable conin
if {$repl_console ne "" && $inputchan eq $conin} {
return [::opunk::Console::at_eof $repl_console]
}
return [chan eof $inputchan]
}
namespace eval repl::argdoc {
lappend PUNKARGS [list {
@id -id ::repl::console_get_size
@cmd -name "repl::console_get_size"\
-summary\
"Console size for this repl - selected console object when present, else punk::console::get_size."\
-help\
"Returns a dict with keys columns and rows. A selected ::opunk::Console
backend answers via its (possibly overridden) size method; the default
console uses punk::console::get_size."
@values -min 0 -max 0
}]
}
proc repl::console_get_size {} {
variable repl_console
if {$repl_console ne ""} {
return [::opunk::Console::size $repl_console]
}
return [punk::console::get_size]
}
proc repl::doprompt {prompt {col {green bold}}} {
#prompt to stderr.
#prompt to stderr (conerr - same channel as conout for a selected foreign console).
#We can pipe commands into repl's stdin without the prompt interfering with the output.
#Although all command output for each line goes to stdout - not just what is emitted with puts
if {$::tcl_interactive} {
flush stdout; #we are writing this prompt on stderr, but stdout could still be writing to screen
variable conout
variable conerr
#G-001: a selected foreign console is a terminal by declaration (constructed knowing its role),
#so prompts are wanted regardless of the process-level tcl_interactive state.
if {$::tcl_interactive || ![console_is_default]} {
flush $conout; #we are writing this prompt on conerr, but conout could still be writing to screen
#our first char on stderr is based on the 'lastchar' of stdout which we have recorded but may not have arrived on screen.
#The issue we're trying to avoid is the (stderr)prompt arriving midway through a large stdout chunk
#REVIEW - this basic attempt to get stderr/stdout to cooperate is experimental and unlikely to achieve the desired effect in all situations
@ -895,9 +1008,9 @@ proc repl::doprompt {prompt {col {green bold}}} {
set o [a {*}$col]
set r [a]
puts -nonewline stderr $c$pre$o$prompt$r
puts -nonewline $conerr $c$pre$o$prompt$r
screen_last_char_add " " "prompt-stderr" prompt
flush stderr
flush $conerr
}
}
@ -910,11 +1023,13 @@ proc repl::rputs {args} {
variable screen_last_chars
variable last_out_was_newline
variable last_repl_char
variable conout
variable conerr
set pseudo_map [dict create {*}{
debug stderr
debugreport stderr
}]
#map pseudo-channels - and, for a selected foreign console (G-001), the std channel
#names - to this repl's console channels. Identity mapping for stdout/stderr when
#running on the process-default console.
set pseudo_map [dict create debug $conerr debugreport $conerr stdout $conout stderr $conerr]
if {[::tcl::mathop::<= 1 [llength $args] 3]} {
set out [lindex $args end]
@ -922,20 +1037,28 @@ proc repl::rputs {args} {
if {([llength $args] > 1) && [lindex $args 0] ne "-nonewline"} {
set this_tail \n
set rputschan [lindex $args 0]
#map pseudo-channels to real
if {$rputschan in [dict keys $pseudo_map]} {
#map pseudo/std channels to this repl's console channels
if {[dict exists $pseudo_map $rputschan]} {
lset args 0 [dict get $pseudo_map $rputschan]
}
} elseif {[llength $args] == 1} {
set this_tail \n
set rputschan "stdout"
#implicit stdout - make the channel explicit so a selected console receives it
set args [list $conout $out]
} else {
#>1 arg with -nonewline
#first arg is -nonewline
set this_tail [string index $out end]
if {[llength $args] == 3} {
set rputschan [lindex $args 1]
#map pseudo-channels to real
if {$rputschan in [dict keys $pseudo_map]} {
lset args 0 [dict get $pseudo_map $rputschan]
#map pseudo/std channels to this repl's console channels
if {[dict exists $pseudo_map $rputschan]} {
lset args 1 [dict get $pseudo_map $rputschan]
}
} else {
#2 args: -nonewline <data> - implicit stdout
set rputschan "stdout"
set args [list -nonewline $conout $out]
}
}
set last_char_info_width 60
@ -961,7 +1084,7 @@ proc repl::rputs {args} {
#set x \ud83c\udf1e
#(2 surrogate pairs - treated as single char in tcl8 - fixed in 9 but won't/can't be backported) -
#see also: https://core.tcl-lang.org/tips/doc/trunk/tip/619.md
puts stderr "$repl_error"
puts $conerr "$repl_error"
}
} else {
#looks like an invalid puts call - use the normal error produced by the puts command
@ -980,7 +1103,7 @@ proc repl::rputs {args} {
} else {
set clear "\n"
}
puts -nonewline stderr "$clear[a red bold]! REPL ERROR IN rputs $c$err$n\n"
puts -nonewline $conerr "$clear[a red bold]! REPL ERROR IN rputs $c$err$n\n"
screen_last_char_add "\n" replerror "rputs err: '$err'"
return
} else {
@ -1898,7 +2021,7 @@ proc repl::repl_handler {inputchan readmore prompt_config} {
}
if {$readmore} {
if {![chan eof $inputchan]} {
if {![console_at_eof $inputchan]} {
##################################################################################
#Re-enable channel read handler only if no waiting chunks - must process in order
##################################################################################
@ -1941,7 +2064,9 @@ proc repl::repl_handler {inputchan readmore prompt_config} {
}
}
if {$::tcl_interactive} {
if {$::tcl_interactive && [console_is_default]} {
#process-console repl only: a foreign console's eof (e.g remote disconnect,
#widget teardown) must finish the repl, not reopen the process stdin.
rputs stderr "\nrepl_handler EOF inputchannel: [chan conf $inputchan]"
#rputs stderr "\n|repl> ctrl-c EOF on $inputchan."
after 1 [list repl::reopen_stdin]
@ -2135,6 +2260,8 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
# ---
variable reading
variable id_outstack
variable conout
variable conerr
#upvar ::punk::config::configdata configd
#set running_config [dict get $configd running]
@ -2296,10 +2423,10 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
set do_checkwidth 1 ;#make configurable if performance hit is too severe? TODO
set consolewidth 132
if {$do_checkwidth} {
if {[catch {set consolewidth [dict get [punk::console::get_size] columns]} errM]} {
if {[catch {set consolewidth [dict get [repl::console_get_size] columns]} errM]} {
#review
if {!$is_vt52} {
puts stderr "repl_process_data failed on call to punk::console::get_size :$errM"
puts stderr "repl_process_data failed on call to repl::console_get_size :$errM"
}
}
#if chan conf stdout doesn't give dimensions and console doesn't respond to queries - we can get empty results in get_size dict
@ -2420,7 +2547,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
} trap {POSIX} {e eopts} {
rputs stderr "trap1 POSIX '$e' eopts:'$eopts"
flush stderr
flush $conerr
} on error {repl_error erropts} {
rputs stderr "error1 in repl_process_data: $repl_error"
rputs stderr "-------------"
@ -2432,14 +2559,14 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
} else {
rputs stderr "*> $inputchan reader active"
}
if {[chan eof $inputchan]} {
if {[console_at_eof $inputchan]} {
rputs stderr "todo - attempt restart of repl on input channel: $inputchan in next loop"
catch {set ::punk::nav::ns::ns_current "::"}
#todo set flag to restart repl ?
} else {
rputs stderr "continuing.."
}
flush stderr
flush $conerr
}
@ -2499,7 +2626,9 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
}
set stdinconf [fconfigure $inputchan]
if {$::tcl_platform(platform) eq "windows" && [dict get $stdinconf -encoding] ni [list unicode utf-16 utf-8]} {
if {[console_is_default] && $::tcl_platform(platform) eq "windows" && [dict get $stdinconf -encoding] ni [list unicode utf-16 utf-8]} {
#(default process console only: a selected foreign console's channel encoding is the
# transport's business - re-decoding its lines as utf-16be would mangle them)
#some long console inputs are split weirdly when -encoding and -translation are left at defaults - requiring extra enter-key to get repl to process.
#experiment to see if using iso8859-1 (raw bytes) and handling line endings manually gives insight.
# - do: chan conf stdin -encoding iso859-1 -translation lf
@ -2695,6 +2824,29 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
set raw_result [tsv::get codethread_$codethread result]
lassign [tsv::get codethread_$codethread info] _o lastoutchar_codethread _e lasterrchar_codethread
if {![console_is_default]} {
#G-001 foreign-console repl: code-interp std-channel writes were diverted into
#pending vars by the junction stacks installed at init - collect and emit them
#to the selected console's channels (rputs maps stdout/stderr to conout/conerr).
#Interleaving between the two streams within a run is not preserved (single
#terminal stream; per-console err semantics are G-011).
set pending [thread::send $codethread {
interp eval code {
set _pendinglist [list $::codeinterp::console_pending_out $::codeinterp::console_pending_err]
set ::codeinterp::console_pending_out ""
set ::codeinterp::console_pending_err ""
set _pendinglist
}
}]
lassign $pending pending_out pending_err
if {$pending_out ne ""} {
rputs -nonewline stdout $pending_out
}
if {$pending_err ne ""} {
rputs -nonewline stderr $pending_err
}
}
#set status [catch {
# thread::send $
# uplevel 1 {namespace inscope $::punk::nav::ns::ns_current $run_command_string}
@ -2711,8 +2863,8 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
#puts stderr "-->>$result<--"
#===============================================================================
flush stdout
flush stderr
flush $conout
flush $conerr
#foreach s [lreverse $outstack] {
# shellfilter::stack::remove stdout $s
#}
@ -3022,8 +3174,10 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
#----------------------------------------------------------------------------
#after any external command - raw mode as the console sees it can be disabled
#set it to match current state of the tsv
#(process-default console only: the tsv raw state and enableRaw target the
# process console, not a selected foreign console - scoped state is G-008)
#----------------------------------------------------------------------------
if {[tsv::get punk_console is_raw]} {
if {[console_is_default] && [tsv::get punk_console is_raw]} {
if {$::tcl_platform(platform) eq "windows"} {
#review
#we are in parent process - twapi might not be loaded here - even if it is in the code interp
@ -3057,14 +3211,14 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
set ::punk::repl::signal_control_c 0
chan event $inputchan readable {}
rputs stderr "* console_control: control-c"
flush stderr
flush $conerr
set c [a yellow bold]
set n [a]
rputs stderr "${c}repl interrupted$n"
#set commandstr [list error "repl interrupted"]
set commandstr ""
doprompt ">_ "
flush stdout
flush $conout
} else {
# parse and determine outermost unclosed quote/bracket and include in prompt
@ -3108,7 +3262,7 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
} trap {POSIX} {e eopts} {
rputs stderr "trap POSIX '$e' eopts:'$eopts"
flush stderr
flush $conerr
} on error {repl_error erropts} {
rputs stderr "error2 in repl_process_data: $repl_error"
rputs stderr "-------------"
@ -3120,14 +3274,14 @@ proc repl::repl_process_data {inputchan chunktype chunk stdinlines prompt_config
} else {
rputs stderr "*> $inputchan reader active"
}
if {[chan eof $inputchan]} {
if {[console_at_eof $inputchan]} {
rputs stderr "todo - attempt restart of repl on input channel: $inputchan in next loop"
catch {set ::punk::nav::ns::ns_current "::"}
#todo set flag to restart repl ?
} else {
rputs stderr "continuing.."
}
flush stderr
flush $conerr
}
}
@ -3194,10 +3348,10 @@ namespace eval repl {
variable codethread_cond
variable codethread_mutex
set opts [list -force 0 -type 0 -safelog 0 -paths {} -callback_interp $default_callback_interp]
set opts [list -force 0 -type 0 -safelog 0 -paths {} -callback_interp $default_callback_interp -console {}]
foreach {k v} $args {
switch -- $k {
-force - -type - -safelog - -paths - -callback_interp {
-force - -type - -safelog - -paths - -callback_interp - -console {
dict set opts $k $v
}
default {
@ -3224,6 +3378,37 @@ namespace eval repl {
if {$codethread ne "" && !$opt_force && [thread::exists $codethread] } {
error "repl:init codethread: $codethread already exists. use -force 1 to override"
}
#G-001 console selection: a -console spec ({in out} pair, anchored opunk::console instance
#name, or ::opunk::Console object value) selects the console this repl reads/writes.
#The resolved object (when present) answers at_eof/size/can_respond via its (possibly
#overridden) methods - see repl::console_at_eof / repl::console_get_size.
set opt_console [dict get $opts -console]
variable repl_console
variable conin
variable conout
variable conerr
if {$opt_console ne ""} {
set cinfo [punk::console::console_spec_resolve $opt_console]
set repl_console [dict get $cinfo object]
set conin [dict get $cinfo in]
set conout [dict get $cinfo out]
if {$conin eq "stdin" && $conout eq "stdout"} {
#explicit selection of the process-default console - full legacy behaviour incl. stderr
set conerr stderr
} else {
set conerr $conout
}
} else {
set repl_console ""
set conin stdin
set conout stdout
set conerr stderr
}
#whether code-interp std-channel writes must be diverted and routed to the selected console
#instead of reaching the process std channels
set conredirect [expr {![console_is_default]}]
set codethread [thread::create -preserved]
#review - naming of the possibly 2 cond variables parent and child thread
set codethread_cond [thread::cond create] ;#repl::codethread_cond held by parent(repl) vs punk::repl::codethread::replthread_cond held by child(codethread)
@ -3243,6 +3428,7 @@ namespace eval repl {
} %packageprefer% [list [package prefer]] {*}{
} %staticprefixes% [list [expr {[info exists ::punkboot::static_prefixes] ? $::punkboot::static_prefixes : ""}]] {*}{
} %staticpackages% [list [expr {[info exists ::punkboot::static_packages] ? $::punkboot::static_packages : ""}]] {*}{
} %conredirect% [list $conredirect] {*}{
}
]
#scriptmap applied at end to satisfy silly editor highlighting.
@ -4125,6 +4311,21 @@ namespace eval repl {
package require punk
package require shellrun
package require shellfilter
if {%conredirect%} {
#G-001 foreign-console repl: code-interp writes to stdout/stderr must not
#reach the process std channels. The shellfilter 'var' transform is a
#junction (no pass-through): writes divert into pending vars which the
#parent repl thread collects after each runscript and emits to the
#selected console's channels. Added before the colour ansiwrap stacks so
#those still apply to the diverted data (writes traverse newest transform
#first, so a junction added earlier captures last).
namespace eval ::codeinterp {
variable console_pending_out ""
variable console_pending_err ""
}
shellfilter::stack::add stdout var -settings {-varname ::codeinterp::console_pending_out}
shellfilter::stack::add stderr var -settings {-varname ::codeinterp::console_pending_err}
}
#set running_config $::punk::config::running
apply {running_config {
if {[string length [dict get $running_config color_stderr]] && [punk::console::colour]} {
@ -4229,6 +4430,11 @@ namespace eval repl {
}
#init - don't auto init - require init with possible options e.g -type
}
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::repl
}
package provide punk::repl [namespace eval punk::repl {
variable version
set version 999999.0a1.0

3
src/modules/punk/repl-buildversion.txt

@ -1,6 +1,7 @@
0.3.0
0.4.0
#First line must be a semantic version number
#all other lines are ignored.
#0.4.0 - G-001: repl::init -console <spec> selects the console the repl reads/writes ({in out} pair, anchored opunk::console instance name, or ::opunk::Console object value, resolved via punk::console::console_spec_resolve). repl::start's inchan is now optional (defaults to the selected console's input). New repl-level channel state (conin/conout/conerr) is routed through rputs (stdout/stderr mapped per-repl) and doprompt; for a selected foreign console the code interp's stdout/stderr are diverted via shellfilter 'var' junction stacks and emitted to the console after each run. New helpers repl::console_is_default / console_at_eof / console_get_size - eof and size are answered by the selected console object's (possibly overridden) methods. Process-console behaviours (tcl_interactive prompt gating, stdin reopen on eof, raw-mode re-enable, utf-16be windows line re-decode experiment, mode-line on exit) now apply only to the default console. Default-console (stdin/stdout) behaviour unchanged. Also fixes rputs pseudo-channel mapping in the 3-arg -nonewline form (mapped value previously written over the -nonewline flag).
#0.3.0 - G-058: codethread init script receives the runtime static/builtin package baseline (::punkboot::static_prefixes/static_packages via new %staticprefixes%/%staticpackages% scriptmap entries) and seeds ifneeded mappings in the codethread interp, so the code interp (seeded in turn via punk::lib::interp_sync_package_paths) can package-require statically-linked runtime packages - fixes 'can't find package Thread' booting a punk9win.vfs kit on the tclsfe-x64 static runtime (punk91)
#0.2.2 - repl_handler line-mode waiting-chunks path no longer performs its opportunistic unsized read on tcl 8.6 windows console channels (no -inputmode key, real twapi console handle): the path is entered via 'after idle' with the channel usually drained, and on the 8.6 console driver a drained read parks a blocking cooked-mode ReadConsole that a later raw flip cannot cancel - after typed-ahead was stashed during a terminal-query raw window, that parked read swallowed every subsequent query response in the session until Enter (companion to the punk::console 0.7.1 three-site console-misdetection fix). On such consoles the path now consumes only data already in the Tcl channel buffer (chan pending input + sized read - no driver probe); with nothing buffered it processes the stashed complete lines directly and arms the readable handler for any remaining partial line (replacing an after-idle reinvoke that could never progress). Behaviour on tcl 9/8.7 (-inputmode consoles) and in raw mode is unchanged.
#0.2.1 - call-site update for punk::console 0.6.0 tsv array rename: console -> punk_console (is_raw); no behaviour change

Loading…
Cancel
Save