Skip to content

Commit

Permalink
Add first example.
Browse files Browse the repository at this point in the history
  • Loading branch information
tibortakacs committed May 19, 2020
1 parent 45c5774 commit 0485562
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
65 changes: 65 additions & 0 deletions mat.complete.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
$MatPythonCommand = "python .\mat.py"
$MatCommandAlias = "mat"

Function mat {
Invoke-Expression "$MatPythonCommand $args"
}

$MatTabCompletionScriptBlock = {
param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)

# In case of scripts, this object hold the current line after string conversion
$line = "$parameterName"
$lineFullLength = $wordToComplete

# The behaviour of completion should depend on the trailing spaces in the current line:
# * "command subcommand " --> TAB --> Completion items parameters/sub-subcommands of "subcommand"
# * "command subcom" --> TAB --> Completion items to extend "subcom" into matching subcommands.
# $line never contains the trailing spaces. However, $lineFullLength is the length of the original
# line (with trailing spaces). This comparision allows the expected user experience.
if ($lineFullLength -gt $line.Length) {
$line = "$line "
}

# Mock bash with environment variable settings
New-Item -Path Env: -Name _ARGCOMPLETE -Value 1 | Out-Null # Enables tab complition in argcomplete
New-Item -Path Env: -Name COMP_TYPE -Value 9 | Out-Null # Constant
New-Item -Path Env: -Name _ARGCOMPLETE_IFS -Value " " | Out-Null # Separator of the items
New-Item -Path Env: -Name _ARGCOMPLETE_SUPPRESS_SPACE -Value 1 | Out-Null # Constant
New-Item -Path Env: -Name _ARGCOMPLETE_COMP_WORDBREAKS -Value "" | Out-Null # Constant
New-Item -Path Env: -Name COMP_POINT -Value $line.Length | Out-Null # Refers to the last character of the current line
New-Item -Path Env: -Name COMP_LINE -Value $line | Out-Null # Current line

# Set a special environment variable to mark that the completion is executed by PowerShell
New-Item -Path Env: -Name _ARGCOMPLETE_POWERSHELL -Value 1 | Out-Null

# Just call the script without any parameter
# Since the environment variables are set, the argcomplete.autocomplete(...) function will be executed.
# The result will be printed on the standard output (see the details in the Python file).
Invoke-Expression $MatPythonCommand -OutVariable completionResult -ErrorVariable errorOut -ErrorAction SilentlyContinue | Out-Null

# Delete environment variables
Remove-Item Env:\_ARGCOMPLETE | Out-Null
Remove-Item Env:\COMP_TYPE | Out-Null
Remove-Item Env:\_ARGCOMPLETE_IFS | Out-Null
Remove-Item Env:\_ARGCOMPLETE_SUPPRESS_SPACE | Out-Null
Remove-Item Env:\_ARGCOMPLETE_COMP_WORDBREAKS | Out-Null
Remove-Item Env:\COMP_POINT | Out-Null
Remove-Item Env:\COMP_LINE | Out-Null

Remove-Item Env:\_ARGCOMPLETE_POWERSHELL | Out-Null

# If there is only one completion item, it will be immediately used. In this case
# a trailing space is important to show the user that the complition for the current
# item is ready.
$items = $completionResult.Split()
if ($items -eq $completionResult) {
"$items "
}
else {
$items
}
}

# Register tab completion for the mat command
Register-ArgumentCompleter -CommandName $MatCommandAlias -ScriptBlock $MatTabCompletionScriptBlock
103 changes: 103 additions & 0 deletions mat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env python3

import argcomplete
import argparse
import os
import sys


def create_mat_command_line():
def add(args):
return (args.numberx + args.numbery, "addition")

def sub(args):
return (args.numbera - args.numberb, "subtraction")

def mul(args):
return (args.u * args.v, "multiplication")

def div_int(args):
return (args.i1 / args.i2, "division with integers")

def div_flt(args):
return (args.f1 / args.f2, "division with floats")

parser = argparse.ArgumentParser(description="Amazing Math CLI", add_help=True)

group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")

subparsers = parser.add_subparsers()

parser_add = subparsers.add_parser("addition", aliases=["add"], help="Add two integers.", parents = [parser], add_help=False)
parser_sub = subparsers.add_parser("subtraction", aliases=["sub"], help="Substracts two integers.", parents = [parser], add_help=False)
parser_div = subparsers.add_parser("division", aliases=["div"], help="Divides two number.")
parser_mul = subparsers.add_parser("multiplication", aliases=["mul"], help="Multiplies two integers.", parents = [parser], add_help=False)

subparsers_div = parser_div.add_subparsers()
parser_div_int = subparsers_div.add_parser("integer", aliases=["int"], help="Divides two integers.", parents = [parser], add_help=False)
parser_div_flt = subparsers_div.add_parser("float", aliases=["flt"], help="Divides two floats.", parents = [parser], add_help=False)

parser_add.add_argument("--numberx", "-x", type=float, help="Number X.")
parser_add.add_argument("--numbery", "-y", type=float, help="Number Y.")

parser_sub.add_argument("--numbera", "-a", type=float, help="Number A.")
parser_sub.add_argument("--numberb", "-b", type=float, help="Number B.")

parser_mul.add_argument("u", type=float, help="Number U.")
parser_mul.add_argument("v", type=float, help="Number V.")

parser_div_int.add_argument("i1", type=int, help="Integer 1.")
parser_div_int.add_argument("i2", type=int, help="Integer 2.")

parser_div_flt.add_argument("f1", type=float, help="Float 1.")
parser_div_flt.add_argument("f2", type=float, help="Float 2.")

parser_add.set_defaults(func=add)
parser_sub.set_defaults(func=sub)
parser_mul.set_defaults(func=mul)
parser_div_int.set_defaults(func=div_int)
parser_div_flt.set_defaults(func=div_flt)

return parser


def execute_mat_operation(options, parser):
if hasattr(options, 'func'):
result = options.func(options)
else:
parser.print_help()
sys.exit(1)

if options.quiet:
print(result[0])
elif options.verbose:
print("Operation '{1}' result is {0}.".format(*result))
else:
print("Result={0}".format(*result))


def main():
# Create the command line parser
parser = create_mat_command_line()

# The argcomplete.autocomplete logic is slightly more complected now:
# * Check for the environment variable which is set in the mat.complete.ps1 script
# * If it is set, use stdout as output stream since PowerShell processes that one.
# * Otherwise, just use the default settings
output_stream=None
if "_ARGCOMPLETE_POWERSHELL" in os.environ:
output_stream = sys.stdout.buffer
argcomplete.autocomplete(parser, output_stream=output_stream)

# Do the parsing (after the completion!)
options = parser.parse_args()

# Just execut the operation
execute_mat_operation(options, parser)
sys.exit(0)


if __name__ == "__main__":
main()

0 comments on commit 0485562

Please sign in to comment.