This commit is contained in:
Jorge Morante 2022-07-06 16:46:12 +02:00
parent 4d45983f71
commit 661c6210a9
29 changed files with 444 additions and 420 deletions

11
Gemfile
View File

@ -1,8 +1,9 @@
source 'https://rubygems.org' source "https://rubygems.org"
group :development do group :development do
gem 'irb' gem "byebug"
gem 'byebug' gem "irb"
gem 'rspec' gem "rspec"
gem 'rspec-retry' gem "rspec-retry"
gem "standardrb"
end end

View File

@ -1,13 +1,20 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
ast (2.4.2)
byebug (11.1.3) byebug (11.1.3)
diff-lcs (1.3) diff-lcs (1.3)
io-console (0.5.6) io-console (0.5.6)
irb (1.2.4) irb (1.2.4)
reline (>= 0.0.1) reline (>= 0.0.1)
parallel (1.22.1)
parser (3.1.2.0)
ast (~> 2.4.1)
rainbow (3.1.1)
regexp_parser (2.5.0)
reline (0.1.4) reline (0.1.4)
io-console (~> 0.5) io-console (~> 0.5)
rexml (3.2.5)
rspec (3.9.0) rspec (3.9.0)
rspec-core (~> 3.9.0) rspec-core (~> 3.9.0)
rspec-expectations (~> 3.9.0) rspec-expectations (~> 3.9.0)
@ -23,6 +30,27 @@ GEM
rspec-retry (0.6.2) rspec-retry (0.6.2)
rspec-core (> 3.3) rspec-core (> 3.3)
rspec-support (3.9.3) rspec-support (3.9.3)
rubocop (1.29.1)
parallel (~> 1.10)
parser (>= 3.1.0.0)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.17.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.18.0)
parser (>= 3.1.1.0)
rubocop-performance (1.13.3)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
ruby-progressbar (1.11.0)
standard (1.12.1)
rubocop (= 1.29.1)
rubocop-performance (= 1.13.3)
standardrb (1.0.1)
standard
unicode-display_width (2.2.0)
PLATFORMS PLATFORMS
ruby ruby
@ -33,6 +61,7 @@ DEPENDENCIES
irb irb
rspec rspec
rspec-retry rspec-retry
standardrb
BUNDLED WITH BUNDLED WITH
2.2.2 2.2.2

12
Vagrantfile vendored
View File

@ -4,13 +4,13 @@
# requires nfs-utils on host # requires nfs-utils on host
Vagrant.configure(2) do |config| Vagrant.configure(2) do |config|
config.vm.provider 'virtualbox' do |v| config.vm.provider "virtualbox" do |v|
v.customize ['modifyvm', :id, '--cpuexecutioncap', '50'] v.customize ["modifyvm", :id, "--cpuexecutioncap", "50"]
end end
config.vm.define 'ubuntu' do |machine| config.vm.define "ubuntu" do |machine|
machine.vm.box = 'ubuntu/focal64' machine.vm.box = "ubuntu/focal64"
machine.vm.synced_folder '.', '/home/vagrant/shared' machine.vm.synced_folder ".", "/home/vagrant/shared"
machine.vm.provision 'shell', path: './spec/provisioning/ubuntu.sh' machine.vm.provision "shell", path: "./spec/provisioning/ubuntu.sh"
end end
end end

View File

@ -1,41 +1,41 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'logger' require "logger"
require 'json' require "json"
require 'singleton' require "singleton"
require 'timeout' require "timeout"
require 'socket' require "socket"
require 'pathname' require "pathname"
require 'tmpdir' require "tmpdir"
require 'set' require "set"
# Top level fingers namespace # Top level fingers namespace
module Fingers module Fingers
end end
require 'tmux' require "tmux"
require 'tmux_format_printer' require "tmux_format_printer"
require 'huffman' require "huffman"
require 'priority_queue' require "priority_queue"
require 'fingers/version' require "fingers/version"
require 'fingers/dirs' require "fingers/dirs"
require 'fingers/config' require "fingers/config"
# commands # commands
# TODO dynamically require command? # TODO dynamically require command?
require 'fingers/commands' require "fingers/commands"
require 'fingers/commands/base' require "fingers/commands/base"
require 'fingers/commands/check_version' require "fingers/commands/check_version"
require 'fingers/commands/load_config' require "fingers/commands/load_config"
require 'fingers/commands/send_input' require "fingers/commands/send_input"
require 'fingers/commands/start' require "fingers/commands/start"
require 'fingers/commands/trace_start' require "fingers/commands/trace_start"
require 'fingers/action_runner' require "fingers/action_runner"
require 'fingers/hinter' require "fingers/hinter"
require 'fingers/input_socket' require "fingers/input_socket"
require 'fingers/logger' require "fingers/logger"
require 'fingers/view' require "fingers/view"
require 'fingers/match_formatter' require "fingers/match_formatter"
require 'fingers/cli' require "fingers/cli"

View File

@ -25,23 +25,23 @@ class Fingers::ActionRunner
return @final_shell_command if @final_shell_command return @final_shell_command if @final_shell_command
@final_shell_command = case action @final_shell_command = case action
when ':copy:' when ":copy:"
copy copy
when ':open:' when ":open:"
open open
when ':paste:' when ":paste:"
paste paste
when nil when nil
# do nothing # do nothing
else else
shell_action shell_action
end end
@final_shell_command = prepend_pane_path(@final_shell_command) @final_shell_command = prepend_pane_path(@final_shell_command)
end end
def prepend_pane_path(cmd) def prepend_pane_path(cmd)
return if (cmd || '').empty? return if (cmd || "").empty?
"cd #{original_pane.pane_current_path}; #{cmd}" "cd #{original_pane.pane_current_path}; #{cmd}"
end end
@ -61,7 +61,7 @@ class Fingers::ActionRunner
end end
def paste def paste
'tmux paste-buffer' "tmux paste-buffer"
end end
def shell_action def shell_action
@ -69,7 +69,7 @@ class Fingers::ActionRunner
end end
def action_env def action_env
{ 'MODIFIER' => modifier, 'HINT' => hint } {"MODIFIER" => modifier, "HINT" => hint}
end end
def action def action
@ -77,33 +77,33 @@ class Fingers::ActionRunner
end end
def system_copy_command def system_copy_command
@system_copy_command ||= if program_exists?('pbcopy') @system_copy_command ||= if program_exists?("pbcopy")
if program_exists?('reattach-to-user-namespace') if program_exists?("reattach-to-user-namespace")
'reattach-to-user-namespace' "reattach-to-user-namespace"
else else
'pbcopy' "pbcopy"
end end
elsif program_exists?('clip.exe') elsif program_exists?("clip.exe")
'cat | clip.exe' "cat | clip.exe"
elsif program_exists?('wl-copy') elsif program_exists?("wl-copy")
'wl-copy' "wl-copy"
elsif program_exists?('xclip') elsif program_exists?("xclip")
'xclip -selection clipboard' "xclip -selection clipboard"
elsif program_exists?('xsel') elsif program_exists?("xsel")
'xsel -i --clipboard' "xsel -i --clipboard"
elsif program_exists?('putclip') elsif program_exists?("putclip")
'putclip' "putclip"
end end
end end
def system_open_command def system_open_command
@system_open_command ||= if program_exists?('cygstart') @system_open_command ||= if program_exists?("cygstart")
'xargs cygstart' "xargs cygstart"
elsif program_exists?('xdg-open') elsif program_exists?("xdg-open")
'xargs xdg-open' "xargs xdg-open"
elsif program_exists?('open') elsif program_exists?("open")
'xargs open' "xargs open"
end end
end end
def program_exists?(program) def program_exists?(program)

View File

@ -8,26 +8,26 @@ module Fingers
end end
def run def run
Fingers.benchmark_stamp('boot:end') if ARGV[0] == 'start' Fingers.benchmark_stamp("boot:end") if ARGV[0] == "start"
command_class = case ARGV[0] command_class = case ARGV[0]
when 'start' when "start"
Fingers::Commands::Start Fingers::Commands::Start
when 'check_version' when "check_version"
Fingers::Commands::CheckVersion Fingers::Commands::CheckVersion
when 'send_input' when "send_input"
Fingers::Commands::SendInput Fingers::Commands::SendInput
when 'load_config' when "load_config"
Fingers::Commands::LoadConfig Fingers::Commands::LoadConfig
when 'trace_start' when "trace_start"
Fingers::Commands::TraceStart Fingers::Commands::TraceStart
else else
raise "Unknown command #{ARGV[0]}" raise "Unknown command #{ARGV[0]}"
end end
begin begin
command_class.new(args, cli_path).run command_class.new(args, cli_path).run
rescue StandardError => e rescue => e
Fingers.logger.error(e) Fingers.logger.error(e)
end end
end end

