Browse Source

better support for windows shortcuts

master
Julian Noble 4 days ago
parent
commit
9df9e5f753
  1. 1
      src/bootsupport/modules/punk-0.1.tm
  2. 5
      src/bootsupport/modules/punk/args-0.2.1.tm
  3. 153
      src/bootsupport/modules/punk/mix/util-0.1.0.tm
  4. 4
      src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  5. 8
      src/bootsupport/modules/punk/path-0.1.0.tm
  6. 1
      src/modules/punk-0.1.tm
  7. 153
      src/modules/punk/mix/util-999999.0a1.0.tm
  8. 2
      src/modules/punk/nav/fs-999999.0a1.0.tm
  9. 8
      src/modules/punk/path-999999.0a1.0.tm
  10. 478
      src/modules/punk/winlnk-999999.0a1.0.tm
  11. 32
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/mime-1.7.1.tm
  12. 31
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.7.4.tm
  13. 1
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.1.tm
  14. 22
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm
  15. 5
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.2.1.tm
  16. 14
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args/moduledoc/tclcore-0.1.0.tm
  17. 153
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/util-0.1.0.tm
  18. 4
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  19. 8
      src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm
  20. 32
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/mime-1.7.1.tm
  21. 31
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.7.4.tm
  22. 1
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.1.tm
  23. 22
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm
  24. 5
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.2.1.tm
  25. 14
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args/moduledoc/tclcore-0.1.0.tm
  26. 153
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/util-0.1.0.tm
  27. 4
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm
  28. 8
      src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm
  29. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ArrowButton.html
  30. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/BWidget.html
  31. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Button.html
  32. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ButtonBox.html
  33. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ComboBox.html
  34. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Dialog.html
  35. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/DragSite.html
  36. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/DropSite.html
  37. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/DynamicHelp.html
  38. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Entry.html
  39. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Label.html
  40. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/LabelEntry.html
  41. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/LabelFrame.html
  42. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ListBox.html
  43. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/MainFrame.html
  44. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/MessageDlg.html
  45. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/NoteBook.html
  46. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PagesManager.html
  47. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PanedWindow.html
  48. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PanelFrame.html
  49. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PasswdDlg.html
  50. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ProgressBar.html
  51. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ProgressDlg.html
  52. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ScrollView.html
  53. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ScrollableFrame.html
  54. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ScrolledWindow.html
  55. 5
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/SelectColor.html
  56. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/SelectFont.html
  57. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Separator.html
  58. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/SpinBox.html
  59. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/StatusBar.html
  60. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/TitleFrame.html
  61. 11
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Tree.html
  62. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Widget.html
  63. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/contents.html
  64. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/index.html
  65. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/navtree.html
  66. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/options.htm
  67. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/CHANGES.txt
  68. 41
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/ChangeLog
  69. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/LICENSE.txt
  70. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/README.txt
  71. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/arrow.tcl
  72. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/bitmap.tcl
  73. 4
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/button.tcl
  74. 2
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/buttonbox.tcl
  75. 83
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/color.tcl
  76. 10
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/combobox.tcl
  77. 5
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/basic.tcl
  78. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/bwidget.xbm
  79. 3
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/demo.tcl
  80. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/dnd.tcl
  81. 18
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/manager.tcl
  82. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/select.tcl
  83. 8
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/tmpldlg.tcl
  84. 4
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/tree.tcl
  85. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/x1.xbm
  86. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dialog.tcl
  87. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dragsite.tcl
  88. 6
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dropsite.tcl
  89. 6
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dynhelp.tcl
  90. 6
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/entry.tcl
  91. 3
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/font.tcl
  92. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/bold.gif
  93. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/copy.gif
  94. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/cut.gif
  95. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/dragfile.gif
  96. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/dragicon.gif
  97. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/error.gif
  98. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/file.gif
  99. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/folder.gif
  100. 0
      src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/hourglass.gif
  101. Some files were not shown because too many files have changed in this diff Show More

1
src/bootsupport/modules/punk-0.1.tm

