aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/completion/Bash.scala
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/completion/Bash.scala')
-rw-r--r--src/main/scala/completion/Bash.scala107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/main/scala/completion/Bash.scala b/src/main/scala/completion/Bash.scala
new file mode 100644
index 0000000..0ba3440
--- /dev/null
+++ b/src/main/scala/completion/Bash.scala
@@ -0,0 +1,107 @@
+package cmd
+package completion
+
+object Bash {
+
+ private def addCommands(command: Command): String = {
+ command.commands.map(c => s"""commands+=("$c")\n""").mkString
+ }
+
+ private def addFlags(command: Command): String = {
+ command.options.map { opt =>
+ val extra = if (opt.argumentRequired) "=" else ""
+ val short = opt.short.map(c => s"""flags+=("-${c}")""").getOrElse("")
+ s"""|flags+=("--${opt.long}$extra")
+ |$short
+ |""".stripMargin
+ }.mkString
+ }
+
+ private def commandBlocks(previous: String,
+ commands: Set[Command]): String = {
+ def block(previous: String, command: Command): String = {
+ s"""_${previous}_${command.name}() {
+ | ${addCommands(command)}
+ | ${addFlags(command)}
+ | true
+ |}
+ |""".stripMargin
+ }
+
+ if (commands.isEmpty) {
+ ""
+ } else {
+ commands.map { cmd =>
+ block(previous, cmd) + commandBlocks(cmd.name, cmd.commands)
+ }.mkString
+ }
+ }
+
+ def completion(command: Command) = {
+ val name = command.name
+
+ s"""__${name}_contains_word() {
+ | local word="$$1"; shift
+ | for w in "$$@"; do
+ | [[ $$w = "$$word" ]] && return 0
+ | done
+ | return 1
+ |}
+ |
+ |__${name}_handle_reply() {
+ | case "$$cur" in
+ | -*)
+ | COMPREPLY=( $$(compgen -W "$${flags[*]}" -- "$$cur") )
+ | if [[ $${#COMPREPLY[@]} -eq 1 ]] && [[ $${COMPREPLY[0]} == *= ]]; then
+ | compopt -o nospace
+ | else
+ | compopt +o nospace
+ | fi
+ | ;;
+ | *)
+ | COMPREPLY=( $$(compgen -W "$${commands[*]}" -- "$$cur") )
+ | ;;
+ | esac
+ |}
+ |
+ |__${name}_handle_word() {
+ | if [[ $$c -ge $$cword ]]; then
+ | __${name}_handle_reply
+ | return
+ | fi
+ | if __${name}_contains_word "$${words[c]}" "$${commands[@]}"; then
+ | local next_command="$${last_command}_$${words[c]}"
+ | last_command="$$next_command"
+ | commands=()
+ | flags=()
+ | $$next_command
+ | fi
+ | c=$$((c+1))
+ | __${name}_handle_word
+ |}
+ |
+ |${commandBlocks(name, command.commands)}
+ |
+ |__${name}_start() {
+ | local words=("$${COMP_WORDS[@]}")
+ | local cword="$$COMP_CWORD"
+ | local cur="$${COMP_WORDS[COMP_CWORD]}"
+ | local c=0
+ | COMPREPLY=()
+ |
+ | local last_command="_${name}"
+ | local commands=()
+ | local flags=()
+ |
+ | ${addCommands(command)}
+ | ${addFlags(command)}
+ |
+ | __${name}_handle_word
+ |
+ | return 0
+ |}
+ |complete -o default -F __${name}_start ${name}
+ |""".stripMargin
+ }
+
+}