summaryrefslogtreecommitdiffstats
path: root/tcllib/modules/term/ansi
diff options
context:
space:
mode:
Diffstat (limited to 'tcllib/modules/term/ansi')
-rw-r--r--tcllib/modules/term/ansi/code.tcl56
-rw-r--r--tcllib/modules/term/ansi/code/attr.tcl108
-rw-r--r--tcllib/modules/term/ansi/code/ctrl.tcl270
-rw-r--r--tcllib/modules/term/ansi/code/macros.tcl93
-rw-r--r--tcllib/modules/term/ansi/ctrlunix.tcl91
-rw-r--r--tcllib/modules/term/ansi/send.tcl92
6 files changed, 710 insertions, 0 deletions
diff --git a/tcllib/modules/term/ansi/code.tcl b/tcllib/modules/term/ansi/code.tcl
new file mode 100644
index 0000000..a8f7d3e
--- /dev/null
+++ b/tcllib/modules/term/ansi/code.tcl
@@ -0,0 +1,56 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Terminal packages - ANSI
+## Generic commands to define commands for code sequences.
+
+# ### ### ### ######### ######### #########
+## Requirements
+
+namespace eval ::term::ansi::code {}
+
+# ### ### ### ######### ######### #########
+## API. Escape clauses, plain and bracket
+## Used by 'define'd commands.
+
+proc ::term::ansi::code::esc {str} {return \033$str}
+proc ::term::ansi::code::escb {str} {esc \[$str}
+
+# ### ### ### ######### ######### #########
+## API. Define command for named control code, or constant.
+## (Simple definitions without arguments)
+
+proc ::term::ansi::code::define {name escape code} {
+ proc [Qualified $name] {} [list ::term::ansi::code::$escape $code]
+}
+
+proc ::term::ansi::code::const {name code} {
+ proc [Qualified $name] {} [list return $code]
+}
+
+# ### ### ### ######### ######### #########
+## Internal helper to construct fully-qualified names.
+
+proc ::term::ansi::code::Qualified {name} {
+ if {![string match ::* $name]} {
+ # Get the caller's namespace; append :: if it is not the
+ # global namespace, for separation from the actual name.
+ set ns [uplevel 2 [list namespace current]]
+ if {$ns ne "::"} {append ns ::}
+ set name $ns$name
+ }
+ return $name
+}
+
+# ### ### ### ######### ######### #########
+
+namespace eval ::term::ansi::code {
+ namespace export esc escb define const
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide term::ansi::code 0.2
+
+##
+# ### ### ### ######### ######### #########
diff --git a/tcllib/modules/term/ansi/code/attr.tcl b/tcllib/modules/term/ansi/code/attr.tcl
new file mode 100644
index 0000000..842beda
--- /dev/null
+++ b/tcllib/modules/term/ansi/code/attr.tcl
@@ -0,0 +1,108 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Terminal packages - ANSI - Attribute codes
+
+# ### ### ### ######### ######### #########
+## Requirements
+
+package require term::ansi::code ; # Constants
+
+namespace eval ::term::ansi::code::attr {}
+
+# ### ### ### ######### ######### #########
+## API. Symbolic names.
+
+proc ::term::ansi::code::attr::names {} {
+ variable attr
+ return $attr
+}
+
+proc ::term::ansi::code::attr::import {{ns attr} args} {
+ if {![llength $args]} {set args *}
+ set args ::term::ansi::code::attr::[join $args " ::term::ansi::code::attr::"]
+ uplevel 1 [list namespace eval ${ns} [linsert $args 0 namespace import]]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal - Setup
+
+proc ::term::ansi::code::attr::DEF {name value} {
+ variable attr
+ const $name $value
+ lappend attr $name
+ namespace export $name
+ return
+}
+
+proc ::term::ansi::code::attr::INIT {} {
+ # ### ### ### ######### ######### #########
+ ##
+
+ # Colors. Foreground <=> Text
+ DEF fgblack 30 ; # Black
+ DEF fgred 31 ; # Red
+ DEF fggreen 32 ; # Green
+ DEF fgyellow 33 ; # Yellow
+ DEF fgblue 34 ; # Blue
+ DEF fgmagenta 35 ; # Magenta
+ DEF fgcyan 36 ; # Cyan
+ DEF fgwhite 37 ; # White
+ DEF fgdefault 39 ; # Default (Black)
+
+ # Colors. Background.
+ DEF bgblack 40 ; # Black
+ DEF bgred 41 ; # Red
+ DEF bggreen 42 ; # Green
+ DEF bgyellow 43 ; # Yellow
+ DEF bgblue 44 ; # Blue
+ DEF bgmagenta 45 ; # Magenta
+ DEF bgcyan 46 ; # Cyan
+ DEF bgwhite 47 ; # White
+ DEF bgdefault 49 ; # Default (Transparent)
+
+ # Non-color attributes. Activation.
+ DEF bold 1 ; # Bold
+ DEF dim 2 ; # Dim
+ DEF italic 3 ; # Italics
+ DEF underline 4 ; # Underscore
+ DEF blink 5 ; # Blink
+ DEF revers 7 ; # Reverse
+ DEF hidden 8 ; # Hidden
+ DEF strike 9 ; # StrikeThrough
+
+ # Non-color attributes. Deactivation.
+ DEF nobold 22 ; # Bold
+ DEF nodim __ ; # Dim
+ DEF noitalic 23 ; # Italics
+ DEF nounderline 24 ; # Underscore
+ DEF noblink 25 ; # Blink
+ DEF norevers 27 ; # Reverse
+ DEF nohidden 28 ; # Hidden
+ DEF nostrike 29 ; # StrikeThrough
+
+ # Remainder
+ DEF reset 0 ; # Reset
+
+ ##
+ # ### ### ### ######### ######### #########
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Data structures.
+
+namespace eval ::term::ansi::code::attr {
+ namespace import ::term::ansi::code::const
+ variable attr {}
+}
+
+::term::ansi::code::attr::INIT
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide term::ansi::code::attr 0.1
+
+##
+# ### ### ### ######### ######### #########
diff --git a/tcllib/modules/term/ansi/code/ctrl.tcl b/tcllib/modules/term/ansi/code/ctrl.tcl
new file mode 100644
index 0000000..167ae80
--- /dev/null
+++ b/tcllib/modules/term/ansi/code/ctrl.tcl
@@ -0,0 +1,270 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Terminal packages - ANSI - Control codes
+
+## References
+# [0] Google: ansi terminal control
+# [1] http://vt100.net/docs/vt100-ug/chapter3.html
+# [2] http://www.termsys.demon.co.uk/vtansi.htm
+# [3] http://rrbrandt.dyndns.org:60000/docs/tut/redes/ansi.php
+# [4] http://www.dee.ufcg.edu.br/~rrbrandt/tools/ansi.html
+# [5] http://www.ecma-international.org/publications/standards/Ecma-048.htm
+
+# ### ### ### ######### ######### #########
+## Requirements
+
+package require term::ansi::code
+package require term::ansi::code::attr
+
+namespace eval ::term::ansi::code::ctrl {}
+
+# ### ### ### ######### ######### #########
+## API. Symbolic names.
+
+proc ::term::ansi::code::ctrl::names {} {
+ variable ctrl
+ return $ctrl
+}
+
+proc ::term::ansi::code::ctrl::import {{ns ctrl} args} {
+ if {![llength $args]} {set args *}
+ set args ::term::ansi::code::ctrl::[join $args " ::term::ansi::code::ctrl::"]
+ uplevel 1 [list namespace eval $ns [linsert $args 0 namespace import]]
+ return
+}
+
+# ### ### ### ######### ######### #########
+
+## TODO = symbolic key codes for skd.
+
+# ### ### ### ######### ######### #########
+## Internal - Setup
+
+proc ::term::ansi::code::ctrl::DEF {name esc value} {
+ variable ctrl
+ define $name $esc $value
+ lappend ctrl $name
+ namespace export $name
+ return
+}
+
+proc ::term::ansi::code::ctrl::DEFC {name arguments script} {
+ variable ctrl
+ proc $name $arguments $script
+ lappend ctrl $name
+ namespace export $name
+ return
+}
+
+proc ::term::ansi::code::ctrl::INIT {} {
+ # ### ### ### ######### ######### #########
+ ##
+
+ # Erasing
+
+ DEF eeol escb K ; # Erase (to) End Of Line
+ DEF esol escb 1K ; # Erase (to) Start Of Line
+ DEF el escb 2K ; # Erase (current) Line
+ DEF ed escb J ; # Erase Down (to bottom)
+ DEF eu escb 1J ; # Erase Up (to top)
+ DEF es escb 2J ; # Erase Screen
+
+ # Scrolling
+
+ DEF sd esc D ; # Scroll Down
+ DEF su esc M ; # Scroll Up
+
+ # Cursor Handling
+
+ DEF ch escb H ; # Cursor Home
+ DEF sc escb s ; # Save Cursor
+ DEF rc escb u ; # Restore Cursor (Unsave)
+ DEF sca esc 7 ; # Save Cursor + Attributes
+ DEF rca esc 8 ; # Restore Cursor + Attributes
+
+ # Tabbing
+
+ DEF st esc H ; # Set Tab (@ current position)
+ DEF ct escb g ; # Clear Tab (@ current position)
+ DEF cat escb 3g ; # Clear All Tabs
+
+ # Device Introspection
+
+ DEF qdc escb c ; # Query Device Code
+ DEF qds escb 5n ; # Query Device Status
+ DEF qcp escb 6n ; # Query Cursor Position
+ DEF rd esc c ; # Reset Device
+
+ # Linewrap on/off
+
+ DEF elw escb 7h ; # Enable Line Wrap
+ DEF dlw escb 7l ; # Disable Line Wrap
+
+ # Graphics Mode (aka use alternate font on/off)
+
+ DEF eg esc F ; # Enter Graphics Mode
+ DEF lg esc G ; # Exit Graphics Mode
+
+ ##
+ # ### ### ### ######### ######### #########
+
+ # ### ### ### ######### ######### #########
+ ## Complex, parameterized codes
+
+ # Select Character Set
+ # Choose which char set is used for default and
+ # alternate font. This does not change whether
+ # default or alternate font are used
+
+ DEFC scs0 {tag} {esc ($tag} ; # Set default character set
+ DEFC scs1 {tag} {esc )$tag} ; # Set alternate character set
+
+ # tags in A : United Kingdom Set
+ # B : ASCII Set
+ # 0 : Special Graphics
+ # 1 : Alternate Character ROM Standard Character Set
+ # 2 : Alternate Character ROM Special Graphics
+
+ # Set Display Attributes
+
+ DEFC sda {args} {escb [join $args \;]m}
+
+ # Force Cursor Position (aka Go To)
+
+ DEFC fcp {r c} {escb ${r}\;${c}f}
+
+ # Cursor Up, Down, Forward, Backward
+
+ DEFC cu {{n 1}} {escb [expr {$n == 1 ? "A" : "${n}A"}]}
+ DEFC cd {{n 1}} {escb [expr {$n == 1 ? "B" : "${n}B"}]}
+ DEFC cf {{n 1}} {escb [expr {$n == 1 ? "C" : "${n}C"}]}
+ DEFC cb {{n 1}} {escb [expr {$n == 1 ? "D" : "${n}D"}]}
+
+ # Scroll Screen (entire display, or between rows start end, inclusive).
+
+ DEFC ss {args} {
+ if {[llength $args] == 0} {return [escb r]}
+ if {[llength $args] == 2} {foreach {s e} $args break ; return [escb ${s};${e}r]}
+ return -code error "wrong\#args"
+ }
+
+ # Set Key Definition
+
+ DEFC skd {code str} {escb $code\;\"$str\"p}
+
+ # Terminal title
+
+ DEFC title {str} {esc \]0\;$str\007}
+
+ # Switch to and from character/box graphics.
+
+ DEFC gron {} {return \016}
+ DEFC groff {} {return \017}
+
+ # Character graphics, box symbols
+ # - 4 corners, 4 t-junctions,
+ # one 4-way junction, 2 lines
+
+ DEFC tlc {} {return [gron]l[groff]} ; # Top Left Corner
+ DEFC trc {} {return [gron]k[groff]} ; # Top Right Corner
+ DEFC brc {} {return [gron]j[groff]} ; # Bottom Right Corner
+ DEFC blc {} {return [gron]m[groff]} ; # Bottom Left Corner
+
+ DEFC ltj {} {return [gron]t[groff]} ; # Left T Junction
+ DEFC ttj {} {return [gron]w[groff]} ; # Top T Junction
+ DEFC rtj {} {return [gron]u[groff]} ; # Right T Junction
+ DEFC btj {} {return [gron]v[groff]} ; # Bottom T Junction
+
+ DEFC fwj {} {return [gron]n[groff]} ; # Four-Way Junction
+
+ DEFC hl {} {return [gron]q[groff]} ; # Horizontal Line
+ DEFC vl {} {return [gron]x[groff]} ; # Vertical Line
+
+ # Optimize character graphics. The generator commands above create
+ # way to many superfluous commands shifting into and out of the
+ # graphics mode. The command below removes all shifts which are
+ # not needed. To this end it also knows which characters will look
+ # the same in both modes, to handle strings created outside this
+ # package.
+
+ DEFC groptim {string} {
+ variable grforw
+ variable grback
+ while {![string equal $string [set new [string map \
+ [list \017\016 {} \016\017 {}] [string map \
+ $grback [string map \
+ $grforw $string]]]]]} {
+ set string $new
+ }
+ return $string
+ }
+
+ ##
+ # ### ### ### ######### ######### #########
+
+ # ### ### ### ######### ######### #########
+ ## Higher level operations
+
+ # Clear screen <=> CursorHome + EraseDown
+ # Init (Fonts): Default ASCII, Alternate Graphics
+ # Show a block of text at a specific location.
+
+ DEFC clear {} {return [ch][ed]}
+ DEFC init {} {return [scs0 B][scs1 0]}
+
+ DEFC showat {r c text} {
+ if {![string length $text]} {return {}}
+ return [fcp $r $c][sca][join \
+ [split $text \n] \
+ [rca][cd][sca]][rca][cd]
+ }
+
+ ##
+ # ### ### ### ######### ######### #########
+
+ # ### ### ### ######### ######### #########
+ ## Attribute control (single attributes)
+
+ foreach a [::term::ansi::code::attr::names] {
+ DEF sda_$a escb [::term::ansi::code::attr::$a]m
+ }
+
+ ##
+ # ### ### ### ######### ######### #########
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Data structures.
+
+namespace eval ::term::ansi::code::ctrl {
+ namespace import ::term::ansi::code::define
+ namespace import ::term::ansi::code::esc
+ namespace import ::term::ansi::code::escb
+
+ variable grforw
+ variable grback
+ variable _
+
+ foreach _ {
+ ! \" # $ % & ' ( ) * + , - . /
+ 0 1 2 3 4 5 6 7 8 9 : ; < = >
+ ? @ 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 [ ^
+ \\ ]
+ } {
+ lappend grforw \016$_ $_\016
+ lappend grback $_\017 \017$_
+ }
+ unset _
+}
+
+::term::ansi::code::ctrl::INIT
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide term::ansi::code::ctrl 0.2
+
+##
+# ### ### ### ######### ######### #########
diff --git a/tcllib/modules/term/ansi/code/macros.tcl b/tcllib/modules/term/ansi/code/macros.tcl
new file mode 100644
index 0000000..1f1d47d
--- /dev/null
+++ b/tcllib/modules/term/ansi/code/macros.tcl
@@ -0,0 +1,93 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Terminal packages - ANSI - Higher level macros
+
+# ### ### ### ######### ######### #########
+## Requirements
+
+package require textutil::repeat
+package require textutil::tabify
+package require term::ansi::code::ctrl
+
+namespace eval ::term::ansi::code::macros {}
+
+# ### ### ### ######### ######### #########
+## API. Symbolic names.
+
+proc ::term::ansi::code::macros::import {{ns macros} args} {
+ if {![llength $args]} {set args *}
+ set args ::term::ansi::code::macros::[join $args " ::term::ansi::code::macros::"]
+ uplevel 1 [list namespace eval ${ns} [linsert $args 0 namespace import]]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Higher level operations
+
+# Format a menu / framed block of text
+
+proc ::term::ansi::code::macros::menu {menu} {
+ # Menu = dict (label => char)
+ array set _ {}
+ set shift 0
+ foreach {label c} $menu {
+ if {[string first $c $label] < 0} {
+ set shift 1
+ break
+ }
+ }
+ set max 0
+ foreach {label c} $menu {
+ set pos [string first $c $label]
+ if {$shift || ($pos < 0)} {
+ set xlabel "$c $label"
+ set pos 0
+ } else {
+ set xlabel $label
+ }
+ set len [string length $xlabel]
+ if {$len > $max} {set max $len}
+ set _($label) " [string replace $xlabel $pos $pos \
+ [cd::sda_fgred][cd::sda_bold][string index $xlabel $pos][cd::sda_reset]]"
+ }
+
+ append ms [cd::tlc][textutil::repeat::strRepeat [cd::hl] $max][cd::trc]\n
+ foreach {l c} $menu {append ms $_($l)\n}
+ append ms [cd::blc][textutil::repeat::strRepeat [cd::hl] $max][cd::brc]
+
+ return [cd::groptim $ms]
+}
+
+proc ::term::ansi::code::macros::frame {string} {
+ set lines [split [textutil::tabify::untabify2 $string] \n]
+ set max 0
+ foreach l $lines {
+ if {[set len [string length $l]] > $max} {set max $len}
+ }
+ append fs [cd::tlc][textutil::repeat::strRepeat [cd::hl] $max][cd::trc]\n
+ foreach l $lines {
+ append fs [cd::vl]${l}[textutil::repeat::strRepeat " " [expr {$max-[string length $l]}]][cd::vl]\n
+ }
+ append fs [cd::blc][textutil::repeat::strRepeat [cd::hl] $max][cd::brc]
+ return [cd::groptim $fs]
+}
+
+##
+# ### ### ### ######### ######### #########
+
+# ### ### ### ######### ######### #########
+## Data structures.
+
+namespace eval ::term::ansi::code::macros {
+ term::ansi::code::ctrl::import cd
+
+ namespace export menu frame
+}
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide term::ansi::code::macros 0.1
+
+##
+# ### ### ### ######### ######### #########
diff --git a/tcllib/modules/term/ansi/ctrlunix.tcl b/tcllib/modules/term/ansi/ctrlunix.tcl
new file mode 100644
index 0000000..675348c
--- /dev/null
+++ b/tcllib/modules/term/ansi/ctrlunix.tcl
@@ -0,0 +1,91 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Terminal packages - ANSI - Control operations
+## (Unix specific implementation).
+
+## This was originally taken from page 11820 (Pure Tcl Console Editor)
+## of the Tcler's Wiki, however page 14693 (Reading a single character
+## ...) is the same in a more self-contained manner.
+
+# ### ### ### ######### ######### #########
+## Requirements
+
+namespace eval ::term::ansi::ctrl::unix {}
+
+# ### ### ### ######### ######### #########
+## Make command easily available
+
+proc ::term::ansi::ctrl::unix::import {{ns ctrl} args} {
+ if {![llength $args]} {set args *}
+ set args ::term::ansi::ctrl::unix::[join $args " ::term::ansi::ctrl::unix::"]
+ uplevel 1 [list namespace eval ${ns} [linsert $args 0 namespace import]]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## API
+
+# We use the <@stdin because stty works out what terminal to work with
+# using standard input on some platforms. On others it prefers
+# /dev/tty instead, but putting in the redirection makes the code more
+# portable
+
+proc ::term::ansi::ctrl::unix::raw {} {
+ variable stty
+ exec $stty raw -echo <@stdin
+ return
+}
+
+proc ::term::ansi::ctrl::unix::cooked {} {
+ variable stty
+ exec $stty -raw echo <@stdin
+ return
+}
+
+proc ::term::ansi::ctrl::unix::columns {} {
+ variable tput
+ return [exec $tput cols <@stdin]
+}
+
+proc ::term::ansi::ctrl::unix::rows {} {
+ variable tput
+ return [exec $tput lines <@stdin]
+}
+
+# ### ### ### ######### ######### #########
+## Package setup
+
+proc ::term::ansi::ctrl::unix::INIT {} {
+ variable tput [auto_execok tput]
+ variable stty [auto_execok stty]
+
+ if {($stty eq "/usr/ucb/stty") &&
+ ($::tcl_platform(os) eq "SunOS")} {
+ set stty /usr/bin/stty
+ }
+
+ if {($tput eq "") || ($stty eq "")} {
+ return -code error \
+ "The external requirements for the \
+ use of this package (tput, stty in \
+ \$PATH) are not met."
+ }
+ return
+}
+
+namespace eval ::term::ansi::ctrl::unix {
+ variable tput {}
+ variable stty {}
+
+ namespace export columns rows raw cooked
+}
+
+::term::ansi::ctrl::unix::INIT
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide term::ansi::ctrl::unix 0.1.1
+
+##
+# ### ### ### ######### ######### #########
diff --git a/tcllib/modules/term/ansi/send.tcl b/tcllib/modules/term/ansi/send.tcl
new file mode 100644
index 0000000..d47f834
--- /dev/null
+++ b/tcllib/modules/term/ansi/send.tcl
@@ -0,0 +1,92 @@
+# -*- tcl -*-
+# ### ### ### ######### ######### #########
+## Terminal packages - ANSI - Control codes
+
+# ### ### ### ######### ######### #########
+## Requirements
+
+package require Tcl 8.4
+package require term::send
+package require term::ansi::code::ctrl
+
+namespace eval ::term::ansi::send {}
+
+# ### ### ### ######### ######### #########
+## Make command easily available
+
+proc ::term::ansi::send::import {{ns send} args} {
+ if {![llength $args]} {set args *}
+ set args ::term::ansi::send::[join $args " ::term::ansi::send::"]
+ uplevel 1 [list namespace eval ${ns} [linsert $args 0 namespace import]]
+ return
+}
+
+# ### ### ### ######### ######### #########
+## Internal - Setup.
+
+proc ::term::ansi::send::ChName {n} {
+ if {![string match *-* $n]} {
+ return ${n}ch
+ }
+ set nl [split $n -]
+ set stem [lindex $nl 0]
+ set sfx [join [lrange $nl 1 end] -]
+ return ${stem}ch-$sfx
+}
+
+proc ::term::ansi::send::Args {n -> arv achv avv} {
+ upvar 1 $arv a $achv ach $avv av
+ set code ::term::ansi::code::ctrl::$n
+ set a [info args $code]
+ set av [expr {
+ [llength $a]
+ ? " \$[join $a { $}]"
+ : $a
+ }]
+ foreach a1 $a[set a {}] {
+ if {[info default $code $a1 default]} {
+ lappend a [list $a1 $default]
+ } else {
+ lappend a $a1
+ }
+ }
+ set ach [linsert $a 0 ch]
+ return $code
+}
+
+proc ::term::ansi::send::INIT {} {
+ foreach n [::term::ansi::code::ctrl::names] {
+ set nch [ChName $n]
+ set code [Args $n -> a ach av]
+
+ if {[lindex $a end] eq "args"} {
+ # An args argument requires more care, and an eval
+ set av [lrange $av 0 end-1]
+ if {$av ne {}} {set av " $av"}
+ set gen "eval \[linsert \$args 0 $code$av\]"
+ #8.5: (written for clarity): set gen "$code$av {*}\$args"
+ } else {
+ set gen $code$av
+ }
+
+ proc $n $a "wr \[$gen\]" ; namespace export $n
+ proc $nch $ach "wrch \$ch \[$gen\]" ; namespace export $nch
+ }
+ return
+}
+
+namespace eval ::term::ansi::send {
+ namespace import ::term::send::wr
+ namespace import ::term::send::wrch
+ namespace export wr wrch
+}
+
+::term::ansi::send::INIT
+
+# ### ### ### ######### ######### #########
+## Ready
+
+package provide term::ansi::send 0.2
+
+##
+# ### ### ### ######### ######### #########