Skip to content
This repository was archived by the owner on Mar 12, 2023. It is now read-only.

Commit bb1a389

Browse files
authored
Merge pull request #79 from nguyenquangminh0711/refactor/improve-key-bindings
Key bindings customization
2 parents 59da2e6 + 5dd7be2 commit bb1a389

35 files changed

+911
-114
lines changed

.github/workflows/rspec.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ jobs:
3838
strategy:
3939
fail-fast: false
4040
matrix:
41-
ruby: [2.5, 2.6, 2.7.1, head]
41+
ruby: [2.5, 2.6, 2.7.2, head]
4242
runs-on: ubuntu-latest
4343
steps:
4444
- uses: actions/checkout@v2
@@ -73,7 +73,7 @@ jobs:
7373
strategy:
7474
fail-fast: false
7575
matrix:
76-
ruby: [2.5, 2.6, 2.7.1, head]
76+
ruby: [2.5, 2.6, 2.7.2, head]
7777
env:
7878
CI_PLATFORM: "macos"
7979
runs-on: macos-latest

.rubocop.yml

+2
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ Style/NilComparison:
8383
Enabled: false
8484
Style/NonNilCheck:
8585
Enabled: false
86+
Style/WordArray:
87+
Enabled: false
8688

8789
RSpec/MultipleExpectations:
8890
Enabled: false

Gemfile

-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,5 @@ group :test do
2222
gem 'parallel_tests'
2323
gem 'reline', require: false
2424
gem 'rspec-retry'
25-
gem 'simplecov', require: false
2625
gem 'sqlite3'
2726
end

lib/ruby_jard.rb

+1-11
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
require 'ruby_jard/path_classifier'
1010
require 'ruby_jard/path_filter'
1111
require 'ruby_jard/control_flow'
12-
require 'ruby_jard/config'
1312
require 'ruby_jard/keys'
13+
require 'ruby_jard/config'
1414
require 'ruby_jard/key_binding'
1515
require 'ruby_jard/key_bindings'
1616
require 'ruby_jard/repl_processor'
@@ -81,16 +81,6 @@ def self.error(exception)
8181
# Ignore
8282
end
8383

84-
def self.global_key_bindings
85-
return @global_key_bindings if defined?(@global_key_bindings)
86-
87-
@global_key_bindings = RubyJard::KeyBindings.new
88-
RubyJard::Keys::DEFAULT_KEY_BINDINGS.each do |sequence, action|
89-
@global_key_bindings.push(sequence, action)
90-
end
91-
@global_key_bindings
92-
end
93-
9484
def self.config
9585
@config ||= RubyJard::Config.smart_load
9686
end

lib/ruby_jard/config.rb

+20-2
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def load_config(config, path)
3939
end
4040

4141
attr_accessor :color_scheme, :alias_to_debugger, :layout
42-
attr_reader :enabled_screens, :filter_version, :filter, :filter_included, :filter_excluded
42+
attr_reader :enabled_screens, :filter_version, :filter, :filter_included, :filter_excluded, :key_bindings
4343

4444
CONFIG_FILE_NAME = '.jardrc'
4545
DEFAULTS = [
@@ -48,7 +48,19 @@ def load_config(config, path)
4848
DEFAULT_LAYOUT = nil, # Pick layout automatically
4949
DEFAULT_FILTER = RubyJard::PathFilter::FILTER_APPLICATION,
5050
DEFAULT_FILTER_INCLUDED = [].freeze,
51-
DEFAULT_FILTER_EXCLUDED = [].freeze
51+
DEFAULT_FILTER_EXCLUDED = [].freeze,
52+
DEFAULT_KEY_BINDINGS = {
53+
RubyJard::Keys::F2 => 'jard filter switch',
54+
RubyJard::Keys::F5 => 'list',
55+
RubyJard::Keys::F6 => 'up',
56+
RubyJard::Keys::SHIFT_F6 => 'down',
57+
RubyJard::Keys::F7 => 'step',
58+
RubyJard::Keys::SHIFT_F7 => 'step-out',
59+
RubyJard::Keys::F8 => 'next',
60+
RubyJard::Keys::F9 => 'continue',
61+
RubyJard::Keys::CTRL_D => 'continue',
62+
RubyJard::Keys::CTRL_C => 'interrupt'
63+
}.freeze
5264
].freeze
5365