View File

@ -1,19 +1,19 @@
class Fingers::Commands::CheckVersion < Fingers::Commands::Base class Fingers::Commands::CheckVersion < Fingers::Commands::Base
def run def run
require 'net/https' require "net/https"
puts 'Checking version...' puts "Checking version..."
uri = URI('https://api.github.com/repos/morantron/tmux-fingers/tags') uri = URI("https://api.github.com/repos/morantron/tmux-fingers/tags")
response = Net::HTTP.get_response(uri) response = Net::HTTP.get_response(uri)
json_response = JSON.parse(response.body) json_response = JSON.parse(response.body)
latest_release = json_response.map { |tag| Gem::Version.new(tag['name']) }.max latest_release = json_response.map { |tag| Gem::Version.new(tag["name"]) }.max
current_release = Gem::Version.new(Fingers::VERSION) current_release = Gem::Version.new(Fingers::VERSION)
puts "There is a new tmux-fingers release: #{latest_release}" if latest_release > current_release puts "There is a new tmux-fingers release: #{latest_release}" if latest_release > current_release
rescue StandardError => e rescue => e
puts 'Could not check version' puts "Could not check version"
end end
end end

View File

@ -1,38 +1,38 @@
class Fingers::Commands::LoadConfig < Fingers::Commands::Base class Fingers::Commands::LoadConfig < Fingers::Commands::Base
DISALLOWED_CHARS = /cimqn/.freeze DISALLOWED_CHARS = /cimqn/
FINGERS_FILE_PATH = "#{ENV['HOME']}/.fingersrc" FINGERS_FILE_PATH = "#{ENV["HOME"]}/.fingersrc"
DEFAULT_PATTERNS = { DEFAULT_PATTERNS = {
"ip": '\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}', 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}', 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}', sha: "[0-9a-f]{7,128}",
"digit": '[0-9]{4,}', digit: "[0-9]{4,}",
"url": "((https?://|git@|git://|ssh://|ftp://|file:///)[^ ()'\"]+)", url: "((https?://|git@|git://|ssh://|ftp://|file:///)[^ ()'\"]+)",
"path": '(([.\\w\\-~\\$@]+)?(/[.\\w\\-@]+)+/?)' path: '(([.\\w\\-~\\$@]+)?(/[.\\w\\-@]+)+/?)'
}.freeze }.freeze
ALPHABET_MAP = { ALPHABET_MAP = {
"qwerty": 'asdfqwerzxcvjklmiuopghtybn', qwerty: "asdfqwerzxcvjklmiuopghtybn",
"qwerty-homerow": 'asdfjklgh', "qwerty-homerow": "asdfjklgh",
"qwerty-left-hand": 'asdfqwerzcxv', "qwerty-left-hand": "asdfqwerzcxv",
"qwerty-right-hand": 'jkluiopmyhn', "qwerty-right-hand": "jkluiopmyhn",
"azerty": 'qsdfazerwxcvjklmuiopghtybn', azerty: "qsdfazerwxcvjklmuiopghtybn",
"azerty-homerow": 'qsdfjkmgh', "azerty-homerow": "qsdfjkmgh",
"azerty-left-hand": 'qsdfazerwxcv', "azerty-left-hand": "qsdfazerwxcv",
"azerty-right-hand": 'jklmuiophyn', "azerty-right-hand": "jklmuiophyn",
"qwertz": 'asdfqweryxcvjkluiopmghtzbn', qwertz: "asdfqweryxcvjkluiopmghtzbn",
"qwertz-homerow": 'asdfghjkl', "qwertz-homerow": "asdfghjkl",
"qwertz-left-hand": 'asdfqweryxcv', "qwertz-left-hand": "asdfqweryxcv",
"qwertz-right-hand": 'jkluiopmhzn', "qwertz-right-hand": "jkluiopmhzn",
"dvorak": 'aoeuqjkxpyhtnsgcrlmwvzfidb', dvorak: "aoeuqjkxpyhtnsgcrlmwvzfidb",
"dvorak-homerow": 'aoeuhtnsid', "dvorak-homerow": "aoeuhtnsid",
"dvorak-left-hand": 'aoeupqjkyix', "dvorak-left-hand": "aoeupqjkyix",
"dvorak-right-hand": 'htnsgcrlmwvz', "dvorak-right-hand": "htnsgcrlmwvz",
"colemak": 'arstqwfpzxcvneioluymdhgjbk', colemak: "arstqwfpzxcvneioluymdhgjbk",
"colemak-homerow": 'arstneiodh', "colemak-homerow": "arstneiodh",
"colemak-left-hand": 'arstqwfpzxcv', "colemak-left-hand": "arstqwfpzxcv",
"colemak-right-hand": 'neioluymjhk' "colemak-right-hand": "neioluymjhk"
}.freeze }.freeze
def run def run
@ -56,9 +56,9 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
option = option option = option
if option.match(/pattern/) if /pattern/.match?(option)
user_defined_patterns.push(value) user_defined_patterns.push(value)
elsif option.match(/format/) elsif /format/.match?(option)
parsed_format = Tmux.instance.parse_format(value) parsed_format = Tmux.instance.parse_format(value)
Fingers.config.send("#{option}=".to_sym, parsed_format) Fingers.config.send("#{option}=".to_sym, parsed_format)
@ -68,21 +68,20 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
end end
Fingers.config.patterns = clean_up_patterns([ Fingers.config.patterns = clean_up_patterns([
*enabled_default_patterns, *enabled_default_patterns,
*user_defined_patterns *user_defined_patterns
]) ])
Fingers.config.alphabet = ALPHABET_MAP[Fingers.config.keyboard_layout.to_sym].split('') Fingers.config.alphabet = ALPHABET_MAP[Fingers.config.keyboard_layout.to_sym].split("")
fingers_file_require_path = File.expand_path(FINGERS_FILE_PATH, __dir__) fingers_file_require_path = File.expand_path(FINGERS_FILE_PATH, __dir__)
Fingers.logger.debug("Config: #{FINGERS_FILE_PATH}") Fingers.logger.debug("Config: #{FINGERS_FILE_PATH}")
Fingers.logger.debug("fingers_file_require_path: #{fingers_file_require_path}") Fingers.logger.debug("fingers_file_require_path: #{fingers_file_require_path}")
if File.exist?(FINGERS_FILE_PATH) if File.exist?(FINGERS_FILE_PATH)
`cp #{FINGERS_FILE_PATH} /tmp/fingersrc.rb` `cp #{FINGERS_FILE_PATH} /tmp/fingersrc.rb`
require "/tmp/fingersrc.rb" require "/tmp/fingersrc"
`rm /tmp/fingersrc.rb` `rm /tmp/fingersrc.rb`
end end
@ -94,17 +93,17 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
end end
def setup_bindings def setup_bindings
input_mode = 'fingers-mode' input_mode = "fingers-mode"
ruby_bin = "#{RbConfig.ruby} --disable-gems" ruby_bin = "#{RbConfig.ruby} --disable-gems"
`tmux bind-key #{Fingers.config.key} run-shell -b "#{ruby_bin} #{cli} start '#{input_mode}' '\#{pane_id}' self >>#{Fingers::Dirs::LOG_PATH} 2>&1"` `tmux bind-key #{Fingers.config.key} run-shell -b "#{ruby_bin} #{cli} start '#{input_mode}' '\#{pane_id}' self >>#{Fingers::Dirs::LOG_PATH} 2>&1"`
`tmux bind-key O run-shell -b "#{ruby_bin} #{cli} start '#{input_mode}' '\#{pane_id}' other >>#{Fingers::Dirs::LOG_PATH} 2>&1"` `tmux bind-key O run-shell -b "#{ruby_bin} #{cli} start '#{input_mode}' '\#{pane_id}' other >>#{Fingers::Dirs::LOG_PATH} 2>&1"`
setup_fingers_mode_bindings if input_mode == 'fingers-mode' setup_fingers_mode_bindings if input_mode == "fingers-mode"
end end
def setup_fingers_mode_bindings def setup_fingers_mode_bindings
('a'..'z').to_a.each do |char| ("a".."z").to_a.each do |char|
next if char.match(DISALLOWED_CHARS) next if char.match(DISALLOWED_CHARS)
fingers_mode_bind(char, "hint:#{char}:main") fingers_mode_bind(char, "hint:#{char}:main")
@ -113,17 +112,17 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
fingers_mode_bind("M-#{char}", "hint:#{char}:alt") fingers_mode_bind("M-#{char}", "hint:#{char}:alt")
end end
fingers_mode_bind('Space', 'fzf') fingers_mode_bind("Space", "fzf")
fingers_mode_bind('C-c', 'exit') fingers_mode_bind("C-c", "exit")
fingers_mode_bind('q', 'exit') fingers_mode_bind("q", "exit")
fingers_mode_bind('Escape', 'exit') fingers_mode_bind("Escape", "exit")
fingers_mode_bind('?', 'toggle-help') fingers_mode_bind("?", "toggle-help")
fingers_mode_bind('Enter', 'noop') fingers_mode_bind("Enter", "noop")
fingers_mode_bind('Tab', 'toggle_multi_mode') fingers_mode_bind("Tab", "toggle_multi_mode")
fingers_mode_bind('Any', 'noop') fingers_mode_bind("Any", "noop")
end end
def enabled_default_patterns def enabled_default_patterns
@ -131,7 +130,7 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
end end
def to_bool(input) def to_bool(input)
input == '1' input == "1"
end end
def shell_safe_options def shell_safe_options
@ -153,12 +152,12 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
end end
def ensure_cache_folder def ensure_cache_folder
require 'fileutils' require "fileutils"
FileUtils.mkdir_p(Fingers::Dirs::CACHE) unless File.exist?(Fingers::Dirs::CACHE) FileUtils.mkdir_p(Fingers::Dirs::CACHE) unless File.exist?(Fingers::Dirs::CACHE)
end end
def fingers_options_names def fingers_options_names
@fingers_options_names ||= `tmux show-options -g | grep ^@fingers`.split("\n").map { |line| line.split(' ')[0] } @fingers_options_names ||= `tmux show-options -g | grep ^@fingers`.split("\n").map { |line| line.split(" ")[0] }
end end
def unset_tmux_option!(option) def unset_tmux_option!(option)
@ -177,13 +176,13 @@ class Fingers::Commands::LoadConfig < Fingers::Commands::Base
return if errors.empty? return if errors.empty?
puts '[tmux-fingers] Errors found in tmux.conf:' puts "[tmux-fingers] Errors found in tmux.conf:"
errors.each { |error| puts " - #{error}" } errors.each { |error| puts " - #{error}" }
exit(1) exit(1)
end end
def option_to_method(option) def option_to_method(option)
option.gsub(/^@fingers-/, '').tr('-', '_') option.gsub(/^@fingers-/, "").tr("-", "_")
end end
def fingers_mode_bind(key, command) def fingers_mode_bind(key, command)

