snippet_cli 0.3.6 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +29 -15
- data/exe/snippet_cli +45 -11
- data/lib/snippet_cli/Espanso_Merged_Matchfile_Schema.json +889 -0
- data/lib/snippet_cli/banner.rb +16 -0
- data/lib/snippet_cli/commands/check.rb +49 -0
- data/lib/snippet_cli/commands/conflict.rb +75 -0
- data/lib/snippet_cli/commands/new.rb +16 -102
- data/lib/snippet_cli/commands/vars.rb +58 -0
- data/lib/snippet_cli/commands/version.rb +17 -0
- data/lib/snippet_cli/conflict_detector.rb +71 -0
- data/lib/snippet_cli/cursor_helper.rb +20 -0
- data/lib/snippet_cli/espanso_config.rb +26 -0
- data/lib/snippet_cli/file_helper.rb +16 -0
- data/lib/snippet_cli/file_validator.rb +33 -0
- data/lib/snippet_cli/file_writer.rb +12 -0
- data/lib/snippet_cli/form_field_parser.rb +13 -0
- data/lib/snippet_cli/global_vars_formatter.rb +63 -0
- data/lib/snippet_cli/global_vars_writer.rb +29 -0
- data/lib/snippet_cli/gum_theme.rb +39 -0
- data/lib/snippet_cli/hash_utils.rb +21 -0
- data/lib/snippet_cli/match_file_writer.rb +26 -0
- data/lib/snippet_cli/match_validator.rb +33 -0
- data/lib/snippet_cli/new_workflow.rb +98 -0
- data/lib/snippet_cli/replacement_text_collector.rb +55 -0
- data/lib/snippet_cli/replacement_validator.rb +35 -0
- data/lib/snippet_cli/replacement_wizard.rb +100 -0
- data/lib/snippet_cli/schema_validator.rb +27 -0
- data/lib/snippet_cli/snippet_builder.rb +133 -0
- data/lib/snippet_cli/string_helper.rb +11 -0
- data/lib/snippet_cli/table_formatter.rb +37 -0
- data/lib/snippet_cli/trigger_resolver.rb +67 -0
- data/lib/snippet_cli/ui.rb +90 -0
- data/lib/snippet_cli/var_builder/form_fields.rb +54 -0
- data/lib/snippet_cli/var_builder/name_collector.rb +69 -0
- data/lib/snippet_cli/var_builder/param_schema.rb +71 -0
- data/lib/snippet_cli/var_builder/params.rb +127 -0
- data/lib/snippet_cli/var_builder.rb +125 -0
- data/lib/snippet_cli/var_summary_renderer.rb +48 -0
- data/lib/snippet_cli/var_usage_checker.rb +48 -0
- data/lib/snippet_cli/var_yaml_renderer.rb +20 -0
- data/lib/snippet_cli/vars_block_renderer.rb +15 -0
- data/lib/snippet_cli/version.rb +3 -1
- data/lib/snippet_cli/wizard_context.rb +13 -0
- data/lib/snippet_cli/wizard_helpers/error_handler.rb +20 -0
- data/lib/snippet_cli/wizard_helpers/match_file_selector.rb +32 -0
- data/lib/snippet_cli/wizard_helpers/prompt_helpers.rb +57 -0
- data/lib/snippet_cli/wizard_helpers/validation_loop.rb +33 -0
- data/lib/snippet_cli/wizard_helpers.rb +8 -0
- data/lib/snippet_cli/yaml_line_resolver.rb +46 -0
- data/lib/snippet_cli/yaml_loader.rb +19 -0
- data/lib/snippet_cli/yaml_param_renderer.rb +33 -0
- data/lib/snippet_cli/yaml_scalar.rb +48 -0
- data/lib/snippet_cli.rb +44 -1
- metadata +134 -101
- data/.gitignore +0 -11
- data/.rspec +0 -3
- data/.travis.yml +0 -9
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -17
- data/Rakefile +0 -10
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/lib/Setup.rb +0 -76
- data/lib/banner.rb +0 -16
- data/lib/snippet_cli/cli.rb +0 -62
- data/lib/snippet_cli/command.rb +0 -121
- data/lib/snippet_cli/commands/info.md +0 -20
- data/lib/snippet_cli/commands/info.rb +0 -36
- data/lib/snippet_cli/commands/setup.rb +0 -108
- data/lib/snippet_cli/templates/.gitkeep +0 -1
- data/lib/snippet_cli/templates/config/.gitkeep +0 -1
- data/lib/snippet_cli/templates/create/.gitkeep +0 -1
- data/lib/snippet_cli/templates/info/.gitkeep +0 -1
- data/lib/snippet_cli/templates/setup/.gitkeep +0 -1
- data/lib/snippet_generator.rb +0 -85
- data/snippet_cli-0.1.0.gem +0 -0
- data/snippet_cli-0.1.1.gem +0 -0
- data/snippet_cli-0.1.2.gem +0 -0
- data/snippet_cli-0.1.3.gem +0 -0
- data/snippet_cli-0.1.4.gem +0 -0
- data/snippet_cli-0.1.5.gem +0 -0
- data/snippet_cli-0.1.6.gem +0 -0
- data/snippet_cli-0.1.7.gem +0 -0
- data/snippet_cli-0.1.8.gem +0 -0
- data/snippet_cli-0.1.9.gem +0 -0
- data/snippet_cli-0.2.0.gem +0 -0
- data/snippet_cli-0.2.1.gem +0 -0
- data/snippet_cli-0.2.2.gem +0 -0
- data/snippet_cli-0.2.3.gem +0 -0
- data/snippet_cli-0.2.4.gem +0 -0
- data/snippet_cli-0.2.6.gem +0 -0
- data/snippet_cli-0.2.7.gem +0 -0
- data/snippet_cli-0.2.8.gem +0 -0
- data/snippet_cli.gemspec +0 -37
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SnippetCli
|
|
4
|
+
# Carries shared wizard configuration: which file to save to,
|
|
5
|
+
# which global var names are already declared in that file,
|
|
6
|
+
# and the pipe IO for structured output when stdout is redirected.
|
|
7
|
+
# Passed explicitly rather than communicated via global state.
|
|
8
|
+
WizardContext = Data.define(:global_var_names, :save_path, :pipe_output) do
|
|
9
|
+
def initialize(global_var_names: [], save_path: nil, pipe_output: nil)
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SnippetCli
|
|
4
|
+
module WizardHelpers
|
|
5
|
+
# Wraps a command body with standard error handling.
|
|
6
|
+
# Rescues WizardInterrupted (Ctrl+C) universally.
|
|
7
|
+
# Rescues typed error_classes passed by the caller, displaying their message via UI.error and exiting 1.
|
|
8
|
+
module ErrorHandler
|
|
9
|
+
def handle_errors(*error_classes)
|
|
10
|
+
yield
|
|
11
|
+
rescue *error_classes => e
|
|
12
|
+
UI.error(e.message)
|
|
13
|
+
exit 1
|
|
14
|
+
rescue WizardInterrupted
|
|
15
|
+
puts
|
|
16
|
+
UI.error('Interrupted, exiting snippet_cli.')
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'gum'
|
|
4
|
+
require_relative 'prompt_helpers'
|
|
5
|
+
|
|
6
|
+
module SnippetCli
|
|
7
|
+
module WizardHelpers
|
|
8
|
+
# Selects an Espanso match file for saving.
|
|
9
|
+
# Auto-selects when only one file exists; otherwise prompts via Gum.filter.
|
|
10
|
+
module MatchFileSelector
|
|
11
|
+
include PromptHelpers
|
|
12
|
+
|
|
13
|
+
# Returns [basename, full_path] of the chosen match file.
|
|
14
|
+
# Raises NoMatchFilesError when no files exist.
|
|
15
|
+
def pick_match_file
|
|
16
|
+
files = EspansoConfig.match_files
|
|
17
|
+
abort_no_match_files if files.empty?
|
|
18
|
+
return [File.basename(files.first), files.first] if files.size == 1
|
|
19
|
+
|
|
20
|
+
basenames = files.map { |f| File.basename(f) }
|
|
21
|
+
chosen = prompt!(Gum.filter(*basenames, header: 'Save to which match file?'))
|
|
22
|
+
[chosen, files.find { |f| File.basename(f) == chosen }]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def abort_no_match_files
|
|
28
|
+
raise NoMatchFilesError, 'No match files found in Espanso config.'
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'English'
|
|
4
|
+
require 'gum'
|
|
5
|
+
require_relative '../table_formatter'
|
|
6
|
+
|
|
7
|
+
module SnippetCli
|
|
8
|
+
module WizardHelpers
|
|
9
|
+
# Gum prompt primitives with Ctrl+C detection via WizardInterrupted.
|
|
10
|
+
module PromptHelpers
|
|
11
|
+
# Returns the value if non-nil; raises WizardInterrupted otherwise.
|
|
12
|
+
# Gum.choose / .input / .filter / .write return nil on Ctrl+C.
|
|
13
|
+
def prompt!(value)
|
|
14
|
+
raise WizardInterrupted if value.nil?
|
|
15
|
+
|
|
16
|
+
value
|
|
17
|
+
rescue Interrupt
|
|
18
|
+
raise WizardInterrupted
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Wraps Gum.confirm and checks $?.exitstatus for 130 (Ctrl+C).
|
|
22
|
+
# Gum.confirm uses system() which swallows SIGINT and returns false,
|
|
23
|
+
# making it indistinguishable from the user answering "no" — except
|
|
24
|
+
# that $? records the child's exit code 130.
|
|
25
|
+
# SIGINT can also raise Interrupt in Ruby before $? is read.
|
|
26
|
+
def confirm!(text)
|
|
27
|
+
result = Gum.confirm(text, prompt_style: UI::PROMPT_STYLE)
|
|
28
|
+
raise WizardInterrupted if result.nil?
|
|
29
|
+
raise WizardInterrupted if $CHILD_STATUS.respond_to?(:exitstatus) && $CHILD_STATUS.exitstatus == 130
|
|
30
|
+
|
|
31
|
+
result
|
|
32
|
+
rescue Interrupt
|
|
33
|
+
raise WizardInterrupted
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Renders a table of collected items and asks a follow-up question, without a border.
|
|
37
|
+
def list_confirm!(label, rows, headers, question)
|
|
38
|
+
table = TableFormatter.render(rows, headers: headers)
|
|
39
|
+
confirm!("Current #{label}s:\n\n#{table}\n\n#{question}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Confirms a question then collects a value via the block, or returns nil if declined.
|
|
43
|
+
def optional_prompt(question)
|
|
44
|
+
yield if confirm!(question)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Prompts for search terms via a multiline write block.
|
|
48
|
+
# Returns an empty array if the user declines.
|
|
49
|
+
def collect_search_terms
|
|
50
|
+
return [] unless confirm!('Add search terms?')
|
|
51
|
+
|
|
52
|
+
raw = prompt!(Gum.write(header: 'Put one search term per line', prompt_style: UI::PROMPT_STYLE, header_style: UI::PROMPT_STYLE))
|
|
53
|
+
raw.to_s.lines.map(&:chomp).reject(&:empty?)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SnippetCli
|
|
4
|
+
module WizardHelpers
|
|
5
|
+
# Loop-until-valid prompt abstractions.
|
|
6
|
+
module ValidationLoop
|
|
7
|
+
# General loop-until-valid primitive.
|
|
8
|
+
# The block must yield [value, error_or_nil].
|
|
9
|
+
# When error is a String, shows it as a transient warning.
|
|
10
|
+
# When error is a Callable (e.g. a lambda), uses it directly as the clear function.
|
|
11
|
+
# Loops until the block yields a nil error.
|
|
12
|
+
def prompt_until_valid
|
|
13
|
+
clear = nil
|
|
14
|
+
loop do
|
|
15
|
+
value, error = yield
|
|
16
|
+
clear&.call
|
|
17
|
+
return value if error.nil?
|
|
18
|
+
|
|
19
|
+
clear = error.respond_to?(:call) ? error : UI.transient_warning(error)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Loops until the block yields a non-empty string.
|
|
24
|
+
# Shows warning_message as a transient warning on empty input.
|
|
25
|
+
def prompt_non_empty(warning_message, &prompt_block)
|
|
26
|
+
prompt_until_valid do
|
|
27
|
+
value = prompt_block.call
|
|
28
|
+
[value, value.strip.empty? ? warning_message : nil]
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Convenience require — loads all focused WizardHelpers sub-modules.
|
|
4
|
+
# Prefer requiring only the specific sub-module your class needs.
|
|
5
|
+
require_relative 'wizard_helpers/prompt_helpers'
|
|
6
|
+
require_relative 'wizard_helpers/validation_loop'
|
|
7
|
+
require_relative 'wizard_helpers/match_file_selector'
|
|
8
|
+
require_relative 'wizard_helpers/error_handler'
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'psych'
|
|
4
|
+
|
|
5
|
+
module SnippetCli
|
|
6
|
+
# Resolves a JSON Pointer (e.g. "/matches/354") to a 1-based line number
|
|
7
|
+
# in a YAML file by navigating the Psych AST node tree.
|
|
8
|
+
module YamlLineResolver
|
|
9
|
+
# Returns the 1-based line number for the given JSON pointer, or nil if
|
|
10
|
+
# the pointer is empty, invalid, or cannot be resolved in the file.
|
|
11
|
+
def self.resolve(file, pointer)
|
|
12
|
+
return nil if pointer.to_s.empty?
|
|
13
|
+
|
|
14
|
+
segments = pointer.to_s.sub(%r{\A/}, '').split('/')
|
|
15
|
+
return nil if segments.empty?
|
|
16
|
+
|
|
17
|
+
tree = Psych.parse_file(file)
|
|
18
|
+
node = navigate(tree.root, segments)
|
|
19
|
+
node&.start_line&.+(1)
|
|
20
|
+
rescue StandardError
|
|
21
|
+
nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.navigate(node, segments)
|
|
25
|
+
return node if segments.empty?
|
|
26
|
+
|
|
27
|
+
seg, *rest = segments
|
|
28
|
+
case node
|
|
29
|
+
when Psych::Nodes::Document then navigate(node.root, segments)
|
|
30
|
+
when Psych::Nodes::Mapping then navigate_mapping(node, seg, rest)
|
|
31
|
+
when Psych::Nodes::Sequence then navigate(node.children[Integer(seg, 10)], rest)
|
|
32
|
+
end
|
|
33
|
+
rescue ArgumentError, TypeError
|
|
34
|
+
nil
|
|
35
|
+
end
|
|
36
|
+
private_class_method :navigate
|
|
37
|
+
|
|
38
|
+
def self.navigate_mapping(node, key, rest)
|
|
39
|
+
node.children.each_slice(2) do |k, v|
|
|
40
|
+
return navigate(v, rest) if k.value == key
|
|
41
|
+
end
|
|
42
|
+
nil
|
|
43
|
+
end
|
|
44
|
+
private_class_method :navigate_mapping
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require_relative 'file_helper'
|
|
5
|
+
|
|
6
|
+
module SnippetCli
|
|
7
|
+
# Shared YAML file loading with existence check and syntax-error handling.
|
|
8
|
+
module YamlLoader
|
|
9
|
+
# Loads and parses a YAML file.
|
|
10
|
+
# Raises FileMissingError if the file does not exist.
|
|
11
|
+
# Raises InvalidYamlError if the file contains invalid YAML syntax.
|
|
12
|
+
def self.load(path, permitted_classes: [Symbol])
|
|
13
|
+
FileHelper.ensure_readable!(path)
|
|
14
|
+
YAML.safe_load_file(path, permitted_classes: permitted_classes) || {}
|
|
15
|
+
rescue Psych::SyntaxError => e
|
|
16
|
+
raise InvalidYamlError, "Invalid YAML: #{e.message}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'yaml_scalar'
|
|
4
|
+
|
|
5
|
+
module SnippetCli
|
|
6
|
+
# Renders variable param key/value pairs as YAML lines with proper indentation.
|
|
7
|
+
module YamlParamRenderer
|
|
8
|
+
def self.lines(key, val, indent)
|
|
9
|
+
case val
|
|
10
|
+
when Hash then hash_lines(key, val, indent)
|
|
11
|
+
when Array then ["#{indent}#{key}:", *val.map { |item| "#{indent} - #{YamlScalar.quote(item.to_s)}" }]
|
|
12
|
+
when true, false then ["#{indent}#{key}: #{val}"]
|
|
13
|
+
else scalar_lines(key, val.to_s, indent)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.hash_lines(key, hash, indent)
|
|
18
|
+
result = ["#{indent}#{key}:"]
|
|
19
|
+
hash.each { |k, v| result.concat(lines(k, v, "#{indent} ")) }
|
|
20
|
+
result
|
|
21
|
+
end
|
|
22
|
+
private_class_method :hash_lines
|
|
23
|
+
|
|
24
|
+
def self.scalar_lines(key, str, indent)
|
|
25
|
+
if str.include?("\n")
|
|
26
|
+
indented = str.lines.map { |line| "#{indent} #{line.chomp}" }.join("\n")
|
|
27
|
+
["#{indent}#{key}: |", indented]
|
|
28
|
+
else
|
|
29
|
+
["#{indent}#{key}: #{YamlScalar.quote(str)}"]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SnippetCli
|
|
4
|
+
# Helpers for quoting scalar values in hand-built YAML output.
|
|
5
|
+
module YamlScalar
|
|
6
|
+
class InvalidCharacterError < StandardError; end
|
|
7
|
+
|
|
8
|
+
BOOLEAN_LIKE = /\A(y|n|yes|no|true|false|on|off|null|~)\z/i
|
|
9
|
+
LEADING_SPECIAL = /\A[:#&*!|>"%@`{}\[\]]/
|
|
10
|
+
# Control characters that are invalid in YAML scalars (excludes tab \x09, newline \x0a, carriage return \x0d)
|
|
11
|
+
CONTROL_CHARS = /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/
|
|
12
|
+
|
|
13
|
+
# Quote a scalar value for YAML output.
|
|
14
|
+
# Strategy (per yaml-multiline.info):
|
|
15
|
+
# - string containing ' → normal-quoted with escaped inner content
|
|
16
|
+
# - string matching special YAML patterns → normal-quoted
|
|
17
|
+
# - all other strings → single-quoted
|
|
18
|
+
def self.quote(str)
|
|
19
|
+
return "''" if str.nil? || str.empty?
|
|
20
|
+
|
|
21
|
+
reject_control_chars!(str)
|
|
22
|
+
|
|
23
|
+
if str.include?("'")
|
|
24
|
+
escaped = str.gsub('\\', '\\\\\\\\').gsub('"', '\\"')
|
|
25
|
+
return "\"#{escaped}\""
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
return "\"#{str.gsub('\\', '\\\\\\\\').gsub('"', '\\"')}\"" if needs_normal_quote?(str)
|
|
29
|
+
|
|
30
|
+
"'#{str}'"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.reject_control_chars!(str)
|
|
34
|
+
return unless CONTROL_CHARS.match?(str)
|
|
35
|
+
|
|
36
|
+
raise InvalidCharacterError, "String contains YAML-invalid control characters: #{str.inspect}"
|
|
37
|
+
end
|
|
38
|
+
private_class_method :reject_control_chars!
|
|
39
|
+
|
|
40
|
+
def self.needs_normal_quote?(str)
|
|
41
|
+
LEADING_SPECIAL.match?(str) ||
|
|
42
|
+
BOOLEAN_LIKE.match?(str) ||
|
|
43
|
+
str.include?(': ') ||
|
|
44
|
+
str.include?(' #')
|
|
45
|
+
end
|
|
46
|
+
private_class_method :needs_normal_quote?
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/snippet_cli.rb
CHANGED
|
@@ -1,4 +1,47 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'dry/cli'
|
|
4
|
+
require_relative 'snippet_cli/version'
|
|
5
|
+
require_relative 'snippet_cli/commands/version'
|
|
6
|
+
require_relative 'snippet_cli/commands/conflict'
|
|
7
|
+
require_relative 'snippet_cli/commands/vars'
|
|
8
|
+
require_relative 'snippet_cli/commands/new'
|
|
9
|
+
require_relative 'snippet_cli/commands/check'
|
|
2
10
|
|
|
3
11
|
module SnippetCli
|
|
12
|
+
# Raised when any Gum prompt is cancelled by Ctrl+C.
|
|
13
|
+
class WizardInterrupted < StandardError; end
|
|
14
|
+
|
|
15
|
+
# Raised by FileHelper when a required file does not exist.
|
|
16
|
+
class FileMissingError < StandardError; end
|
|
17
|
+
|
|
18
|
+
# Raised by YamlLoader when a file contains invalid YAML syntax.
|
|
19
|
+
class InvalidYamlError < StandardError; end
|
|
20
|
+
|
|
21
|
+
# Raised by TriggerResolver when mutually exclusive trigger flags are combined.
|
|
22
|
+
class InvalidFlagsError < StandardError; end
|
|
23
|
+
|
|
24
|
+
# Raised by WizardHelpers when no Espanso match files are found.
|
|
25
|
+
class NoMatchFilesError < StandardError; end
|
|
26
|
+
|
|
27
|
+
# Raised by VarBuilder::Params when collected params violate the type's schema.
|
|
28
|
+
class InvalidParamsError < StandardError; end
|
|
29
|
+
|
|
30
|
+
# When stdout is piped, holds the original stdout IO for structured output (YAML).
|
|
31
|
+
# All UI continues through $stdout (redirected to the terminal).
|
|
32
|
+
@pipe_output = nil
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
attr_accessor :pipe_output
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
module CLI
|
|
39
|
+
extend Dry::CLI::Registry
|
|
40
|
+
|
|
41
|
+
register 'version', Commands::Version
|
|
42
|
+
register 'conflict', Commands::Conflict, aliases: ['c']
|
|
43
|
+
register 'vars', Commands::Vars, aliases: ['v']
|
|
44
|
+
register 'new', Commands::New, aliases: ['n']
|
|
45
|
+
register 'check', Commands::Check, aliases: ['k']
|
|
46
|
+
end
|
|
4
47
|
end
|