5466
def initialize
@@ -62,6 +74,8 @@ def initialize
6274
@alias_to_debugger = DEFAULT_ALIAS_TO_DEBUGGER.freeze
6375
@layout = DEFAULT_LAYOUT.freeze
6476
@enabled_screens = RubyJard::Screens.names.dup.freeze
77+
78+
@key_bindings = RubyJard::KeyBindings.new(DEFAULT_KEY_BINDINGS)
6579
end
6680

6781
def config
@@ -86,5 +100,9 @@ def filter_included=(input)
86100
@filter_version += 1
87101
@filter_included = input.freeze
88102
end
103+
104+
def key_bindings=(sequences)
105+
@key_bindings = RubyJard::KeyBindings.new(sequences)
106+
end
89107
end
90108
end

lib/ruby_jard/key_bindings.rb

+19-21
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,15 @@ module RubyJard
66
# match a key binding sequence from input.
77
# As this class is performant-sensitive, a lookup tree is built
88
# and updated whenever a new key is added.
9-
# TODO: Write tests for this file
109
class KeyBindings
11-
attr_reader :indexes
10+
attr_reader :indexes, :key_bindings
1211

13-
def initialize
12+
def initialize(sequences = [])
1413
@key_bindings = []
1514
@indexes = {}
16-
end
17-
18-
def to_a
19-
@key_bindings.dup
20-
end
21-
22-
def push(sequence, action)
23-
if sequence.is_a?(Array)
24-
sequence.each { |s| push(s, action) }
25-
return
15+
sequences.each do |sequence, action|
16+
push(sequence, action)
2617
end
27-
28-
raise RubyJard::Error if sequence.to_s.empty?
29-
30-
key_binding = RubyJard::KeyBinding.new(sequence, action)
31-
reindex(key_binding)
32-
@key_bindings << key_binding
3318
end
3419

3520
def match(&read_key)
@@ -56,8 +41,8 @@ def match(&read_key)
5641
elsif node[byte].nil?
5742
# It's sure that no more bindings to match
5843
return buffer
59-
elsif buffer == node[byte].sequence
60-
# Exact match current key binding
44+
elsif buffer.start_with?(node[byte].sequence)
45+
# Match current key binding. Discard the rest
6146
return node[byte]
6247
else
6348
return buffer
@@ -68,6 +53,19 @@ def match(&read_key)
6853

6954
private
7055

56+
def push(sequence, action)
57+
if sequence.is_a?(Array)
58+
sequence.each { |s| push(s, action) }
59+
return
60+
end
61+
62+
raise RubyJard::Error if sequence.to_s.empty?
63+
64+
key_binding = RubyJard::KeyBinding.new(sequence, action)
65+
reindex(key_binding)
66+
@key_bindings << key_binding
67+
end
68+
7169
def reindex(key_binding)
7270
parent = nil
7371
node = @indexes

lib/ruby_jard/keys.rb

+168-13
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@ module RubyJard
66
class Keys
77
# X-Term: https://invisible-island.net/xterm/xterm-function-keys.html
88
END_LINE = ["\n", "\r\n", "\r"].freeze
9-
CTRL_C = "\u0003"
10-
CTRL_D = "\u0004"
9+
ESC = "\e"
1110

