Module: Doing::Completion

Defined in:
lib/doing/completion.rb,
lib/doing/completion/fig_completion.rb,
lib/doing/completion/zsh_completion.rb,
lib/doing/completion/bash_completion.rb,
lib/doing/completion/fish_completion.rb,
lib/doing/completion/completion_string.rb

Overview

Completion script generator

Defined Under Namespace

Modules: StringUtils Classes: BashCompletions, FigCompletions, FishCompletions, ZshCompletions

Constant Summary collapse

OPTIONS_RX =
/(?:-(?<short>\w), )?(?:--(?:\[no-\])?(?<long>\w+)(?:=(?<arg>\w+))?)\s+- (?<desc>.*?)$/.freeze
SECTIONS_RX =
/(?m-i)^([A-Z ]+)\n([\s\S]*?)(?=\n+[A-Z]+|\Z)/.freeze
COMMAND_RX =
/^(?<cmd>[^, \t]+)(?<alias>(?:, [^, \t]+)*)?\s+- (?<desc>.*?)$/.freeze

Class Method Summary collapse

Class Method Details

.generate_completion(type: 'zsh', file: :default, link: true) ⇒ Object

Generate a completion script and output to file or stdout

Parameters:

  • type (String) (defaults to: 'zsh')

    shell to generate for (zsh|bash|fish)

  • file (String) (defaults to: :default)

    Path to save to, or 'stdout'



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/doing/completion.rb', line 68

def generate_completion(type: 'zsh', file: :default, link: true)
  return generate_all if type =~ /^all$/i

  file = file == :default ? default_file(type) : file
  file = validate_target(file)
  result = generate_type(type)

  if file =~ /^stdout$/i
    $stdout.puts result
  else
    File.open(file, 'w') { |f| f.puts result }
    Doing.logger.warn('File written:', "#{type} completions written to #{file}")

    link_completion_type(type, file) if link
  end
end

.get_help_sections(command = "") ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/doing/completion.rb', line 19

def get_help_sections(command = "")
  res = `doing help #{command}|command cat`.strip
  scanned = res.scan(SECTIONS_RX)
  sections = {}
  scanned.each do |sect|
    title = sect[0].downcase.strip.gsub(/ +/, '_').to_sym
    content = sect[1].split(/\n/).map(&:strip).delete_if(&:empty?)
    sections[title] = content
  end
  sections
end

.install_builtin(type) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/doing/completion.rb', line 96

def install_builtin(type)
  FileUtils.mkdir_p(default_dir)
  src = File.expand_path(File.join(File.dirname(__FILE__), '..', 'completion', default_filenames[type]))

  if File.exist?(File.join(default_dir, default_filenames[type]))
    return unless Doing::Prompt.yn("Update #{type} completion script", default_response: 'n')

  end

  FileUtils.cp(src, default_dir)
  Doing.logger.warn('File written:', "#{type} completions saved to #{default_file(type)}")
end

Raises:

  • (InvalidArgument)


85
86
87
88
89
90
91
92
93
94
# File 'lib/doing/completion.rb', line 85

def link_default(type)
  type = normalize_type(type)
  raise InvalidArgument, 'Unrecognized shell specified' if type == :invalid

  return %i[zsh bash fish fig].each { |t| link_default(t) } if type == :all

  install_builtin(type)

  link_completion_type(type, File.join(default_dir, default_filenames[type]))
end

.normalize_type(type) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/doing/completion.rb', line 109

def normalize_type(type)
  case type.to_s
  when /^fig/i
    :fig
  when /^f/i
    :fish
  when /^b/i
    :bash
  when /^z/i
    :zsh
  when /^a/i
    :all
  else
    :invalid
  end
end

.parse_command(command) ⇒ Object



47
48
49
50
51
52
53
54
55
56
# File 'lib/doing/completion.rb', line 47

def parse_command(command)
  res = command.match(COMMAND_RX)
  commands = [res['cmd']]
  commands.concat(res['alias'].split(/, /).delete_if(&:empty?)) if res['alias']

  {
    commands: commands,
    description: res['desc'].short_desc
  }
end

.parse_commands(commands) ⇒ Object



58
59
60
# File 'lib/doing/completion.rb', line 58

def parse_commands(commands)
  commands.map { |cmd| parse_command(cmd) }
end

.parse_option(option) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
# File 'lib/doing/completion.rb', line 31

def parse_option(option)
  res = option.match(OPTIONS_RX)
  return nil unless res

  {
    short: res['short'],
    long: res['long'],
    arg: res['arg'],
    description: res['desc'].short_desc
  }
end

.parse_options(options) ⇒ Object



43
44
45
# File 'lib/doing/completion.rb', line 43

def parse_options(options)
  options.map { |opt| parse_option(opt) }
end