View File

@ -1,17 +1,17 @@
class PanePrinter class PanePrinter
def initialize(pane_tty) def initialize(pane_tty)
@pane_tty = pane_tty @pane_tty = pane_tty
@buf = '' @buf = ""
@file = File.open(@pane_tty, 'w') @file = File.open(@pane_tty, "w")
end end
def print(msg) def print(msg)
@file.print(msg) @file.print(msg)
#@buf += msg # @buf += msg
end end
def flush def flush
#@file.print(@buf) # @file.print(@buf)
end end
end end
@ -58,7 +58,7 @@ class Fingers::Commands::Start < Fingers::Commands::Base
end end
def fingers_window def fingers_window
@fingers_window ||= tmux.create_window('[fingers]', 'cat', 80, 24) @fingers_window ||= tmux.create_window("[fingers]", "cat", 80, 24)
end end
def target_pane def target_pane
@ -94,8 +94,8 @@ class Fingers::Commands::Start < Fingers::Commands::Base
@state.multi_mode = false @state.multi_mode = false
@state.show_help = false @state.show_help = false
@state.input = '' @state.input = ""
@state.modifier = '' @state.modifier = ""
@state.selected_hints = [] @state.selected_hints = []
@state.selected_matches = [] @state.selected_matches = []
@state.multi_matches = [] @state.multi_matches = []
@ -119,12 +119,12 @@ class Fingers::Commands::Start < Fingers::Commands::Base
input_socket = InputSocket.new input_socket = InputSocket.new
tmux.disable_prefix tmux.disable_prefix
tmux.set_key_table 'fingers' tmux.set_key_table "fingers"
Fingers.benchmark_stamp('ready-for-input:end') Fingers.benchmark_stamp("ready-for-input:end")
Fingers.trace_for_tests_do_not_remove_or_the_whole_fabric_of_reality_will_tear_apart_with_unforeseen_consequences('fingers-ready') Fingers.trace_for_tests_do_not_remove_or_the_whole_fabric_of_reality_will_tear_apart_with_unforeseen_consequences("fingers-ready")
return if Fingers.config.trace_perf == '1' return if Fingers.config.trace_perf == "1"
input_socket.on_input do |input| input_socket.on_input do |input|
view.process_input(input) view.process_input(input)
@ -153,11 +153,11 @@ class Fingers::Commands::Start < Fingers::Commands::Base
end end
def pane_was_zoomed? def pane_was_zoomed?
target_pane.window_zoomed_flag == '1' target_pane.window_zoomed_flag == "1"
end end
def teardown def teardown
tmux.set_key_table 'root' tmux.set_key_table "root"
tmux.swap_panes(fingers_pane_id, target_pane.pane_id) tmux.swap_panes(fingers_pane_id, target_pane.pane_id)
tmux.kill_pane(fingers_pane_id) tmux.kill_pane(fingers_pane_id)
@ -167,7 +167,7 @@ class Fingers::Commands::Start < Fingers::Commands::Base
restore_options restore_options
view.run_action if state.result view.run_action if state.result
Fingers.trace_for_tests_do_not_remove_or_the_whole_fabric_of_reality_will_tear_apart_with_unforeseen_consequences('fingers-finish') Fingers.trace_for_tests_do_not_remove_or_the_whole_fabric_of_reality_will_tear_apart_with_unforeseen_consequences("fingers-finish")
end end
def compute_target_pane def compute_target_pane

View File

@ -18,20 +18,20 @@ module Fingers
:trace_perf :trace_perf
) do ) do
def initialize( def initialize(
key = 'F', key = "F",
keyboard_layout = 'qwerty', keyboard_layout = "qwerty",
alphabet = [], alphabet = [],
patterns = [], patterns = [],
main_action = ':copy:', main_action = ":copy:",
ctrl_action = ':open:', ctrl_action = ":open:",
alt_action = '', alt_action = "",
shift_action = ':paste:', shift_action = ":paste:",
hint_position = 'left', hint_position = "left",
hint_format = Tmux.instance.parse_format('fg=yellow,bold'), hint_format = Tmux.instance.parse_format("fg=yellow,bold"),
selected_hint_format = Tmux.instance.parse_format('fg=green,bold'), selected_hint_format = Tmux.instance.parse_format("fg=green,bold"),
selected_highlight_format = Tmux.instance.parse_format('fg=green,nobold,dim'), selected_highlight_format = Tmux.instance.parse_format("fg=green,nobold,dim"),
highlight_format = Tmux.instance.parse_format('fg=yellow,nobold,dim'), highlight_format = Tmux.instance.parse_format("fg=yellow,nobold,dim"),
trace_perf = '0' trace_perf = "0"
) )
super super
end end
@ -43,7 +43,7 @@ module Fingers
def self.config def self.config
$config ||= Fingers.load_from_cache $config ||= Fingers.load_from_cache
rescue StandardError rescue
$config ||= ConfigStruct.new $config ||= ConfigStruct.new
end end
@ -52,15 +52,13 @@ module Fingers
end end
def self.save_config def self.save_config
File.open(CONFIG_PATH, 'w') do |f| File.write(CONFIG_PATH, Marshal.dump(Fingers.config))
f.write(Marshal.dump(Fingers.config))
end
end end
def self.load_from_cache def self.load_from_cache
Fingers.benchmark_stamp('load-config-from-cache:start') Fingers.benchmark_stamp("load-config-from-cache:start")
result = Marshal.load(File.open(CONFIG_PATH)) result = Marshal.load(File.open(CONFIG_PATH))
Fingers.benchmark_stamp('load-config-from-cache:end') Fingers.benchmark_stamp("load-config-from-cache:end")
result result
end end

