mirror of
https://github.com/httpie/cli.git
synced 2024-11-27 02:03:31 +01:00
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" ) )
|
||||
}
|
@ -13,21 +13,22 @@ _httpie_params () {
|
||||
|
||||
if ! [[ $current == -* ]]; then
|
||||
if (( CURRENT == NORMARG + 0 )); then
|
||||
_httpie_method && ret=0
|
||||
fi
|
||||
if (( CURRENT == NORMARG + 0 )); then
|
||||
_httpie_url && ret=0
|
||||
fi
|
||||
if (( CURRENT == NORMARG + 1 )) && [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||
_httpie_url && ret=0
|
||||
fi
|
||||
if (( CURRENT >= NORMARG + 2 )); then
|
||||
_httpie_request_item && ret=0
|
||||
fi
|
||||
if (( CURRENT >= NORMARG + 1 )) && ! [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||
_httpie_request_item && ret=0
|
||||
fi
|
||||
_httpie_method && ret=0
|
||||
fi
|
||||
if (( CURRENT == NORMARG + 0 )); then
|
||||
_httpie_url && ret=0
|
||||
fi
|
||||
if (( CURRENT == NORMARG + 1 )) && [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||
_httpie_url && ret=0
|
||||
fi
|
||||
if (( CURRENT >= NORMARG + 2 )); then
|
||||
_httpie_request_item && ret=0
|
||||
fi
|
||||
if (( CURRENT >= NORMARG + 1 )) && ! [[ ${METHODS[(ie)$predecessor]} -le ${#METHODS} ]]; then
|
||||
_httpie_request_item && ret=0
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
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
|
||||
{% for flow_item in generate_flow() -%}
|
||||
{{ compile_zsh(flow_item) }}
|
||||
{% endfor -%}
|
||||
{{ compile_zsh(flow_item) | indent(width=8) }}
|
||||
{% endfor %}
|
||||
fi
|
||||
|
||||
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 enum import Enum, auto
|
||||
from typing import List, Iterator
|
||||
from typing import Iterator, List
|
||||
|
||||
|
||||
class Condition(Enum):
|
||||
|
@ -1,18 +1,17 @@
|
||||
from atexit import register
|
||||
import functools
|
||||
import string
|
||||
import textwrap
|
||||
|
||||
from jinja2 import Template
|
||||
from atexit import register
|
||||
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.definition import options
|
||||
from httpie.cli.options import Argument, ParserSpec
|
||||
|
||||
from completion_flow import generate_flow
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
EXTRAS_DIR = Path(__file__).parent.parent.parent
|
||||
@ -202,7 +201,7 @@ def zsh_completer(spec: ParserSpec) -> Dict[str, Any]:
|
||||
return {
|
||||
'escape_zsh': escape_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():
|
||||
for shell_type, completer in COMPLETERS.items():
|
||||
print(f'Generating {shell_type} completer.')
|
||||
|
@ -1,17 +1,16 @@
|
||||
from functools import singledispatch
|
||||
from enum import Enum
|
||||
from lib2to3.pgen2.pgen import generate_grammar
|
||||
from functools import singledispatch
|
||||
|
||||
from completion_flow import (
|
||||
Node,
|
||||
Check,
|
||||
Suggest,
|
||||
Variable,
|
||||
Condition,
|
||||
Suggestion,
|
||||
If,
|
||||
And,
|
||||
Check,
|
||||
Condition,
|
||||
If,
|
||||
Node,
|
||||
Not,
|
||||
generate_flow,
|
||||
Suggest,
|
||||
Suggestion,
|
||||
Variable,
|
||||
)
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user