diff --git a/functions/-zui-list-box-loop b/functions/-zui-list-box-loop index c655165..e49a53d 100644 --- a/functions/-zui-list-box-loop +++ b/functions/-zui-list-box-loop @@ -1,12 +1,14 @@ # -*- mode: zsh; sh-indentation: 2; indent-tabs-mode: nil; sh-basic-offset: 2; -*- # vim: ft=zsh sw=2 ts=2 et -# +# shellcheck shell=bash + # Draws list-box drop-down list local __page_height="$1" __page_width="$2" __ypos="$3" __xpos="$4" __id="$5" __width_var="$6" __idx_var="$7" __opts_var="$8" __data2="$9" __data2="$10" __data3="$11" # Get maximum width local -a options options=( "${(@Ps:;:)__opts_var}" ) + # Remove color marks # [all] [fg] [bg] TEXT options=( "${options[@]//(#b)([$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'])([$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\017']|)([$'\020'-$'\030']|)([^${ZUI[FMT_END]}]#)${ZUI[FMT_END]}/$match[4]}" ) @@ -15,26 +17,26 @@ options=( "${options[@]//(#b)([$'\03'-$'\07'$'\013'-$'\014'$'\016'-$'\031'])([$' local txt integer width=7 height=10 size="${#options}" for txt in "${options[@]}"; do - (( width = ${(m)#txt} > width ? ${(m)#txt} : width )) + (( width = ${(m)#txt} > width ? ${(m)#txt} : width )) done if (( __ypos + size + 2 > __page_height + 1 )); then - if (( size + 2 > __page_height + 1 )); then - height=__page_height-2 - (( height <= 0 )) && height=__page_height # paranoid - __ypos=3 - else - height=size - (( __ypos = __page_height - size - 1 )) - fi -else - (( __ypos+=1 )) + if (( size + 2 > __page_height + 1 )); then + height=__page_height-2 + (( height <= 0 )) && height=__page_height # paranoid + __ypos=3 + else height=size + (( __ypos = __page_height - size - 1 )) + fi +else + (( __ypos+=1 )) + height=size fi if (( __xpos + width + 4 > __page_width )); then - # Basic protection, can be inaccurate - (( __xpos=__page_width - width - 4 )) + # Basic protection, can be inaccurate + (( __xpos=__page_width - width - 4 )) fi zcurses delwin lbox 2>/dev/null @@ -45,6 +47,7 @@ zcurses bg lbox "${ZUI[colorpair]}" zcurses timeout lbox 0 zcurses input lbox key keypad zcurses timeout lbox -1 + key="" keypad="" @@ -52,89 +55,87 @@ integer hidx __start __end return_val=0 initial_idx=${(P)__idx_var} __start=initial_idx-height/2 if (( __start <= 0 )); then - __start=1 - __end=size - if (( size > height )); then - __end=height - fi + __start=1 + __end=size + if (( size > height )); then + __end=height + fi elif (( __start + height - 1 > size )); then - __start=size-height+1 - __end=size + __start=size-height+1 + __end=size else - __end=initial_idx+(height-height/2)-1 + __end=initial_idx+(height-height/2)-1 fi while (( 1 )); do - # Draw list box - zcurses clear lbox - - integer i count=1 - hidx=${(P)__idx_var} - for (( i = __start; i <= __end; ++ i )); do - txt="${options[i]}" - zcurses move lbox "$count" 2 - - if (( i == hidx )); then - zcurses attr lbox +reverse - zcurses string lbox "$txt" - zcurses attr lbox -reverse - else - zcurses string lbox "$txt" - fi - - (( ++ count )) - done - - zcurses border lbox - zcurses refresh lbox - - # Wait for input - local key keypad final_key - zcurses input "lbox" key keypad - - # Get the special (i.e. "keypad") key or regular key - if [[ -n "$key" ]]; then - final_key="$key" - elif [[ -n "$keypad" ]]; then - final_key="$keypad" - fi - - case "$final_key" in - (UP|k|BTAB) - hidx=${(P)__idx_var} - (( hidx = hidx > 1 ? hidx-1 : hidx )) - if (( hidx < __start )); then - __start=hidx - __end=__start+height-1 - fi - : ${(P)__idx_var::=$hidx} - ;; - (DOWN|j|$'\t') - hidx=${(P)__idx_var} - (( hidx = hidx < ${#options} ? hidx+1 : hidx )) - if (( hidx > __end )); then - __end=hidx - __start=__end-height+1 - fi - : ${(P)__idx_var::=$hidx} - ;; - ($'\E') - : ${(P)__idx_var::=$initial_idx} - return_val=1 - break - ;; - ($'\n') - break - ;; - (??*) - ;; - (*) - ;; - esac + # Draw list box + zcurses clear lbox + + integer i count=1 + hidx=${(P)__idx_var} + for (( i = __start; i <= __end; ++ i )); do + txt="${options[i]}" + zcurses move lbox "$count" 2 + + if (( i == hidx )); then + zcurses attr lbox +reverse + zcurses string lbox "$txt" + zcurses attr lbox -reverse + else + zcurses string lbox "$txt" + fi + + (( ++ count )) + done + + zcurses border lbox + zcurses refresh lbox + + # Wait for input + local key keypad final_key + zcurses input "lbox" key keypad + + # Get the special (i.e. "keypad") key or regular key + if [[ -n "$key" ]]; then + final_key="$key" + elif [[ -n "$keypad" ]]; then + final_key="$keypad" + fi + + case "$final_key" in + (UP|k|BTAB) + hidx=${(P)__idx_var} + (( hidx = hidx > 1 ? hidx-1 : hidx )) + if (( hidx < __start )); then + __start=hidx + __end=__start+height-1 + fi + : ${(P)__idx_var::=$hidx} + ;; + (DOWN|j|$'\t') + hidx=${(P)__idx_var} + (( hidx = hidx < ${#options} ? hidx+1 : hidx )) + if (( hidx > __end )); then + __end=hidx + __start=__end-height+1 + fi + : ${(P)__idx_var::=$hidx} + ;; + ($'\E') + : ${(P)__idx_var::=$initial_idx} + return_val=1 + break + ;; + ($'\n') + break + ;; + (??*) + ;; + (*) + ;; + esac done zcurses delwin lbox 2>/dev/null return $return_val - -# vim:ft=zsh diff --git a/functions/-zui-log b/functions/-zui-log index f4a0edf..74a75de 100644 --- a/functions/-zui-log +++ b/functions/-zui-log @@ -28,92 +28,94 @@ # $4 - indentation # $5 - actual length of text in current line (output parameter name) -zuilog_counted_msg() { - local color="$1" txt="$2" line_var="$3" indent="$4" actlen_var="$5" - - [[ -z "$txt" ]] && return 0 - - [[ -n "$color" ]] && zcurses attr "$window" "$color/${win_colorpair#*/}" - - while (( ${(P)actlen_var} + ${#txt} > win_width - indent * 2 )); do - integer part_count=$(( (win_width - indent * 2) - ${(P)actlen_var} )) - zcurses string "$window" "${txt[1,part_count]}" - : ${(P)actlen_var::=0} - # Needed next line 0-based > maximum line 0-based -> abort - [[ $(( ${(P)line_var} + 1 )) -gt $(( win_height - win_border - 1 )) ]] && { - [[ -n "$color" ]] && zcurses attr "$window" "$win_colorpair" - return 1 - } - txt="${txt[part_count+1,-1]}" - - # Curses cursor: right after text. Line number: at text. - if [[ -n "$txt" ]]; then - : ${(P)line_var::=${(P)line_var}+1} - zcurses move "$window" "${(P)line_var}" "$indent" - fi - done + local color="$1" txt="$2" line_var="$3" indent="$4" actlen_var="$5" + + [[ -z "$txt" ]] && return 0 + + [[ -n "$color" ]] && zcurses attr "$window" "$color/${win_colorpair#*/}" + + while (( ${(P)actlen_var} + ${#txt} > win_width - indent * 2 )); do + integer part_count=$(( (win_width - indent * 2) - ${(P)actlen_var} )) + zcurses string "$window" "${txt[1,part_count]}" + : ${(P)actlen_var::=0} + + # Needed next line 0-based > maximum line 0-based -> abort + [[ $(( ${(P)line_var} + 1 )) -gt $(( win_height - win_border - 1 )) ]] && { + [[ -n "$color" ]] && zcurses attr "$window" "$win_colorpair" + return 1 + } + txt="${txt[part_count+1,-1]}" + # Curses cursor: right after text. Line number: at text. if [[ -n "$txt" ]]; then - zcurses string "$window" "$txt" - : ${(P)actlen_var::=${(P)actlen_var}+${#txt}} + : ${(P)line_var::=${(P)line_var}+1} + zcurses move "$window" "${(P)line_var}" "$indent" fi + done - [[ -n "$color" ]] && zcurses attr "$window" "$win_colorpair" + if [[ -n "$txt" ]]; then + zcurses string "$window" "$txt" + : ${(P)actlen_var::=${(P)actlen_var}+${#txt}} + fi - return 0 + [[ -n "$color" ]] && zcurses attr "$window" "$win_colorpair" + + return 0 } # Outputs a message in the bottom of the screen # "[UNIQ]", "Text", "[Grep string]", "Generation time", "$reply[@]" from callback -zuilog_output_message() { - local direction="${1:-above}" line_var="$2" entry="$3" number="$4" txt - integer indent=2 msg_len track_len=0 index=0 - - local -a elems - elems=( "${(@Q)${(z@)entry}}" ) - msg_len="${elems[1]}" - shift 3 elems - - (( msg_len == 0 )) && return - - msg_len+=${#elems[1]} - - (( number > 0 )) && msg_len+=3+${#number} - - # - # Scroll - # - - if [[ "$direction" = "below" ]]; then - # (P)line_var is 0-based and it points after previous text - integer __line="${(P)line_var}"+$(( (msg_len-1)/(win_width-2*indent) )) - # Needed line 0-based, minus maximum line 0-based - integer __scroll=__line-$(( win_height - win_border - 1 )) - if (( __scroll > 0 )); then - (( __scroll = __scroll > (${(P)line_var}-win_border) ? ${(P)line_var} - win_border : __scroll )) - zcurses scroll "$window" +$__scroll - : ${(P)line_var::=${(P)line_var}-$__scroll} - fi - elif [[ "$direction" = "above" ]]; then - zcurses scroll "$window" -$(( 1 + (msg_len-1)/(win_width-2*indent) )) + local direction="${1:-above}" line_var="$2" entry="$3" number="$4" txt + integer indent=2 msg_len track_len=0 index=0 + + local -a elems + elems=( "${(@Q)${(z@)entry}}" ) + msg_len="${elems[1]}" + shift 3 elems + + (( msg_len == 0 )) && return + + msg_len+=${#elems[1]} + + (( number > 0 )) && msg_len+=3+${#number} + + # + # Scroll + # + + if [[ "$direction" = "below" ]]; then + # (P)line_var is 0-based and it points after previous text + integer __line="${(P)line_var}"+$(( (msg_len-1)/(win_width-2*indent) )) + + # Needed line 0-based, minus maximum line 0-based + integer __scroll=__line-$(( win_height - win_border - 1 )) + if (( __scroll > 0 )); then + (( __scroll = __scroll > (${(P)line_var}-win_border) ? ${(P)line_var} - win_border : __scroll )) + zcurses scroll "$window" +$__scroll + : ${(P)line_var::=${(P)line_var}-$__scroll} fi + elif [[ "$direction" = "above" ]]; then + zcurses scroll "$window" -$(( 1 + (msg_len-1)/(win_width-2*indent) )) + fi - zcurses move "$window" "${(P)line_var}" $indent + zcurses move "$window" "${(P)line_var}" $indent - # - # Print - # + # + # Print + # - (( number > 0 )) && -zuilog_counted_msg "${zui_log_colors[1]}" "[$number] " "$line_var" $indent track_len + (( number > 0 )) && -zuilog_counted_msg "${zui_log_colors[1]}" "[$number] " "$line_var" $indent track_len - index=2 - for txt in "${elems[@]}"; do - [[ -n "$txt" ]] && { -zuilog_counted_msg "${zui_log_colors[index]}" "$txt" "$line_var" $indent track_len || break; } - (( ++ index )) - done + index=2 + for txt in "${elems[@]}"; do + [[ -n "$txt" ]] && { -zuilog_counted_msg "${zui_log_colors[index]}" "$txt" "$line_var" $indent track_len || break; } + (( ++ index )) + done - # Return number of lines of the message - REPLY=$(( (msg_len-1)/(win_width-2*indent) + 1 )) + # Return number of lines of the message + REPLY=$(( (msg_len-1)/(win_width-2*indent) + 1 )) } local window="$1" @@ -147,34 +149,33 @@ zcurses clear "$window" local entry for entry in "${(@)ZUI_MESSAGES[start,last]}"; do - -zuilog_output_message "${ZUI[log_append]}" "line" "$entry" "$message_num" - (( message_num = message_num ? ++ message_num : 0 )) - - if [[ "${ZUI[log_append]}" = "below" ]]; then - (( ++ line )) - else - (( line = win_border )) - fi + -zuilog_output_message "${ZUI[log_append]}" "line" "$entry" "$message_num" + (( message_num = message_num ? ++ message_num : 0 )) + + if [[ "${ZUI[log_append]}" = "below" ]]; then + (( ++ line )) + else + (( line = win_border )) + fi done if [[ "${ZUI[status_pointer]}" = "1" ]]; then - if [[ "${ZUI[log_append]}" = "above" || $(( win_height - win_border - 1 )) -ge "$line" || "$REPLY" -ge $(( win_height - 2*win_border )) ]]; then - zcurses scroll "$window" -1 - fi + if [[ "${ZUI[log_append]}" = "above" || $(( win_height - win_border - 1 )) -ge "$line" || "$REPLY" -ge $(( win_height - 2*win_border )) ]]; then + zcurses scroll "$window" -1 + fi - zcurses move "$window" "$win_border" 2 - zcurses clear "$window" eol + zcurses move "$window" "$win_border" 2 + zcurses clear "$window" eol - local track_len=0 - line=0 + local track_len=0 + line=0 - if [[ -n "$_gen" ]]; then - -zuilog_counted_msg "yellow" "$_gen " line 2 track_len - else - for txt in $_uniq $_text $_grep; do - -zuilog_counted_msg "" "$txt " line 2 track_len - done - fi + if [[ -n "$_gen" ]]; then + -zuilog_counted_msg "yellow" "$_gen " line 2 track_len + else + for txt in $_uniq $_text $_grep; do + -zuilog_counted_msg "" "$txt " line 2 track_len + done + fi fi -# vim:ft=zsh diff --git a/zui.plugin.zsh b/zui.plugin.zsh index c0e98eb..25f45ea 100644 --- a/zui.plugin.zsh +++ b/zui.plugin.zsh @@ -17,6 +17,19 @@ typeset -gA Plugins Plugins[ZUI_DIR]="${0:h}" Plugins[ZUI_CONFIG_DIR]="${ZI[CONFIG_DIR]}/zui:-${XDG_CONFIG_HOME:-$HOME/.config}/zi/zui" +# Assign functions to Plugins array +typeset -a ZUI_FUNCTIONS ZUI_DEMO_FUNCTIONS +ZUI_FUNCTIONS=(${0:h}/functions/*) +ZUI_DEMO_FUNCTIONS=(${0:h}/demos/*) + +ZUI_FUNCTIONS=(${ZUI_FUNCTIONS#*functions/*}) +ZUI_DEMO_FUNCTIONS=(${ZUI_FUNCTIONS#*demos/*}) + +Plugins[ZUI_FUNCTIONS]=${ZUI_FUNCTIONS[@]} +Plugins[ZUI_DEMO_FUNCTIONS]=${ZUI_DEMO_FUNCTIONS[@]} + +unset ZUI_FUNCTIONS ZUI_DEMO_FUNCTIONS + # https://wiki.zshell.dev/community/zsh_plugin_standard#functions-directory if [[ $PMSPEC != *f* ]]; then fpath+=( "${0:h}/functions" ) @@ -30,10 +43,12 @@ fi # # Support reloading -(( ${+functions[zui-list]} )) && { unfunction -- zui-list zui-list-draw zui-list-input zui-list-wrapper -zui-log zui-event-loop -zui-list-box-loop zui-process-buffer zui-process-buffer2 zui-usetty-wrapper zui-demo-various zui-demo-hello-world zui-demo-text-fields zui-demo-fly zui-demo-append zui-demo-buttons zui-demo-anchors zui-demo-list-boxes zui-demo-history -zui_std_cleanup -zui_std_init 2>/dev/null; unset ZUI; } +(( ${+functions[zui-list]} )) && { + builtin unfunction ${Plugins[ZUI_FUNCTIONS]} ${Plugins[ZUI_DEMO_FUNCTIONS]} 2>/dev/null + unset ZUI +} -autoload -- zui-list zui-list-draw zui-list-input zui-list-wrapper -zui-log zui-event-loop -zui-list-box-loop -autoload -- zui-process-buffer zui-process-buffer2 zui-usetty-wrapper +builtin autoload -Uz ${Plugins[ZUI_FUNCTIONS]} # # Global parameters @@ -46,9 +61,7 @@ typeset -ga ZUI_MESSAGES if (( ZUI[DEMOS] )); then fpath+=( "${0:h}/demos" ) - autoload -- zui-demo-hello-world zui-demo-fly zui-demo-append zui-demo-text-fields zui-demo-list-boxes zui-demo-anchors - autoload -- zui-demo-ganchors zui-demo-buttons zui-demo-special-text zui-demo-history zui-demo-various zui-demo-timeout - autoload -- zui-demo-configure zui-demo-edit zui-demo-toggles zui-demo-nmap + builtin autoload -Uz ${Plugins[ZUI_DEMO_FUNCTIONS]} zle -N zui-demo-various bindkey "^O^Z" zui-demo-various @@ -72,9 +85,9 @@ zmodload zsh/datetime && ZUI[datetime_available]="1" || ZUI[datetime_available]= -zui_std_cleanup() { unfunction -- -zui_std_cleanup - [[ "${ZUI[stdlib_sourced]}" != "1" ]] && source "${Plugins[ZUI_DIR]}/lib/stdlib.lzui" - [[ "${ZUI[syslib_sourced]}" != "1" ]] && source "${Plugins[ZUI_DIR]}/lib/syslib.lzui" - [[ "${ZUI[utillib_sourced]}" != "1" ]] && source "${Plugins[ZUI_DIR]}/lib/utillib.lzui" + [[ "${ZUI[stdlib_sourced]}" != "1" ]] && builtin source "${Plugins[ZUI_DIR]}/lib/stdlib.lzui" + [[ "${ZUI[syslib_sourced]}" != "1" ]] && builtin source "${Plugins[ZUI_DIR]}/lib/syslib.lzui" + [[ "${ZUI[utillib_sourced]}" != "1" ]] && builtin source "${Plugins[ZUI_DIR]}/lib/utillib.lzui" -zui_std_cleanup "$@" } @@ -84,9 +97,9 @@ zmodload zsh/datetime && ZUI[datetime_available]="1" || ZUI[datetime_available]= -zui_std_init() { unfunction -- -zui_std_init - [[ "${ZUI[stdlib_sourced]}" != "1" ]] && source "${Plugins[ZUI_DIR]}/lib/stdlib.lzui" - [[ "${ZUI[syslib_sourced]}" != "1" ]] && source "${Plugins[ZUI_DIR]}/lib/syslib.lzui" - [[ "${ZUI[utillib_sourced]}" != "1" ]] && source "${Plugins[ZUI_DIR]}/lib/utillib.lzui" + [[ "${ZUI[stdlib_sourced]}" != "1" ]] && builtin source "${Plugins[ZUI_DIR]}/lib/stdlib.lzui" + [[ "${ZUI[syslib_sourced]}" != "1" ]] && builtin source "${Plugins[ZUI_DIR]}/lib/syslib.lzui" + [[ "${ZUI[utillib_sourced]}" != "1" ]] && builtin source "${Plugins[ZUI_DIR]}/lib/utillib.lzui" -zui_std_init "$@" }