View File

@ -1,11 +1,11 @@
module Fingers::Dirs module Fingers::Dirs
tmux_pid = (ENV['TMUX'] || ',0000').split(',')[1] tmux_pid = (ENV["TMUX"] || ",0000").split(",")[1]
FINGERS_REPO_ROOT = Pathname.new(__dir__).parent.parent FINGERS_REPO_ROOT = Pathname.new(__dir__).parent.parent
root = Pathname.new(Dir.tmpdir) / 'tmux-fingers' root = Pathname.new(Dir.tmpdir) / "tmux-fingers"
LOG_PATH = FINGERS_REPO_ROOT / 'fingers.log' LOG_PATH = FINGERS_REPO_ROOT / "fingers.log"
CACHE = root / "tmux-#{tmux_pid}" CACHE = root / "tmux-#{tmux_pid}"
CONFIG_PATH = CACHE / 'fingers.config' CONFIG_PATH = CACHE / "fingers.config"
SOCKET_PATH = CACHE / 'fingers.sock' SOCKET_PATH = CACHE / "fingers.sock"
end end

View File

@ -3,9 +3,8 @@ class ::Fingers::Hinter
input:, input:,
width:, width:,
state:, state:,
patterns: Fingers.config.patterns, output:, patterns: Fingers.config.patterns,
alphabet: Fingers.config.alphabet, alphabet: Fingers.config.alphabet,
output:,
huffman: Huffman.new, huffman: Huffman.new,
formatter: ::Fingers::MatchFormatter.new formatter: ::Fingers::MatchFormatter.new
) )
@ -22,7 +21,7 @@ class ::Fingers::Hinter
def run def run
lines[0..-2].each { |line| process_line(line, "\n") } lines[0..-2].each { |line| process_line(line, "\n") }
process_line(lines[-1], '') process_line(lines[-1], "")
STDOUT.flush STDOUT.flush
output.flush output.flush
@ -41,16 +40,16 @@ class ::Fingers::Hinter
private private
attr_reader :hints, attr_reader :hints,
:hints_by_text, :hints_by_text,
:input, :input,
:lookup_table, :lookup_table,
:width, :width,
:state, :state,
:formatter, :formatter,
:huffman, :huffman,
:output, :output,
:patterns, :patterns,
:alphabet :alphabet
def build_lookup_table! def build_lookup_table!
@lookup_table = hints_by_text.invert @lookup_table = hints_by_text.invert
@ -62,7 +61,7 @@ class ::Fingers::Hinter
end end
def pattern def pattern
@pattern ||= Regexp.compile("(#{patterns.join('|')})") @pattern ||= Regexp.compile("(#{patterns.join("|")})")
end end
def hints def hints
@ -74,9 +73,9 @@ class ::Fingers::Hinter
def replace(match) def replace(match)
text = match[0] text = match[0]
captured_text = match && match.named_captures['capture'] || text captured_text = match && match.named_captures["capture"] || text
if match.named_captures['capture'] if match.named_captures["capture"]
match_start, match_end = match.offset(0) match_start, match_end = match.offset(0)
capture_start, capture_end = match.offset(:capture) capture_start, capture_end = match.offset(:capture)
@ -85,7 +84,6 @@ class ::Fingers::Hinter
capture_offset = nil capture_offset = nil
end end
if hints_by_text.has_key?(captured_text) if hints_by_text.has_key?(captured_text)
hint = hints_by_text[captured_text] hint = hints_by_text[captured_text]
else else
@ -103,7 +101,7 @@ class ::Fingers::Hinter
end end
def lines def lines
@lines ||= input.force_encoding('UTF-8').split("\n") @lines ||= input.force_encoding("UTF-8").split("\n")
end end
def n_matches def n_matches
@ -111,7 +109,7 @@ class ::Fingers::Hinter
match_set = ::Set.new match_set = ::Set.new
Fingers.benchmark_stamp('counting-matches:start') Fingers.benchmark_stamp("counting-matches:start")
lines.each do |line| lines.each do |line|
line.scan(pattern) do |match| line.scan(pattern) do |match|
@ -119,7 +117,7 @@ class ::Fingers::Hinter
end end
end end
Fingers.benchmark_stamp('counting-matches:end') Fingers.benchmark_stamp("counting-matches:end")
@n_matches = match_set.length @n_matches = match_set.length

View File

@ -10,7 +10,7 @@ class InputSocket
socket = server.accept socket = server.accept
message = socket.readline message = socket.readline
next if message == 'ping' next if message == "ping"
yield message yield message
end end
@ -23,7 +23,7 @@ class InputSocket
end end
def wait_for_input def wait_for_input
send_message 'ping' send_message "ping"
rescue Errno::ENOENT rescue Errno::ENOENT
retry retry
end end

View File

@ -1,4 +1,4 @@
require 'logger' require "logger"
module Fingers module Fingers
def self.logger def self.logger
@ -7,7 +7,7 @@ module Fingers
@logger = Logger.new( @logger = Logger.new(
Fingers::Dirs::LOG_PATH Fingers::Dirs::LOG_PATH
) )
@logger.level = Logger.const_get(ENV.fetch('FINGERS_LOG_LEVEL', 'INFO')) @logger.level = Logger.const_get(ENV.fetch("FINGERS_LOG_LEVEL", "INFO"))
@logger @logger
end end

View File

@ -17,8 +17,8 @@ class ::Fingers::MatchFormatter
def format(hint:, highlight:, selected:, offset: nil) def format(hint:, highlight:, selected:, offset: nil)
before_offset(offset, highlight) + before_offset(offset, highlight) +
format_offset(selected, hint, within_offset(offset, highlight)) + format_offset(selected, hint, within_offset(offset, highlight)) +
after_offset(offset, highlight) after_offset(offset, highlight)
end end
private private
@ -57,7 +57,7 @@ class ::Fingers::MatchFormatter
end end
def chop_highlight(hint, highlight) def chop_highlight(hint, highlight)
if hint_position == 'right' if hint_position == "right"
highlight[0..-(hint.length + 1)] || "" highlight[0..-(hint.length + 1)] || ""
else else
highlight[hint.length..-1] || "" highlight[hint.length..-1] || ""

View File

@ -1,3 +1,3 @@
module Fingers module Fingers
VERSION = '2.0.0'.freeze VERSION = "2.0.0".freeze
end end

View File

@ -9,7 +9,7 @@ class Fingers::View
end end
def process_input(input) def process_input(input)
command, *args = input.gsub(/-/, '_').split(':') command, *args = input.tr("-", "_").split(":")
send("#{command}_message".to_sym, *args) send("#{command}_message".to_sym, *args)
end end
@ -42,10 +42,11 @@ class Fingers::View
def toggle_help_message def toggle_help_message
output.print CLEAR_ESCAPE_SEQUENCE output.print CLEAR_ESCAPE_SEQUENCE
output.print 'Help message' output.print "Help message"
end end
def noop_message; end def noop_message
end
def toggle_multi_mode_message def toggle_multi_mode_message
prev_state = state.multi_mode prev_state = state.multi_mode
@ -53,7 +54,7 @@ class Fingers::View
current_state = state.multi_mode current_state = state.multi_mode
if prev_state == true && current_state == false if prev_state == true && current_state == false
state.result = state.multi_matches.join(' ') state.result = state.multi_matches.join(" ")
request_exit! request_exit!
end end
end end
@ -73,7 +74,7 @@ class Fingers::View
end end
def fzf_message def fzf_message
file = File.open('/tmp/fingers_fzf', 'w') file = File.open("/tmp/fingers_fzf", "w")
hinter.matches.each do |match| hinter.matches.each do |match|
file.puts match file.puts match
end end
@ -86,7 +87,7 @@ class Fingers::View
if state.multi_mode if state.multi_mode
state.multi_matches << match state.multi_matches << match
state.selected_hints << state.input state.selected_hints << state.input
state.input = '' state.input = ""
render render
else else
state.result = match state.result = match

View File

