add fzf and change completion

This commit is contained in:
2022-04-18 19:19:25 -03:00
parent 3072128d31
commit c706ac893c
8 changed files with 171 additions and 227 deletions

View File

@ -30,6 +30,8 @@
information.
- Nodes can be stored on @folder or @subfolder@folder to organize your
devices. Then can be referenced using node@subfolder@folder or node@folder
- If you have too many nodes. Get completion script using: conn config
--completion, or use fzf installing pyfzf and running conn config --fzf true
- Much more!
</code></pre>
<h3 id="usage">Usage</h3>
@ -43,12 +45,12 @@ positional arguments:
Show all available connections globaly or in specified path
Options:
-h, --help show this help message and exit
-v, --version Show version
-a, --add Add new node[@subfolder][@folder] or [@subfolder]@folder
-r, --del, --rm Delete node[@subfolder][@folder] or [@subfolder]@folder
-e, --mod, --edit Modify node[@subfolder][@folder]
-s, --show Show node[@subfolder][@folder]
-d, --debug Display all conections steps
-v, --version Show version
Commands:
profile Manage profiles
@ -144,6 +146,8 @@ Connpy is a connection manager that allows you to store nodes to connect them fa
information.
- Nodes can be stored on @folder or @subfolder@folder to organize your
devices. Then can be referenced using node@subfolder@folder or node@folder
- If you have too many nodes. Get completion script using: conn config
--completion, or use fzf installing pyfzf and running conn config --fzf true
- Much more!
### Usage
@ -158,12 +162,12 @@ positional arguments:
Show all available connections globaly or in specified path
Options:
-h, --help show this help message and exit
-v, --version Show version
-a, --add Add new node[@subfolder][@folder] or [@subfolder]@folder
-r, --del, --rm Delete node[@subfolder][@folder] or [@subfolder]@folder
-e, --mod, --edit Modify node[@subfolder][@folder]
-s, --show Show node[@subfolder][@folder]
-d, --debug Display all conections steps
-v, --version Show version
Commands:
profile Manage profiles
@ -265,6 +269,7 @@ __all__ = [&#34;node&#34;, &#34;nodes&#34;, &#34;configfile&#34;, &#34;connapp&#
__author__ = &#34;Federico Luzzi&#34;
__pdoc__ = {
&#39;core&#39;: False,
&#39;completion&#39;: False,
}</code></pre>
</details>
</section>
@ -384,7 +389,7 @@ __pdoc__ = {
def _createconfig(self, conf):
#Create config file
defaultconfig = {&#39;config&#39;: {&#39;case&#39;: False, &#39;idletime&#39;: 30}, &#39;connections&#39;: {}, &#39;profiles&#39;: { &#34;default&#34;: { &#34;host&#34;:&#34;&#34;, &#34;protocol&#34;:&#34;ssh&#34;, &#34;port&#34;:&#34;&#34;, &#34;user&#34;:&#34;&#34;, &#34;password&#34;:&#34;&#34;, &#34;options&#34;:&#34;&#34;, &#34;logs&#34;:&#34;&#34; }}}
defaultconfig = {&#39;config&#39;: {&#39;case&#39;: False, &#39;idletime&#39;: 30, &#39;fzf&#39;: False}, &#39;connections&#39;: {}, &#39;profiles&#39;: { &#34;default&#34;: { &#34;host&#34;:&#34;&#34;, &#34;protocol&#34;:&#34;ssh&#34;, &#34;port&#34;:&#34;&#34;, &#34;user&#34;:&#34;&#34;, &#34;password&#34;:&#34;&#34;, &#34;options&#34;:&#34;&#34;, &#34;logs&#34;:&#34;&#34; }}}
if not os.path.exists(conf):
with open(conf, &#34;w&#34;) as f:
json.dump(defaultconfig, f, indent = 4)
@ -644,6 +649,10 @@ __pdoc__ = {
self.folders = self._getallfolders()
self.profiles = list(self.config.profiles.keys())
self.case = self.config.config[&#34;case&#34;]
try:
self.fzf = self.config.config[&#34;fzf&#34;]
except:
self.fzf = False
#DEFAULTPARSER
defaultparser = argparse.ArgumentParser(prog = &#34;conn&#34;, description = &#34;SSH and Telnet connection manager&#34;, formatter_class=argparse.RawTextHelpFormatter)
subparsers = defaultparser.add_subparsers(title=&#34;Commands&#34;)
@ -651,12 +660,12 @@ __pdoc__ = {
nodeparser = subparsers.add_parser(&#34;node&#34;,usage=self._help(&#34;usage&#34;), help=self._help(&#34;node&#34;),epilog=self._help(&#34;end&#34;), formatter_class=argparse.RawTextHelpFormatter)
nodecrud = nodeparser.add_mutually_exclusive_group()
nodeparser.add_argument(&#34;node&#34;, metavar=&#34;node|folder&#34;, nargs=&#39;?&#39;, default=None, action=self._store_type, type=self._type_node, help=self._help(&#34;node&#34;))
nodecrud.add_argument(&#34;-v&#34;,&#34;--version&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Show version&#34;, const=&#34;version&#34;, default=&#34;connect&#34;)
nodecrud.add_argument(&#34;-a&#34;,&#34;--add&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Add new node[@subfolder][@folder] or [@subfolder]@folder&#34;, const=&#34;add&#34;, default=&#34;connect&#34;)
nodecrud.add_argument(&#34;-r&#34;,&#34;--del&#34;, &#34;--rm&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Delete node[@subfolder][@folder] or [@subfolder]@folder&#34;, const=&#34;del&#34;, default=&#34;connect&#34;)
nodecrud.add_argument(&#34;-e&#34;,&#34;--mod&#34;, &#34;--edit&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Modify node[@subfolder][@folder]&#34;, const=&#34;mod&#34;, default=&#34;connect&#34;)
nodecrud.add_argument(&#34;-s&#34;,&#34;--show&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Show node[@subfolder][@folder]&#34;, const=&#34;show&#34;, default=&#34;connect&#34;)
nodecrud.add_argument(&#34;-d&#34;,&#34;--debug&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Display all conections steps&#34;, const=&#34;debug&#34;, default=&#34;connect&#34;)
nodecrud.add_argument(&#34;-v&#34;,&#34;--version&#34;, dest=&#34;action&#34;, action=&#34;store_const&#34;, help=&#34;Show version&#34;, const=&#34;version&#34;, default=&#34;connect&#34;)
nodeparser.set_defaults(func=self._func_node)
#PROFILEPARSER
profileparser = subparsers.add_parser(&#34;profile&#34;, help=&#34;Manage profiles&#34;)
@ -685,9 +694,11 @@ __pdoc__ = {
bulkparser.set_defaults(func=self._func_others)
#CONFIGPARSER
configparser = subparsers.add_parser(&#34;config&#34;, help=&#34;Manage app config&#34;)
configparser.add_argument(&#34;--allow-uppercase&#34;, dest=&#34;case&#34;, nargs=1, action=self._store_type, help=&#34;Allow case sensitive names&#34;, choices=[&#34;true&#34;,&#34;false&#34;])
configparser.add_argument(&#34;--keepalive&#34;, dest=&#34;idletime&#34;, nargs=1, action=self._store_type, help=&#34;Set keepalive time in seconds, 0 to disable&#34;, type=int, metavar=&#34;INT&#34;)
configparser.add_argument(&#34;--completion&#34;, dest=&#34;completion&#34;, nargs=1, choices=[&#34;bash&#34;,&#34;zsh&#34;], action=self._store_type, help=&#34;Get terminal completion configuration for conn&#34;)
configcrud = configparser.add_mutually_exclusive_group(required=True)
configcrud.add_argument(&#34;--allow-uppercase&#34;, dest=&#34;case&#34;, nargs=1, action=self._store_type, help=&#34;Allow case sensitive names&#34;, choices=[&#34;true&#34;,&#34;false&#34;])
configcrud.add_argument(&#34;--fzf&#34;, dest=&#34;fzf&#34;, nargs=1, action=self._store_type, help=&#34;Use fzf for lists&#34;, choices=[&#34;true&#34;,&#34;false&#34;])
configcrud.add_argument(&#34;--keepalive&#34;, dest=&#34;idletime&#34;, nargs=1, action=self._store_type, help=&#34;Set keepalive time in seconds, 0 to disable&#34;, type=int, metavar=&#34;INT&#34;)
configcrud.add_argument(&#34;--completion&#34;, dest=&#34;completion&#34;, nargs=1, choices=[&#34;bash&#34;,&#34;zsh&#34;], action=self._store_type, help=&#34;Get terminal completion configuration for conn&#34;)
configparser.set_defaults(func=self._func_others)
#Set default subparser and tune arguments
commands = [&#34;node&#34;, &#34;profile&#34;, &#34;mv&#34;, &#34;move&#34;,&#34;copy&#34;, &#34;cp&#34;, &#34;bulk&#34;, &#34;ls&#34;, &#34;list&#34;, &#34;config&#34;]
@ -1014,6 +1025,11 @@ __pdoc__ = {
args.data[0] = True
elif args.data[0] == &#34;false&#34;:
args.data[0] = False
if args.command == &#34;fzf&#34;:
if args.data[0] == &#34;true&#34;:
args.data[0] = True
elif args.data[0] == &#34;false&#34;:
args.data[0] = False
if args.command == &#34;idletime&#34;:
if args.data[0] &lt; 0:
args.data[0] = 0
@ -1023,12 +1039,20 @@ __pdoc__ = {
def _choose(self, list, name, action):
#Generates an inquirer list to pick
questions = [inquirer.List(name, message=&#34;Pick {} to {}:&#34;.format(name,action), choices=list, carousel=True)]
answer = inquirer.prompt(questions)
if answer == None:
return
if FzfPrompt and self.fzf:
fzf = FzfPrompt(executable_path=&#34;fzf-tmux&#34;)
answer = fzf.prompt(list, fzf_options=&#34;-d 25%&#34;)
if len(answer) == 0:
return
else:
return answer[0]
else:
return answer[name]
questions = [inquirer.List(name, message=&#34;Pick {} to {}:&#34;.format(name,action), choices=list, carousel=True)]
answer = inquirer.prompt(questions)
if answer == None:
return
else:
return answer[name]
def _host_validation(self, answers, current, regex = &#34;^.+$&#34;):
#Validate hostname in inquirer when managing nodes
@ -1299,121 +1323,28 @@ __pdoc__ = {
if type == &#34;bashcompletion&#34;:
return &#39;&#39;&#39;
#Here starts bash completion for conn
#You need jq installed in order to use this
_conn()
{
DATADIR=$HOME/.config/conn
command -v jq &gt;/dev/null 2&gt;&amp;1 &amp;&amp; {
mapfile -t connections &lt; &lt;(jq -r &#39; .[&#34;connections&#34;] | paths as $path | select(getpath($path) == &#34;connection&#34;) | $path | [map(select(. != &#34;type&#34;))[-1,-2,-3]] | map(select(. !=null)) | join(&#34;@&#34;)&#39; $DATADIR/config.json)
mapfile -t folders &lt; &lt;(jq -r &#39; .[&#34;connections&#34;] | paths as $path | select(getpath($path) == &#34;folder&#34; or getpath($path) == &#34;subfolder&#34;) | $path | [map(select(. != &#34;type&#34;))[-1,-2]] | map(select(. !=null)) | join(&#34;@&#34;)&#39; $DATADIR/config.json)
mapfile -t profiles &lt; &lt;(jq -r &#39;.[&#34;profiles&#34;] | keys[]&#39; $DATADIR/config.json)
}
if [ &#34;${#COMP_WORDS[@]}&#34; = &#34;2&#34; ]; then
strings=&#34;--add --del --rm --edit --mod --show mv move ls list cp copy profile bulk config --help&#34;
strings=&#34;$strings ${connections[@]} ${folders[@]/#/@}&#34;
COMPREPLY=($(compgen -W &#34;$strings&#34; -- &#34;${COMP_WORDS[1]}&#34;))
fi
if [ &#34;${#COMP_WORDS[@]}&#34; = &#34;3&#34; ]; then
strings=&#34;&#34;
if [ &#34;${COMP_WORDS[1]}&#34; = &#34;profile&#34; ]; then strings=&#34;--add --rm --del --edit --mod --show --help&#34;; fi
if [ &#34;${COMP_WORDS[1]}&#34; = &#34;config&#34; ]; then strings=&#34;--allow-uppercase --keepalive --completion --help&#34;; fi
if [[ &#34;${COMP_WORDS[1]}&#34; =~ --mod|--edit|-e|--show|-s|--add|-a|--rm|--del|-r ]]; then strings=&#34;profile&#34;; fi
if [[ &#34;${COMP_WORDS[1]}&#34; =~ list|ls ]]; then strings=&#34;profiles nodes folders&#34;; fi
if [[ &#34;${COMP_WORDS[1]}&#34; =~ bulk|mv|move|cp|copy ]]; then strings=&#34;--help&#34;; fi
if [[ &#34;${COMP_WORDS[1]}&#34; =~ --rm|--del|-r ]]; then strings=&#34;$strings ${folders[@]/#/@}&#34;; fi
if [[ &#34;${COMP_WORDS[1]}&#34; =~ --rm|--del|-r|--mod|--edit|-e|mv|move|cp|copy|--show|-s ]]; then
strings=&#34;$strings ${connections[@]}&#34;
fi
COMPREPLY=($(compgen -W &#34;$strings&#34; -- &#34;${COMP_WORDS[2]}&#34;))
fi
if [ &#34;${#COMP_WORDS[@]}&#34; = &#34;4&#34; ]; then
strings=&#34;&#34;
if [ &#34;${COMP_WORDS[1]}&#34; = &#34;profile&#34; ]; then
if [[ &#34;${COMP_WORDS[2]}&#34; =~ --rm|--del|-r|--mod|--edit|-e|--show|-s ]] ; then
strings=&#34;$strings ${profiles[@]}&#34;
fi
fi
if [ &#34;${COMP_WORDS[2]}&#34; = &#34;profile&#34; ]; then
if [[ &#34;${COMP_WORDS[1]}&#34; =~ --rm|--del|-r|--mod|--edit|-e|--show|-s ]] ; then
strings=&#34;$strings ${profiles[@]}&#34;
fi
fi
if [ &#34;${COMP_WORDS[1]}&#34; = &#34;config&#34; ]; then
if [[ &#34;${COMP_WORDS[2]}&#34; = &#34;--completion&#34; ]] ; then
strings=&#34;bash zsh&#34;
fi
fi
COMPREPLY=($(compgen -W &#34;$strings&#34; -- &#34;${COMP_WORDS[3]}&#34;))
fi
strings=&#34;$(connpy-completion-helper ${#COMP_WORDS[@]} ${COMP_WORDS[@]})&#34;
COMPREPLY=($(compgen -W &#34;$strings&#34; -- &#34;${COMP_WORDS[-1]}&#34;))
}
complete -o nosort -F _conn conn
complete -o nosort -F _conn connpy
#Here ends bash completion for conn
&#39;&#39;&#39;
if type == &#34;zshcompletion&#34;:
return &#39;&#39;&#39;
#Here starts zsh completion for conn
#You need jq installed in order to use this
#Here starts zsh completion for conn
autoload -U compinit &amp;&amp; compinit
_conn()
{
DATADIR=$HOME/.config/conn
local COMP_WORDS num
COMP_WORDS=( $words )
num=${#COMP_WORDS[@]}
if [[ $words =~ &#39;.* $&#39; ]]; then
num=$(($num + 1))
fi
command -v jq &gt;/dev/null 2&gt;&amp;1 &amp;&amp; {
x=`jq -r &#39; .[&#34;connections&#34;] | paths as $path | select(getpath($path) == &#34;connection&#34;) | $path | [map(select(. != &#34;type&#34;))[-1,-2,-3]] | map(select(. !=null)) | join(&#34;@&#34;)&#39; $DATADIR/config.json`
connections=( $x )
x=`jq -r &#39; .[&#34;connections&#34;] | paths as $path | select(getpath($path) == &#34;folder&#34; or getpath($path) == &#34;subfolder&#34;) | $path | [map(select(. != &#34;type&#34;))[-1,-2]] | map(select(. !=null)) | join(&#34;@&#34;)&#39; $DATADIR/config.json | sed -e &#39;s/^/@/&#39;`
folders=( $x )
x=`jq -r &#39;.[&#34;profiles&#34;] | keys[]&#39; $DATADIR/config.json`
profiles=( $x )
}
if [ &#34;${num}&#34; = &#34;2&#34; ]; then
strings=&#34;--add --del --rm --edit --mod --show mv move ls list cp copy profile bulk config --help&#34;
strings=&#34;$strings ${connections[@]} ${folders[@]}&#34;
compadd &#34;$@&#34; -- `echo $strings`
fi
if [ &#34;${num}&#34; = &#34;3&#34; ]; then
strings=&#34;&#34;
if [ &#34;${COMP_WORDS[2]}&#34; = &#34;profile&#34; ]; then strings=&#34;--add --rm --del --edit --mod --show --help&#34;; fi
if [ &#34;${COMP_WORDS[2]}&#34; = &#34;config&#34; ]; then strings=&#34;--allow-uppercase --keepalive --completion --help&#34;; fi
if [[ &#34;${COMP_WORDS[2]}&#34; =~ &#39;--mod|--edit|-e|--show|-s|--add|-a|--rm|--del|-r&#39; ]]; then strings=&#34;profile&#34;; fi
if [[ &#34;${COMP_WORDS[2]}&#34; =~ &#39;list|ls&#39; ]]; then strings=&#34;profiles nodes folders&#34;; fi
if [[ &#34;${COMP_WORDS[2]}&#34; =~ &#39;bulk|mv|move|cp|copy&#39; ]]; then strings=&#34;--help&#34;; fi
if [[ &#34;${COMP_WORDS[2]}&#34; =~ &#39;--rm|--del|-r&#39; ]]; then strings=&#34;$strings ${folders[@]}&#34;; fi
if [[ &#34;${COMP_WORDS[2]}&#34; =~ &#39;--rm|--del|-r|--mod|--edit|-e|mv|move|cp|copy|--show|-s&#39; ]]; then
strings=&#34;$strings ${connections[@]}&#34;
fi
compadd &#34;$@&#34; -- `echo $strings`
fi
if [ &#34;${num}&#34; = &#34;4&#34; ]; then
strings=&#34;&#34;
if [ &#34;${COMP_WORDS[2]}&#34; = &#34;profile&#34; ]; then
if [[ &#34;${COMP_WORDS[3]}&#34; =~ &#39;--rm|--del|-r|--mod|--edit|-e|--show|-s&#39; ]] ; then
strings=&#34;$strings ${profiles[@]}&#34;
fi
fi
if [ &#34;${COMP_WORDS[3]}&#34; = &#34;profile&#34; ]; then
if [[ &#34;${COMP_WORDS[2]}&#34; =~ &#39;--rm|--del|-r|--mod|--edit|-e|--show|-s&#39; ]] ; then
strings=&#34;$strings ${profiles[@]}&#34;
fi
fi
if [ &#34;${COMP_WORDS[2]}&#34; = &#34;config&#34; ]; then
if [[ &#34;${COMP_WORDS[3]}&#34; = &#39;--completion&#39; ]] ; then
strings=&#34;bash zsh&#34;
fi
fi
compadd &#34;$@&#34; -- `echo $strings`
fi
strings=($(connpy-completion-helper ${#words} $words))
compadd &#34;$@&#34; -- `echo $strings`
}
compdef _conn conn
compdef _conn connpy
#Here ends zsh completion for conn
&#39;&#39;&#39;
def _getallnodes(self):