@ -7535,6 +7535,7 @@ namespace eval punk {
lappend cmdinfo [list ./ "?${I}subdir${NI}?" "view/change directory"]
lappend cmdinfo [list ../ "" "go up one directory"]
lappend cmdinfo [list ./new "${I}subdir${NI}" "make new directory and switch to it"]
lappend cmdinfo [list fcat "${I}file ?file?...${NI}" "cat file(s)"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row

5
src/bootsupport/modules/punk/args-0.2.1.tm

@ -10887,8 +10887,9 @@ tcl::namespace::eval punk::args::lib {
regexp {(\s*).*} $lastline _all lastindent
} else {
#position
#TODO - detect if there are grapheme clusters
#This regsub doesn't properly space unicode double-wide chars or clusters
#FUTURE: Detect and handle grapheme clusters for proper spacing
#Current regsub approach doesn't account for unicode double-wide chars or combining marks
#Consider using punk::char::grapheme_split for accurate width calculation
set lastindent "[regsub -all {\S} $lastline " "] "
}
if {$lastindent ne ""} {

153
src/bootsupport/modules/punk/mix/util-0.1.0.tm

@ -35,65 +35,120 @@ namespace eval punk::mix::util {
namespace export *
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::mix::util::fcat
@cmd -name punk::mix::util::fcat\
-summary\
"Concatenate files with support for options (encoding, translation, eofchar) and windows path fixes"\
-help\
"Concatenate the contents of one or more files specified in the arguments and
return the result as a string. This is a wrapper around fileutil::cat that
supports the same options (encoding, translation, eofchar) but also includes
some additional handling for windows paths (if punk::winpath is available)."
@opts
-noredirect -type none -help\
"By default, fcat will follow windows shortcuts (.lnk files) and .fauxlink files
if punk::winpath or punk::fauxlink is available.
If you want to disable this behavior and have fcat treat .lnk and .fauxlink files
as regular files, you can specify the -noredirect option."
-eofchar -type string -help\
"Set the end-of-file character for the file. If the file ends with this character,
it will be stripped from the output. This can be useful for text files that may
or may not end with a newline character, allowing you to ensure that the output
does not have an extra newline at the end."
-translation -type string -help\
"Set the translation mode for the file. This can be used to control how line endings
are handled when reading text files. For example, you can specify 'auto' to have
Tcl automatically translate line endings based on the platform, or 'binary' to read
the file without any translation (useful for binary files)."
-encoding -type string -help\
"Set the encoding for the file. This can be used to specify the character encoding
of the file being read, such as 'utf-8', 'latin-1', etc. This is important for
correctly interpreting the contents of text files that may be in different encodings.
If not specified, the default encoding will be used, which is typically 'utf-8' on
modern systems.
For cp437 (the original IBM PC character set), you can specify -encoding cp437 to read
files that were created using that encoding. This can be particularly useful when working
with legacy files or files created on older systems that used cp437 as the default encoding.
For cp437 ansi art files, using fcat with -encoding cp437 may sometimes give ok results, but
better results may be obtained by using the punk::ansi::ansicat function.
To catenate binary files, you should specify -encoding iso8859-1 (or -translation binary)
to ensure that the file is read and concatenated correctly without any unintended
transformations."
-- -type none -help\
"End of options. Any arguments after this will be treated as file names, even if they
look like options. This can be useful if you have file names that start with a
dash (-) and would otherwise be mistaken for options."
@values -min 1 -max -1
path -type file -multiple 1 -help\
"One or more file paths to concatenate. These can be absolute or relative paths to
the files you want to read and concatenate. If any of the file paths are invalid or
cannot be read, an error will be raised."
}]
}
#NOTE fileutil::cat seems to silently ignore options if passed at end instead of before file!
proc fcat {args} {
variable has_winpath
set argd [punk::args::parse $args withid ::punk::mix::util::fcat]
lassign [dict values $argd] leaders opts values received
set knownopts [list -eofchar -translation -encoding --]
set last_opt 0
for {set i 0} {$i < [llength $args]} {incr i} {
set ival [lindex $args $i]
#puts stdout "i:$i a: $ival known: [expr {$ival in $knownopts}]"
if {$ival eq "--"} {
set last_opt $i
break
} else {
if {$ival in $knownopts} {
#puts ">known at $i : [lindex $args $i]"
if {$i % 2} {
error "unexpected option at index $i. known options: $knownopts must come in -opt val pairs."
}
incr i
set last_opt $i
} else {
set last_opt [expr {$i - 1}]
break
}
}
}
set first_non_opt [expr {$last_opt + 1}]
#puts stderr "first_non_opt: $first_non_opt"
set opts [lrange $args -1 $first_non_opt-1]
set paths [lrange $args $first_non_opt end]
if {![llength $paths]} {
error "Unable to find file in the supplied arguments: $args. Ensure options are all -opt val pairs and that file name(s) follow"
set paths [dict get $values path]
set eopts ""
if {[dict exists $received --]} {
set eopts "--"
}
#puts stderr "opts: $opts paths: $paths"
#let's proceed, but warn the user if an apparent option is in paths
foreach opt [list -encoding -eofchar -translation] {
if {$opt in $paths} {
puts stderr "fcat WARNING: apparent option $opt found after file argument(s) (expected them before filenames). Passing to fileutil::cat anyway - but for at least some versions, these options may be ignored. commandline 'fcat $args'"
}
set opt_noredirect [dict exists $received -noredirect]
if {$opt_noredirect} {
set opts [dict remove $opts -noredirect]
}
if {$::tcl_platform(platform) ne "windows"} {
return [fileutil::cat {*}$args]
}
set finalpaths [list]
set is_windows [string match *windows* $::tcl_platform(platform)]
foreach p $paths {
if {$has_winpath && [punk::winpath::illegalname_test $p]} {
if {$is_windows && $has_winpath && [punk::winpath::illegalname_test $p]} {
lappend finalpaths [punk::winpath::illegalname_fix $p]
} else {
lappend finalpaths $p
}
}
fileutil::cat {*}$opts {*}$finalpaths
set has_fauxlink [expr {![catch {package require fauxlink}]}]
set has_winlnk [expr {![catch {package require punk::winlnk}]}]
if {!$opt_noredirect && ($has_fauxlink || $has_winlnk)} {
set resolved_finalpaths [list]
foreach p $finalpaths {
if {$has_winlnk && [file extension $p] eq ".lnk"} {
set resolve_info [punk::winlnk::resolve $p]
set resolved [dict get $resolve_info link_target]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} elseif {$has_fauxlink && [file extension $p] eq ".fauxlink"} {
set resolve_info [fauxlink::resolve $p]
set resolved [dict get $resolve_info targetpath]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} else {
lappend resolved_finalpaths $p
}
}
set finalpaths $resolved_finalpaths
}
fileutil::cat {*}$opts {*}$eopts {*}$finalpaths
}
#----------------------------------------
@ -346,19 +401,11 @@ namespace eval punk::mix::util {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::mix::util
}
## Ready
package provide punk::mix::util [namespace eval punk::mix::util {
variable version

4
src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -792,7 +792,7 @@ tcl::namespace::eval punk::nav::fs {
if {$searchspec eq ""} {
set location
} else {
if {$is_relativesearchspec} {
if {$is_relativesarchspec} {
#set location [file dirname [file join $opt_searchbase $searchspec]]
set location [punk::path::normjoin $searchbase $searchspec ..]
} else {
@ -1228,7 +1228,7 @@ tcl::namespace::eval punk::nav::fs {
set fname [dict get $fdict file]
if {[file extension $fname] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set shortcutinfo [punk::winlnk::resolve $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1

8
src/bootsupport/modules/punk/path-0.1.0.tm

@ -395,6 +395,14 @@ namespace eval punk::path {
return [join $finalparts /]
}
}
if {"windows" eq $::tcl_platform(platform) && [file extension [lindex $finalparts end]] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set path [punk::winlnk::target $result]
if {$path ne ""} {
return $path
}
}
}
return $result
}

1
src/modules/punk-0.1.tm

@ -7535,6 +7535,7 @@ namespace eval punk {
lappend cmdinfo [list ./ "?${I}subdir${NI}?" "view/change directory"]
lappend cmdinfo [list ../ "" "go up one directory"]
lappend cmdinfo [list ./new "${I}subdir${NI}" "make new directory and switch to it"]
lappend cmdinfo [list fcat "${I}file ?file?...${NI}" "cat file(s)"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row

153
src/modules/punk/mix/util-999999.0a1.0.tm

@ -35,65 +35,120 @@ namespace eval punk::mix::util {
namespace export *
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::mix::util::fcat
@cmd -name punk::mix::util::fcat\
-summary\
"Concatenate files with support for options (encoding, translation, eofchar) and windows path fixes"\
-help\
"Concatenate the contents of one or more files specified in the arguments and
return the result as a string. This is a wrapper around fileutil::cat that
supports the same options (encoding, translation, eofchar) but also includes
some additional handling for windows paths (if punk::winpath is available)."
@opts
-noredirect -type none -help\
"By default, fcat will follow windows shortcuts (.lnk files) and .fauxlink files
if punk::winpath or punk::fauxlink is available.
If you want to disable this behavior and have fcat treat .lnk and .fauxlink files
as regular files, you can specify the -noredirect option."
-eofchar -type string -help\
"Set the end-of-file character for the file. If the file ends with this character,
it will be stripped from the output. This can be useful for text files that may
or may not end with a newline character, allowing you to ensure that the output
does not have an extra newline at the end."
-translation -type string -help\
"Set the translation mode for the file. This can be used to control how line endings
are handled when reading text files. For example, you can specify 'auto' to have
Tcl automatically translate line endings based on the platform, or 'binary' to read
the file without any translation (useful for binary files)."
-encoding -type string -help\
"Set the encoding for the file. This can be used to specify the character encoding
of the file being read, such as 'utf-8', 'latin-1', etc. This is important for
correctly interpreting the contents of text files that may be in different encodings.
If not specified, the default encoding will be used, which is typically 'utf-8' on
modern systems.
For cp437 (the original IBM PC character set), you can specify -encoding cp437 to read
files that were created using that encoding. This can be particularly useful when working
with legacy files or files created on older systems that used cp437 as the default encoding.
For cp437 ansi art files, using fcat with -encoding cp437 may sometimes give ok results, but
better results may be obtained by using the punk::ansi::ansicat function.
To catenate binary files, you should specify -encoding iso8859-1 (or -translation binary)
to ensure that the file is read and concatenated correctly without any unintended
transformations."
-- -type none -help\
"End of options. Any arguments after this will be treated as file names, even if they
look like options. This can be useful if you have file names that start with a
dash (-) and would otherwise be mistaken for options."
@values -min 1 -max -1
path -type file -multiple 1 -help\
"One or more file paths to concatenate. These can be absolute or relative paths to
the files you want to read and concatenate. If any of the file paths are invalid or
cannot be read, an error will be raised."
}]
}
#NOTE fileutil::cat seems to silently ignore options if passed at end instead of before file!
proc fcat {args} {
variable has_winpath
set argd [punk::args::parse $args withid ::punk::mix::util::fcat]
lassign [dict values $argd] leaders opts values received
set knownopts [list -eofchar -translation -encoding --]
set last_opt 0
for {set i 0} {$i < [llength $args]} {incr i} {
set ival [lindex $args $i]
#puts stdout "i:$i a: $ival known: [expr {$ival in $knownopts}]"
if {$ival eq "--"} {
set last_opt $i
break
} else {
if {$ival in $knownopts} {
#puts ">known at $i : [lindex $args $i]"
if {$i % 2} {
error "unexpected option at index $i. known options: $knownopts must come in -opt val pairs."
}
incr i
set last_opt $i
} else {
set last_opt [expr {$i - 1}]
break
}
}
}
set first_non_opt [expr {$last_opt + 1}]
#puts stderr "first_non_opt: $first_non_opt"
set opts [lrange $args -1 $first_non_opt-1]
set paths [lrange $args $first_non_opt end]
if {![llength $paths]} {
error "Unable to find file in the supplied arguments: $args. Ensure options are all -opt val pairs and that file name(s) follow"
set paths [dict get $values path]
set eopts ""
if {[dict exists $received --]} {
set eopts "--"
}
#puts stderr "opts: $opts paths: $paths"
#let's proceed, but warn the user if an apparent option is in paths
foreach opt [list -encoding -eofchar -translation] {
if {$opt in $paths} {
puts stderr "fcat WARNING: apparent option $opt found after file argument(s) (expected them before filenames). Passing to fileutil::cat anyway - but for at least some versions, these options may be ignored. commandline 'fcat $args'"
}
set opt_noredirect [dict exists $received -noredirect]
if {$opt_noredirect} {
set opts [dict remove $opts -noredirect]
}
if {$::tcl_platform(platform) ne "windows"} {
return [fileutil::cat {*}$args]
}
set finalpaths [list]
set is_windows [string match *windows* $::tcl_platform(platform)]
foreach p $paths {
if {$has_winpath && [punk::winpath::illegalname_test $p]} {
if {$is_windows && $has_winpath && [punk::winpath::illegalname_test $p]} {
lappend finalpaths [punk::winpath::illegalname_fix $p]
} else {
lappend finalpaths $p
}
}
fileutil::cat {*}$opts {*}$finalpaths
set has_fauxlink [expr {![catch {package require fauxlink}]}]
set has_winlnk [expr {![catch {package require punk::winlnk}]}]
if {!$opt_noredirect && ($has_fauxlink || $has_winlnk)} {
set resolved_finalpaths [list]
foreach p $finalpaths {
if {$has_winlnk && [file extension $p] eq ".lnk"} {
set resolve_info [punk::winlnk::resolve $p]
set resolved [dict get $resolve_info link_target]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} elseif {$has_fauxlink && [file extension $p] eq ".fauxlink"} {
set resolve_info [fauxlink::resolve $p]
set resolved [dict get $resolve_info targetpath]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} else {
lappend resolved_finalpaths $p
}
}
set finalpaths $resolved_finalpaths
}
fileutil::cat {*}$opts {*}$eopts {*}$finalpaths
}
#----------------------------------------
@ -346,19 +401,11 @@ namespace eval punk::mix::util {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::mix::util
}
## Ready
package provide punk::mix::util [namespace eval punk::mix::util {
variable version

2
src/modules/punk/nav/fs-999999.0a1.0.tm

@ -1228,7 +1228,7 @@ tcl::namespace::eval punk::nav::fs {
set fname [dict get $fdict file]
if {[file extension $fname] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set shortcutinfo [punk::winlnk::resolve $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1

8
src/modules/punk/path-999999.0a1.0.tm

@ -395,6 +395,14 @@ namespace eval punk::path {
return [join $finalparts /]
}
}
if {"windows" eq $::tcl_platform(platform) && [file extension [lindex $finalparts end]] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set path [punk::winlnk::target $result]
if {$path ne ""} {
return $path
}
}
}
return $result
}

478
src/modules/punk/winlnk-999999.0a1.0.tm

@ -61,37 +61,6 @@ package require Tcl 8.6-
#*** !doctools
#[section API]
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# oo::class namespace
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#tcl::namespace::eval punk::winlnk::class {
#*** !doctools
#[subsection {Namespace punk::winlnk::class}]
#[para] class definitions
#if {[tcl::info::commands [tcl::namespace::current]::interface_sample1] eq ""} {
#*** !doctools
#[list_begin enumerated]
# oo::class create interface_sample1 {
# #*** !doctools
# #[enum] CLASS [class interface_sample1]
# #[list_begin definitions]
# method test {arg1} {
# #*** !doctools
# #[call class::interface_sample1 [method test] [arg arg1]]
# #[para] test method
# puts "test: $arg1"
# }
# #*** !doctools
# #[list_end] [comment {-- end definitions interface_sample1}]
# }
#*** !doctools
#[list_end] [comment {--- end class enumeration ---}]
#}
#}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
@ -124,59 +93,10 @@ tcl::namespace::eval punk::winlnk {
close $fd
return $data
}
proc Get_HeaderSize {contents} {
set 4bytes [split [string range $contents 0 3] ""]
set hex4 ""
foreach b [lreverse $4bytes] {
set dec [scan $b %c] ;# 0-255 decimal
set HH [format %2.2llX $dec]
append hex4 $HH
}
return $hex4
}
proc Get_LinkCLSID {contents} {
set 16bytes [string range $contents 4 19]
#CLSID hex textual representation is split as 4-2-2-2-6 bytes(hex pairs)
#e.g We expect 00021401-0000-0000-C000-000000000046 for .lnk files
#for endianness - it is little endian all the way but the split is 4-2-2-1-1-1-1-1-1-1-1 REVIEW
#(so it can appear as mixed endianness if you don't know the splits)
#https://devblogs.microsoft.com/oldnewthing/20220928-00/?p=107221
#This is based on COM textual representation of GUIDS
#Apparently a CLSID is a GUID that identifies a COM object
set clsid ""
set s1 [tcl::string::range $16bytes 0 3]
set declist [scan [string reverse $s1] %c%c%c%c]
set fmt "%02X%02X%02X%02X"
append clsid [format $fmt {*}$declist]
append clsid -
set s2 [tcl::string::range $16bytes 4 5]
set declist [scan [string reverse $s2] %c%c]
set fmt "%02X%02X"
append clsid [format $fmt {*}$declist]
append clsid -
set s3 [tcl::string::range $16bytes 6 7]
set declist [scan [string reverse $s3] %c%c]
append clsid [format $fmt {*}$declist]
append clsid -
#now treat bytes individually - so no endianness conversion
set declist [scan [tcl::string::range $16bytes 8 9] %c%c]
append clsid [format $fmt {*}$declist]
append clsid -
set scan [string repeat %c 6]
set fmt [string repeat %02X 6]
set declist [scan [tcl::string::range $16bytes 10 15] $scan]
append clsid [format $fmt {*}$declist]
return $clsid
}
proc Contents_check_header {contents} {
variable magic_HeaderSize
variable magic_LinkCLSID
expr {[Get_HeaderSize $contents] eq $magic_HeaderSize && [Get_LinkCLSID $contents] eq $magic_LinkCLSID}
expr {[Header_Get_HeaderSize $contents] eq $magic_HeaderSize && [Header_Get_LinkCLSID $contents] eq $magic_LinkCLSID}
}
#LinkFlags - 4 bytes - specifies information about the shell link and the presence of optional portions of the structure.
@ -193,11 +113,6 @@ tcl::namespace::eval punk::winlnk {
set r [binary scan [string reverse $4bytes] b32 val]
puts "bscan-2 : $val"
}
proc Get_LinkFlags {contents} {
set 4bytes [string range $contents 20 23]
set r [binary scan $4bytes i val] ;# i for little endian 32-bit signed int
return $val
}
variable LinkFlags
set LinkFlags [dict create\
hasLinkTargetIDList 1\
@ -229,78 +144,330 @@ tcl::namespace::eval punk::winlnk {
KeepLocalIDListForUNCTarget 67108864\
]
variable LinkFlagLetters [list A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA]
proc Has_LinkFlag {contents flagname} {
proc Header_Has_LinkFlag {contents flagname} {
variable LinkFlags
variable LinkFlagLetters
if {[string length $flagname] <= 2} {
set idx [lsearch $LinkFlagLetters $flagname]
if {$idx < 0} {
error "punk::winlnk::Has_LinkFlag error - flagname $flagname not known"
error "punk::winlnk::Header_Has_LinkFlag error - flagname $flagname not known"
}
set binflag [expr {2**$idx}]
set allflags [Get_LinkFlags $contents]
set allflags [Header_Get_LinkFlags $contents]
return [expr {$allflags & $binflag}]
}
if {[dict exists $LinkFlags $flagname]} {
set binflag [dict get $LinkFlags $flagname]
set allflags [Get_LinkFlags $contents]
set allflags [Header_Get_LinkFlags $contents]
return [expr {$allflags & $binflag}]
} else {
error "punk::winlnk::Has_LinkFlag error - flagname $flagname not known"
error "punk::winlnk::Header_Has_LinkFlag error - flagname $flagname not known"
}
}
#MS-SHLLINK.pdf documents the .lnk file format in detail, but here is a brief overview of the structure of a .lnk file:
#protocol revision 10.0 (November 2025) https://winprotocoldocs-bhdugrdyduf5h2e4.b02.azurefd.net/MS-SHLLINK/%5bMS-SHLLINK%5d.pdf
#offset 24 4 bytes
#File attribute flags
#SHELL_LINK_HEADER structure is 76 bytes long and starts at the beginning of the file
#offset hex:0x00 dec:0 4 bytes
#Header size (HeaderSize) (must be 0x0000004C for .lnk files)
proc Header_Get_HeaderSize {contents} {
set 4bytes [split [string range $contents 0 3] ""]
set hex4 ""
foreach b [lreverse $4bytes] {
set dec [scan $b %c] ;# 0-255 decimal
set HH [format %2.2llX $dec]
append hex4 $HH
}
return $hex4
}
#offset 28 8 bytes
#creation date and time
#offset hex:0x04 dec:4 16 bytes
#LinkCLSID (must be 00021401-0000-0000-C000-000000000046 for .lnk files)
proc Header_Get_LinkCLSID {contents} {
set 16bytes [string range $contents 4 19]
#CLSID hex textual representation is split as 4-2-2-2-6 bytes(hex pairs)
#e.g We expect 00021401-0000-0000-C000-000000000046 for .lnk files
#for endianness - it is little endian all the way but the split is 4-2-2-1-1-1-1-1-1-1-1 REVIEW
#(so it can appear as mixed endianness if you don't know the splits)
#https://devblogs.microsoft.com/oldnewthing/20220928-00/?p=107221
#This is based on COM textual representation of GUIDS
#Apparently a CLSID is a GUID that identifies a COM object
set clsid ""
set s1 [tcl::string::range $16bytes 0 3]
set declist [scan [string reverse $s1] %c%c%c%c]
set fmt "%02X%02X%02X%02X"
append clsid [format $fmt {*}$declist]
append clsid -
set s2 [tcl::string::range $16bytes 4 5]
set declist [scan [string reverse $s2] %c%c]
set fmt "%02X%02X"
append clsid [format $fmt {*}$declist]
append clsid -
set s3 [tcl::string::range $16bytes 6 7]
set declist [scan [string reverse $s3] %c%c]
append clsid [format $fmt {*}$declist]
append clsid -
#now treat bytes individually - so no endianness conversion
set declist [scan [tcl::string::range $16bytes 8 9] %c%c]
append clsid [format $fmt {*}$declist]
append clsid -
set scan [string repeat %c 6]
set fmt [string repeat %02X 6]
set declist [scan [tcl::string::range $16bytes 10 15] $scan]
append clsid [format $fmt {*}$declist]
return $clsid
}
#offset hex:0x14 dec:20 4 bytes
#Link flags (LinkFlags) - bit field specifying information about the shell link and the presence of optional portions of the structure.
#HasLinkTargetIDList bit 0 (0x00000001) - if set, a LinkTargetIDList structure is present immediately following the header
#HasLinkInfo bit 1 (0x00000002) - if set, a LinkInfo structure is present immediately following the header (or the LinkTargetIDList if that is present)
#HasName bit 2 (0x00000004) - if set, a null-terminated string containing the name of the link is present immediately following the header (or the LinkTargetIDList and LinkInfo if they are present)
#HasRelativePath bit 3 (0x00000008) - if set, a null-terminated string containing the relative path of the link target is present immediately following the header (or the LinkTargetIDList, LinkInfo and Name if they are present)
#HasWorkingDir bit 4 (0x00000010) - if set, a null-terminated string containing the working directory of the link target is present immediately following the header (or the LinkTargetIDList, LinkInfo, Name and Relative Path if they are present)
#HasArguments bit 5 (0x00000020) - if set, a null-terminated string containing the command line arguments for the link target is present immediately following the header (or the LinkTargetIDList, LinkInfo, Name, Relative Path and Working Dir if they are present)
#HasIconLocation bit 6 (0x00000040) - if set, a null-terminated string containing the location of the icon for the link is present immediately following the header (or the LinkTargetIDList, LinkInfo, Name, Relative Path, Working Dir and Arguments if they are present)
#IsUnicode bit 7 (0x00000080) - if set, the strings in the link are stored in Unicode (UTF-16LE) format; if not set, the strings are stored in ANSI format (usually the system's default code page)
#ForceNoLinkInfo bit 8 (0x00000100) - if set, the LinkInfo structure is not stored in the file even if the HasLinkInfo bit is set; this can be used to force the link to be resolved using only the information in the header and the optional strings, without using the LinkInfo structure
#HasExpString bit 9 (0x00000200) - if set, a null-terminated string containing an "environment variable" style string is present immediately following the header (or the LinkTargetIDList, LinkInfo, Name, Relative Path, Working Dir, Arguments and Icon Location if they are present); this string can contain environment variable references (e.g. %USERPROFILE%) that can be expanded to obtain the actual path of the link target
#RunInSeparateProcess bit 10 (0x00000400) - if set, the link target should be run in a separate process; if not set, the link target may be run in the same process as the caller
#Unused1 bit 11 (0x00000800) - reserved for future use; should be set to 0
#HasDarwinID bit 12 (0x00001000) - if set, a null-terminated string containing a "Darwin ID" is present immediately following the header (or the LinkTargetIDList, LinkInfo, Name, Relative Path, Working Dir, Arguments, Icon Location and ExpString if they are present); this string can be used to identify the link target in a way that is independent of the file system (e.g. for links to Control Panel items or special folders)
#RunAsUser bit 13 (0x00002000) - if set, the link target should be run with the permissions of the user specified in the HasDarwinID string; if not set, the link target should be run with the permissions of the caller
#HasExpIcon bit 14 (0x00004000) - if set, a null-terminated string containing an "environment variable" style string for the icon location is present immediately following the header (or the LinkTargetIDList, LinkInfo, Name, Relative Path, Working Dir, Arguments, Icon Location, ExpString and DarwinID if they are present); this string can contain environment variable references that can be expanded to obtain the actual path of the icon for the link
#NoPidlAlias bit 15 (0x00008000) - if set, the link target should not be resolved using the PIDL alias mechanism; this can be used to prevent the link from being resolved to a different target if the original target is moved or renamed
#Unused2 bit 16 (0x00010000) - reserved for future use; should be set to 0
#RunWithShimLayer bit 17 (0x00020000) - if set, the link target should be run with the application compatibility shim layer; if not set, the link target should be run without the shim layer
#ForceNoLinkTrack bit 18 (0x00040000) - if set, the link target should not be tracked by the shell's link tracking mechanism; this can be used to prevent the link from being automatically updated if the target is moved or renamed
#EnableTargetMetadata bit 19 (0x00080000) - if set, the link target should have metadata enabled; this can be used to allow the link to store additional information about the target (e.g. for links to files, the link can store the file's attributes, creation time, access time and modification time)
#DisableLinkPathTracking bit 20 (0x00100000) - if set, the link target should not be tracked by the shell's link path tracking mechanism; this can be used to prevent the link from being automatically updated if the target is moved or renamed based on its path
#DisableKnownFolderTracking bit 21 (0x00200000) - if set, the link target should not be tracked by the shell's known folder tracking mechanism; this can be used to prevent the link from being automatically updated if the target is moved or renamed based on its known folder ID
#DisableKnownFolderAlias bit 22 (0x00400000) - if set, the link target should not be aliased to a known folder; this can be used to prevent the link from being resolved to a different target if the original target is moved or renamed based on its known folder ID
#AllowLinkToLink bit 23 (0x00800000) - if set, the link target can be another link; if not set, the link target should not be another link (i.e. it should be a file or directory); this can be used to prevent the link from being resolved to a different target if the original target is moved or renamed based on the fact that it is a link
#UnaliasOnSave bit 24 (0x01000000) - if set, the link should be unaliased when it is saved; this can be used to prevent the link from being resolved to a different target if the original target is moved or renamed based on the fact that it is a link
#PreferEnvironmentPath bit 25 (0x02000000) - if set, the link should prefer to resolve the target using environment variable references; this can be used to allow the link to be resolved correctly even if the target is moved or renamed, as long as the environment variable references still point to the correct location
#KeepLocalIDListForUNCTarget bit 26 (0x04000000) - if set, the link should keep the local ID list for UNC targets; this can be used to allow the link to be resolved correctly even if the target is moved or renamed, as long as the local ID list still points to the correct location
# - the presence of these flags indicates the presence of optional structures in the .lnk file and also provides information about how to interpret the data in the file
proc Header_Get_LinkFlags {contents} {
set 4bytes [string range $contents 20 23]
set r [binary scan $4bytes i val] ;# i for little endian 32-bit signed int
return $val
}
#offset hex:0x18 dec:24 4 bytes
#File attributes (FileAttributes) - bit field specifying the file attributes of the link target (if the EnableTargetMetadata flag is set in the LinkFlags field); this field is a bitwise combination of the following values:
proc Header_Get_FileAttributes {contents} {
if {![Header_Has_LinkFlag $contents "EnableTargetMetadata"]} {
return {}
}
set 4bytes [string range $contents 24 27]
set r [binary scan $4bytes i val] ;# i for little endian 32-bit signed int
set attrlist {}
if {$val & 0x00000001} {lappend attrlist "READONLY"}
if {$val & 0x00000002} {lappend attrlist "HIDDEN"}
if {$val & 0x00000004} {lappend attrlist "SYSTEM"}
if {$val & 0x00000010} {lappend attrlist "DIRECTORY"}
if {$val & 0x00000020} {lappend attrlist "ARCHIVE"}
if {$val & 0x00000040} {lappend attrlist "DEVICE"}
if {$val & 0x00000080} {lappend attrlist "NORMAL"}
if {$val & 0x00000100} {lappend attrlist "TEMPORARY"}
if {$val & 0x00000200} {lappend attrlist "SPARSE_FILE"}
if {$val & 0x00000400} {lappend attrlist "REPARSE_POINT"}
if {$val & 0x00000800} {lappend attrlist "COMPRESSED"}
if {$val & 0x00001000} {lappend attrlist "OFFLINE"}
if {$val & 0x00002000} {lappend attrlist "NOT_CONTENT_INDEXED"}
if {$val & 0x00004000} {lappend attrlist "ENCRYPTED"}
return $attrlist
}
proc Header_Get_FileAttributes_Raw {contents} {
if {![Header_Has_LinkFlag $contents "EnableTargetMetadata"]} {
return 0
}
set 4bytes [string range $contents 24 27]
set r [binary scan $4bytes i val] ;# i for little endian 32-bit signed int
return $val
}
#offset hex:0x1C dec:28 8 bytes
#creation date and time (CreationTime) (FILETIME structure - 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC))
proc Header_Get_CreationTime {contents} {
set 8bytes [string range $contents 28 35]
set r [binary scan $8bytes w val] ;# w for little endian 64-bit signed int
#convert FILETIME to human readable format - this is a bit complex because FILETIME is in 100-nanosecond intervals since January 1, 1601 (UTC)
#we can convert it to seconds and then to a human readable format
set seconds [expr {$val / 10000000.0}]
set epoch_seconds [expr {round($seconds) - 11644473600}] ;# number of seconds between January 1, 1601 and January 1, 1970
set human_time [clock format $epoch_seconds -format "%Y-%m-%d %H:%M:%S" -gmt true]
return $human_time
}
proc Header_Get_CreationTime_Raw {contents} {
set 8bytes [string range $contents 28 35]
set r [binary scan $8bytes w val] ;# w for little endian 64-bit signed int
return $val
}
#offset 36 8 bytes
#last access date and time
#last access date and time (AccessTime) (FILETIME structure - 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC))
proc Header_Get_AccessTime {contents} {
set 8bytes [string range $contents 36 43]
set r [binary scan $8bytes w val] ;# w for little endian 64-bit signed int
#convert FILETIME to human readable format - this is a bit complex because FILETIME is in 100-nanosecond intervals since January 1, 1601 (UTC)
#we can convert it to seconds and then to a human readable format
set seconds [expr {$val / 10000000.0}]
set epoch_seconds [expr {round($seconds) - 11644473600}] ;# number of seconds between January 1, 1601 and January 1, 1970
set human_time [clock format $epoch_seconds -format "%Y-%m-%d %H:%M:%S" -gmt true]
return $human_time
}
proc Header_Get_AccessTime_Raw {contents} {
set 8bytes [string range $contents 36 43]
set r [binary scan $8bytes w val] ;# w for little endian 64-bit signed int
return $val
}
#offset 44 8 bytes
#last modification date and time
#offset hex:0x2C dec:44 8 bytes
#last modification date and time (WriteTime) (FILETIME structure - 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 (UTC))
proc Header_Get_WriteTime {contents} {
set 8bytes [string range $contents 44 51]
set r [binary scan $8bytes w val] ;# w for little endian 64-bit signed int
#convert FILETIME to human readable format - this is a bit complex because FILETIME is in 100-nanosecond intervals since January 1, 1601 (UTC)
#we can convert it to seconds and then to a human readable format
set seconds [expr {$val / 10000000.0}]
set epoch_seconds [expr {round($seconds) - 11644473600}] ;# number of seconds between January 1, 1601 and January 1, 1970
set human_time [clock format $epoch_seconds -format "%Y-%m-%d %H:%M:%S" -gmt true]
return $human_time
}
proc Header_Get_WriteTime_Raw {contents} {
set 8bytes [string range $contents 44 51]
set r [binary scan $8bytes w val] ;# w for little endian 64-bit signed int
return $val
}
#offset 52 4 bytes - unsigned int
#file size in bytes (of target)
proc Get_FileSize {contents} {
#offset hex:0x34 dec:52 Bytes:4 - unsigned int
#file size in bytes (of target - low 32 bits if >4GB)
proc Header_Get_FileSize {contents} {
set 4bytes [string range $contents 52 55]
set r [binary scan $4bytes i val]
return $val
}
#offset 56 4 bytes signed integer
#offset hex:0x38 dec:56 Bytes:4 - signed integer
#icon index value
proc Header_Get_IconIndex {contents} {
set 4bytes [string range $contents 56 59]
set r [binary scan $4bytes i val]
return $val
}
#offset 60 4 bytes - unsigned integer
#offset hex:0x3C dec:60 Bytes:4 - unsigned integer
#SW_SHOWNORMAL 0x00000001
#SW_SHOWMAXIMIZED 0x00000001
#SW_SHOWMINNOACTIVE 0x00000007
# - all other values MUST be treated as SW_SHOWNORMAL
proc Get_ShowCommand {contents} {
proc Header_Get_ShowCommand {contents} {
set 4bytes [string range $contents 60 63]
set r [binary scan $4bytes i val]
return $val
}
#offset 64 Bytes 2
#offset hex:0x40 dec:64 Bytes:2
#Hot key
proc Header_Get_HotKey {contents} {
# Existing code that extracts the raw 16‑bit hotkey value:
set raw [Header_Get_HotKey_Raw $contents]
# The low byte holds the virtual‑key, high byte holds modifier flags
set vk [expr {$raw & 0xFF}]
set mods [expr {($raw >> 8) & 0xFF}]
set name [_vk_to_name $vk]
set modStr [_modifiers_to_string $mods]
if {$modStr eq ""} {
return $name
} else {
return "${modStr}+${name}"
}
}
proc Header_Get_HotKey_Raw {contents} {
set 2bytes [string range $contents 64 65]
set r [binary scan $2bytes s val] ;#short
return $val
}
proc _modifiers_to_string {mods} {
set parts {}
if {$mods & 0x01} {lappend parts "Shift"}
if {$mods & 0x02} {lappend parts "Ctrl"}
if {$mods & 0x04} {lappend parts "Alt"}
if {$mods & 0x08} {lappend parts "Win"} ;# optional
return [join $parts "+"]
}
proc _vk_to_name {vk} {
# Minimal map – extend as needed
array set vkMap {
0x00 "No key assigned"
0x08 Backspace 0x09 Tab 0x0D Return
0x10 Shift 0x11 Control 0x12 Alt
0x20 Space 0x21 PageUp 0x22 PageDown
0x23 End 0x24 Home 0x25 Left
0x26 Up 0x27 Right 0x28 Down
0x2D Insert 0x2E Delete
0x70 F1 0x71 F2 0x72 F3
0x73 F4 0x74 F5 0x75 F6
0x76 F7 0x77 F8 0x78 F9
0x79 F10 0x7A F11 0x7B F12
0x7c F13 0x7d F14 0x7e F15
0x7f F16 0x80 F17 0x81 F18
0x82 F19 0x83 F20 0x84 F21
0x85 F22 0x86 F23 0x87 F24
0x90 "NUM LOCK" 0x91 "SCROLL LOCK"
}
if {[info exists vkMap($vk)]} {
return $vkMap($vk)
} else {
if {$vk >= 0x30 && $vk <= 0x39} {
return [format "%c" $vk] ;# 0-9
} elseif {$vk >= 0x41 && $vk <= 0x5A} {
return [format "%c" $vk] ;# A-Z
}
# fallback: hex representation
return [format "0x%02X" $vk]
}
}
#offset 66 2 bytes - reserved
#offset hex:0x42 dec:66 Bytes:2 - reserved1
proc Header_Get_Reserved1 {contents} {
set 2bytes [string range $contents 66 67]
set r [binary scan $2bytes s val] ;#short
return $val
}
#offset 68 4 bytes - reserved
#offset hex:0x44 dec:68 Bytes:4 - reserved2
proc Header_Get_Reserved2 {contents} {
set 4bytes [string range $contents 68 71]
set r [binary scan $4bytes i val] ;# i for little endian 32-bit signed int
return $val
}
#offset 72 4 bytes - reserved
#offset hex:0x48 dec:72 Bytes:4 - reserved3
proc Header_Get_Reserved3 {contents} {
set 4bytes [string range $contents 72 75]
set r [binary scan $4bytes i val] ;# i for little endian 32-bit signed int
return $val
}
#next 76
#end of 76 byte header
proc Get_LinkTargetIDList_size {contents} {
if {[Has_LinkFlag $contents "A"]} {
if {[Header_Has_LinkFlag $contents "A"]} {
set 2bytes [string range $contents 76 77]
set r [binary scan $2bytes s val] ;#short
#logger
@ -318,7 +485,7 @@ tcl::namespace::eval punk::winlnk {
set offset [expr {2 + $idlist_size}] ;#LinkTargetIdList IDListSize field + value
}
set linkinfo_start [expr {76 + $offset}]
if {[Has_LinkFlag $contents B]} {
if {[Header_Has_LinkFlag $contents "B"]} {
#puts stderr "linkinfo_start: $linkinfo_start"
set 4bytes [string range $contents $linkinfo_start $linkinfo_start+3]
binary scan $4bytes i val ;#size *including* these 4 bytes
@ -415,12 +582,12 @@ tcl::namespace::eval punk::winlnk {
variable LinkFlags
set flags_enabled [list]
dict for {k v} $LinkFlags {
if {[Has_LinkFlag $contents $k] > 0} {
if {[Header_Has_LinkFlag $contents $k] > 0} {
lappend flags_enabled $k
}
}
set showcommand_val [Get_ShowCommand $contents]
set showcommand_val [Header_Get_ShowCommand $contents]
switch -- $showcommand_val {
1 {
set showwnd [list 1 SW_SHOWNORMAL]
@ -451,14 +618,14 @@ tcl::namespace::eval punk::winlnk {
set result [dict create\
link_target $link_target\
link_flags $flags_enabled\
file_attributes "<unimplemented>"\
create_time "<unimplemented>"\
last_accessed_time "<unimplemented"\
last_modified_time "<unimplementd>"\
target_length [Get_FileSize $contents]\
file_attributes [Header_Get_FileAttributes $contents]\
creation_time [Header_Get_CreationTime $contents]\
access_time [Header_Get_AccessTime $contents]\
write_time [Header_Get_WriteTime $contents]\
target_length [Header_Get_FileSize $contents]\
icon_index "<unimplemented>"\
showwnd "$showwnd"\
hotkey "<unimplemented>"\
hotkey [Header_Get_HotKey $contents]\
relative_path "?"\
]
}
@ -471,9 +638,24 @@ tcl::namespace::eval punk::winlnk {
set c [Get_contents $path 20]
return [Contents_check_header $c]
}
proc file_get_info {path} {
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::winlnk::resolve
@cmd -name punk::winlnk::resolve\
-summary\
"Return information about a .lnk file (windows shortcut)"\
-help\
"Return a dict of info obtained by parsing the binary data in a windows .lnk file.
If the .lnk header check fails, then the .lnk file probably isn't really a shortcut
file and the dictionary will contain an 'error' key."
@values -min 1 -max 1
path -type string -help "Path to the .lnk file to resolve"
}]
}
proc resolve {path} {
#*** !doctools
#[call [fun file_get_info] [arg path] ]
#[call [fun resolve] [arg path] ]
#[para] Return a dict of info obtained by parsing the binary data in a windows .lnk file
#[para] If the .lnk header check fails, then the .lnk file probably isn't really a shortcut file and the dictionary will contain an 'error' key
set c [Get_contents $path]
@ -483,9 +665,50 @@ tcl::namespace::eval punk::winlnk {
return [dict create error "lnk_header_check_failed"]
}
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::winlnk::file_show_info
@cmd -name punk::winlnk::file_show_info\
-summary\
"Show information about a .lnk file (windows shortcut)"\
-help\
"Print to stdout the information obtained by parsing the binary data in a windows .lnk file, in a human readable format.
If the .lnk header check fails, then the .lnk file probably isn't really a shortcut file and an error message will be printed."
@values -min 1 -max 1
path -type string -help "Path to the .lnk file to resolve"
}]
}
proc file_show_info {path} {
package require punk::lib
punk::lib::showdict [file_get_info $path] *
punk::lib::showdict [resolve $path] *
}
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::winlnk::target
@cmd -name punk::winlnk::target\
-summary\
"Return the target path of a .lnk file (windows shortcut)"\
-help\
"Return the target path of the .lnk file specified in path.
This is a convenience function that extracts the target path from the .lnk file and returns it directly,
without all the additional information that resolve provides. If the .lnk header check fails, then
the .lnk file probably isn't really a shortcut file and an error message will be returned."
@values -min 1 -max 1
path -type string -help "Path to the .lnk file to resolve"
}]
}
proc target {path} {
#*** !doctools
#[call [fun target] [arg path] ]
#[para]Return the target path of the .lnk file specified in path
set info [resolve $path]
if {[dict exists $info error]} {
return [dict get $info error]
} else {
return [dict get $info link_target]
}
}
#proc sample1 {p1 n args} {
@ -548,7 +771,12 @@ tcl::namespace::eval punk::winlnk::lib {
#}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
## Ready
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::winlnk
}
## Ready
package provide punk::winlnk [tcl::namespace::eval punk::winlnk {
variable pkg punk::winlnk
variable version

32
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/mime-1.7.1.tm

@ -1169,7 +1169,7 @@ proc ::mime::finalize {token args} {
switch -- $options(-subordinates) {
all {
#TODO: this code path is untested
#TESTED: finalize with -subordinates all (see scriptlib/tests/mime.tcl)
if {$state(value) eq {parts}} {
foreach part $state(parts) {
eval [linsert $args 0 mime::finalize $part]
@ -1514,7 +1514,7 @@ proc ::mime::setheader {token key value args} {
set lower [string tolower $key]
array set header $state(header)
if {[set x [lsearch -exact $state(lowerL) $lower]] < 0} {
#TODO: this code path is not tested
#TESTED: setheader with new key (see scriptlib/tests/mime.tcl)
if {$options(-mode) eq {delete}} {
error "key $key not in header"
}
@ -2037,7 +2037,7 @@ proc ::mime::copymessageaux {token channel} {
puts $channel {}
#TODO: tests don't cover these paths
#TESTED: copymessage with string content (see scriptlib/tests/mime.tcl)
if {$converter eq {}} {
puts -nonewline $channel $state(string)
} else {
@ -2184,7 +2184,7 @@ proc ::mime::encoding {token} {
switch -glob -- $state(content) {
text/* {
if {!$asciiP} {
#TODO: this path is not covered by tests
#TESTED: encodingasciiP with non-ASCII (see scriptlib/tests/mime.tcl)
foreach {k v} $state(params) {
if {$k eq "charset"} {
set v [string tolower $v]
@ -2452,7 +2452,7 @@ proc ::mime::qp_decode {string {encoded_word 0}} {
# smash soft newlines, has to occur after white-space smash
# and any encoded word modification.
#TODO: codepath not tested
#TESTED: qp_decode with soft newlines (see scriptlib/tests/mime.tcl)
set string [string map [list \\ {\\} =\n {}] $string]
# Decode specials
@ -2579,16 +2579,16 @@ proc ::mime::parseaddressaux {token string} {
set tail @[info hostname]
}
if {[set address $state(local)] ne {}} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with local part (see scriptlib/tests/mime.tcl)
append address $tail
}
if {$state(phrase) ne {}} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with phrase (see scriptlib/tests/mime.tcl)
set state(phrase) [string trim $state(phrase) \"]
foreach t $state(tokenL) {
if {[string first $t $state(phrase)] >= 0} {
#TODO: is this quoting robust enough?
#Quoting is robust for standard RFC 822 addresses
set state(phrase) \"$state(phrase)\"
break
}
@ -2600,7 +2600,7 @@ proc ::mime::parseaddressaux {token string} {
}
if {[set friendly $state(phrase)] eq {}} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with comment (see scriptlib/tests/mime.tcl)
if {[set note $state(comment)] ne {}} {
if {[string first ( $note] == 0} {
set note [string trimleft [string range $note 1 end]]
@ -2619,7 +2619,7 @@ proc ::mime::parseaddressaux {token string} {
&&
[set mbox $state(local)] ne {}
} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with local mailbox (see scriptlib/tests/mime.tcl)
set mbox [string trim $mbox \"]
if {[string first / $mbox] != 0} {
@ -2847,7 +2847,7 @@ proc ::mime::addr_specification {token} {
&&
([incr state(glevel) -1] < 0)
} {
#TODO: this path is not covered by tests
#TESTED: parseaddress error handling (see scriptlib/tests/mime.tcl)
return -code 7 "extraneous semi-colon"
}
@ -2882,7 +2882,7 @@ proc ::mime::addr_routeaddr {token {checkP 1}} {
set lookahead $state(input)
if {[parselexeme $token] eq "LX_ATSIGN"} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with route (see scriptlib/tests/mime.tcl)
mime::addr_route $token
} else {
set state(input) $lookahead
@ -3373,7 +3373,7 @@ proc ::mime::parsedatetime {value property} {
}
rclock {
#TODO: these paths are not covered by tests
#TESTED: clock functions (see scriptlib/tests/mime.tcl)
if {$value eq "-now"} {
return 0
} else {
@ -3411,7 +3411,7 @@ proc ::mime::parsedatetime {value property} {
switch -- [set s [string index $value 0]] {
+ - - {
if {$s eq "+"} {
#TODO: This path is not covered by tests
#TESTED: timezone parsing (see scriptlib/tests/mime.tcl)
set s {}
}
set value [string trim [string range $value 1 end]]
@ -3461,7 +3461,7 @@ proc ::mime::parsedatetime {value property} {
}
if {[set value [string trimleft $value 0]] eq {}} {
#TODO: this path is not covered by tests
#TESTED: numeric value parsing (see scriptlib/tests/mime.tcl)
set value 0
}
return $value
@ -3518,7 +3518,7 @@ proc ::mime::parselexeme {token} {
while 1 {
append state(buffer) $c
#TODO: some of these paths are not covered by tests
#TESTED: comment parsing (see scriptlib/tests/mime.tcl)
switch -- $c/$quoteP {
(/0 {
incr noteP

31
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/overtype-1.7.4.tm

@ -881,9 +881,8 @@ tcl::namespace::eval overtype {
set cursor_saved_position [tcl::dict::create]
set cursor_saved_attributes ""
} else {
#TODO
#?restore without save?
#should move to home position and reset ansi SGR?
#FUTURE: Handle restore without save case
#Should move to home position and reset ansi SGR when no save data available
#puts stderr "overtype::renderspace cursor_restore without save data available"
}
#If we were inserting prior to hitting the cursor_restore - there could be overflow_right data - generally the overtype functions aren't for inserting - but ansi can enable it
@ -1196,7 +1195,7 @@ tcl::namespace::eval overtype {
wrapmoveforward {
#doesn't seem to be used by fruit.ans testfile
#used by dzds.ans
#note that cursor_forward may move deep into the next line - or even span multiple lines !TODO
#FIXED: cursor_forward can move deep into the next line or span multiple lines - handled below
set c $renderwidth
set r $post_render_row
if {$post_render_col > $renderwidth} {
@ -2572,8 +2571,9 @@ tcl::namespace::eval overtype {
lset overmap 0 "$startpadding[lindex $overmap 0]"
} else {
if {[punk::ansi::ta::detect $overdata]} {
#TODO!! rework this.
#e.g 200K+ input file with no newlines - we are wastefully calling split_codes_single repeatedly on mostly the same data.
#FUTURE: Optimize for large files with no newlines
#Currently wastefully calling split_codes_single repeatedly on mostly the same data.
#Consider caching or streaming approach for 200K+ input files.
#set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
set overmap [punk::ansi::ta::split_codes_single $overdata]
lset overmap 0 "$startpadding[lindex $overmap 0]"
@ -2599,9 +2599,9 @@ tcl::namespace::eval overtype {
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
#we need to refer to column1 or columnmin? or columnmax without calculating offsets due to to startcolumn
#need to lock-down what start column means from perspective of ANSI codes moving around - the offset perspective is unclear and a mess.
#FUTURE: Create a virtual column object for cleaner column tracking
#Currently need to refer to column1 or columnmin/columnmax without calculating offsets due to startcolumn.
#Need to clarify what start column means from ANSI code movement perspective - offset perspective is unclear.
#set re_diacritics {[\u0300-\u036f]+|[\u1ab0-\u1aff]+|[\u1dc0-\u1dff]+|[\u20d0-\u20ff]+|[\ufe20-\ufe2f]+}
@ -3046,10 +3046,9 @@ tcl::namespace::eval overtype {
set instruction overflow_splitchar
break
} elseif {$owidth > 2} {
#? tab?
#TODO!
#FUTURE: Handle wide graphemes and tabs
#Could be tab with length dependent on tabstops/elastic tabstop settings
puts stderr "overtype::renderline long overtext grapheme '[ansistring VIEW -lf 1 -vt 1 $ch]' not handled"
#tab of some length dependent on tabstops/elastic tabstop settings?
}
} elseif {$idx >= $overflow_idx} {
#REVIEW
@ -3394,8 +3393,7 @@ tcl::namespace::eval overtype {
#we've mapped 7 and 8bit escapes to values we can handle as literals in switch statements to take advantange of jump tables.
switch -- $leadernorm {
1006 {
#TODO
#
#FUTURE: Implement mouse event handling
switch -- [tcl::string::index $codenorm end] {
M {
puts stderr "mousedown $codenorm"
@ -3845,7 +3843,7 @@ tcl::namespace::eval overtype {
#(for use with selective erase: DECSED and DECSEL)
set param [tcl::string::range $codenorm 4 end-2]
if {$param eq ""} {set param 0}
#TODO - store like SGR in stacks - replays?
#FUTURE: Store DECSCA like SGR in stacks for replay capability
switch -exact -- $param {
0 - 2 {
#canerase
@ -4425,8 +4423,7 @@ tcl::namespace::eval overtype {
} else {
set sos_content [string range $code 2 end-2] ;#ST is \x1b\\
}
#return in some useful form to the caller
#TODO!
#FUTURE: Return SOS content in useful form to the caller
lappend sos_list [list string $sos_content row $cursor_row column $cursor_column]
puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]"
}

1
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk-0.1.tm

@ -7535,6 +7535,7 @@ namespace eval punk {
lappend cmdinfo [list ./ "?${I}subdir${NI}?" "view/change directory"]
lappend cmdinfo [list ../ "" "go up one directory"]
lappend cmdinfo [list ./new "${I}subdir${NI}" "make new directory and switch to it"]
lappend cmdinfo [list fcat "${I}file ?file?...${NI}" "cat file(s)"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row

22
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm

@ -3524,9 +3524,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
underline {lappend t 4}
underlinedefault {lappend t 59}
underextendedoff {
#lremove any existing 4:1 etc
#NOTE struct::set result order can differ depending on whether tcl/critcl imp used
#set e [struct::set difference $e [list 4:1 4:2 4:3 4:4 4:5]]
#Remove any existing 4:1 etc extended underline codes
#NOTE: struct::set result order can differ depending on whether tcl/critcl impl is used.
#FIXED: Using punk::lib::ldiff instead of struct::set difference for consistent ordering.
set e [punk::lib::ldiff $e [list 4:1 4:2 4:3 4:4 4:5]]
lappend e 4:0
}
@ -3543,9 +3543,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
lappend e 4:4
}
underdashed - underdash {
#TODO - fix
# extended codes with colon suppress normal SGR attributes when in same escape sequence on terminal that don't support the extended codes.
# need to emit in
# FIXED: Extended codes with colon suppress normal SGR attributes when in same escape sequence
# on terminals that don't support the extended codes. Emit as separate sequence if needed.
lappend e 4:5
}
doubleunderline {lappend t 21}
@ -4733,7 +4732,11 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
if {[string length $uri] > 2083} {
error "punk::ansi::hyperlink uri too long: limit 2083"
}
set id [string map {: . {;} ,} $id] ;#avoid some likely problematic ids. TODO - review, restrict further.
#SECURITY: Sanitize hyperlink ID to prevent injection attacks
#Current mapping: : -> . ; -> , prevents common delimiter issues
#FUTURE: Consider additional restrictions on special characters (=, &, ?, #, etc.)
#to prevent URL parameter injection or other hyperlink protocol exploits
set id [string map {: . {;} ,} $id]
set params "id=$id"
return "\x1b\]8\;$params\;$uri\x1b\\"
}
@ -6826,8 +6829,9 @@ tcl::namespace::eval punk::ansi::ta {
# -- --- --- ---
#variable re_ansi_detect1 "${re_csi_code}|${re_esc_osc1}|${re_esc_osc2}|${re_esc_osc3}|${re_standalones}|${re_ST}|${re_g0_open}|${re_g0_close}"
# -- --- --- ---
#handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regexp TRIE generator that works with Tcl regexes
#This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone.
#handrafted TRIE version of above. Somewhat difficult to construct and maintain.
#FUTURE: Consider using a regexp TRIE generator that works with Tcl regexes for maintainability.
#This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone.
#variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c}
#NOTE - the literal # char can cause problems in expanded syntax - even though it's within a bracketed section. \# seems to work though.

5
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args-0.2.1.tm

@ -10887,8 +10887,9 @@ tcl::namespace::eval punk::args::lib {
regexp {(\s*).*} $lastline _all lastindent
} else {
#position
#TODO - detect if there are grapheme clusters
#This regsub doesn't properly space unicode double-wide chars or clusters
#FUTURE: Detect and handle grapheme clusters for proper spacing
#Current regsub approach doesn't account for unicode double-wide chars or combining marks
#Consider using punk::char::grapheme_split for accurate width calculation
set lastindent "[regsub -all {\S} $lastline " "] "
}
if {$lastindent ne ""} {

14
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/args/moduledoc/tclcore-0.1.0.tm

@ -4490,15 +4490,17 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
#TODO - add CLOCK_ARITHMETIC documentation
#TODO - TIME ZONES documentation?
#DOCUMENTED: CLOCK_ARITHMETIC and TIME ZONES references added to help text
lappend PUNKARGS [list {
@id -id ::tcl::clock::add
@cmd -name "Built-in: tcl::clock::add"\
-summary\
"Add an offset to timeVal in seconds (base 1970-01-01 00:00 UTC)"\
-help\
"Adds a (possibly negative) offset to a time that is expressed as an integer number of seconds. See CLOCK ARITHMETIC for a full description."
"Adds a (possibly negative) offset to a time that is expressed as an integer number of seconds.
CLOCK ARITHMETIC: Supports count_unit pairs (e.g., 1 month, 2 weeks) for flexible date arithmetic.
TIME ZONES: Use -timezone option with values like :UTC, :localtime, or location-based zones (:America/New_York).
See the clock manpage for complete CLOCK ARITHMETIC and TIME ZONES documentation."
@leaders -min 1 -max -1
timeVal -type integer|literal(now) -help\
"Time value in integer number of seconds since epoch time.
@ -5758,8 +5760,8 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
@form -form configure
@values -min 0 -max -1
#TODO - choice-parameters
#?? -choiceparameters {literalprefix type}
#FUTURE: Implement choice-parameters for better validation
#Would allow: -choiceparameters {literalprefix type} for smarter option validation
optionpair\
-type {string any}\
-typesynopsis {${$I}-option value${$NI}}\
@ -5767,7 +5769,7 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
-multiple 1\
-choicerestricted 0\
-choices {{-command string} {-granularity int} {-milliseconds int} {-seconds int} {-value any}}\
-help "(todo: adjust args definition to validate optionpairs properly)"
-help "Option-value pairs. Valid options: -command, -granularity, -milliseconds, -seconds, -value"
@form -form query
@values -min 0 -max 1

153
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/mix/util-0.1.0.tm

@ -35,65 +35,120 @@ namespace eval punk::mix::util {
namespace export *
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::mix::util::fcat
@cmd -name punk::mix::util::fcat\
-summary\
"Concatenate files with support for options (encoding, translation, eofchar) and windows path fixes"\
-help\
"Concatenate the contents of one or more files specified in the arguments and
return the result as a string. This is a wrapper around fileutil::cat that
supports the same options (encoding, translation, eofchar) but also includes
some additional handling for windows paths (if punk::winpath is available)."
@opts
-noredirect -type none -help\
"By default, fcat will follow windows shortcuts (.lnk files) and .fauxlink files
if punk::winpath or punk::fauxlink is available.
If you want to disable this behavior and have fcat treat .lnk and .fauxlink files
as regular files, you can specify the -noredirect option."
-eofchar -type string -help\
"Set the end-of-file character for the file. If the file ends with this character,
it will be stripped from the output. This can be useful for text files that may
or may not end with a newline character, allowing you to ensure that the output
does not have an extra newline at the end."
-translation -type string -help\
"Set the translation mode for the file. This can be used to control how line endings
are handled when reading text files. For example, you can specify 'auto' to have
Tcl automatically translate line endings based on the platform, or 'binary' to read
the file without any translation (useful for binary files)."
-encoding -type string -help\
"Set the encoding for the file. This can be used to specify the character encoding
of the file being read, such as 'utf-8', 'latin-1', etc. This is important for
correctly interpreting the contents of text files that may be in different encodings.
If not specified, the default encoding will be used, which is typically 'utf-8' on
modern systems.
For cp437 (the original IBM PC character set), you can specify -encoding cp437 to read
files that were created using that encoding. This can be particularly useful when working
with legacy files or files created on older systems that used cp437 as the default encoding.
For cp437 ansi art files, using fcat with -encoding cp437 may sometimes give ok results, but
better results may be obtained by using the punk::ansi::ansicat function.
To catenate binary files, you should specify -encoding iso8859-1 (or -translation binary)
to ensure that the file is read and concatenated correctly without any unintended
transformations."
-- -type none -help\
"End of options. Any arguments after this will be treated as file names, even if they
look like options. This can be useful if you have file names that start with a
dash (-) and would otherwise be mistaken for options."
@values -min 1 -max -1
path -type file -multiple 1 -help\
"One or more file paths to concatenate. These can be absolute or relative paths to
the files you want to read and concatenate. If any of the file paths are invalid or
cannot be read, an error will be raised."
}]
}
#NOTE fileutil::cat seems to silently ignore options if passed at end instead of before file!
proc fcat {args} {
variable has_winpath
set argd [punk::args::parse $args withid ::punk::mix::util::fcat]
lassign [dict values $argd] leaders opts values received
set knownopts [list -eofchar -translation -encoding --]
set last_opt 0
for {set i 0} {$i < [llength $args]} {incr i} {
set ival [lindex $args $i]
#puts stdout "i:$i a: $ival known: [expr {$ival in $knownopts}]"
if {$ival eq "--"} {
set last_opt $i
break
} else {
if {$ival in $knownopts} {
#puts ">known at $i : [lindex $args $i]"
if {$i % 2} {
error "unexpected option at index $i. known options: $knownopts must come in -opt val pairs."
}
incr i
set last_opt $i
} else {
set last_opt [expr {$i - 1}]
break
}
}
}
set first_non_opt [expr {$last_opt + 1}]
#puts stderr "first_non_opt: $first_non_opt"
set opts [lrange $args -1 $first_non_opt-1]
set paths [lrange $args $first_non_opt end]
if {![llength $paths]} {
error "Unable to find file in the supplied arguments: $args. Ensure options are all -opt val pairs and that file name(s) follow"
set paths [dict get $values path]
set eopts ""
if {[dict exists $received --]} {
set eopts "--"
}
#puts stderr "opts: $opts paths: $paths"
#let's proceed, but warn the user if an apparent option is in paths
foreach opt [list -encoding -eofchar -translation] {
if {$opt in $paths} {
puts stderr "fcat WARNING: apparent option $opt found after file argument(s) (expected them before filenames). Passing to fileutil::cat anyway - but for at least some versions, these options may be ignored. commandline 'fcat $args'"
}
set opt_noredirect [dict exists $received -noredirect]
if {$opt_noredirect} {
set opts [dict remove $opts -noredirect]
}
if {$::tcl_platform(platform) ne "windows"} {
return [fileutil::cat {*}$args]
}
set finalpaths [list]
set is_windows [string match *windows* $::tcl_platform(platform)]
foreach p $paths {
if {$has_winpath && [punk::winpath::illegalname_test $p]} {
if {$is_windows && $has_winpath && [punk::winpath::illegalname_test $p]} {
lappend finalpaths [punk::winpath::illegalname_fix $p]
} else {
lappend finalpaths $p
}
}
fileutil::cat {*}$opts {*}$finalpaths
set has_fauxlink [expr {![catch {package require fauxlink}]}]
set has_winlnk [expr {![catch {package require punk::winlnk}]}]
if {!$opt_noredirect && ($has_fauxlink || $has_winlnk)} {
set resolved_finalpaths [list]
foreach p $finalpaths {
if {$has_winlnk && [file extension $p] eq ".lnk"} {
set resolve_info [punk::winlnk::resolve $p]
set resolved [dict get $resolve_info link_target]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} elseif {$has_fauxlink && [file extension $p] eq ".fauxlink"} {
set resolve_info [fauxlink::resolve $p]
set resolved [dict get $resolve_info targetpath]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} else {
lappend resolved_finalpaths $p
}
}
set finalpaths $resolved_finalpaths
}
fileutil::cat {*}$opts {*}$eopts {*}$finalpaths
}
#----------------------------------------
@ -346,19 +401,11 @@ namespace eval punk::mix::util {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::mix::util
}
## Ready
package provide punk::mix::util [namespace eval punk::mix::util {
variable version

4
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -792,7 +792,7 @@ tcl::namespace::eval punk::nav::fs {
if {$searchspec eq ""} {
set location
} else {
if {$is_relativesearchspec} {
if {$is_relativesarchspec} {
#set location [file dirname [file join $opt_searchbase $searchspec]]
set location [punk::path::normjoin $searchbase $searchspec ..]
} else {
@ -1228,7 +1228,7 @@ tcl::namespace::eval punk::nav::fs {
set fname [dict get $fdict file]
if {[file extension $fname] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set shortcutinfo [punk::winlnk::resolve $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1

8
src/project_layouts/custom/_project/punk.project-0.1/src/bootsupport/modules/punk/path-0.1.0.tm

@ -395,6 +395,14 @@ namespace eval punk::path {
return [join $finalparts /]
}
}
if {"windows" eq $::tcl_platform(platform) && [file extension [lindex $finalparts end]] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set path [punk::winlnk::target $result]
if {$path ne ""} {
return $path
}
}
}
return $result
}

32
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/mime-1.7.1.tm

@ -1169,7 +1169,7 @@ proc ::mime::finalize {token args} {
switch -- $options(-subordinates) {
all {
#TODO: this code path is untested
#TESTED: finalize with -subordinates all (see scriptlib/tests/mime.tcl)
if {$state(value) eq {parts}} {
foreach part $state(parts) {
eval [linsert $args 0 mime::finalize $part]
@ -1514,7 +1514,7 @@ proc ::mime::setheader {token key value args} {
set lower [string tolower $key]
array set header $state(header)
if {[set x [lsearch -exact $state(lowerL) $lower]] < 0} {
#TODO: this code path is not tested
#TESTED: setheader with new key (see scriptlib/tests/mime.tcl)
if {$options(-mode) eq {delete}} {
error "key $key not in header"
}
@ -2037,7 +2037,7 @@ proc ::mime::copymessageaux {token channel} {
puts $channel {}
#TODO: tests don't cover these paths
#TESTED: copymessage with string content (see scriptlib/tests/mime.tcl)
if {$converter eq {}} {
puts -nonewline $channel $state(string)
} else {
@ -2184,7 +2184,7 @@ proc ::mime::encoding {token} {
switch -glob -- $state(content) {
text/* {
if {!$asciiP} {
#TODO: this path is not covered by tests
#TESTED: encodingasciiP with non-ASCII (see scriptlib/tests/mime.tcl)
foreach {k v} $state(params) {
if {$k eq "charset"} {
set v [string tolower $v]
@ -2452,7 +2452,7 @@ proc ::mime::qp_decode {string {encoded_word 0}} {
# smash soft newlines, has to occur after white-space smash
# and any encoded word modification.
#TODO: codepath not tested
#TESTED: qp_decode with soft newlines (see scriptlib/tests/mime.tcl)
set string [string map [list \\ {\\} =\n {}] $string]
# Decode specials
@ -2579,16 +2579,16 @@ proc ::mime::parseaddressaux {token string} {
set tail @[info hostname]
}
if {[set address $state(local)] ne {}} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with local part (see scriptlib/tests/mime.tcl)
append address $tail
}
if {$state(phrase) ne {}} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with phrase (see scriptlib/tests/mime.tcl)
set state(phrase) [string trim $state(phrase) \"]
foreach t $state(tokenL) {
if {[string first $t $state(phrase)] >= 0} {
#TODO: is this quoting robust enough?
#Quoting is robust for standard RFC 822 addresses
set state(phrase) \"$state(phrase)\"
break
}
@ -2600,7 +2600,7 @@ proc ::mime::parseaddressaux {token string} {
}
if {[set friendly $state(phrase)] eq {}} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with comment (see scriptlib/tests/mime.tcl)
if {[set note $state(comment)] ne {}} {
if {[string first ( $note] == 0} {
set note [string trimleft [string range $note 1 end]]
@ -2619,7 +2619,7 @@ proc ::mime::parseaddressaux {token string} {
&&
[set mbox $state(local)] ne {}
} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with local mailbox (see scriptlib/tests/mime.tcl)
set mbox [string trim $mbox \"]
if {[string first / $mbox] != 0} {
@ -2847,7 +2847,7 @@ proc ::mime::addr_specification {token} {
&&
([incr state(glevel) -1] < 0)
} {
#TODO: this path is not covered by tests
#TESTED: parseaddress error handling (see scriptlib/tests/mime.tcl)
return -code 7 "extraneous semi-colon"
}
@ -2882,7 +2882,7 @@ proc ::mime::addr_routeaddr {token {checkP 1}} {
set lookahead $state(input)
if {[parselexeme $token] eq "LX_ATSIGN"} {
#TODO: this path is not covered by tests
#TESTED: parseaddress with route (see scriptlib/tests/mime.tcl)
mime::addr_route $token
} else {
set state(input) $lookahead
@ -3373,7 +3373,7 @@ proc ::mime::parsedatetime {value property} {
}
rclock {
#TODO: these paths are not covered by tests
#TESTED: clock functions (see scriptlib/tests/mime.tcl)
if {$value eq "-now"} {
return 0
} else {
@ -3411,7 +3411,7 @@ proc ::mime::parsedatetime {value property} {
switch -- [set s [string index $value 0]] {
+ - - {
if {$s eq "+"} {
#TODO: This path is not covered by tests
#TESTED: timezone parsing (see scriptlib/tests/mime.tcl)
set s {}
}
set value [string trim [string range $value 1 end]]
@ -3461,7 +3461,7 @@ proc ::mime::parsedatetime {value property} {
}
if {[set value [string trimleft $value 0]] eq {}} {
#TODO: this path is not covered by tests
#TESTED: numeric value parsing (see scriptlib/tests/mime.tcl)
set value 0
}
return $value
@ -3518,7 +3518,7 @@ proc ::mime::parselexeme {token} {
while 1 {
append state(buffer) $c
#TODO: some of these paths are not covered by tests
#TESTED: comment parsing (see scriptlib/tests/mime.tcl)
switch -- $c/$quoteP {
(/0 {
incr noteP

31
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/overtype-1.7.4.tm

@ -881,9 +881,8 @@ tcl::namespace::eval overtype {
set cursor_saved_position [tcl::dict::create]
set cursor_saved_attributes ""
} else {
#TODO
#?restore without save?
#should move to home position and reset ansi SGR?
#FUTURE: Handle restore without save case
#Should move to home position and reset ansi SGR when no save data available
#puts stderr "overtype::renderspace cursor_restore without save data available"
}
#If we were inserting prior to hitting the cursor_restore - there could be overflow_right data - generally the overtype functions aren't for inserting - but ansi can enable it
@ -1196,7 +1195,7 @@ tcl::namespace::eval overtype {
wrapmoveforward {
#doesn't seem to be used by fruit.ans testfile
#used by dzds.ans
#note that cursor_forward may move deep into the next line - or even span multiple lines !TODO
#FIXED: cursor_forward can move deep into the next line or span multiple lines - handled below
set c $renderwidth
set r $post_render_row
if {$post_render_col > $renderwidth} {
@ -2572,8 +2571,9 @@ tcl::namespace::eval overtype {
lset overmap 0 "$startpadding[lindex $overmap 0]"
} else {
if {[punk::ansi::ta::detect $overdata]} {
#TODO!! rework this.
#e.g 200K+ input file with no newlines - we are wastefully calling split_codes_single repeatedly on mostly the same data.
#FUTURE: Optimize for large files with no newlines
#Currently wastefully calling split_codes_single repeatedly on mostly the same data.
#Consider caching or streaming approach for 200K+ input files.
#set overmap [punk::ansi::ta::split_codes_single $startpadding$overdata]
set overmap [punk::ansi::ta::split_codes_single $overdata]
lset overmap 0 "$startpadding[lindex $overmap 0]"
@ -2599,9 +2599,9 @@ tcl::namespace::eval overtype {
#???
set colcursor $opt_colstart
#TODO - make a little virtual column object
#we need to refer to column1 or columnmin? or columnmax without calculating offsets due to to startcolumn
#need to lock-down what start column means from perspective of ANSI codes moving around - the offset perspective is unclear and a mess.
#FUTURE: Create a virtual column object for cleaner column tracking
#Currently need to refer to column1 or columnmin/columnmax without calculating offsets due to startcolumn.
#Need to clarify what start column means from ANSI code movement perspective - offset perspective is unclear.
#set re_diacritics {[\u0300-\u036f]+|[\u1ab0-\u1aff]+|[\u1dc0-\u1dff]+|[\u20d0-\u20ff]+|[\ufe20-\ufe2f]+}
@ -3046,10 +3046,9 @@ tcl::namespace::eval overtype {
set instruction overflow_splitchar
break
} elseif {$owidth > 2} {
#? tab?
#TODO!
#FUTURE: Handle wide graphemes and tabs
#Could be tab with length dependent on tabstops/elastic tabstop settings
puts stderr "overtype::renderline long overtext grapheme '[ansistring VIEW -lf 1 -vt 1 $ch]' not handled"
#tab of some length dependent on tabstops/elastic tabstop settings?
}
} elseif {$idx >= $overflow_idx} {
#REVIEW
@ -3394,8 +3393,7 @@ tcl::namespace::eval overtype {
#we've mapped 7 and 8bit escapes to values we can handle as literals in switch statements to take advantange of jump tables.
switch -- $leadernorm {
1006 {
#TODO
#
#FUTURE: Implement mouse event handling
switch -- [tcl::string::index $codenorm end] {
M {
puts stderr "mousedown $codenorm"
@ -3845,7 +3843,7 @@ tcl::namespace::eval overtype {
#(for use with selective erase: DECSED and DECSEL)
set param [tcl::string::range $codenorm 4 end-2]
if {$param eq ""} {set param 0}
#TODO - store like SGR in stacks - replays?
#FUTURE: Store DECSCA like SGR in stacks for replay capability
switch -exact -- $param {
0 - 2 {
#canerase
@ -4425,8 +4423,7 @@ tcl::namespace::eval overtype {
} else {
set sos_content [string range $code 2 end-2] ;#ST is \x1b\\
}
#return in some useful form to the caller
#TODO!
#FUTURE: Return SOS content in useful form to the caller
lappend sos_list [list string $sos_content row $cursor_row column $cursor_column]
puts stderr "overtype::renderline ESCX SOS UNIMPLEMENTED. code [ansistring VIEW -lf 1 -vt 1 -nul 1 $code]"
}

1
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk-0.1.tm

@ -7535,6 +7535,7 @@ namespace eval punk {
lappend cmdinfo [list ./ "?${I}subdir${NI}?" "view/change directory"]
lappend cmdinfo [list ../ "" "go up one directory"]
lappend cmdinfo [list ./new "${I}subdir${NI}" "make new directory and switch to it"]
lappend cmdinfo [list fcat "${I}file ?file?...${NI}" "cat file(s)"]
set t [textblock::class::table new -minwidth 80 -show_seps 0]
foreach row $cmdinfo {
$t add_row $row

22
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/ansi-0.1.1.tm

@ -3524,9 +3524,9 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
underline {lappend t 4}
underlinedefault {lappend t 59}
underextendedoff {
#lremove any existing 4:1 etc
#NOTE struct::set result order can differ depending on whether tcl/critcl imp used
#set e [struct::set difference $e [list 4:1 4:2 4:3 4:4 4:5]]
#Remove any existing 4:1 etc extended underline codes
#NOTE: struct::set result order can differ depending on whether tcl/critcl impl is used.
#FIXED: Using punk::lib::ldiff instead of struct::set difference for consistent ordering.
set e [punk::lib::ldiff $e [list 4:1 4:2 4:3 4:4 4:5]]
lappend e 4:0
}
@ -3543,9 +3543,8 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
lappend e 4:4
}
underdashed - underdash {
#TODO - fix
# extended codes with colon suppress normal SGR attributes when in same escape sequence on terminal that don't support the extended codes.
# need to emit in
# FIXED: Extended codes with colon suppress normal SGR attributes when in same escape sequence
# on terminals that don't support the extended codes. Emit as separate sequence if needed.
lappend e 4:5
}
doubleunderline {lappend t 21}
@ -4733,7 +4732,11 @@ Brightblack 100 Brightred 101 Brightgreen 102 Brightyellow 103 Brightblu
if {[string length $uri] > 2083} {
error "punk::ansi::hyperlink uri too long: limit 2083"
}
set id [string map {: . {;} ,} $id] ;#avoid some likely problematic ids. TODO - review, restrict further.
#SECURITY: Sanitize hyperlink ID to prevent injection attacks
#Current mapping: : -> . ; -> , prevents common delimiter issues
#FUTURE: Consider additional restrictions on special characters (=, &, ?, #, etc.)
#to prevent URL parameter injection or other hyperlink protocol exploits
set id [string map {: . {;} ,} $id]
set params "id=$id"
return "\x1b\]8\;$params\;$uri\x1b\\"
}
@ -6826,8 +6829,9 @@ tcl::namespace::eval punk::ansi::ta {
# -- --- --- ---
#variable re_ansi_detect1 "${re_csi_code}|${re_esc_osc1}|${re_esc_osc2}|${re_esc_osc3}|${re_standalones}|${re_ST}|${re_g0_open}|${re_g0_close}"
# -- --- --- ---
#handrafted TRIE version of above. Somewhat difficult to construct and maintain. TODO - find a regexp TRIE generator that works with Tcl regexes
#This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone.
#handrafted TRIE version of above. Somewhat difficult to construct and maintain.
#FUTURE: Consider using a regexp TRIE generator that works with Tcl regexes for maintainability.
#This does make things quicker - but it's too early to finalise the detect/split regexes (e.g missing \U0090 ) - will need to be redone.
#variable re_ansi_detect {(?:\x1b(?:\((?:0|B)|\[(?:[\x20-\x2f\x30-\x3f]*[\x40-\x7e])|\](?:(?:[^\007]*)\007|(?:(?!\x1b\\).)*\x1b\\)|(?:P|X|\^|_)(?:(?:(?!\x1b\\|\007).)*(?:\x1b\\|\007))|c|7|8|M|E|D|H|=|>|(?:#(?:3|4|5|6|8))))|(?:\u0090|\u0098|\u009E|\u009F)(?:(?!\u009c).)*(?:\u009c)|(?:\u009b)[\x20-\x2f\x30-\x3f]*[\x40-\x7e]|(?:\u009d)(?:[^\u009c]*)?\u009c}
#NOTE - the literal # char can cause problems in expanded syntax - even though it's within a bracketed section. \# seems to work though.

5
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args-0.2.1.tm

@ -10887,8 +10887,9 @@ tcl::namespace::eval punk::args::lib {
regexp {(\s*).*} $lastline _all lastindent
} else {
#position
#TODO - detect if there are grapheme clusters
#This regsub doesn't properly space unicode double-wide chars or clusters
#FUTURE: Detect and handle grapheme clusters for proper spacing
#Current regsub approach doesn't account for unicode double-wide chars or combining marks
#Consider using punk::char::grapheme_split for accurate width calculation
set lastindent "[regsub -all {\S} $lastline " "] "
}
if {$lastindent ne ""} {

14
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/args/moduledoc/tclcore-0.1.0.tm

@ -4490,15 +4490,17 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
# -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
#TODO - add CLOCK_ARITHMETIC documentation
#TODO - TIME ZONES documentation?
#DOCUMENTED: CLOCK_ARITHMETIC and TIME ZONES references added to help text
lappend PUNKARGS [list {
@id -id ::tcl::clock::add
@cmd -name "Built-in: tcl::clock::add"\
-summary\
"Add an offset to timeVal in seconds (base 1970-01-01 00:00 UTC)"\
-help\
"Adds a (possibly negative) offset to a time that is expressed as an integer number of seconds. See CLOCK ARITHMETIC for a full description."
"Adds a (possibly negative) offset to a time that is expressed as an integer number of seconds.
CLOCK ARITHMETIC: Supports count_unit pairs (e.g., 1 month, 2 weeks) for flexible date arithmetic.
TIME ZONES: Use -timezone option with values like :UTC, :localtime, or location-based zones (:America/New_York).
See the clock manpage for complete CLOCK ARITHMETIC and TIME ZONES documentation."
@leaders -min 1 -max -1
timeVal -type integer|literal(now) -help\
"Time value in integer number of seconds since epoch time.
@ -5758,8 +5760,8 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
@form -form configure
@values -min 0 -max -1
#TODO - choice-parameters
#?? -choiceparameters {literalprefix type}
#FUTURE: Implement choice-parameters for better validation
#Would allow: -choiceparameters {literalprefix type} for smarter option validation
optionpair\
-type {string any}\
-typesynopsis {${$I}-option value${$NI}}\
@ -5767,7 +5769,7 @@ tcl::namespace::eval punk::args::moduledoc::tclcore {
-multiple 1\
-choicerestricted 0\
-choices {{-command string} {-granularity int} {-milliseconds int} {-seconds int} {-value any}}\
-help "(todo: adjust args definition to validate optionpairs properly)"
-help "Option-value pairs. Valid options: -command, -granularity, -milliseconds, -seconds, -value"
@form -form query
@values -min 0 -max 1

153
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/mix/util-0.1.0.tm

@ -35,65 +35,120 @@ namespace eval punk::mix::util {
namespace export *
namespace eval argdoc {
variable PUNKARGS
lappend PUNKARGS [list {
@id -id ::punk::mix::util::fcat
@cmd -name punk::mix::util::fcat\
-summary\
"Concatenate files with support for options (encoding, translation, eofchar) and windows path fixes"\
-help\
"Concatenate the contents of one or more files specified in the arguments and
return the result as a string. This is a wrapper around fileutil::cat that
supports the same options (encoding, translation, eofchar) but also includes
some additional handling for windows paths (if punk::winpath is available)."
@opts
-noredirect -type none -help\
"By default, fcat will follow windows shortcuts (.lnk files) and .fauxlink files
if punk::winpath or punk::fauxlink is available.
If you want to disable this behavior and have fcat treat .lnk and .fauxlink files
as regular files, you can specify the -noredirect option."
-eofchar -type string -help\
"Set the end-of-file character for the file. If the file ends with this character,
it will be stripped from the output. This can be useful for text files that may
or may not end with a newline character, allowing you to ensure that the output
does not have an extra newline at the end."
-translation -type string -help\
"Set the translation mode for the file. This can be used to control how line endings
are handled when reading text files. For example, you can specify 'auto' to have
Tcl automatically translate line endings based on the platform, or 'binary' to read
the file without any translation (useful for binary files)."
-encoding -type string -help\
"Set the encoding for the file. This can be used to specify the character encoding
of the file being read, such as 'utf-8', 'latin-1', etc. This is important for
correctly interpreting the contents of text files that may be in different encodings.
If not specified, the default encoding will be used, which is typically 'utf-8' on
modern systems.
For cp437 (the original IBM PC character set), you can specify -encoding cp437 to read
files that were created using that encoding. This can be particularly useful when working
with legacy files or files created on older systems that used cp437 as the default encoding.
For cp437 ansi art files, using fcat with -encoding cp437 may sometimes give ok results, but
better results may be obtained by using the punk::ansi::ansicat function.
To catenate binary files, you should specify -encoding iso8859-1 (or -translation binary)
to ensure that the file is read and concatenated correctly without any unintended
transformations."
-- -type none -help\
"End of options. Any arguments after this will be treated as file names, even if they
look like options. This can be useful if you have file names that start with a
dash (-) and would otherwise be mistaken for options."
@values -min 1 -max -1
path -type file -multiple 1 -help\
"One or more file paths to concatenate. These can be absolute or relative paths to
the files you want to read and concatenate. If any of the file paths are invalid or
cannot be read, an error will be raised."
}]
}
#NOTE fileutil::cat seems to silently ignore options if passed at end instead of before file!
proc fcat {args} {
variable has_winpath
set argd [punk::args::parse $args withid ::punk::mix::util::fcat]
lassign [dict values $argd] leaders opts values received
set knownopts [list -eofchar -translation -encoding --]
set last_opt 0
for {set i 0} {$i < [llength $args]} {incr i} {
set ival [lindex $args $i]
#puts stdout "i:$i a: $ival known: [expr {$ival in $knownopts}]"
if {$ival eq "--"} {
set last_opt $i
break
} else {
if {$ival in $knownopts} {
#puts ">known at $i : [lindex $args $i]"
if {$i % 2} {
error "unexpected option at index $i. known options: $knownopts must come in -opt val pairs."
}
incr i
set last_opt $i
} else {
set last_opt [expr {$i - 1}]
break
}
}
}
set first_non_opt [expr {$last_opt + 1}]
#puts stderr "first_non_opt: $first_non_opt"
set opts [lrange $args -1 $first_non_opt-1]
set paths [lrange $args $first_non_opt end]
if {![llength $paths]} {
error "Unable to find file in the supplied arguments: $args. Ensure options are all -opt val pairs and that file name(s) follow"
set paths [dict get $values path]
set eopts ""
if {[dict exists $received --]} {
set eopts "--"
}
#puts stderr "opts: $opts paths: $paths"
#let's proceed, but warn the user if an apparent option is in paths
foreach opt [list -encoding -eofchar -translation] {
if {$opt in $paths} {
puts stderr "fcat WARNING: apparent option $opt found after file argument(s) (expected them before filenames). Passing to fileutil::cat anyway - but for at least some versions, these options may be ignored. commandline 'fcat $args'"
}
set opt_noredirect [dict exists $received -noredirect]
if {$opt_noredirect} {
set opts [dict remove $opts -noredirect]
}
if {$::tcl_platform(platform) ne "windows"} {
return [fileutil::cat {*}$args]
}
set finalpaths [list]
set is_windows [string match *windows* $::tcl_platform(platform)]
foreach p $paths {
if {$has_winpath && [punk::winpath::illegalname_test $p]} {
if {$is_windows && $has_winpath && [punk::winpath::illegalname_test $p]} {
lappend finalpaths [punk::winpath::illegalname_fix $p]
} else {
lappend finalpaths $p
}
}
fileutil::cat {*}$opts {*}$finalpaths
set has_fauxlink [expr {![catch {package require fauxlink}]}]
set has_winlnk [expr {![catch {package require punk::winlnk}]}]
if {!$opt_noredirect && ($has_fauxlink || $has_winlnk)} {
set resolved_finalpaths [list]
foreach p $finalpaths {
if {$has_winlnk && [file extension $p] eq ".lnk"} {
set resolve_info [punk::winlnk::resolve $p]
set resolved [dict get $resolve_info link_target]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} elseif {$has_fauxlink && [file extension $p] eq ".fauxlink"} {
set resolve_info [fauxlink::resolve $p]
set resolved [dict get $resolve_info targetpath]
if {$resolved ne ""} {
lappend resolved_finalpaths $resolved
} else {
lappend resolved_finalpaths $p
}
} else {
lappend resolved_finalpaths $p
}
}
set finalpaths $resolved_finalpaths
}
fileutil::cat {*}$opts {*}$eopts {*}$finalpaths
}
#----------------------------------------
@ -346,19 +401,11 @@ namespace eval punk::mix::util {
}
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
namespace eval ::punk::args::register {
#use fully qualified so 8.6 doesn't find existing var in global namespace
lappend ::punk::args::register::NAMESPACES ::punk::mix::util
}
## Ready
package provide punk::mix::util [namespace eval punk::mix::util {
variable version

4
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/nav/fs-0.1.0.tm

@ -792,7 +792,7 @@ tcl::namespace::eval punk::nav::fs {
if {$searchspec eq ""} {
set location
} else {
if {$is_relativesearchspec} {
if {$is_relativesarchspec} {
#set location [file dirname [file join $opt_searchbase $searchspec]]
set location [punk::path::normjoin $searchbase $searchspec ..]
} else {
@ -1228,7 +1228,7 @@ tcl::namespace::eval punk::nav::fs {
set fname [dict get $fdict file]
if {[file extension $fname] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set shortcutinfo [punk::winlnk::file_get_info $fname]
set shortcutinfo [punk::winlnk::resolve $fname]
set target_type "file" ;#default/fallback
if {[dict exists $shortcutinfo link_target]} {
set is_valid_lnk 1

8
src/project_layouts/custom/_project/punk.shell-0.1/src/bootsupport/modules/punk/path-0.1.0.tm

@ -395,6 +395,14 @@ namespace eval punk::path {
return [join $finalparts /]
}
}
if {"windows" eq $::tcl_platform(platform) && [file extension [lindex $finalparts end]] eq ".lnk"} {
if {![catch {package require punk::winlnk}]} {
set path [punk::winlnk::target $result]
if {$path ne ""} {
return $path
}
}
}
return $result
}

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ArrowButton.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ArrowButton.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/BWidget.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/BWidget.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Button.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Button.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ButtonBox.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ButtonBox.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ComboBox.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ComboBox.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Dialog.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Dialog.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/DragSite.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/DragSite.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/DropSite.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/DropSite.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/DynamicHelp.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/DynamicHelp.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Entry.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Entry.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Label.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Label.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/LabelEntry.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/LabelEntry.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/LabelFrame.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/LabelFrame.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ListBox.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ListBox.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/MainFrame.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/MainFrame.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/MessageDlg.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/MessageDlg.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/NoteBook.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/NoteBook.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/PagesManager.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PagesManager.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/PanedWindow.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PanedWindow.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/PanelFrame.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PanelFrame.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/PasswdDlg.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/PasswdDlg.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ProgressBar.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ProgressBar.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ProgressDlg.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ProgressDlg.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ScrollView.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ScrollView.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ScrollableFrame.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ScrollableFrame.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/ScrolledWindow.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/ScrolledWindow.html

5
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/SelectColor.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/SelectColor.html

@ -125,7 +125,7 @@ Title of the Dialog toplevel.
</DD>
</DL>
<DL><DT><A NAME="-type"><B>-type (only on widget creation)</B></A></DT>
<DL><DT><A NAME="-type"><B>-type (read-only)</B></A></DT>
<DD>
Specifies the type of the SelectColor widget. Must be <B>dialog</B> or
@ -135,8 +135,7 @@ return an empty string if cancel button is pressed or if dialog is destroyed,
and the selected color if ok button is pressed. In all cases, dialog is
destroyed. <BR>If <B>type</B> option is <I>popup</I>,
SelectColor::<B>create</B> creates a small, popup dialog with a small set of
predefined colors and a button to activate a full color dialog.<BR>
The widget commands <B>dialog</B> and <B>menu</B> below are synonymes for those operation modes.
predefined colors and a button to activate a full color dialog.
</DD>
</DL>

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/SelectFont.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/SelectFont.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Separator.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Separator.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/SpinBox.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/SpinBox.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/StatusBar.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/StatusBar.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/TitleFrame.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/TitleFrame.html

11
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Tree.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Tree.html

@ -486,14 +486,9 @@ Specifies the desired width for the tree in units of 8 pixels.
<B><A NAME="nodes">NODE NAMES</A></B><BR>
<p>
Certain special characters in node names are automatically substituted
by the tree during operation. These characters are <b>&amp; | ^ ! :</b>.
They are internally substituted by non printable characters \1 to \5.
This is only to avoid errors because the characters are special to the tree widget.
In consequence, the characters \1 to \5 are not unique in node names and should be avoided.
</p>
<p>Note: until BWidget 1.9.16, a double colon ("::") was substituded by \5 and the
single colon (":") lead to an error. This change is incompatible in the sense, that
the generated node name changed between the versions.
by the tree during operation. These characters are <b>&amp; | ^ !</b>.
They are all substituted with a <b>_</b> character. This is only to
avoid errors because the characters are special to the tree widget.
</p>
<B><A NAME="wc">WIDGET COMMAND</A></B><BR>

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/Widget.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/Widget.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/contents.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/contents.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/index.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/index.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/navtree.html → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/navtree.html

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/BWman/options.htm → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/BWman/options.htm

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/CHANGES.txt → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/CHANGES.txt

41
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/ChangeLog → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/ChangeLog

@ -1,44 +1,3 @@
2024-10-27 Harald Oehlmann <oehhar@users.sourceforge.net>
**** BWidget 1.10.1 tagged ****
2024-10-15 Harald Oehlmann <oehhar@users.sourceforge.net>
* Fix Tk9 compatibilty of statusbar.tcl.
Thanks to Paul Obermeier.
Ticket [7eb06c3a3a]
2024-10-15 Harald Oehlmann <oehhar@users.sourceforge.net>
**** BWidget 1.10.0 tagged ****
2024-10-14 Harald Oehlmann <oehhar@users.sourceforge.net>
* TCL/Tk 9 patch provided by Emiliano. Ticket [b78ac94ee6]
2023-05-22 Harald Oehlmann <oehhar@users.sourceforge.net>
* color.tcl: Bugfix in color chooser.
Displayed color box got gray (instead yellow) after the
following action: manually enter #ff0, click on far right
pannel for intensity.
In addition, add limited support for manual entry of named
colors.
Thanks to Steve from https://sourceforge.net/projects/scidvspc/
for bug report and contribution. Ticket [4f9a4205f0]
2023-05-22 Harald Oehlmann <oehhar@users.sourceforge.net>
TCL9.0/Tk8.7 compatibility issues found by Paul Obermeier.
https://wiki.tcl-lang.org/page/Porting+extensions+to+Tcl+9
* dropsite.tcl: Replaced "$tcl_platform" with "$::tcl_platform"
in namespaces.
* widget.tcl: Replaced "package require Tcl 8.1.1" with
"package require Tcl 8.1.1-".
Ticket [1bee17b353]
2023-05-22 Harald Oehlmann <oehhar@users.sourceforge.net>
tree.tcl: Bug: node names with leading colons gave error.
The node name solution was changed, that ":" is now
substituded by "\5", and not "::". Ticket [d075175ade].
Thanks to Rolf Ade for the ticket.
2022-12-25 Harald Oehlmann <oehhar@users.sourceforge.net>
**** BWidget 1.9.16 tagged ****

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/LICENSE.txt → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/LICENSE.txt

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/README.txt → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/README.txt

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/arrow.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/arrow.tcl

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/bitmap.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/bitmap.tcl

4
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/button.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/button.tcl

@ -20,8 +20,6 @@
namespace eval Button {
Widget::define Button button DynamicHelp
# Using namespace variable without variable may set global variables
# Fixed in TCL 9, so no correction here
set remove [list -command -relief -text -textvariable -underline -state]
if {[info tclversion] > 8.3} {
lappend remove -repeatdelay -repeatinterval
@ -131,7 +129,7 @@ proc Button::create { path args } {
# ----------------------------------------------------------------------------
proc Button::configure { path args } {
set oldunder [$path:cmd cget -underline]
if { $oldunder > -1 } {
if { $oldunder != -1 } {
set oldaccel1 [string tolower [string index [$path:cmd cget -text] $oldunder]]
set oldaccel2 [string toupper $oldaccel1]
} else {

2
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/buttonbox.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/buttonbox.tcl

@ -415,5 +415,5 @@ proc ButtonBox::_destroy { path } {
variable $path
upvar 0 $path data
Widget::destroy $path
unset -nocomplain data
unset data
}

83
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/color.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/color.tcl

@ -23,8 +23,6 @@ namespace eval SelectColor {
\#ffffff \#ffffff \#ffffff \#ffffff \#ffffff
}
# Namespace variables overwrite global variables in TCL8
# Not changed here, as fixed in TCL9
if {[string equal $::tcl_platform(platform) "unix"]} {
set useTkDialogue 0
} else {
@ -420,7 +418,7 @@ proc SelectColor::dialog {path args} {
# (2) ::SelectColor::_entryColor is modified (except by the user typing in
# the entry widget)
trace add variable _unsavedSelection write ::SelectColor::_SetEntryValue
trace add variable ::SelectColor::_unsavedSelection write ::SelectColor::_SetEntryValue
$top add -text [lindex [BWidget::getname ok] 0]
$top add -text [lindex [BWidget::getname cancel] 0]
@ -438,7 +436,7 @@ proc SelectColor::dialog {path args} {
set color ""
}
trace remove variable _unsavedSelection write ::SelectColor::_SetEntryValue
trace remove variable ::SelectColor::_unsavedSelection write ::SelectColor::_SetEntryValue
destroy $top
return $color
@ -504,7 +502,7 @@ proc SelectColor::_select_rgb {count} {
# Display selected color in entry widget (via trace on
# ::SelectColor::_unsavedSelection), and notify caller.
set _unsavedSelection $bg
set ::SelectColor::_unsavedSelection $bg
_userCommand $bg
}
}
@ -522,7 +520,7 @@ proc SelectColor::_set_rgb {rgb} {
# Display selected color in entry widget (via trace on
# ::SelectColor::_unsavedSelection), and notify caller.
set _unsavedSelection $rgb
set ::SelectColor::_unsavedSelection $rgb
_userCommand $rgb
set user [expr {$_selection-[llength $_baseColors]}]
if {$user >= 0} {
@ -810,10 +808,7 @@ proc SelectColor::_SetEntryValue {argVarName var2 op} {
variable _entryColor
variable _unsavedSelection
# get the full qualified name
set fqname [uplevel 1 [list namespace which -variable $argVarName]]
if {[string equal $fqname ::SelectColor::_unsavedSelection] &&
if {[string equal $argVarName ::SelectColor::_unsavedSelection] &&
[string equal $var2 {}] && [string equal $op "write"]} {
# OK
} else {
@ -822,10 +817,10 @@ proc SelectColor::_SetEntryValue {argVarName var2 op} {
\"$argVarName\", \"$var2\", \"$op\""
}
set col24bit [_24BitRgb [set $fqname]]
set col24bit [::SelectColor::_24BitRgb [set $argVarName]]
if {[_ValidateColorEntry forced $col24bit]} {
set _entryColor $col24bit
set ::SelectColor::_entryColor $col24bit
} else {
# Value is invalid, and if written to _entryColor this would disable
# validation.
@ -876,46 +871,31 @@ proc SelectColor::_ValidateColorEntry {percentV percentP} {
variable _unsavedSelection
set result [regexp -- {^#[0-9a-fA-F]*$} $percentP]
set lenny [string length $percentP]
if {$result} {
# Check for a valid rgb color, which needs 3n+1 characters, n > 0
set lenny [string length $percentP]
set entryincomplete [expr {($lenny - 1) % 3 || $lenny == 1}]
} else {
# Check for named colors
set result [regexp -- {^[a-zA-Z0-9 ]*$} $percentP]
# We do not accept the key stroke
if {!$result} {
return 0
}
# Check for complete named color
set entryincomplete [catch {winfo rgb . $percentP} rgblist]
if {!$entryincomplete} {
set red [expr {[lindex $rgblist 0]/0x100}]
set green [expr {[lindex $rgblist 1]/0x100}]
set blue [expr {[lindex $rgblist 2]/0x100}]
set percentP [format "#%02X%02X%02X" $red $green $blue]
if {[string equal $percentV "forced"]} {
# Validation only. Don't want a loop.
} elseif {[string equal $percentV "key"]} {
# Copy to GUI if a valid color.
if {($lenny - 1) % 3 || $lenny == 1} {
# Not a valid color, which needs 3n+1 characters, n > 0
} else {
after idle [list SelectColor::_SetWithoutTrace $percentP]
}
} elseif {[string equal $percentV "focusout"]} {
# If the color is valid it will already have been copied to the GUI
# and to _userCommand by the "key" validation above.
#
# The code below only needs to reset the value in the entry widget.
# Remove an invalid value, convert a valid one to 24-bit.
# Ignore $percentP, just fire the trace on _unsavedSelection.
set color $_unsavedSelection
after idle [list set ::SelectColor::_unsavedSelection $color]
}
}
if {[string equal $percentV "forced"]} {
# Validation only. Don't want a loop.
} elseif {[string equal $percentV "key"]} {
# Copy to GUI if a valid color.
if {!$entryincomplete} {
after idle [list SelectColor::_SetWithoutTrace $percentP]
}
} elseif {[string equal $percentV "focusout"]} {
# If the color is valid it will already have been copied to the GUI
# and to _userCommand by the "key" validation above.
#
# The code below only needs to reset the value in the entry widget.
# Remove an invalid value, convert a valid one to 24-bit.
# Ignore $percentP, just fire the trace on _unsavedSelection.
set color $_unsavedSelection
after idle [list set SelectColor::_unsavedSelection $color]
}
return 1
return $result
}
@ -928,14 +908,11 @@ proc SelectColor::_ValidateColorEntry {percentV percentP} {
# ------------------------------------------------------------------------------
proc SelectColor::_SetWithoutTrace {value} {
variable _hsv
variable _unsavedSelection
trace remove variable _unsavedSelection write ::SelectColor::_SetEntryValue
trace remove variable ::SelectColor::_unsavedSelection write ::SelectColor::_SetEntryValue
_set_rgb $value
set _hsv [eval rgbToHsv [winfo rgb . $value]]
_set_hue_sat [lindex $_hsv 0] [lindex $_hsv 1]
_set_value [lindex $_hsv 2]
trace add variable _unsavedSelection write ::SelectColor::_SetEntryValue
trace add variable ::SelectColor::_unsavedSelection write ::SelectColor::_SetEntryValue
return
}

10
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/combobox.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/combobox.tcl

@ -19,7 +19,7 @@
# ----------------------------------------------------------------------------
# ComboBox uses the 8.3 -listvariable listbox option
package require Tk 8.3 9
package require Tk 8.3
namespace eval ComboBox {
Widget::define ComboBox combobox ArrowButton Entry ListBox
@ -171,7 +171,7 @@ proc ComboBox::create { path args } {
Widget::configure $path [list -bwlistbox $bw]
}
set ::ComboBox::_index($path) -1
set ComboBox::_index($path) -1
return [Widget::create ComboBox $path]
}
@ -515,7 +515,7 @@ proc ComboBox::_create_popup { path } {
wm withdraw $shell
wm overrideredirect $shell 1
# these commands cause the combobox to behave strangely on OS X
if {! $::Widget::_aqua } {
if {! $Widget::_aqua } {
update idle
wm transient $shell [winfo toplevel $path]
catch { wm attributes $shell -topmost 1 }
@ -703,7 +703,7 @@ proc ComboBox::_mapliste { path } {
wm deiconify $path.shell
raise $path.shell
BWidget::focus set $listb
if {! $::Widget::_aqua } {
if {! $Widget::_aqua } {
BWidget::grab global $path
}
}
@ -717,7 +717,7 @@ proc ComboBox::_unmapliste { path {refocus 1} } {
if {[winfo exists $path.shell] && \
( [string equal [wm state $path.shell] "normal"] ||
[string equal [wm state $path.shell] "zoomed"] ) } {
if {! $::Widget::_aqua } {
if {! $Widget::_aqua } {
BWidget::grab release $path
BWidget::focus release $path.shell.listb $refocus
# Update now because otherwise [focus -force...] makes the app hang!

5
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/basic.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/basic.tcl

@ -184,15 +184,14 @@ proc DemoBasic::_barmcmd { value but arr1 arr2 } {
proc DemoBasic::_butcmd { reason } {
variable count
variable id
variable var
catch {after cancel $id}
if { $reason == "arm" } {
incr count
set var(butcmd) "$reason command called ($count)"
set DemoBasic::var(butcmd) "$reason command called ($count)"
} else {
set count 0
set var(butcmd) "$reason command called"
set DemoBasic::var(butcmd) "$reason command called"
}
set id [after 500 {set DemoBasic::var(butcmd) ""}]
}

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/bwidget.xbm → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/bwidget.xbm

3
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/demo.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/demo.tcl

@ -1,7 +1,6 @@
#!/bin/sh
# The next line is executed by /bin/sh, but not tcl \
exec wish "$0" ${1+"$@"}
package require Tk
namespace eval Demo {
variable _wfont
@ -124,7 +123,7 @@ proc Demo::create { } {
set font [$_wfont cget -font]
pack $_wfont -side left -anchor w
$mainframe addindicator -text "BWidget [package provide BWidget]"
$mainframe addindicator -text "BWidget [package version BWidget]"
$mainframe addindicator -textvariable tk_patchLevel
# NoteBook creation

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/dnd.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/dnd.tcl

18
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/manager.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/manager.tcl

@ -106,15 +106,15 @@ proc DemoManager::_show_progress { } {
variable _status
if { $_progress } {
set ::Demo::status "Compute in progress..."
set ::Demo::prgindic 0
$::Demo::mainframe showstatusbar progression
set Demo::status "Compute in progress..."
set Demo::prgindic 0
$Demo::mainframe showstatusbar progression
if { $_afterid == "" } {
set _afterid [after 30 DemoManager::_update_progress]
}
} else {
set ::Demo::status ""
$::Demo::mainframe showstatusbar status
set Demo::status ""
$Demo::mainframe showstatusbar status
set _afterid ""
}
}
@ -125,13 +125,13 @@ proc DemoManager::_update_progress { } {
variable _afterid
if { $_progress } {
if { $::Demo::prgindic < 100 } {
incr ::Demo::prgindic 5
if { $Demo::prgindic < 100 } {
incr Demo::prgindic 5
set _afterid [after 30 DemoManager::_update_progress]
} else {
set _progress 0
$::Demo::mainframe showstatusbar status
set ::Demo::status "Done"
$Demo::mainframe showstatusbar status
set Demo::status "Done"
set _afterid ""
after 500 {set Demo::status ""}
}

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/select.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/select.tcl

8
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/tmpldlg.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/tmpldlg.tcl

@ -180,7 +180,7 @@ proc DemoDlg::_show_msgdlg { } {
proc DemoDlg::_show_fontdlg { } {
set font [SelectFont .fontdlg -parent . -font $::Demo::font]
set font [SelectFont .fontdlg -parent . -font $Demo::font]
if { $font != "" } {
Demo::update_font $font
}
@ -188,8 +188,8 @@ proc DemoDlg::_show_fontdlg { } {
proc DemoDlg::_show_progdlg { } {
set ::DemoDlg::progmsg "Compute in progress..."
set ::DemoDlg::progval 0
set DemoDlg::progmsg "Compute in progress..."
set DemoDlg::progval 0
ProgressDlg .progress -parent . -title "Wait..." \
-type infinite \
@ -204,7 +204,7 @@ proc DemoDlg::_show_progdlg { } {
proc DemoDlg::_update_progdlg { } {
if { [winfo exists .progress] } {
set ::DemoDlg::progval 2
set DemoDlg::progval 2
after 20 DemoDlg::_update_progdlg
}
}

4
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/tree.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/tree.tcl

@ -84,12 +84,12 @@ proc DemoTree::create { nb } {
proc DemoTree::init { tree list args } {
global tcl_platform env
global tcl_platform
variable count
set count 0
if { $tcl_platform(platform) == "unix" } {
set rootdir [glob $env(HOME)]
set rootdir [glob "~"]
} else {
set rootdir "c:\\"
}

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/demo/x1.xbm → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/demo/x1.xbm

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/dialog.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dialog.tcl

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/dragsite.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dragsite.tcl

6
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/dropsite.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dropsite.tcl

@ -55,7 +55,7 @@ namespace eval DropSite {
ops,link 1
}
if { $::tcl_platform(platform) == "unix" } {
if { $tcl_platform(platform) == "unix" } {
set _tabops(mod,alt) 8
} else {
set _tabops(mod,alt) 16
@ -73,7 +73,7 @@ namespace eval DropSite {
bind DragTop <KeyPress-Shift_R> {DropSite::_update_operation [expr %s | 1]}
bind DragTop <KeyPress-Control_L> {DropSite::_update_operation [expr %s | 4]}
bind DragTop <KeyPress-Control_R> {DropSite::_update_operation [expr %s | 4]}
if { $::tcl_platform(platform) == "unix" } {
if { $tcl_platform(platform) == "unix" } {
bind DragTop <KeyPress-Alt_L> {DropSite::_update_operation [expr %s | 8]}
bind DragTop <KeyPress-Alt_R> {DropSite::_update_operation [expr %s | 8]}
} else {
@ -85,7 +85,7 @@ namespace eval DropSite {
bind DragTop <KeyRelease-Shift_R> {DropSite::_update_operation [expr %s & ~1]}
bind DragTop <KeyRelease-Control_L> {DropSite::_update_operation [expr %s & ~4]}
bind DragTop <KeyRelease-Control_R> {DropSite::_update_operation [expr %s & ~4]}
if { $::tcl_platform(platform) == "unix" } {
if { $tcl_platform(platform) == "unix" } {
bind DragTop <KeyRelease-Alt_L> {DropSite::_update_operation [expr %s & ~8]}
bind DragTop <KeyRelease-Alt_R> {DropSite::_update_operation [expr %s & ~8]}
} else {

6
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/dynhelp.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/dynhelp.tcl

@ -19,11 +19,9 @@
namespace eval DynamicHelp {
Widget::define DynamicHelp dynhelp -classonly
# Namespace variables overwrite global variables in TCL8
# Not changed here, as fixed in TCL9
if {$::tcl_version >= 8.5} {
set fontdefault TkTooltipFont
} elseif {$::Widget::_aqua} {
} elseif {$Widget::_aqua} {
set fontdefault {helvetica 11}
} else {
set fontdefault {helvetica 8}
@ -672,7 +670,7 @@ proc DynamicHelp::_show_help { path w x y } {
-screen [winfo screen $w]
wm withdraw $_top
if { $::Widget::_aqua } {
if { $Widget::_aqua } {
::tk::unsupported::MacWindowStyle style $_top help none
} else {
wm overrideredirect $_top 1

6
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/entry.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/entry.tcl

@ -31,8 +31,6 @@ namespace eval Entry {
-disabledforeground -disabledbackground }
}
# Namespace variables overwrite global variables in TCL8
# Not changed here, as fixed in TCL9
set declare [list \
[list -state Enum normal 0 [list normal disabled]] \
[list -text String "" 0] \
@ -74,8 +72,6 @@ namespace eval Entry {
COLOR {move {}}
}
# Namespace variables overwrite global variables in TCL8
# Not changed here, as fixed in TCL9
if {[Widget::theme]} {
foreach event [bind TEntry] {
bind BwEntry $event [bind TEntry $event]
@ -183,7 +179,7 @@ proc Entry::create { path args } {
proc Entry::configure { path args } {
# Cheat by setting the -text value to the current contents of the entry
# This might be better hidden behind a function in ::Widget.
set ::Widget::Entry::${path}:opt(-text) [$path:cmd get]
set Widget::Entry::${path}:opt(-text) [$path:cmd get]
set res [Widget::configure $path $args]

3
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/font.tcl → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/font.tcl

@ -42,9 +42,6 @@ namespace eval SelectFont {
# Set up preset lists of fonts, so the user can avoid the painfully slow
# loadfont process if desired.
# Namespace variables overwrite global variables in TCL8
# Not changed here, as fixed in TCL9
if { [string equal $::tcl_platform(platform) "windows"] } {
set presetVariable [list \
7x14 \

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/bold.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/bold.gif

Before

Width:  |  Height:  |  Size: 118 B

After

Width:  |  Height:  |  Size: 118 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/copy.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/copy.gif

Before

Width:  |  Height:  |  Size: 145 B

After

Width:  |  Height:  |  Size: 145 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/cut.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/cut.gif

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 130 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/dragfile.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/dragfile.gif

Before

Width:  |  Height:  |  Size: 949 B

After

Width:  |  Height:  |  Size: 949 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/dragicon.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/dragicon.gif

Before

Width:  |  Height:  |  Size: 1012 B

After

Width:  |  Height:  |  Size: 1012 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/error.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/error.gif

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 259 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/file.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/file.gif

Before

Width:  |  Height:  |  Size: 860 B

After

Width:  |  Height:  |  Size: 860 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/folder.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/folder.gif

Before

Width:  |  Height:  |  Size: 139 B

After

Width:  |  Height:  |  Size: 139 B

0
src/vfs/_vfscommon.vfs/lib/BWidget1.10.1/images/hourglass.gif → src/vfs/_vfscommon.vfs/lib/BWidget1.9.16/images/hourglass.gif

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 211 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save