@ -111,6 +111,6 @@ class Huffman
end end
def translate_path(path) def translate_path(path)
path.map { |i| alphabet[i] }.join('') path.map { |i| alphabet[i] }.join("")
end end
end end

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
# rubocop:disable Metrics/ClassLength
class Tmux class Tmux
include Singleton include Singleton
@ -58,34 +57,34 @@ class Tmux
def new_session(name, cmd, width, height) def new_session(name, cmd, width, height)
flags = [] flags = []
flags.push('-f', config_file) if config_file flags.push("-f", config_file) if config_file
`env -u TMUX #{tmux} #{flags.join(' ')} new-session -d -s #{name} -x #{width} -y #{height} '#{cmd}'` `env -u TMUX #{tmux} #{flags.join(" ")} new-session -d -s #{name} -x #{width} -y #{height} '#{cmd}'`
end end
def start_server def start_server
flags = [] flags = []
flags.push('-f', config_file) if config_file flags.push("-f", config_file) if config_file
`#{tmux} #{flags.join(' ')} start-server &` `#{tmux} #{flags.join(" ")} start-server &`
end end
def pane_by_id(id) def pane_by_id(id)
panes.find { |pane| pane['pane_id'] == id } panes.find { |pane| pane["pane_id"] == id }
end end
def window_by_id(id) def window_by_id(id)
windows.find { |window| window['window_id'] == id } windows.find { |window| window["window_id"] == id }
end end
def panes_by_window_id(window_id) def panes_by_window_id(window_id)
panes.select { |pane| pane['window_id'] == window_id } panes.select { |pane| pane["window_id"] == window_id }
end end
def pane_exec(pane_id, cmd) def pane_exec(pane_id, cmd)
send_keys(pane_id, " #{cmd}") send_keys(pane_id, " #{cmd}")
send_keys(pane_id, 'Enter') send_keys(pane_id, "Enter")
end end
def send_keys(pane_id, keys) def send_keys(pane_id, keys)
@ -95,7 +94,7 @@ class Tmux
def capture_pane(pane_id) def capture_pane(pane_id)
pane = pane_by_id(pane_id) pane = pane_by_id(pane_id)
if pane.pane_in_mode == '1' if pane.pane_in_mode == "1"
start_line = -pane.scroll_position.to_i start_line = -pane.scroll_position.to_i
end_line = pane.pane_height.to_i - pane.scroll_position.to_i - 1 end_line = pane.pane_height.to_i - pane.scroll_position.to_i - 1
@ -117,7 +116,7 @@ class Tmux
def swap_panes(src_id, dst_id) def swap_panes(src_id, dst_id)
# TODO: -Z not supported on all tmux versions # TODO: -Z not supported on all tmux versions
system(tmux, 'swap-pane', '-d', '-s', src_id, '-t', dst_id) system(tmux, "swap-pane", "-d", "-s", src_id, "-t", dst_id)
end end
def kill_pane(id) def kill_pane(id)
@ -130,12 +129,12 @@ class Tmux
# TODO: this command is version dependant D: # TODO: this command is version dependant D:
def resize_window(window_id, width, height) def resize_window(window_id, width, height)
system(tmux, 'resize-window', '-t', window_id, '-x', width.to_s, '-y', height.to_s) system(tmux, "resize-window", "-t", window_id, "-x", width.to_s, "-y", height.to_s)
end end
# TODO: this command is version dependant D: # TODO: this command is version dependant D:
def resize_pane(pane_id, width, height) def resize_pane(pane_id, width, height)
system(tmux, 'resize-pane', '-t', pane_id, '-x', width.to_s, '-y', height.to_s) system(tmux, "resize-pane", "-t", pane_id, "-x", width.to_s, "-y", height.to_s)
end end
def last_pane_id def last_pane_id
@ -143,21 +142,21 @@ class Tmux
end end
def set_window_option(name, value) def set_window_option(name, value)
system(tmux, 'set-window-option', name, value) system(tmux, "set-window-option", name, value)
end end
def set_key_table(table) def set_key_table(table)
system(tmux, 'set-window-option', 'key-table', table) system(tmux, "set-window-option", "key-table", table)
system(tmux, 'switch-client', '-T', table) system(tmux, "switch-client", "-T", table)
end end
def disable_prefix def disable_prefix
set_global_option('prefix', 'None') set_global_option("prefix", "None")
set_global_option('prefix2', 'None') set_global_option("prefix2", "None")
end end
def set_global_option(name, value) def set_global_option(name, value)
system(tmux, 'set-option', '-g', name, value) system(tmux, "set-option", "-g", name, value)
end end
def get_global_option(name) def get_global_option(name)
@ -167,15 +166,15 @@ class Tmux
def set_buffer(value) def set_buffer(value)
return unless value return unless value
system(tmux, 'set-buffer', value) system(tmux, "set-buffer", value)
end end
def select_pane(id) def select_pane(id)
system(tmux, 'select-pane', '-t', id) system(tmux, "select-pane", "-t", id)
end end
def zoom_pane(id) def zoom_pane(id)
system(tmux, 'resize-pane', '-Z', '-t', id) system(tmux, "resize-pane", "-Z", "-t", id)
end end
def parse_format(format) def parse_format(format)
@ -191,29 +190,29 @@ class Tmux
def tmux def tmux
flags = [] flags = []
flags.push('-L', socket_flag_value) if socket_flag_value flags.push("-L", socket_flag_value) if socket_flag_value
return "tmux #{flags.join(' ')}" unless flags.empty? return "tmux #{flags.join(" ")}" unless flags.empty?
'tmux' "tmux"
end end
def build_tmux_output_format(fields) def build_tmux_output_format(fields)
fields.map { |field| format("\#{%<field>s}", field: field) }.join(';') fields.map { |field| format("\#{%<field>s}", field: field) }.join(";")
end end
def parse_tmux_formatted_output(output) def parse_tmux_formatted_output(output)
output.split("\n").map do |line| output.split("\n").map do |line|
fields = line.split(';') fields = line.split(";")
yield fields yield fields
end end
end end
def socket_flag_value def socket_flag_value
return ENV['FINGERS_TMUX_SOCKET'] if ENV['FINGERS_TMUX_SOCKET'] return ENV["FINGERS_TMUX_SOCKET"] if ENV["FINGERS_TMUX_SOCKET"]
socket socket
end end
end end
#Tmux = TmuxControl # Tmux = TmuxControl
# rubocop:enable Metrics/ClassLength # rubocop:enable Metrics/ClassLength

View File

@ -1,5 +1,5 @@
class TmuxFormatPrinter class TmuxFormatPrinter
FORMAT_SEPARATOR = /[ ,]+/.freeze FORMAT_SEPARATOR = /[ ,]+/
COLOR_MAP = { COLOR_MAP = {
black: 0, black: 0,
@ -13,17 +13,17 @@ class TmuxFormatPrinter
}.freeze }.freeze
LAYER_MAP = { LAYER_MAP = {
bg: 'setab', bg: "setab",
fg: 'setaf' fg: "setaf"
}.freeze }.freeze
STYLE_MAP = { STYLE_MAP = {
bright: 'bold', bright: "bold",
bold: 'bold', bold: "bold",
dim: 'dim', dim: "dim",
underscore: 'smul', underscore: "smul",
reverse: 'rev', reverse: "rev",
italics: 'sitm' italics: "sitm"
}.freeze }.freeze
class ShellExec class ShellExec
@ -39,7 +39,7 @@ class TmuxFormatPrinter
def print(input, reset_styles_after: false) def print(input, reset_styles_after: false)
@applied_styles = {} @applied_styles = {}
output = '' output = ""
input.split(FORMAT_SEPARATOR).each do |format| input.split(FORMAT_SEPARATOR).each do |format|
output += parse_format(format) output += parse_format(format)
@ -51,7 +51,7 @@ class TmuxFormatPrinter
end end
def parse_format(format) def parse_format(format)
if format.match(/^(bg|fg)=/) if /^(bg|fg)=/.match?(format)
parse_color(format) parse_color(format)
else else
parse_style(format) parse_style(format)
@ -65,7 +65,7 @@ class TmuxFormatPrinter
color = match[:color].to_sym color = match[:color].to_sym
color_code = match[:color_code] color_code = match[:color_code]
if match[:color] == 'default' if match[:color] == "default"
@applied_styles.delete(layer) @applied_styles.delete(layer)
return reset_to_applied_styles! return reset_to_applied_styles!
end end
@ -81,7 +81,7 @@ class TmuxFormatPrinter
def parse_style(format) def parse_style(format)
match = format.match(/(?<remove>no)?(?<style>.*)/) match = format.match(/(?<remove>no)?(?<style>.*)/)
should_remove_style = match[:remove] == 'no' should_remove_style = match[:remove] == "no"
style = match[:style].to_sym style = match[:style].to_sym
result = shell.exec("tput #{STYLE_MAP[style]}") result = shell.exec("tput #{STYLE_MAP[style]}")
@ -101,7 +101,7 @@ class TmuxFormatPrinter
end end
def reset_sequence def reset_sequence
@reset_sequence ||= shell.exec('tput sgr0').chomp.freeze @reset_sequence ||= shell.exec("tput sgr0").chomp.freeze
end end
private private

