diff --git a/features/run_control/key.feature b/features/run_control/key.feature new file mode 100644 index 0000000..842f1c8 --- /dev/null +++ b/features/run_control/key.feature @@ -0,0 +1,10 @@ +Feature: `key' run control keyword + + Scenario: defines code to run when given key is pressed + Given a run control file with: + """ + key(:f) { puts 'trigger f key code' } + """ + And uhwm is running + When I press the alt+f keys + Then the output must contain "trigger f key code" diff --git a/lib/uh/wm.rb b/lib/uh/wm.rb index 7e2b4a0..fcf448c 100644 --- a/lib/uh/wm.rb +++ b/lib/uh/wm.rb @@ -7,6 +7,7 @@ require 'uh/wm/cli' require 'uh/wm/dispatcher' require 'uh/wm/env' require 'uh/wm/manager' +require 'uh/wm/run_control' require 'uh/wm/runner' module Uh diff --git a/lib/uh/wm/env.rb b/lib/uh/wm/env.rb index 3c14d9b..5cf8318 100644 --- a/lib/uh/wm/env.rb +++ b/lib/uh/wm/env.rb @@ -13,12 +13,13 @@ module Uh def_delegator :logger, :debug, :log_debug def_delegator :@output, :print - attr_reader :output + attr_reader :output, :keybinds attr_accessor :verbose, :debug, :rc_path, :layout_class def initialize output @output = output @rc_path = RC_PATH + @keybinds = {} end def verbose? diff --git a/lib/uh/wm/run_control.rb b/lib/uh/wm/run_control.rb new file mode 100644 index 0000000..fc66ceb --- /dev/null +++ b/lib/uh/wm/run_control.rb @@ -0,0 +1,25 @@ +module Uh + module WM + class RunControl + class << self + def evaluate env + rc_path = File.expand_path(env.rc_path) + rc = new env + rc.evaluate File.read(rc_path) if File.exist?(rc_path) + end + end + + def initialize env + @env = env + end + + def evaluate code + instance_eval code + end + + def key keysym, &block + @env.keybinds[keysym] = block + end + end + end +end diff --git a/lib/uh/wm/runner.rb b/lib/uh/wm/runner.rb index e972cbe..18a3262 100644 --- a/lib/uh/wm/runner.rb +++ b/lib/uh/wm/runner.rb @@ -32,8 +32,7 @@ module Uh end def evaluate_run_control - rc_path = File.expand_path(@env.rc_path) - eval File.read(rc_path) if File.exist?(rc_path) + RunControl.evaluate(env) end def register_event_hooks @@ -45,6 +44,9 @@ module Uh def connect_manager @manager.connect @manager.grab_key :q + @env.keybinds.each do |keysym, _| + @manager.grab_key *keysym + end end def run_until &block @@ -71,6 +73,9 @@ module Uh def register_key_bindings_hooks @events.on(:key, :q) { stop! } + @env.keybinds.each do |keysym, code| + @events.on :key, keysym, &code + end end end end diff --git a/spec/uh/wm/run_control_spec.rb b/spec/uh/wm/run_control_spec.rb new file mode 100644 index 0000000..3ac1f39 --- /dev/null +++ b/spec/uh/wm/run_control_spec.rb @@ -0,0 +1,67 @@ +require 'support/filesystem_helpers' + +module Uh + module WM + RSpec.describe RunControl do + include FileSystemHelpers + + let(:code) { :run_control_code } + let(:env) { Env.new(StringIO.new) } + subject(:rc) { described_class.new env } + + describe '.evaluate' do + around do |example| + with_file ':run_control_code' do |f| + env.rc_path = f.path + example.run + end + end + + it 'builds a new instance with given env' do + expect(described_class).to receive(:new).with(env).and_call_original + described_class.evaluate env + end + + it 'tells the new instance to evaluate run control file content' do + expect(rc).to receive(:evaluate).with ':run_control_code' + allow(described_class).to receive(:new) { rc } + described_class.evaluate env + end + + context 'when run control file is not present' do + before { env.rc_path = 'non_existent_rc_file.rb' } + + it 'does not raise any error' do + expect { described_class.evaluate env }.not_to raise_error + end + end + end + + describe '#evaluate' do + it 'evaluates given code' do + expect { rc.evaluate 'throw :run_control_code' } + .to throw_symbol :run_control_code + end + + it 'provides access to assigned env' do + expect { rc.evaluate 'fail @env.object_id.to_s' } + .to raise_error env.object_id.to_s + end + end + + describe '#key' do + let(:code) { -> { :keybind_code } } + + before { rc.key :f, &code } + + it 'registers a key binding in the env' do + expect(env.keybinds.keys).to include :f + end + + it 'registers given block with the key binding' do + expect(env.keybinds[:f].call).to eq :keybind_code + end + end + end + end +end diff --git a/spec/uh/wm/runner_spec.rb b/spec/uh/wm/runner_spec.rb index b04f493..3dd8630 100644 --- a/spec/uh/wm/runner_spec.rb +++ b/spec/uh/wm/runner_spec.rb @@ -1,5 +1,3 @@ -require 'support/filesystem_helpers' - SomeLayout = Class.new do define_method(:register) { |*args| } end @@ -7,8 +5,6 @@ end module Uh module WM RSpec.describe Runner do - include FileSystemHelpers - let(:env) { Env.new(StringIO.new) } subject(:runner) { described_class.new env } @@ -60,19 +56,9 @@ module Uh end describe '#evaluate_run_control' do - context 'when run control file is present' do - it 'evaluates the run control file' do - with_file 'throw :run_control' do |f| - env.rc_path = f.path - expect { runner.evaluate_run_control }.to throw_symbol :run_control - end - end - end - - context 'when run control file is not present' do - it 'does not raise any error' do - expect { runner.evaluate_run_control }.not_to raise_error - end + it 'evaluates the run control file with RunControl and current env' do + expect(RunControl).to receive(:evaluate).with env + runner.evaluate_run_control end end @@ -90,8 +76,9 @@ module Uh end it 'registers key bindings event hooks' do + env.keybinds[:f] = -> { } runner.register_event_hooks - expect(runner.events[:key, :q]).not_to be_empty + expect(runner.events[:key, :f]).not_to be_empty end end @@ -104,8 +91,9 @@ module Uh runner.connect_manager end - it 'tells the manager to grab keys' do - expect(runner.manager).to receive(:grab_key).with :q + it 'tells the manager to grab keys for env key bindings' do + env.keybinds[:f] = -> { } + expect(runner.manager).to receive(:grab_key).with :f runner.connect_manager end end