diff --git a/src/modules/punk/console-999999.0a1.0.tm b/src/modules/punk/console-999999.0a1.0.tm index 9a833056..86572af6 100644 --- a/src/modules/punk/console-999999.0a1.0.tm +++ b/src/modules/punk/console-999999.0a1.0.tm @@ -2998,12 +2998,19 @@ namespace eval punk::console { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::move 2000 2000] + #flush before querying: the position query may execute in the console-owning + #thread (G-007 routing), whose flush acts on its own channel instance for the same + #OS handle - an unflushed move here would leave the terminal reporting the + #unmoved cursor position (seen as 'columns 1' on tcl 8.6 where the -winsize + #shortcut is unavailable and this mechanism actually runs) + flush $out lassign [get_cursor_pos_list $inoutchannels] lines cols puts -nonewline $out [punk::ansi::move $start_row $start_col][punk::ansi::cursor_on];flush $out set result [dict create columns $cols rows $lines] } errM]} { puts -nonewline $out [punk::ansi::move $start_row $start_col] puts -nonewline $out [punk::ansi::cursor_on] + catch {flush $out} error "$errM" } else { return $result @@ -3037,12 +3044,16 @@ namespace eval punk::console { #some terminals (conemu on windows) scroll the viewport when we make a big move down like this - a move to 1 1 immediately after cursor_save doesn't seem to fix that. #This issue also occurs when switching back from the alternate screen buffer - so perhaps that needs to be addressed elsewhere. puts -nonewline $out [punk::ansi::cursor_off][punk::ansi::cursor_save_dec][punk::ansi::move 2000 2000] + #flush before querying - see get_size_using_cursormove (G-007 routing: the query + #may flush a different channel instance in the console-owning thread) + flush $out lassign [get_cursor_pos_list $inoutchannels] lines cols puts -nonewline $out [punk::ansi::cursor_restore][punk::ansi::cursor_on];flush $out set result [dict create columns $cols rows $lines] } errM]} { puts -nonewline $out [punk::ansi::cursor_restore_dec] puts -nonewline $out [punk::ansi::cursor_on] + catch {flush $out} error "$errM" } else { return $result @@ -4292,6 +4303,10 @@ namespace eval punk::console { if {!$emit} { puts -nonewline $out \033\[2K\033\[1G ;#2K erase line, 1G cursor at col1 } + #flush before each cursor query: the query may execute in the console-owning thread + #(G-007 routing) whose flush acts on its own channel instance - unflushed emissions + #here would be measured as if they never happened (see get_size_using_cursormove) + flush $out set response "" if {[catch { set response [punk::console::get_cursor_pos $inoutchannels] @@ -4313,6 +4328,7 @@ namespace eval punk::console { } errM]} { puts stderr "test_char_width couldn't emit this string - \nerror: $errM" } + flush $out ;#the test emission must reach the terminal before the (possibly routed) query measures it set response [punk::console::get_cursor_pos $inoutchannels] lassign [split $response ";"] _row2 col2 @@ -4367,6 +4383,10 @@ namespace eval punk::console { if {!$emit} { puts -nonewline $out \033\[2K\033\[1G ;#2K erase line, 1G cursor at col1 } + #flush before the cursor query - the alt-screen/move/erase emissions above must reach + #the terminal first (the query may flush a different channel instance in the + #console-owning thread under G-007 routing - see get_size_using_cursormove) + flush $out set response "" if {[catch { set response [punk::console::get_cursor_pos $inoutchannels] diff --git a/src/modules/punk/console-buildversion.txt b/src/modules/punk/console-buildversion.txt index d4696937..62e2eb28 100644 --- a/src/modules/punk/console-buildversion.txt +++ b/src/modules/punk/console-buildversion.txt @@ -1,6 +1,7 @@ 0.7.1 #First line must be a semantic version number #all other lines are ignored. +#0.7.1 - compound emit-then-query operations flush their emissions before querying: get_size_using_cursormove/get_size_using_cursorrestore (the far-corner move), test_char_width (positioning and the measured test emission) and test_string_cursor (alt-screen/move/erase). Under G-007 routing the position query may execute in the console-owning thread, whose flush acts on its own channel instance for the same OS handle - the caller's unflushed emissions then reach the terminal after the query measures, e.g. get_size returning 'columns 1' on tcl 8.6 where the -winsize shortcut is unavailable and the ANSI mechanism actually runs (pre-routing this was masked because emit and query shared one channel instance, so the query's flush pushed the emissions too). Error paths flush their cursor-restore emissions likewise. #0.7.1 - ensure_object_integration hardening: returns 0 as a graceful no-op (without latching object_integration_done) when opunk::console is not loaded, instead of erroring into the nonexistent namespace; and on wiring the lifecycle callback it retro-registers ownership for anchors created in this interp before the wiring (previously 'package require opunk::console; opunk::console::create ...' with no intervening punk::console object operation left the console without a registered owner - fact-store share qualifiers then fell back to the calling thread and other threads could not address that console's facts). Retro-registration fills empty registry entries only; existing live registrations are preserved. #0.7.1 - fix Tcl 8.6 windows console misdetection (one root cause, three sites): 8.6 console channels expose no -inputmode configure key, so guards that test for -inputmode/-mode classified a real 8.6 console as a pipe. A twapi console handle for stdin is now treated as definitive at all three sites (stdin only - pipe probes still never flip the process console; mintty-as-pipes has no console handle and falls through to the env heuristics). Site 1: get_ansi_response_payload's raw-cycling gate (0.1.5) skipped the raw cycle for 8.6 line-mode queries. Site 2: is_input_console_or_tty false negative made settle_can_respond's layer-2 heuristic settle a real 8.6 console as unable to respond. Site 3 (the line-mode query killer, introduced 0.1.2): input_at_eof took the pipe branch and performed its probe read on the drained console channel - a read on a drained 8.6 console makes the channel driver park a blocking cooked-mode ReadConsole that a later raw flip cannot cancel (verified empirically against clean tclkits 8.6.13/8.6.17: driver reads sample the console mode when issued, not when data arrives), and since get_ansi_response_payload calls input_at_eof immediately before its raw cycle, every 8.6 line-mode query's response was swallowed by that parked read until Enter (~500ms timeout + response leaking to the line reader as phantom input; also the cause of increased ANSI artifacts in outputs like 'help env' once 0.7.0 brokering made code-interp queries actually reach the terminal). #0.7.0 - G-007 slice 2 (choke-point brokering): a terminal query (internal::get_ansi_response_payload and every query proc layered above it) on the process-default console {stdin stdout} issued by a thread that is not the registered owner is forwarded whole to the owning thread via synchronous thread::send, so queueing, raw-mode cycling, cooperative reader handling (input_chunks_waiting) and can_respond gating all execute in the owner's context; owner-side errors propagate to the caller with routing context