1211
F1 = "\eOP"
1312
F2 = "\eOQ"
@@ -34,16 +33,172 @@ class Keys
3433
SHIFT_F10 = "\e[21;2~"
3534
SHIFT_F11 = "\e[23;2~"
3635
SHIFT_F12 = "\e[24;2~"
37-
DEFAULT_KEY_BINDINGS = {
38-
F2 => (ACTION_FILTER = 'jard filter switch'),
39-
F5 => (ACTION_LIST = 'list'),
40-
F6 => (ACTION_UP = 'up'),
41-
SHIFT_F6 => (ACTION_DOWN = 'down'),
42-
F7 => (ACTION_STEP = 'step'),
43-
SHIFT_F7 => (ACTION_STEP_OUT = 'step-out'),
44-
F8 => (ACTION_NEXT = 'next'),
45-
F9 => (ACTION_CONTINUE = 'continue'),
46-
CTRL_D => ACTION_CONTINUE
47-
}.freeze
36+
37+
CTRL_A = "\C-a"
38+
CTRL_B = "\C-b"
39+
CTRL_C = "\C-c"
40+
CTRL_D = "\C-d"
41+
CTRL_E = "\C-e"
42+
CTRL_F = "\C-f"
43+
CTRL_G = "\C-g"
44+
CTRL_H = "\C-h"
45+
CTRL_I = "\C-i"
46+
CTRL_J = "\C-j"
47+
CTRL_K = "\C-k"
48+
CTRL_L = "\C-l"
49+
CTRL_M = "\C-m"
50+
CTRL_N = "\C-n"
51+
CTRL_O = "\C-o"
52+
CTRL_P = "\C-p"
53+
CTRL_Q = "\C-q"
54+
CTRL_R = "\C-r"
55+
CTRL_S = "\C-s"
56+
CTRL_T = "\C-t"
57+
CTRL_U = "\C-u"
58+
CTRL_V = "\C-v"
59+
CTRL_W = "\C-w"
60+
CTRL_X = "\C-x"
61+
CTRL_Y = "\C-y"
62+
CTRL_Z = "\C-z"
63+
64+
CTRL_F1 = "\e[1;5P"
65+
CTRL_F2 = "\e[1;5Q"
66+
CTRL_F3 = "\e[1;5R"
67+
CTRL_F4 = "\e[1;5S"
68+
CTRL_F5 = "\e[15;5~"
69+
CTRL_F6 = "\e[17;5~"
70+
CTRL_F7 = "\e[18;5~"
71+
CTRL_F8 = "\e[19;5~"
72+
CTRL_F9 = "\e[20;5~"
73+
CTRL_F10 = "\e[21;5~"
74+
CTRL_F11 = "\e[23;5~"
75+
CTRL_F12 = "\e[24;5~"
76+
77+
CTRL_SHIFT_F1 = "\e[1;6P"
78+
CTRL_SHIFT_F2 = "\e[1;6Q"
79+
CTRL_SHIFT_F3 = "\e[1;6R"
80+
CTRL_SHIFT_F4 = "\e[1;6S"
81+
CTRL_SHIFT_F5 = "\e[15;6~"
82+
CTRL_SHIFT_F6 = "\e[17;6~"
83+
CTRL_SHIFT_F7 = "\e[18;6~"
84+
CTRL_SHIFT_F8 = "\e[19;6~"
85+
CTRL_SHIFT_F9 = "\e[20;6~"
86+
CTRL_SHIFT_F10 = "\e[21;6~"
87+
CTRL_SHIFT_F11 = "\e[23;6~"
88+
CTRL_SHIFT_F12 = "\e[24;6~"
89+
90+
META_A = "\ea"
91+
META_B = "\eb"
92+
META_C = "\ec"
93+
META_D = "\ed"
94+
META_E = "\ee"
95+
META_F = "\ef"
96+
META_G = "\eg"
97+
META_H = "\eh"
98+
META_I = "\ei"
99+
META_J = "\ej"
100+
META_K = "\ek"
101+
META_L = "\el"
102+
META_M = "\em"
103+
META_N = "\en"
104+
META_O = "\eo"
105+
META_P = "\ep"
106+
META_Q = "\eq"
107+
META_R = "\er"
108+
META_S = "\es"
109+
META_T = "\et"
110+
META_U = "\eu"
111+
META_V = "\ev"
112+
META_W = "\ew"
113+
META_X = "\ex"
114+
META_Y = "\ey"
115+
META_Z = "\ez"
116+
117+
META_F1 = "\e[1;3P"
118+
META_F2 = "\e[1;3Q"
119+
META_F3 = "\e[1;3R"
120+
META_F4 = "\e[1;3S"
121+
META_F5 = "\e[15;3~"
122+
META_F6 = "\e[17;3~"
123+
META_F7 = "\e[18;3~"
124+
META_F8 = "\e[19;3~"
125+
META_F9 = "\e[20;3~"
126+
META_F10 = "\e[21;3~"
127+
META_F11 = "\e[23;3~"
128+
META_F12 = "\e[24;3~"
129+
130+
META_SHIFT_A = "\eA"
131+
META_SHIFT_B = "\eB"
132+
META_SHIFT_C = "\eC"
133+
META_SHIFT_D = "\eD"
134+
META_SHIFT_E = "\eE"
135+
META_SHIFT_F = "\eF"
136+
META_SHIFT_G = "\eG"
137+
META_SHIFT_H = "\eH"
138+
META_SHIFT_I = "\eI"
139+
META_SHIFT_J = "\eJ"
140+
META_SHIFT_K = "\eK"
141+
META_SHIFT_L = "\eL"
142+
META_SHIFT_M = "\eM"
143+
META_SHIFT_N = "\eN"
144+
META_SHIFT_O = "\eO"
145+
META_SHIFT_P = "\eP"
146+
META_SHIFT_Q = "\eQ"
147+
META_SHIFT_R = "\eR"
148+
META_SHIFT_S = "\eS"
149+
META_SHIFT_T = "\eT"
150+
META_SHIFT_U = "\eU"
151+
META_SHIFT_V = "\eV"
152+
META_SHIFT_W = "\eW"
153+
META_SHIFT_X = "\eX"
154+
META_SHIFT_Y = "\eY"
155+
META_SHIFT_Z = "\eZ"
156+
157+
META_SHIFT_F1 = "\e[1;4P"
158+
META_SHIFT_F2 = "\e[1;4Q"
159+
META_SHIFT_F3 = "\e[1;4R"
160+
META_SHIFT_F4 = "\e[1;4S"
161+
META_SHIFT_F5 = "\e[15;4~"
162+
META_SHIFT_F6 = "\e[17;4~"
163+
META_SHIFT_F7 = "\e[18;4~"
164+
META_SHIFT_F8 = "\e[19;4~"
165+
META_SHIFT_F9 = "\e[20;4~"
166+
META_SHIFT_F10 = "\e[21;4~"
167+
META_SHIFT_F11 = "\e[23;4~"
168+
META_SHIFT_F12 = "\e[24;4~"
169+
170+
CTRL_META_A = "\e\C-a"
171+
CTRL_META_B = "\e\C-b"
172+
CTRL_META_C = "\e\C-c"
173+
CTRL_META_D = "\e\C-d"
174+
CTRL_META_E = "\e\C-e"
175+
CTRL_META_F = "\e\C-f"
176+
CTRL_META_G = "\e\C-g"
177+
CTRL_META_H = "\e\C-h"
178+
CTRL_META_I = "\e\C-i"
179+
CTRL_META_J = "\e\C-j"
180+
CTRL_META_K = "\e\C-k"
181+
CTRL_META_L = "\e\C-l"
182+
CTRL_META_M = "\e\C-m"
183+
CTRL_META_N = "\e\C-n"
184+
CTRL_META_O = "\e\C-o"
185+
CTRL_META_P = "\e\C-p"
186+
CTRL_META_Q = "\e\C-q"
187+
CTRL_META_R = "\e\C-r"
188+
CTRL_META_S = "\e\C-s"
189+
CTRL_META_T = "\e\C-t"
190+
CTRL_META_U = "\e\C-u"
191+
CTRL_META_V = "\e\C-v"
192+
CTRL_META_W = "\e\C-w"
193+
CTRL_META_X = "\e\C-x"
194+
CTRL_META_Y = "\e\C-y"
195+
CTRL_META_Z = "\e\C-z"
196+
197+
REVERSED_KEYS = constants(false).map do |con|
198+
[
199+
RubyJard::Keys.const_get(con),
200+
con.to_s.split('_').map(&:capitalize).join('+')
201+
]
202+
end.to_h
48203
end
49204
end

0 commit comments

Comments
 (0)