1
0
mirror of https://github.com/UzixLS/picocom.git synced 2025-07-19 07:21:18 +03:00
Files
picocom/bash_completion/picocom
Nick Patavalis a6a7c70f1b Comments
2018-03-03 09:08:33 +02:00

399 lines
12 KiB
Plaintext

# Custom bash completion for picocom.
#
# Source this file like this:
# . <picocom-src-dir>/bash-completion/picocom
# Or arrange for it to be sourced by your ".bashrc",
# Or copy it in /etc/bash_completion.d (it will be sourced automatically)
#
# The idea is to provide simple custom completions for option names
# and option values, while keeping the standard ones (variable,
# pathname, etc) if the custom ones don't produce matches. This script
# does not depend on the "bash-completion" package (just plain bash)
# and it does not use any of its helper functions.
#
# The code is not bullet-proof; you *can* confuse it with strange
# input if you try.
#
# See also:
# Bash mapage (man bash)
# Bash reference manual, sections 8.6, 8.7, 8.8
# The bash-completion project / package
# https://github.com/scop/bash-completion
# https://debian-administration.org/article/
# 316/An_introduction_to_bash_completion_part_1
# https://debian-administration.org/article/
# 316/An_introduction_to_bash_completion_part_2
#
# Tested with:
# GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
# GNU bash, version 4.4.18(1)-release (x86_64-unknown-linux-gnu)
#
# by Nick Patavalis (npat@efault.net)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
#
# _picocom_split_line
#
# Splits line into words. Line is split in almost exatcly the same way
# as readline does it. Using this function, you can specify your own
# delimiter and separator characters without having to mess with
# COMP_WORDBREAKS (which may affect other completion functions /
# scripts). In addtion, this function takes into account COMP_POINT
# and splits up to it, which may help when completing to the middle of
# an argument.
#
# Line is split taking into account quoting (backslash, single and
# double), as well as ${...}, $(...), and backquoting. Double-quotes,
# ${..} and $(..} can nest inside each other at any depth (because
# that's how readline treats them when splitting).
#
# Words are broken-up either by delimiter characters (which do not
# appear in the resulting word-stream) or by separator characters,
# which do. Consequitive separator characters are treated as single
# word.
#
function _picocom_split_line()
{
local delimiters=$' \t\n'
local separators=$'=><'
local flag line wbreaks state word c c1 i
local -a stack
while getopts "d:s:" flag "$@"; do
case $flag in
d) delimiters=$OPTARG ;;
s) separators=$OPTARG ;;
esac
done
# state names: ' (single quote),
# " (double quote),
# { (string-brace),
# ( (string-paren)
# ` (backquote)
# D (delimiter)
# W (naked word)
#
# ", ${, and $( can nest inside each-other any number of times
wbreaks=$delimiters$separators
line=${COMP_LINE:0:$COMP_POINT}
state=D
for (( i=0; i<${#line}; i++)); do
c=${line:i:1}
c1=${line:i+1:1}
#echo " [$i\t$c\t$c1\t$state\t$word\t\t${stack[*]} ]" > $DEBUG
if [[ $state == D || $state == W ]]; then
if [[ $c == [$wbreaks] ]]; then
if [[ $state == W ]]; then
words+=( "$word" )
word=
state=D
fi
# handle separators
if [[ $c == [$separators] ]]; then
while [[ $c == [$separators] ]]; do
word+=$c
let i++
c=${line:i:1}
done
if [[ -n $c ]]; then
# emit word (but not at eol)
words+=( "$word" )
word=
fi
let i--
fi
continue
elif [[ $c == [\'\"\`] ]]; then
stack+=( W )
state=$c
elif [[ $c == '\' ]]; then
word+=$c
let i++
c=$c1
state=W
elif [[ $c == '$' && ( $c1 == '(' || $c1 == '{' ) ]]; then
word+=$c
let i++
c=$c1
stack+=( W )
state=$c1
else
state=W
fi
word+=$c
elif [[ $state == "'" ]]; then
if [[ $c == "'" ]]; then
state=${stack[-1]}
unset stack[-1]
fi
word+=$c
elif [[ $state == '`' ]]; then
if [[ $c == '\' ]]; then
word+=$c
let i++
c=$c1
elif [[ $c == '`' ]]; then
state=${stack[-1]}
unset stack[-1]
fi
word+=$c
elif [[ $state == '"' ]]; then
if [[ $c == '\' ]]; then
word+=$c
let i++
c=$c1
elif [[ $c == '`' ]]; then
stack+=( W )
state=$c
elif [[ $c == '$' && ( $c1 == '(' || $c1 == '{' ) ]]; then
let i++
word+=$c
c=$c1
stack+=( $state )
state=$c1
elif [[ $c == '"' ]]; then
state=${stack[-1]}
unset stack[-1]
fi
word+=$c
elif [[ $state == '(' || $state == '{' ]]; then
if [[ $c == [\'\"\`] ]]; then
stack+=( $state )
state=$c
elif [[ $c == '\' ]]; then
word+=$c
let i++
c=$c1
elif [[ $c == '$' && ( $c1 == '(' || $c1 == '{' ) ]]; then
let i++
word+=$c
c=$c1
stack+=( $state )
state=$c
elif [[ $state$c == '{}' || $state$c == "()" ]]; then
state=${stack[-1]}
unset stack[-1]
fi
word+=$c
fi
done
words+=( "$word" )
}
_picocom_dequote()
{
local quoted="$1"
local word i inside
for (( i=0; i<${#quoted}; i++ )); do
c=${quoted:i:1}
c1=${quoted:i+1:1}
#echo " [$c] [$c1] [$inside]" > $DEBUG
if [[ -z $inside ]]; then
if [[ $c == '\' ]]; then
let i++
c=$c1
elif [[ $c == [\'\"] ]]; then
inside=$c
continue
fi
elif [[ $inside == "'" ]]; then
if [[ $c == "'" ]]; then
inside=
continue
fi
elif [[ $inside == '"' ]]; then
if [[ $c == '\' ]]; then
let i++
c=$c1
elif [[ $c == '"' ]]; then
inside=
continue
fi
fi
word+=$c
done
echo "$word"
}
_picocom_filter_mappings()
{
local IFS cur1 m c found
local -a cura
cur1=$(_picocom_dequote "$cur")
IFS=$', \t'
cura=( $cur1 )
IFS=$' \t\n'
for m in "${mappings[@]}"; do
found=
for c in "${cura[@]}"; do
[[ $c == "$m" ]] && { found=yes; break; }
done
[[ -z $found ]] && mapfilt+=( "$m" )
done
}
# Check if $1 is valid picocom option name
_picocom_is_opt()
{
local e match="$1"
for e in "${opts[@]}"; do
[[ $e == "$match" ]] && return 0
done
return 1
}
# Custom completion function for picocom
_picocom()
{
local cur cur0 cur1 prev
local -a words opts baudrates mappings mapfilt
local DEBUG=/dev/pts/8
opts=( --baud --flow --databits --stopbits --parity \
--lower-rts --lower-dtr --raise-rts --raise-dtr \
--imap --omap --emap
--echo --initstring \
--noinit --noreset --hangup \
--receive-cmd --send-cmd \
--escape --no-escape \
--logfile \
--exit-after --exit \
--nolock \
--quiet --help \
)
baudrates=( 50 75 110 134 150 200 300 600 1200 1800 2400 4800 9600 \
19200 38400 57600 115200 \
230400 460800 500000 576000 921600 1000000 1152000 1500000 \
2000000 2500000 3000000 3500000 4000000 )
mappings=( crlf crcrlf igncr lfcr lfcrlf ignlf delbs bsdel \
spchex tabhex crhex lfhex 8bithex nrmhex )
# We split the line ourselves. We don't use COMP_WORDS
_picocom_split_line
cur="${words[-1]}"
prev="${words[-2]}"
echo > $DEBUG
echo "------------" > $DEBUG
echo COMP_LINE "$COMP_LINE" > $DEBUG
echo COMP_POINT $COMP_POINT > $DEBUG
local wrd
for wrd in "${words[@]}"; do
echo -n "$wrd | " > $DEBUG
done
echo > $DEBUG
echo "$prev | $cur | " > $DEBUG
# Handle option values given with "=" or "=="
if [[ $cur =~ "="+ ]]; then
_picocom_is_opt "$prev" && cur=
fi
if [[ $prev =~ "="+ ]]; then
_picocom_is_opt "${words[-3]}" && prev="${words[-3]}"
fi
case "$prev" in
-v | --receive-cmd | -s | --send-cmd)
# nothing special, just default completion
return 0
;;
-I | --imap | -O | --omap | -E | --emap )
[[ "$cur" =~ ^[\'\"]?[A-Za-z0-9,\ \\]*[\'\"]?$ ]] || return 0
_picocom_filter_mappings
cur1=${cur##*[, ]}
cur0=${cur%"$cur1"}
echo "$cur0 | $cur1 |" > $DEBUG
local IFS=$'\n'
COMPREPLY=( $(compgen -P "$cur0" -S "," -W "${mapfilt[*]}" -- "$cur1") )
echo "${COMPREPLY[*]}" > $DEBUG
if [[ ${#COMPREPLY[@]} -ne 0 ]]; then
compopt -o nospace
# This only works for bash-4.4 and newer
compopt -o nosort > /dev/null 2>&1
fi
return 0
;;
-e | --escape)
# nothing special, just default completion
return 0
;;
-f | --flow)
COMPREPLY=( $(compgen -W "hard soft none" -- "$cur") )
return 0
;;
-b | --baud)
COMPREPLY=( $(compgen -W "${baudrates[*]}" -- "$cur") )
if [[ ${#COMPREPLY[@]} -ne 0 ]]; then
# This only works for bash 4.4 and newer
compopt -o nosort > /dev/null 2>&1
fi
return 0
;;
-y | --parity)
COMPREPLY=( $(compgen -W "even odd none" -- "$cur") )
return 0
;;
-d | --databits)
COMPREPLY=( $(compgen -W "5 6 7 8" -- "$cur") )
return 0
;;
-p | --stopbits)
COMPREPLY=( $(compgen -W "1 2" -- "$cur") )
return 0
;;
-g | --logfile)
# nothing special, just default completion
return 0
;;
-t | --initstring)
# nothing special, just default completion
return 0
;;
-x | --exit-after)
# nothing special, just default completion
return 0
;;
*)
;;
esac
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts[*]}" -- "$cur") )
# This only works for bash 4.4 and newer
compopt -o nosort > /dev/null 2>&1
return 0
fi
if [[ -z $cur ]]; then
COMPREPLY=( $(compgen -G "/dev/tty*") )
return 0
fi
}
# Bind custom completion function to command
complete -o default -o bashdefault -F _picocom picocom
# Local variables:
# mode: sh
# End: