aboutsummaryrefslogblamecommitdiff
path: root/src/main/scala/completion/Bash.scala
blob: e049fe1814619f197e03cc3bd2cedd56149b6775 (plain) (tree)
1
                









































































































                                                                                          
package commando
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
  }

}