View File

@ -1,141 +1,141 @@
require 'spec_helper' require "spec_helper"
require_relative '../tmuxomatic_setup.rb' require_relative "../tmuxomatic_setup"
describe 'acceptance', :retry => 3 do describe "acceptance", retry: 3 do
include_context 'tmuxomatic setup' include_context "tmuxomatic setup"
let(:config_name) { 'basic' } let(:config_name) { "basic" }
context 'basic yank' do context "basic yank" do
before do before do
exec('cat spec/fixtures/grep-output') exec("cat spec/fixtures/grep-output")
invoke_fingers invoke_fingers
send_keys('b') send_keys("b")
echo_yanked echo_yanked
end end
it { should contain_content('yanked text is scripts/debug.sh') } it { should contain_content("yanked text is scripts/debug.sh") }
end end
context 'custom patterns' do context "custom patterns" do
let(:config_name) { 'custom-patterns' } let(:config_name) { "custom-patterns" }
before do before do
exec('cat spec/fixtures/custom-patterns') exec("cat spec/fixtures/custom-patterns")
send_keys('echo yanked text is ') send_keys("echo yanked text is ")
invoke_fingers invoke_fingers
send_keys('y') send_keys("y")
wait_for_fingers_teardown wait_for_fingers_teardown
paste paste
invoke_fingers invoke_fingers
send_keys('b') send_keys("b")
wait_for_fingers_teardown wait_for_fingers_teardown
paste paste
send_keys('Enter') send_keys("Enter")
end end
it { should contain_content('yanked text is W00TW00TW00TYOLOYOLOYOLO') } it { should contain_content("yanked text is W00TW00TW00TYOLOYOLOYOLO") }
end end
context 'more than one match per line' do context "more than one match per line" do
before do before do
exec('cat spec/fixtures/ip-output') exec("cat spec/fixtures/ip-output")
invoke_fingers invoke_fingers
send_keys('i') send_keys("i")
echo_yanked echo_yanked
end end
it { should contain_content('yanked text is 10.0.3.255') } it { should contain_content("yanked text is 10.0.3.255") }
end end
context 'preserve zoom state' do context "preserve zoom state" do
let(:config_name) { 'basic' } let(:config_name) { "basic" }
before do before do
send_prefix_and('%') send_prefix_and("%")
# TODO: moving back to pane with PS1="# ". If you have emojis in PS1 it # TODO: moving back to pane with PS1="# ". If you have emojis in PS1 it
# will break with this exception when splitting lines in hinter # will break with this exception when splitting lines in hinter
# #
# invalid byte sequence in US-ASCII (ArgumentError) # invalid byte sequence in US-ASCII (ArgumentError)
# #
send_prefix_and('Left') send_prefix_and("Left")
send_prefix_and('z') send_prefix_and("z")
exec('echo 123456') exec("echo 123456")
invoke_fingers invoke_fingers
send_keys('C-c') send_keys("C-c")
wait_for_fingers_teardown wait_for_fingers_teardown
exec('echo current pane is $(tmux list-panes -F "#{?window_zoomed_flag,zoomed,not_zoomed}" | head -1)') exec('echo current pane is $(tmux list-panes -F "#{?window_zoomed_flag,zoomed,not_zoomed}" | head -1)')
end end
it { should contain_content('current pane is zoomed') } it { should contain_content("current pane is zoomed") }
end end
context 'alt action' do context "alt action" do
let(:config_name) { 'alt-action' } let(:config_name) { "alt-action" }
before do before do
`rm -rf /tmp/fingers-stub-output` `rm -rf /tmp/fingers-stub-output`
exec('cat spec/fixtures/grep-output') exec("cat spec/fixtures/grep-output")
invoke_fingers invoke_fingers
send_keys('M-y') send_keys("M-y")
wait_for_fingers_teardown wait_for_fingers_teardown
exec('cat /tmp/fingers-stub-output') exec("cat /tmp/fingers-stub-output")
zzz 10 zzz 10
end end
it { should contain_content('action-stub => scripts/hints.sh') } it { should contain_content("action-stub => scripts/hints.sh") }
after do after do
`rm -rf /tmp/fingers-stub-output` `rm -rf /tmp/fingers-stub-output`
end end
end end
context 'shift action' do context "shift action" do
before do before do
exec('cat spec/fixtures/grep-output') exec("cat spec/fixtures/grep-output")
send_keys('yanked text is ') send_keys("yanked text is ")
invoke_fingers invoke_fingers
send_keys('Y') send_keys("Y")
wait_for_fingers_teardown wait_for_fingers_teardown
end end
it { should contain_content('yanked text is scripts/hints.sh') } it { should contain_content("yanked text is scripts/hints.sh") }
end end
context 'ctrl action' do context "ctrl action" do
let(:config_name) { 'ctrl-action' } let(:config_name) { "ctrl-action" }
let(:prefix) { 'C-b' } let(:prefix) { "C-b" }
let(:hint_to_press) { 'C-y' } let(:hint_to_press) { "C-y" }
before do before do
`rm -rf /tmp/fingers-stub-output` `rm -rf /tmp/fingers-stub-output`
exec('cat spec/fixtures/grep-output') exec("cat spec/fixtures/grep-output")
invoke_fingers invoke_fingers
send_keys(hint_to_press) send_keys(hint_to_press)
wait_for_fingers_teardown wait_for_fingers_teardown
exec('cat /tmp/fingers-stub-output') exec("cat /tmp/fingers-stub-output")
end end
it { should contain_content('action-stub => scripts/hints.sh') } it { should contain_content("action-stub => scripts/hints.sh") }
context 'and is sending prefix' do context "and is sending prefix" do
let(:hint_to_press) { prefix } let(:hint_to_press) { prefix }
it { should contain_content('action-stub => scripts/debug.sh') } it { should contain_content("action-stub => scripts/debug.sh") }
end end
after do after do
@ -143,20 +143,20 @@ describe 'acceptance', :retry => 3 do
end end
end end
context 'copy stuff with quotes' do context "copy stuff with quotes" do
let(:config_name) { 'quotes' } let(:config_name) { "quotes" }
before do before do
# zleep 3 # zleep 3
exec('cat spec/fixtures/quotes') exec("cat spec/fixtures/quotes")
send_keys('echo yanked text is ') send_keys("echo yanked text is ")
invoke_fingers invoke_fingers
send_keys('b') send_keys("b")
wait_for_fingers_teardown wait_for_fingers_teardown
paste paste
send_keys(' ') send_keys(" ")
invoke_fingers invoke_fingers
send_keys('y') send_keys("y")
wait_for_fingers_teardown wait_for_fingers_teardown
paste paste
end end
@ -164,15 +164,15 @@ describe 'acceptance', :retry => 3 do
it { should contain_content(%(yanked text is "laser" 'laser')) } it { should contain_content(%(yanked text is "laser" 'laser')) }
end end
context 'config options validation' do context "config options validation" do
let(:config_name) { 'invalid' } let(:config_name) { "invalid" }
let(:wait_for_initial_clear) { false } let(:wait_for_initial_clear) { false }
before do before do
zzz 5 zzz 5
end end
it { should contain_content('@fingers-lol is not a valid option') } it { should contain_content("@fingers-lol is not a valid option") }
end end
# TODO: multi match spec # TODO: multi match spec

View File

