Improve performance with single-pass awk implementation
This commit is contained in:
parent
6c297dee65
commit
e8c1e59e29
|
@ -1,7 +1,9 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
source $CURRENT_DIR/utils.sh
|
||||
|
||||
# TODO empty patterns are invalid
|
||||
function check_pattern() {
|
||||
echo "beep beep" | grep -e "$1" 2> /dev/null
|
||||
|
||||
|
@ -12,15 +14,31 @@ function check_pattern() {
|
|||
fi
|
||||
}
|
||||
|
||||
HAS_GAWK=$(which gawk &> /dev/null && echo $(($? == 0)))
|
||||
|
||||
function supports_intervals_in_awk() {
|
||||
echo "wtfwtfwtf" | __awk__ "/(wtf){3}/ { print \"wtf\" }" | grep -c wtf
|
||||
}
|
||||
|
||||
source "$CURRENT_DIR/utils.sh"
|
||||
|
||||
PATTERNS_LIST=(
|
||||
"((^|^\.|[[:space:]]|[[:space:]]\.|[[:space:]]\.\.|^\.\.)[[:alnum:]~_-]*/[][[:alnum:]_.#$%&+=/@-]*)"
|
||||
"([[:digit:]]{4,})"
|
||||
"([0-9a-f]{7}|[0-9a-f]{40})"
|
||||
"((https?://|git@|git://|ssh://|ftp://|file:///)[[:alnum:]?=%/_.:,;~@!#$&()*+-]*)"
|
||||
"([[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3})"
|
||||
)
|
||||
if [[ supports_intervals_in_awk == "1" ]]; then
|
||||
PATTERNS_LIST=(
|
||||
"((^|^\.|[[:space:]]|[[:space:]]\.|[[:space:]]\.\.|^\.\.)[[:alnum:]~_-]*/[][[:alnum:]_.#$%&+=/@-]*)"
|
||||
"([[:digit:]]{4,})"
|
||||
"([0-9a-f]{7}|[0-9a-f]{40})"
|
||||
"((https?://|git@|git://|ssh://|ftp://|file:///)[[:alnum:]?=%/_.:,;~@!#$&()*+-]*)"
|
||||
"([[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3})"
|
||||
)
|
||||
else
|
||||
PATTERNS_LIST=(
|
||||
"((^|^\.|[[:space:]]|[[:space:]]\.|[[:space:]]\.\.|^\.\.)[[:alnum:]~_-]*/[][[:alnum:]_.#$%&+=/@-]*)"
|
||||
"([[:digit:]][[:digit:]][[:digit:]][[:digit:]]([[:digit:]])*)"
|
||||
"([0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]|[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])"
|
||||
"((https?://|git@|git://|ssh://|ftp://|file:///)[[:alnum:]?=%/_.:,;~@!#$&()*+-]*)"
|
||||
"([[:digit:]][[:digit:]]?[[:digit:]]?\.[[:digit:]][[:digit:]]?[[:digit:]]?\.[[:digit:]][[:digit:]]?[[:digit:]]?\.[[:digit:]][[:digit:]]?[[:digit:]]?)"
|
||||
)
|
||||
fi
|
||||
|
||||
IFS=$'\n'
|
||||
USER_DEFINED_PATTERNS=($(tmux show-options -g | grep ^@fingers-pattern | sed 's/^@fingers-pattern-[0-9] "\(.*\)"$/(\1)/'))
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
|
||||
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
function current_ms() {
|
||||
echo $(($(date +%s%N)/1000000))
|
||||
}
|
||||
|
||||
function log() {
|
||||
echo "$1" >> "$CURRENT_DIR/../fingers.log"
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
source $CURRENT_DIR/config.sh
|
||||
source $CURRENT_DIR/actions.sh
|
||||
source $CURRENT_DIR/hints.sh
|
||||
source $CURRENT_DIR/utils.sh
|
||||
|
||||
LOG_PATH=$CURRENT_DIR/../fingers.log
|
||||
FINGERS_COPY_COMMAND=$(tmux show-option -gqv @fingers-copy-command)
|
||||
|
||||
current_pane_id=$1
|
||||
|
@ -14,15 +16,6 @@ tmp_path=$3
|
|||
|
||||
BACKSPACE=$'\177'
|
||||
|
||||
function clear_screen() {
|
||||
clear
|
||||
tmux clearhist -t "$fingers_pane_id"
|
||||
}
|
||||
|
||||
function has_capitals() {
|
||||
echo "$1" | grep -c "[A-Z]"
|
||||
}
|
||||
|
||||
function is_pane_zoomed() {
|
||||
local pane_id=$1
|
||||
|
||||
|
@ -37,12 +30,6 @@ function zoom_pane() {
|
|||
tmux resize-pane -Z -t "$pane_id"
|
||||
}
|
||||
|
||||
clear_screen
|
||||
print_hints
|
||||
pane_was_zoomed=$(is_pane_zoomed "$current_pane_id")
|
||||
tmux swap-pane -s "$current_pane_id" -t "$fingers_pane_id"
|
||||
[[ $pane_was_zoomed == "1" ]] && zoom_pane "$fingers_pane_id"
|
||||
|
||||
function handle_exit() {
|
||||
tmux swap-pane -s "$current_pane_id" -t "$fingers_pane_id"
|
||||
[[ $pane_was_zoomed == "1" ]] && zoom_pane "$current_pane_id"
|
||||
|
@ -68,20 +55,6 @@ function copy_result() {
|
|||
fi
|
||||
}
|
||||
|
||||
function sanitize_input() {
|
||||
local input=$(echo "$(str_to_ascii "$1")" | sed -r "s/ 27 91 [0-9]{2}//")
|
||||
local sanitized=''
|
||||
|
||||
OLDIFS=$IFS
|
||||
IFS=' '
|
||||
for char_code in $input; do
|
||||
sanitized="${sanitized}$(chr "$char_code")"
|
||||
done
|
||||
IFS=$OLDIFS
|
||||
|
||||
echo "$sanitized"
|
||||
}
|
||||
|
||||
function is_valid_input() {
|
||||
local input=$1
|
||||
local is_valid=1
|
||||
|
@ -98,10 +71,18 @@ function is_valid_input() {
|
|||
echo $is_valid
|
||||
}
|
||||
|
||||
function hide_cursor() {
|
||||
echo -n $(tput civis)
|
||||
}
|
||||
|
||||
trap "handle_exit" EXIT
|
||||
|
||||
input=''
|
||||
pane_was_zoomed=$(is_pane_zoomed "$current_pane_id")
|
||||
show_hints_and_swap $current_pane_id $fingers_pane_id
|
||||
[[ $pane_was_zoomed == "1" ]] && zoom_pane "$fingers_pane_id"
|
||||
|
||||
hide_cursor
|
||||
input=''
|
||||
while read -rsn1 char; do
|
||||
# Escape sequence, flush input
|
||||
if [[ "$char" == $'\x1b' ]]; then
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
BEGIN {
|
||||
n_matches = 0;
|
||||
line_pos = 0;
|
||||
col_pos = 0;
|
||||
|
||||
HINTS[0] = "p"
|
||||
HINTS[1] = "o"
|
||||
HINTS[2] = "i"
|
||||
HINTS[3] = "u"
|
||||
HINTS[4] = "l"
|
||||
HINTS[5] = "k"
|
||||
HINTS[6] = "j"
|
||||
HINTS[7] = "t"
|
||||
HINTS[8] = "r"
|
||||
HINTS[9] = "e"
|
||||
HINTS[10] = "wj"
|
||||
HINTS[11] = "wt"
|
||||
HINTS[12] = "wr"
|
||||
HINTS[13] = "we"
|
||||
HINTS[14] = "ww"
|
||||
HINTS[15] = "wq"
|
||||
HINTS[16] = "wf"
|
||||
HINTS[17] = "wd"
|
||||
HINTS[18] = "ws"
|
||||
HINTS[19] = "wa"
|
||||
HINTS[20] = "qp"
|
||||
HINTS[21] = "qo"
|
||||
HINTS[22] = "qi"
|
||||
HINTS[23] = "qu"
|
||||
HINTS[24] = "ql"
|
||||
HINTS[25] = "qk"
|
||||
HINTS[26] = "qj"
|
||||
HINTS[27] = "qt"
|
||||
HINTS[28] = "qr"
|
||||
HINTS[29] = "qe"
|
||||
HINTS[30] = "qw"
|
||||
HINTS[31] = "qq"
|
||||
HINTS[32] = "qf"
|
||||
HINTS[33] = "qd"
|
||||
HINTS[34] = "qs"
|
||||
HINTS[35] = "qa"
|
||||
HINTS[36] = "fp"
|
||||
HINTS[37] = "fo"
|
||||
HINTS[38] = "fi"
|
||||
HINTS[39] = "fu"
|
||||
HINTS[40] = "fl"
|
||||
HINTS[41] = "fk"
|
||||
HINTS[42] = "fj"
|
||||
HINTS[43] = "ft"
|
||||
HINTS[44] = "fr"
|
||||
HINTS[45] = "fe"
|
||||
HINTS[46] = "fw"
|
||||
HINTS[47] = "fq"
|
||||
HINTS[48] = "ff"
|
||||
HINTS[49] = "fd"
|
||||
HINTS[50] = "fs"
|
||||
HINTS[51] = "fa"
|
||||
HINTS[52] = "dp"
|
||||
HINTS[53] = "do"
|
||||
HINTS[54] = "di"
|
||||
HINTS[55] = "du"
|
||||
HINTS[56] = "dl"
|
||||
HINTS[57] = "dk"
|
||||
HINTS[58] = "dj"
|
||||
HINTS[59] = "dt"
|
||||
HINTS[60] = "dr"
|
||||
HINTS[61] = "de"
|
||||
HINTS[62] = "dw"
|
||||
HINTS[63] = "dq"
|
||||
HINTS[64] = "df"
|
||||
HINTS[65] = "dd"
|
||||
HINTS[66] = "ds"
|
||||
HINTS[67] = "da"
|
||||
HINTS[68] = "sp"
|
||||
HINTS[69] = "so"
|
||||
HINTS[70] = "si"
|
||||
HINTS[71] = "su"
|
||||
HINTS[72] = "sl"
|
||||
HINTS[73] = "sk"
|
||||
HINTS[74] = "sj"
|
||||
HINTS[75] = "st"
|
||||
HINTS[76] = "sr"
|
||||
HINTS[77] = "se"
|
||||
HINTS[78] = "sw"
|
||||
HINTS[79] = "sq"
|
||||
HINTS[80] = "sf"
|
||||
HINTS[81] = "sd"
|
||||
HINTS[82] = "ss"
|
||||
HINTS[83] = "sa"
|
||||
HINTS[84] = "ap"
|
||||
HINTS[85] = "ao"
|
||||
HINTS[86] = "ai"
|
||||
HINTS[87] = "au"
|
||||
HINTS[88] = "al"
|
||||
HINTS[89] = "ak"
|
||||
HINTS[90] = "aj"
|
||||
HINTS[91] = "at"
|
||||
HINTS[92] = "ar"
|
||||
HINTS[93] = "ae"
|
||||
HINTS[94] = "aw"
|
||||
HINTS[95] = "aq"
|
||||
HINTS[96] = "af"
|
||||
HINTS[97] = "ad"
|
||||
HINTS[98] = "as"
|
||||
HINTS[99] = "aa"
|
||||
|
||||
finger_patterns = ENVIRON["FINGER_PATTERNS"];
|
||||
|
||||
hint_format = "\033[1;33m[%s]\033[0m"
|
||||
highlight_format = "\033[1;33m%s\033[0m "
|
||||
printf "%s\n", finger_patterns | "cat 1>&4"
|
||||
}
|
||||
|
||||
{
|
||||
line = $0;
|
||||
pos = 0;
|
||||
col_pos = 0;
|
||||
col_pos_correction = 0;
|
||||
|
||||
output_line = line;
|
||||
|
||||
while (match(line, finger_patterns)) {
|
||||
n_matches += 1;
|
||||
|
||||
hint = HINTS[n_matches - 1]
|
||||
pos += RSTART;
|
||||
|
||||
col_pos = pos;
|
||||
line_match = substr(line, RSTART, RLENGTH);
|
||||
|
||||
col_pos = col_pos + col_pos_correction
|
||||
|
||||
line_pos = NR;
|
||||
|
||||
pre_match = substr(output_line, 0, col_pos - 1);
|
||||
hint_match = sprintf(highlight_format hint_format, line_match, hint);
|
||||
post_match = substr(output_line, col_pos + RLENGTH, length(line) - 1);
|
||||
|
||||
output_line = pre_match hint_match post_match;
|
||||
|
||||
line = post_match;
|
||||
|
||||
col_pos_correction += (length(sprintf(highlight_format, line_match)) - 1 + length(sprintf(hint_format, hint)) - 1) + 1;
|
||||
|
||||
printf hint ":" line_match "\n" | "cat 1>&3"
|
||||
}
|
||||
|
||||
printf "\n%s", output_line
|
||||
}
|
|
@ -1,68 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
source $CURRENT_DIR/utils.sh
|
||||
|
||||
MATCH_PARSER="\([0-9]*\):\(.*\)"
|
||||
match_lookup_table=$(fingers_tmp)
|
||||
|
||||
HINTS=(p o i u l k j t r e wj wt wr we ww wq wf wd ws wa qp qo qi qu ql qk qj qt qr qe qw qq qf qd qs qa fp fo fi fu fl fk fj ft fr fe fw fq ff fd fs fa dp do di du dl dk dj dt dr de dw dq df dd ds da sp so si su sl sk sj st sr se sw sq sf sd ss sa ap ao ai au al ak aj at ar ae aw aq af ad as aa)
|
||||
match_lookup_table=''
|
||||
|
||||
declare -A match_lookup_table
|
||||
|
||||
function get_hint() {
|
||||
echo "${HINTS[$1]}"
|
||||
}
|
||||
|
||||
function highlight() {
|
||||
printf "\033[1;33m%s\033[0m" "$1"
|
||||
function clear_screen() {
|
||||
local fingers_pane_id=$1
|
||||
clear
|
||||
tmux clearhist -t $fingers_pane_id
|
||||
}
|
||||
|
||||
function lookup_match() {
|
||||
local input=$1
|
||||
echo ${match_lookup_table[$input]}
|
||||
echo "$(cat $match_lookup_table | grep "^$input:" | sed "s/^$input://")"
|
||||
}
|
||||
|
||||
lines=''
|
||||
OLDIFS=$IFS
|
||||
IFS=
|
||||
while read -r line
|
||||
do
|
||||
lines+="$line\n"
|
||||
done < /dev/stdin
|
||||
IFS=$OLDIFS
|
||||
|
||||
# POSIX grep does linenumber on every line with both -o and -n flags set
|
||||
normalize_grep_output='
|
||||
BEGIN {
|
||||
previous_line_no = 0;
|
||||
}
|
||||
{
|
||||
if ( $0 ~ /^[0-9]+:/ ) {
|
||||
split($0, split_at_colon, ":")
|
||||
previous_line_no = split_at_colon[1]
|
||||
print $0
|
||||
} else {
|
||||
printf "%d:%s\n", previous_line_no, $0
|
||||
}
|
||||
}
|
||||
'
|
||||
matches=$(echo -e $lines | (grep -oniE "$PATTERNS" 2> /dev/null) | awk $normalize_grep_output | sort -u)
|
||||
output="$lines"
|
||||
i=0
|
||||
|
||||
OLDIFS=$IFS
|
||||
IFS=$(echo -en "\n\b") # wtf bash?
|
||||
for match in $matches ; do
|
||||
hint=$(get_hint $i)
|
||||
linenumber=$(echo $match | sed "s!${MATCH_PARSER//!\\!}!\1!")
|
||||
text=$(echo $match | sed "s!${MATCH_PARSER//!\\!}!\2!")
|
||||
|
||||
output=$(echo -ne "$output" | sed "${linenumber}s!${text//!/\\!}!$(highlight ${text//!/\\!}) $(highlight "[${hint//!/\\!}]")!g")
|
||||
match_lookup_table[$hint]=$text
|
||||
i=$((i + 1))
|
||||
done
|
||||
IFS=$OLDIFS
|
||||
|
||||
function print_hints() {
|
||||
echo -ne "$output"
|
||||
function show_hints_and_swap() {
|
||||
current_pane_id=$1
|
||||
fingers_pane_id=$2
|
||||
tmux swap-pane -s "$current_pane_id" -t "$fingers_pane_id"
|
||||
clear_screen "$fingers_pane_id"
|
||||
cat | FINGER_PATTERNS=$PATTERNS __awk__ -f $CURRENT_DIR/hinter.awk 3> $match_lookup_table 4>> $CURRENT_DIR/../fingers.log
|
||||
cat $match_lookup_table >> $CURRENT_DIR/../fingers.log
|
||||
}
|
||||
|
|
|
@ -33,8 +33,7 @@ function capture_pane() {
|
|||
function prompt_fingers_for_pane() {
|
||||
local current_pane_id=$1
|
||||
local fingers_pane_id=$(init_fingers_pane)
|
||||
local tmp_path=$(mktemp "${TMPDIR:-/tmp}/tmux-fingers.XXXXXXXX")
|
||||
chmod 600 "$tmp_path"
|
||||
local tmp_path=$(fingers_tmp)
|
||||
|
||||
wait
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
CURRENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
#TODO split all this crap in lib/ folder
|
||||
|
||||
function array_join() {
|
||||
local IFS="$1"; shift; echo "$*";
|
||||
|
@ -80,3 +80,17 @@ function pane_exec() {
|
|||
tmux send-keys -t $pane_id " $pane_command"
|
||||
tmux send-keys -t $pane_id Enter
|
||||
}
|
||||
|
||||
function fingers_tmp() {
|
||||
local tmp_path=$(mktemp "${TMPDIR:-/tmp}/tmux-fingers.XXXXXXXX")
|
||||
chmod 600 "$tmp_path"
|
||||
echo "$tmp_path"
|
||||
}
|
||||
|
||||
function __awk__() {
|
||||
if hash gawk 2>/dev/null; then
|
||||
gawk "$@"
|
||||
else
|
||||
awk "$@"
|
||||
fi
|
||||
}
|
||||
|
|
|
@ -1,18 +1,26 @@
|
|||
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
|
||||
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
inet 127.0.0.1 scope host lo
|
||||
inet 127.0.0.1/8 scope host lo
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 ::1 scope host
|
||||
inet6 ::1/128 scope host
|
||||
valid_lft forever preferred_lft forever
|
||||
2: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
|
||||
link/ether 78:31:c1:d5:40:ce brd ff:ff:ff:ff:ff:ff
|
||||
inet 192.168.1.39 brd 192.168.1.255 scope global dynamic wlp3s0
|
||||
valid_lft 33919sec preferred_lft 33919sec
|
||||
inet6 fe80::7a31:c1ff:fed5:40ce scope link tentative dadfailed
|
||||
inet 192.168.1.33/24 brd 192.168.1.255 scope global dynamic wlp3s0
|
||||
valid_lft 40162sec preferred_lft 40162sec
|
||||
inet6 fe80::7a31:c1ff:fed5:40ce/64 scope link tentative dadfailed
|
||||
valid_lft forever preferred_lft forever
|
||||
3: vboxnet0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
|
||||
3: br0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
|
||||
link/ether 46:06:f6:15:ea:fb brd ff:ff:ff:ff:ff:ff
|
||||
inet 10.0.3.1/24 brd 10.0.3.255 scope global br0
|
||||
valid_lft forever preferred_lft forever
|
||||
4: vboxnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
|
||||
link/ether 0a:00:27:00:00:00 brd ff:ff:ff:ff:ff:ff
|
||||
inet 10.0.1.1 brd 10.0.1.255 scope global vboxnet0
|
||||
inet 10.0.1.1/24 brd 10.0.1.255 scope global vboxnet0
|
||||
valid_lft forever preferred_lft forever
|
||||
inet6 fe80::800:27ff:fe00:0 scope link
|
||||
inet6 fe80::800:27ff:fe00:0/64 scope link
|
||||
valid_lft forever preferred_lft forever
|
||||
5: vboxnet1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
|
||||
link/ether 0a:00:27:00:00:01 brd ff:ff:ff:ff:ff:ff
|
||||
6: vboxnet2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000
|
||||
link/ether 0a:00:27:00:00:02 brd ff:ff:ff:ff:ff:ff
|
||||
|
|
|
@ -31,7 +31,7 @@ proc init_pane {} {
|
|||
|
||||
proc invoke_fingers {} {
|
||||
tmux_send "F";
|
||||
sleep 0.5;
|
||||
sleep 1.0;
|
||||
}
|
||||
|
||||
proc echo_yanked {} {
|
||||
|
@ -39,6 +39,7 @@ proc echo_yanked {} {
|
|||
send "echo yanked text is ";
|
||||
tmux_send "]";
|
||||
send "\r";
|
||||
sleep 0.5;
|
||||
}
|
||||
|
||||
proc exit_ok {} {
|
||||
|
|
|
@ -12,11 +12,11 @@ sleep 0.5;
|
|||
init_pane
|
||||
exec "cat ./test/fixtures/ip-output";
|
||||
invoke_fingers;
|
||||
send "t";
|
||||
send "r";
|
||||
echo_yanked;
|
||||
|
||||
expect {
|
||||
"yanked text is 10.0.1.255" { exit_ok }
|
||||
"yanked text is 192.168.1.33" { exit_ok }
|
||||
timeout { exit_fail }
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue