373 lines
12 KiB
Bash
373 lines
12 KiB
Bash
# ble/contrib/layer/sample.adapter.bash (C) 2015, akinomyoga
|
|
#
|
|
# The first implementation of ``syntax highlighting'' in ble.sh.
|
|
#
|
|
# This file contains a historical implementation of syntax highlighting in
|
|
# ble.sh. The initial interface was different from the current one (see the
|
|
# functions ble/syntax-highlight+*). When the new interface is introduced in
|
|
# commit ec3f3661b (2015-02-23), the `adapter` layer was implemented to bridge
|
|
# the older implementation of highlighter and the new layer interface. This
|
|
# served the first implementation of syntax highlighting and later replaced by
|
|
# a serious implementation based on a real shell parser (ble-syntax.sh,
|
|
# currently src/core-syntax.sh). After a long time since it was superceded,
|
|
# the layer definition was moved from the main file `ble-color.sh` to the
|
|
# archive `archive/layer/adapter.sh` in commit afdcc1598 (2017-03-05 #D0386).
|
|
# Now, let us move the file to the `contrib` repository and preserve it as a
|
|
# historical implementation of ``syntax highlighting'' and an illustration of
|
|
# implementing a layer.
|
|
#
|
|
# To try this layer, you can set the following values to the array
|
|
# `_ble_highlight_layer_list`:
|
|
#
|
|
# ```bash
|
|
# ble-import layer/sample.adapter
|
|
# _ble_highlight_layer_list=(plain adapter)
|
|
# ```
|
|
#
|
|
# It should be noted that the behavior related the selected regions seems buggy
|
|
# within the current layer model.
|
|
|
|
##
|
|
## レイヤー ble/highlight/layer:adapter
|
|
##
|
|
## 古い枠組みに依る色つけのアダプターを
|
|
## レイヤーの実装のサンプルとして此処に残す。
|
|
## 使う場合は例えば以下の様にする。
|
|
##
|
|
## _ble_highlight_layer_list=(plain adapter)
|
|
##
|
|
##
|
|
|
|
bleopt/declare -v syntax_highlight_mode default
|
|
|
|
_ble_region_highlight_table=()
|
|
|
|
## 古い実装からの adapter
|
|
_ble_highlight_layer_adapter_buff=()
|
|
_ble_highlight_layer_adapter_table=()
|
|
function ble/highlight/layer:adapter/update {
|
|
local text=$1 player=$2
|
|
|
|
# update g table
|
|
local LAYER_UMIN LAYER_UMAX
|
|
local -a _ble_region_highlight_table
|
|
ble/highlight/layer/update/shift _ble_region_highlight_table _ble_highlight_layer_adapter_table
|
|
if [[ $bleopt_syntax_highlight_mode ]]; then
|
|
# LAYER_UMIN を設定しない highlight_mode の場合はそのまま。
|
|
# LAYER_UMIN を設定する highlight_mode の場合は参照せずに上書きされる。
|
|
LAYER_UMIN=0 LAYER_UMAX=$iN
|
|
"ble/syntax-highlight+$bleopt_syntax_highlight_mode" "$text"
|
|
else
|
|
LAYER_UMIN=$iN LAYER_UMAX=0
|
|
fi
|
|
_ble_highlight_layer_adapter_table=("${_ble_region_highlight_table[@]}")
|
|
|
|
# 描画文字を更新する範囲 [i1,i2]
|
|
# text[i2] (更新範囲の次の文字) の SGR に影響を与えない為、
|
|
# 実際の更新は text[i2] に対しても行う。
|
|
((PREV_UMIN>=0&&LAYER_UMIN>PREV_UMIN&&(LAYER_UMIN=PREV_UMIN),
|
|
PREV_UMAX>=0&&LAYER_UMAX<PREV_UMAX&&(LAYER_UMAX=PREV_UMAX)))
|
|
local i1=$LAYER_UMIN i2=$LAYER_UMAX
|
|
((i2>=iN&&(i2=iN-1)))
|
|
|
|
# update char buffer
|
|
ble/highlight/layer/update/shift _ble_highlight_layer_adapter_buff
|
|
local i g gprev=0 ctx=0 ret
|
|
((i1>0)) && { ble/highlight/layer/getg "$((i1-1))"; gprev=$g; }
|
|
# ble/edit/info/show text "layer:adapter u = $i1-$i2"
|
|
for ((i=i1;i<=i2;i++)); do
|
|
local ch
|
|
if [[ ${_ble_region_highlight_table[i]} ]]; then
|
|
ch=${_ble_highlight_layer_plain_buff[i]}
|
|
((g=_ble_region_highlight_table[i]))
|
|
if ((ctx!=0||g!=gprev)); then
|
|
((ctx=0,gprev=g))
|
|
ble/color/g2sgr "$g"
|
|
ch=$ret$ch
|
|
fi
|
|
else
|
|
builtin eval "ch=\${$PREV_BUFF[i]}"
|
|
if ((ctx!=1)); then
|
|
((ctx=1,gprev=-1))
|
|
ble/highlight/layer/update/getg
|
|
ble/color/g2sgr "$g"
|
|
ch=$ret$ch
|
|
fi
|
|
fi
|
|
|
|
_ble_highlight_layer_adapter_buff[i]=$ch
|
|
done
|
|
|
|
PREV_BUFF=_ble_highlight_layer_adapter_buff
|
|
if ((LAYER_UMIN<LAYER_UMAX)); then
|
|
((PREV_UMIN=LAYER_UMIN,PREV_UMAX=LAYER_UMAX))
|
|
else
|
|
((PREV_UMIN=-1,PREV_UMAX=-1))
|
|
fi
|
|
}
|
|
function ble/highlight/layer:adapter/getg {
|
|
# 描画属性がない時は _ble_region_highlight_table[i]
|
|
# には空文字列が入っているのでOK
|
|
g=${_ble_highlight_layer_adapter_table[$1]}
|
|
}
|
|
|
|
|
|
#------------------------------------------------------------------------------
|
|
|
|
## @fn _ble_region_highlight_table; ble/syntax-highlight/append triplets ; _ble_region_highlight_table
|
|
function ble/syntax-highlight/append {
|
|
while (($#)); do
|
|
local -a triplet
|
|
triplet=($1)
|
|
local ret; ble/color/gspec2g "${triplet[2]}"; local g=$ret
|
|
local i=${triplet[0]} iN=${triplet[1]}
|
|
for ((;i<iN;i++)); do
|
|
_ble_region_highlight_table[$i]=$g
|
|
done
|
|
shift
|
|
done
|
|
}
|
|
|
|
function ble/syntax-highlight+region {
|
|
if [[ $_ble_edit_mark_active ]]; then
|
|
if ((_ble_edit_mark>_ble_edit_ind)); then
|
|
ble/syntax-highlight/append "$_ble_edit_ind $_ble_edit_mark bg=60,fg=white"
|
|
elif ((_ble_edit_mark<_ble_edit_ind)); then
|
|
ble/syntax-highlight/append "$_ble_edit_mark $_ble_edit_ind bg=60,fg=white"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
function ble/syntax-highlight+test {
|
|
local text=$1
|
|
local i iN=${#text} w
|
|
local mode=cmd
|
|
for ((i=0;i<iN;)); do
|
|
local tail=${text:i} rex
|
|
if [[ $mode == cmd ]]; then
|
|
if rex='^[_a-zA-Z][_a-zA-Z0-9]*=' && [[ $tail =~ $rex ]]; then
|
|
# 変数への代入
|
|
local var=${tail%%=*}
|
|
ble/syntax-highlight/append "$i $((i+${#var})) fg=orange"
|
|
((i+=${#var}+1))
|
|
|
|
mode=rhs
|
|
elif rex='^[_a-zA-Z][_a-zA-Z0-9]*\[[^]]+\]=' && [[ $tail =~ $rex ]]; then
|
|
# 配列変数への代入
|
|
local var="${tail%%\[*}"
|
|
ble/syntax-highlight/append "$i $((i+${#var})) fg=orange"
|
|
((i+=${#var}+1))
|
|
|
|
local tmp="${tail%%\]=*}"
|
|
local ind="${tmp#*\[}"
|
|
ble/syntax-highlight/append "$i $((i+${#ind})) fg=green"
|
|
((i+=${#var}+1))
|
|
|
|
mode=rhs
|
|
elif rex='^[^ "'\'']+([ ]|$)' && [[ $tail =~ $rex ]]; then
|
|
local cmd="${tail%%[ ]*}" cmd_type
|
|
ble/util/type cmd_type "$cmd"
|
|
case $cmd_type:$cmd in
|
|
builtin:*)
|
|
ble/syntax-highlight/append "$i $((i+${#cmd})) fg=red" ;;
|
|
alias:*)
|
|
ble/syntax-highlight/append "$i $((i+${#cmd})) fg=teal" ;;
|
|
function:*)
|
|
ble/syntax-highlight/append "$i $((i+${#cmd})) fg=navy" ;;
|
|
file:*)
|
|
ble/syntax-highlight/append "$i $((i+${#cmd})) fg=green" ;;
|
|
keyword:*)
|
|
ble/syntax-highlight/append "$i $((i+${#cmd})) fg=blue" ;;
|
|
*)
|
|
ble/syntax-highlight/append "$i $((i+${#cmd})) bg=224" ;;
|
|
esac
|
|
((i+=${#cmd}))
|
|
mode=arg
|
|
else
|
|
((i++))
|
|
fi
|
|
else
|
|
((i++))
|
|
fi
|
|
done
|
|
|
|
ble/syntax-highlight+region "$@"
|
|
|
|
# ble/syntax-highlight/append "${#text1} $((${#text1}+1)) standout"
|
|
}
|
|
|
|
function ble/syntax-highlight+default/type {
|
|
type=$1
|
|
local cmd=$2
|
|
case $type:$cmd in
|
|
(builtin::|builtin:.)
|
|
# 見にくいので太字にする
|
|
type=builtin_bold ;;
|
|
(builtin:*)
|
|
type=builtin ;;
|
|
(alias:*)
|
|
type=alias ;;
|
|
(function:*)
|
|
type=function ;;
|
|
(file:*)
|
|
type=file ;;
|
|
(keyword:*)
|
|
type=keyword ;;
|
|
(*:%*)
|
|
# jobs
|
|
ble/util/joblist.check
|
|
if jobs "$cmd" &>/dev/null; then
|
|
type=jobs
|
|
else
|
|
type=error
|
|
fi ;;
|
|
(*)
|
|
type=error ;;
|
|
esac
|
|
}
|
|
|
|
function ble/syntax-highlight+default {
|
|
local rex IFS=$_ble_term_IFS
|
|
local text=$1
|
|
local i iN=${#text} w
|
|
local mode=cmd
|
|
for ((i=0;i<iN;)); do
|
|
local tail=${text:i}
|
|
if [[ $mode == cmd ]]; then
|
|
if rex='^([_a-zA-Z][_a-zA-Z0-9]*)\+?=' && [[ $tail =~ $rex ]]; then
|
|
# for bash-3.1 ${#arr[n]} bug
|
|
local rematch1="${BASH_REMATCH[1]}"
|
|
|
|
# local var="${BASH_REMATCH[0]::-1}"
|
|
ble/syntax-highlight/append "$i $((i+$rematch1)) fg=orange"
|
|
((i+=${#BASH_REMATCH}))
|
|
mode=rhs
|
|
continue
|
|
elif rex='^([^'"$IFS"'|&;()<>'\''"\]|\\.)+' && [[ $tail =~ $rex ]]; then
|
|
# ■ time'hello' 等の場合に time だけが切り出されてしまう
|
|
|
|
local word=${BASH_REMATCH[0]}
|
|
builtin eval "local cmd=${word}"
|
|
|
|
# この部分の判定で fork を沢山する \if 等に対しては 4fork+2exec になる。
|
|
# ■キャッシュ(accept-line 時に clear)するなどした方が良いかもしれない。
|
|
local type; ble/util/type type "$cmd"
|
|
ble/syntax-highlight+default/type "$type" "$cmd" # -> type
|
|
if [[ $type = alias && $cmd != "$word" ]]; then
|
|
# alias を \ で無効化している場合
|
|
# → unalias して再度 check (2fork)
|
|
type=$(
|
|
builtin unalias "$cmd"
|
|
ble/util/type type "$cmd"
|
|
ble/syntax-highlight+default/type "$type" "$cmd" # -> type
|
|
ble/util/put "$type")
|
|
elif [[ "$type" = keyword && "$cmd" != "$word" ]]; then
|
|
# keyword (time do if function else elif fi の類) を \ で無効化している場合
|
|
# →file, function, builtin, jobs のどれかになる。以下 3fork+2exec
|
|
ble/util/joblist.check
|
|
if [[ ! ${cmd##%*} ]] && jobs "$cmd" &>/dev/null; then
|
|
# %() { :; } として 関数を定義できるが jobs の方が優先される。
|
|
# (% という名の関数を呼び出す方法はない?)
|
|
# でも % で始まる物が keyword になる事はそもそも無いような。
|
|
type=jobs
|
|
elif ble/is-function "$cmd"; then
|
|
type=function
|
|
elif enable -p | ble/bin/grep -q -F -x "enable $cmd" &>/dev/null; then
|
|
type=builtin
|
|
elif which "$cmd" &>/dev/null; then
|
|
type=file
|
|
else
|
|
type=error
|
|
fi
|
|
fi
|
|
|
|
case $type in
|
|
(file)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) fg=green" ;;
|
|
(alias)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) fg=teal" ;;
|
|
(function)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) fg=navy" ;;
|
|
(builtin)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) fg=red" ;;
|
|
(builtin_bold)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) fg=red,bold" ;;
|
|
(keyword)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) fg=blue" ;;
|
|
(jobs)
|
|
ble/syntax-highlight/append "$i $((i+1)) fg=red" ;;
|
|
(error|*)
|
|
ble/syntax-highlight/append "$i $((i+${#word})) bg=224" ;;
|
|
esac
|
|
|
|
((i+=${#BASH_REMATCH}))
|
|
if rex='^keyword:([!{]|time|do|if|then|else|while|until)$|^builtin:eval$' && [[ $type:$cmd =~ $rex ]]; then
|
|
mode=cmd
|
|
else
|
|
mode=arg
|
|
fi
|
|
|
|
continue
|
|
fi
|
|
elif [[ $mode == arg ]]; then
|
|
if rex='^([^"$'"$IFS"'|&;()<>'\''"`\]|\\.)+' && [[ $tail =~ $rex ]]; then
|
|
# ■ time'hello' 等の場合に time だけが切り出されてしまう
|
|
local arg=${BASH_REMATCH[0]}
|
|
|
|
local file=$arg
|
|
[[ ( $file == '~' || $file = '~/'* ) && ! ( -e $file || -h $file ) ]] && file=$HOME${file:1}
|
|
if [[ -d $file ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#arg})) fg=navy,underline"
|
|
elif [[ -h $file ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#arg})) fg=teal,underline"
|
|
elif [[ -x $file ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#arg})) fg=green,underline"
|
|
elif [[ -f $file ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#arg})) underline"
|
|
fi
|
|
|
|
((i+=${#arg}))
|
|
continue
|
|
fi
|
|
fi
|
|
|
|
# /^'([^'])*'|^\$'([^\']|\\.)*'|^`([^\`]|\\.)*`|^\\./
|
|
if rex='^'\''([^'\''])*'\''|^\$'\''([^\'\'']|\\.)*'\''|^`([^\`]|\\.)*`|^\\.' && [[ $tail =~ $rex ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#BASH_REMATCH})) fg=green"
|
|
((i+=${#BASH_REMATCH}))
|
|
mode=arg_
|
|
continue
|
|
elif rex='^['"$IFS"']+' && [[ $tail =~ $rex ]]; then
|
|
((i+=${#BASH_REMATCH}))
|
|
local spaces=${BASH_REMATCH[0]}
|
|
if [[ $spaces =~ $'\n' ]]; then
|
|
mode=cmd
|
|
else
|
|
[[ $mode = arg_ ]] && mode=arg
|
|
fi
|
|
continue
|
|
elif rex='^;;?|^;;&$|^&&?|^\|\|?' && [[ $tail =~ $rex ]]; then
|
|
if [[ $mode = cmd ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#BASH_REMATCH})) bg=224"
|
|
fi
|
|
((i+=${#BASH_REMATCH}))
|
|
mode=cmd
|
|
continue
|
|
elif rex='^(&?>>?|<>?|[<>]&)' && [[ $tail =~ $rex ]]; then
|
|
ble/syntax-highlight/append "$i $((i+${#BASH_REMATCH})) bold"
|
|
((i+=${#BASH_REMATCH}))
|
|
mode=arg
|
|
continue
|
|
elif rex='^(' && [[ $tail =~ $rex ]]; then
|
|
((i+=${#BASH_REMATCH}))
|
|
mode=cmd
|
|
continue
|
|
fi
|
|
# 他 "...", ${}, $... arg と共通
|
|
|
|
((i++))
|
|
# a[]=... の引数は、${} や "" を考慮に入れるだけでなく [] の数を数える。
|
|
done
|
|
|
|
ble/syntax-highlight+region "$@"
|
|
}
|