diff --git a/completions/_protonvpn b/completions/_protonvpn new file mode 100644 index 0000000..8abb369 --- /dev/null +++ b/completions/_protonvpn @@ -0,0 +1,208 @@ +#compdef protonvpn +# Zsh completion for protonvpn +# Place this file in a directory listed in $fpath (e.g. /usr/share/zsh/site-functions/) + +_protonvpn_toggle_values() { + local -a values + values=( + 'on:Enable' + 'off:Disable' + ) + _describe -t values 'value' values +} + +_protonvpn_config_set_custom_dns() { + _arguments \ + '1:state:(on off)' \ + '--dns[Comma-separated DNS server IPs]:dns IPs: ' +} + +_protonvpn_config_set() { + local state line + typeset -A opt_args + + _arguments -C \ + '1:setting:->setting' \ + '*::arg:->args' + + case $state in + setting) + local -a settings + settings=( + 'netshield:Ad-blocking and malware protection' + 'kill-switch:Block internet if VPN drops' + 'port-forwarding:Port forwarding for P2P' + 'custom-dns:Custom DNS servers' + 'vpn-accelerator:Performance optimization' + 'moderate-nat:NAT type for gaming/P2P' + 'ipv6:IPv6 support' + 'anonymous-crash-reports:Anonymous crash reporting' + ) + _describe -t settings 'setting' settings + ;; + args) + case $line[1] in + netshield) + local -a values + values=( + 'off:Disable NetShield' + 'malware-only:Block malware domains' + 'malware-ads-trackers:Block malware, ads, and trackers' + ) + _describe -t values 'mode' values + ;; + kill-switch) + local -a values + values=( + 'off:Disable Kill Switch' + 'standard:Block internet if VPN drops' + ) + _describe -t values 'mode' values + ;; + custom-dns) + _protonvpn_config_set_custom_dns + ;; + vpn-accelerator|moderate-nat|ipv6|anonymous-crash-reports|port-forwarding) + _protonvpn_toggle_values + ;; + esac + ;; + esac +} + +_protonvpn_config() { + local state line + typeset -A opt_args + + _arguments -C \ + '1:subcommand:->subcmd' \ + '*::arg:->args' + + case $state in + subcmd) + local -a subcommands + subcommands=( + 'list:Show current configuration' + 'set:Change a setting' + ) + _describe -t subcommands 'config subcommand' subcommands + ;; + args) + case $line[1] in + set) + _protonvpn_config_set + ;; + list) + _message 'no more arguments' + ;; + esac + ;; + esac +} + +_protonvpn_connect() { + _arguments \ + '1::server name: ' \ + '--country[Connect to country (code or name)]:country: ' \ + '--city[Connect to city]:city: ' \ + '--p2p[P2P-optimized server]' \ + '(-sc --securecore)'{-sc,--securecore}'[Secure Core server]' \ + '--tor[Tor over VPN server]' \ + '--random[Random server]' \ + '(-h --help)'{-h,--help}'[Show help]' +} + +_protonvpn_countries() { + local state line + typeset -A opt_args + + _arguments -C \ + '1:subcommand:->subcmd' + + case $state in + subcmd) + local -a subcommands + subcommands=('list:List all countries') + _describe -t subcommands 'countries subcommand' subcommands + ;; + esac +} + +_protonvpn_cities() { + local state line + typeset -A opt_args + + _arguments -C \ + '1:subcommand:->subcmd' \ + '*::arg:->args' + + case $state in + subcmd) + local -a subcommands + subcommands=('list:List cities in a country') + _describe -t subcommands 'cities subcommand' subcommands + ;; + args) + case $line[1] in + list) + _message 'country code or name' + ;; + esac + ;; + esac +} + +_protonvpn() { + local state line + typeset -A opt_args + + local -a commands + commands=( + 'signin:Sign in to Proton VPN' + 'signout:Sign out from Proton VPN' + 'info:Display account information' + 'connect:Connect to VPN server' + 'disconnect:Disconnect from VPN' + 'status:Show connection status' + 'servers:View available servers' + 'countries:Discover countries with servers' + 'cities:Discover cities with servers' + 'config:Configure VPN settings' + ) + + _arguments -C \ + '(-v --verbose)'{-v,--verbose}'[Show detailed output]' \ + '(-h --help)'{-h,--help}'[Show help]' \ + '1:command:->command' \ + '*::arg:->args' + + case $state in + command) + _describe -t commands 'protonvpn command' commands + ;; + args) + case $line[1] in + signin) + _message 'username' + ;; + signout|info|disconnect|status|servers) + _message 'no more arguments' + ;; + connect) + _protonvpn_connect + ;; + countries) + _protonvpn_countries + ;; + cities) + _protonvpn_cities + ;; + config) + _protonvpn_config + ;; + esac + ;; + esac +} + +_protonvpn "$@" diff --git a/completions/protonvpn b/completions/protonvpn new file mode 100644 index 0000000..fffa236 --- /dev/null +++ b/completions/protonvpn @@ -0,0 +1,118 @@ +# Bash completion for protonvpn +# Source this file or place it in /etc/bash_completion.d/ +# Requires: bash-completion (https://github.com/scop/bash-completion) + +_protonvpn() { + local cur prev words cword + _init_completion || return + + local commands="signin signout info connect disconnect status servers countries cities config" + local config_subcommands="list set" + local config_set_settings="netshield kill-switch port-forwarding custom-dns vpn-accelerator moderate-nat ipv6 anonymous-crash-reports" + local toggle_values="on off" + + # Walk the command line to determine the subcommand context + local cmd="" subcmd="" setting="" + local i + for ((i = 1; i < cword; i++)); do + case "${words[i]}" in + -v|--verbose|-h|--help) + continue + ;; + signin|signout|info|connect|disconnect|status|servers|countries|cities|config) + cmd="${words[i]}" + ;; + list|set) + if [[ "$cmd" == "config" || "$cmd" == "countries" || "$cmd" == "cities" ]]; then + subcmd="${words[i]}" + fi + ;; + netshield|kill-switch|port-forwarding|custom-dns|vpn-accelerator|moderate-nat|ipv6|anonymous-crash-reports) + if [[ "$cmd" == "config" && "$subcmd" == "set" ]]; then + setting="${words[i]}" + fi + ;; + esac + done + + # Complete based on context + case "$cmd" in + "") + # Top-level: complete commands and global options + if [[ "$cur" == -* ]]; then + COMPREPLY=($(compgen -W "-v --verbose -h --help" -- "$cur")) + else + COMPREPLY=($(compgen -W "$commands" -- "$cur")) + fi + ;; + signin) + # signin takes a USERNAME argument, no completions + return + ;; + signout|info|disconnect|status|servers) + # These commands take no arguments + if [[ "$cur" == -* ]]; then + COMPREPLY=($(compgen -W "-h --help" -- "$cur")) + fi + ;; + connect) + if [[ "$prev" == "--country" || "$prev" == "--city" ]]; then + # These take a value argument; no static completions + return + fi + COMPREPLY=($(compgen -W "--country --city --p2p -sc --securecore --tor --random -h --help" -- "$cur")) + ;; + countries) + if [[ -z "$subcmd" ]]; then + COMPREPLY=($(compgen -W "list" -- "$cur")) + fi + ;; + cities) + if [[ -z "$subcmd" ]]; then + COMPREPLY=($(compgen -W "list" -- "$cur")) + fi + # cities list takes a COUNTRY argument; no static completions + ;; + config) + case "$subcmd" in + "") + COMPREPLY=($(compgen -W "$config_subcommands" -- "$cur")) + ;; + list) + if [[ "$cur" == -* ]]; then + COMPREPLY=($(compgen -W "-h --help" -- "$cur")) + fi + ;; + set) + if [[ -z "$setting" ]]; then + COMPREPLY=($(compgen -W "$config_set_settings" -- "$cur")) + else + # Complete setting values + case "$setting" in + netshield) + COMPREPLY=($(compgen -W "off malware-only malware-ads-trackers" -- "$cur")) + ;; + kill-switch) + COMPREPLY=($(compgen -W "off standard" -- "$cur")) + ;; + custom-dns) + if [[ "$cur" == -* ]]; then + COMPREPLY=($(compgen -W "--dns -h --help" -- "$cur")) + elif [[ "$prev" == "--dns" ]]; then + return + else + COMPREPLY=($(compgen -W "$toggle_values" -- "$cur")) + fi + ;; + vpn-accelerator|moderate-nat|ipv6|anonymous-crash-reports|port-forwarding) + COMPREPLY=($(compgen -W "$toggle_values" -- "$cur")) + ;; + esac + fi + ;; + esac + ;; + esac +} + +complete -F _protonvpn protonvpn diff --git a/completions/protonvpn.fish b/completions/protonvpn.fish new file mode 100644 index 0000000..2433562 --- /dev/null +++ b/completions/protonvpn.fish @@ -0,0 +1,148 @@ +# Fish completion for protonvpn +# Place this file in ~/.config/fish/completions/ or /usr/share/fish/vendor_completions.d/ + +# Disable file completions by default +complete -c protonvpn -f + +# Helper: check if a specific subcommand has been given +function __protonvpn_using_command + set -l cmd (commandline -opc) + set -e cmd[1] # remove 'protonvpn' + # Strip flags + set -l tokens + for t in $cmd + switch $t + case '-*' + continue + case '*' + set -a tokens $t + end + end + # Check if the tokens match the expected sequence + set -l expected $argv + set -l count (count $expected) + if test (count $tokens) -ne $count + return 1 + end + for i in (seq $count) + if test "$tokens[$i]" != "$expected[$i]" + return 1 + end + end + return 0 +end + +function __protonvpn_using_command_prefix + set -l cmd (commandline -opc) + set -e cmd[1] + set -l tokens + for t in $cmd + switch $t + case '-*' + continue + case '*' + set -a tokens $t + end + end + set -l expected $argv + set -l count (count $expected) + if test (count $tokens) -lt $count + return 1 + end + for i in (seq $count) + if test "$tokens[$i]" != "$expected[$i]" + return 1 + end + end + return 0 +end + +# --- Top-level commands --- +set -l commands signin signout info connect disconnect status servers countries cities config + +complete -c protonvpn -n '__protonvpn_using_command' -a signin -d 'Sign in to Proton VPN' +complete -c protonvpn -n '__protonvpn_using_command' -a signout -d 'Sign out from Proton VPN' +complete -c protonvpn -n '__protonvpn_using_command' -a info -d 'Display account information' +complete -c protonvpn -n '__protonvpn_using_command' -a connect -d 'Connect to VPN server' +complete -c protonvpn -n '__protonvpn_using_command' -a disconnect -d 'Disconnect from VPN' +complete -c protonvpn -n '__protonvpn_using_command' -a status -d 'Show connection status' +complete -c protonvpn -n '__protonvpn_using_command' -a servers -d 'View available servers' +complete -c protonvpn -n '__protonvpn_using_command' -a countries -d 'Discover countries with servers' +complete -c protonvpn -n '__protonvpn_using_command' -a cities -d 'Discover cities with servers' +complete -c protonvpn -n '__protonvpn_using_command' -a config -d 'Configure VPN settings' + +# --- Global options --- +complete -c protonvpn -s v -l verbose -d 'Show detailed output' +complete -c protonvpn -s h -l help -d 'Show help' + +# --- connect options --- +complete -c protonvpn -n '__protonvpn_using_command_prefix connect' -l country -d 'Connect to country (code or name)' -x +complete -c protonvpn -n '__protonvpn_using_command_prefix connect' -l city -d 'Connect to city' -x +complete -c protonvpn -n '__protonvpn_using_command_prefix connect' -l p2p -d 'P2P-optimized server' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect' -l securecore -d 'Secure Core server' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect' -l tor -d 'Tor over VPN server' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect' -l random -d 'Random server' +# Expose connect options as arguments so they appear without typing - +complete -c protonvpn -n '__protonvpn_using_command_prefix connect; and not string match -q -- "-*" (commandline -ct)' -f -a '--country' -d 'Connect to country (code or name)' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect; and not string match -q -- "-*" (commandline -ct)' -f -a '--city' -d 'Connect to city' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect; and not string match -q -- "-*" (commandline -ct)' -f -a '--p2p' -d 'P2P-optimized server' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect; and not string match -q -- "-*" (commandline -ct)' -f -a '-sc --securecore' -d 'Secure Core server' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect; and not string match -q -- "-*" (commandline -ct)' -f -a '--tor' -d 'Tor over VPN server' +complete -c protonvpn -n '__protonvpn_using_command_prefix connect; and not string match -q -- "-*" (commandline -ct)' -f -a '--random' -d 'Random server' + +# --- countries subcommands --- +complete -c protonvpn -n '__protonvpn_using_command countries' -a list -d 'List all countries' + +# --- cities subcommands --- +complete -c protonvpn -n '__protonvpn_using_command cities' -a list -d 'List cities in a country' + +# --- config subcommands --- +complete -c protonvpn -n '__protonvpn_using_command config' -a list -d 'Show current configuration' +complete -c protonvpn -n '__protonvpn_using_command config' -a set -d 'Change a setting' + +# --- config set: setting names --- +set -l config_set_settings "netshield kill-switch port-forwarding custom-dns vpn-accelerator moderate-nat ipv6 anonymous-crash-reports" + +complete -c protonvpn -n '__protonvpn_using_command config set' -a netshield -d 'Ad-blocking and malware protection' +complete -c protonvpn -n '__protonvpn_using_command config set' -a kill-switch -d 'Block internet if VPN drops' +complete -c protonvpn -n '__protonvpn_using_command config set' -a port-forwarding -d 'Port forwarding for P2P' +complete -c protonvpn -n '__protonvpn_using_command config set' -a custom-dns -d 'Custom DNS servers' +complete -c protonvpn -n '__protonvpn_using_command config set' -a vpn-accelerator -d 'Performance optimization' +complete -c protonvpn -n '__protonvpn_using_command config set' -a moderate-nat -d 'NAT type for gaming/P2P' +complete -c protonvpn -n '__protonvpn_using_command config set' -a ipv6 -d 'IPv6 support' +complete -c protonvpn -n '__protonvpn_using_command config set' -a anonymous-crash-reports -d 'Anonymous crash reporting' + +# --- config set values --- +# netshield +complete -c protonvpn -n '__protonvpn_using_command config set netshield' -a 'off' -d 'Disable NetShield' +complete -c protonvpn -n '__protonvpn_using_command config set netshield' -a 'malware-only' -d 'Block malware domains' +complete -c protonvpn -n '__protonvpn_using_command config set netshield' -a 'malware-ads-trackers' -d 'Block malware, ads, and trackers' + +# kill-switch +complete -c protonvpn -n '__protonvpn_using_command config set kill-switch' -a 'off' -d 'Disable Kill Switch' +complete -c protonvpn -n '__protonvpn_using_command config set kill-switch' -a 'standard' -d 'Block internet if VPN drops' + +# port-forwarding +complete -c protonvpn -n '__protonvpn_using_command config set port-forwarding' -a 'on' -d 'Enable port forwarding' +complete -c protonvpn -n '__protonvpn_using_command config set port-forwarding' -a 'off' -d 'Disable port forwarding' + +# custom-dns +complete -c protonvpn -n '__protonvpn_using_command config set custom-dns' -a 'on' -d 'Enable custom DNS' +complete -c protonvpn -n '__protonvpn_using_command config set custom-dns' -a 'off' -d 'Disable custom DNS' +complete -c protonvpn -n '__protonvpn_using_command_prefix config set custom-dns' -l dns -d 'Comma-separated DNS server IPs' -x + +# vpn-accelerator +complete -c protonvpn -n '__protonvpn_using_command config set vpn-accelerator' -a 'on' -d 'Enable VPN Accelerator' +complete -c protonvpn -n '__protonvpn_using_command config set vpn-accelerator' -a 'off' -d 'Disable VPN Accelerator' + +# moderate-nat +complete -c protonvpn -n '__protonvpn_using_command config set moderate-nat' -a 'on' -d 'Enable Moderate NAT' +complete -c protonvpn -n '__protonvpn_using_command config set moderate-nat' -a 'off' -d 'Disable Moderate NAT' + +# ipv6 +complete -c protonvpn -n '__protonvpn_using_command config set ipv6' -a 'on' -d 'Enable IPv6' +complete -c protonvpn -n '__protonvpn_using_command config set ipv6' -a 'off' -d 'Disable IPv6' + +# anonymous-crash-reports +complete -c protonvpn -n '__protonvpn_using_command config set anonymous-crash-reports' -a 'on' -d 'Enable crash reporting' +complete -c protonvpn -n '__protonvpn_using_command config set anonymous-crash-reports' -a 'off' -d 'Disable crash reporting' diff --git a/setup.py b/setup.py index d41b013..c8245d3 100644 --- a/setup.py +++ b/setup.py @@ -48,6 +48,11 @@ "Programming Language :: Python", "Topic :: Security", ], + data_files=[ + ("share/bash-completion/completions", ["completions/protonvpn"]), + ("share/zsh/site-functions", ["completions/_protonvpn"]), + ("share/fish/vendor_completions.d", ["completions/protonvpn.fish"]), + ], entry_points={ "console_scripts": [ ['protonvpn=proton.vpn.cli:main'],