sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

color.sh (70865B)


      1 #!/bin/bash
      2 
      3 # gflags
      4 
      5 _ble_color_gflags_Bold=0x01
      6 _ble_color_gflags_Italic=0x02
      7 _ble_color_gflags_Underline=0x04
      8 _ble_color_gflags_Revert=0x08
      9 _ble_color_gflags_Invisible=0x10
     10 _ble_color_gflags_Strike=0x20
     11 _ble_color_gflags_Blink=0x40
     12 
     13 _ble_color_gflags_DecorationMask=0x77
     14 _ble_color_gflags_FgMask=0x00000000FFFFFF00
     15 _ble_color_gflags_BgMask=0x00FFFFFF00000000
     16 _ble_color_gflags_FgShift=8
     17 _ble_color_gflags_BgShift=32
     18 _ble_color_gflags_FgIndexed=0x0100000000000000
     19 _ble_color_gflags_BgIndexed=0x0200000000000000
     20 
     21 _ble_color_index_colors_default=$_ble_term_colors
     22 if [[ $TERM == xterm* || $TERM == *-256color || $TERM == kterm* ]]; then
     23   _ble_color_index_colors_default=256
     24 elif [[ $TERM == *-88color ]]; then
     25   _ble_color_index_colors_default=88
     26 fi
     27 
     28 bleopt/declare -v term_true_colors semicolon
     29 bleopt/declare -v term_index_colors auto
     30 
     31 function bleopt/check:term_true_colors {
     32   ble/color/g2sgr/.clear-cache
     33   return 0
     34 }
     35 function bleopt/check:term_index_colors {
     36   ble/color/g2sgr/.clear-cache
     37   return 0
     38 }
     39 function ble/color/initialize-term-colors {
     40   local fields
     41   ble/string#split fields \; "$_ble_term_DA2R"
     42   if [[ $bleopt_term_true_colors == auto ]]; then
     43     # truecolor support 自動判定 (暫定実装)
     44     local value=
     45     if [[ $TERM == *-24bit || $TERM == *-direct ]]; then
     46       value=colon
     47     elif [[ $TERM == *-24bits || $TERM == *-truecolor || $COLORTERM == *24bit* || $COLORTERM == *truecolor* ]]; then
     48       value=semicolon
     49     else
     50       case ${fields[0]} in
     51       (83) # screen (truecolor on にしている必要がある。判定方法は不明)
     52         if ((fields[1]>=49900)); then
     53           value=semicolon
     54         fi ;;
     55       (67)
     56         if ((fields[1]>=100000)); then
     57           : # cygwin terminal
     58         else
     59           # contra
     60           value=colon
     61         fi ;;
     62       esac
     63     fi
     64     [[ $value ]] &&
     65       bleopt term_true_colors="$value"
     66   fi
     67 }
     68 blehook term_DA2R!=ble/color/initialize-term-colors
     69 
     70 
     71 function ble-color-show {
     72   if (($#)); then
     73     ble/base/print-usage-for-no-argument-command 'Update and reload ble.sh.' "$@"
     74     return "$?"
     75   fi
     76 
     77   local cols=$(((${COLUMNS:-80}-1)/4))
     78   ((cols<1?(cols=1):(cols>16&&(cols=16))))
     79   local bg bg0 bgN ret gflags=$((_ble_color_gflags_BgIndexed|_ble_color_gflags_FgIndexed))
     80   for ((bg0=0;bg0<256;bg0+=cols)); do
     81     ((bgN=bg0+cols,bgN<256||(bgN=256)))
     82     for ((bg=bg0;bg<bgN;bg++)); do
     83       ble/color/g2sgr "$((gflags|bg<<_ble_color_gflags_BgShift))"
     84       printf '%s%03d ' "$ret" "$bg"
     85     done
     86     printf '%s\n' "$_ble_term_sgr0"
     87     for ((bg=bg0;bg<bgN;bg++)); do
     88       ble/color/g2sgr "$((gflags|bg<<_ble_color_gflags_BgShift|15<<_ble_color_gflags_FgShift))"
     89       printf '%s%03d ' "$ret" "$bg"
     90     done
     91     printf '%s\n' "$_ble_term_sgr0"
     92   done
     93 }
     94 function ble-palette {
     95   if (($#)); then
     96     ble/base/print-usage-for-no-argument-command 'Update and reload ble.sh.' "$@"
     97     return "$?"
     98   fi
     99 
    100   if ((${COLUMNS:-80}<80)); then
    101     ble-color-show
    102     return 0
    103   fi
    104 
    105   local ret gflags=$((_ble_color_gflags_BgIndexed|_ble_color_gflags_FgIndexed))
    106   local l c bg
    107   for ((l=0;l<2;l++)); do
    108     for ((c=0;c<16;c++)); do
    109       ((bg=l/2*8+c))
    110       ble/color/g2sgr "$((gflags|bg<<_ble_color_gflags_BgShift|(l%2?15:0)<<_ble_color_gflags_FgShift))"
    111       printf '%s%03d ' "$ret" "$bg"
    112     done
    113     printf '%s\n' "$_ble_term_sgr0"
    114   done
    115 
    116   local l p B G R
    117   for ((l=0;l<24;l++)); do
    118     ((G=l%12/2))
    119     for ((p=0;p<3;p++)); do
    120       ((R=l>=12?3+p:p))
    121       for ((B=0;B<6;B++)); do
    122         ((bg=16+R*36+G*6+B))
    123         ble/color/g2sgr "$((gflags|bg<<_ble_color_gflags_BgShift|(l%2?15:0)<<_ble_color_gflags_FgShift))"
    124         printf '%s%03d ' "$ret" "$bg"
    125       done
    126       if ((p+1<3)); then
    127         printf '%s ' "$_ble_term_sgr0"
    128       else
    129         printf '%s\n' "$_ble_term_sgr0"
    130       fi
    131     done
    132   done
    133 
    134   local l c K
    135   for ((l=0;l<4;l++)); do
    136     for ((c=0;c<12;c++)); do
    137       ((K=l/2*12+c))
    138       ((bg=232+K))
    139       ble/color/g2sgr "$((gflags|bg<<_ble_color_gflags_BgShift|(l%2?15:0)<<_ble_color_gflags_FgShift))"
    140       printf '%s%03d ' "$ret" "$bg"
    141     done
    142     printf '%s\n' "$_ble_term_sgr0"
    143   done
    144 }
    145 
    146 
    147 ## @fn ble/color/g2sgr g
    148 ## @fn ble/color/g2sgr-ansi g
    149 ##   @param[in] g
    150 ##   @var[out] ret
    151 ##
    152 #
    153 # Note: もし SGR 以外の制御機能を使って (tput 等の出力を用いて) 描画シー
    154 #   ケンスを構築する様に拡張する場合には、
    155 #   ble/textarea#slice-text-buffer に於いて行っている CR LF の組の検出
    156 #   において、間に許容する制御機能の種類に注意する。もし考慮に入れてい
    157 #   ない物をここで使いたい時には、それを
    158 #   ble/textarea#slice-text-buffer の正規表現に追加しなければならない。
    159 #
    160 _ble_color_g2sgr_version=0
    161 _ble_color_g2sgr=()
    162 _ble_color_g2sgr_ansi=()
    163 function ble/color/g2sgr/.impl {
    164   local g=$(($1))
    165 
    166   local sgr=0
    167   ((g&_ble_color_gflags_Bold))      && sgr="$sgr;${_ble_term_sgr_bold:-1}"
    168   ((g&_ble_color_gflags_Italic))    && sgr="$sgr;${_ble_term_sgr_sitm:-3}"
    169   ((g&_ble_color_gflags_Underline)) && sgr="$sgr;${_ble_term_sgr_smul:-4}"
    170   ((g&_ble_color_gflags_Blink))     && sgr="$sgr;${_ble_term_sgr_blink:-5}"
    171   ((g&_ble_color_gflags_Revert))    && sgr="$sgr;${_ble_term_sgr_rev:-7}"
    172   ((g&_ble_color_gflags_Invisible)) && sgr="$sgr;${_ble_term_sgr_invis:-8}"
    173   ((g&_ble_color_gflags_Strike))    && sgr="$sgr;${_ble_term_sgr_strike:-9}"
    174   if ((g&_ble_color_gflags_FgIndexed)); then
    175     local fg=$((g>>8&0xFF))
    176     ble/color/.color2sgrfg "$fg"
    177     sgr="$sgr;$ret"
    178   elif ((g&_ble_color_gflags_FgMask)); then
    179     local rgb=$((1<<24|g>>8&0xFFFFFF))
    180     ble/color/.color2sgrfg "$rgb"
    181     sgr="$sgr;$ret"
    182   fi
    183   if ((g&_ble_color_gflags_BgIndexed)); then
    184     local bg=$((g>>32&0xFF))
    185     ble/color/.color2sgrbg "$bg"
    186     sgr="$sgr;$ret"
    187   elif ((g&_ble_color_gflags_BgMask)); then
    188     local rgb=$((1<<24|g>>32&0xFFFFFF))
    189     ble/color/.color2sgrbg "$rgb"
    190     sgr="$sgr;$ret"
    191   fi
    192 
    193   ret=$'\e['$sgr'm'
    194   _ble_color_g2sgr[$1]=$ret
    195 }
    196 function ble/color/g2sgr/.clear-cache {
    197   _ble_color_g2sgr=()
    198   ((_ble_color_g2sgr_version++))
    199 }
    200 function ble/color/g2sgr {
    201   ret=${_ble_color_g2sgr[$1]}
    202   [[ $ret ]] || ble/color/g2sgr/.impl "$1"
    203 }
    204 function ble/color/g2sgr-ansi/.impl {
    205   local g=$(($1))
    206 
    207   local sgr=0
    208   ((g&_ble_color_gflags_Bold))      && sgr="$sgr;1"
    209   ((g&_ble_color_gflags_Italic))    && sgr="$sgr;3"
    210   ((g&_ble_color_gflags_Underline)) && sgr="$sgr;4"
    211   ((g&_ble_color_gflags_Blink))     && sgr="$sgr;5"
    212   ((g&_ble_color_gflags_Revert))    && sgr="$sgr;7"
    213   ((g&_ble_color_gflags_Invisible)) && sgr="$sgr;8"
    214   ((g&_ble_color_gflags_Strike))    && sgr="$sgr;9"
    215   if ((g&_ble_color_gflags_FgIndexed)); then
    216     local fg=$((g>>8&0xFF))
    217     sgr="$sgr;38:5:$fg"
    218   elif ((g&_ble_color_gflags_FgMask)); then
    219     local rgb=$((1<<24|g>>8&0xFFFFFF))
    220     local R=$((rgb>>16&0xFF)) G=$((rgb>>8&0xFF)) B=$((rgb&0xFF))
    221     sgr="$sgr;38:2::$R:$G:$B"
    222   fi
    223   if ((g&_ble_color_gflags_BgIndexed)); then
    224     local bg=$((g>>32&0xFF))
    225     sgr="$sgr;48:5:$bg"
    226   elif ((g&_ble_color_gflags_BgMask)); then
    227     local rgb=$((1<<24|g>>32&0xFFFFFF))
    228     local R=$((rgb>>16&0xFF)) G=$((rgb>>8&0xFF)) B=$((rgb&0xFF))
    229     sgr="$sgr;48:2::$R:$G:$B"
    230   fi
    231 
    232   ret=$'\e['$sgr'm'
    233   _ble_color_g2sgr_ansi[$1]=$ret
    234 }
    235 function ble/color/g2sgr-ansi {
    236   ret=${_ble_color_g2sgr_ansi[$1]}
    237   [[ $ret ]] || ble/color/g2sgr-ansi/.impl "$1"
    238 }
    239 
    240 function ble/color/g#setfg-clear {
    241   (($1&=~(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)))
    242 }
    243 function ble/color/g#setbg-clear {
    244   (($1&=~(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)))
    245 }
    246 function ble/color/g#setfg-index {
    247   local _ble_local_color=$2
    248   (($1=$1&~_ble_color_gflags_FgMask|_ble_color_gflags_FgIndexed|(_ble_local_color&0xFF)<<8)) # index color
    249 }
    250 function ble/color/g#setbg-index {
    251   local _ble_local_color=$2
    252   (($1=$1&~_ble_color_gflags_BgMask|_ble_color_gflags_BgIndexed|(_ble_local_color&0xFF)<<32)) # index color
    253 }
    254 function ble/color/g#setfg-rgb {
    255   local _ble_local_R=$2
    256   local _ble_local_G=$3
    257   local _ble_local_B=$4
    258   ((_ble_local_R&=0xFF,_ble_local_G&=0xFF,_ble_local_B&=0xFF))
    259   if ((_ble_local_R==0&&_ble_local_G==0&&_ble_local_B==0)); then
    260     ble/color/g#setfg-index "$1" 16
    261   else
    262     (($1=$1&~(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)|_ble_local_R<<24|_ble_local_G<<16|_ble_local_B<<8)) # true color
    263   fi
    264 }
    265 function ble/color/g#setbg-rgb {
    266   local _ble_local_R=$2
    267   local _ble_local_G=$3
    268   local _ble_local_B=$4
    269   ((_ble_local_R&=0xFF,_ble_local_G&=0xFF,_ble_local_B&=0xFF))
    270   if ((_ble_local_R==0&&_ble_local_G==0&&_ble_local_B==0)); then
    271     ble/color/g#setbg-index "$1" 16
    272   else
    273     (($1=$1&~(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)|_ble_local_R<<48|_ble_local_G<<40|_ble_local_B<<32)) # true color
    274   fi
    275 }
    276 function ble/color/g#setfg-cmyk {
    277   local _ble_local_C=$2
    278   local _ble_local_M=$3
    279   local _ble_local_Y=$4
    280   local _ble_local_K=${5:-0}
    281   ((_ble_local_K=~_ble_local_K&0xFF,
    282     _ble_local_C=(~_ble_local_C&0xFF)*_ble_local_K/255,
    283     _ble_local_M=(~_ble_local_M&0xFF)*_ble_local_K/255,
    284     _ble_local_Y=(~_ble_local_Y&0xFF)*_ble_local_K/255))
    285   ble/color/g#setfg-rgb "$_ble_local_C" "$_ble_local_M" "$_ble_local_Y"
    286 }
    287 function ble/color/g#setbg-cmyk {
    288   local _ble_local_C=$2
    289   local _ble_local_M=$3
    290   local _ble_local_Y=$4
    291   local _ble_local_K=${5:-0}
    292   ((_ble_local_K=~_ble_local_K&0xFF,
    293     _ble_local_C=(~_ble_local_C&0xFF)*_ble_local_K/255,
    294     _ble_local_M=(~_ble_local_M&0xFF)*_ble_local_K/255,
    295     _ble_local_Y=(~_ble_local_Y&0xFF)*_ble_local_K/255))
    296   ble/color/g#setbg-rgb "$1" "$_ble_local_C" "$_ble_local_M" "$_ble_local_Y"
    297 }
    298 function ble/color/g#setfg {
    299   local _ble_local_color=$2
    300   if ((_ble_local_color<0)); then
    301     ble/color/g#setfg-clear "$1"
    302   elif ((_ble_local_color>=0x1000000)); then
    303     if ((_ble_local_color==0x1000000)); then
    304       ble/color/g#setfg-index "$1" 16
    305     else
    306       (($1=$1&~(_ble_color_gflags_FgIndexed|_ble_color_gflags_FgMask)|(_ble_local_color&0xFFFFFF)<<8)) # true color
    307     fi
    308   else
    309     ble/color/g#setfg-index "$1" "$_ble_local_color"
    310   fi
    311 }
    312 function ble/color/g#setbg {
    313   local _ble_local_color=$2
    314   if ((_ble_local_color<0)); then
    315     ble/color/g#setbg-clear "$1"
    316   elif ((_ble_local_color>=0x1000000)); then
    317     if ((_ble_local_color==0x1000000)); then
    318       ble/color/g#setbg-index "$1" 16
    319     else
    320       (($1=$1&~(_ble_color_gflags_BgIndexed|_ble_color_gflags_BgMask)|(_ble_local_color&0xFFFFFF)<<32)) # true color
    321     fi
    322   else
    323     ble/color/g#setbg-index "$1" "$_ble_local_color"
    324   fi
    325 }
    326 ## @fn ble/color/g#append g g2
    327 ##   g に描画属性 g2 を上書きします。
    328 ##   @param[in,out] g
    329 ##   @param[in] g2
    330 function ble/color/g#append {
    331   local _ble_local_g2=$2
    332   ((_ble_local_g2&(_ble_color_gflags_FgMask|_ble_color_gflags_FgIndexed))) &&
    333     (($1&=~(_ble_color_gflags_FgMask|_ble_color_gflags_FgIndexed)))
    334   ((_ble_local_g2&(_ble_color_gflags_BgMask|_ble_color_gflags_BgIndexed))) &&
    335     (($1&=~(_ble_color_gflags_BgMask|_ble_color_gflags_BgIndexed)))
    336   (($1|=_ble_local_g2))
    337 }
    338 function ble/color/g#compose {
    339   (($1=($2)))
    340   local _ble_local_g2
    341   for _ble_local_g2 in "${@:3}"; do
    342     ble/color/g#append "$1" "$_ble_local_g2"
    343   done
    344 }
    345 function ble/color/g.setfg { ble/color/g#setfg g "$@"; }
    346 function ble/color/g.setbg { ble/color/g#setbg g "$@"; }
    347 function ble/color/g.setfg-clear { ble/color/g#setfg-clear g "$@"; }
    348 function ble/color/g.setbg-clear { ble/color/g#setbg-clear g "$@"; }
    349 function ble/color/g.setfg-index { ble/color/g#setfg-index g "$@"; }
    350 function ble/color/g.setbg-index { ble/color/g#setbg-index g "$@"; }
    351 function ble/color/g.setfg-rgb { ble/color/g#setfg-rgb g "$@"; }
    352 function ble/color/g.setbg-rgb { ble/color/g#setbg-rgb g "$@"; }
    353 function ble/color/g.setfg-cmyk { ble/color/g#setfg-cmyk g "$@"; }
    354 function ble/color/g.setbg-cmyk { ble/color/g#setbg-cmyk g "$@"; }
    355 function ble/color/g.append { ble/color/g#append g "$@"; }
    356 function ble/color/g.compose { ble/color/g#compose g "$@"; }
    357 
    358 function ble/color/g#getfg {
    359   local g=$1
    360   if ((g&_ble_color_gflags_FgIndexed)); then
    361     ((ret=g>>8&0xFF))
    362   elif ((g&_ble_color_gflags_FgMask)); then
    363     ((ret=0x1000000|(g>>8&0xFFFFFF)))
    364   else
    365     ((ret=-1))
    366   fi
    367 }
    368 function ble/color/g#getbg {
    369   local g=$1
    370   if ((g&_ble_color_gflags_BgIndexed)); then
    371     ((ret=g>>32&0xFF))
    372   elif ((g&_ble_color_gflags_BgMask)); then
    373     ((ret=0x1000000|(g>>32&0xFFFFFF)))
    374   else
    375     ((ret=-1))
    376   fi
    377 }
    378 function ble/color/g#compute-fg {
    379   local g=$1
    380   if ((g&_ble_color_gflags_Invisible)); then
    381     ble/color/g#compute-bg "$g"
    382   elif ((g&_ble_color_gflags_Revert)); then
    383     ble/color/g#getbg "$g"
    384   else
    385     ble/color/g#getfg "$g"
    386   fi
    387 }
    388 function ble/color/g#compute-bg {
    389   local g=$1
    390   if ((g&_ble_color_gflags_Revert)); then
    391     ble/color/g#getfg "$g"
    392   else
    393     ble/color/g#getbg "$g"
    394   fi
    395 }
    396 
    397 ## @fn ble/color/gspec2g gspec
    398 ##   @param[in] gspec
    399 ##   @var[out] ret
    400 function ble/color/gspec2g {
    401   local g=0 entry
    402   for entry in ${1//,/ }; do
    403     case $entry in
    404     (bold)      ((g|=_ble_color_gflags_Bold)) ;;
    405     (underline) ((g|=_ble_color_gflags_Underline)) ;;
    406     (blink)     ((g|=_ble_color_gflags_Blink)) ;;
    407     (invis)     ((g|=_ble_color_gflags_Invisible)) ;;
    408     (reverse)   ((g|=_ble_color_gflags_Revert)) ;;
    409     (strike)    ((g|=_ble_color_gflags_Strike)) ;;
    410     (italic)    ((g|=_ble_color_gflags_Italic)) ;;
    411     (standout)  ((g|=_ble_color_gflags_Revert|_ble_color_gflags_Bold)) ;;
    412     (fg=*)
    413       ble/color/.name2color "${entry:3}"
    414       ble/color/g.setfg "$ret" ;;
    415     (bg=*)
    416       ble/color/.name2color "${entry:3}"
    417       ble/color/g.setbg "$ret" ;;
    418     (none)
    419       g=0 ;;
    420     esac
    421   done
    422   ret=$g
    423 }
    424 ## @fn ble/color/g2gspec g
    425 ##   @var[out] ret
    426 function ble/color/g2gspec {
    427   local g=$1 gspec=
    428   if ((g&_ble_color_gflags_FgIndexed)); then
    429     local fg=$((g>>8&0xFF))
    430     ble/color/.color2name "$fg"
    431     gspec=$gspec,fg=$ret
    432   elif ((g&_ble_color_gflags_FgMask)); then
    433     local rgb=$((1<<24|g>>8&0xFFFFFF))
    434     ble/color/.color2name "$rgb"
    435     gspec=$gspec,fg=$ret
    436   fi
    437   if ((g&_ble_color_gflags_BgIndexed)); then
    438     local bg=$((g>>32&0xFF))
    439     ble/color/.color2name "$bg"
    440     gspec=$gspec,bg=$ret
    441   elif ((g&_ble_color_gflags_BgMask)); then
    442     local rgb=$((1<<24|g>>32&0xFFFFFF))
    443     ble/color/.color2name "$rgb"
    444     gspec=$gspec,bg=$ret
    445   fi
    446   ((g&_ble_color_gflags_Bold))      && gspec=$gspec,bold
    447   ((g&_ble_color_gflags_Underline)) && gspec=$gspec,underline
    448   ((g&_ble_color_gflags_Blink))     && gspec=$gspec,blink
    449   ((g&_ble_color_gflags_Invisible)) && gspec=$gspec,invis
    450   ((g&_ble_color_gflags_Revert))    && gspec=$gspec,reverse
    451   ((g&_ble_color_gflags_Strike))    && gspec=$gspec,strike
    452   ((g&_ble_color_gflags_Italic))    && gspec=$gspec,italic
    453   gspec=${gspec#,}
    454   ret=${gspec:-none}
    455 }
    456 
    457 ## @fn ble/color/gspec2sgr gspec
    458 ##   @param[in] gspec
    459 ##   @var[out] ret
    460 function ble/color/gspec2sgr {
    461   local sgr=0 entry
    462 
    463   for entry in ${1//,/ }; do
    464     case $entry in
    465     (bold)      sgr="$sgr;${_ble_term_sgr_bold:-1}" ;;
    466     (underline) sgr="$sgr;${_ble_term_sgr_smul:-4}" ;;
    467     (blink)     sgr="$sgr;${_ble_term_sgr_blink:-5}" ;;
    468     (invis)     sgr="$sgr;${_ble_term_sgr_invis:-8}" ;;
    469     (reverse)   sgr="$sgr;${_ble_term_sgr_rev:-7}" ;;
    470     (strike)    sgr="$sgr;${_ble_term_sgr_strike:-9}" ;;
    471     (italic)    sgr="$sgr;${_ble_term_sgr_sitm:-3}" ;;
    472     (standout)  sgr="$sgr;${_ble_term_sgr_bold:-1};${_ble_term_sgr_rev:-7}" ;;
    473     (fg=*)
    474       ble/color/.name2color "${entry:3}"
    475       ble/color/.color2sgrfg "$ret"
    476       sgr="$sgr;$ret" ;;
    477     (bg=*)
    478       ble/color/.name2color "${entry:3}"
    479       ble/color/.color2sgrbg "$ret"
    480       sgr="$sgr;$ret" ;;
    481     (none)
    482       sgr=0 ;;
    483     esac
    484   done
    485 
    486   ret="[${sgr}m"
    487 }
    488 
    489 function ble/color/.name2color/.clamp {
    490   local text=$1 max=$2
    491   if [[ $text == *% ]]; then
    492     ((ret=10#0${text%'%'}*max/100))
    493   else
    494     ((ret=10#0$text))
    495   fi
    496   ((ret>max)) && ret=max
    497 }
    498 function ble/color/.name2color/.wrap {
    499   local text=$1 max=$2
    500   if [[ $text == *% ]]; then
    501     ((ret=10#0${text%'%'}*max/100))
    502   else
    503     ((ret=10#0$text))
    504   fi
    505   ((ret%=max))
    506 }
    507 function ble/color/.hxx2color {
    508   local H=$1 Min=$2 Range=$3 Unit=$4
    509   local h1 h2 x=$Min y=$Min z=$Min
    510   ((h1=H%120,h2=120-h1,
    511     x+=Range*(h2<60?h2:60)/60,
    512     y+=Range*(h1<60?h1:60)/60))
    513   ((x=x*255/Unit,
    514     y=y*255/Unit,
    515     z=z*255/Unit))
    516   case $((H/120)) in
    517   (0) local R=$x G=$y B=$z ;;
    518   (1) local R=$z G=$x B=$y ;;
    519   (2) local R=$y G=$z B=$x ;;
    520   esac
    521   ((ret=1<<24|R<<16|G<<8|B))
    522 }
    523 function ble/color/.hsl2color {
    524   local H=$1 S=$2 L=$3 Unit=$4
    525   local Range=$((2*(L<=Unit/2?L:Unit-L)*S/Unit))
    526   local Min=$((L-Range/2))
    527   ble/color/.hxx2color "$H" "$Min" "$Range" "$Unit"
    528 }
    529 function ble/color/.hsb2color {
    530   local H=$1 S=$2 B=$3 Unit=$4
    531   local Range=$((B*S/Unit))
    532   local Min=$((B-Range))
    533   ble/color/.hxx2color "$H" "$Min" "$Range" "$Unit"
    534 }
    535 ## @fn ble/color/.name2color colorName
    536 ##   @var[out] ret
    537 function ble/color/.name2color {
    538   local colorName=$1
    539   if [[ ! ${colorName//[0-9]} ]]; then
    540     ((ret=10#0$colorName&255))
    541   elif [[ $colorName == '#'* ]]; then
    542     if local rex='^#[0-9a-fA-F]{3}$'; [[ $colorName =~ $rex ]]; then
    543       let "ret=1<<24|16#${colorName:1:1}*0x11<<16|16#${colorName:2:1}*0x11<<8|16#${colorName:3:1}*0x11"
    544     elif rex='^#[0-9a-fA-F]{6}$'; [[ $colorName =~ $rex ]]; then
    545       let "ret=1<<24|16#${colorName:1:2}<<16|16#${colorName:3:2}<<8|16#${colorName:5:2}"
    546     else
    547       ret=-1
    548     fi
    549   elif [[ $colorName == *:* ]]; then
    550     if local rex='^rgb:([0-9]+%?)/([0-9]+%?)/([0-9]+%?)$'; [[ $colorName =~ $rex ]]; then
    551       ble/color/.name2color/.clamp "${BASH_REMATCH[1]}" 255; local R=$ret
    552       ble/color/.name2color/.clamp "${BASH_REMATCH[2]}" 255; local G=$ret
    553       ble/color/.name2color/.clamp "${BASH_REMATCH[3]}" 255; local B=$ret
    554       ((ret=1<<24|R<<16|G<<8|B))
    555     elif
    556       local rex1='^cmy:([0-9]+%?)/([0-9]+%?)/([0-9]+%?)$'
    557       local rex2='^cmyk:([0-9]+%?)/([0-9]+%?)/([0-9]+%?)/([0-9]+%?)$'
    558       [[ $colorName =~ $rex1 || $colorName =~ $rex2 ]]
    559     then
    560       ble/color/.name2color/.clamp "${BASH_REMATCH[1]}" 255; local C=$ret
    561       ble/color/.name2color/.clamp "${BASH_REMATCH[2]}" 255; local M=$ret
    562       ble/color/.name2color/.clamp "${BASH_REMATCH[3]}" 255; local Y=$ret
    563       ble/color/.name2color/.clamp "${BASH_REMATCH[4]:-0}" 255; local K=$ret
    564       local K=$((~K&0xFF))
    565       local R=$(((~C&0xFF)*K/255))
    566       local G=$(((~M&0xFF)*K/255))
    567       local B=$(((~Y&0xFF)*K/255))
    568       ((ret=1<<24|R<<16|G<<8|B))
    569     elif rex='^hs[lvb]:([0-9]+)/([0-9]+%)/([0-9]+%)$'; [[ $colorName =~ $rex ]]; then
    570       ble/color/.name2color/.wrap  "${BASH_REMATCH[1]}" 360; local H=$ret
    571       ble/color/.name2color/.clamp "${BASH_REMATCH[2]}" 1000; local S=$ret
    572       ble/color/.name2color/.clamp "${BASH_REMATCH[3]}" 1000; local X=$ret
    573       if [[ $colorName == hsl:* ]]; then
    574         ble/color/.hsl2color "$H" "$S" "$X" 1000
    575       else
    576         ble/color/.hsb2color "$H" "$S" "$X" 1000
    577       fi
    578     else
    579       ret=-1
    580     fi
    581   else
    582     case $colorName in
    583     (black)   ret=0 ;;
    584     (brown)   ret=1 ;;
    585     (green)   ret=2 ;;
    586     (olive)   ret=3 ;;
    587     (navy)    ret=4 ;;
    588     (purple)  ret=5 ;;
    589     (teal)    ret=6 ;;
    590     (silver)  ret=7 ;;
    591 
    592     (gr[ae]y) ret=8 ;;
    593     (red)     ret=9 ;;
    594     (lime)    ret=10 ;;
    595     (yellow)  ret=11 ;;
    596     (blue)    ret=12 ;;
    597     (magenta) ret=13 ;;
    598     (cyan)    ret=14 ;;
    599     (white)   ret=15 ;;
    600 
    601     (orange)  ret=202 ;;
    602     (transparent|default) ret=-1 ;;
    603     (*)       ret=-1 ;;
    604     esac
    605   fi
    606 }
    607 function ble/color/.color2name {
    608   if (($1>=0x1000000)); then
    609     ble/util/sprintf ret '#%06x' "$(($1&0xFFFFFF))"
    610     return 0
    611   fi
    612 
    613   ((ret=(10#0$1&255)))
    614   case $ret in
    615   (0)  ret=black   ;;
    616   (1)  ret=brown   ;;
    617   (2)  ret=green   ;;
    618   (3)  ret=olive   ;;
    619   (4)  ret=navy    ;;
    620   (5)  ret=purple  ;;
    621   (6)  ret=teal    ;;
    622   (7)  ret=silver  ;;
    623   (8)  ret=gray    ;;
    624   (9)  ret=red     ;;
    625   (10) ret=lime    ;;
    626   (11) ret=yellow  ;;
    627   (12) ret=blue    ;;
    628   (13) ret=magenta ;;
    629   (14) ret=cyan    ;;
    630   (15) ret=white   ;;
    631   (202) ret=orange ;;
    632   esac
    633 }
    634 
    635 ## @fn ble/color/convert-color88-to-color256 color
    636 ##   @param[in] color
    637 ##   @var[out] ret
    638 function ble/color/convert-color88-to-color256 {
    639   local color=$1
    640   if ((color>=16)); then
    641     if ((color>=80)); then
    642       local L=$((((color-80+1)*25+4)/9))
    643       ((color=L==0?16:(L==25?231:232+(L-1))))
    644     else
    645       ((color-=16))
    646       local R=$((color/16)) G=$((color/4%4)) B=$((color%4))
    647       ((R=(R*5+1)/3,G=(G*5+1)/3,B=(B*5+1)/3,
    648         color=16+R*36+G*6+B))
    649     fi
    650   fi
    651   ret=$color
    652 }
    653 ## @fn ble/color/convert-color256-to-color88 color
    654 ##   @param[in] color
    655 ##   @var[out] ret
    656 function ble/color/convert-color256-to-color88 {
    657   local color=$1
    658   if ((color>=16)); then
    659     if ((color>=232)); then
    660       local L=$((((color-232+1)*9+12)/25))
    661       ((color=L==0?16:(L==9?79:80+(L-1))))
    662     else
    663       ((color-=16))
    664       local R=$((color/36)) G=$((color/6%6)) B=$((color%6))
    665       ((R=(R*3+2)/5,G=(G*3+2)/5,B=(B*3+2)/5,
    666         color=16+R*16+G*4+B))
    667     fi
    668   fi
    669   ret=$color
    670 }
    671 ## @fn ble/color/convert-rgb24-to-color256 R G B
    672 ##   @param[in] R G B
    673 ##     0..255 の階調値
    674 ##   @var[out] ret
    675 function ble/color/convert-rgb24-to-color256 {
    676   local R=$1 G=$2 B=$3
    677   if ((R==G&&G==B)); then
    678     # xterm 24 grayscale: 10k+8 (0..238)
    679     if ((R<=3)); then
    680       # 6x6x6 cube (0,0,0)
    681       ret=16
    682     elif ((R>=247)); then
    683       # 6x6x6 cube (5,5,5)
    684       ret=231
    685     elif ((R>=92&&(R-92)%40<5)); then
    686       # 6x6x6 cube (1,1,1)-(4,4,4)
    687       ((ret=59+43*(R-92)/40))
    688     else
    689       local level=$(((R-3)/10))
    690       ((ret=232+(level<=23?level:23)))
    691     fi
    692   else
    693     # xterm 6x6x6 cube: k?55+40k:0
    694     ((R=R<=47?0:(R<=95?1:(R-35)/40)))
    695     ((G=G<=47?0:(G<=95?1:(G-35)/40)))
    696     ((B=B<=47?0:(B<=95?1:(B-35)/40)))
    697     ((ret=16+36*R+6*G+B))
    698   fi
    699 }
    700 ## @fn ble/color/convert-rgb24-to-color88 R G B
    701 ##   @param[in] R G B
    702 ##     0..255 の階調値
    703 ##   @var[out] ret
    704 function ble/color/convert-rgb24-to-color88 {
    705   local R=$1 G=$2 B=$3
    706   if ((R==G&&G==B)); then
    707     # xterm 8 grayscale: 46+25k = 46,71,96,121,146,171,196,221
    708     if ((R<=22)); then
    709       ret=16 # 4x4x4 cube (0,0,0)=0:0:0
    710     elif ((R>=239)); then
    711       ret=79 # 4x4x4 cube (3,3,3)=255:255:255
    712     elif ((131<=R&&R<=142)); then
    713       ret=37 # 4x4x4 cube (1,1,1)=139:139:139
    714     elif ((197<=R&&R<=208)); then
    715       ret=58 # 4x4x4 cube (2,2,2)=197:197:197
    716     else
    717       local level=$(((R-34)/25))
    718       ((ret=80+(level<=7?level:7)))
    719     fi
    720   else
    721     # xterm 4x4x4 cube: (k?81+58k:0) = 0,139,197,255
    722     ((R=R<=69?0:(R<=168?1:(R-52)/58)))
    723     ((G=G<=69?0:(G<=168?1:(G-52)/58)))
    724     ((B=B<=69?0:(B<=168?1:(B-52)/58)))
    725     ((ret=16+16*R+4*G+B))
    726   fi
    727 }
    728 
    729 _ble_color_color2sgr_filter=
    730 ## @fn ble/color/.color2sgrfg color
    731 ## @fn ble/color/.color2sgrbg color
    732 ##   @param[in] color
    733 ##     0-255 の値は index color を表します。
    734 ##     1XXXXXX の値は 24bit color を表します。
    735 ##   @var[out] ret
    736 function ble/color/.color2sgr-impl {
    737   local ccode=$1 prefix=$2 # 3 for fg, 4 for bg
    738   builtin eval -- "$_ble_color_color2sgr_filter"
    739   if ((ccode<0)); then
    740     ret=${prefix}9
    741   elif ((ccode<16&&ccode<_ble_term_colors)); then
    742     if ((prefix==4)); then
    743       ret=${_ble_term_sgr_ab[ccode]}
    744     else
    745       ret=${_ble_term_sgr_af[ccode]}
    746     fi
    747   elif ((ccode<256)); then
    748     local index_colors=$_ble_color_index_colors_default
    749     [[ $bleopt_term_index_colors == auto ]] || ((index_colors=bleopt_term_index_colors))
    750     if ((index_colors>=256)); then
    751       ret="${prefix}8;5;$ccode"
    752     elif ((index_colors>=88)); then
    753       ble/color/convert-color256-to-color88 "$ccode"
    754       ret="${prefix}8;5;$ret"
    755     elif ((ccode<index_colors)); then
    756       ret="${prefix}8;5;$ccode"
    757     elif ((_ble_term_colors>=16||_ble_term_colors==8)); then
    758       if ((ccode>=16)); then
    759         if ((ccode>=232)); then
    760           local L=$((((ccode-232+1)*3+12)/25))
    761           ((ccode=L==0?0:(L==1?8:(L==2?7:15))))
    762         else
    763           ((ccode-=16))
    764           local R=$((ccode/36)) G=$((ccode/6%6)) B=$((ccode%6))
    765           if ((R==G&&G==B)); then
    766             local L=$(((R*3+2)/5))
    767             ((ccode=L==0?0:(L==1?8:(L==2?7:15))))
    768           else
    769             local min max
    770             ((R<G?(min=R,max=G):(min=G,max=R),
    771               B<min?(min=B):(B>max&&(max=B))))
    772             local Range=$((max-min))
    773             ((R=(R-min+Range/2)/Range,
    774               G=(G-min+Range/2)/Range,
    775               B=(B-min+Range/2)/Range,
    776               ccode=R+G*2+B*4+(min+max>=5?8:0)))
    777           fi
    778         fi
    779       fi
    780       ((_ble_term_colors==8&&ccode>=8&&(ccode-=8)))
    781 
    782       if ((prefix==4)); then
    783         ret=${_ble_term_sgr_ab[ccode]}
    784       else
    785         ret=${_ble_term_sgr_af[ccode]}
    786       fi
    787     else
    788       ret=${prefix}9
    789     fi
    790   elif ((0x1000000<=ccode&&ccode<0x2000000)); then
    791     # 24bit True Colors
    792     local R=$((ccode>>16&0xFF)) G=$((ccode>>8&0xFF)) B=$((ccode&0xFF))
    793     if [[ $bleopt_term_true_colors == semicolon ]]; then
    794       ret="${prefix}8;2;$R;$G;$B"
    795     elif [[ $bleopt_term_true_colors == colon ]]; then
    796       ret="${prefix}8:2::$R:$G:$B"
    797     else
    798       local index_colors=$_ble_color_index_colors_default
    799       [[ $bleopt_term_index_colors == auto ]] || ((index_colors=bleopt_term_index_colors))
    800       local index=
    801       if ((index_colors>=256)); then
    802         ble/color/convert-rgb24-to-color256 "$R" "$G" "$B"
    803         index=$ret
    804       elif ((index_colors>=88)); then
    805         ble/color/convert-rgb24-to-color88 "$R" "$G" "$B"
    806         index=$ret
    807       else
    808         ble/color/convert-rgb24-to-color256 "$R" "$G" "$B"
    809         if ((ret<index_colors)); then
    810           index=$ret
    811         else
    812           ble/color/.color2sgr-impl "$ret" "$prefix"
    813         fi
    814       fi
    815       [[ $index ]] && ret="${prefix}8;5;$index"
    816     fi
    817   else
    818     ret=${prefix}9
    819   fi
    820 }
    821 
    822 ## @fn ble/color/.color2sgrfg color_code
    823 ##   @var[out] ret
    824 function ble/color/.color2sgrfg {
    825   ble/color/.color2sgr-impl "$1" 3
    826 }
    827 ## @fn ble/color/.color2sgrbg color_code
    828 ##   @var[out] ret
    829 function ble/color/.color2sgrbg {
    830   ble/color/.color2sgr-impl "$1" 4
    831 }
    832 
    833 #------------------------------------------------------------------------------
    834 
    835 ## @fn ble/color/read-sgrspec/.arg-next
    836 ##   @var[in    ] fields
    837 ##   @var[in,out] j
    838 ##   @var[   out] arg
    839 function ble/color/read-sgrspec/.arg-next {
    840   local _ble_local_var=arg _ble_local_ret
    841   if [[ $1 == -v ]]; then
    842     _ble_local_var=$2
    843     shift 2
    844   fi
    845 
    846   if ((j<${#fields[*]})); then
    847     ((_ble_local_ret=10#0${fields[j++]}))
    848   else
    849     ((i++))
    850     ((_ble_local_ret=10#0${specs[i]%%:*}))
    851   fi
    852 
    853   (($_ble_local_var=_ble_local_ret))
    854 }
    855 
    856 ## @fn ble-color/read-sgrspec sgrspec opts
    857 ##   @param[in] sgrspec
    858 ##   @var[in,out] g
    859 function ble/color/read-sgrspec {
    860   local specs i iN
    861   ble/string#split specs \; "$1"
    862   for ((i=0,iN=${#specs[@]};i<iN;i++)); do
    863     local spec=${specs[i]} fields
    864     ble/string#split fields : "$spec"
    865     local arg=$((10#0${fields[0]}))
    866     if ((arg==0)); then
    867       g=0
    868       continue
    869     elif [[ :$opts: != *:ansi:* ]]; then
    870       [[ ${_ble_term_sgr_term2ansi[arg]} ]] &&
    871         arg=${_ble_term_sgr_term2ansi[arg]}
    872     fi
    873 
    874     if ((30<=arg&&arg<50)); then
    875       # colors
    876       if ((30<=arg&&arg<38)); then
    877         local color=$((arg-30))
    878         ble/color/g.setfg-index "$color"
    879       elif ((40<=arg&&arg<48)); then
    880         local color=$((arg-40))
    881         ble/color/g.setbg-index "$color"
    882       elif ((arg==38)); then
    883         local j=1 color cspace
    884         ble/color/read-sgrspec/.arg-next -v cspace
    885         if ((cspace==5)); then
    886           ble/color/read-sgrspec/.arg-next -v color
    887           if [[ :$opts: != *:ansi:* ]] && ((bleopt_term_index_colors==88)); then
    888             local ret; ble/color/convert-color88-to-color256 "$color"; color=$ret
    889           fi
    890           ble/color/g.setfg-index "$color"
    891         elif ((cspace==2)); then
    892           local S R G B
    893           ((${#fields[@]}>5)) &&
    894             ble/color/read-sgrspec/.arg-next -v S
    895           ble/color/read-sgrspec/.arg-next -v R
    896           ble/color/read-sgrspec/.arg-next -v G
    897           ble/color/read-sgrspec/.arg-next -v B
    898           ble/color/g.setfg-rgb "$R" "$G" "$B"
    899         elif ((cspace==3||cspace==4)); then
    900           local S C M Y K=0
    901           ((${#fields[@]}>2+cspace)) &&
    902             ble/color/read-sgrspec/.arg-next -v S
    903           ble/color/read-sgrspec/.arg-next -v C
    904           ble/color/read-sgrspec/.arg-next -v M
    905           ble/color/read-sgrspec/.arg-next -v Y
    906           ((cspace==4)) &&
    907             ble/color/read-sgrspec/.arg-next -v K
    908           ble/color/g.setfg-cmyk "$C" "$M" "$Y" "$K"
    909         else
    910           ble/color/g.setfg-clear
    911         fi
    912       elif ((arg==48)); then
    913         local j=1 color cspace
    914         ble/color/read-sgrspec/.arg-next -v cspace
    915         if ((cspace==5)); then
    916           ble/color/read-sgrspec/.arg-next -v color
    917           if [[ :$opts: != *:ansi:* ]] && ((bleopt_term_index_colors==88)); then
    918             local ret; ble/color/convert-color88-to-color256 "$color"; color=$ret
    919           fi
    920           ble/color/g.setbg-index "$color"
    921         elif ((cspace==2)); then
    922           local S R G B
    923           ((${#fields[@]}>5)) &&
    924             ble/color/read-sgrspec/.arg-next -v S
    925           ble/color/read-sgrspec/.arg-next -v R
    926           ble/color/read-sgrspec/.arg-next -v G
    927           ble/color/read-sgrspec/.arg-next -v B
    928           ble/color/g.setbg-rgb "$R" "$G" "$B"
    929         elif ((cspace==3||cspace==4)); then
    930           local S C M Y K=0
    931           ((${#fields[@]}>2+cspace)) &&
    932             ble/color/read-sgrspec/.arg-next -v S
    933           ble/color/read-sgrspec/.arg-next -v C
    934           ble/color/read-sgrspec/.arg-next -v M
    935           ble/color/read-sgrspec/.arg-next -v Y
    936           ((cspace==4)) &&
    937             ble/color/read-sgrspec/.arg-next -v K
    938           ble/color/g.setbg-cmyk "$C" "$M" "$Y" "$K"
    939         else
    940           ble/color/g.setbg-clear
    941         fi
    942       elif ((arg==39)); then
    943         ble/color/g.setfg-clear
    944       elif ((arg==49)); then
    945         ble/color/g.setbg-clear
    946       fi
    947     elif ((90<=arg&&arg<98)); then
    948       local color=$((arg-90+8))
    949       ble/color/g.setfg-index "$color"
    950     elif ((100<=arg&&arg<108)); then
    951       local color=$((arg-100+8))
    952       ble/color/g.setbg-index "$color"
    953     else
    954       case $arg in
    955       (1)    ((g|=_ble_color_gflags_Bold))       ;;
    956       (22)   ((g&=~_ble_color_gflags_Bold))      ;;
    957       (4)    ((g|=_ble_color_gflags_Underline))  ;;
    958       (24)   ((g&=~_ble_color_gflags_Underline)) ;;
    959       (7)    ((g|=_ble_color_gflags_Revert))     ;;
    960       (27)   ((g&=~_ble_color_gflags_Revert))    ;;
    961       (9807) ((g^=_ble_color_gflags_Revert))     ;; # toggle (for internal use)
    962       (3)    ((g|=_ble_color_gflags_Italic))     ;;
    963       (23)   ((g&=~_ble_color_gflags_Italic))    ;;
    964       (5)    ((g|=_ble_color_gflags_Blink))      ;;
    965       (25)   ((g&=~_ble_color_gflags_Blink))     ;;
    966       (8)    ((g|=_ble_color_gflags_Invisible))  ;;
    967       (28)   ((g&=~_ble_color_gflags_Invisible)) ;;
    968       (9)    ((g|=_ble_color_gflags_Strike))     ;;
    969       (29)   ((g&=~_ble_color_gflags_Strike))    ;;
    970       esac
    971     fi
    972   done
    973 }
    974 
    975 ## @fn ble/color/sgrspec2g str
    976 ##   SGRに対する引数から描画属性を構築します。
    977 ##   @var[out] ret
    978 function ble/color/sgrspec2g {
    979   local g=0
    980   ble/color/read-sgrspec "$1"
    981   ret=$g
    982 }
    983 
    984 ## @fn ble/color/ansi2g str
    985 ##   ANSI制御シーケンスから描画属性を構築します。
    986 ##   Note: canvas.sh を読み込んで以降でないと使えません。
    987 ##   @var[out] ret
    988 function ble/color/ansi2g {
    989   local x=0 y=0 g=0
    990   ble/function#try ble/canvas/trace "$1" # -> ret
    991   ret=$g
    992 }
    993 
    994 #------------------------------------------------------------------------------
    995 # _ble_faces
    996 
    997 # 遅延初期化登録
    998 # @hook color_defface_load (defined in src/def.sh)
    999 # @hook color_setface_load (defined in src/def.sh)
   1000 
   1001 # 遅延初期化
   1002 if [[ ! ${_ble_faces_count-} ]]; then # reload #D0875
   1003   _ble_faces_count=0
   1004   _ble_faces=()
   1005 fi
   1006 
   1007 ## @fn ble/color/setface/.check-argument
   1008 ##   @var[out] ext
   1009 function ble/color/setface/.check-argument {
   1010   local rex='^[_a-zA-Z0-9]+$'
   1011   [[ $# == 2 && $1 =~ $rex && $2 ]] && return 0
   1012 
   1013   local flags=a
   1014   while (($#)); do
   1015     local arg=$1; shift
   1016     case $arg in
   1017     (--help) flags=H$flags ;;
   1018     (--color|--color=always) flags=c${flags//[ac]} ;;
   1019     (--color=auto) flags=a${flags//[ac]} ;;
   1020     (--color=never) flags=${flags//[ac]} ;;
   1021     (-*)
   1022       ble/util/print "${FUNCNAME[1]}: unrecognized option '$arg'." >&2
   1023       flags=E$flags ;;
   1024     (*)
   1025       ble/util/print "${FUNCNAME[1]}: unrecognized argument '$arg'." >&2
   1026       flags=E$flags ;;
   1027     esac
   1028   done
   1029 
   1030   if [[ $flags == *E* ]]; then
   1031     ext=2; return 1
   1032   elif [[ $flags == *H* ]]; then
   1033     ble/util/print-lines \
   1034       "usage: $name FACE_NAME [TYPE:]SPEC" \
   1035       '    Set face.' \
   1036       '' \
   1037       '  TYPE      Specifies the format of SPEC. The following values are available.' \
   1038       '    gspec   Comma separated graphic attribute list' \
   1039       '    g       Integer value' \
   1040       '    ref     Face name or id (reference)' \
   1041       '    copy    Face name or id (copy value)' \
   1042       '    sgrspec Parameters to the control function SGR' \
   1043       '    ansi    ANSI Sequences' >&2
   1044     ext=0; return 1
   1045   fi
   1046 
   1047   local opts=
   1048   [[ $flags == *c* || $flags == *a* && -t 1 ]] && opts=$opts:color
   1049   ble/color/list-faces "$opts"; ext=$?; return 1
   1050 }
   1051 function ble-color-defface {
   1052   local ext; ble/color/setface/.check-argument "$@" || return "$ext"
   1053   ble/color/defface "$@"
   1054 }
   1055 function ble-color-setface {
   1056   local ext; ble/color/setface/.check-argument "$@" || return "$ext"
   1057   ble/color/setface "$@"
   1058 }
   1059 
   1060 # 遅延関数 (後で上書き)
   1061 function ble/color/defface   { local q=\' Q="'\''"; blehook color_defface_load+="ble/color/defface '${1//$q/$Q}' '${2//$q/$Q}'"; }
   1062 function ble/color/setface   { local q=\' Q="'\''"; blehook color_setface_load+="ble/color/setface '${1//$q/$Q}' '${2//$q/$Q}'"; }
   1063 function ble/color/face2g    { ble/color/initialize-faces && ble/color/face2g    "$@"; }
   1064 function ble/color/face2sgr  { ble/color/initialize-faces && ble/color/face2sgr  "$@"; }
   1065 function ble/color/iface2g   { ble/color/initialize-faces && ble/color/iface2g   "$@"; }
   1066 function ble/color/iface2sgr { ble/color/initialize-faces && ble/color/iface2sgr "$@"; }
   1067 function ble/color/spec2g    { ble/color/initialize-faces && ble/color/spec2g    "$@"; }
   1068 
   1069 function ble/color/face2sgr-ansi { ble/color/initialize-faces && ble/color/face2sgr  "$@"; }
   1070 
   1071 # 遅延初期化子
   1072 _ble_color_faces_initialized=
   1073 function ble/color/initialize-faces {
   1074   local _ble_color_faces_initializing=1
   1075   local -a _ble_color_faces_errors=()
   1076 
   1077   ## @fn ble/color/face2g face
   1078   ##   @var[out] ret
   1079   function ble/color/face2g {
   1080     ((ret=_ble_faces[_ble_faces__$1]))
   1081   }
   1082   ## @fn ble/color/face2sgr face
   1083   ##   @var[out] ret
   1084   function ble/color/face2sgr { ble/color/g2sgr "$((_ble_faces[_ble_faces__$1]))"; }
   1085   function ble/color/face2sgr-ansi { ble/color/g2sgr-ansi "$((_ble_faces[_ble_faces__$1]))"; }
   1086   ## @fn ble/color/iface2g iface
   1087   ##   @var[out] ret
   1088   function ble/color/iface2g {
   1089     ((ret=_ble_faces[$1]))
   1090   }
   1091   ## @fn ble/color/iface2sgr iface
   1092   ##   @var[out] ret
   1093   function ble/color/iface2sgr {
   1094     ble/color/g2sgr "$((_ble_faces[$1]))"
   1095   }
   1096   ## @fn ble/color/spec2g [TYPE:]SPEC
   1097   function ble/color/spec2g {
   1098     ble/color/setface/.spec2gexpr "$@" prefix-face
   1099     ((ret=ret))
   1100   }
   1101 
   1102   ## @fn ble/color/setface/.spec2gexpr spec
   1103   ##   @var[out] ret
   1104   function ble/color/setface/.spec2gexpr {
   1105     local spec=$1 value=${1#*:} opts=$2
   1106     case $spec in
   1107     (gspec:*)   ble/color/gspec2g "$value" ;;
   1108     (g:*)       ret=$(($value)) ;;
   1109     (ref:*)
   1110       if [[ ! ${value//[0-9]} ]]; then
   1111         ret=_ble_faces[$((value))]
   1112       else
   1113         ret=_ble_faces[_ble_faces__$value]
   1114       fi ;;
   1115     (copy:*|face:*|iface:*)
   1116       # `face:*' and `iface:*' are obsoleted forms.
   1117       [[ $spec == copy:* || $spec == face:* && :$opts: == *:prefix-face:* ]] ||
   1118         ble/util/print "ble-face: \"${spec%%:*}:*\" is obsoleted. Use \"copy:*\" instead." >&2
   1119       if [[ ! ${value//[0-9]} ]]; then
   1120         ble/color/iface2g "$value"
   1121       else
   1122         ble/color/face2g "$value"
   1123       fi ;;
   1124     (sgrspec:*) ble/color/sgrspec2g "$value" ;;
   1125     (ansi:*)    ble/color/ansi2g "$value" ;;
   1126     (*)         ble/color/gspec2g "$spec" ;;
   1127     esac
   1128   }
   1129 
   1130   function ble/color/defface {
   1131     local name=_ble_faces__$1 spec=$2 ret
   1132     (($name)) && return 0
   1133     (($name=++_ble_faces_count))
   1134     ble/color/setface/.spec2gexpr "$spec"
   1135     _ble_faces[$name]=$ret
   1136     _ble_faces_def[$name]=$ret
   1137   }
   1138   function ble/color/setface {
   1139     local name=_ble_faces__$1 spec=$2 ret
   1140     if [[ ${!name} ]]; then
   1141       ble/color/setface/.spec2gexpr "$spec"; _ble_faces[$name]=$ret
   1142     else
   1143       local message="ble.sh: the specified face \`$1' is not defined."
   1144       if [[ $_ble_color_faces_initializing ]]; then
   1145         ble/array#push _ble_color_faces_errors "$message"
   1146       else
   1147         ble/util/print "$message" >&2
   1148       fi
   1149       return 1
   1150     fi
   1151   }
   1152 
   1153   _ble_color_faces_initialized=1
   1154   blehook/invoke color_defface_load
   1155   blehook/invoke color_setface_load
   1156   blehook color_defface_load=
   1157   blehook color_setface_load=
   1158 
   1159   if ((${#_ble_color_faces_errors[@]})); then
   1160     if ((_ble_edit_attached)) && [[ ! $_ble_textarea_invalidated && $_ble_term_state == internal ]]; then
   1161       IFS=$'\n' builtin eval 'local message="${_ble_color_faces_errors[*]}"'
   1162       ble/widget/print "$message"
   1163     else
   1164       printf '%s\n' "${_ble_color_faces_errors[@]}" >&2
   1165     fi
   1166     return 1
   1167   else
   1168     return 0
   1169   fi
   1170 }
   1171 ble/function#try ble/util/idle.push ble/color/initialize-faces
   1172 
   1173 ## @fn ble/color/list-faces opts
   1174 function ble/color/list-faces {
   1175   local flags=
   1176   [[ :$1: == *:color:* ]] && flags=c
   1177 
   1178   local ret sgr0= sgr1= sgr2=
   1179   if [[ $flags == *c* ]]; then
   1180     sgr0=$_ble_term_sgr0
   1181     ble/color/face2sgr command_function; sgr1=$ret
   1182     ble/color/face2sgr syntax_varname; sgr2=$ret
   1183   fi
   1184 
   1185   local key
   1186   for key in "${!_ble_faces__@}"; do
   1187     ble-face/.print-face "$key"
   1188   done
   1189 }
   1190 
   1191 function ble-face/.read-arguments/process-set {
   1192   local o=$1 face=$2 value=$3
   1193   if local rex='^[_a-zA-Z0-9@][_a-zA-Z0-9@]*$'; ! [[ $face =~ $rex ]]; then
   1194     ble/util/print "ble-face: invalid face name '$face'." >&2
   1195     flags=E$flags
   1196     return 1
   1197   elif [[ $o == '-d' && $face == *@* ]]; then
   1198     ble/util/print "ble-face: wildcards cannot be used in the face name '$face' for definition." >&2
   1199     flags=E$flags
   1200     return 1
   1201   fi
   1202 
   1203   local assign='='
   1204   [[ $o == -d ]] && assign=':='
   1205   ble/array#push setface "$face$assign$value"
   1206 }
   1207 
   1208 ## @fn ble-face/.read-arguments args...
   1209 ##   @var[out] flags
   1210 ##     H = help
   1211 ##     E = error
   1212 ##     L = literal
   1213 ##     c = color
   1214 ##     r = reset
   1215 ##     u = changed
   1216 function ble-face/.read-arguments {
   1217   flags= setface=() print=()
   1218   local opt_color=auto
   1219   local args iarg narg=$#; args=("$@")
   1220   for ((iarg=0;iarg<narg;)); do
   1221     local arg=${args[iarg++]}
   1222     if [[ $arg == -* ]]; then
   1223       if [[ $flags == *L* ]]; then
   1224         ble/util/print "ble-face: unrecognized argument '$arg'." >&2
   1225         flags=E$flags
   1226       else
   1227         case $arg in
   1228         (--help) flags=H$flags ;;
   1229         (--color)
   1230           opt_color=always ;;
   1231         (--color=always|--color=auto|--color=never)
   1232           opt_color=${arg#*=} ;;
   1233         (--color=*)
   1234           ble/util/print "ble-face: '${arg#*=}': unrecognized option argument for '--color'." >&2
   1235           flags=E$flags ;;
   1236         (--reset) flags=r$flags ;;
   1237         (--changed) flags=u$flags ;;
   1238         (--) flags=L$flags ;;
   1239         (--*)
   1240           ble/util/print "ble-face: unrecognized long option '$arg'." >&2
   1241           flags=E$flags ;;
   1242         (-?*)
   1243           local i c
   1244           for ((i=1;i<${#arg};i++)); do
   1245             c=${arg:i:1}
   1246             case $c in
   1247             ([ru]) flags=$c$flags ;;
   1248             ([sd])
   1249               if ((i+1<${#arg})); then
   1250                 local lhs=${arg:i+1}
   1251               else
   1252                 local lhs=${args[iarg++]}
   1253               fi
   1254               local rhs=${args[iarg++]}
   1255               if ((iarg>narg)); then
   1256                 ble/util/print "ble-face: missing option argument for '-$c FACE SPEC'." >&2
   1257                 flags=E$flags
   1258                 continue
   1259               fi
   1260               ble-face/.read-arguments/process-set "${arg::2}" "$lhs" "$rhs"
   1261               break ;;
   1262             (*)
   1263               ble/util/print "ble-face: unrecognized option '-$c'." >&2
   1264               flags=E$flags ;;
   1265             esac
   1266           done ;;
   1267         (-)
   1268           ble/util/print "ble-face: unrecognized argument '$arg'." >&2
   1269           flags=E$flags ;;
   1270         esac
   1271       fi
   1272 
   1273     elif [[ $arg == *=* ]]; then
   1274       if local rex='^[_a-zA-Z@][_a-zA-Z0-9@]*:?='; [[ $arg =~ $rex ]]; then
   1275         ble/array#push setface "$arg"
   1276       else
   1277         local lhs=${arg%%=*}; lhs=${lhs%:}
   1278         ble/util/print "ble-face: invalid left-hand side '$lhs' ($arg)." >&2
   1279         flags=E$flags
   1280       fi
   1281 
   1282     else
   1283       if local rex='^[_a-zA-Z@][_a-zA-Z0-9@]*$'; [[ $arg =~ $rex ]]; then
   1284         ble/array#push print "$arg"
   1285       else
   1286         ble/util/print "ble-face: unrecognized form of argument '$arg'." >&2
   1287         flags=E$flags
   1288       fi
   1289     fi
   1290   done
   1291 
   1292   [[ $opt_color == auto && -t 1 || $opt_color == always ]] && flags=c$flags
   1293   [[ $flags != *E* ]]
   1294 }
   1295 function ble-face/.print-help {
   1296   ble/util/print-lines >&2 \
   1297     'ble-face --help' \
   1298     'ble-face [FACEPAT[:=|=][TYPE:]SPEC | -[sd] FACEPAT [TYPE:]SPEC]]...' \
   1299     'ble-face [-ur|--color[=WHEN]] [FACE...]' \
   1300     '' \
   1301     '  OPTIONS/ARGUMENTS' \
   1302     '' \
   1303     '    FACEPAT=[TYPE:]SPEC' \
   1304     '    -s FACEPAT [TYPE:]SPEC' \
   1305     '            Set a face.  FACEPAT can include a wildcard @ which matches one or' \
   1306     '            more characters.' \
   1307     '' \
   1308     '    FACE:=[TYPE:]SPEC' \
   1309     '    -d FACE [TYPE:]SPEC' \
   1310     '            Define a face' \
   1311     '' \
   1312     '    [-u | --color[=always|never|auto]]... FACEPAT...' \
   1313     '            Print faces.  If faces are not specified, all faces are selected.' \
   1314     '            If -u is specified, only the faces with different values from their' \
   1315     '            default will be printed.  The option "--color" controls the output' \
   1316     '            color settings.  The default is "auto".' \
   1317     '' \
   1318     '    -r FACEPAT...' \
   1319     '            Reset faces.  If faces are not specified, all faces are selected.' \
   1320     '' \
   1321     '  FACEPAT   Specifies a face name.  The character @ in the face name is treated' \
   1322     '            as a wildcard.' \
   1323     '' \
   1324     '  FACE      Specifies a face name.  Wildcard @ cannot be used.' \
   1325     '' \
   1326     '  TYPE      Specifies the format of SPEC. The following values are available.' \
   1327     '    gspec   Comma separated graphic attribute list' \
   1328     '    g       Integer value' \
   1329     '    ref     Face name or id (reference)' \
   1330     '    copy    Face name or id (copy value)' \
   1331     '    sgrspec Parameters to the control function SGR' \
   1332     '    ansi    ANSI Sequences' \
   1333     ''
   1334   return 0
   1335 }
   1336 ## @fn ble/color/.print-face key
   1337 ##   @param[in] key
   1338 ##   @var[in] flags sgr0 sgr1 sgr2
   1339 function ble-face/.print-face {
   1340   local key=$1 ret
   1341   local name=${key#_ble_faces__}
   1342   local cur=${_ble_faces[key]}
   1343   if [[ $flags == *u* ]]; then
   1344     local def=_ble_faces_def[key]
   1345     [[ ${!def+set} && $cur == "${!def}" ]] && return 0
   1346   fi
   1347   local def=${_ble_faces[key]}
   1348   if [[ $cur == '_ble_faces['*']' ]]; then
   1349     cur=${cur#'_ble_faces['}
   1350     cur=${cur%']'}
   1351     cur=ref:${cur#_ble_faces__}
   1352   else
   1353     ble/color/g2gspec "$((cur))"; cur=$ret
   1354   fi
   1355   if [[ $flags == *c* ]]; then
   1356     ble/color/iface2sgr "$((key))"
   1357     cur=$ret$cur$_ble_term_sgr0
   1358   fi
   1359   printf '%s %s=%s\n' "${sgr1}ble-face$sgr0" "$sgr2$name$sgr0" "$cur"
   1360 }
   1361 ## @fn ble/color/.print-face key
   1362 ##   @param[in] key
   1363 ##   @var[in] flags sgr0 sgr1 sgr2
   1364 function ble-face/.reset-face {
   1365   local key=$1 ret
   1366   [[ ${_ble_faces_def[key]+set} ]] &&
   1367     _ble_faces[key]=${_ble_faces_def[key]}
   1368 }
   1369 function ble-face {
   1370   local flags setface print
   1371   ble-face/.read-arguments "$@"
   1372   if [[ $flags == *H* ]]; then
   1373     ble-face/.print-help
   1374     return 2
   1375   elif [[ $flags == *E* ]]; then
   1376     return 2
   1377   fi
   1378 
   1379   if ((!${#print[@]}&&!${#setface[@]})); then
   1380     print=(@)
   1381   fi
   1382 
   1383   ((${#print[@]})) && ble/color/initialize-faces
   1384   if [[ ! $_ble_color_faces_initialized ]]; then
   1385     local ret
   1386     ble/string#quote-command ble-face "${setface[@]}"
   1387     blehook color_setface_load+="$ret"
   1388     return 0
   1389   fi
   1390 
   1391   local spec
   1392   for spec in "${setface[@]}"; do
   1393     if local rex='^([_a-zA-Z@][_a-zA-Z0-9@]*)(:?=)(.*)$'; ! [[ $spec =~ $rex ]]; then
   1394       ble/util/print "ble-face: unrecognized setting '$spec'" >&2
   1395       flags=E$flags
   1396       continue
   1397     fi
   1398 
   1399     local var=${BASH_REMATCH[1]}
   1400     local type=${BASH_REMATCH[2]}
   1401     local value=${BASH_REMATCH[3]}
   1402     if [[ $type == ':=' ]]; then
   1403       if [[ $var == *@* ]]; then
   1404         ble/util/print "ble-face: wild card @ cannot be used for face definition ($spec)." >&2
   1405         flags=E$flags
   1406       else
   1407         ble/color/defface "$var" "$value"
   1408       fi
   1409     else
   1410       local ret face
   1411       if bleopt/expand-variable-pattern "_ble_faces__$var"; then
   1412         for face in "${ret[@]}"; do
   1413           ble/color/setface "${face#_ble_faces__}" "$value"
   1414         done
   1415       else
   1416         ble/util/print "ble-face: face '$var' not found" >&2
   1417         flags=E$flags
   1418       fi
   1419     fi
   1420   done
   1421 
   1422   if ((${#print[@]})); then
   1423     # initialize
   1424     local ret sgr0= sgr1= sgr2=
   1425     if [[ $flags == *c* ]]; then
   1426       sgr0=$_ble_term_sgr0
   1427       ble/color/face2sgr command_function; sgr1=$ret
   1428       ble/color/face2sgr syntax_varname; sgr2=$ret
   1429     fi
   1430 
   1431     local spec
   1432     for spec in "${print[@]}"; do
   1433       local ret face
   1434       if bleopt/expand-variable-pattern "_ble_faces__$spec"; then
   1435         if [[ $flags == *r* ]]; then
   1436           for face in "${ret[@]}"; do
   1437             ble-face/.reset-face "$face"
   1438           done
   1439         else
   1440           for face in "${ret[@]}"; do
   1441             ble-face/.print-face "$face"
   1442           done
   1443         fi
   1444       else
   1445         ble/util/print "ble-face: face '$spec' not found" >&2
   1446         flags=E$flags
   1447       fi
   1448     done
   1449   fi
   1450   [[ $flags != *E* ]]
   1451 }
   1452 
   1453 #------------------------------------------------------------------------------
   1454 # ble/highlight/layer
   1455 
   1456 _ble_highlight_layer_list=(plain)
   1457 
   1458 ## @fn ble/highlight/layer/update text opts [DMIN DMAX DMAX0]
   1459 ##   @param[in] text opts DMIN DMAX DMAX0
   1460 ##   @var[out] HIGHLIGHT_BUFF
   1461 ##   @var[out] HIGHLIGHT_UMIN
   1462 ##   @var[out] HIGHLIGHT_UMAX
   1463 function ble/highlight/layer/update {
   1464   local text=$1 iN=${#1} opts=$2
   1465   local DMIN=${3:-0} DMAX=${4:-$iN} DMAX0=${5:-0}
   1466 
   1467   local PREV_BUFF=_ble_highlight_layer_plain_buff
   1468   local PREV_UMIN=-1
   1469   local PREV_UMAX=-1
   1470   local layer player=plain LEVEL
   1471   local nlevel=${#_ble_highlight_layer_list[@]}
   1472   for ((LEVEL=0;LEVEL<nlevel;LEVEL++)); do
   1473     layer=${_ble_highlight_layer_list[LEVEL]}
   1474 
   1475     "ble/highlight/layer:$layer/update" "$text" "$player"
   1476     # echo "PREV($LEVEL) $PREV_UMIN $PREV_UMAX" >> 1.tmp
   1477 
   1478     player=$layer
   1479   done
   1480 
   1481   HIGHLIGHT_BUFF=$PREV_BUFF
   1482   HIGHLIGHT_UMIN=$PREV_UMIN
   1483   HIGHLIGHT_UMAX=$PREV_UMAX
   1484 }
   1485 
   1486 function ble/highlight/layer/update/add-urange {
   1487   local umin=$1 umax=$2
   1488   (((PREV_UMIN<0||PREV_UMIN>umin)&&(PREV_UMIN=umin),
   1489     (PREV_UMAX<0||PREV_UMAX<umax)&&(PREV_UMAX=umax)))
   1490 }
   1491 function ble/highlight/layer/update/shift {
   1492   local _ble_local_dstarr=$1
   1493   local _ble_local_srcarr=${2:-$_ble_local_dstarr}
   1494   if ((DMIN>=0)); then
   1495     ble/array#reserve-prototype "$((DMAX-DMIN))"
   1496     builtin eval "
   1497     $_ble_local_dstarr=(
   1498       \"\${$_ble_local_srcarr[@]::DMIN}\"
   1499       \"\${_ble_array_prototype[@]::DMAX-DMIN}\"
   1500       \"\${$_ble_local_srcarr[@]:DMAX0}\")"
   1501   else
   1502     [[ $_ble_local_dstarr != "$_ble_local_srcarr" ]] &&
   1503       builtin eval -- "$_ble_local_dstarr=(\"\${$_ble_local_srcarr[@]}\")"
   1504   fi
   1505 }
   1506 
   1507 function ble/highlight/layer/update/getg {
   1508   g=
   1509   local LEVEL=$LEVEL
   1510   while ((--LEVEL>=0)); do
   1511     "ble/highlight/layer:${_ble_highlight_layer_list[LEVEL]}/getg" "$1"
   1512     [[ $g ]] && return 0
   1513   done
   1514   g=0
   1515 }
   1516 
   1517 ## @fn ble/highlight/layer/getg index
   1518 ##   @param[in] index
   1519 ##   @var[out] g
   1520 function ble/highlight/layer/getg {
   1521   LEVEL=${#_ble_highlight_layer_list[*]} ble/highlight/layer/update/getg "$1"
   1522 }
   1523 
   1524 ## レイヤーの実装
   1525 ##   先ず作成するレイヤーの名前を決めます。ここでは <layerName> とします。
   1526 ##   次に、以下の配列変数と二つの関数を用意します。
   1527 ##
   1528 ## @arr _ble_highlight_layer_<layerName>_VARNAMES
   1529 ##   レイヤーの動的な状態を保持する変数の一覧です。ble/textarea#save-state で参
   1530 ##   照されます。もしこの配列が定義されていない場合は、代わりに
   1531 ##   _ble_highlight_layer_<layerName>_ で始まる変数名を全て記録します。
   1532 ##
   1533 ## @arr _ble_highlight_layer_<layerName>_buff=()
   1534 ##   グローバルに定義する配列変数です。
   1535 ##   後述の ble/highlight/layer:<layerName>/update が呼ばれた時に更新します。
   1536 ##
   1537 ##   各要素は編集文字列の各文字に対応しています。
   1538 ##   各要素は "<SGR指定><表示文字>" の形式になります。
   1539 ##
   1540 ##   "SGR指定" には描画属性を指定するエスケープシーケンスを指定します。
   1541 ##   "SGR指定" は前の文字と同じ描画属性の場合には省略可能です。
   1542 ##   この描画属性は現在のレイヤーとその下層にある全てのレイヤーの結果を総合した物になります。
   1543 ##   この描画属性は後述する ble/highlight/layer/getg 関数によって得られる
   1544 ##   g 値と対応している必要があります。
   1545 ##
   1546 ##   "<表示文字>" は編集文字列中の文字に対応する、予め定められた文字列です。
   1547 ##   基本レイヤーである plain の _ble_highlight_layer_plain_buff 配列に
   1548 ##   対応する "<表示文字>" が (SGR属性無しで) 格納されているのでこれを使用して下さい。
   1549 ##   表示文字の内容は基本的に、その文字自身と同一の物になります。
   1550 ##   但し、改行を除く制御文字の場合には、文字自身とは異なる "<表示文字>" になります。
   1551 ##   ASCII code 1-8, 11-31 の文字については "^A" ~ "^_" という2文字になります。
   1552 ##   ASCII code 9 (TAB) の場合には、空白が幾つか (端末の設定に応じた数だけ) 並んだ物になります。
   1553 ##   ASCII code 127 (DEL) については "^?" という2文字の表現になります。
   1554 ##   通常は _ble_highlight_layer_plain_buff に格納されている値をそのまま使えば良いので、
   1555 ##   これらの "<表示文字>" の詳細について考慮に入れる必要はありません。
   1556 ##
   1557 ## @fn ble/highlight/layer:<layerName>/update text player
   1558 ##   _ble_highlight_layer_<layerName>_buff の内容を更新します。
   1559 ##
   1560 ##   @param[in]     text
   1561 ##   @var  [in]     DMIN DMAX DMAX0
   1562 ##     第一引数 text には現在の編集文字列が指定されます。
   1563 ##     シェル変数 DMIN DMAX DMAX0 には前回の呼出の後の編集文字列の変更位置が指定されます。
   1564 ##     DMIN<0 の時は前回の呼出から text が変わっていない事を表します。
   1565 ##     DMIN>=0 の時は、現在の text の DMIN から DMAX までが変更された部分になります。
   1566 ##     DMAX0 は、DMAX の編集前の対応位置を表します。幾つか例を挙げます:
   1567 ##     - aaaa の 境界2 に挿入があって aaxxaa となった場合、DMIN DMAX DMAX0 は 2 4 2 となります。
   1568 ##     - aaxxaa から xx を削除して aaaa になった場合、DMIN DMAX DMAX0 はそれぞれ 2 2 4 となります。
   1569 ##     - aaxxaa が aayyyaa となった場合 DMIN DMAX DMAX0 は 2 5 4 となります。
   1570 ##     - aaxxaa が aazzaa となった場合 DMIN DMAX DMAX0 は 2 4 4 となります。
   1571 ##
   1572 ##   @param[in]     player
   1573 ##   @var  [in,out] LAYER_UMIN (unused)
   1574 ##   @var  [in,out] LAYER_UMAX (unused)
   1575 ##   @param[in]     PREV_BUFF
   1576 ##   @var  [in,out] PREV_UMIN
   1577 ##   @var  [in,out] PREV_UMAX
   1578 ##     player には現在のレイヤーの一つ下にあるレイヤーの名前が指定されます。
   1579 ##     通常 _ble_highlight_layer_<layerName>_buff は
   1580 ##     _ble_highlight_layer_<player>_buff の値を上書きする形で実装します。
   1581 ##     LAYER_UMIN, LAYER_UMAX は _ble_highlight_layer_<player>_buff において、
   1582 ##     前回の呼び出し以来、変更のあった範囲が指定されます。
   1583 ##
   1584 ##   @param[in,out] _ble_highlight_layer_<layerName>_buff
   1585 ##     前回の呼出の時の状態で関数が呼び出されます。
   1586 ##     DMIN DMAX DMAX0, LAYER_UMIN, LAYER_UMAX を元に
   1587 ##     前回から描画属性の変化がない部分については、
   1588 ##     呼出時に入っている値を再利用する事ができます。
   1589 ##     ble/highlight/layer/update/shift 関数も参照して下さい。
   1590 ##
   1591 ## @fn ble/highlight/layer:<layerName>/getg index
   1592 ##   指定した index に対応する描画属性の値を g 値で取得します。
   1593 ##   前回の ble/highlight/layer:<layerName>/update の呼出に基づく描画属性です。
   1594 ##   @var[out] g
   1595 ##     結果は変数 g に設定する事によって返します。
   1596 ##     より下層のレイヤーの値を引き継ぐ場合には空文字列を設定します: g=
   1597 ##
   1598 
   1599 #------------------------------------------------------------------------------
   1600 # ble/highlight/layer:plain
   1601 
   1602 _ble_highlight_layer_plain_VARNAMES=(
   1603   _ble_highlight_layer_plain_buff)
   1604 function ble/highlight/layer:plain/initialize-vars {
   1605   _ble_highlight_layer_plain_buff=()
   1606 }
   1607 ble/highlight/layer:plain/initialize-vars
   1608 
   1609 ## @fn ble/highlight/layer:plain/update/.getch
   1610 ##   @var[in,out] ch
   1611 function ble/highlight/layer:plain/update/.getch {
   1612   [[ $ch == [' '-'~'] ]] && return 0
   1613   if [[ $ch == [$'\t\n\177'] ]]; then
   1614     if [[ $ch == $'\t' ]]; then
   1615       ch=${_ble_string_prototype::it}
   1616     elif [[ $ch == $'\n' ]]; then
   1617       ch=$_ble_term_el$_ble_term_nl
   1618     elif [[ $ch == $'\177' ]]; then
   1619       ch='^?'
   1620     fi
   1621   else
   1622     local ret; ble/util/s2c "$ch"
   1623     local cs=${_ble_unicode_GraphemeCluster_ControlRepresentation[ret]}
   1624     if [[ $cs ]]; then
   1625       ch=$cs
   1626     elif ((ret<0x20)); then
   1627       ble/util/c2s "$((ret+64))"
   1628       ch="^$ret"
   1629     elif ((0x80<=ret&&ret<=0x9F)); then
   1630       # C1 characters
   1631       ble/util/c2s "$((ret-64))"
   1632       ch="M-^$ret"
   1633     fi
   1634   fi
   1635 }
   1636 
   1637 ## @fn ble/highlight/layer:<layerName>/update text pbuff
   1638 function ble/highlight/layer:plain/update {
   1639   if ((DMIN>=0)); then
   1640     ble/highlight/layer/update/shift _ble_highlight_layer_plain_buff
   1641 
   1642     local i text=$1 ch
   1643     local it=$_ble_term_it
   1644     for ((i=DMIN;i<DMAX;i++)); do
   1645       ch=${text:i:1}
   1646 
   1647       # LC_COLLATE for cygwin collation
   1648       local LC_ALL= LC_COLLATE=C
   1649       ble/highlight/layer:plain/update/.getch
   1650 
   1651       _ble_highlight_layer_plain_buff[i]=$ch
   1652     done
   1653   fi
   1654 
   1655   PREV_BUFF=_ble_highlight_layer_plain_buff
   1656   ((PREV_UMIN=DMIN,PREV_UMAX=DMAX))
   1657 }
   1658 # Note: suppress LC_COLLATE errors #D1205 #D1440
   1659 ble/function#suppress-stderr ble/highlight/layer:plain/update
   1660 
   1661 ## @fn ble/highlight/layer:plain/getg index
   1662 ##   @var[out] g
   1663 function ble/highlight/layer:plain/getg {
   1664   g=0
   1665 }
   1666 
   1667 #------------------------------------------------------------------------------
   1668 # abstract layer {selection}
   1669 
   1670 # This layer supports multiple selections with different gflags.
   1671 
   1672 function ble/highlight/layer:{selection}/declare {
   1673   local layer_name=$1
   1674   local layer_prefix=_ble_highlight_layer_${layer_name}_
   1675   builtin eval -- "
   1676     ${layer_prefix}VARNAMES=(
   1677       ${layer_prefix}buff
   1678       ${layer_prefix}osel
   1679       ${layer_prefix}ogflags)"
   1680   ble/highlight/layer:{selection}/initialize-vars "$layer_name"
   1681 }
   1682 
   1683 ## @fn ble/highlight/layer:{selection}/initialize-vars layer_name
   1684 ##   レイヤーで内部使用する配列を初期化します。
   1685 ##   @arr[out] _ble_highlight_layer_<layer_name>_buff
   1686 ##   @arr[out] _ble_highlight_layer_<layer_name>_osel
   1687 ##     前回の選択範囲の端点を保持する配列です。
   1688 ##   @arr[out] _ble_highlight_layer_<layer_name>_ogflags
   1689 ##     前回の選択範囲の着色を保持します。
   1690 ##
   1691 function ble/highlight/layer:{selection}/initialize-vars {
   1692   local layer_name=$1
   1693   local layer_prefix=_ble_highlight_layer_${layer_name}_
   1694   builtin eval -- "
   1695     ${layer_prefix}buff=()
   1696     ${layer_prefix}osel=()
   1697     ${layer_prefix}ogflags=()"
   1698 }
   1699 
   1700 ## @fn ble/highlight/layer:{selection}/.invalidate a b
   1701 ##   Include the range [a, b) (or [b, a) for the reversed range) in the dirty
   1702 ##   range (i.e., the range of the command line that needs to be re-rendered
   1703 ##   because of the updates).
   1704 ##
   1705 ##   @param[in] a b
   1706 ##   @var[in,out] umin umax
   1707 function ble/highlight/layer:{selection}/.invalidate {
   1708   local a=$1 b=$2 p q
   1709   ((a==b)) && return 0
   1710   (((a<b?(p=a,q=b):(p=b,q=a)),
   1711     (umin<0||umin>p)&&(umin=p),
   1712     (umax<0||umax<q)&&(umax=q)))
   1713 }
   1714 
   1715 ## @fn ble/highlight/layer:{selection}/update layer_name text
   1716 ##
   1717 ##   @param[in] layer_name
   1718 ##     This is used to save/restore the layer information.  All the related
   1719 ##     data are stored in the variables of the names:
   1720 ##     `_ble_highlight_layer_${layer_name}_${name}`.
   1721 ##   @arr[in] sel gflags
   1722 ##     The caller should prepare the list of the selection and the
   1723 ##     corresponding gflags.  The array `sel` contains two elements for each
   1724 ##     selection while `gflags` contains one for each.  The content of `sel` is
   1725 ##     (<selection1-begin> <selection1-end> <selection2-begin> <selection2-end>
   1726 ##     ... <selectionN-begin> <selectionN-end>) where <selectionX-begin/end>
   1727 ##     are integers specifying indices in the command-line string.  The content
   1728 ##     of `gflags` is (<selection1-gflags> <selection2-gflags>
   1729 ##     ... <selectionN-gflags>) where <selectionX-gflags> are integers
   1730 ##     specifying the highlighting style in gflags.
   1731 ##
   1732 ##     When `sel` is set to -1, it means that the selections do not change from
   1733 ##     its previous state.
   1734 function ble/highlight/layer:{selection}/update {
   1735   local layer_name=$1
   1736   local layer_prefix=_ble_highlight_layer_${layer_name}_
   1737   shift
   1738 
   1739   local IFS=$_ble_term_IFS
   1740 
   1741   # Retrieve the previous selections and adjust positions by the insertion and
   1742   # deletion of substrings in the command line.
   1743   local omin=-1 omax=-1 osel ogflags olen
   1744   ble/util/restore-vars "$layer_prefix" osel ogflags
   1745   olen=${#osel[@]}
   1746   if ((olen)); then
   1747     if ((DMIN>=0)); then
   1748       local k
   1749       for ((k=0;k<olen;k++)); do
   1750         if ((DMAX0<=osel[k])); then
   1751           ((osel[k]+=DMAX-DMAX0))
   1752         elif ((DMIN<osel[k])); then
   1753           ((osel[k]=DMIN))
   1754         fi
   1755       done
   1756     fi
   1757     omin=${osel[0]}
   1758     omax=${osel[olen-1]}
   1759   fi
   1760 
   1761   # Retrieve the new selections.  The array `sel` and `gflags` are supposed to
   1762   # be specified by the caller.
   1763   if ((sel==-1)); then
   1764     sel=("${osel[@]}")
   1765     gflags=("${ogflags[@]}")
   1766   fi
   1767   local rlen=${#sel[@]}
   1768 
   1769   # 変更がない時はそのまま通過
   1770   if ((DMIN<0&&(PREV_UMIN<0||rlen>=2&&sel[0]<=PREV_UMIN&&PREV_UMAX<=sel[1]))); then
   1771     if [[ ${sel[*]} == "${osel[*]}" && ${gflags[*]} == "${ogflags[*]}" ]]; then
   1772       [[ ${sel[*]} ]] && PREV_BUFF=${layer_prefix}buff
   1773       return 0
   1774     fi
   1775   else
   1776     [[ ! ${sel[*]} && ! ${osel[*]} ]] && return 0
   1777   fi
   1778 
   1779   local umin=-1 umax=-1
   1780   if ((rlen)); then
   1781     # 選択範囲がある時
   1782     local rmin=${sel[0]}
   1783     local rmax=${sel[rlen-1]}
   1784 
   1785     # 描画文字配列の更新
   1786     local -a buff=()
   1787     local g ret
   1788     local k=0 inext iprev=0
   1789     for inext in "${sel[@]}"; do
   1790       if ((inext>iprev)); then
   1791         if ((k==0)); then
   1792           ble/array#push buff "\"\${$PREV_BUFF[@]::$inext}\""
   1793         elif ((k%2)); then
   1794           ble/color/g2sgr "${gflags[k/2]}"
   1795           ble/array#push buff "\"$ret\${_ble_highlight_layer_plain_buff[@]:$iprev:$((inext-iprev))}\""
   1796         else
   1797           ble/highlight/layer/update/getg "$iprev"
   1798           ble/color/g2sgr "$g"
   1799           ble/array#push buff "\"$ret\${$PREV_BUFF[@]:$iprev:$((inext-iprev))}\""
   1800         fi
   1801       fi
   1802       ((iprev=inext,k++))
   1803     done
   1804     ble/highlight/layer/update/getg "$iprev"
   1805     ble/color/g2sgr "$g"
   1806     ble/array#push buff "\"$ret\${$PREV_BUFF[@]:$iprev}\""
   1807     builtin eval -- "${layer_prefix}buff=(${buff[*]})"
   1808     PREV_BUFF=${layer_prefix}buff
   1809 
   1810     # (Dirty range 1) DMIN-DMAX の間
   1811     if ((DMIN>=0)); then
   1812       ble/highlight/layer:{selection}/.invalidate "$DMIN" "$DMAX"
   1813     fi
   1814 
   1815     # (Dirty range 2) 選択範囲の変更
   1816     if ((olen==2&&rlen==2)); then
   1817       # Optimized code for the case where both osel and sel are single
   1818       # selections (i.e., the next `if ((omin>=0))` branch is general and
   1819       # should also work for this specific case).
   1820       #
   1821       # Note: The following two branches are currently equivalent because
   1822       # `.invalidate` manages only a single covering range [umin, umax), but
   1823       # these are semantically different when multiple ranges would be managed
   1824       # by `.invalidate`.
   1825       if [[ ${gflags[0]} != "${ogflags[0]}" ]]; then
   1826         # 色が変化する場合
   1827         ble/highlight/layer:{selection}/.invalidate "$omin" "$omax"
   1828         ble/highlight/layer:{selection}/.invalidate "$rmin" "$rmax"
   1829       else
   1830         # 端点の移動による再描画
   1831         ble/highlight/layer:{selection}/.invalidate "$omin" "$rmin"
   1832         ble/highlight/layer:{selection}/.invalidate "$omax" "$rmax"
   1833       fi
   1834     elif ((omin>=0)); then
   1835       # Find the first and last non-matching selection boundaries and update
   1836       # the dirty range.
   1837       local k m
   1838       local min_len=$((olen<rlen?olen:rlen))
   1839       local max_len=$((olen>rlen?olen:rlen))
   1840       for ((k=0;k<max_len;k++)); do
   1841         # Compare each selection in `sel` and `osel` and advance `k` as far as
   1842         # the selections match.  If there is no corresponding selection or the
   1843         # color is different or the boundary is different, process the later
   1844         # part of the loop.  Otherwise, skip this loop and try next `k`.
   1845         if ((k<min_len)); then
   1846           [[ k%2 -eq 0 && ${gflags[k/2]} != "${ogflags[k/2]}" ]] ||
   1847             ((sel[k]!=osel[k])) ||
   1848             continue
   1849         fi
   1850         local smin=$((sel[k]<osel[k]?sel[k]:osel[k]))
   1851 
   1852         for ((m=0;m<max_len;m++)); do
   1853           local rind=$((rlen-m-1)) oind=$((olen-m-1))
   1854           # Compare each selection from the end of the list (where `m` is the
   1855           # offset from the end) and increment `m` as far as the selections
   1856           # match.  If there is no correponding selection or the color is
   1857           # different or the boundary is different, process the later part of
   1858           # the loop.  Otherwise, skip this loop and try next `m`.
   1859           if ((m==min_len)); then
   1860             [[ m%2 -eq 0 && ${gflags[rind/2]} != "${ogflags[oind/2]}" ]] ||
   1861               ((sel[rind]!=osel[oind])) ||
   1862               continue
   1863           fi
   1864           local smax=$((sel[rind]>osel[oind]?sel[rind]:osel[oind]))
   1865 
   1866           ((smin<smax)) &&
   1867             ble/highlight/layer:{selection}/.invalidate "$smin" "$smax"
   1868           break
   1869         done
   1870         break
   1871       done
   1872     else
   1873       # 新規選択
   1874       ble/highlight/layer:{selection}/.invalidate "$rmin" "$rmax"
   1875     fi
   1876 
   1877     # (Dirty range 3) 下層の変更 (rmin ~ rmax は表には反映されない)
   1878     local pmin=$PREV_UMIN pmax=$PREV_UMAX
   1879     if ((rlen==2)); then
   1880       # Optimized code for the single-selection case (i.e., the next `if
   1881       # ((rlen))` branch is general and should also work for this specific
   1882       # case).
   1883       ((rmin<=pmin&&pmin<rmax&&(pmin=rmax),
   1884         rmin<pmax&&pmax<=rmax&&(pmax=rmin)))
   1885     elif ((rlen)); then
   1886       # この層の選択範囲で隠されている部分は省略可能
   1887       local k
   1888       for ((k=0;k<rlen;k+=2)); do
   1889         if ((pmin<sel[k])); then
   1890           break
   1891         elif ((sel[k]<=pmin&&pmin<sel[k+1])); then
   1892           pmin=${sel[k+1]}
   1893         fi
   1894       done
   1895 
   1896       for ((k=rlen-2;k>=0;k-=2)); do
   1897         if ((sel[k+1]<pmax)); then
   1898           break
   1899         elif ((sel[k]<pmax&&pmax<=sel[k+1])); then
   1900           pmax=${sel[k]}
   1901         fi
   1902       done
   1903     fi
   1904     ble/highlight/layer:{selection}/.invalidate "$pmin" "$pmax"
   1905   else
   1906     # 選択範囲がない時
   1907 
   1908     # 下層の変更
   1909     umin=$PREV_UMIN umax=$PREV_UMAX
   1910 
   1911     # 選択解除の範囲
   1912     ble/highlight/layer:{selection}/.invalidate "$omin" "$omax"
   1913   fi
   1914 
   1915   osel=("${sel[@]}")
   1916   ogflags=("${gflags[@]}")
   1917   ble/util/save-vars "$layer_prefix" osel ogflags
   1918   ((PREV_UMIN=umin,PREV_UMAX=umax))
   1919 }
   1920 
   1921 function ble/highlight/layer:{selection}/getg {
   1922   local layer_name=$1
   1923   local layer_prefix=_ble_highlight_layer_${layer_name}_
   1924   shift
   1925 
   1926   local index=$1
   1927 
   1928   local osel olen
   1929   ble/util/restore-vars "$layer_prefix" osel
   1930   olen=${#osel[@]}
   1931   ((olen)) || return 1
   1932   ((osel[0]<=index&&index<osel[olen-1])) || return 1
   1933 
   1934   local isel=
   1935   if ((olen>=4)); then
   1936     # When there are multiple selections, we identify the position of `index`
   1937     # using bisection.
   1938     local l=0 u=$((olen-1)) m
   1939     while ((l+1<u)); do
   1940       ((osel[m=(l+u)/2]<=index?(l=m):(u=m)))
   1941     done
   1942 
   1943     # When `l` sits at the end of a selection, check if the next selection
   1944     # immediately starts.  If it is the case, we increment `l` to pick the
   1945     # gflags of the next selection.
   1946     ((l%2&&l+1<olen&&osel[l]==osel[l+1]&&l++))
   1947 
   1948     ((l%2==0)) && ((isel=l/2))
   1949   else
   1950     # When there is only a single selection, the position `index` is always
   1951     # inside the selection because otherwise we already returned from the
   1952     # function by an earlier check.
   1953     isel=0
   1954   fi
   1955 
   1956   if [[ $isel ]]; then
   1957     local ref=${layer_prefix}ogflags[isel]
   1958     g=${!ref}
   1959   fi
   1960 }
   1961 
   1962 #------------------------------------------------------------------------------
   1963 # ble/highlight/layer:region
   1964 
   1965 function ble/color/defface.onload {
   1966   ble/color/defface region         bg=60,fg=white
   1967   ble/color/defface region_target  bg=153,fg=black
   1968   ble/color/defface region_match   bg=55,fg=white
   1969   ble/color/defface region_insert  fg=12,bg=252
   1970   ble/color/defface disabled       fg=242
   1971   ble/color/defface overwrite_mode fg=black,bg=51
   1972 }
   1973 blehook color_defface_load+=ble/color/defface.onload
   1974 
   1975 ## @arr _ble_highlight_layer_region_buff
   1976 ##
   1977 ## @arr _ble_highlight_layer_region_osel
   1978 ##   前回の選択範囲の端点を保持する配列です。
   1979 ##
   1980 ## @var _ble_highlight_layer_region_ogflags
   1981 ##   前回の選択範囲の着色を保持します。
   1982 ##
   1983 ble/highlight/layer:{selection}/declare region
   1984 
   1985 function ble/highlight/layer:region/update {
   1986   local -a sel=() gflags=()
   1987   if [[ $_ble_edit_mark_active ]]; then
   1988     # 外部定義の選択範囲があるか確認
   1989     #   vi-mode のビジュアルモード (文字選択、行選択、矩形選択) の実装で使用する。
   1990     local -a selection=()
   1991     if ! ble/function#try ble/highlight/layer:region/mark:"$_ble_edit_mark_active"/get-selection; then
   1992       if ((_ble_edit_mark>_ble_edit_ind)); then
   1993         selection=("$_ble_edit_ind" "$_ble_edit_mark")
   1994       elif ((_ble_edit_mark<_ble_edit_ind)); then
   1995         selection=("$_ble_edit_mark" "$_ble_edit_ind")
   1996       fi
   1997     fi
   1998 
   1999     # gflags の決定
   2000     local face=region
   2001     ble/function#try ble/highlight/layer:region/mark:"$_ble_edit_mark_active"/get-face
   2002     local ret; ble/color/face2g "$face"; local g=$ret
   2003 
   2004     sel=("${selection[@]}")
   2005     ble/array#fill-range gflags 0 "$((${#selection[@]}/2))" "$g"
   2006   fi
   2007 
   2008   ble/highlight/layer:{selection}/update region "$@"
   2009 }
   2010 
   2011 function ble/highlight/layer:region/getg {
   2012   ble/highlight/layer:{selection}/getg region "$@"
   2013 }
   2014 
   2015 #------------------------------------------------------------------------------
   2016 # ble/highlight/layer:disabled
   2017 
   2018 _ble_highlight_layer_disabled_VARNAMES=(
   2019   _ble_highlight_layer_disabled_prev
   2020   _ble_highlight_layer_disabled_buff)
   2021 function ble/highlight/layer:disabled/initialize-vars {
   2022   _ble_highlight_layer_disabled_prev=
   2023   _ble_highlight_layer_disabled_buff=()
   2024 }
   2025 ble/highlight/layer:disabled/initialize-vars
   2026 
   2027 function ble/highlight/layer:disabled/update {
   2028   if [[ $_ble_edit_line_disabled ]]; then
   2029     if ((DMIN>=0)) || [[ ! $_ble_highlight_layer_disabled_prev ]]; then
   2030       local ret; ble/color/face2sgr disabled; local sgr=$ret
   2031       _ble_highlight_layer_disabled_buff=("$sgr""${_ble_highlight_layer_plain_buff[@]}")
   2032     fi
   2033     PREV_BUFF=_ble_highlight_layer_disabled_buff
   2034 
   2035     if [[ $_ble_highlight_layer_disabled_prev ]]; then
   2036       PREV_UMIN=$DMIN PREV_UMAX=$DMAX
   2037     else
   2038       PREV_UMIN=0 PREV_UMAX=${#1}
   2039     fi
   2040   else
   2041     if [[ $_ble_highlight_layer_disabled_prev ]]; then
   2042       PREV_UMIN=0 PREV_UMAX=${#1}
   2043     fi
   2044   fi
   2045 
   2046   _ble_highlight_layer_disabled_prev=$_ble_edit_line_disabled
   2047 }
   2048 
   2049 function ble/highlight/layer:disabled/getg {
   2050   if [[ $_ble_highlight_layer_disabled_prev ]]; then
   2051     local ret; ble/color/face2g disabled; g=$ret
   2052   fi
   2053 }
   2054 
   2055 #------------------------------------------------------------------------------
   2056 # ble/highlight/layer:overwrite_mode
   2057 
   2058 _ble_highlight_layer_overwrite_mode_VARNAMES=(
   2059   _ble_highlight_layer_overwrite_mode_index
   2060   _ble_highlight_layer_overwrite_mode_buff)
   2061 function ble/highlight/layer:overwrite_mode/initialize-vars {
   2062   _ble_highlight_layer_overwrite_mode_index=-1
   2063   _ble_highlight_layer_overwrite_mode_buff=()
   2064 }
   2065 ble/highlight/layer:overwrite_mode/initialize-vars
   2066 
   2067 function ble/highlight/layer:overwrite_mode/update {
   2068   local oindex=$_ble_highlight_layer_overwrite_mode_index
   2069   if ((DMIN>=0)); then
   2070     if ((oindex>=DMAX0)); then
   2071       ((oindex+=DMAX-DMAX0))
   2072     elif ((oindex>=DMIN)); then
   2073       oindex=-1
   2074     fi
   2075   fi
   2076 
   2077   local index=-1
   2078   if [[ $_ble_edit_overwrite_mode && ! $_ble_edit_mark_active ]]; then
   2079     local next=${_ble_edit_str:_ble_edit_ind:1}
   2080     if [[ $next && $next != [$'\n\t'] ]]; then
   2081       index=$_ble_edit_ind
   2082 
   2083       local g ret
   2084 
   2085       # PREV_BUFF の内容をロード
   2086       if ((PREV_UMIN<0&&oindex>=0)); then
   2087         # 前回の結果が残っている場合
   2088         ble/highlight/layer/update/getg "$oindex"
   2089         ble/color/g2sgr "$g"
   2090         _ble_highlight_layer_overwrite_mode_buff[oindex]=$ret${_ble_highlight_layer_plain_buff[oindex]}
   2091       else
   2092         # コピーした方が速い場合
   2093         builtin eval "_ble_highlight_layer_overwrite_mode_buff=(\"\${$PREV_BUFF[@]}\")"
   2094       fi
   2095       PREV_BUFF=_ble_highlight_layer_overwrite_mode_buff
   2096 
   2097       # 1文字着色
   2098       # ble/highlight/layer/update/getg "$index"
   2099       # ((g^=_ble_color_gflags_Revert))
   2100       ble/color/face2g overwrite_mode
   2101       ble/color/g2sgr "$ret"
   2102       _ble_highlight_layer_overwrite_mode_buff[index]=$ret${_ble_highlight_layer_plain_buff[index]}
   2103       if ((index+1<${#1})); then
   2104         ble/highlight/layer/update/getg "$((index+1))"
   2105         ble/color/g2sgr "$g"
   2106         _ble_highlight_layer_overwrite_mode_buff[index+1]=$ret${_ble_highlight_layer_plain_buff[index+1]}
   2107       fi
   2108     fi
   2109   fi
   2110 
   2111   if ((index>=0)); then
   2112     ble/term/cursor-state/hide
   2113   else
   2114     ble/term/cursor-state/reveal
   2115   fi
   2116 
   2117   if ((index!=oindex)); then
   2118     ((oindex>=0)) && ble/highlight/layer/update/add-urange "$oindex" "$((oindex+1))"
   2119     ((index>=0)) && ble/highlight/layer/update/add-urange "$index" "$((index+1))"
   2120   fi
   2121 
   2122   _ble_highlight_layer_overwrite_mode_index=$index
   2123 }
   2124 function ble/highlight/layer:overwrite_mode/getg {
   2125   local index=$_ble_highlight_layer_overwrite_mode_index
   2126   if ((index>=0&&index==$1)); then
   2127     # ble/highlight/layer/update/getg "$1"
   2128     # ((g^=_ble_color_gflags_Revert))
   2129     local ret; ble/color/face2g overwrite_mode; g=$ret
   2130   fi
   2131 }
   2132 
   2133 #------------------------------------------------------------------------------
   2134 
   2135 _ble_highlight_layer_list=(plain syntax region overwrite_mode disabled)