Module: Thor::Completion::Bash::ThorMixin::ClassMethods

Defined in:
lib/thor/completion/bash/thor_mixin.rb

Overview

Methods to be mixed as class methods in to Thor.

Instance Method Summary collapse

Instance Method Details

#bash_complete(request:, index:) ⇒ Object

Handles Bash completion requests at the Thor class level.

This consists of:

  1. Finding the next word in the ‘request` at of after `index` that identifies next the command or subcommand.

    NOTE This is done by simply scanning over words that start with ‘-`, which will not work for options that take values as separate shell words.

  2. Looking for an exact match command or subcommand to the word from (1), and passing processing off to the respective Thor::Command instance or Base subclass.

  3. Or returning an array of “starts with” matches for available Base::ClassMethods#all_commands and any partial input.

    Checks against both Thor::Command#name (“method” name) and Thor::Command#usage_name, preferring usage name.

Parameters:



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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/thor/completion/bash/thor_mixin.rb', line 58

def bash_complete request:, index:
  # logger.level = :trace

  logger.trace __method__,
    request: request,
    index: index,
    word: request.words[index]
  
  # Index we'll incremenet as we scan past options
  scan_index = index
  
  while scan_index < request.cword &&
        scan_index < request.words.length &&
        request.words[scan_index].start_with?( '-' )
    scan_index += 1
  end

  if scan_index == request.cword
    return bash_complete_cur request: request
  end

  unless scan_index < request.words.length
    # We ran out of words without hitting a command name or ending 
    # empty string (for which we would provide all commands as options)
    # 
    # TODO  In the future we can deal with half-written class options
    #       I guess? Maybe? But for now we just give up.
    # 
    return [].tap { |results|
      logger.trace "No command or empty string found",
        results: []
    }
  end
  
  # OK, we should have either '' or something we can match
  match_word = request.words[scan_index]

  # We have nothing, return all commands
  if match_word == ''
    return all_commands.values.map( &:usage_name ).tap { |results|
      logger.trace "Empty match word, returning all commands",
        results: results
    }
  end

  # See what possibilities we have
  possibilities = find_command_possibilities match_word.tr( '-', '_' )

  case possibilities.length
  when 0
    # We couldn't match anything
    logger.trace "Found no command possibilities",
      match_word: match_word,
      results: []

    return []

  when 1
    # We have a unique match

    logger.trace "Unique command matched",
      match_word: match_word,
      match: possibilities[0]
  
    # pass to below

  else
    # There is more than one possbility, but we're trying to fill in 
    # something later on, so we're SO
    return []
  end

  # See if we're got an extact match
  cmd = all_commands[ possibilities[0].underscore ]
  
  # Bump the index to the scan index + 1 to go past the word we just
  # used to find `cmd`
  index = scan_index + 1
  
  # is it a subcommand?
  if subcommand_classes.key? cmd.name
    # It is, hand it off to there
    subcommand_classes[cmd.name].bash_complete \
      request: request,
      index: index
  else
    cmd.bash_complete request: request, index: index, klass: self
  end
end