forked from extern/httpie-cli
Implement support for bash & completion flow generation
This commit is contained in:
parent
b8e0be241c
commit
ee5fc59c51
53
extras/completion/completion.bash
Normal file
53
extras/completion/completion.bash
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
METHODS=("GET" "POST" "PUT" "DELETE" "HEAD" "OPTIONS" "PATCH" "TRACE" "CONNECT" )
|
||||||
|
NORMARG=1 # TO-DO: dynamically calculate this?
|
||||||
|
|
||||||
|
_http_complete() {
|
||||||
|
local cur_word=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
local prev_word=${COMP_WORDS[COMP_CWORD - 1]}
|
||||||
|
|
||||||
|
if [[ "$cur_word" == -* ]]; then
|
||||||
|
_http_complete_options "$cur_word"
|
||||||
|
else
|
||||||
|
if (( COMP_CWORD == NORMARG + 0 )); then
|
||||||
|
_http_complete_methods "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD == NORMARG + 0 )); then
|
||||||
|
_http_complete_url "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD == NORMARG + 1 )) && [[ " ${METHODS[*]} " =~ " ${prev_word} " ]]; then
|
||||||
|
_http_complete_url "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD >= NORMARG + 2 )); then
|
||||||
|
_httpie_complete_request_item "$cur_word"
|
||||||
|
fi
|
||||||
|
if (( COMP_CWORD >= NORMARG + 1 )) && ! [[ " ${METHODS[*]} " =~ " ${prev_word} " ]]; then
|
||||||
|
_httpie_complete_request_item "$cur_word"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -o default -F _http_complete http httpie.http httpie.https https
|
||||||
|
|
||||||
|
_http_complete_methods() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="GET POST PUT DELETE HEAD OPTIONS PATCH TRACE CONNECT"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_url() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="http:// https://"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_complete_request_item() {
|
||||||
|
local cur_word=$1
|
||||||
|
COMPREPLY+=("==" "=" ":=" ":=@")
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_options() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="--json -j --form -f --multipart --boundary --raw --compress -x --pretty --style -s --unsorted --sorted --response-charset --response-mime --format-options --print -p --headers -h --meta -m --body -b --verbose -v --all --stream -S --output -o --download -d --continue -c --quiet -q --session --session-read-only --auth -a --auth-type -A --ignore-netrc --offline --proxy --follow -F --max-redirects --max-headers --timeout --check-status --path-as-is --chunked --verify --ssl --ciphers --cert --cert-key --cert-key-pass --ignore-stdin -I --help --manual --version --traceback --default-scheme --debug "
|
||||||
|
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
@ -27,6 +27,7 @@ fi
|
|||||||
if (( CURRENT >= NORMARG + 1 )) && ! [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
if (( CURRENT >= NORMARG + 1 )) && ! [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||||
_httpie_request_item && ret=0
|
_httpie_request_item && ret=0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return $ret
|
return $ret
|
||||||
|
40
extras/completion/templates/completion.bash.j2
Normal file
40
extras/completion/templates/completion.bash.j2
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
METHODS=({% for method in methods -%} "{{ method }}" {% endfor -%})
|
||||||
|
NORMARG=1 # TO-DO: dynamically calculate this?
|
||||||
|
|
||||||
|
_http_complete() {
|
||||||
|
local cur_word=${COMP_WORDS[COMP_CWORD]}
|
||||||
|
local prev_word=${COMP_WORDS[COMP_CWORD - 1]}
|
||||||
|
|
||||||
|
if [[ "$cur_word" == -* ]]; then
|
||||||
|
_http_complete_options "$cur_word"
|
||||||
|
else
|
||||||
|
{% for flow_item in generate_flow() -%}
|
||||||
|
{{ compile_bash(flow_item) | indent(width=8) }}
|
||||||
|
{% endfor %}
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
complete -o default -F _http_complete http httpie.http httpie.https https
|
||||||
|
|
||||||
|
_http_complete_methods() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="{{' '.join(methods)}}"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_url() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="http:// https://"
|
||||||
|
COMPREPLY+=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
||||||
|
|
||||||
|
_httpie_complete_request_item() {
|
||||||
|
local cur_word=$1
|
||||||
|
COMPREPLY+=("==" "=" ":=" ":=@")
|
||||||
|
}
|
||||||
|
|
||||||
|
_http_complete_options() {
|
||||||
|
local cur_word=$1
|
||||||
|
local options="{% for argument in arguments -%} {{ ' '.join(argument.aliases) }} {% endfor -%}"
|
||||||
|
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
|
||||||
|
}
|
@ -13,8 +13,8 @@ _httpie_params () {
|
|||||||
|
|
||||||
if ! [[ $current == -* ]]; then
|
if ! [[ $current == -* ]]; then
|
||||||
{% for flow_item in generate_flow() -%}
|
{% for flow_item in generate_flow() -%}
|
||||||
{{ compile_zsh(flow_item) }}
|
{{ compile_zsh(flow_item) | indent(width=8) }}
|
||||||
{% endfor -%}
|
{% endfor %}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return $ret
|
return $ret
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
_http_complete() {
|
|
||||||
local cur_word=${COMP_WORDS[COMP_CWORD]}
|
|
||||||
local prev_word=${COMP_WORDS[COMP_CWORD - 1]}
|
|
||||||
|
|
||||||
if [[ "$cur_word" == -* ]]; then
|
|
||||||
_http_complete_options "$cur_word"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
complete -o default -F _http_complete http httpie.http httpie.https https
|
|
||||||
|
|
||||||
_http_complete_options() {
|
|
||||||
local cur_word=$1
|
|
||||||
local options="-j --json -f --form --pretty -s --style -p --print
|
|
||||||
-v --verbose -h --headers -b --body -S --stream -o --output -d --download
|
|
||||||
-c --continue --session --session-read-only -a --auth --auth-type --proxy
|
|
||||||
--follow --verify --cert --cert-key --timeout --check-status --ignore-stdin
|
|
||||||
--help --version --traceback --debug --raw"
|
|
||||||
COMPREPLY=( $( compgen -W "$options" -- "$cur_word" ) )
|
|
||||||
}
|
|
83
extras/scripts/completion/bash.py
Normal file
83
extras/scripts/completion/bash.py
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
from enum import Enum
|
||||||
|
from functools import singledispatch
|
||||||
|
|
||||||
|
from completion_flow import (
|
||||||
|
And,
|
||||||
|
Check,
|
||||||
|
Condition,
|
||||||
|
If,
|
||||||
|
Node,
|
||||||
|
Not,
|
||||||
|
Suggest,
|
||||||
|
Suggestion,
|
||||||
|
Variable,
|
||||||
|
generate_flow,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class BashVariable(str, Enum):
|
||||||
|
CURRENT = 'COMP_CWORD'
|
||||||
|
NORMARG = 'NORMARG'
|
||||||
|
CURRENT_WORD = 'cur_word'
|
||||||
|
PREDECESSOR = 'prev_word'
|
||||||
|
METHODS = 'METHODS'
|
||||||
|
|
||||||
|
|
||||||
|
SUGGESTION_TO_FUNCTION = {
|
||||||
|
Suggestion.METHOD: '_http_complete_methods',
|
||||||
|
Suggestion.URL: '_http_complete_url',
|
||||||
|
Suggestion.REQUEST_ITEM: '_httpie_complete_request_item',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@singledispatch
|
||||||
|
def compile_bash(node: Node) -> ...:
|
||||||
|
raise NotImplementedError(f'{type(node)} is not supported')
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(If)
|
||||||
|
def compile_if(node: If) -> str:
|
||||||
|
check = compile_bash(node.check)
|
||||||
|
action = compile_bash(node.action)
|
||||||
|
return f'if {check}; then\n {action}\nfi'
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(Check)
|
||||||
|
def compile_check(node: Check) -> str:
|
||||||
|
args = [
|
||||||
|
BashVariable(arg.name) if isinstance(arg, Variable) else arg
|
||||||
|
for arg in node.args
|
||||||
|
]
|
||||||
|
|
||||||
|
if node.condition is Condition.POSITION_EQ:
|
||||||
|
return f'(( {BashVariable.CURRENT} == {BashVariable.NORMARG} + {args[0]} ))'
|
||||||
|
elif node.condition is Condition.POSITION_GE:
|
||||||
|
return f'(( {BashVariable.CURRENT} >= {BashVariable.NORMARG} + {args[0]} ))'
|
||||||
|
elif node.condition is Condition.CONTAINS_PREDECESSOR:
|
||||||
|
parts = [
|
||||||
|
'[[ ',
|
||||||
|
'" ${',
|
||||||
|
BashVariable.METHODS,
|
||||||
|
'[*]} " =~ " ${',
|
||||||
|
BashVariable.PREDECESSOR,
|
||||||
|
'} " ]]',
|
||||||
|
]
|
||||||
|
return ''.join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(And)
|
||||||
|
def compile_and(node: And) -> str:
|
||||||
|
return ' && '.join(compile_bash(check) for check in node.checks)
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(Not)
|
||||||
|
def compile_not(node: Not) -> str:
|
||||||
|
return f'! {compile_bash(node.check)}'
|
||||||
|
|
||||||
|
|
||||||
|
@compile_bash.register(Suggest)
|
||||||
|
def compile_suggest(node: Suggest) -> str:
|
||||||
|
return (
|
||||||
|
SUGGESTION_TO_FUNCTION[node.suggestion]
|
||||||
|
+ f' "${BashVariable.CURRENT_WORD}"'
|
||||||
|
)
|
@ -1,6 +1,6 @@
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from typing import List, Iterator
|
from typing import Iterator, List
|
||||||
|
|
||||||
|
|
||||||
class Condition(Enum):
|
class Condition(Enum):
|
||||||
|
@ -1,18 +1,17 @@
|
|||||||
from atexit import register
|
|
||||||
import functools
|
import functools
|
||||||
import string
|
import string
|
||||||
import textwrap
|
import textwrap
|
||||||
|
from atexit import register
|
||||||
from jinja2 import Template
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Callable, TypeVar
|
from typing import Any, Callable, Dict, TypeVar
|
||||||
|
|
||||||
|
from completion_flow import generate_flow
|
||||||
|
from jinja2 import Template
|
||||||
|
|
||||||
from httpie.cli.constants import SEPARATOR_FILE_UPLOAD
|
from httpie.cli.constants import SEPARATOR_FILE_UPLOAD
|
||||||
from httpie.cli.definition import options
|
from httpie.cli.definition import options
|
||||||
from httpie.cli.options import Argument, ParserSpec
|
from httpie.cli.options import Argument, ParserSpec
|
||||||
|
|
||||||
from completion_flow import generate_flow
|
|
||||||
|
|
||||||
T = TypeVar('T')
|
T = TypeVar('T')
|
||||||
|
|
||||||
EXTRAS_DIR = Path(__file__).parent.parent.parent
|
EXTRAS_DIR = Path(__file__).parent.parent.parent
|
||||||
@ -202,7 +201,7 @@ def zsh_completer(spec: ParserSpec) -> Dict[str, Any]:
|
|||||||
return {
|
return {
|
||||||
'escape_zsh': escape_zsh,
|
'escape_zsh': escape_zsh,
|
||||||
'serialize_argument_to_zsh': serialize_argument_to_zsh,
|
'serialize_argument_to_zsh': serialize_argument_to_zsh,
|
||||||
'compile_zsh': compile_zsh
|
'compile_zsh': compile_zsh,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -213,6 +212,15 @@ def fish_completer(spec: ParserSpec) -> Dict[str, Any]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@use_template('bash')
|
||||||
|
def fish_completer(spec: ParserSpec) -> Dict[str, Any]:
|
||||||
|
from bash import compile_bash
|
||||||
|
|
||||||
|
return {
|
||||||
|
'compile_bash': compile_bash,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
for shell_type, completer in COMPLETERS.items():
|
for shell_type, completer in COMPLETERS.items():
|
||||||
print(f'Generating {shell_type} completer.')
|
print(f'Generating {shell_type} completer.')
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
from functools import singledispatch
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from lib2to3.pgen2.pgen import generate_grammar
|
from functools import singledispatch
|
||||||
|
|
||||||
from completion_flow import (
|
from completion_flow import (
|
||||||
Node,
|
|
||||||
Check,
|
|
||||||
Suggest,
|
|
||||||
Variable,
|
|
||||||
Condition,
|
|
||||||
Suggestion,
|
|
||||||
If,
|
|
||||||
And,
|
And,
|
||||||
|
Check,
|
||||||
|
Condition,
|
||||||
|
If,
|
||||||
|
Node,
|
||||||
Not,
|
Not,
|
||||||
generate_flow,
|
Suggest,
|
||||||
|
Suggestion,
|
||||||
|
Variable,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user