@ -1,16 +1,16 @@
require 'spec_helper' require "spec_helper"
require_relative '../tmuxomatic_setup.rb' require_relative "../tmuxomatic_setup"
require 'benchmark' require "benchmark"
describe 'performance', performance: true do describe "performance", performance: true do
include_context 'tmuxomatic setup' include_context "tmuxomatic setup"
let(:config_name) { 'benchmark' } let(:config_name) { "benchmark" }
let(:tmuxomatic_window_width) { 100 } let(:tmuxomatic_window_width) { 100 }
let(:tmuxomatic_window_height) { 100 } let(:tmuxomatic_window_height) { 100 }
it 'runs smooooooth' do it "runs smooooooth" do
ruby = RbConfig.ruby ruby = RbConfig.ruby
exec('COLUMNS=$COLUMNS LINES=$LINES ruby spec/fill_screen.rb') exec("COLUMNS=$COLUMNS LINES=$LINES ruby spec/fill_screen.rb")
exec(%(hyperfine --export-json /tmp/perf.json "#{ruby} --disable-gems bin/fingers start fingers-mode $TMUX_PANE self")) exec(%(hyperfine --export-json /tmp/perf.json "#{ruby} --disable-gems bin/fingers start fingers-mode $TMUX_PANE self"))
end end
end end

View File

@ -1,10 +1,10 @@
require 'securerandom' require "securerandom"
ENV['LINES'].to_i.times do ENV["LINES"].to_i.times do
codes = [] codes = []
(ENV['COLUMNS'].to_i / 16 - 1).times do (ENV["COLUMNS"].to_i / 16 - 1).times do
codes << SecureRandom.hex(8).to_s.tr('abcdef', '123456') codes << SecureRandom.hex(8).to_s.tr("abcdef", "123456")
end end
puts codes.join(' ') puts codes.join(" ")
end end

View File

@ -1,6 +1,6 @@
describe Fingers::Hinter do describe Fingers::Hinter do
let(:input) do let(:input) do
' '
ola ke ase ola ke ase
ke ase ola ke ase ola
ke olaola ke ke olaola ke
@ -23,7 +23,7 @@ beep beep
let(:output) do let(:output) do
class TextOutput class TextOutput
def initialize def initialize
@contents = '' @contents = ""
end end
def print(msg) def print(msg)
@ -42,17 +42,17 @@ beep beep
let(:formatter) do let(:formatter) do
::Fingers::MatchFormatter.new( ::Fingers::MatchFormatter.new(
hint_format: '%s', hint_format: "%s",
highlight_format: '%s', highlight_format: "%s",
selected_hint_format: '%s', selected_hint_format: "%s",
selected_highlight_format: '%s', selected_highlight_format: "%s",
hint_position: 'left' hint_position: "left"
) )
end end
let(:patterns) { ['ola'] } let(:patterns) { ["ola"] }
let(:alphabet) { 'asdf'.split('') } let(:alphabet) { "asdf".split("") }
let(:hinter) do let(:hinter) do
::Fingers::Hinter.new( ::Fingers::Hinter.new(
@ -62,11 +62,11 @@ beep beep
patterns: patterns, patterns: patterns,
alphabet: alphabet, alphabet: alphabet,
output: output, output: output,
formatter: formatter, formatter: formatter
) )
end end
it 'works' do it "works" do
hinter.run hinter.run
puts output.contents puts output.contents

View File

@ -1,16 +1,16 @@
require 'spec_helper' require "spec_helper"
describe Fingers::MatchFormatter do describe Fingers::MatchFormatter do
let(:hint_format) { '#[fg=yellow,bold]' } let(:hint_format) { "#[fg=yellow,bold]" }
let(:highlight_format) { '#[fg=yellow]' } let(:highlight_format) { "#[fg=yellow]" }
let(:hint_position) { 'left' } let(:hint_position) { "left" }
let(:selected_hint_format) { '#[fg=green,bold]' } let(:selected_hint_format) { "#[fg=green,bold]" }
let(:selected_highlight_format) { '#[fg=green]' } let(:selected_highlight_format) { "#[fg=green]" }
let(:selected) { false } let(:selected) { false }
let(:offset) { nil } let(:offset) { nil }
let(:hint) { 'a' } let(:hint) { "a" }
let(:highlight) { 'yolo' } let(:highlight) { "yolo" }
let(:formatter) do let(:formatter) do
described_class.new( described_class.new(
@ -19,7 +19,7 @@ describe Fingers::MatchFormatter do
selected_highlight_format: selected_highlight_format, selected_highlight_format: selected_highlight_format,
selected_hint_format: selected_hint_format, selected_hint_format: selected_hint_format,
hint_position: hint_position, hint_position: hint_position,
reset_sequence: '#[reset]' reset_sequence: "#[reset]"
) )
end end
@ -27,39 +27,39 @@ describe Fingers::MatchFormatter do
formatter.format(hint: hint, highlight: highlight, selected: selected, offset: offset) formatter.format(hint: hint, highlight: highlight, selected: selected, offset: offset)
end end
context 'when hint position' do context "when hint position" do
context 'is set to left' do context "is set to left" do
let(:hint_position) { 'left' } let(:hint_position) { "left" }
it 'places the hint on the left side' do it "places the hint on the left side" do
expect(result).to eq('#[fg=yellow,bold]a#[fg=yellow]olo#[reset]') expect(result).to eq("#[fg=yellow,bold]a#[fg=yellow]olo#[reset]")
end end
end end
context 'is set to right' do context "is set to right" do
let(:hint_position) { 'right' } let(:hint_position) { "right" }
it 'places the hint on the right side' do it "places the hint on the right side" do
expect(result).to eq('#[fg=yellow]yol#[fg=yellow,bold]a#[reset]') expect(result).to eq("#[fg=yellow]yol#[fg=yellow,bold]a#[reset]")
end end
end end
end end
context 'when a hint is selected' do context "when a hint is selected" do
let(:selected) { true } let(:selected) { true }
it 'selects the correct format' do it "selects the correct format" do
expect(result).to eq('#[fg=green,bold]a#[fg=green]olo#[reset]') expect(result).to eq("#[fg=green,bold]a#[fg=green]olo#[reset]")
end end
end end
context 'when offset is provided' do context "when offset is provided" do
let(:offset) { [1, 5] } let(:offset) { [1, 5] }
let(:highlight) { 'yoloyoloyolo' } let(:highlight) { "yoloyoloyolo" }
let(:hint) { 'a' } let(:hint) { "a" }
it 'only highlights at specified offset' do it "only highlights at specified offset" do
expect(result).to eq('y#[fg=yellow,bold]a#[fg=yellow]loyo#[reset]loyolo') expect(result).to eq("y#[fg=yellow,bold]a#[fg=yellow]loyo#[reset]loyolo")
end end
end end
end end

View File

@ -1,4 +1,4 @@
require 'spec_helper' require "spec_helper"
describe TmuxFormatPrinter do describe TmuxFormatPrinter do
let(:printer) do let(:printer) do
@ -11,21 +11,21 @@ describe TmuxFormatPrinter do
TmuxFormatPrinter.new(shell: FakeShell.new) TmuxFormatPrinter.new(shell: FakeShell.new)
end end
it 'transforms tmux status line format into escape sequences' do it "transforms tmux status line format into escape sequences" do
result = printer.print('bg=red,fg=yellow,bold', reset_styles_after: true) result = printer.print("bg=red,fg=yellow,bold", reset_styles_after: true)
expected = '$(tput setab 1)$(tput setaf 3)$(tput bold)$(tput sgr0)' expected = "$(tput setab 1)$(tput setaf 3)$(tput bold)$(tput sgr0)"
expect(result).to eq(expected) expect(result).to eq(expected)
end end
it 'transforms tmux status line format into escape sequences' do it "transforms tmux status line format into escape sequences" do
result = printer.print('bg=red,fg=yellow,bold', reset_styles_after: true) result = printer.print("bg=red,fg=yellow,bold", reset_styles_after: true)
expected = '$(tput setab 1)$(tput setaf 3)$(tput bold)$(tput sgr0)' expected = "$(tput setab 1)$(tput setaf 3)$(tput bold)$(tput sgr0)"
expect(result).to eq(expected) expect(result).to eq(expected)
end end
xit 'raises on unknown formats' do xit "raises on unknown formats" do
# TODO # TODO
end end
end end

View File

