aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/completion/Bash.scala
blob: e049fe1814619f197e03cc3bd2cedd56149b6775 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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
  }

}