refactoring load-config and Config.struct
This commit is contained in:
parent
c9c6d8e79b
commit
5cf5765160
|
@ -0,0 +1,125 @@
|
|||
require "../spec_helper"
|
||||
require "../../src/fingers/config"
|
||||
|
||||
describe Fingers::Config do
|
||||
describe "errors" do
|
||||
it "should valid when there are noerrors" do
|
||||
conf = Fingers::Config.build
|
||||
conf.valid?.should eq(true)
|
||||
end
|
||||
|
||||
it "should not be valid when there are errors" do
|
||||
conf = Fingers::Config.build
|
||||
conf.errors << "shit"
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
|
||||
it "errors should not be serialized" do
|
||||
conf = Fingers::Config.build
|
||||
has_errors = !!conf.to_json.match(/errors/)
|
||||
has_errors.should eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "keyboard-layout" do
|
||||
it "is valid for known layouts" do
|
||||
conf = Fingers::Config.build
|
||||
conf.keyboard_layout = "qwerty"
|
||||
conf.valid?.should eq(true)
|
||||
end
|
||||
|
||||
it "is should not include disallowed chars" do
|
||||
conf = Fingers::Config.build
|
||||
conf.keyboard_layout = "qwerty"
|
||||
conf.alphabet.includes?("c").should eq(false)
|
||||
conf.alphabet.includes?("i").should eq(false)
|
||||
conf.alphabet.includes?("m").should eq(false)
|
||||
conf.alphabet.includes?("q").should eq(false)
|
||||
conf.alphabet.includes?("n").should eq(false)
|
||||
end
|
||||
|
||||
it "is not valid for unknown layouts" do
|
||||
conf = Fingers::Config.build
|
||||
conf.keyboard_layout = "potato"
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
|
||||
it "is qwerty by default" do
|
||||
conf = Fingers::Config.build
|
||||
conf.keyboard_layout.should eq("qwerty")
|
||||
end
|
||||
|
||||
it "populates alphabet" do
|
||||
conf = Fingers::Config.build
|
||||
conf.alphabet.empty?.should eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "patterns" do
|
||||
it "is valid for correct regexp" do
|
||||
conf = Fingers::Config.build
|
||||
conf.patterns = ["(foo|bar)"]
|
||||
conf.valid?.should eq(true)
|
||||
conf.patterns.size.should be > 0
|
||||
end
|
||||
|
||||
it "is not valid for incorrect regexps" do
|
||||
conf = Fingers::Config.build
|
||||
conf.patterns = ["(unbalanced"]
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
|
||||
it "is empty by default" do
|
||||
conf = Fingers::Config.build
|
||||
conf.patterns.size.should eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
describe "styles" do
|
||||
it "is valid for correct style" do
|
||||
conf = Fingers::Config.build
|
||||
conf.highlight_style = "fg=blue"
|
||||
conf.valid?.should eq(true)
|
||||
end
|
||||
|
||||
it "is not valid for incorrect style" do
|
||||
conf = Fingers::Config.build
|
||||
conf.highlight_style = "fg=shit"
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "hint_position" do
|
||||
it "is valid for correct value" do
|
||||
conf = Fingers::Config.build
|
||||
conf.hint_position = "left"
|
||||
conf.valid?.should eq(true)
|
||||
end
|
||||
|
||||
it "is not valid for incorrect value" do
|
||||
conf = Fingers::Config.build
|
||||
conf.hint_position = "behind"
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "set_option" do
|
||||
it "can set known options" do
|
||||
conf = Fingers::Config.build
|
||||
conf.set_option("keyboard_layout", "qwerty")
|
||||
conf.valid?.should eq(true)
|
||||
end
|
||||
|
||||
it "can set known options with invalid values" do
|
||||
conf = Fingers::Config.build
|
||||
conf.set_option("keyboard_layout", "caca")
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
|
||||
it "is invalid when setting wrong option names" do
|
||||
conf = Fingers::Config.build
|
||||
conf.set_option("potato", "tomato")
|
||||
conf.valid?.should eq(false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,77 @@
|
|||
require "../../../spec_helper.cr"
|
||||
require "../../../../src/fingers/commands/load_config"
|
||||
|
||||
class FakeShell < Shell
|
||||
@known_cmds = {} of String => String
|
||||
|
||||
def exec(cmd) : String
|
||||
output = @known_cmds[cmd]?
|
||||
|
||||
return "" if cmd =~ /bind-key.*send-input/
|
||||
|
||||
if output.nil?
|
||||
puts "Unknown cmd #{cmd}"
|
||||
""
|
||||
else
|
||||
output
|
||||
end
|
||||
end
|
||||
|
||||
def expect(cmd, output)
|
||||
@known_cmds[cmd] = output
|
||||
end
|
||||
|
||||
def clear!
|
||||
@known_cmds = {} of String => String
|
||||
end
|
||||
end
|
||||
|
||||
describe Fingers::Commands::LoadConfig do
|
||||
it "can be instantiated" do
|
||||
cmd = Fingers::Commands::LoadConfig.new(FakeShell.new)
|
||||
end
|
||||
|
||||
it "can run" do
|
||||
shell = FakeShell.new
|
||||
cmd = Fingers::Commands::LoadConfig.new(shell: shell, executable_path: "/path/to/fingers", log_path: "/tmp/log_path")
|
||||
|
||||
shell.expect("tmux show-options -g | grep ^@fingers", "@fingers-key")
|
||||
shell.expect("tmux show-option -gv @fingers-key", "F")
|
||||
shell.expect("tmux -V", "3.3a")
|
||||
shell.expect(%(tmux bind-key F run-shell -b "/path/to/fingers start '\#{pane_id}' self >>/tmp/log_path 2>&1"), "")
|
||||
|
||||
cmd.run
|
||||
end
|
||||
|
||||
it "assigns options to config struct" do
|
||||
shell = FakeShell.new
|
||||
cmd = Fingers::Commands::LoadConfig.new(shell: shell, executable_path: "/path/to/fingers", log_path: "/tmp/log_path")
|
||||
|
||||
shell.expect("tmux show-options -g | grep ^@fingers", "@fingers-key")
|
||||
shell.expect("tmux show-option -gv @fingers-key", "A")
|
||||
shell.expect("tmux -V", "3.3a")
|
||||
shell.expect(%(tmux bind-key A run-shell -b "/path/to/fingers start '\#{pane_id}' self >>/tmp/log_path 2>&1"), "")
|
||||
|
||||
cmd.run
|
||||
Fingers.config.key.should eq("A")
|
||||
end
|
||||
|
||||
it "propagates config errors" do
|
||||
shell = FakeShell.new
|
||||
output = IO::Memory.new
|
||||
cmd = Fingers::Commands::LoadConfig.new(shell: shell, executable_path: "/path/to/fingers", log_path: "/tmp/log_path", output: output)
|
||||
|
||||
shell.expect("tmux show-options -g | grep ^@fingers", "@fingers-hint-style")
|
||||
shell.expect("tmux show-option -gv @fingers-hint-style", "fg=caca")
|
||||
shell.expect("tmux -V", "3.3a")
|
||||
shell.expect(%(tmux bind-key F run-shell -b "/path/to/fingers start '\#{pane_id}' self >>/tmp/log_path 2>&1"), "")
|
||||
shell.expect(%(tmux set-option -ug @fingers-hint-style), "")
|
||||
|
||||
cmd.run
|
||||
|
||||
output.rewind
|
||||
|
||||
cmd.errors.empty?.should eq(false)
|
||||
(output.gets || "").size.should be > 0
|
||||
end
|
||||
end
|
|
@ -1,7 +1,7 @@
|
|||
require "spec"
|
||||
require "../../src/tmux_style_printer"
|
||||
|
||||
class FakeShell < TmuxStylePrinter::Shell
|
||||
class FakeShell < Shell
|
||||
def exec(cmd)
|
||||
"$(#{cmd})"
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ module Fingers
|
|||
when "start"
|
||||
Fingers::Commands::Start.new(args)
|
||||
when "load-config"
|
||||
Fingers::Commands::LoadConfig.new(args)
|
||||
Fingers::Commands::LoadConfig.new
|
||||
when "send-input"
|
||||
Fingers::Commands::SendInput.new(args)
|
||||
when "version"
|
||||
|
|
|
@ -2,22 +2,30 @@ require "file_utils"
|
|||
require "./base"
|
||||
require "../dirs"
|
||||
require "../config"
|
||||
require "../types"
|
||||
require "../../tmux"
|
||||
require "../../persistent_shell"
|
||||
|
||||
class Fingers::Commands::LoadConfig < Fingers::Commands::Base
|
||||
class Fingers::Commands::LoadConfig
|
||||
@fingers_options_names : Array(String) | Nil
|
||||
|
||||
property config : Fingers::Config
|
||||
property shell : Shell
|
||||
property log_path : String
|
||||
property executable_path : String
|
||||
property errors : Array(String) = [] of String
|
||||
property output : IO
|
||||
|
||||
DISALLOWED_CHARS = /cimqn/
|
||||
|
||||
def initialize(*args)
|
||||
super(*args)
|
||||
@config = Fingers::Config.new
|
||||
def initialize(
|
||||
@shell = PersistentShell.new,
|
||||
@log_path = Fingers::Dirs::LOG_PATH.to_s,
|
||||
@executable_path = Process.executable_path.to_s,
|
||||
@output = STDOUT
|
||||
)
|
||||
@config = Fingers::Config.build
|
||||
end
|
||||
|
||||
def run
|
||||
validate_options!
|
||||
parse_tmux_conf
|
||||
setup_bindings
|
||||
end
|
||||
|
@ -31,75 +39,46 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
|
|||
|
||||
Fingers.reset_config
|
||||
|
||||
config.tmux_version = `tmux -V`.chomp.split(" ").last
|
||||
config.tmux_version = shell.exec("tmux -V").chomp.split(" ").last
|
||||
|
||||
options.each do |option, value|
|
||||
# TODO generate an enum somehow and use an exhaustive case
|
||||
case option
|
||||
when "key"
|
||||
config.key = value
|
||||
when "keyboard_layout"
|
||||
config.keyboard_layout = value
|
||||
when "main_action"
|
||||
config.main_action = value
|
||||
when "ctrl_action"
|
||||
config.ctrl_action = value
|
||||
when "alt_action"
|
||||
config.alt_action = value
|
||||
when "shift_action"
|
||||
config.shift_action = value
|
||||
when "benchmark_mode"
|
||||
config.benchmark_mode = value
|
||||
when "hint_position"
|
||||
config.hint_position = value
|
||||
when "hint_style"
|
||||
config.hint_style = tmux.parse_style(value)
|
||||
when "selected_hint_style"
|
||||
config.selected_hint_style = tmux.parse_style(value)
|
||||
when "highlight_style"
|
||||
config.highlight_style = tmux.parse_style(value)
|
||||
when "backdrop_style"
|
||||
config.backdrop_style = tmux.parse_style(value)
|
||||
when "selected_highlight_style"
|
||||
config.selected_highlight_style = tmux.parse_style(value)
|
||||
if option.match(/pattern_[0-9]+/)
|
||||
user_defined_patterns << value
|
||||
next
|
||||
end
|
||||
|
||||
if option.match(/pattern/)
|
||||
check_pattern!(value)
|
||||
user_defined_patterns.push(value)
|
||||
config.set_option(option, value)
|
||||
|
||||
if !config.valid?
|
||||
unset_tmux_option!(method_to_option(option))
|
||||
output.puts "Found errors #{config.errors}"
|
||||
self.errors = config.errors.clone
|
||||
end
|
||||
end
|
||||
|
||||
config.patterns = clean_up_patterns([
|
||||
config.patterns = [
|
||||
*enabled_default_patterns,
|
||||
*user_defined_patterns,
|
||||
])
|
||||
]
|
||||
|
||||
config.alphabet = ::Fingers::Config::ALPHABET_MAP[Fingers.config.keyboard_layout].split("").reject do |char|
|
||||
char.match(DISALLOWED_CHARS)
|
||||
if !config.valid?
|
||||
output.puts "Found errors #{config.errors}"
|
||||
#exit(1)
|
||||
end
|
||||
|
||||
config.save
|
||||
|
||||
Fingers.reset_config
|
||||
rescue e : TmuxStylePrinter::InvalidFormat
|
||||
puts "[tmux-fingers] #{e.message}"
|
||||
exit(1)
|
||||
end
|
||||
|
||||
def clean_up_patterns(patterns)
|
||||
patterns.reject(&.empty?)
|
||||
end
|
||||
|
||||
def setup_bindings
|
||||
`tmux bind-key #{Fingers.config.key} run-shell -b "#{cli} start "\#{pane_id}" self >>#{Fingers::Dirs::LOG_PATH} 2>&1"`
|
||||
`tmux bind-key O run-shell -b "#{cli} start "\#{pane_id}" other >>#{Fingers::Dirs::LOG_PATH} 2>&1"`
|
||||
shell.exec(%(tmux bind-key #{Fingers.config.key} run-shell -b "#{executable_path} start '\#{pane_id}' self >>#{log_path} 2>&1"))
|
||||
setup_fingers_mode_bindings
|
||||
end
|
||||
|
||||
def setup_fingers_mode_bindings
|
||||
("a".."z").to_a.each do |char|
|
||||
next if char.match(DISALLOWED_CHARS)
|
||||
next if char.match(Fingers::Config::DISALLOWED_CHARS)
|
||||
|
||||
fingers_mode_bind(char, "hint:#{char}:main")
|
||||
fingers_mode_bind(char.upcase, "hint:#{char}:shift")
|
||||
|
@ -124,79 +103,43 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
|
|||
::Fingers::Config::DEFAULT_PATTERNS.values
|
||||
end
|
||||
|
||||
def to_bool(input)
|
||||
input == "1"
|
||||
end
|
||||
|
||||
def shell_safe_options
|
||||
options = {} of String => String
|
||||
|
||||
fingers_options_names.each do |option|
|
||||
option_method = option_to_method(option)
|
||||
|
||||
options[option_method] = `tmux show-option -gv #{option}`.chomp
|
||||
options[option_method] = shell.exec(%(tmux show-option -gv #{option})).chomp
|
||||
end
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
def valid_option?(option)
|
||||
option_method = option_to_method(option)
|
||||
|
||||
@config.members.includes?(option_method) || option_method.match(/pattern_[0-9]+/) || option_method == "skip_wizard"
|
||||
end
|
||||
|
||||
def fingers_options_names
|
||||
@fingers_options_names ||= `tmux show-options -g | grep ^@fingers`
|
||||
@fingers_options_names ||= shell.exec(%(tmux show-options -g | grep ^@fingers))
|
||||
.chomp.split("\n")
|
||||
.map { |line| line.split(" ")[0] }
|
||||
.reject { |option| option.empty? }
|
||||
end
|
||||
|
||||
def unset_tmux_option!(option)
|
||||
`tmux set-option -ug #{option}`
|
||||
end
|
||||
|
||||
def check_pattern!(pattern)
|
||||
begin
|
||||
Regex.new(pattern)
|
||||
rescue e: ArgumentError
|
||||
puts "[tmux-fingers] Invalid pattern: #{pattern}"
|
||||
puts "[tmux-fingers] #{e.message}"
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
def validate_options!
|
||||
errors = [] of String
|
||||
|
||||
fingers_options_names.each do |option|
|
||||
unless valid_option?(option)
|
||||
errors << "'#{option}' is not a valid option"
|
||||
unset_tmux_option!(option)
|
||||
end
|
||||
end
|
||||
|
||||
return if errors.empty?
|
||||
|
||||
puts "[tmux-fingers] Errors found in tmux.conf:"
|
||||
errors.each { |error| puts " - #{error}" }
|
||||
exit(1)
|
||||
shell.exec(%(tmux set-option -ug #{option}))
|
||||
end
|
||||
|
||||
def option_to_method(option)
|
||||
option.gsub(/^@fingers-/, "").tr("-", "_")
|
||||
end
|
||||
|
||||
def fingers_mode_bind(key, command)
|
||||
`tmux bind-key -Tfingers "#{key}" run-shell -b "#{cli} send-input #{command}"`
|
||||
def method_to_option(method)
|
||||
"@fingers-#{method.tr("_", "-")}"
|
||||
end
|
||||
|
||||
def cli
|
||||
Process.executable_path
|
||||
def fingers_mode_bind(key, command)
|
||||
shell.exec(%(tmux bind-key -Tfingers "#{key}" run-shell -b "#{executable_path} send-input #{command}"))
|
||||
end
|
||||
|
||||
|
||||
def tmux
|
||||
Tmux.new(`tmux -V`.chomp.split(" ").last)
|
||||
Tmux.new(shell.exec("tmux -V").chomp.split(" ").last)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,42 +1,10 @@
|
|||
require "json"
|
||||
require "../tmux_style_printer"
|
||||
|
||||
module Fingers
|
||||
struct Config
|
||||
include JSON::Serializable
|
||||
|
||||
property key : String
|
||||
property keyboard_layout : String
|
||||
property patterns : Array(String)
|
||||
property alphabet : Array(String)
|
||||
property benchmark_mode : String
|
||||
property main_action : String
|
||||
property ctrl_action : String
|
||||
property alt_action : String
|
||||
property shift_action : String
|
||||
property hint_position : String
|
||||
property hint_style : String
|
||||
property selected_hint_style : String
|
||||
property highlight_style : String
|
||||
property selected_highlight_style : String
|
||||
property backdrop_style : String
|
||||
property tmux_version : String
|
||||
|
||||
FORMAT_PRINTER = TmuxStylePrinter.new
|
||||
|
||||
DEFAULT_PATTERNS = {
|
||||
"ip": "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}",
|
||||
"uuid": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
||||
"sha": "[0-9a-f]{7,128}",
|
||||
"digit": "[0-9]{4,}",
|
||||
"url": "((https?://|git@|git://|ssh://|ftp://|file:///)[^\\s()\"]+)",
|
||||
"path": "(([.\\w\\-~\\$@]+)?(/[.\\w\\-@]+)+/?)",
|
||||
"hex": "(0x[0-9a-fA-F]+)",
|
||||
"kubernetes": "(deployment.app|binding|componentstatuse|configmap|endpoint|event|limitrange|namespace|node|persistentvolumeclaim|persistentvolume|pod|podtemplate|replicationcontroller|resourcequota|secret|serviceaccount|service|mutatingwebhookconfiguration.admissionregistration.k8s.io|validatingwebhookconfiguration.admissionregistration.k8s.io|customresourcedefinition.apiextension.k8s.io|apiservice.apiregistration.k8s.io|controllerrevision.apps|daemonset.apps|deployment.apps|replicaset.apps|statefulset.apps|tokenreview.authentication.k8s.io|localsubjectaccessreview.authorization.k8s.io|selfsubjectaccessreviews.authorization.k8s.io|selfsubjectrulesreview.authorization.k8s.io|subjectaccessreview.authorization.k8s.io|horizontalpodautoscaler.autoscaling|cronjob.batch|job.batch|certificatesigningrequest.certificates.k8s.io|events.events.k8s.io|daemonset.extensions|deployment.extensions|ingress.extensions|networkpolicies.extensions|podsecuritypolicies.extensions|replicaset.extensions|networkpolicie.networking.k8s.io|poddisruptionbudget.policy|clusterrolebinding.rbac.authorization.k8s.io|clusterrole.rbac.authorization.k8s.io|rolebinding.rbac.authorization.k8s.io|role.rbac.authorization.k8s.io|storageclasse.storage.k8s.io)[[:alnum:]_#$%&+=/@-]+",
|
||||
"git-status": "(modified|deleted|new file): +(?<match>.+)",
|
||||
"git-status-branch": "Your branch is up to date with '(?<match>.*)'.",
|
||||
"diff": "(---|\\+\\+\\+) [ab]/(?<match>.*)",
|
||||
}
|
||||
|
||||
ALPHABET_MAP = {
|
||||
"qwerty": "asdfqwerzxcvjklmiuopghtybn",
|
||||
"qwerty-homerow": "asdfjklgh",
|
||||
|
@ -60,24 +28,154 @@ module Fingers
|
|||
"colemak-right-hand": "neioluymjhk",
|
||||
}
|
||||
|
||||
def initialize(
|
||||
@key = "F",
|
||||
@keyboard_layout = "qwerty",
|
||||
@alphabet = [] of String,
|
||||
@patterns = [] of String,
|
||||
@main_action = ":copy:",
|
||||
@ctrl_action = ":open:",
|
||||
@alt_action = "",
|
||||
@shift_action = ":paste:",
|
||||
@hint_position = "left",
|
||||
@hint_style = FORMAT_PRINTER.print("fg=green,bold"),
|
||||
@highlight_style = FORMAT_PRINTER.print("fg=yellow"),
|
||||
@selected_hint_style = FORMAT_PRINTER.print("fg=blue,bold"),
|
||||
@selected_highlight_style = FORMAT_PRINTER.print("fg=blue"),
|
||||
@backdrop_style = "",
|
||||
@tmux_version = "",
|
||||
@benchmark_mode = "0"
|
||||
)
|
||||
DISALLOWED_CHARS = /[cimqn]/
|
||||
|
||||
DEFAULT_PATTERNS = {
|
||||
"ip": "\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}",
|
||||
"uuid": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}",
|
||||
"sha": "[0-9a-f]{7,128}",
|
||||
"digit": "[0-9]{4,}",
|
||||
"url": "((https?://|git@|git://|ssh://|ftp://|file:///)[^\\s()\"]+)",
|
||||
"path": "(([.\\w\\-~\\$@]+)?(/[.\\w\\-@]+)+/?)",
|
||||
"hex": "(0x[0-9a-fA-F]+)",
|
||||
"kubernetes": "(deployment.app|binding|componentstatuse|configmap|endpoint|event|limitrange|namespace|node|persistentvolumeclaim|persistentvolume|pod|podtemplate|replicationcontroller|resourcequota|secret|serviceaccount|service|mutatingwebhookconfiguration.admissionregistration.k8s.io|validatingwebhookconfiguration.admissionregistration.k8s.io|customresourcedefinition.apiextension.k8s.io|apiservice.apiregistration.k8s.io|controllerrevision.apps|daemonset.apps|deployment.apps|replicaset.apps|statefulset.apps|tokenreview.authentication.k8s.io|localsubjectaccessreview.authorization.k8s.io|selfsubjectaccessreviews.authorization.k8s.io|selfsubjectrulesreview.authorization.k8s.io|subjectaccessreview.authorization.k8s.io|horizontalpodautoscaler.autoscaling|cronjob.batch|job.batch|certificatesigningrequest.certificates.k8s.io|events.events.k8s.io|daemonset.extensions|deployment.extensions|ingress.extensions|networkpolicies.extensions|podsecuritypolicies.extensions|replicaset.extensions|networkpolicie.networking.k8s.io|poddisruptionbudget.policy|clusterrolebinding.rbac.authorization.k8s.io|clusterrole.rbac.authorization.k8s.io|rolebinding.rbac.authorization.k8s.io|role.rbac.authorization.k8s.io|storageclasse.storage.k8s.io)[[:alnum:]_#$%&+=/@-]+",
|
||||
"git-status": "(modified|deleted|new file): +(?<match>.+)",
|
||||
"git-status-branch": "Your branch is up to date with '(?<match>.*)'.",
|
||||
"diff": "(---|\\+\\+\\+) [ab]/(?<match>.*)",
|
||||
}
|
||||
|
||||
def self.build
|
||||
from_json("{}")
|
||||
end
|
||||
|
||||
def self.alphabet_for(layout)
|
||||
ALPHABET_MAP[layout].split("").reject { |char| char =~ DISALLOWED_CHARS }
|
||||
end
|
||||
|
||||
def self.parse_style(style)
|
||||
FORMAT_PRINTER.print(style)
|
||||
end
|
||||
|
||||
include JSON::Serializable
|
||||
|
||||
property key : String = "F"
|
||||
|
||||
getter keyboard_layout : String = "qwerty"
|
||||
def keyboard_layout=(value)
|
||||
if !ALPHABET_MAP[value]?
|
||||
errors << "Invalid layout #{value}"
|
||||
return
|
||||
end
|
||||
|
||||
@keyboard_layout = value
|
||||
end
|
||||
|
||||
def alphabet
|
||||
self.class.alphabet_for(keyboard_layout)
|
||||
end
|
||||
|
||||
getter patterns : Array(String) = [] of String
|
||||
def patterns=(value)
|
||||
value.each do |pattern|
|
||||
error = Regex.error?(pattern)
|
||||
if error
|
||||
@errors << "Invalid regexp\n\t#{pattern}\n\t#{error}"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@patterns = value
|
||||
end
|
||||
|
||||
getter highlight_style : String = parse_style("fg=green,bold")
|
||||
def highlight_style=(value)
|
||||
parsed_style = parse_style!(value)
|
||||
@highlight_style if parsed_style
|
||||
end
|
||||
|
||||
def parse_style!(style)
|
||||
begin
|
||||
self.class.parse_style(style)
|
||||
rescue TmuxStylePrinter::InvalidFormat
|
||||
@errors << "Invalid style: #{style}"
|
||||
end
|
||||
end
|
||||
|
||||
getter highlight_style : String = parse_style("fg=yellow")
|
||||
def highlight_style=(value)
|
||||
parsed_style = parse_style!(value)
|
||||
@highlight_style if parsed_style
|
||||
end
|
||||
|
||||
getter hint_style : String = parse_style("fg=green,bold")
|
||||
def hint_style=(value)
|
||||
parsed_style = parse_style!(value)
|
||||
@hint_style if parsed_style
|
||||
end
|
||||
|
||||
getter selected_highlight_style : String = parse_style("fg=blue")
|
||||
def highlight_style=(value)
|
||||
parsed_style = parse_style!(value)
|
||||
@highlight_style if parsed_style
|
||||
end
|
||||
|
||||
getter selected_hint_style : String = parse_style("fg=blue,bold")
|
||||
def hint_style=(value)
|
||||
parsed_style = parse_style!(value)
|
||||
@hint_style if parsed_style
|
||||
end
|
||||
|
||||
getter backdrop_style : String = ""
|
||||
def hint_style=(value)
|
||||
parsed_style = parse_style!(value)
|
||||
@backdrop_style if parsed_style
|
||||
end
|
||||
|
||||
def parse_style!(style)
|
||||
begin
|
||||
self.class.parse_style(style)
|
||||
rescue TmuxStylePrinter::InvalidFormat
|
||||
@errors << "Invalid style: #{style}"
|
||||
end
|
||||
end
|
||||
|
||||
property tmux_version : String = ""
|
||||
property main_action : String = ":copy:"
|
||||
property ctrl_action : String = ":open:"
|
||||
property alt_action : String = ""
|
||||
property shift_action : String = ":paste: "
|
||||
|
||||
getter hint_position : String = "left"
|
||||
def hint_position=(value)
|
||||
if !["left", "right"].includes?(value)
|
||||
@errors << "Invalid hint_position #{value}"
|
||||
end
|
||||
@hint_position = value
|
||||
end
|
||||
|
||||
property benchmark_mode : String = "0"
|
||||
property skip_wizard : String = "0"
|
||||
|
||||
@[JSON::Field(ignore: true)]
|
||||
property errors : Array(String) = [] of String
|
||||
|
||||
def valid?
|
||||
errors.empty?
|
||||
end
|
||||
|
||||
macro define_set_option
|
||||
def set_option(option : String, value : String | Array(String))
|
||||
case option
|
||||
{% for method in @type.methods %}
|
||||
{% if method.name.split("").last == "=" && method.name != "patterns=" && method.name != "errors=" %}
|
||||
when "{{method.name.gsub(/=$/, "")}}"
|
||||
self.{{method.name}} value
|
||||
{% end %}
|
||||
{% end %}
|
||||
else
|
||||
errors << "#{option} is not a valid option"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.load_from_cache
|
||||
|
@ -91,12 +189,16 @@ module Fingers
|
|||
def members : Array(String)
|
||||
JSON.parse(to_json).as_h.keys
|
||||
end
|
||||
|
||||
macro finished
|
||||
define_set_option
|
||||
end
|
||||
end
|
||||
|
||||
def self.config
|
||||
@@config ||= Config.load_from_cache
|
||||
rescue
|
||||
@@config ||= Config.new
|
||||
@@config ||= Config.build
|
||||
end
|
||||
|
||||
def self.reset_config
|
||||
|
|
|
@ -8,3 +8,7 @@ module Fingers
|
|||
abstract def format(hint : String, highlight : String, selected : Bool, offset : Tuple(Int32, Int32) | Nil)
|
||||
end
|
||||
end
|
||||
|
||||
abstract class Shell
|
||||
abstract def exec(cmd)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
require "./fingers/types"
|
||||
|
||||
class PersistentShell < Shell
|
||||
def initialize
|
||||
@sh = Process.new("/bin/sh", input: :pipe, output: :pipe, error: :close)
|
||||
end
|
||||
|
||||
def exec(cmd)
|
||||
ch = Channel(String).new
|
||||
|
||||
spawn do
|
||||
output = ""
|
||||
while line = @sh.output.read_line
|
||||
break if line == "cmd-end"
|
||||
|
||||
output += "#{line}\n"
|
||||
end
|
||||
|
||||
ch.send(output)
|
||||
end
|
||||
|
||||
@sh.input.print("#{cmd}; echo cmd-end\n")
|
||||
@sh.input.flush
|
||||
output = ch.receive
|
||||
output
|
||||
end
|
||||
end
|
28
src/tmux.cr
28
src/tmux.cr
|
@ -39,32 +39,6 @@ end
|
|||
|
||||
# rubocop:disable Metrics/ClassLength
|
||||
class Tmux
|
||||
class Shell
|
||||
def initialize
|
||||
@sh = Process.new("/bin/sh", input: :pipe, output: :pipe, error: :close)
|
||||
end
|
||||
|
||||
def exec(cmd)
|
||||
ch = Channel(String).new
|
||||
|
||||
spawn do
|
||||
output = ""
|
||||
while line = @sh.output.read_line
|
||||
break if line == "cmd-end"
|
||||
|
||||
output += "#{line}\n"
|
||||
end
|
||||
|
||||
ch.send(output)
|
||||
end
|
||||
|
||||
@sh.input.print("#{cmd}; echo cmd-end\n")
|
||||
@sh.input.flush
|
||||
output = ch.receive
|
||||
output
|
||||
end
|
||||
end
|
||||
|
||||
struct Pane
|
||||
include JSON::Serializable
|
||||
|
||||
|
@ -130,7 +104,7 @@ class Tmux
|
|||
end
|
||||
|
||||
def initialize(version_string)
|
||||
@sh = Shell.new
|
||||
@sh = PersistentShell.new
|
||||
@version = Tmux.tmux_version_to_semver(version_string)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
require "./fingers/types"
|
||||
|
||||
class TmuxStylePrinter
|
||||
|
||||
class InvalidFormat < Exception
|
||||
end
|
||||
|
||||
abstract class Shell
|
||||
abstract def exec(cmd)
|
||||
end
|
||||
|
||||
STYLE_SEPARATOR = /[ ,]+/
|
||||
|
||||
COLOR_MAP = {
|
||||
|
|
Loading…
Reference in New Issue