@ -1,8 +1,8 @@
$LOAD_PATH.unshift File.expand_path('lib', __dir__) $LOAD_PATH.unshift File.expand_path("lib", __dir__)
require 'byebug' require "byebug"
require 'fingers' require "fingers"
require 'rspec/retry' require "rspec/retry"
# This file was generated by the `rspec --init` command. Conventionally, all # This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
@ -57,7 +57,7 @@ RSpec.configure do |config|
# # is tagged with `:focus`, all examples get run. RSpec also provides # # is tagged with `:focus`, all examples get run. RSpec also provides
# # aliases for `it`, `describe`, and `context` that include `:focus` # # aliases for `it`, `describe`, and `context` that include `:focus`
# # metadata: `fit`, `fdescribe` and `fcontext`, respectively. # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
#config.filter_run_excluding :performance # config.filter_run_excluding :performance
# #
# # Allows RSpec to persist some state between runs in order to support # # Allows RSpec to persist some state between runs in order to support
# # the `--only-failures` and `--next-failure` CLI options. We recommend # # the `--only-failures` and `--next-failure` CLI options. We recommend

View File

@ -1,30 +1,30 @@
require 'rspec/expectations' require "rspec/expectations"
require 'byebug' require "byebug"
require 'timeout' require "timeout"
shared_context 'tmuxomatic setup', a: :b do shared_context "tmuxomatic setup", a: :b do
let(:tmuxomatic) do let(:tmuxomatic) do
Tmux.instance.socket = 'tmuxomatic' Tmux.instance.socket = "tmuxomatic"
Tmux.instance.config_file = '/dev/null' Tmux.instance.config_file = "/dev/null"
# TODO: resize window to 80x24? # TODO: resize window to 80x24?
Tmux.instance Tmux.instance
end end
let(:config_name) { 'basic' } let(:config_name) { "basic" }
let(:prefix) { 'C-a' } let(:prefix) { "C-a" }
let(:fingers_key) { 'F' } let(:fingers_key) { "F" }
let(:tmuxomatic_window_width) { 80 } let(:tmuxomatic_window_width) { 80 }
let(:tmuxomatic_window_height) { 24 } let(:tmuxomatic_window_height) { 24 }
let(:tmuxomatic_pane_id) { tmuxomatic.panes.first['pane_id'] } let(:tmuxomatic_pane_id) { tmuxomatic.panes.first["pane_id"] }
let(:tmuxomatic_window_id) { tmuxomatic.panes.first['window_id'] } let(:tmuxomatic_window_id) { tmuxomatic.panes.first["window_id"] }
let(:wait_for_initial_clear) { true } let(:wait_for_initial_clear) { true }
# Like sleep, but slower on CI lol # Like sleep, but slower on CI lol
def zzz(amount) def zzz(amount)
sleep ENV['CI'] ? amount * 2 : amount sleep ENV["CI"] ? amount * 2 : amount
end end
def send_keys(keys, trace_benchmark: false) def send_keys(keys, trace_benchmark: false)
@ -36,7 +36,7 @@ shared_context 'tmuxomatic setup', a: :b do
end end
def exec(cmd, wait: true) def exec(cmd, wait: true)
wait_for_trace(trace: 'command-completed', wait: wait) do wait_for_trace(trace: "command-completed", wait: wait) do
tmuxomatic.pane_exec(tmuxomatic_pane_id, cmd) tmuxomatic.pane_exec(tmuxomatic_pane_id, cmd)
end end
end end
@ -58,7 +58,7 @@ shared_context 'tmuxomatic setup', a: :b do
def wait_for_fingers_teardown def wait_for_fingers_teardown
Timeout.timeout(10) do Timeout.timeout(10) do
sleep 0.2 while tmuxomatic.capture_pane(tmuxomatic_pane_id).include?('[fingers]') sleep 0.2 while tmuxomatic.capture_pane(tmuxomatic_pane_id).include?("[fingers]")
end end
end end
@ -67,11 +67,11 @@ shared_context 'tmuxomatic setup', a: :b do
end end
def count_in_log_file(str) def count_in_log_file(str)
File.open(Fingers::Dirs::LOG_PATH).read.scan(str).length File.read(Fingers::Dirs::LOG_PATH).scan(str).length
end end
def invoke_fingers(trace_benchmark: false) def invoke_fingers(trace_benchmark: false)
wait_for_trace(trace: 'fingers-ready', wait: true) do wait_for_trace(trace: "fingers-ready", wait: true) do
send_keys(prefix) send_keys(prefix)
send_keys(fingers_key, trace_benchmark: trace_benchmark) send_keys(fingers_key, trace_benchmark: trace_benchmark)
end end
@ -80,14 +80,14 @@ shared_context 'tmuxomatic setup', a: :b do
def echo_yanked def echo_yanked
wait_for_fingers_teardown wait_for_fingers_teardown
exec('clear') exec("clear")
send_keys('echo yanked text is ') send_keys("echo yanked text is ")
paste paste
end end
def paste def paste
send_keys(prefix) send_keys(prefix)
send_keys(']') send_keys("]")
zzz 0.5 zzz 0.5
end end
@ -97,33 +97,33 @@ shared_context 'tmuxomatic setup', a: :b do
end end
def tmuxomatic_unlock_path def tmuxomatic_unlock_path
File.expand_path(File.join(File.dirname(__FILE__), '.tmuxomatic_unlock_command_prompt')) File.expand_path(File.join(File.dirname(__FILE__), ".tmuxomatic_unlock_command_prompt"))
end end
def fingers_root def fingers_root
File.expand_path(File.join(File.dirname(__FILE__), '../')) File.expand_path(File.join(File.dirname(__FILE__), "../"))
end end
def fingers_stubs_path def fingers_stubs_path
File.expand_path(File.join( File.expand_path(File.join(
fingers_root, fingers_root,
'./spec/stubs' "./spec/stubs"
)) ))
end end
before do before do
conf_path = File.expand_path( conf_path = File.expand_path(
File.join( File.join(
File.dirname(__FILE__), File.dirname(__FILE__),
'../spec/conf/', "../spec/conf/",
"#{config_name}.conf" "#{config_name}.conf"
) )
) )
tmuxomatic tmuxomatic
tmuxomatic.new_session('tmuxomatic', "PATH=\"#{fingers_root}:#{fingers_stubs_path}:$PATH\" TMUX='' tmux -L tmuxomatic_inner -f #{conf_path}", tmuxomatic_window_width, tmuxomatic_window_height) tmuxomatic.new_session("tmuxomatic", "PATH=\"#{fingers_root}:#{fingers_stubs_path}:$PATH\" TMUX='' tmux -L tmuxomatic_inner -f #{conf_path}", tmuxomatic_window_width, tmuxomatic_window_height)
tmuxomatic.set_global_option('prefix', 'None') tmuxomatic.set_global_option("prefix", "None")
tmuxomatic.set_global_option('status', 'off') tmuxomatic.set_global_option("status", "off")
tmuxomatic.resize_window(tmuxomatic_window_id, tmuxomatic_window_width, tmuxomatic_window_height) tmuxomatic.resize_window(tmuxomatic_window_id, tmuxomatic_window_width, tmuxomatic_window_height)
`touch #{Fingers::Dirs::LOG_PATH}` `touch #{Fingers::Dirs::LOG_PATH}`
@ -136,7 +136,7 @@ shared_context 'tmuxomatic setup', a: :b do
exec("export PROMPT_COMMAND='#{tmuxomatic_unlock_path}'", wait: false) exec("export PROMPT_COMMAND='#{tmuxomatic_unlock_path}'", wait: false)
zzz 1.0 zzz 1.0
exec('clear', wait: wait_for_initial_clear) exec("clear", wait: wait_for_initial_clear)
end end
after do after do
@ -149,7 +149,7 @@ def wrap_in_box(output, width)
output.split("\n").map do |line| output.split("\n").map do |line|
"" + line.ljust(width, " ") + "" "" + line.ljust(width, " ") + ""
end.join("\n") + "\n" + end.join("\n") + "\n" +
"" + "" * width + "" "" + "" * width + ""
end end
RSpec::Matchers.define :contain_content do |expected| RSpec::Matchers.define :contain_content do |expected|
@ -164,6 +164,6 @@ RSpec::Matchers.define :contain_content do |expected|
failure_message do |_actual| failure_message do |_actual|
"Could not find '#{expected}' in:\n" + "Could not find '#{expected}' in:\n" +
wrap_in_box(pane_output, pane.pane_width.to_i) wrap_in_box(pane_output, pane.pane_width.to_i)
end end
end end

1
vendor/tmux-printer vendored

@ -1 +0,0 @@
Subproject commit e727260def12b0df311e71b73f94e85ab0b00e31