Browse Source

ansi improvements

master
Julian Noble 11 months ago
parent
commit
ceb66b4f65
  1. 25
      src/modules/punk-0.1.tm
  2. 100
      src/modules/punk/char-999999.0a1.0.tm
  3. 758
      src/modules/punk/char/emoji-variation-sequences.txt
  4. 253
      src/modules/punk/console-999999.0a1.0.tm
  5. 2
      src/modules/punk/ns-999999.0a1.0.tm
  6. 20
      src/modules/punk/repo-999999.0a1.0.tm
  7. 55
      src/modules/shellfilter-0.1.8.tm
  8. 141
      src/modules/textblock-999999.0a1.0.tm
  9. 20
      src/punk86.vfs/lib/app-punk/repl.tcl
  10. 623
      src/vendormodules/overtype-1.5.0.tm

25
src/modules/punk-0.1.tm

@ -6017,13 +6017,24 @@ namespace eval punk {
# important for pipeline & match_assign
# -line trimline|trimleft|trimright -block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty -commandprefix {string length} ?
# -block trimming only trims completely empty lines. use -line trimming to remove whitespace e.g -line trimright will clear empty lines without affecting leading whitespace on other lines that aren't pure whitespace
proc linelist {text args} {
proc linelist {args} {
set usage "linelist ?-line trimline|trimleft|trimright? ?-block trimhead|trimtail|triminner|trimall|trimhead1|trimtail1|collateempty? -commandprefix <cmdlist> text"
if {[llength $args] == 0} {
error "linelist missing textchunk argument usage:$usage"
}
set text [lindex $args end]
set arglist [lrange $args 0 end-1]
set defaults [dict create\
-block {trimhead1 trimtail1}\
-line {}\
-commandprefix ""\
]
set opts [dict merge $defaults $args]
foreach {o v} $arglist {
if {$o ni [dict keys $defaults]} {
error "linelist: Unrecognized option '$o' usage:$usage"
}
}
set opts [dict merge $defaults $arglist]
# -- --- --- --- --- ---
set opt_block [dict get $opts -block]
set known_blockopts [list trimhead trimtail triminner trimall trimhead1 trimtail1 collateempty]
@ -6131,11 +6142,13 @@ namespace eval punk {
#e.g linesort -decreasing $data
proc linesort {args} {
if {[llength $args] < 1} {
error "linesort missing lines argument"
}
set lines [lindex $args end]
if {[llength $args] > 1} {
set opts [lrange $args 0 end-1]
} else {
set opts [list]
set opts [lrange $args 0 end-1]
if {[llength $opts] % 2 != 0} {
error "linesort options must come in pairs"
}
.= list $lines |@0,sortopts/1> linelist |> .=data>1,sortopts>1* lsort |> list_as_lines <| {*}$opts
}

100
src/modules/punk/char-999999.0a1.0.tm

@ -283,6 +283,16 @@ namespace eval punk::char {
}
return $outchar
}
proc pagechar_info {page num} {
package require punk::console
puts -nonewline stdout \033\[s;flush stdout
set posn1 [punk::console::get_cursor_position]
set h [format %04x $num]
puts -nonewline stdout "[format %c [subst 0x$h]]";flush stdout
set posn2 [punk::console::get_cursor_position]
puts -nonewline stdout "\033\[u";flush stdout
return "$posn1 -> $posn2"
}
proc pagebyte {page num} {
set encpage $page
@ -461,10 +471,10 @@ namespace eval punk::char {
#todo - benchmark peformance - improve punk pipeline
proc asciidict128 {} {
regexp -all -inline {\S+} [concat {*}[linelist [ascii] -line trimleft]]
regexp -all -inline {\S+} [concat {*}[linelist -line trimleft [ascii]]]
}
proc _asciidict128 {} {
.= ascii |> .=>1 linelist -line trimleft |> .=* concat |> {regexp -all -inline {\S+} $data}
.= ascii |> .=> linelist -line trimleft |> .=* concat |> {regexp -all -inline {\S+} $data}
}
proc asciidict2 {} {
@ -523,6 +533,43 @@ namespace eval punk::char {
puts "reencoded: [encoding convertfrom $encoding $eyat] [encoding convertfrom $encoding $ebun]"
return $yatbun
}
proc test_grave {} {
set g [format %c 0x300]
puts stdout "Testing console display of grave accented a in between letters x and y - accent should combine over the top of the letter a."
puts stdout "Apparent width should theoretically be 1 console-column"
package require punk::console
puts stdout "# -- --- --- ---"
puts -nonewline "xa${g}z";set cursorposn [punk::console::get_cursor_position]
puts stdout \n
puts stdout "cursor position immediately after outputing 4 bytes (expecting 3 glyphs): $cursorposn"
puts stdout "# -- --- --- ---"
puts -nonewline "xyz";set cursorposn [punk::console::get_cursor_position]
puts stdout \n
puts stdout "cursor position immediately after outputing 3 bytes (xyz): $cursorposn"
}
proc test_farmer {} {
#an interesting article re grapheme clustering problems in terminals https://mitchellh.com/writing/grapheme-clusters-in-terminals
#(similar to the problem with grave accent rendering width that the test_grave proc is written for)
set test_farmer1 🧑🌾 ;#contains zero-width joiner between
set test_farmer2 🧑🌾
set farmer1 "\U0001f9d1\U0000200d\U0001f33e"
set farmer2 "\U0001f9d1\U0001f33e"
puts stdout "farmer1 with zero-width joiner: $farmer1"
puts stdout "farmer2 with no joiner : $farmer2"
package require punk::console
puts stdout "#2--5---9---C---"
puts -nonewline "${farmer1}";set cursorposn [punk::console::get_cursor_position]
puts stdout \n
puts stdout "cursor position immediately after outputing farmer1 (expecting 1 glyph 2 wide): $cursorposn"
puts stdout "#2--5---9---C---"
puts -nonewline "${farmer2}";set cursorposn [punk::console::get_cursor_position]
puts stdout \n
puts stdout "cursor position immediately after outputing farmer2 (expecting 1 glyph 2 wide): $cursorposn"
return [list $farmer1 $farmer2]
}
#G0 Sets Sequence G1 Sets Sequence Meaning
#ESC ( A ESC ) A United Kingdom Set
@ -581,6 +628,29 @@ namespace eval punk::char {
#...
dict set charinfo 10175 [list desc "Double Curly Loop" short "dingbats_double_curly_loop"]
# -- -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
#variation selectors 0xFe01 - 0xFE0F
dict set charsets "variation selectors" [list ranges [list {start 65024 end 65039}] description "Variation Selectors" note "combining character with previous char - variant glyph display"]
dict set charinfo 65024 [list desc "Variation Selector-1" short "VS1"]
dict set charinfo 65025 [list desc "Variation Selector-2" short "VS2"]
dict set charinfo 65026 [list desc "Variation Selector-3" short "VS3"]
dict set charinfo 65027 [list desc "Variation Selector-4" short "VS4"]
dict set charinfo 65027 [list desc "Variation Selector-5" short "VS5"]
dict set charinfo 65029 [list desc "Variation Selector-6" short "VS6"]
dict set charinfo 65030 [list desc "Variation Selector-7" short "VS7"]
dict set charinfo 65031 [list desc "Variation Selector-8" short "VS8"]
dict set charinfo 65032 [list desc "Variation Selector-9" short "VS9"]
dict set charinfo 65033 [list desc "Variation Selector-10" short "VS10"]
dict set charinfo 65034 [list desc "Variation Selector-11" short "VS11"]
dict set charinfo 65035 [list desc "Variation Selector-12" short "VS12"]
dict set charinfo 65036 [list desc "Variation Selector-13" short "VS13"]
dict set charinfo 65037 [list desc "Variation Selector-14" short "VS14"]
dict set charinfo 65038 [list desc "Variation Selector-15 text variation" short "VS15"] ;#still an image - just more suitable for text-presentation e.g word-processing doc
dict set charinfo 65039 [list desc "Variation Selector-16 emoji variation" short "VS16"]
# -- -- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
# emoticons https://www.unicode.org/charts/PDF/U1F600.pdf
dict set charsets "emoticons" [list ranges [list {start 128512 end 128591}] description "Emoticons"]
@ -850,6 +920,28 @@ namespace eval punk::char {
return [charset_dict "box_drawing"]
}
proc char_info {char} {
variable charinfo
variable charsets
set dec_char [scan $char %c]
set hex_char [format %x $dec_char]
set memberof [list]
dict for {setname setinfo} $charsets {
set ranges [dict get $setinfo ranges]
foreach r $ranges {
set s [dict get $r start]
set e [dict get $r end]
if {$dec_char >= $s && $dec_char <= $e} {
lappend member_of $setname
break
}
}
}
set returninfo [dict get $charinfo $dec_char]
dict set returninfo memberof $memberof
dict set returninfo hex $
return $returninfo
}
proc char_range_dict {start end args} {
if {![string is integer -strict $start] || ![string is integer -strict $end]} {
error "char_range_dict error start and end must be integers"
@ -909,6 +1001,10 @@ namespace eval punk::char {
variable charsets
return [dict keys $charsets]
}
proc charset_def {charsetname} {
variable charsets
return [dict get $charsets $charsetname]
}
proc charset_dict {name} {
variable charsets
if {$name ni [charset_names]} {

758
src/modules/punk/char/emoji-variation-sequences.txt

@ -0,0 +1,758 @@
# emoji-variation-sequences.txt
# Date: 2023-02-01, 02:22:54 GMT
# © 2023 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see https://www.unicode.org/terms_of_use.html
#
# Emoji Variation Sequences for UTS #51
# Used with Emoji Version 15.1 and subsequent minor revisions (if any)
#
# For documentation and usage, see https://www.unicode.org/reports/tr51
#
0023 FE0E ; text style; # (1.1) NUMBER SIGN
0023 FE0F ; emoji style; # (1.1) NUMBER SIGN
002A FE0E ; text style; # (1.1) ASTERISK
002A FE0F ; emoji style; # (1.1) ASTERISK
0030 FE0E ; text style; # (1.1) DIGIT ZERO
0030 FE0F ; emoji style; # (1.1) DIGIT ZERO
0031 FE0E ; text style; # (1.1) DIGIT ONE
0031 FE0F ; emoji style; # (1.1) DIGIT ONE
0032 FE0E ; text style; # (1.1) DIGIT TWO
0032 FE0F ; emoji style; # (1.1) DIGIT TWO
0033 FE0E ; text style; # (1.1) DIGIT THREE
0033 FE0F ; emoji style; # (1.1) DIGIT THREE
0034 FE0E ; text style; # (1.1) DIGIT FOUR
0034 FE0F ; emoji style; # (1.1) DIGIT FOUR
0035 FE0E ; text style; # (1.1) DIGIT FIVE
0035 FE0F ; emoji style; # (1.1) DIGIT FIVE
0036 FE0E ; text style; # (1.1) DIGIT SIX
0036 FE0F ; emoji style; # (1.1) DIGIT SIX
0037 FE0E ; text style; # (1.1) DIGIT SEVEN
0037 FE0F ; emoji style; # (1.1) DIGIT SEVEN
0038 FE0E ; text style; # (1.1) DIGIT EIGHT
0038 FE0F ; emoji style; # (1.1) DIGIT EIGHT
0039 FE0E ; text style; # (1.1) DIGIT NINE
0039 FE0F ; emoji style; # (1.1) DIGIT NINE
00A9 FE0E ; text style; # (1.1) COPYRIGHT SIGN
00A9 FE0F ; emoji style; # (1.1) COPYRIGHT SIGN
00AE FE0E ; text style; # (1.1) REGISTERED SIGN
00AE FE0F ; emoji style; # (1.1) REGISTERED SIGN
203C FE0E ; text style; # (1.1) DOUBLE EXCLAMATION MARK
203C FE0F ; emoji style; # (1.1) DOUBLE EXCLAMATION MARK
2049 FE0E ; text style; # (3.0) EXCLAMATION QUESTION MARK
2049 FE0F ; emoji style; # (3.0) EXCLAMATION QUESTION MARK
2122 FE0E ; text style; # (1.1) TRADE MARK SIGN
2122 FE0F ; emoji style; # (1.1) TRADE MARK SIGN
2139 FE0E ; text style; # (3.0) INFORMATION SOURCE
2139 FE0F ; emoji style; # (3.0) INFORMATION SOURCE
2194 FE0E ; text style; # (1.1) LEFT RIGHT ARROW
2194 FE0F ; emoji style; # (1.1) LEFT RIGHT ARROW
2195 FE0E ; text style; # (1.1) UP DOWN ARROW
2195 FE0F ; emoji style; # (1.1) UP DOWN ARROW
2196 FE0E ; text style; # (1.1) NORTH WEST ARROW
2196 FE0F ; emoji style; # (1.1) NORTH WEST ARROW
2197 FE0E ; text style; # (1.1) NORTH EAST ARROW
2197 FE0F ; emoji style; # (1.1) NORTH EAST ARROW
2198 FE0E ; text style; # (1.1) SOUTH EAST ARROW
2198 FE0F ; emoji style; # (1.1) SOUTH EAST ARROW
2199 FE0E ; text style; # (1.1) SOUTH WEST ARROW
2199 FE0F ; emoji style; # (1.1) SOUTH WEST ARROW
21A9 FE0E ; text style; # (1.1) LEFTWARDS ARROW WITH HOOK
21A9 FE0F ; emoji style; # (1.1) LEFTWARDS ARROW WITH HOOK
21AA FE0E ; text style; # (1.1) RIGHTWARDS ARROW WITH HOOK
21AA FE0F ; emoji style; # (1.1) RIGHTWARDS ARROW WITH HOOK
231A FE0E ; text style; # (1.1) WATCH
231A FE0F ; emoji style; # (1.1) WATCH
231B FE0E ; text style; # (1.1) HOURGLASS
231B FE0F ; emoji style; # (1.1) HOURGLASS
2328 FE0E ; text style; # (1.1) KEYBOARD
2328 FE0F ; emoji style; # (1.1) KEYBOARD
23CF FE0E ; text style; # (4.0) EJECT SYMBOL
23CF FE0F ; emoji style; # (4.0) EJECT SYMBOL
23E9 FE0E ; text style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE
23E9 FE0F ; emoji style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE
23EA FE0E ; text style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE
23EA FE0F ; emoji style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE
23EB FE0E ; text style; # (6.0) BLACK UP-POINTING DOUBLE TRIANGLE
23EB FE0F ; emoji style; # (6.0) BLACK UP-POINTING DOUBLE TRIANGLE
23EC FE0E ; text style; # (6.0) BLACK DOWN-POINTING DOUBLE TRIANGLE
23EC FE0F ; emoji style; # (6.0) BLACK DOWN-POINTING DOUBLE TRIANGLE
23ED FE0E ; text style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
23ED FE0F ; emoji style; # (6.0) BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
23EE FE0E ; text style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
23EE FE0F ; emoji style; # (6.0) BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
23EF FE0E ; text style; # (6.0) BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
23EF FE0F ; emoji style; # (6.0) BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
23F0 FE0E ; text style; # (6.0) ALARM CLOCK
23F0 FE0F ; emoji style; # (6.0) ALARM CLOCK
23F1 FE0E ; text style; # (6.0) STOPWATCH
23F1 FE0F ; emoji style; # (6.0) STOPWATCH
23F2 FE0E ; text style; # (6.0) TIMER CLOCK
23F2 FE0F ; emoji style; # (6.0) TIMER CLOCK
23F3 FE0E ; text style; # (6.0) HOURGLASS WITH FLOWING SAND
23F3 FE0F ; emoji style; # (6.0) HOURGLASS WITH FLOWING SAND
23F8 FE0E ; text style; # (7.0) DOUBLE VERTICAL BAR
23F8 FE0F ; emoji style; # (7.0) DOUBLE VERTICAL BAR
23F9 FE0E ; text style; # (7.0) BLACK SQUARE FOR STOP
23F9 FE0F ; emoji style; # (7.0) BLACK SQUARE FOR STOP
23FA FE0E ; text style; # (7.0) BLACK CIRCLE FOR RECORD
23FA FE0F ; emoji style; # (7.0) BLACK CIRCLE FOR RECORD
24C2 FE0E ; text style; # (1.1) CIRCLED LATIN CAPITAL LETTER M
24C2 FE0F ; emoji style; # (1.1) CIRCLED LATIN CAPITAL LETTER M
25AA FE0E ; text style; # (1.1) BLACK SMALL SQUARE
25AA FE0F ; emoji style; # (1.1) BLACK SMALL SQUARE
25AB FE0E ; text style; # (1.1) WHITE SMALL SQUARE
25AB FE0F ; emoji style; # (1.1) WHITE SMALL SQUARE
25B6 FE0E ; text style; # (1.1) BLACK RIGHT-POINTING TRIANGLE
25B6 FE0F ; emoji style; # (1.1) BLACK RIGHT-POINTING TRIANGLE
25C0 FE0E ; text style; # (1.1) BLACK LEFT-POINTING TRIANGLE
25C0 FE0F ; emoji style; # (1.1) BLACK LEFT-POINTING TRIANGLE
25FB FE0E ; text style; # (3.2) WHITE MEDIUM SQUARE
25FB FE0F ; emoji style; # (3.2) WHITE MEDIUM SQUARE
25FC FE0E ; text style; # (3.2) BLACK MEDIUM SQUARE
25FC FE0F ; emoji style; # (3.2) BLACK MEDIUM SQUARE
25FD FE0E ; text style; # (3.2) WHITE MEDIUM SMALL SQUARE
25FD FE0F ; emoji style; # (3.2) WHITE MEDIUM SMALL SQUARE
25FE FE0E ; text style; # (3.2) BLACK MEDIUM SMALL SQUARE
25FE FE0F ; emoji style; # (3.2) BLACK MEDIUM SMALL SQUARE
2600 FE0E ; text style; # (1.1) BLACK SUN WITH RAYS
2600 FE0F ; emoji style; # (1.1) BLACK SUN WITH RAYS
2601 FE0E ; text style; # (1.1) CLOUD
2601 FE0F ; emoji style; # (1.1) CLOUD
2602 FE0E ; text style; # (1.1) UMBRELLA
2602 FE0F ; emoji style; # (1.1) UMBRELLA
2603 FE0E ; text style; # (1.1) SNOWMAN
2603 FE0F ; emoji style; # (1.1) SNOWMAN
2604 FE0E ; text style; # (1.1) COMET
2604 FE0F ; emoji style; # (1.1) COMET
260E FE0E ; text style; # (1.1) BLACK TELEPHONE
260E FE0F ; emoji style; # (1.1) BLACK TELEPHONE
2611 FE0E ; text style; # (1.1) BALLOT BOX WITH CHECK
2611 FE0F ; emoji style; # (1.1) BALLOT BOX WITH CHECK
2614 FE0E ; text style; # (4.0) UMBRELLA WITH RAIN DROPS
2614 FE0F ; emoji style; # (4.0) UMBRELLA WITH RAIN DROPS
2615 FE0E ; text style; # (4.0) HOT BEVERAGE
2615 FE0F ; emoji style; # (4.0) HOT BEVERAGE
2618 FE0E ; text style; # (4.1) SHAMROCK
2618 FE0F ; emoji style; # (4.1) SHAMROCK
261D FE0E ; text style; # (1.1) WHITE UP POINTING INDEX
261D FE0F ; emoji style; # (1.1) WHITE UP POINTING INDEX
2620 FE0E ; text style; # (1.1) SKULL AND CROSSBONES
2620 FE0F ; emoji style; # (1.1) SKULL AND CROSSBONES
2622 FE0E ; text style; # (1.1) RADIOACTIVE SIGN
2622 FE0F ; emoji style; # (1.1) RADIOACTIVE SIGN
2623 FE0E ; text style; # (1.1) BIOHAZARD SIGN
2623 FE0F ; emoji style; # (1.1) BIOHAZARD SIGN
2626 FE0E ; text style; # (1.1) ORTHODOX CROSS
2626 FE0F ; emoji style; # (1.1) ORTHODOX CROSS
262A FE0E ; text style; # (1.1) STAR AND CRESCENT
262A FE0F ; emoji style; # (1.1) STAR AND CRESCENT
262E FE0E ; text style; # (1.1) PEACE SYMBOL
262E FE0F ; emoji style; # (1.1) PEACE SYMBOL
262F FE0E ; text style; # (1.1) YIN YANG
262F FE0F ; emoji style; # (1.1) YIN YANG
2638 FE0E ; text style; # (1.1) WHEEL OF DHARMA
2638 FE0F ; emoji style; # (1.1) WHEEL OF DHARMA
2639 FE0E ; text style; # (1.1) WHITE FROWNING FACE
2639 FE0F ; emoji style; # (1.1) WHITE FROWNING FACE
263A FE0E ; text style; # (1.1) WHITE SMILING FACE
263A FE0F ; emoji style; # (1.1) WHITE SMILING FACE
2640 FE0E ; text style; # (1.1) FEMALE SIGN
2640 FE0F ; emoji style; # (1.1) FEMALE SIGN
2642 FE0E ; text style; # (1.1) MALE SIGN
2642 FE0F ; emoji style; # (1.1) MALE SIGN
2648 FE0E ; text style; # (1.1) ARIES
2648 FE0F ; emoji style; # (1.1) ARIES
2649 FE0E ; text style; # (1.1) TAURUS
2649 FE0F ; emoji style; # (1.1) TAURUS
264A FE0E ; text style; # (1.1) GEMINI
264A FE0F ; emoji style; # (1.1) GEMINI
264B FE0E ; text style; # (1.1) CANCER
264B FE0F ; emoji style; # (1.1) CANCER
264C FE0E ; text style; # (1.1) LEO
264C FE0F ; emoji style; # (1.1) LEO
264D FE0E ; text style; # (1.1) VIRGO
264D FE0F ; emoji style; # (1.1) VIRGO
264E FE0E ; text style; # (1.1) LIBRA
264E FE0F ; emoji style; # (1.1) LIBRA
264F FE0E ; text style; # (1.1) SCORPIUS
264F FE0F ; emoji style; # (1.1) SCORPIUS
2650 FE0E ; text style; # (1.1) SAGITTARIUS
2650 FE0F ; emoji style; # (1.1) SAGITTARIUS
2651 FE0E ; text style; # (1.1) CAPRICORN
2651 FE0F ; emoji style; # (1.1) CAPRICORN
2652 FE0E ; text style; # (1.1) AQUARIUS
2652 FE0F ; emoji style; # (1.1) AQUARIUS
2653 FE0E ; text style; # (1.1) PISCES
2653 FE0F ; emoji style; # (1.1) PISCES
265F FE0E ; text style; # (1.1) BLACK CHESS PAWN
265F FE0F ; emoji style; # (1.1) BLACK CHESS PAWN
2660 FE0E ; text style; # (1.1) BLACK SPADE SUIT
2660 FE0F ; emoji style; # (1.1) BLACK SPADE SUIT
2663 FE0E ; text style; # (1.1) BLACK CLUB SUIT
2663 FE0F ; emoji style; # (1.1) BLACK CLUB SUIT
2665 FE0E ; text style; # (1.1) BLACK HEART SUIT
2665 FE0F ; emoji style; # (1.1) BLACK HEART SUIT
2666 FE0E ; text style; # (1.1) BLACK DIAMOND SUIT
2666 FE0F ; emoji style; # (1.1) BLACK DIAMOND SUIT
2668 FE0E ; text style; # (1.1) HOT SPRINGS
2668 FE0F ; emoji style; # (1.1) HOT SPRINGS
267B FE0E ; text style; # (3.2) BLACK UNIVERSAL RECYCLING SYMBOL
267B FE0F ; emoji style; # (3.2) BLACK UNIVERSAL RECYCLING SYMBOL
267E FE0E ; text style; # (4.1) PERMANENT PAPER SIGN
267E FE0F ; emoji style; # (4.1) PERMANENT PAPER SIGN
267F FE0E ; text style; # (4.1) WHEELCHAIR SYMBOL
267F FE0F ; emoji style; # (4.1) WHEELCHAIR SYMBOL
2692 FE0E ; text style; # (4.1) HAMMER AND PICK
2692 FE0F ; emoji style; # (4.1) HAMMER AND PICK
2693 FE0E ; text style; # (4.1) ANCHOR
2693 FE0F ; emoji style; # (4.1) ANCHOR
2694 FE0E ; text style; # (4.1) CROSSED SWORDS
2694 FE0F ; emoji style; # (4.1) CROSSED SWORDS
2695 FE0E ; text style; # (4.1) STAFF OF AESCULAPIUS
2695 FE0F ; emoji style; # (4.1) STAFF OF AESCULAPIUS
2696 FE0E ; text style; # (4.1) SCALES
2696 FE0F ; emoji style; # (4.1) SCALES
2697 FE0E ; text style; # (4.1) ALEMBIC
2697 FE0F ; emoji style; # (4.1) ALEMBIC
2699 FE0E ; text style; # (4.1) GEAR
2699 FE0F ; emoji style; # (4.1) GEAR
269B FE0E ; text style; # (4.1) ATOM SYMBOL
269B FE0F ; emoji style; # (4.1) ATOM SYMBOL
269C FE0E ; text style; # (4.1) FLEUR-DE-LIS
269C FE0F ; emoji style; # (4.1) FLEUR-DE-LIS
26A0 FE0E ; text style; # (4.0) WARNING SIGN
26A0 FE0F ; emoji style; # (4.0) WARNING SIGN
26A1 FE0E ; text style; # (4.0) HIGH VOLTAGE SIGN
26A1 FE0F ; emoji style; # (4.0) HIGH VOLTAGE SIGN
26A7 FE0E ; text style; # (4.1) MALE WITH STROKE AND MALE AND FEMALE SIGN
26A7 FE0F ; emoji style; # (4.1) MALE WITH STROKE AND MALE AND FEMALE SIGN
26AA FE0E ; text style; # (4.1) MEDIUM WHITE CIRCLE
26AA FE0F ; emoji style; # (4.1) MEDIUM WHITE CIRCLE
26AB FE0E ; text style; # (4.1) MEDIUM BLACK CIRCLE
26AB FE0F ; emoji style; # (4.1) MEDIUM BLACK CIRCLE
26B0 FE0E ; text style; # (4.1) COFFIN
26B0 FE0F ; emoji style; # (4.1) COFFIN
26B1 FE0E ; text style; # (4.1) FUNERAL URN
26B1 FE0F ; emoji style; # (4.1) FUNERAL URN
26BD FE0E ; text style; # (5.2) SOCCER BALL
26BD FE0F ; emoji style; # (5.2) SOCCER BALL
26BE FE0E ; text style; # (5.2) BASEBALL
26BE FE0F ; emoji style; # (5.2) BASEBALL
26C4 FE0E ; text style; # (5.2) SNOWMAN WITHOUT SNOW
26C4 FE0F ; emoji style; # (5.2) SNOWMAN WITHOUT SNOW
26C5 FE0E ; text style; # (5.2) SUN BEHIND CLOUD
26C5 FE0F ; emoji style; # (5.2) SUN BEHIND CLOUD
26C8 FE0E ; text style; # (5.2) THUNDER CLOUD AND RAIN
26C8 FE0F ; emoji style; # (5.2) THUNDER CLOUD AND RAIN
26CE FE0E ; text style; # (6.0) OPHIUCHUS
26CE FE0F ; emoji style; # (6.0) OPHIUCHUS
26CF FE0E ; text style; # (5.2) PICK
26CF FE0F ; emoji style; # (5.2) PICK
26D1 FE0E ; text style; # (5.2) HELMET WITH WHITE CROSS
26D1 FE0F ; emoji style; # (5.2) HELMET WITH WHITE CROSS
26D3 FE0E ; text style; # (5.2) CHAINS
26D3 FE0F ; emoji style; # (5.2) CHAINS
26D4 FE0E ; text style; # (5.2) NO ENTRY
26D4 FE0F ; emoji style; # (5.2) NO ENTRY
26E9 FE0E ; text style; # (5.2) SHINTO SHRINE
26E9 FE0F ; emoji style; # (5.2) SHINTO SHRINE
26EA FE0E ; text style; # (5.2) CHURCH
26EA FE0F ; emoji style; # (5.2) CHURCH
26F0 FE0E ; text style; # (5.2) MOUNTAIN
26F0 FE0F ; emoji style; # (5.2) MOUNTAIN
26F1 FE0E ; text style; # (5.2) UMBRELLA ON GROUND
26F1 FE0F ; emoji style; # (5.2) UMBRELLA ON GROUND
26F2 FE0E ; text style; # (5.2) FOUNTAIN
26F2 FE0F ; emoji style; # (5.2) FOUNTAIN
26F3 FE0E ; text style; # (5.2) FLAG IN HOLE
26F3 FE0F ; emoji style; # (5.2) FLAG IN HOLE
26F4 FE0E ; text style; # (5.2) FERRY
26F4 FE0F ; emoji style; # (5.2) FERRY
26F5 FE0E ; text style; # (5.2) SAILBOAT
26F5 FE0F ; emoji style; # (5.2) SAILBOAT
26F7 FE0E ; text style; # (5.2) SKIER
26F7 FE0F ; emoji style; # (5.2) SKIER
26F8 FE0E ; text style; # (5.2) ICE SKATE
26F8 FE0F ; emoji style; # (5.2) ICE SKATE
26F9 FE0E ; text style; # (5.2) PERSON WITH BALL
26F9 FE0F ; emoji style; # (5.2) PERSON WITH BALL
26FA FE0E ; text style; # (5.2) TENT
26FA FE0F ; emoji style; # (5.2) TENT
26FD FE0E ; text style; # (5.2) FUEL PUMP
26FD FE0F ; emoji style; # (5.2) FUEL PUMP
2702 FE0E ; text style; # (1.1) BLACK SCISSORS
2702 FE0F ; emoji style; # (1.1) BLACK SCISSORS
2705 FE0E ; text style; # (6.0) WHITE HEAVY CHECK MARK
2705 FE0F ; emoji style; # (6.0) WHITE HEAVY CHECK MARK
2708 FE0E ; text style; # (1.1) AIRPLANE
2708 FE0F ; emoji style; # (1.1) AIRPLANE
2709 FE0E ; text style; # (1.1) ENVELOPE
2709 FE0F ; emoji style; # (1.1) ENVELOPE
270A FE0E ; text style; # (6.0) RAISED FIST
270A FE0F ; emoji style; # (6.0) RAISED FIST
270B FE0E ; text style; # (6.0) RAISED HAND
270B FE0F ; emoji style; # (6.0) RAISED HAND
270C FE0E ; text style; # (1.1) VICTORY HAND
270C FE0F ; emoji style; # (1.1) VICTORY HAND
270D FE0E ; text style; # (1.1) WRITING HAND
270D FE0F ; emoji style; # (1.1) WRITING HAND
270F FE0E ; text style; # (1.1) PENCIL
270F FE0F ; emoji style; # (1.1) PENCIL
2712 FE0E ; text style; # (1.1) BLACK NIB
2712 FE0F ; emoji style; # (1.1) BLACK NIB
2714 FE0E ; text style; # (1.1) HEAVY CHECK MARK
2714 FE0F ; emoji style; # (1.1) HEAVY CHECK MARK
2716 FE0E ; text style; # (1.1) HEAVY MULTIPLICATION X
2716 FE0F ; emoji style; # (1.1) HEAVY MULTIPLICATION X
271D FE0E ; text style; # (1.1) LATIN CROSS
271D FE0F ; emoji style; # (1.1) LATIN CROSS
2721 FE0E ; text style; # (1.1) STAR OF DAVID
2721 FE0F ; emoji style; # (1.1) STAR OF DAVID
2728 FE0E ; text style; # (6.0) SPARKLES
2728 FE0F ; emoji style; # (6.0) SPARKLES
2733 FE0E ; text style; # (1.1) EIGHT SPOKED ASTERISK
2733 FE0F ; emoji style; # (1.1) EIGHT SPOKED ASTERISK
2734 FE0E ; text style; # (1.1) EIGHT POINTED BLACK STAR
2734 FE0F ; emoji style; # (1.1) EIGHT POINTED BLACK STAR
2744 FE0E ; text style; # (1.1) SNOWFLAKE
2744 FE0F ; emoji style; # (1.1) SNOWFLAKE
2747 FE0E ; text style; # (1.1) SPARKLE
2747 FE0F ; emoji style; # (1.1) SPARKLE
274C FE0E ; text style; # (6.0) CROSS MARK
274C FE0F ; emoji style; # (6.0) CROSS MARK
274E FE0E ; text style; # (6.0) NEGATIVE SQUARED CROSS MARK
274E FE0F ; emoji style; # (6.0) NEGATIVE SQUARED CROSS MARK
2753 FE0E ; text style; # (6.0) BLACK QUESTION MARK ORNAMENT
2753 FE0F ; emoji style; # (6.0) BLACK QUESTION MARK ORNAMENT
2754 FE0E ; text style; # (6.0) WHITE QUESTION MARK ORNAMENT
2754 FE0F ; emoji style; # (6.0) WHITE QUESTION MARK ORNAMENT
2755 FE0E ; text style; # (6.0) WHITE EXCLAMATION MARK ORNAMENT
2755 FE0F ; emoji style; # (6.0) WHITE EXCLAMATION MARK ORNAMENT
2757 FE0E ; text style; # (5.2) HEAVY EXCLAMATION MARK SYMBOL
2757 FE0F ; emoji style; # (5.2) HEAVY EXCLAMATION MARK SYMBOL
2763 FE0E ; text style; # (1.1) HEAVY HEART EXCLAMATION MARK ORNAMENT
2763 FE0F ; emoji style; # (1.1) HEAVY HEART EXCLAMATION MARK ORNAMENT
2764 FE0E ; text style; # (1.1) HEAVY BLACK HEART
2764 FE0F ; emoji style; # (1.1) HEAVY BLACK HEART
2795 FE0E ; text style; # (6.0) HEAVY PLUS SIGN
2795 FE0F ; emoji style; # (6.0) HEAVY PLUS SIGN
2796 FE0E ; text style; # (6.0) HEAVY MINUS SIGN
2796 FE0F ; emoji style; # (6.0) HEAVY MINUS SIGN
2797 FE0E ; text style; # (6.0) HEAVY DIVISION SIGN
2797 FE0F ; emoji style; # (6.0) HEAVY DIVISION SIGN
27A1 FE0E ; text style; # (1.1) BLACK RIGHTWARDS ARROW
27A1 FE0F ; emoji style; # (1.1) BLACK RIGHTWARDS ARROW
27B0 FE0E ; text style; # (6.0) CURLY LOOP
27B0 FE0F ; emoji style; # (6.0) CURLY LOOP
27BF FE0E ; text style; # (6.0) DOUBLE CURLY LOOP
27BF FE0F ; emoji style; # (6.0) DOUBLE CURLY LOOP
2934 FE0E ; text style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS
2934 FE0F ; emoji style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING UPWARDS
2935 FE0E ; text style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
2935 FE0F ; emoji style; # (3.2) ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS
2B05 FE0E ; text style; # (4.0) LEFTWARDS BLACK ARROW
2B05 FE0F ; emoji style; # (4.0) LEFTWARDS BLACK ARROW
2B06 FE0E ; text style; # (4.0) UPWARDS BLACK ARROW
2B06 FE0F ; emoji style; # (4.0) UPWARDS BLACK ARROW
2B07 FE0E ; text style; # (4.0) DOWNWARDS BLACK ARROW
2B07 FE0F ; emoji style; # (4.0) DOWNWARDS BLACK ARROW
2B1B FE0E ; text style; # (5.1) BLACK LARGE SQUARE
2B1B FE0F ; emoji style; # (5.1) BLACK LARGE SQUARE
2B1C FE0E ; text style; # (5.1) WHITE LARGE SQUARE
2B1C FE0F ; emoji style; # (5.1) WHITE LARGE SQUARE
2B50 FE0E ; text style; # (5.1) WHITE MEDIUM STAR
2B50 FE0F ; emoji style; # (5.1) WHITE MEDIUM STAR
2B55 FE0E ; text style; # (5.2) HEAVY LARGE CIRCLE
2B55 FE0F ; emoji style; # (5.2) HEAVY LARGE CIRCLE
3030 FE0E ; text style; # (1.1) WAVY DASH
3030 FE0F ; emoji style; # (1.1) WAVY DASH
303D FE0E ; text style; # (3.2) PART ALTERNATION MARK
303D FE0F ; emoji style; # (3.2) PART ALTERNATION MARK
3297 FE0E ; text style; # (1.1) CIRCLED IDEOGRAPH CONGRATULATION
3297 FE0F ; emoji style; # (1.1) CIRCLED IDEOGRAPH CONGRATULATION
3299 FE0E ; text style; # (1.1) CIRCLED IDEOGRAPH SECRET
3299 FE0F ; emoji style; # (1.1) CIRCLED IDEOGRAPH SECRET
1F004 FE0E ; text style; # (5.1) MAHJONG TILE RED DRAGON
1F004 FE0F ; emoji style; # (5.1) MAHJONG TILE RED DRAGON
1F170 FE0E ; text style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER A
1F170 FE0F ; emoji style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER A
1F171 FE0E ; text style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER B
1F171 FE0F ; emoji style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER B
1F17E FE0E ; text style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER O
1F17E FE0F ; emoji style; # (6.0) NEGATIVE SQUARED LATIN CAPITAL LETTER O
1F17F FE0E ; text style; # (5.2) NEGATIVE SQUARED LATIN CAPITAL LETTER P
1F17F FE0F ; emoji style; # (5.2) NEGATIVE SQUARED LATIN CAPITAL LETTER P
1F202 FE0E ; text style; # (6.0) SQUARED KATAKANA SA
1F202 FE0F ; emoji style; # (6.0) SQUARED KATAKANA SA
1F21A FE0E ; text style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-7121
1F21A FE0F ; emoji style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-7121
1F22F FE0E ; text style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-6307
1F22F FE0F ; emoji style; # (5.2) SQUARED CJK UNIFIED IDEOGRAPH-6307
1F237 FE0E ; text style; # (6.0) SQUARED CJK UNIFIED IDEOGRAPH-6708
1F237 FE0F ; emoji style; # (6.0) SQUARED CJK UNIFIED IDEOGRAPH-6708
1F30D FE0E ; text style; # (6.0) EARTH GLOBE EUROPE-AFRICA
1F30D FE0F ; emoji style; # (6.0) EARTH GLOBE EUROPE-AFRICA
1F30E FE0E ; text style; # (6.0) EARTH GLOBE AMERICAS
1F30E FE0F ; emoji style; # (6.0) EARTH GLOBE AMERICAS
1F30F FE0E ; text style; # (6.0) EARTH GLOBE ASIA-AUSTRALIA
1F30F FE0F ; emoji style; # (6.0) EARTH GLOBE ASIA-AUSTRALIA
1F315 FE0E ; text style; # (6.0) FULL MOON SYMBOL
1F315 FE0F ; emoji style; # (6.0) FULL MOON SYMBOL
1F31C FE0E ; text style; # (6.0) LAST QUARTER MOON WITH FACE
1F31C FE0F ; emoji style; # (6.0) LAST QUARTER MOON WITH FACE
1F321 FE0E ; text style; # (7.0) THERMOMETER
1F321 FE0F ; emoji style; # (7.0) THERMOMETER
1F324 FE0E ; text style; # (7.0) WHITE SUN WITH SMALL CLOUD
1F324 FE0F ; emoji style; # (7.0) WHITE SUN WITH SMALL CLOUD
1F325 FE0E ; text style; # (7.0) WHITE SUN BEHIND CLOUD
1F325 FE0F ; emoji style; # (7.0) WHITE SUN BEHIND CLOUD
1F326 FE0E ; text style; # (7.0) WHITE SUN BEHIND CLOUD WITH RAIN
1F326 FE0F ; emoji style; # (7.0) WHITE SUN BEHIND CLOUD WITH RAIN
1F327 FE0E ; text style; # (7.0) CLOUD WITH RAIN
1F327 FE0F ; emoji style; # (7.0) CLOUD WITH RAIN
1F328 FE0E ; text style; # (7.0) CLOUD WITH SNOW
1F328 FE0F ; emoji style; # (7.0) CLOUD WITH SNOW
1F329 FE0E ; text style; # (7.0) CLOUD WITH LIGHTNING
1F329 FE0F ; emoji style; # (7.0) CLOUD WITH LIGHTNING
1F32A FE0E ; text style; # (7.0) CLOUD WITH TORNADO
1F32A FE0F ; emoji style; # (7.0) CLOUD WITH TORNADO
1F32B FE0E ; text style; # (7.0) FOG
1F32B FE0F ; emoji style; # (7.0) FOG
1F32C FE0E ; text style; # (7.0) WIND BLOWING FACE
1F32C FE0F ; emoji style; # (7.0) WIND BLOWING FACE
1F336 FE0E ; text style; # (7.0) HOT PEPPER
1F336 FE0F ; emoji style; # (7.0) HOT PEPPER
1F378 FE0E ; text style; # (6.0) COCKTAIL GLASS
1F378 FE0F ; emoji style; # (6.0) COCKTAIL GLASS
1F37D FE0E ; text style; # (7.0) FORK AND KNIFE WITH PLATE
1F37D FE0F ; emoji style; # (7.0) FORK AND KNIFE WITH PLATE
1F393 FE0E ; text style; # (6.0) GRADUATION CAP
1F393 FE0F ; emoji style; # (6.0) GRADUATION CAP
1F396 FE0E ; text style; # (7.0) MILITARY MEDAL
1F396 FE0F ; emoji style; # (7.0) MILITARY MEDAL
1F397 FE0E ; text style; # (7.0) REMINDER RIBBON
1F397 FE0F ; emoji style; # (7.0) REMINDER RIBBON
1F399 FE0E ; text style; # (7.0) STUDIO MICROPHONE
1F399 FE0F ; emoji style; # (7.0) STUDIO MICROPHONE
1F39A FE0E ; text style; # (7.0) LEVEL SLIDER
1F39A FE0F ; emoji style; # (7.0) LEVEL SLIDER
1F39B FE0E ; text style; # (7.0) CONTROL KNOBS
1F39B FE0F ; emoji style; # (7.0) CONTROL KNOBS
1F39E FE0E ; text style; # (7.0) FILM FRAMES
1F39E FE0F ; emoji style; # (7.0) FILM FRAMES
1F39F FE0E ; text style; # (7.0) ADMISSION TICKETS
1F39F FE0F ; emoji style; # (7.0) ADMISSION TICKETS
1F3A7 FE0E ; text style; # (6.0) HEADPHONE
1F3A7 FE0F ; emoji style; # (6.0) HEADPHONE
1F3AC FE0E ; text style; # (6.0) CLAPPER BOARD
1F3AC FE0F ; emoji style; # (6.0) CLAPPER BOARD
1F3AD FE0E ; text style; # (6.0) PERFORMING ARTS
1F3AD FE0F ; emoji style; # (6.0) PERFORMING ARTS
1F3AE FE0E ; text style; # (6.0) VIDEO GAME
1F3AE FE0F ; emoji style; # (6.0) VIDEO GAME
1F3C2 FE0E ; text style; # (6.0) SNOWBOARDER
1F3C2 FE0F ; emoji style; # (6.0) SNOWBOARDER
1F3C4 FE0E ; text style; # (6.0) SURFER
1F3C4 FE0F ; emoji style; # (6.0) SURFER
1F3C6 FE0E ; text style; # (6.0) TROPHY
1F3C6 FE0F ; emoji style; # (6.0) TROPHY
1F3CA FE0E ; text style; # (6.0) SWIMMER
1F3CA FE0F ; emoji style; # (6.0) SWIMMER
1F3CB FE0E ; text style; # (7.0) WEIGHT LIFTER
1F3CB FE0F ; emoji style; # (7.0) WEIGHT LIFTER
1F3CC FE0E ; text style; # (7.0) GOLFER
1F3CC FE0F ; emoji style; # (7.0) GOLFER
1F3CD FE0E ; text style; # (7.0) RACING MOTORCYCLE
1F3CD FE0F ; emoji style; # (7.0) RACING MOTORCYCLE
1F3CE FE0E ; text style; # (7.0) RACING CAR
1F3CE FE0F ; emoji style; # (7.0) RACING CAR
1F3D4 FE0E ; text style; # (7.0) SNOW CAPPED MOUNTAIN
1F3D4 FE0F ; emoji style; # (7.0) SNOW CAPPED MOUNTAIN
1F3D5 FE0E ; text style; # (7.0) CAMPING
1F3D5 FE0F ; emoji style; # (7.0) CAMPING
1F3D6 FE0E ; text style; # (7.0) BEACH WITH UMBRELLA
1F3D6 FE0F ; emoji style; # (7.0) BEACH WITH UMBRELLA
1F3D7 FE0E ; text style; # (7.0) BUILDING CONSTRUCTION
1F3D7 FE0F ; emoji style; # (7.0) BUILDING CONSTRUCTION
1F3D8 FE0E ; text style; # (7.0) HOUSE BUILDINGS
1F3D8 FE0F ; emoji style; # (7.0) HOUSE BUILDINGS
1F3D9 FE0E ; text style; # (7.0) CITYSCAPE
1F3D9 FE0F ; emoji style; # (7.0) CITYSCAPE
1F3DA FE0E ; text style; # (7.0) DERELICT HOUSE BUILDING
1F3DA FE0F ; emoji style; # (7.0) DERELICT HOUSE BUILDING
1F3DB FE0E ; text style; # (7.0) CLASSICAL BUILDING
1F3DB FE0F ; emoji style; # (7.0) CLASSICAL BUILDING
1F3DC FE0E ; text style; # (7.0) DESERT
1F3DC FE0F ; emoji style; # (7.0) DESERT
1F3DD FE0E ; text style; # (7.0) DESERT ISLAND
1F3DD FE0F ; emoji style; # (7.0) DESERT ISLAND
1F3DE FE0E ; text style; # (7.0) NATIONAL PARK
1F3DE FE0F ; emoji style; # (7.0) NATIONAL PARK
1F3DF FE0E ; text style; # (7.0) STADIUM
1F3DF FE0F ; emoji style; # (7.0) STADIUM
1F3E0 FE0E ; text style; # (6.0) HOUSE BUILDING
1F3E0 FE0F ; emoji style; # (6.0) HOUSE BUILDING
1F3ED FE0E ; text style; # (6.0) FACTORY
1F3ED FE0F ; emoji style; # (6.0) FACTORY
1F3F3 FE0E ; text style; # (7.0) WAVING WHITE FLAG
1F3F3 FE0F ; emoji style; # (7.0) WAVING WHITE FLAG
1F3F5 FE0E ; text style; # (7.0) ROSETTE
1F3F5 FE0F ; emoji style; # (7.0) ROSETTE
1F3F7 FE0E ; text style; # (7.0) LABEL
1F3F7 FE0F ; emoji style; # (7.0) LABEL
1F408 FE0E ; text style; # (6.0) CAT
1F408 FE0F ; emoji style; # (6.0) CAT
1F415 FE0E ; text style; # (6.0) DOG
1F415 FE0F ; emoji style; # (6.0) DOG
1F41F FE0E ; text style; # (6.0) FISH
1F41F FE0F ; emoji style; # (6.0) FISH
1F426 FE0E ; text style; # (6.0) BIRD
1F426 FE0F ; emoji style; # (6.0) BIRD
1F43F FE0E ; text style; # (7.0) CHIPMUNK
1F43F FE0F ; emoji style; # (7.0) CHIPMUNK
1F441 FE0E ; text style; # (7.0) EYE
1F441 FE0F ; emoji style; # (7.0) EYE
1F442 FE0E ; text style; # (6.0) EAR
1F442 FE0F ; emoji style; # (6.0) EAR
1F446 FE0E ; text style; # (6.0) WHITE UP POINTING BACKHAND INDEX
1F446 FE0F ; emoji style; # (6.0) WHITE UP POINTING BACKHAND INDEX
1F447 FE0E ; text style; # (6.0) WHITE DOWN POINTING BACKHAND INDEX
1F447 FE0F ; emoji style; # (6.0) WHITE DOWN POINTING BACKHAND INDEX
1F448 FE0E ; text style; # (6.0) WHITE LEFT POINTING BACKHAND INDEX
1F448 FE0F ; emoji style; # (6.0) WHITE LEFT POINTING BACKHAND INDEX
1F449 FE0E ; text style; # (6.0) WHITE RIGHT POINTING BACKHAND INDEX
1F449 FE0F ; emoji style; # (6.0) WHITE RIGHT POINTING BACKHAND INDEX
1F44D FE0E ; text style; # (6.0) THUMBS UP SIGN
1F44D FE0F ; emoji style; # (6.0) THUMBS UP SIGN
1F44E FE0E ; text style; # (6.0) THUMBS DOWN SIGN
1F44E FE0F ; emoji style; # (6.0) THUMBS DOWN SIGN
1F453 FE0E ; text style; # (6.0) EYEGLASSES
1F453 FE0F ; emoji style; # (6.0) EYEGLASSES
1F46A FE0E ; text style; # (6.0) FAMILY
1F46A FE0F ; emoji style; # (6.0) FAMILY
1F47D FE0E ; text style; # (6.0) EXTRATERRESTRIAL ALIEN
1F47D FE0F ; emoji style; # (6.0) EXTRATERRESTRIAL ALIEN
1F4A3 FE0E ; text style; # (6.0) BOMB
1F4A3 FE0F ; emoji style; # (6.0) BOMB
1F4B0 FE0E ; text style; # (6.0) MONEY BAG
1F4B0 FE0F ; emoji style; # (6.0) MONEY BAG
1F4B3 FE0E ; text style; # (6.0) CREDIT CARD
1F4B3 FE0F ; emoji style; # (6.0) CREDIT CARD
1F4BB FE0E ; text style; # (6.0) PERSONAL COMPUTER
1F4BB FE0F ; emoji style; # (6.0) PERSONAL COMPUTER
1F4BF FE0E ; text style; # (6.0) OPTICAL DISC
1F4BF FE0F ; emoji style; # (6.0) OPTICAL DISC
1F4CB FE0E ; text style; # (6.0) CLIPBOARD
1F4CB FE0F ; emoji style; # (6.0) CLIPBOARD
1F4DA FE0E ; text style; # (6.0) BOOKS
1F4DA FE0F ; emoji style; # (6.0) BOOKS
1F4DF FE0E ; text style; # (6.0) PAGER
1F4DF FE0F ; emoji style; # (6.0) PAGER
1F4E4 FE0E ; text style; # (6.0) OUTBOX TRAY
1F4E4 FE0F ; emoji style; # (6.0) OUTBOX TRAY
1F4E5 FE0E ; text style; # (6.0) INBOX TRAY
1F4E5 FE0F ; emoji style; # (6.0) INBOX TRAY
1F4E6 FE0E ; text style; # (6.0) PACKAGE
1F4E6 FE0F ; emoji style; # (6.0) PACKAGE
1F4EA FE0E ; text style; # (6.0) CLOSED MAILBOX WITH LOWERED FLAG
1F4EA FE0F ; emoji style; # (6.0) CLOSED MAILBOX WITH LOWERED FLAG
1F4EB FE0E ; text style; # (6.0) CLOSED MAILBOX WITH RAISED FLAG
1F4EB FE0F ; emoji style; # (6.0) CLOSED MAILBOX WITH RAISED FLAG
1F4EC FE0E ; text style; # (6.0) OPEN MAILBOX WITH RAISED FLAG
1F4EC FE0F ; emoji style; # (6.0) OPEN MAILBOX WITH RAISED FLAG
1F4ED FE0E ; text style; # (6.0) OPEN MAILBOX WITH LOWERED FLAG
1F4ED FE0F ; emoji style; # (6.0) OPEN MAILBOX WITH LOWERED FLAG
1F4F7 FE0E ; text style; # (6.0) CAMERA
1F4F7 FE0F ; emoji style; # (6.0) CAMERA
1F4F9 FE0E ; text style; # (6.0) VIDEO CAMERA
1F4F9 FE0F ; emoji style; # (6.0) VIDEO CAMERA
1F4FA FE0E ; text style; # (6.0) TELEVISION
1F4FA FE0F ; emoji style; # (6.0) TELEVISION
1F4FB FE0E ; text style; # (6.0) RADIO
1F4FB FE0F ; emoji style; # (6.0) RADIO
1F4FD FE0E ; text style; # (7.0) FILM PROJECTOR
1F4FD FE0F ; emoji style; # (7.0) FILM PROJECTOR
1F508 FE0E ; text style; # (6.0) SPEAKER
1F508 FE0F ; emoji style; # (6.0) SPEAKER
1F50D FE0E ; text style; # (6.0) LEFT-POINTING MAGNIFYING GLASS
1F50D FE0F ; emoji style; # (6.0) LEFT-POINTING MAGNIFYING GLASS
1F512 FE0E ; text style; # (6.0) LOCK
1F512 FE0F ; emoji style; # (6.0) LOCK
1F513 FE0E ; text style; # (6.0) OPEN LOCK
1F513 FE0F ; emoji style; # (6.0) OPEN LOCK
1F549 FE0E ; text style; # (7.0) OM SYMBOL
1F549 FE0F ; emoji style; # (7.0) OM SYMBOL
1F54A FE0E ; text style; # (7.0) DOVE OF PEACE
1F54A FE0F ; emoji style; # (7.0) DOVE OF PEACE
1F550 FE0E ; text style; # (6.0) CLOCK FACE ONE OCLOCK
1F550 FE0F ; emoji style; # (6.0) CLOCK FACE ONE OCLOCK
1F551 FE0E ; text style; # (6.0) CLOCK FACE TWO OCLOCK
1F551 FE0F ; emoji style; # (6.0) CLOCK FACE TWO OCLOCK
1F552 FE0E ; text style; # (6.0) CLOCK FACE THREE OCLOCK
1F552 FE0F ; emoji style; # (6.0) CLOCK FACE THREE OCLOCK
1F553 FE0E ; text style; # (6.0) CLOCK FACE FOUR OCLOCK
1F553 FE0F ; emoji style; # (6.0) CLOCK FACE FOUR OCLOCK
1F554 FE0E ; text style; # (6.0) CLOCK FACE FIVE OCLOCK
1F554 FE0F ; emoji style; # (6.0) CLOCK FACE FIVE OCLOCK
1F555 FE0E ; text style; # (6.0) CLOCK FACE SIX OCLOCK
1F555 FE0F ; emoji style; # (6.0) CLOCK FACE SIX OCLOCK
1F556 FE0E ; text style; # (6.0) CLOCK FACE SEVEN OCLOCK
1F556 FE0F ; emoji style; # (6.0) CLOCK FACE SEVEN OCLOCK
1F557 FE0E ; text style; # (6.0) CLOCK FACE EIGHT OCLOCK
1F557 FE0F ; emoji style; # (6.0) CLOCK FACE EIGHT OCLOCK
1F558 FE0E ; text style; # (6.0) CLOCK FACE NINE OCLOCK
1F558 FE0F ; emoji style; # (6.0) CLOCK FACE NINE OCLOCK
1F559 FE0E ; text style; # (6.0) CLOCK FACE TEN OCLOCK
1F559 FE0F ; emoji style; # (6.0) CLOCK FACE TEN OCLOCK
1F55A FE0E ; text style; # (6.0) CLOCK FACE ELEVEN OCLOCK
1F55A FE0F ; emoji style; # (6.0) CLOCK FACE ELEVEN OCLOCK
1F55B FE0E ; text style; # (6.0) CLOCK FACE TWELVE OCLOCK
1F55B FE0F ; emoji style; # (6.0) CLOCK FACE TWELVE OCLOCK
1F55C FE0E ; text style; # (6.0) CLOCK FACE ONE-THIRTY
1F55C FE0F ; emoji style; # (6.0) CLOCK FACE ONE-THIRTY
1F55D FE0E ; text style; # (6.0) CLOCK FACE TWO-THIRTY
1F55D FE0F ; emoji style; # (6.0) CLOCK FACE TWO-THIRTY
1F55E FE0E ; text style; # (6.0) CLOCK FACE THREE-THIRTY
1F55E FE0F ; emoji style; # (6.0) CLOCK FACE THREE-THIRTY
1F55F FE0E ; text style; # (6.0) CLOCK FACE FOUR-THIRTY
1F55F FE0F ; emoji style; # (6.0) CLOCK FACE FOUR-THIRTY
1F560 FE0E ; text style; # (6.0) CLOCK FACE FIVE-THIRTY
1F560 FE0F ; emoji style; # (6.0) CLOCK FACE FIVE-THIRTY
1F561 FE0E ; text style; # (6.0) CLOCK FACE SIX-THIRTY
1F561 FE0F ; emoji style; # (6.0) CLOCK FACE SIX-THIRTY
1F562 FE0E ; text style; # (6.0) CLOCK FACE SEVEN-THIRTY
1F562 FE0F ; emoji style; # (6.0) CLOCK FACE SEVEN-THIRTY
1F563 FE0E ; text style; # (6.0) CLOCK FACE EIGHT-THIRTY
1F563 FE0F ; emoji style; # (6.0) CLOCK FACE EIGHT-THIRTY
1F564 FE0E ; text style; # (6.0) CLOCK FACE NINE-THIRTY
1F564 FE0F ; emoji style; # (6.0) CLOCK FACE NINE-THIRTY
1F565 FE0E ; text style; # (6.0) CLOCK FACE TEN-THIRTY
1F565 FE0F ; emoji style; # (6.0) CLOCK FACE TEN-THIRTY
1F566 FE0E ; text style; # (6.0) CLOCK FACE ELEVEN-THIRTY
1F566 FE0F ; emoji style; # (6.0) CLOCK FACE ELEVEN-THIRTY
1F567 FE0E ; text style; # (6.0) CLOCK FACE TWELVE-THIRTY
1F567 FE0F ; emoji style; # (6.0) CLOCK FACE TWELVE-THIRTY
1F56F FE0E ; text style; # (7.0) CANDLE
1F56F FE0F ; emoji style; # (7.0) CANDLE
1F570 FE0E ; text style; # (7.0) MANTELPIECE CLOCK
1F570 FE0F ; emoji style; # (7.0) MANTELPIECE CLOCK
1F573 FE0E ; text style; # (7.0) HOLE
1F573 FE0F ; emoji style; # (7.0) HOLE
1F574 FE0E ; text style; # (7.0) MAN IN BUSINESS SUIT LEVITATING
1F574 FE0F ; emoji style; # (7.0) MAN IN BUSINESS SUIT LEVITATING
1F575 FE0E ; text style; # (7.0) SLEUTH OR SPY
1F575 FE0F ; emoji style; # (7.0) SLEUTH OR SPY
1F576 FE0E ; text style; # (7.0) DARK SUNGLASSES
1F576 FE0F ; emoji style; # (7.0) DARK SUNGLASSES
1F577 FE0E ; text style; # (7.0) SPIDER
1F577 FE0F ; emoji style; # (7.0) SPIDER
1F578 FE0E ; text style; # (7.0) SPIDER WEB
1F578 FE0F ; emoji style; # (7.0) SPIDER WEB
1F579 FE0E ; text style; # (7.0) JOYSTICK
1F579 FE0F ; emoji style; # (7.0) JOYSTICK
1F587 FE0E ; text style; # (7.0) LINKED PAPERCLIPS
1F587 FE0F ; emoji style; # (7.0) LINKED PAPERCLIPS
1F58A FE0E ; text style; # (7.0) LOWER LEFT BALLPOINT PEN
1F58A FE0F ; emoji style; # (7.0) LOWER LEFT BALLPOINT PEN
1F58B FE0E ; text style; # (7.0) LOWER LEFT FOUNTAIN PEN
1F58B FE0F ; emoji style; # (7.0) LOWER LEFT FOUNTAIN PEN
1F58C FE0E ; text style; # (7.0) LOWER LEFT PAINTBRUSH
1F58C FE0F ; emoji style; # (7.0) LOWER LEFT PAINTBRUSH
1F58D FE0E ; text style; # (7.0) LOWER LEFT CRAYON
1F58D FE0F ; emoji style; # (7.0) LOWER LEFT CRAYON
1F590 FE0E ; text style; # (7.0) RAISED HAND WITH FINGERS SPLAYED
1F590 FE0F ; emoji style; # (7.0) RAISED HAND WITH FINGERS SPLAYED
1F5A5 FE0E ; text style; # (7.0) DESKTOP COMPUTER
1F5A5 FE0F ; emoji style; # (7.0) DESKTOP COMPUTER
1F5A8 FE0E ; text style; # (7.0) PRINTER
1F5A8 FE0F ; emoji style; # (7.0) PRINTER
1F5B1 FE0E ; text style; # (7.0) THREE BUTTON MOUSE
1F5B1 FE0F ; emoji style; # (7.0) THREE BUTTON MOUSE
1F5B2 FE0E ; text style; # (7.0) TRACKBALL
1F5B2 FE0F ; emoji style; # (7.0) TRACKBALL
1F5BC FE0E ; text style; # (7.0) FRAME WITH PICTURE
1F5BC FE0F ; emoji style; # (7.0) FRAME WITH PICTURE
1F5C2 FE0E ; text style; # (7.0) CARD INDEX DIVIDERS
1F5C2 FE0F ; emoji style; # (7.0) CARD INDEX DIVIDERS
1F5C3 FE0E ; text style; # (7.0) CARD FILE BOX
1F5C3 FE0F ; emoji style; # (7.0) CARD FILE BOX
1F5C4 FE0E ; text style; # (7.0) FILE CABINET
1F5C4 FE0F ; emoji style; # (7.0) FILE CABINET
1F5D1 FE0E ; text style; # (7.0) WASTEBASKET
1F5D1 FE0F ; emoji style; # (7.0) WASTEBASKET
1F5D2 FE0E ; text style; # (7.0) SPIRAL NOTE PAD
1F5D2 FE0F ; emoji style; # (7.0) SPIRAL NOTE PAD
1F5D3 FE0E ; text style; # (7.0) SPIRAL CALENDAR PAD
1F5D3 FE0F ; emoji style; # (7.0) SPIRAL CALENDAR PAD
1F5DC FE0E ; text style; # (7.0) COMPRESSION
1F5DC FE0F ; emoji style; # (7.0) COMPRESSION
1F5DD FE0E ; text style; # (7.0) OLD KEY
1F5DD FE0F ; emoji style; # (7.0) OLD KEY
1F5DE FE0E ; text style; # (7.0) ROLLED-UP NEWSPAPER
1F5DE FE0F ; emoji style; # (7.0) ROLLED-UP NEWSPAPER
1F5E1 FE0E ; text style; # (7.0) DAGGER KNIFE
1F5E1 FE0F ; emoji style; # (7.0) DAGGER KNIFE
1F5E3 FE0E ; text style; # (7.0) SPEAKING HEAD IN SILHOUETTE
1F5E3 FE0F ; emoji style; # (7.0) SPEAKING HEAD IN SILHOUETTE
1F5E8 FE0E ; text style; # (7.0) LEFT SPEECH BUBBLE
1F5E8 FE0F ; emoji style; # (7.0) LEFT SPEECH BUBBLE
1F5EF FE0E ; text style; # (7.0) RIGHT ANGER BUBBLE
1F5EF FE0F ; emoji style; # (7.0) RIGHT ANGER BUBBLE
1F5F3 FE0E ; text style; # (7.0) BALLOT BOX WITH BALLOT
1F5F3 FE0F ; emoji style; # (7.0) BALLOT BOX WITH BALLOT
1F5FA FE0E ; text style; # (7.0) WORLD MAP
1F5FA FE0F ; emoji style; # (7.0) WORLD MAP
1F610 FE0E ; text style; # (6.0) NEUTRAL FACE
1F610 FE0F ; emoji style; # (6.0) NEUTRAL FACE
1F687 FE0E ; text style; # (6.0) METRO
1F687 FE0F ; emoji style; # (6.0) METRO
1F68D FE0E ; text style; # (6.0) ONCOMING BUS
1F68D FE0F ; emoji style; # (6.0) ONCOMING BUS
1F691 FE0E ; text style; # (6.0) AMBULANCE
1F691 FE0F ; emoji style; # (6.0) AMBULANCE
1F694 FE0E ; text style; # (6.0) ONCOMING POLICE CAR
1F694 FE0F ; emoji style; # (6.0) ONCOMING POLICE CAR
1F698 FE0E ; text style; # (6.0) ONCOMING AUTOMOBILE
1F698 FE0F ; emoji style; # (6.0) ONCOMING AUTOMOBILE
1F6AD FE0E ; text style; # (6.0) NO SMOKING SYMBOL
1F6AD FE0F ; emoji style; # (6.0) NO SMOKING SYMBOL
1F6B2 FE0E ; text style; # (6.0) BICYCLE
1F6B2 FE0F ; emoji style; # (6.0) BICYCLE
1F6B9 FE0E ; text style; # (6.0) MENS SYMBOL
1F6B9 FE0F ; emoji style; # (6.0) MENS SYMBOL
1F6BA FE0E ; text style; # (6.0) WOMENS SYMBOL
1F6BA FE0F ; emoji style; # (6.0) WOMENS SYMBOL
1F6BC FE0E ; text style; # (6.0) BABY SYMBOL
1F6BC FE0F ; emoji style; # (6.0) BABY SYMBOL
1F6CB FE0E ; text style; # (7.0) COUCH AND LAMP
1F6CB FE0F ; emoji style; # (7.0) COUCH AND LAMP
1F6CD FE0E ; text style; # (7.0) SHOPPING BAGS
1F6CD FE0F ; emoji style; # (7.0) SHOPPING BAGS
1F6CE FE0E ; text style; # (7.0) BELLHOP BELL
1F6CE FE0F ; emoji style; # (7.0) BELLHOP BELL
1F6CF FE0E ; text style; # (7.0) BED
1F6CF FE0F ; emoji style; # (7.0) BED
1F6E0 FE0E ; text style; # (7.0) HAMMER AND WRENCH
1F6E0 FE0F ; emoji style; # (7.0) HAMMER AND WRENCH
1F6E1 FE0E ; text style; # (7.0) SHIELD
1F6E1 FE0F ; emoji style; # (7.0) SHIELD
1F6E2 FE0E ; text style; # (7.0) OIL DRUM
1F6E2 FE0F ; emoji style; # (7.0) OIL DRUM
1F6E3 FE0E ; text style; # (7.0) MOTORWAY
1F6E3 FE0F ; emoji style; # (7.0) MOTORWAY
1F6E4 FE0E ; text style; # (7.0) RAILWAY TRACK
1F6E4 FE0F ; emoji style; # (7.0) RAILWAY TRACK
1F6E5 FE0E ; text style; # (7.0) MOTOR BOAT
1F6E5 FE0F ; emoji style; # (7.0) MOTOR BOAT
1F6E9 FE0E ; text style; # (7.0) SMALL AIRPLANE
1F6E9 FE0F ; emoji style; # (7.0) SMALL AIRPLANE
1F6F0 FE0E ; text style; # (7.0) SATELLITE
1F6F0 FE0F ; emoji style; # (7.0) SATELLITE
1F6F3 FE0E ; text style; # (7.0) PASSENGER SHIP
1F6F3 FE0F ; emoji style; # (7.0) PASSENGER SHIP
#Total sequences: 371
#EOF

253
src/modules/punk/console-999999.0a1.0.tm

@ -31,102 +31,146 @@ namespace eval punk::console {
if {"windows" eq $::tcl_platform(platform)} {
proc enableAnsi {} {
define_windows_procs
#loopavoidancetoken (don't remove)
internal::define_windows_procs
internal::abort_if_loop
tailcall enableAnsi
}
proc enableRaw {{channel stdin}} {
define_windows_procs
#loopavoidancetoken (don't remove)
internal::define_windows_procs
internal::abort_if_loop
tailcall enableRaw $channel
}
proc disableRaw {{channel stdin}} {
define_windows_procs
#loopavoidancetoken (don't remove)
internal::define_windows_procs
internal::abort_if_loop
tailcall disableRaw $channel
}
} else {
proc enableAnsi {} {
#todo?
}
proc enableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw -echo <@$channel
}
proc disableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw echo <@$channel
}
proc enableAnsi {} {
#todo?
}
proc enableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw -echo <@$channel
}
proc disableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw echo <@$channel
}
}
proc define_windows_procs {} {
set loadstate [zzzload::pkg_require twapi]
if {$loadstate ni [list loading failed]} {
package require twapi ;#should be fast once twapi dll loaded in zzzload thread
set ::punk::console::has_twapi 1
proc enableAnsi {} {
twapi::SetConsoleMode [twapi::get_console_handle stdout] 5
}
proc enableRaw {{channel stdin}} {
#review - change to modify_console_input_mode
set console_handle [twapi::GetStdHandle -10]
set oldmode [twapi::GetConsoleMode $console_handle]
set newmode [expr {$oldmode & ~6}] ;# Turn off the echo and line-editing bits
twapi::SetConsoleMode $console_handle $newmode
}
proc disableRaw {{channel stdin}} {
set console_handle [twapi::GetStdHandle -10]
set oldmode [twapi::GetConsoleMode $console_handle]
set newmode [expr {$oldmode | 6}] ;# Turn on the echo and line-editing bits
twapi::SetConsoleMode $console_handle $newmode
namespace eval internal {
proc abort_if_loop {{failmsg ""}} {
#puts "il1 [info level 1]"
#puts "thisproc: [lindex [info level 0] 0]"
set would_loop [uplevel 1 {expr {[string match *loopavoidancetoken* [info body [namespace tail [lindex [info level 0] 0]]]]}}]
#puts "would_loop: $would_loop"
if {$would_loop} {
set procname [uplevel 1 {namespace tail [lindex [info level 0] 0]}]
if {$failmsg eq ""} {
set errmsg "[namespace current] Failed to redefine procedure $procname"
} else {
set errmsg $failmsg
}
error $errmsg
}
} else {
if {$loadstate eq "failed"} {
puts stderr "punk::console falling back to stty because twapi load failed"
proc enableAnsi {} {
puts stderr "punk::console::enableAnsi todo"
}
proc define_windows_procs {} {
set loadstate [zzzload::pkg_require twapi]
if {$loadstate ni [list loading failed]} {
package require twapi ;#should be fast once twapi dll loaded in zzzload thread
set ::punk::console::has_twapi 1
proc [namespace parent]::enableAnsi {} {
#Enable virtual terminal processing (sometimes off in older windows terminals)
twapi::SetConsoleMode [twapi::get_console_handle stdout] 5
}
proc [namespace parent]::enableRaw {{channel stdin}} {
#review - change to modify_console_input_mode
set console_handle [twapi::GetStdHandle -10]
set oldmode [twapi::GetConsoleMode $console_handle]
set newmode [expr {$oldmode & ~6}] ;# Turn off the echo and line-editing bits
twapi::SetConsoleMode $console_handle $newmode
}
proc enableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw -echo <@$channel
proc [namespace parent]::disableRaw {{channel stdin}} {
set console_handle [twapi::GetStdHandle -10]
set oldmode [twapi::GetConsoleMode $console_handle]
set newmode [expr {$oldmode | 6}] ;# Turn on the echo and line-editing bits
twapi::SetConsoleMode $console_handle $newmode
}
proc disableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw echo <@$channel
} else {
if {$loadstate eq "failed"} {
puts stderr "punk::console falling back to stty because twapi load failed"
proc [namespace parent]::enableAnsi {} {
puts stderr "punk::console::enableAnsi todo"
}
proc [namespace parent]::enableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw -echo <@$channel
}
proc [namespace parent]::disableRaw {{channel stdin}} {
set sttycmd [auto_execok stty]
exec {*}$sttycmd raw echo <@$channel
}
}
}
tailcall du_dirlisting_generic $folderpath {*}$args
}
}
proc ansi_response_handler {chan} {
set status [catch {read $chan 1} bytes]
if { $status != 0 } {
# Error on the channel
puts "error reading $chan: $bytes"
set ::punk::console::chunkdone 2
} elseif {$bytes ne ""} {
# Successfully read the channel
#puts "got: [string length $bytes]"
append ::punk::console::chunk $bytes
if {$bytes eq "R"} {
set ::punk::console::chunkdone 4
proc ansi_response_handler {chan} {
set status [catch {read $chan 1} bytes]
if { $status != 0 } {
# Error on the channel
puts "error reading $chan: $bytes"
set ::punk::console::chunkdone 2
} elseif {$bytes ne ""} {
# Successfully read the channel
#puts "got: [string length $bytes]"
append ::punk::console::chunk $bytes
if {$bytes eq "R"} {
set ::punk::console::chunkdone 4
} else {
fileevent stdin readable [list ::punk::console::internal::ansi_response_handler stdin]
}
} elseif { [eof $chan] } {
# End of file on the channel
#review
puts "ansi_response_handler end of file"
set ::punk::console::chunkdone 1
} elseif { [fblocked $chan] } {
# Read blocked. Just return
} else {
fileevent stdin readable [list ::punk::console::ansi_response_handler stdin]
# Something else
puts "ansi_response_handler can't happen"
set ::punk::console::chunkdone 3
}
} elseif { [eof $chan] } {
# End of file on the channel
#review
puts "ansi_response_handler end of file"
set ::punk::console::chunkdone 1
} elseif { [fblocked $chan] } {
# Read blocked. Just return
} else {
# Something else
puts "ansi_response_handler can't happen"
set ::punk::console::chunkdone 3
}
proc splitn {str {len 1}} {
#textutil::split::splitn
if {$len <= 0} {
return -code error "len must be > 0"
}
if {$len == 1} {
return [split $str {}]
}
set result [list]
set max [string length $str]
set i 0
set j [expr {$len -1}]
while {$i < $max} {
lappend result [string range $str $i $j]
incr i $len
incr j $len
}
return $result
}
}
proc reset {} {
tailcall puts -nonewline stdout \u001bc
}
proc get_cursor_position {} {
set ::punk::console::chunk ""
enableRaw
@ -134,7 +178,7 @@ namespace eval punk::console {
#e.g \033\[46;1R
#todo - reset
fconfigure stdin -blocking 0
fileevent stdin readable [list ::punk::console::ansi_response_handler stdin]
fileevent stdin readable [list ::punk::console::internal::ansi_response_handler stdin]
set info ""
vwait ::punk::console::chunkdone
fileevent stdin readable {}
@ -157,6 +201,67 @@ namespace eval punk::console {
set data [string range [string trim $info] 2 end-1]
return [split $data ";"]
}
#string to 2digit hex - e.g used by XTGETTCAP
proc str2hex {input} {
set 2hex ""
foreach ch [split $input ""] {
append 2hex [format %02X [scan $ch %c]]
}
return $2hex
}
proc hex2str {2digithexchars} {
if {$2digithexchars eq ""} {
return ""
}
if {[string length $2digithexchars] % 2 != 0} {
error "hex2str requires an even number of hex digits (2 per character)"
}
set 2str ""
foreach pair [internal::splitn $2digithexchars 2] {
append 2str [format %c 0x$pair]
}
return $2str
}
# -- --- --- --- --- ---
#XTGETTCAP
# xterm responds with
# DCS 1 + r Pt ST for valid requests, adding to Pt an = , and
# the value of the corresponding string that xterm would send,
# or
# DCS 0 + r ST for invalid requests.
# The strings are encoded in hexadecimal (2 digits per
# character). If more than one name is given, xterm replies
# with each name/value pair in the same response. An invalid
# name (one not found in xterm's tables) ends processing of the
# list of names.
proc getcap {keylist} {
#ESC P = 0x90 = DCS = Device Control String
set hexkeys [list]
foreach k $keylist {
lappend hexkeys [str2hex $k]
}
set payload [join $hexkeys ";"]
return "\x1bP+q$payload\x1b\\"
}
proc getcap2 {keylist} {
#ESC P = 0x90 = DCS = Device Control String
set hexkeys [list]
foreach k $keylist {
lappend hexkeys [str2hex $k]
}
set payload [join $hexkeys ";"]
return "\u0090+q$payload\u009c"
}
# -- --- --- --- --- ---
proc test_decaln {} {
#Screen Alignment Test
#Reset margins, move cursor to the top left, and fill the screen with 'E'
#(doesn't work on many terminals - seems to work in FreeBSD 13.2 and wezterm on windows)
return \x1b#8
}
}

2
src/modules/punk/ns-999999.0a1.0.tm

@ -898,7 +898,7 @@ namespace eval punk::ns {
#nscommands returns exactly one line per entry + a trailing newline. If there is an empty line other than at the end - that is because there is a command named as the empty string.
# By default 'linelist' trims 1st and last empty line. Turn off all block trimming with -block {}
set commands [.= nscommands -raw [nsjoin $ch $glob] |> .=>1 linelist -block {}]
set commands [.= nscommands -raw [nsjoin $ch $glob] |> .=> linelist -block {}]
#by convention - returning just \n represents a single result of the empty string whereas no results
#after passing through linelist this becomes {} {} which appears as a list of two empty strings.
#this is because there isn't a way to represent unambiguously all 3 cases of: empty-list, list of single empty string, list of two empty strings just using \n separated lines

20
src/modules/punk/repo-999999.0a1.0.tm

@ -388,6 +388,8 @@ namespace eval punk::repo {
#set checkrevision [fossil_revision $abspath]
dict set resultdict ahead ""
dict set resultdict behind ""
foreach ln [split $fossilstate \n] {
if {[string trim $ln] eq ""} {continue}
@ -439,6 +441,18 @@ namespace eval punk::repo {
puts stderr "workingdir_state: git revision is (initial) - no file state to gather"
break
}
dict set resultdict ahead ""
dict set resultdict behind ""
set aheadbehind [lindex [grep {# branch.ab *} $gitstate] 0]
if {[llength $aheadbehind] > 0} {
lassign [lrange $aheadbehind 2 3] a b
if {$a > 0} {
dict set resultdict ahead [expr {abs($a)}]
}
if {$b < 0} {
dict set resultdict behind [expr {abs($b)}]
}
}
#set checkrevision [git_revision $abspath]
if {[catch {punk::mix::util::do_in_path $repodir [list exec {*}$git_cmd ls-tree -r $revision $abspath]} gitfiles]} {
error "workingdir_state error: Unable to retrieve files for revision '$revision' using git. Errormsg: $gitfiles"
@ -519,7 +533,7 @@ namespace eval punk::repo {
}
package require overtype
set defaults [dict create\
-fields {unchanged changed new missing extra}\
-fields {ahead behind unchanged changed new missing extra}\
]
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- ---
@ -532,6 +546,8 @@ namespace eval punk::repo {
repodir repodir\
subpath subpath\
revision revision\
ahead ahead\
behind behind\
repotype repotype\
unchanged unchanged\
changed changed\
@ -573,7 +589,7 @@ namespace eval punk::repo {
}
set filestates [dict values [dict get $repostate paths]]
set path_count_fields [list unchanged changed new missing extra]
set state_fields [list repodir subpath repotype revision]
set state_fields [list ahead behind repodir subpath repotype revision]
set dresult [dict create]
foreach f $state_fields {
dict set dresult $f [dict get $repostate $f]

55
src/modules/shellfilter-0.1.8.tm

@ -165,9 +165,62 @@ namespace eval shellfilter::ansi {
#return "\x1b\[0m" ;#reset color only
}
#maint warning - from overtype package
proc stripcodes {text} {
#single "final byte" in the range 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).
dict set escape_terminals CSI [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 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 "\{" "\}"]
#dict set escape_terminals CSI [list J K m n A B C D E F G s u] ;#basic
dict set escape_terminals OSC [list \007 \033\\] ;#note mix of 1 and 2-byte terminals
#we process char by char - line-endings whether \r\n or \n should be processed as per any other character.
#line endings can theoretically occur within an ansi escape sequence (review e.g title?)
set inputlist [split $text ""]
set outputlist [list]
#self-contained 2 byte ansi escape sequences - review more?
set 2bytecodes_dict [dict create\
"reset_terminal" "\033c"\
"save_cursor_posn" "\u001b7"\
"restore_cursor_posn" "\u001b8"\
"cursor_up_one" "\u001bM"\
]
set 2bytecodes [dict values $2bytecodes_dict]
set in_escapesequence 0
#assumption - undertext already 'rendered' - ie no backspaces or carriagereturns or other cursor movement controls
set i 0
foreach u $inputlist {
set v [lindex $inputlist $i+1]
set uv ${u}${v}
if {$in_escapesequence eq "2b"} {
#2nd byte - done.
set in_escapesequence 0
} elseif {$in_escapesequence != 0} {
set escseq [dict get $escape_terminals $in_escapesequence]
if {$u in $escseq} {
set in_escapesequence 0
} elseif {$uv in $escseq} {
set in_escapseequence 2b ;#flag next byte as last in sequence
}
} else {
#handle both 7-bit and 8-bit CSI and OSC
if {[regexp {^(?:\033\[|\u009b)} $uv]} {
set in_escapesequence CSI
} elseif {[regexp {^(?:\033\]|\u009c)} $uv]} {
set in_escapesequence OSC
} elseif {$uv in $2bytecodes} {
#self-contained e.g terminal reset - don't pass through.
set in_escapesequence 2b
} else {
lappend outputlist $u
}
}
incr i
}
return [join $outputlist ""]
}
#maintenance warning - also in 'overtype' pkg
#strip ansi codes from text - basic! assumes we don't get data split in the middle of an ansi-code ie best used with line-buffering
proc stripcodes {text} {
proc stripcodes1_bogus {text} {
if {[set posn [string first "\033\[" $text]] >= 0} {
set mnext [string first m [string range $text $posn end]]
if {$mnext >= 0} {

141
src/modules/textblock-999999.0a1.0.tm

@ -25,6 +25,9 @@ package require textutil
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++
#
#Note: A textblock does not necessarily have lines the same length - either in number of characters or print-width
#
namespace eval textblock {
namespace eval cd {
#todo - save and restore existing namespace export in case macros::cd has default exports in future
@ -33,6 +36,30 @@ namespace eval textblock {
namespace eval ::term::ansi::code::macros::cd {namespace export -clear}
}
#return a homogenous block of characters - ie lines all same length, all same character
#printing-width in terminal columns is not necessarily same as blockcols even if a single char is passed (could be full-width unicode character)
proc block {blockrows blockcols {char " "}} {
if {($blockrows <= 0 || $blockcols <= 0)} {
error "textblock::block blockrows and blockcols must be positive integers"
}
if {$char eq ""} {return ""}
if {[string length $char] == 1} {
set row [string repeat $char $blockcols]
set mtrx [lrepeat $blockrows $row]
return [::join $mtrx \n]
} else {
set charblock [string map [list \r\n \n] $char]
if {$blockcols > 1} {
set row [.= val $charblock {*}[lrepeat [expr {$blockcols -1}] |> piper_blockjoin $charblock]]
} else {
set row $charblock
}
set mtrx [lrepeat $blockrows $row]
return [::join $mtrx \n]
}
}
#must be able to handle block as string with or without newlines
#if no newlines - attempt to treat as a list
#must handle whitespace-only string,list elements, and/or lines.
@ -53,31 +80,74 @@ namespace eval textblock {
}
return [tcl::mathfunc::max {*}[lmap v $block {string length [stripansi $v]}]]
}
pipealias ::textblock::padleft .= {list $input [string repeat " " $indent]} |/0,padding/1> linelist |> .= {lmap v $data {overtype::right $padding $v}} |> list_as_lines <input/0,indent/1|
pipealias ::textblock::padright .= {list $input [string repeat " " $colsize]} |/0,padding/1> linelist |> .= {lmap v $data {overtype::left $padding $v}} |> list_as_lines <input/0,colsize/1|
proc ::textblock::pad {block args} {
set defaults [dict set\
-padchar " "\
-which "right"\
-width ""\
-overflow 0\
]
set usage "pad ?-padchar <character>? ?-which right|left|centre? -width <int>"
foreach {k v} $args {
if {$k ni [dict keys $defaults]} {
error "textblock::pad unrecognised option '$k'. Usage: $usage"
}
}
set opts [dict merge $defaults $args]
# -- --- --- --- --- --- --- --- --- ---
set padchar [dict get $opts -padchar]
# -- --- --- --- --- --- --- --- --- ---
set known_whiches [list l left r right c center centre]
set which [string tolower [dict get $opts -which]]
if {$which in [list centre center]} {set which "c"}
if {$which in [list left]} {set which "l"}
if {$which in [list right]} {set which "r"}
if {$which ni $known_whiches} {
error "textblock::pad unrecognised value for -which option. Known values $known_whiches"
}
# -- --- --- --- --- --- --- --- --- ---
set width [dict get $opts -width]
# -- --- --- --- --- --- --- --- --- ---
if {$width = ""} {
}
}
pipealias ::textblock::padleft .= {list $input [string repeat " " $indent]} |/0,padding/1> linelist |> .= {lmap v $data {val "$padding$v"}} |> list_as_lines <input/0,indent/1|
pipealias ::textblock::padright .= {list $input [string repeat " " $colsize]} |/0,padding/1> linelist |> .= {lmap v $data {val "$v$padding"}} |> list_as_lines <input/0,colsize/1|
pipealias ::textblock::join_width .= {list $lhs [string repeat " " $w1] $rhs [string repeat " " $w2]} {|
/2,col1/1,col2/3
>} .=>1 linelist -block {} {|
>} linelist -block {} {|
data2
>} .=lhs>1 linelist -block {} {|
>} .=lhs> linelist -block {} {|
>} .= {lmap v $data w $data2 {val "[overtype::left $col1 $v][overtype::left $col2 $w]"}} {|
>} list_as_lines <lhs/0,w1/1,rhs/2,w2/3|
pipealias ::textblock::join .= {list $lhs [string repeat " " [width $lhs]] $rhs [string repeat " " [width $rhs]]} {|
/2,col1/1,col2/3
>} .=>1 linelist -block {} {|
>} .=> linelist -block {} {|
data2
>} .=lhs>1 linelist -block {} {|
>} .=lhs> linelist -block {} {|
>} .= {lmap v $data w $data2 {val "[overtype::left $col1 $v][overtype::left $col2 $w]"}} {|
>} list_as_lines <lhs/0,rhs/1|
namespace eval ::textblock::piper {
proc join {rhs existing} {
tailcall ::textblock::join $existing $rhs
}
}
interp alias {} piper_blockjoin {} ::textblock::piper::join
pipealias ::textblock::join_right .= {list $lhs [string repeat " " [width $lhs]] $rhs [string repeat " " [width $rhs]]} {|
/2,col1/1,col2/3
>} .=>1 linelist -block {} {|
>} .=> linelist -block {} {|
data2
>} .=lhs>1 linelist -block {} {|
>} .=lhs> linelist -block {} {|
>} .= {lmap v $data w $data2 {val "[overtype::right $col1 $v][overtype::right $col2 $w]"}} {|
>} list_as_lines <lhs/0,rhs/1|
@ -86,22 +156,53 @@ namespace eval textblock {
.= textblock::join [list 1 2 3 4 5 6 7] [>punk . lhs] |> .=>1 textblock::join " " |> .=>1 textblock::join $text |> .=>1 textblock::join [>punk . rhs] |> .=>1 textblock::join [lrepeat 7 " | "]
}
proc frame {string args} {
proc frame {args} {
package require punk::char
set contents [lindex $args end]
set arglist [lrange $args 0 end-1]
if {[llength $arglist] % 2 != 0} {
error "Usage frame ?-ansi 0|1? <contents>"
}
#todo args -justify left|centre|right (center)
set string [textutil::tabify::untabify2 $string]
set string [string map [list \r\n \n] $string]
if {[string first \n $string] >= 0} {
set width [width $string]
set defaults [dict create\
-ansi 0\
]
set opts [dict merge $defaults $arglist]
# -- --- --- --- --- ---
set ansi [dict get $opts -ansi]
# -- --- --- --- --- ---
set contents [textutil::tabify::untabify2 $contents]
set contents [string map [list \r\n \n] $contents]
if {[string first \n $contents] >= 0} {
set width [width $contents]
} else {
set width [width [list $string]]
set width [width [list $contents]]
}
set lines [split $string \n]
append fs [cd::tlc][string repeat [cd::hl] $width][cd::trc]\n
foreach l $lines {
append fs [cd::vl]${l}[string repeat " " [expr {$width-[string length [stripansi $l]]}]][cd::vl]\n
set lines [split $contents \n]
if {$ansi} {
#old style ansi escape sequences with alternate graphics page G0
append fs [cd::tlc][string repeat [cd::hl] $width][cd::trc]\n
foreach l $lines {
append fs [cd::vl]${l}[string repeat " " [expr {$width-[string length [stripansi $l]]}]][cd::vl]\n
}
append fs [cd::blc][string repeat [cd::hl] $width][cd::brc]
return [cd::groptim $fs]
} else {
#unicode box drawing set
set hz [punk::char::charshort boxd_lhz] ;# light horizontal
append fs [punk::char::charshort boxd_ldr][string repeat $hz $width][punk::char::charshort boxd_ldl]\n
set vl [punk::char::charshort boxd_lv] ;#light vertical
foreach l $lines {
append fs $vl${l}[string repeat " " [expr {$width-[string length [stripansi $l]]}]]$vl\n
}
append fs [punk::char::charshort boxd_lur][string repeat $hz $width][punk::char::charshort boxd_lul]
return $fs
}
append fs [cd::blc][string repeat [cd::hl] $width][cd::brc]
return [cd::groptim $fs]
}
namespace import ::overtype::stripansi
}

20
src/punk86.vfs/lib/app-punk/repl.tcl

@ -14,8 +14,13 @@ package provide app-punk 1.0
set original_tm_list [tcl::tm::list]
tcl::tm::remove {*}$original_tm_list
#tm list first added end up later in the list - and then override earlier ones if version the same - so add pwd-relative 1st to give higher priority
#1
if {[file exists [pwd]/modules]} {
catch {tcl::tm::add [pwd]/modules}
}
#1)
#2)
if {[string match "*.vfs/*" [info script]]} {
#src/xxx.vfs/lib/app-punk/repl.tcl
#we assume if calling directly into .vfs that the user would prefer to use src/modules - so go up 4 levels
@ -31,16 +36,17 @@ if {[file exists $modulefolder]} {
} else {
puts stderr "Warning unable to find module folder at: $modulefolder"
}
if {[file exists [pwd]/modules]} {
catch {tcl::tm::add [pwd]/modules}
}
if {[file exists [pwd]/lib]} {
lappend ::auto_path [pwd]/lib
}
#libs are appended to end - so add higher prioriy libraries last (opposite to modules)
#auto_path - add exe-relative after exe-relative path
set libfolder [file dirname [file dirname [info nameofexecutable]]]/lib
if {[file exists $libfolder]} {
lappend ::auto_path $libfolder
}
if {[file exists [pwd]/lib]} {
lappend ::auto_path [pwd]/lib
}
#2)
#now add current dir (if no conflict with above)

623
src/vendormodules/overtype-1.5.0.tm

@ -61,26 +61,67 @@ proc overtype::about {} {
proc overtype::stripcodes {text} {
tailcall overtype::stripansi $text
}
namespace eval overtype {
variable escape_terminals
#single "final byte" in the range 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).
dict set escape_terminals CSI [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 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 "\{" "\}"]
#dict set escape_terminals CSI [list J K m n A B C D E F G s u] ;#basic
dict set escape_terminals OSC [list \007 \033\\] ;#note mix of 1 and 2-byte terminals
#self-contained 2 byte ansi escape sequences - review more?
variable ansi_2byte_codes_dict
set ansi_2byte_codes_dict [dict create\
"reset_terminal" "\u001bc"\
"save_cursor_posn" "\u001b7"\
"restore_cursor_posn" "\u001b8"\
"cursor_up_one" "\u001bM"\
"NEL - Next Line" "\u001bE"\
"IND - Down one line" "\u001bD"\
"HTS - Set Tab Stop" "\u001bH"\
]
#debatable whether strip should reveal the somethinghidden - some terminals don't hide it anyway.
# "PM - Privacy Message" "\u001b^somethinghidden\033\\"\
}
proc overtype::stripansi {text} {
variable escape_terminals ;#dict
variable ansi_2byte_codes_dict
set text [convert_g0 $text]
#we process char by char - line-endings whether \r\n or \n should be processed as per any other character.
#line endings can theoretically occur within an ansi escape sequence (review e.g title?)
set inputlist [split $text ""]
set outputlist [list]
dict set escape_terminals 1 [list J K m n A B C D E F G s u] ;#review
dict set escape_terminals 2 [list \007]
set outputlist [list]
set 2bytecodes [dict values $ansi_2byte_codes_dict]
set in_escapesequence 0
#assumption - undertext already 'rendered' - ie no backspaces or carriagereturns or other cursor movement controls
set i 0
foreach u $inputlist {
set v [lindex $inputlist $i+1]
if {$in_escapesequence != 0} {
if {$u in [dict get $escape_terminals $in_escapesequence]} {
set uv ${u}${v}
if {$in_escapesequence eq "2b"} {
#2nd byte - done.
set in_escapesequence 0
} elseif {$in_escapesequence != 0} {
set escseq [dict get $escape_terminals $in_escapesequence]
if {$u in $escseq} {
set in_escapesequence 0
} elseif {$uv in $escseq} {
set in_escapseequence 2b ;#flag next byte as last in sequence
}
} else {
if {$u eq "\033" && $v eq "\["} {
set in_escapesequence 1
} elseif {$u eq "\033" && $v eq "\]"} {
set in_escapesequence 2
#handle both 7-bit and 8-bit CSI and OSC
if {[regexp {^(?:\033\[|\u009b)} $uv]} {
set in_escapesequence CSI
} elseif {[regexp {^(?:\033\]|\u009c)} $uv]} {
set in_escapesequence OSC
} elseif {$uv in $2bytecodes} {
#self-contained e.g terminal reset - don't pass through.
set in_escapesequence 2b
} else {
lappend outputlist $u
}
@ -88,65 +129,50 @@ proc overtype::stripansi {text} {
incr i
}
return [join $outputlist ""]
}
#review
#todo - map other chars to unicode equivs
proc overtype::convert_g0 {text} {
#using not \033 inside to stop greediness - review how does it compare to ".*?"
set re {\033\(0[^\033]*\033\(B}
set re2 {\033\(0(.*)\033\(B} ;#capturing
set parts [ta::_perlish_split $re $text]
set out ""
foreach {pt g} $parts {
append out $pt
if {$g ne ""} {
#puts --$g--
#box sample
#lqk
#x x
#mqj
#m = boxd_lur
#set map [list l \u250f k \u2513] ;#heavy
set map [list l \u250c q \u2500 k \u2510 x \u2502 m \u2514 j \u2518] ;#light
regexp $re2 $g _match contents
append out [string map $map $contents]
}
}
return $out
}
#maintenance warning - also in 'shellfilter' pkg
#strip ansi codes from text - basic! assumes we don't get data split in the middle of an ansi-code ie best used with line-buffering
proc overtype::stripansi2 {text} {
variable lasttext ""
if {[set posn [string first "\033" $text]] < 0} {
return $text
}
if {[set posn [string first "\033(" $text]] >= 0} {
#todo - convert esc(0 graphics sequences to single char unicode equivalents e.g box drawing set
# esc) ??
proc overtype::stripansi_gx {text} {
#e.g "\033(0" - select VT100 graphics for character set G0
#e.g "\033(X" - where X is any char other than 0 to reset
set text [string range $text 0 $posn-1][string range $text $posn+3 end]
}
if {[set posn [string first "\033)" $text]] >= 0} {
#e.g "\033(B" - reset
#e.g "\033)0" - select VT100 graphics for character set G1
#e.g "\033)X" - where X is any char other than 0 to reset
set text [string range $text 0 $posn-1][string range $text $posn+3 end]
}
#strip title including inner text - the title is an instruction to the window - so the title-text doesn't form part of the line-data in the text block
if {[set posn [string first "\033\]" $text]] >= 0} {
set next2 [string range $text $posn+2 $posn+3]
if {$next2 in [list {0;} {1;} {2;}]} {
#0; set icon name and window title
#1; set icon name
#2; set window title
set tail [string range $text $posn end]
set endoffset [string first \007 $tail]
if {$endoffset > 3} {
set text [string range $text 0 $posn-1][string range $text $posn+$offset+1 end]
} else {
#unexpected.. we seem to be missing terminating BEL character
puts stderr "stripansi failure: missing terminator BEL on title"
}
}
}
if {[set posn [string first "\033\[" $text]] >= 0} {
set mnext [string first m [string range $text $posn end]]
if {$mnext >= 0} {
set mpos [expr {$posn + $mnext}]
set stripped1 [string range $text 0 $posn-1][string range $text $mpos+1 end]
#return [stripansi $stripped1] ;#recurse to get any others
tailcall ::overtype::stripansi $stripped1
} else {
#partial or not actually a basic ansi code.. pass it all through
return $text
}
}
if {[set posn [string first "\033" $text]] >= 0} {
if {$lasttext eq $text} {
return $text
}
set lasttext $text
tailcall ::overtype::stripansi $text
}
return $text
#e.g "\033)X" - where X is any char other than 0 to reset ??
return [convert_g0 $text]
}
proc overtype::strip_nonprinting {str} {
proc overtype::strip_nonprinting_ascii {str} {
#review - some single-byte 'control' chars have visual representations e.g ETX as heart
#It is currently used for screen display width calculations
#equivalent for various unicode combining chars etc?
set map [list\
\007 ""\
[format %c 0] ""\
@ -156,7 +182,8 @@ proc overtype::strip_nonprinting {str} {
}
#length of text for printing characters only
#review - unicode and other non-printing chars?
#review - unicode and other non-printing chars and combining sequences?
#certain unicode chars are full-width (single char 2 columns wide) e.g see "Halfwdith and fullwidth forms" and ascii_fuillwidth blocks in punk::char::charset_names
#review - is there an existing library or better method? print to a terminal and query cursor position?
#Note this length calculation is only suitable for lines being appended to other strings if the line is pre-processed to account for backspace and carriage returns first
#If the raw line is appended to another string without such processing - the backspaces & carriage returns can affect data prior to the start of the string.
@ -165,7 +192,7 @@ proc overtype::printing_length {line} {
error "line_print_length must not contain newline characters"
}
set line [stripansi $line]
set line [strip_nonprinting $line] ;#only strip nonprinting after stripansi - some like BEL are part of ansi
set line [strip_nonprinting_ascii $line] ;#only strip nonprinting after stripansi - some like BEL are part of ansi
#backspace 0x08 only erases* printing characters anyway - so presumably order of processing doesn't matter
#(* more correctly - moves cursor back)
#backspace will not move beyond a preceding newline - but we have disallowed newlines for this function already
@ -183,10 +210,12 @@ proc overtype::printing_length {line} {
#set line [string map [list "\r${bs}" "\r"] $line] ;#backsp following a \r will have no effect
set line [string trim $line $bs]
set n 0
set chars [split $line ""]
#build an output
set idx 0
set out [list]
set outchars [list]
set outsizes [list]
foreach c $chars {
if {$c eq $bs} {
if {$idx > 0} {
@ -199,17 +228,18 @@ proc overtype::printing_length {line} {
incr idx
}
}
set line2 [join $out ""]
set line2 [join $outchars ""]
return [string length $line2]
}
namespace eval overtype::priv {
proc printing_length_addchar {i c} {
upvar out o
set nxt [llength $o]
upvar outchars outc
upvar outsizes outs
set nxt [llength $outc]
if {$i < $nxt} {
lset o $i $c
lset outc $i $c
} else {
lappend o $c
lappend outc $c
}
}
}
@ -258,7 +288,7 @@ proc overtype::left {args} {
set diff [expr {$overlen - $colwidth}]
#review
append overtext "\033\[0m"
#append overtext "\033\[0m"
if {$diff > 0} {
#background line is narrower
@ -369,6 +399,101 @@ proc overtype::centre {args} {
return [join $outputlines \n]
}
proc overtype::right {args} {
variable default_ellipsis_horizontal
# @d !todo - implement overflow, length checks etc
if {[llength $args] < 2} {
error {usage: ?-overflow [1|0]? undertext overtext}
}
foreach {underblock overblock} [lrange $args end-1 end] break
set defaults [dict create\
-bias left\
-ellipsis 0\
-ellipsistext $default_ellipsis_horizontal\
-overflow 0\
-transparent 0\
]
set known_opts [dict keys $defaults]
set argsflags [lrange $args 0 end-2]
dict for {k v} $argsflags {
if {$k ni $known_opts} {
error "overtype::centre unknown option '$k'. Known options: $known_opts"
}
}
set opts [dict merge $defaults $argsflags]
# -- --- --- --- --- ---
set opt_transparent [dict get $opts -transparent]
set opt_ellipsis [dict get $opts -ellipsis]
set opt_ellipsistext [dict get $opts -ellipsistext]
set opt_overflow [dict get $opts -overflow]
# -- --- --- --- --- ---
set norm [list \r\n \n]
set underblock [string map $norm $underblock]
set overblock [string map $norm $overblock]
set underlines [split $underblock \n]
set colwidth [tcl::mathfunc::max {*}[lmap v $underlines {printing_length $v}]]
set overlines [split $overblock \n]
set outputlines [list]
foreach undertext $underlines overtext $overlines {
set olen [printing_length $overtext]
set ulen [printing_length $undertext]
if {$ulen < $colwidth} {
set udiff [expr {$colwidth - $ulen}]
set undertext "$undertext[string repeat { } $udiff]"
}
#review
#append overtext "\033\[0m"
set overflowlength [expr {$olen - $colwidth}]
if {$overflowlength > 0} {
#overtext wider than undertext column
set rendered [renderline -transparent $opt_transparent -overflow $opt_overflow -start 0 $undertext $overtext]
if {!$opt_overflow} {
if {$opt_ellipsis} {
set rendered [overtype::right $rendered $opt_ellipsistext]
}
}
lappend outputlines $rendered
} else {
#lappend outputlines [string range $undertext 0 end-$olen]$overtext
lappend outputlines [renderline -transparent $opt_transparent -start [expr {$colwidth - $olen}] $undertext $overtext]
}
}
return [join $outputlines \n]
}
proc overtype::right_prev {args} {
# @d !todo - implement overflow, length checks etc
if {[llength $args] < 2} {
error {usage: ?-overflow [1|0]? undertext overtext}
}
foreach {undertext overtext} [lrange $args end-1 end] break
set opt(-overflow) 0
array set opt [lrange $args 0 end-2]
set olen [printing_length $overtext]
set ulen [printing_length $undertext]
if {$opt(-overflow)} {
return [string range $undertext 0 end-$olen]$overtext
} else {
if {$olen > $ulen} {
set diff [expr {$olen - $ulen}]
return [string range $undertext 0 end-$olen][string range $overtext 0 end-$diff]
} else {
return [string range $undertext 0 end-$olen]$overtext
}
}
}
# -- --- --- --- --- --- --- --- --- --- ---
#todo - ansi
proc overtype::transparentline {args} {
@ -381,12 +506,24 @@ proc overtype::transparentline {args} {
tailcall overtype::renderline {*}$newargs $under $over
}
#renderline may not make sense as it is in the long run. We are trying to handle ansi codes in a block of text which is acting like a mini-terminal in some sense.
#renderline may not make sense as it is in the long run for blocks of text - but is handy in the single-line-handling form anyway.
# We are trying to handle ansi codes in a block of text which is acting like a mini-terminal in some sense.
#We can process standard cursor moves such as \b \r - but no way to respond to other cursor movements e.g moving to other lines.
#
namespace eval overtype::piper {
proc renderline {args} {
if {[llength $args] < 2} {
error {usage: ?-start <int>? ?-transparent [0|1|<regexp>]? ?-overflow [1|0]? overtext pipelinedata}
}
foreach {over under} [lrange $args end-1 end] break
set argsflags [lrange $args 0 end-2]
tailcall overtype::renderline {*}$argsflags $under $over
}
}
interp alias "" piper_renderline "" overtype::piper::renderline
proc overtype::renderline {args} {
if {[llength $args] < 2} {
error {usage: ?-transparent [0|1|<regexp>]? ?-overflow [1|0]? undertext overtext}
error {usage: ?-start <int>? ?-transparent [0|1|<regexp>]? ?-overflow [1|0]? undertext overtext}
}
foreach {under over} [lrange $args end-1 end] break
if {[string first \n $under] >=0 || [string first \n $over] >= 0} {
@ -395,6 +532,7 @@ proc overtype::renderline {args} {
set defaults [dict create\
-overflow 0\
-transparent 0\
-start 0\
]
set known_opts [dict keys $defaults]
set argsflags [lrange $args 0 end-2]
@ -406,6 +544,163 @@ proc overtype::renderline {args} {
set opts [dict merge $defaults $argsflags]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_overflow [dict get $opts -overflow]
set opt_colstart [dict get $opts -start]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_transparent [dict get $opts -transparent]
if {$opt_transparent eq "0"} {
set do_transparency 0
} else {
set do_transparency 1
if {$opt_transparent eq "1"} {
set opt_transparent {[\s]}
}
}
# -- --- --- --- --- --- --- --- --- --- --- ---
if {[string first \t $under] >= 0} {
set under [textutil::tabify::untabify2 $under]
}
set overdata $over
if {[string first \t $over] >= 0} {
set overdata [textutil::tabify::untabify2 $over]
}
set over [string repeat " " $opt_colstart]
append over $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
set undermap [overtype::ta::split_codes_single $under]
set overmap [overtype::ta::split_codes_single $over]
set understacks [dict create]
set i_u 0
set i_o 0
set out [list]
set u_codestack [list]
foreach {pt code} $undermap {
foreach ch [split $pt ""] {
dict set understacks $i_u $u_codestack
incr i_u
lappend out $ch
}
if {[priv::is_csi_reset $code]} {
set u_codestack [list]
} else {
lappend u_codestack $code
}
}
set overstacks [dict create]
set o_codestack [list]
foreach {pt code} $overmap {
foreach ch [split $pt ""] {
dict set overstacks $i_o $o_codestack
incr i_o
}
if {[priv::is_csi_reset $code]} {
set o_codestack [list]
} else {
lappend o_codestack $code
}
}
set bs [format %c 0x08]
set idx 0
set idx_over -1
foreach {pt code} $overmap {
foreach ch [split $pt ""] {
incr idx_over
if {$ch eq "\r"} {
set idx $opt_colstart
} elseif {$ch eq "\b"} {
if {$idx > $opt_colstart} {
incr idx -1
}
} elseif {$idx < $opt_colstart} {
incr idx
} elseif {$do_transparency && [regexp $opt_transparent $ch]} {
if {$idx > [llength $out]-1} {
lappend out " "
dict set understacks $idx [list] ;#review - use idx-1 codestack?
}
incr idx
} else {
priv::render_addchar $idx $ch [dict get $overstacks $idx_over]
incr idx
}
}
}
#coalesce and replay codestacks for out char list
set outstring ""
set i 0
set cstack [list]
set prevstack [list]
foreach ch $out {
set cstack [dict get $understacks $i]
if {$cstack ne $prevstack} {
if {[llength $prevstack]} {
append outstring \033\[m
}
foreach code $cstack {
append outstring $code
}
}
append outstring $ch
set prevstack $cstack
incr i
}
#pdict $understacks
return $outstring
#return [join $out ""]
}
namespace eval overtype::priv {
proc is_csi_reset {code} {
#todo 8-bit csi
regexp {\033\[0*m} $code
}
#whether this code has 0 (or equivalently empty) parameter (but may set others)
proc has_csi_reset {code} {
}
proc render_addchar {i c stack} {
upvar out o
upvar understacks ustacks
set nxt [llength $o]
if {$i < $nxt} {
lset o $i $c
} else {
lappend o $c
}
dict set ustacks $i $stack
}
}
proc overtype::renderline1 {args} {
if {[llength $args] < 2} {
error {usage: ?-start <int>? ?-transparent [0|1|<regexp>]? ?-overflow [1|0]? undertext overtext}
}
foreach {under over} [lrange $args end-1 end] break
if {[string first \n $under] >=0 || [string first \n $over] >= 0} {
error "overtype::renderline not allowed to contain newlines"
}
set defaults [dict create\
-overflow 0\
-transparent 0\
-start 0\
]
set known_opts [dict keys $defaults]
set argsflags [lrange $args 0 end-2]
dict for {k v} $argsflags {
if {$k ni $known_opts} {
error "overtype::renderline unknown option '$k'. Known options: $known_opts"
}
}
set opts [dict merge $defaults $argsflags]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_overflow [dict get $opts -overflow]
set opt_colstart [dict get $opts -start]
# -- --- --- --- --- --- --- --- --- --- --- ---
set opt_transparent [dict get $opts -transparent]
if {$opt_transparent eq "0"} {
@ -422,9 +717,12 @@ proc overtype::renderline {args} {
if {[string first \t $under] >= 0} {
set under [textutil::tabify::untabify2 $under]
}
set overdata $over
if {[string first \t $over] >= 0} {
set over [textutil::tabify::untabify2 $over]
set overdata [textutil::tabify::untabify2 $over]
}
set over [string repeat " " $opt_colstart]
append over $overdata ;#overdata with left padding spaces based on col-start under will show through for left-padding portion regardless of -transparency
set bs [format %c 0x08]
@ -435,7 +733,7 @@ proc overtype::renderline {args} {
set out [split $under ""]
set under_printables [list]
set in_escapesequence 0
#assumption - undertext already 'rendered' - ie no backspaces or carriagereturns or other cursor movement controls
#assumption - undertext already 'rendered/wrapped' - ie no backspaces or carriagereturns or other cursor movement controls
#this is basically a form of stripansi... review!
foreach u [split $under ""] {
if {$in_escapesequence} {
@ -491,6 +789,9 @@ proc overtype::renderline {args} {
if {$i_printable > 0} {
incr i_printable -1
}
} elseif {$i_printable < $opt_colstart} {
incr i
incr i_printable
} elseif {$do_transparency && [regexp $opt_transparent $o]} {
if {$i > [llength $out]-1} {
lappend out " "
@ -501,8 +802,6 @@ proc overtype::renderline {args} {
}
incr i_printable
} else {
priv::renderline_addchar $i $o
priv::renderline_addprintable $i_printable $o
if {!$opt_overflow} {
if {$i_printable == $original_under_printlen} {
#we have reached our cutoff length - but there could be a closing ansi code or other control characters that would change the already-processed output.
@ -512,6 +811,8 @@ proc overtype::renderline {args} {
break
}
}
priv::renderline_addchar $i $o
priv::renderline_addprintable $i_printable $o
incr i
incr i_printable
}
@ -550,75 +851,117 @@ namespace eval overtype::priv {
}
}
# -- --- --- --- --- --- --- --- --- --- ---
namespace eval overtype::ta {
namespace path ::overtype
#*based* on but not identical to:
#https://github.com/perlancar/perl-Text-ANSI-Util/blob/master/lib/Text/ANSI/BaseUtil.pm
#handle both 7-bit and 8-bit csi
#review - does codepage affect this? e.g ebcdic has 8bit csi in different position
#CSI
variable re_csi_open {(?:\033\[|\u009b)[0-9;]+}
#colour and style
variable re_csi_colour {(?:\033\[|\u009b)[0-9;]*m} ;#e.g \033\[31m \033\[m \033\[0m \033\[m0000m
#single "final byte" in the range 0x40–0x7E (ASCII @A–Z[\]^_`a–z{|}~).
variable re_csi_code {(?:\033\[|\u009b])[0-9;]*[a-zA-Z\\@^_|~`]}
#OSC - termnate with BEL (\a \007) or ST (string terminator \033\\)
#variable re_esc_osc1 {(?:\033\]|\u009c).*\007}
#variable re_esc_osc2 {(?:\033\]|\u009c).*\033\\}
#test - non-greedy
variable re_esc_osc1 {(?:\033\]|\u009c).*?\007}
variable re_esc_osc2 {(?:\033\]|\u009c).*?\033\\}
#detect any ansi escapes
proc detect {text} {
variable re_csi_open
variable re_esc_osc1
variable re_esc_osc2
#todo - other escape sequences
expr {[regexp $re_csi_open $text] || [regexp $re_esc_osc1 $text] || [regexp $re_esc_osc2 $text]}
}
#not in perl ta
proc detect_csi {text} {
variable re_csi_colour
expr {[regexp $re_csi_colour $text]}
}
proc strip {text} {
tailcall stripansi $text
}
#note this is character length after stripping ansi codes - not the printing length
proc length {text} {
string length [overtype::stripansi $text]
}
#todo - handle newlines
#not in perl ta
proc printing_length {text} {
proc overtype::centre_prev {args} {
if {[llength $args] < 2} {
error {usage: ?-bias [left|right]? ?-overflow [1|0]? undertext overtext}
}
foreach {undertext overtext} [lrange $args end-1 end] break
set opt(-bias) left
set opt(-overflow) 0
array set opt [lrange $args 0 end-2]
set olen [printing_length $overtext]
set ulen [printing_length $undertext]
set diff [expr {$ulen - $olen}]
if {$diff > 0} {
set half [expr {round(int($diff / 2))}]
if {[string match right $opt(-bias)]} {
if {[expr {2 * $half}] < $diff} {
incr half
}
}
set rhs [expr {$diff - $half - 1}]
set lhs [expr {$half - 1}]
set a [string range $undertext 0 $lhs]
set b $overtext
set c [string range $undertext end-$rhs end]
return $a$b$c
} else {
if {$diff < 0} {
if {$opt(-overflow)} {
return $overtext
} else {
return [string range $overtext 0 [expr {$ulen - 1}]]
}
} else {
return $overtext
}
}
}
proc overtype::right {args} {
# @d !todo - implement overflow, length checks etc
if {[llength $args] < 2} {
error {usage: ?-overflow [1|0]? undertext overtext}
}
foreach {undertext overtext} [lrange $args end-1 end] break
set opt(-overflow) 0
array set opt [lrange $args 0 end-2]
}
#not in perl ta
#returns just the plaintext portions in a list
proc split_at_codes {text} {
variable re_esc_osc1
variable re_esc_osc2
variable re_csi_code
textutil::splitx $text "${re_csi_code}|${re_esc_osc1}|${re_esc_osc2}"
}
# -- --- --- --- --- ---
#Split $text to a list containing alternating ANSI color codes and text.
#ANSI color codes are always on the second element, fourth, and so on.
#(ie plaintext on odd list-indices ansi on even indices)
# Example:
#ta_split_codes "" # => ""
#ta_split_codes "a" # => "a"
#ta_split_codes "a\e[31m" # => {"a" "\e[31m"}
#ta_split_codes "\e[31ma" # => {"" "\e[31m" "a"}
#ta_split_codes "\e[31ma\e[0m" # => {"" "\e[31m" "a" "\e[0m"}
#ta_split_codes "\e[31ma\e[0mb" # => {"" "\e[31m" "a" "\e[0m", "b"}
#ta_split_codes "\e[31m\e[0mb" # => {"" "\e[31m\e[0m" "b"}
#
proc split_codes {text} {
variable re_esc_osc1
variable re_esc_osc2
variable re_csi_code
set re "(?:${re_csi_code}|${re_esc_osc1}|${re_esc_osc2})+"
return [_perlish_split $re $text]
}
#like split_codes - but each ansi-escape is split out separately (with empty string of plaintext between codes so odd/even plain ansi still holds)
proc split_codes_single {text} {
variable re_esc_osc1
variable re_esc_osc2
variable re_csi_code
set re "${re_csi_code}|${re_esc_osc1}|${re_esc_osc2}"
return [_perlish_split $re $text]
}
set olen [printing_length $overtext]
set ulen [printing_length $undertext]
#review - tcl greedy expressions may match multiple in one element
proc _perlish_split {re text} {
if {[string length $text] == 0} {
return {}
}
set list [list]
set start 0
while {[regexp -start $start -indices -- $re $text match]} {
lassign $match matchStart matchEnd
lappend list [string range $text $start $matchStart-1] [string range $text $matchStart $matchEnd]
set start [expr {$matchEnd+1}]
}
lappend list [string range $text $start end]
return $list
}
proc _ws_split {text} {
regexp -all -inline {(?:\S+)|(?:\s+)} $text
}
# -- --- --- --- --- ---
if {$opt(-overflow)} {
return [string range $undertext 0 end-$olen]$overtext
} else {
if {$olen > $ulen} {
set diff [expr {$olen - $ulen}]
return [string range $undertext 0 end-$olen][string range $overtext 0 end-$diff]
} else {
return [string range $undertext 0 end-$olen]$overtext
}
}
}
# -- --- --- --- --- --- --- --- --- --- ---
namespace eval overtype {
interp alias {} ::overtype::center {} ::overtype::centre
}

Loading…
Cancel
Save