module Complete

Module containing tab-completion logic and methods.

Public Class Methods

complete(line, state) click to toggle source

Return an Array of completion options for the given input line and client state.

# File lib/droxi/complete.rb, line 8
def self.complete(line, state)
  tokens = Text.tokenize(line, include_empty: true)
  type = completion_type(tokens)
  completion_options(type, tokens.last, state).map do |option|
    option.gsub(' ', '\ ').sub(/\\ $/, ' ')
      .split.drop(tokens.last.count(' ')).join(' ')
      .sub(%r{[^\\/]$}, '\0 ')
  end
end

Private Class Methods

basename(string) click to toggle source
# File lib/droxi/complete.rb, line 111
def self.basename(string)
  string.end_with?('/') ? '' : File.basename(string)
end
collapse(path) click to toggle source

Return a version of a path with .. and . resolved to appropriate directories.

# File lib/droxi/complete.rb, line 131
def self.collapse(path)
  new_path = path.dup
  nil while new_path.sub!(%r{[^/]+/\.\./}, '/')
  nil while new_path.sub!('./', '')
  new_path
end
command(string, names) click to toggle source

Return an Array of potential command name tab-completions for a String.

# File lib/droxi/complete.rb, line 48
def self.command(string, names)
  names.select { |n| n.start_with?(string) }.map { |n| n + ' ' }
end
completion_options(type, word, state) click to toggle source

Return an Array of potential tab-completion options for a given completion type, word, and client state.

# File lib/droxi/complete.rb, line 22
def self.completion_options(type, word, state)
  case type
  when 'COMMAND'     then command(word, Commands::NAMES)
  when 'LOCAL_FILE'  then local(word)
  when 'LOCAL_DIR'   then local_dir(word)
  when 'REMOTE_FILE' then remote(word, state)
  when 'REMOTE_DIR'  then remote_dir(word, state)
  else []
  end
end
completion_type(tokens) click to toggle source

Return a String representing the type of tab-completion that should be performed, given the current line buffer state.

# File lib/droxi/complete.rb, line 35
def self.completion_type(tokens)
  index = tokens.drop_while { |token| token[/^-\w+$/] }.size
  if index <= 1
    'COMMAND'
  elsif tokens[0].start_with?('!') || tokens[0].downcase == 'exec'
    'LOCAL_FILE'
  elsif Commands::NAMES.include?(tokens.first)
    cmd = Commands.const_get(tokens.first.upcase.to_sym)
    cmd.type_of_arg(index - 2)
  end
end
final_match(string, candidate, is_dir) click to toggle source
# File lib/droxi/complete.rb, line 119
def self.final_match(string, candidate, is_dir)
  string + candidate.partition(basename(string))[2] + (is_dir ? '/' : ' ')
end
local(string) click to toggle source

Return an Array of potential local tab-completions for a String.

# File lib/droxi/complete.rb, line 61
def self.local(string)
  dir = local_search_path(string)
  basename = basename(string)

  begin
    matches = Dir.entries(dir).select { |entry| match?(basename, entry) }
    matches.map do |entry|
      final_match(string, entry, File.directory?(dir + '/' + entry))
    end
  rescue Errno::ENOENT
    []
  end
end
local_dir(string) click to toggle source

Return an Array of potential local tab-completions for a String, including only directories.

# File lib/droxi/complete.rb, line 77
def self.local_dir(string)
  local(string).select { |match| match.end_with?('/') }
end
local_search_path(string) click to toggle source

Return the directory in which to search for potential local tab-completions for a String.

# File lib/droxi/complete.rb, line 54
def self.local_search_path(string)
  File.expand_path(strip_filename(string))
rescue ArgumentError
  string
end
match?(prefix, candidate) click to toggle source
# File lib/droxi/complete.rb, line 115
def self.match?(prefix, candidate)
  candidate.start_with?(prefix) && !candidate[/^\.\.?$/]
end
remote(string, state) click to toggle source

Return an Array of potential remote tab-completions for a String.

# File lib/droxi/complete.rb, line 94
def self.remote(string, state)
  dir = remote_search_path(string, state)
  basename = basename(string)

  entries = state.contents(dir).map { |entry| File.basename(entry) }
  matches = entries.select { |entry| match?(basename, entry) }
  matches.map do |entry|
    final_match(string, entry, state.directory?(dir + '/' + entry))
  end
end
remote_dir(string, state) click to toggle source

Return an Array of potential remote tab-completions for a String, including only directories.

# File lib/droxi/complete.rb, line 107
def self.remote_dir(string, state)
  remote(string, state).select { |result| result.end_with?('/') }
end
remote_search_path(string, state) click to toggle source

Return the directory in which to search for potential remote tab-completions for a String.

# File lib/droxi/complete.rb, line 83
def self.remote_search_path(string, state)
  path = case
         when string.empty? then state.pwd + '/'
         when string.start_with?('/') then string
         else state.pwd + '/' + string
         end

  strip_filename(collapse(path))
end
strip_filename(path) click to toggle source

Return the name of the directory indicated by a path.

# File lib/droxi/complete.rb, line 124
def self.strip_filename(path)
  return path if path == '/'
  path.end_with?('/') ? path.sub(%r{/$}, '') : File.dirname(path)
end