From 1b9a29405842e3364bfbc3087dcd2f649fd936f6 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Fri, 10 May 2024 01:34:41 +1000 Subject: [PATCH] textblock table vert sep fixes --- src/bootsupport/modules/punk/lib-0.1.1.tm | 2 +- src/bootsupport/modules/textblock-0.1.1.tm | 225 +++++++++++---------- src/modules/patternpunk-1.1.tm | 15 +- src/modules/punk-0.1.tm | 81 ++++---- src/modules/textblock-999999.0a1.0.tm | 223 +++++++++++--------- 5 files changed, 305 insertions(+), 241 deletions(-) diff --git a/src/bootsupport/modules/punk/lib-0.1.1.tm b/src/bootsupport/modules/punk/lib-0.1.1.tm index 5b33a9a7..9e9f0b37 100644 --- a/src/bootsupport/modules/punk/lib-0.1.1.tm +++ b/src/bootsupport/modules/punk/lib-0.1.1.tm @@ -221,7 +221,7 @@ namespace eval punk::lib { #[para]We want to resolve the index used, without passing arbitrary expressions into the 'expr' function - which could have security risks. #[para]lindex_resolve will parse the index expression and return -1 if the supplied index expression is out of bounds for the supplied list. #[para]Otherwise it will return an integer corresponding to the position in the list. - #[para]Like Tcl list commands - it will produce an error if the form of the + #[para]Like Tcl list commands - it will produce an error if the form of the index is not acceptable #Note that for an index such as $x+1 - we never see the '$x' as it is substituted in the calling command. We will get something like 10+1 - which we will resolve (hopefully safely) with expr if {![llength $list]} { diff --git a/src/bootsupport/modules/textblock-0.1.1.tm b/src/bootsupport/modules/textblock-0.1.1.tm index fc140fab..2a7da301 100644 --- a/src/bootsupport/modules/textblock-0.1.1.tm +++ b/src/bootsupport/modules/textblock-0.1.1.tm @@ -52,7 +52,9 @@ namespace eval textblock { ]\ -framemap_header [list headerleft {} headerinner {} headerright {} headersolo {}]\ -show_edge 1\ - -show_separators 1\ + -show_seps 1\ + -show_hseps ""\ + -show_vseps ""\ -show_header ""\ -show_footer ""\ ] @@ -76,8 +78,8 @@ namespace eval textblock { onlyright [list hlt hlb tlc blc brc trc vlr]\ onlysolo [list hlt hlb vll vlr blc brc trc brc]\ ] - variable table_sep_parts - set table_sep_parts [dict create\ + variable table_hseps + set table_hseps [dict create\ topleft [list blc hlb]\ topinner [list blc hlb]\ topright [list blc hlb brc]\ @@ -95,6 +97,31 @@ namespace eval textblock { onlyright [list]\ onlysolo [list]\ ] + variable table_vseps + set table_vseps [dict create\ + headerleft [list]\ + headerinner [list vll tlc blc]\ + headerright [list vll tlc blc]\ + headersolo [list]\ + topleft [list]\ + topinner [list vll tlc blc]\ + topright [list vll tlc blc]\ + topsolo [list]\ + middleleft [list]\ + middleinner [list vll tlc blc]\ + middleright [list vll tlc blc]\ + middlesolo [list]\ + bottomleft [list]\ + bottominner [list vll tlc blc]\ + bottomright [list vll tlc blc]\ + bottomsolo [list]\ + onlyleft [list]\ + onlyinner [list vll tlc blc]\ + onlyright [list vll tlc blc]\ + onlysolo [list]\ + ] + + variable header_border_parts set header_border_parts [dict create\ headerleft [list vll tlc blc hlt]\ @@ -117,9 +144,9 @@ namespace eval textblock { return $map } proc table_sep_map {char} { - variable table_sep_parts + variable table_hseps set map [list] - dict for {celltype parts} $table_sep_parts { + dict for {celltype parts} $table_hseps { set tmap [list] foreach p $parts { dict set tmap $p $char @@ -188,6 +215,30 @@ namespace eval textblock { set o_rowstates [dict create] ;#actual row data such as -minheight and -maxheight detected from supplied row data } + method Get_seps {} { + set requested_seps [dict get $o_opts_table -show_seps] + set requested_seps_h [dict get $o_opts_table -show_hseps] + set requested_seps_v [dict get $o_opts_table -show_vseps] + set seps $requested_seps + set seps_h $requested_seps_h + set seps_v $requested_seps_v + if {$requested_seps eq ""} { + if {$requested_seps_h eq ""} { + set seps_h 1 + } + if {$requested_seps_v eq ""} { + set seps_v 1 + } + } else { + if {$requested_seps_h eq ""} { + set seps_h $seps + } + if {$requested_seps_v eq ""} { + set seps_v $seps + } + } + return [dict create horizontal $seps_h vertical $seps_v] + } method Get_frametypes {} { set requested_ft [dict get $o_opts_table -frametype] set requested_ft_header [dict get $o_opts_table -frametype_header] @@ -242,6 +293,21 @@ namespace eval textblock { set checked_opts [list] dict for {k v} $args { switch -- $k { + -ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder-body - -ansiborder_footer { + set parts [punk::ansi::ta::split_codes_single $v] ;#caller may have supplied separated codes eg "[a+ Yellow][a+ red]" + set ansi_codes [list] ; + foreach {pt code} $parts { + if {$pt ne ""} { + #we don't expect plaintext in an ansibase + error "Unable to interpret $k value as ansi SGR codes. Plaintext detected. Consider using for example: '\[punk::ansi::a+ green]' (or alias '\[a+ green]') to build ansi. debug view: [punk::ansi::ansistring VIEW $v]" + } + if {$code ne ""} { + lappend ansi_codes $code + } + } + set ansival [punk::ansi::codetype::sgr_merge $ansi_codes] + lappend checked_opts $k $ansival + } -ansireset { if {$v eq "\uFFEF"} { lappend checked_opts $k "\x1b\[m" ;# [a] @@ -607,56 +673,35 @@ namespace eval textblock { left { set header_boxlimits {hl tlc blc vll} set header_joins [list down-$ftype_body] - set boxlimits_build {hlb blc vll} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } + set boxlimits_position {hlb blc vll} set boxlimits_headerless {hlb hlt blc vll tlc} set joins {down} } inner { set header_boxlimits {hl tlc blc vll} set header_joins [list left down-$ftype_body] - set boxlimits_build {hlb blc vll} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } + set boxlimits_position {hlb blc vll} set boxlimits_headerless {hlb hlt blc vll tlc} set joins {down left} } right { - set header_boxlimits {hl tlc blc vl trc brc} + set header_boxlimits {hl tlc blc vll vlr trc brc} set header_joins [list left down-$ftype_body] - set boxlimits_build {hlb blc vll vlr brc} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } + set boxlimits_position {hlb blc vll vlr brc} set boxlimits_headerless {hlb hlt blc vll vlr brc tlc trc} set joins {down left} } solo { - set header_boxlimits {hl tlc blc vl trc brc} + set header_boxlimits {hl tlc blc vll vlr trc brc} set header_joins [list down-$ftype_body] - set boxlimits_build {hlb blc vll vlr brc} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } - set boxlimits_headerless {hlb hlt blc vl brc tlc trc} + set boxlimits_position {hlb blc vll vlr brc} + set boxlimits_headerless {hlb hlt blc vll vlr brc tlc trc} set joins {down} } } + #use struct::set instead of simple for loop - will be faster at least when critcl available + set boxlimits [struct::set intersect [dict get $o_opts_table -framelimits_body] $boxlimits_position] + upvar ::textblock::class::opts_table_defaults tdefaults set defaultmap [dict get $tdefaults -framemap_body] set default_hmap [dict get $tdefaults -framemap_header] @@ -667,46 +712,23 @@ namespace eval textblock { set fmap [dict merge $defaultmap [dict get $o_opts_table -framemap_body]] set hmap [dict merge $default_hmap [dict get $o_opts_table -framemap_header]] } - set sep_elements $::textblock::class::table_sep_parts + set sep_elements_horizontal $::textblock::class::table_hseps + set sep_elements_vertical $::textblock::class::table_vseps - switch -- $opt_posn { - left { - set topmap [dict get $fmap topleft] - set botmap [dict get $fmap bottomleft] - set midmap [dict get $fmap middleleft] - set onlymap [dict get $fmap onlyleft] - set hdrmap [dict get $hmap headerleft] - set topseps [dict get $sep_elements topleft] - set midseps [dict get $sep_elements middleleft] - } - inner { - set topmap [dict get $fmap topinner] - set botmap [dict get $fmap bottominner] - set midmap [dict get $fmap middleinner] - set onlymap [dict get $fmap onlyinner] - set hdrmap [dict get $hmap headerinner] - set topseps [dict get $sep_elements topinner] - set midseps [dict get $sep_elements middleinner] - } - right { - set topmap [dict get $fmap topright] - set botmap [dict get $fmap bottomright] - set midmap [dict get $fmap middleright] - set onlymap [dict get $fmap onlyright] - set hdrmap [dict get $hmap headerright] - set topseps [dict get $sep_elements topright] - set midseps [dict get $sep_elements middleright] - } - solo { - set topmap [dict get $fmap topsolo] - set botmap [dict get $fmap bottomsolo] - set midmap [dict get $fmap middlesolo] - set onlymap [dict get $fmap onlysolo] - set hdrmap [dict get $hmap headersolo] - set topseps [dict get $sep_elements topsolo] - set midseps [dict get $sep_elements middlesolo] - } - } + set topmap [dict get $fmap top$opt_posn] + set botmap [dict get $fmap bottom$opt_posn] + set midmap [dict get $fmap middle$opt_posn] + set onlymap [dict get $fmap only$opt_posn] + set hdrmap [dict get $hmap header$opt_posn] + set topseps_h [dict get $sep_elements_horizontal top$opt_posn] + set topseps_v [dict get $sep_elements_vertical top$opt_posn] + set midseps_h [dict get $sep_elements_horizontal middle$opt_posn] + set midseps_v [dict get $sep_elements_vertical middle$opt_posn] + set botseps_v [dict get $sep_elements_vertical bottom$opt_posn] + + set headerseps_v [dict get $sep_elements_vertical header$opt_posn] + + lassign [my Get_seps] _h show_seps_h _v show_seps_v if {$do_show_header} { #puts "boxlimitsinfo header $opt_posn: -- boxlimits $header_boxlimits -- boxmap $hdrmap" @@ -732,9 +754,14 @@ namespace eval textblock { set hval_block [join $hval_lines \n] set headercell [overtype::left -experimental test_mode $ansibase_header$hcell_blank$RST $hval_block] + set hlims $header_boxlimits + if {!$show_seps_v} { + set hlims [struct::set difference $header_boxlimits $headerseps_v] + } + set header_frame [textblock::frame -width [expr {$colwidth+2}] -type [dict get $ftypes header]\ -ansibase $ansibase_header -ansiborder $ansiborder_final\ - -boxlimits $header_boxlimits -boxmap $hdrmap -joins $header_joins $hval\ + -boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\ ] #puts ">> '[ansistring VIEW $hval]' -> $header_frame" @@ -747,24 +774,18 @@ namespace eval textblock { set blims_mid $boxlimits set blims_top $boxlimits + set blims_bot $boxlimits set blims_top_headerless $boxlimits_headerless - if {![dict get $o_opts_table -show_separators]} { - foreach el $midseps { - set elposn [lsearch $blims_mid $el] - if {$elposn >= 0} { - set blims_mid [lremove $blims_mid $elposn] - } - } - foreach el $topseps { - set elposn [lsearch $blims_top $el] - if {$elposn >= 0} { - set blims_top [lremove $blims_top $elposn] - } - set elposn [lsearch $blims_top_headerless $el] - if {$elposn >= 0} { - set blims_top_headerless [lremove $blims_top_headerless $elposn] - } - } + if {!$show_seps_h} { + set blims_mid [struct::set difference $blims_mid $midseps_h] + set blims_top [struct::set difference $blims_top $topseps_h] + set blims_top_headerless [struct::set difference $blims_top_headerless $topseps_h] + } + if {!$show_seps_v} { + set blims_mid [struct::set difference $blims_mid $midseps_v] + set blims_top [struct::set difference $blims_top $topseps_v] + set blims_top_headerless [struct::set difference $blims_top_headerless $topseps_v] + set blims_bot [struct::set difference $blims_bot $botseps_v] } set colidx [lindex [dict keys $o_columndefs] $index_expression] ;#convert possible end-1,2+2 etc expression to >= 0 integer in dict range @@ -819,10 +840,10 @@ namespace eval textblock { if {$r == $rmax} { set joins [lremove $joins [lsearch $joins down*]] set bmap $botmap - set blims $boxlimits + set blims $blims_bot } else { set bmap $midmap - set blims $blims_mid ;#will only be reduced from boxlimits if -show_separators was processed above + set blims $blims_mid ;#will only be reduced from boxlimits if -show_seps was processed above } append output [textblock::frame -type [dict get $ftypes body] -ansibase $ansibase -ansiborder $border_ansi_final -boxlimits $blims -boxmap $bmap -joins $joins $c]\n } @@ -1102,16 +1123,16 @@ namespace eval textblock { namespace eval ::term::ansi::code::macros::cd {namespace export -clear} } - proc list_as_table {datalist table_or_colcount args} { + proc list_as_table {table_or_colcount datalist args} { set defaults [dict create\ -return string\ -frametype \uFFEF\ -show_edge \uFFEF\ - -show_separators \uFFEF\ + -show_seps \uFFEF\ ] foreach {k v} $args { switch -- $k { - -return - -show_edge - -show_separators - -frametype {} + -return - -show_edge - -show_seps - -frametype {} default { error "unrecognised option '$k'. Known options [dict keys $defaults]" } @@ -1132,10 +1153,10 @@ namespace eval textblock { if {[dict get $opts -show_edge] eq "\uFFEF"} { dict set opts -show_edge 1 } - if {[dict get $opts -show_separators] eq "\uFFEF"} { - dict set opts -show_separators 1 + if {[dict get $opts -show_seps] eq "\uFFEF"} { + dict set opts -show_seps 1 } - set t [textblock::class::table new -show_header 0 -show_edge [dict get $opts -show_edge] -frametype [dict get $opts -frametype] -show_separators [dict get $opts -show_separators]] + set t [textblock::class::table new -show_header 0 -show_edge [dict get $opts -show_edge] -frametype [dict get $opts -frametype] -show_seps [dict get $opts -show_seps]] for {set c 0} {$c < $cols} {incr c} { $t add_column -header c$c } @@ -2839,7 +2860,7 @@ namespace eval textblock { #boxlimits used for partial borders in table generation set all_exact_boxlimits [list vll vlr hlt hlb tlc blc trc blc] - set unspecified_limits [struct::set diff $all_exact_boxlimits $exact_boxlimits] + set unspecified_limits [struct::set difference $all_exact_boxlimits $exact_boxlimits] foreach lim $unspecified_limits { switch -- $lim { vll { diff --git a/src/modules/patternpunk-1.1.tm b/src/modules/patternpunk-1.1.tm index ea5be7aa..c90d7ede 100644 --- a/src/modules/patternpunk-1.1.tm +++ b/src/modules/patternpunk-1.1.tm @@ -20,7 +20,7 @@ pattern::init ::>pattern .. Create ::>punk ::>punk .. Property license {Public Domain} -::>punk .. Property logo2 [string trim { +::>punk .. Property logo_ascii [string trim { +-----------------------+ | Pattern PUNK | | . \\\_ . | @@ -32,7 +32,7 @@ pattern::init | . _+ +_ . | +-----------------------+ } \n] -set ::punk::bannerTemplate [string trim { +set ::punk::bannerTemplate0 [string trim { +-----------------------+ | .000000000000000. | | .*. \\\_ .=. | @@ -44,6 +44,16 @@ set ::punk::bannerTemplate [string trim { |111111111_+ +_2222222| +-----------------------+ } \n] +set ::punk::bannerTemplate [string trim { + .000000000000000. + .*. \\\_ .=. + .*.*. \@ > .=.=. +.*.*.*. | ~ .=.=.=. + .*.*. \_- -_/ .=.=. + .*. \\ .=. + . / \ . +111111111_+ +_2222222 +} \n] >punk .. Method banner {args} { set defaults [list -title "Pattern PUNK" -left "" -right ""] @@ -54,7 +64,6 @@ set ::punk::bannerTemplate [string trim { set word1 [overtype::left [string repeat " " 9] [dict get $opts -left]] set word2 [overtype::right [string repeat " " 7] [dict get $opts -right]] set title [overtype::centre [string repeat " " 15] [dict get $opts -title]] - return [string map [list 111111111 $word1 2222222 $word2 000000000000000 $title] $::punk::bannerTemplate] } diff --git a/src/modules/punk-0.1.tm b/src/modules/punk-0.1.tm index 22626d11..e10ba7f8 100644 --- a/src/modules/punk-0.1.tm +++ b/src/modules/punk-0.1.tm @@ -6918,32 +6918,12 @@ namespace eval punk { catch { package require patternpunk #lappend chunks [list stderr [>punk . rhs]] - append mascotblock [>punk . banner -title "Punk Shell" -left Tcl -right [package provide Tcl]] + append mascotblock [textblock::frame [>punk . banner -title "Punk Shell" -left Tcl -right [package provide Tcl]]] } set topic [lindex $args end] set argopts [lrange $args 0 end-1] - set text "" - if {$topic in [list env environment]} { - set known $::punk::config::known_punk_env_vars - append text $linesep\n - append text "punk environment vars:\n" - append text $linesep\n - set col1 [string repeat " " 25] - set col2 [string repeat " " 50] - foreach v $known { - set c1 [overtype::left $col1 $v] - if {[info exists ::env($v)]} { - set c2 [overtype::left $col2 [set ::env($v)] - } else { - set c2 [overtype::right $col2 "(NOT SET)"] - } - append text "$c1 $c2\n" - } - append text $linesep\n - lappend chunks [list stdout $text] - } set text "" append text "Punk core navigation commands:\n" @@ -6964,11 +6944,17 @@ namespace eval punk { set descr [lsearch -all -inline -index 1 -subindices $cmdinfo *] set widest1 [tcl::mathfunc::max {*}[lmap v $cmds {string length $v}]] set widest2 [tcl::mathfunc::max {*}[lmap v $descr {string length $v}]] - set col1 "[string repeat " " $widest1] " - set col2 "[string repeat " " $widest2] " + set t [textblock::class::table new -show_seps 0] foreach c $cmds d $descr { - append text " [overtype::left $col1 $c][overtype::left $col2 $d]" \n - } + #append text " [overtype::left $col1 $c][overtype::left $col2 $d]" \n + $t add_row [list $c $d] + } + set widest1 [$t column_datawidth 0] + $t configure_column 0 -minwidth [expr {$widest1 + 2}] + set widest2 [$t column_datawidth 1] + $t configure_column 1 -minwidth [expr {$widest2 + 1}] + append text [$t print] + set warningblock "" @@ -6978,15 +6964,40 @@ namespace eval punk { append warningblock \n "WARNING: textblock package couldn't be loaded. Side-by-side display not available" } else { - set introblock [textblock::join " " $mascotblock " " $text] + set introblock [textblock::join " " \n$mascotblock " " $text] } + + lappend chunks [list stdout $introblock] + + if {$topic in [list tcl]} { if {[punk::repl::has_script_var_bug]} { append warningblock \n "minor warning: punk::repl::has_script_var_bug returned true! (string rep for list variable in script generated when script changed)" } } + set text "" + if {$topic in [list env environment]} { + set known $::punk::config::known_punk_env_vars + append text $linesep\n + append text "punk environment vars:\n" + append text $linesep\n + set col1 [string repeat " " 25] + set col2 [string repeat " " 50] + foreach v $known { + set c1 [overtype::left $col1 $v] + if {[info exists ::env($v)]} { + set c2 [overtype::left $col2 [set ::env($v)] + } else { + set c2 [overtype::right $col2 "(NOT SET)"] + } + append text "$c1 $c2\n" + } + append text $linesep\n + lappend chunks [list stdout $text] + } + if {$topic in [list console terminal]} { lappend cstring_tests [dict create\ type "PM "\ @@ -7034,24 +7045,26 @@ namespace eval punk { } } - lappend chunks [list stdout $introblock] lappend chunks [list stderr $warningblock] if {$topic in [list topics help]} { set text "" set topics [dict create\ - "topic|help" "List help topics"\ + "topics|help" "List help topics"\ "tcl" "Tcl version warnings"\ "env|environment" "punkshell environment vars"\ "console|terminal" "Some console behaviour tests and warnings"\ ] - set col1 [string repeat " " 20] - append text \n [string repeat - 20] - append text \n "Topic" - append text \n [string repeat - 20] + + set t [textblock::class::table new -show_seps 0] + $t add_column -header "Topic" + $t add_column foreach {k v} $topics { - append text \n "[overtype::left $col1 $k] $v" + $t add_row [list $k $v] } - append text \n + set widest0 [$t column_datawidth 0] + $t configure_column 0 -minwidth [expr {$widest0 + 4}] + append text \n[$t print] + lappend chunks [list stdout $text] } diff --git a/src/modules/textblock-999999.0a1.0.tm b/src/modules/textblock-999999.0a1.0.tm index 4caf448f..cfdf45cf 100644 --- a/src/modules/textblock-999999.0a1.0.tm +++ b/src/modules/textblock-999999.0a1.0.tm @@ -52,7 +52,9 @@ namespace eval textblock { ]\ -framemap_header [list headerleft {} headerinner {} headerright {} headersolo {}]\ -show_edge 1\ - -show_separators 1\ + -show_seps 1\ + -show_hseps ""\ + -show_vseps ""\ -show_header ""\ -show_footer ""\ ] @@ -76,8 +78,8 @@ namespace eval textblock { onlyright [list hlt hlb tlc blc brc trc vlr]\ onlysolo [list hlt hlb vll vlr blc brc trc brc]\ ] - variable table_sep_parts - set table_sep_parts [dict create\ + variable table_hseps + set table_hseps [dict create\ topleft [list blc hlb]\ topinner [list blc hlb]\ topright [list blc hlb brc]\ @@ -95,6 +97,31 @@ namespace eval textblock { onlyright [list]\ onlysolo [list]\ ] + variable table_vseps + set table_vseps [dict create\ + headerleft [list]\ + headerinner [list vll tlc blc]\ + headerright [list vll tlc blc]\ + headersolo [list]\ + topleft [list]\ + topinner [list vll tlc blc]\ + topright [list vll tlc blc]\ + topsolo [list]\ + middleleft [list]\ + middleinner [list vll tlc blc]\ + middleright [list vll tlc blc]\ + middlesolo [list]\ + bottomleft [list]\ + bottominner [list vll tlc blc]\ + bottomright [list vll tlc blc]\ + bottomsolo [list]\ + onlyleft [list]\ + onlyinner [list vll tlc blc]\ + onlyright [list vll tlc blc]\ + onlysolo [list]\ + ] + + variable header_border_parts set header_border_parts [dict create\ headerleft [list vll tlc blc hlt]\ @@ -117,9 +144,9 @@ namespace eval textblock { return $map } proc table_sep_map {char} { - variable table_sep_parts + variable table_hseps set map [list] - dict for {celltype parts} $table_sep_parts { + dict for {celltype parts} $table_hseps { set tmap [list] foreach p $parts { dict set tmap $p $char @@ -188,6 +215,30 @@ namespace eval textblock { set o_rowstates [dict create] ;#actual row data such as -minheight and -maxheight detected from supplied row data } + method Get_seps {} { + set requested_seps [dict get $o_opts_table -show_seps] + set requested_seps_h [dict get $o_opts_table -show_hseps] + set requested_seps_v [dict get $o_opts_table -show_vseps] + set seps $requested_seps + set seps_h $requested_seps_h + set seps_v $requested_seps_v + if {$requested_seps eq ""} { + if {$requested_seps_h eq ""} { + set seps_h 1 + } + if {$requested_seps_v eq ""} { + set seps_v 1 + } + } else { + if {$requested_seps_h eq ""} { + set seps_h $seps + } + if {$requested_seps_v eq ""} { + set seps_v $seps + } + } + return [dict create horizontal $seps_h vertical $seps_v] + } method Get_frametypes {} { set requested_ft [dict get $o_opts_table -frametype] set requested_ft_header [dict get $o_opts_table -frametype_header] @@ -242,6 +293,21 @@ namespace eval textblock { set checked_opts [list] dict for {k v} $args { switch -- $k { + -ansibase_header - -ansibase_body - -ansiborder_header - -ansiborder-body - -ansiborder_footer { + set parts [punk::ansi::ta::split_codes_single $v] ;#caller may have supplied separated codes eg "[a+ Yellow][a+ red]" + set ansi_codes [list] ; + foreach {pt code} $parts { + if {$pt ne ""} { + #we don't expect plaintext in an ansibase + error "Unable to interpret $k value as ansi SGR codes. Plaintext detected. Consider using for example: '\[punk::ansi::a+ green]' (or alias '\[a+ green]') to build ansi. debug view: [punk::ansi::ansistring VIEW $v]" + } + if {$code ne ""} { + lappend ansi_codes $code + } + } + set ansival [punk::ansi::codetype::sgr_merge $ansi_codes] + lappend checked_opts $k $ansival + } -ansireset { if {$v eq "\uFFEF"} { lappend checked_opts $k "\x1b\[m" ;# [a] @@ -607,56 +673,35 @@ namespace eval textblock { left { set header_boxlimits {hl tlc blc vll} set header_joins [list down-$ftype_body] - set boxlimits_build {hlb blc vll} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } + set boxlimits_position {hlb blc vll} set boxlimits_headerless {hlb hlt blc vll tlc} set joins {down} } inner { set header_boxlimits {hl tlc blc vll} set header_joins [list left down-$ftype_body] - set boxlimits_build {hlb blc vll} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } + set boxlimits_position {hlb blc vll} set boxlimits_headerless {hlb hlt blc vll tlc} set joins {down left} } right { - set header_boxlimits {hl tlc blc vl trc brc} + set header_boxlimits {hl tlc blc vll vlr trc brc} set header_joins [list left down-$ftype_body] - set boxlimits_build {hlb blc vll vlr brc} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } + set boxlimits_position {hlb blc vll vlr brc} set boxlimits_headerless {hlb hlt blc vll vlr brc tlc trc} set joins {down left} } solo { - set header_boxlimits {hl tlc blc vl trc brc} + set header_boxlimits {hl tlc blc vll vlr trc brc} set header_joins [list down-$ftype_body] - set boxlimits_build {hlb blc vll vlr brc} - set boxlimits {} - foreach l $boxlimits_build { - if {$l in [dict get $o_opts_table -framelimits_body]} { - lappend boxlimits $l - } - } - set boxlimits_headerless {hlb hlt blc vl brc tlc trc} + set boxlimits_position {hlb blc vll vlr brc} + set boxlimits_headerless {hlb hlt blc vll vlr brc tlc trc} set joins {down} } } + #use struct::set instead of simple for loop - will be faster at least when critcl available + set boxlimits [struct::set intersect [dict get $o_opts_table -framelimits_body] $boxlimits_position] + upvar ::textblock::class::opts_table_defaults tdefaults set defaultmap [dict get $tdefaults -framemap_body] set default_hmap [dict get $tdefaults -framemap_header] @@ -667,46 +712,23 @@ namespace eval textblock { set fmap [dict merge $defaultmap [dict get $o_opts_table -framemap_body]] set hmap [dict merge $default_hmap [dict get $o_opts_table -framemap_header]] } - set sep_elements $::textblock::class::table_sep_parts + set sep_elements_horizontal $::textblock::class::table_hseps + set sep_elements_vertical $::textblock::class::table_vseps - switch -- $opt_posn { - left { - set topmap [dict get $fmap topleft] - set botmap [dict get $fmap bottomleft] - set midmap [dict get $fmap middleleft] - set onlymap [dict get $fmap onlyleft] - set hdrmap [dict get $hmap headerleft] - set topseps [dict get $sep_elements topleft] - set midseps [dict get $sep_elements middleleft] - } - inner { - set topmap [dict get $fmap topinner] - set botmap [dict get $fmap bottominner] - set midmap [dict get $fmap middleinner] - set onlymap [dict get $fmap onlyinner] - set hdrmap [dict get $hmap headerinner] - set topseps [dict get $sep_elements topinner] - set midseps [dict get $sep_elements middleinner] - } - right { - set topmap [dict get $fmap topright] - set botmap [dict get $fmap bottomright] - set midmap [dict get $fmap middleright] - set onlymap [dict get $fmap onlyright] - set hdrmap [dict get $hmap headerright] - set topseps [dict get $sep_elements topright] - set midseps [dict get $sep_elements middleright] - } - solo { - set topmap [dict get $fmap topsolo] - set botmap [dict get $fmap bottomsolo] - set midmap [dict get $fmap middlesolo] - set onlymap [dict get $fmap onlysolo] - set hdrmap [dict get $hmap headersolo] - set topseps [dict get $sep_elements topsolo] - set midseps [dict get $sep_elements middlesolo] - } - } + set topmap [dict get $fmap top$opt_posn] + set botmap [dict get $fmap bottom$opt_posn] + set midmap [dict get $fmap middle$opt_posn] + set onlymap [dict get $fmap only$opt_posn] + set hdrmap [dict get $hmap header$opt_posn] + set topseps_h [dict get $sep_elements_horizontal top$opt_posn] + set topseps_v [dict get $sep_elements_vertical top$opt_posn] + set midseps_h [dict get $sep_elements_horizontal middle$opt_posn] + set midseps_v [dict get $sep_elements_vertical middle$opt_posn] + set botseps_v [dict get $sep_elements_vertical bottom$opt_posn] + + set headerseps_v [dict get $sep_elements_vertical header$opt_posn] + + lassign [my Get_seps] _h show_seps_h _v show_seps_v if {$do_show_header} { #puts "boxlimitsinfo header $opt_posn: -- boxlimits $header_boxlimits -- boxmap $hdrmap" @@ -732,9 +754,14 @@ namespace eval textblock { set hval_block [join $hval_lines \n] set headercell [overtype::left -experimental test_mode $ansibase_header$hcell_blank$RST $hval_block] + set hlims $header_boxlimits + if {!$show_seps_v} { + set hlims [struct::set difference $header_boxlimits $headerseps_v] + } + set header_frame [textblock::frame -width [expr {$colwidth+2}] -type [dict get $ftypes header]\ -ansibase $ansibase_header -ansiborder $ansiborder_final\ - -boxlimits $header_boxlimits -boxmap $hdrmap -joins $header_joins $hval\ + -boxlimits $hlims -boxmap $hdrmap -joins $header_joins $hval\ ] #puts ">> '[ansistring VIEW $hval]' -> $header_frame" @@ -747,24 +774,18 @@ namespace eval textblock { set blims_mid $boxlimits set blims_top $boxlimits + set blims_bot $boxlimits set blims_top_headerless $boxlimits_headerless - if {![dict get $o_opts_table -show_separators]} { - foreach el $midseps { - set elposn [lsearch $blims_mid $el] - if {$elposn >= 0} { - set blims_mid [lremove $blims_mid $elposn] - } - } - foreach el $topseps { - set elposn [lsearch $blims_top $el] - if {$elposn >= 0} { - set blims_top [lremove $blims_top $elposn] - } - set elposn [lsearch $blims_top_headerless $el] - if {$elposn >= 0} { - set blims_top_headerless [lremove $blims_top_headerless $elposn] - } - } + if {!$show_seps_h} { + set blims_mid [struct::set difference $blims_mid $midseps_h] + set blims_top [struct::set difference $blims_top $topseps_h] + set blims_top_headerless [struct::set difference $blims_top_headerless $topseps_h] + } + if {!$show_seps_v} { + set blims_mid [struct::set difference $blims_mid $midseps_v] + set blims_top [struct::set difference $blims_top $topseps_v] + set blims_top_headerless [struct::set difference $blims_top_headerless $topseps_v] + set blims_bot [struct::set difference $blims_bot $botseps_v] } set colidx [lindex [dict keys $o_columndefs] $index_expression] ;#convert possible end-1,2+2 etc expression to >= 0 integer in dict range @@ -819,10 +840,10 @@ namespace eval textblock { if {$r == $rmax} { set joins [lremove $joins [lsearch $joins down*]] set bmap $botmap - set blims $boxlimits + set blims $blims_bot } else { set bmap $midmap - set blims $blims_mid ;#will only be reduced from boxlimits if -show_separators was processed above + set blims $blims_mid ;#will only be reduced from boxlimits if -show_seps was processed above } append output [textblock::frame -type [dict get $ftypes body] -ansibase $ansibase -ansiborder $border_ansi_final -boxlimits $blims -boxmap $bmap -joins $joins $c]\n } @@ -1102,16 +1123,16 @@ namespace eval textblock { namespace eval ::term::ansi::code::macros::cd {namespace export -clear} } - proc list_as_table {datalist table_or_colcount args} { + proc list_as_table {table_or_colcount datalist args} { set defaults [dict create\ -return string\ -frametype \uFFEF\ -show_edge \uFFEF\ - -show_separators \uFFEF\ + -show_seps \uFFEF\ ] foreach {k v} $args { switch -- $k { - -return - -show_edge - -show_separators - -frametype {} + -return - -show_edge - -show_seps - -frametype {} default { error "unrecognised option '$k'. Known options [dict keys $defaults]" } @@ -1132,10 +1153,10 @@ namespace eval textblock { if {[dict get $opts -show_edge] eq "\uFFEF"} { dict set opts -show_edge 1 } - if {[dict get $opts -show_separators] eq "\uFFEF"} { - dict set opts -show_separators 1 + if {[dict get $opts -show_seps] eq "\uFFEF"} { + dict set opts -show_seps 1 } - set t [textblock::class::table new -show_header 0 -show_edge [dict get $opts -show_edge] -frametype [dict get $opts -frametype] -show_separators [dict get $opts -show_separators]] + set t [textblock::class::table new -show_header 0 -show_edge [dict get $opts -show_edge] -frametype [dict get $opts -frametype] -show_seps [dict get $opts -show_seps]] for {set c 0} {$c < $cols} {incr c} { $t add_column -header c$c }