-
Notifications
You must be signed in to change notification settings - Fork 87
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e76b082
commit 14eeda9
Showing
3 changed files
with
138 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
class Reline::KeyStroke | ||
using Module.new { | ||
refine Array do | ||
def start_with?(other) | ||
other.size <= size && other == self.take(other.size) | ||
end | ||
end | ||
} | ||
|
||
def initialize(config) | ||
@config = config | ||
@buffer = [] | ||
end | ||
|
||
def input_to(bytes) | ||
case match_status(bytes) | ||
when :matching | ||
nil | ||
when :matched | ||
expand(bytes) | ||
when :unmatched | ||
bytes | ||
end | ||
end | ||
|
||
def input_to!(bytes) | ||
@buffer.concat Array(bytes) | ||
input_to(@buffer)&.tap { clear } | ||
end | ||
|
||
private | ||
|
||
def match_status(input) | ||
key_mapping.keys.select { |lhs| | ||
lhs.start_with? input | ||
}.tap { |it| | ||
return :matched if it.size == 1 && (it.max_by(&:size)&.size&.== input.size) | ||
return :matching if it.size == 1 && (it.max_by(&:size)&.size&.!= input.size) | ||
return :matched if it.max_by(&:size)&.size&.< input.size | ||
return :matching if it.size > 1 | ||
} | ||
key_mapping.keys.select { |lhs| | ||
input.start_with? lhs | ||
}.tap { |it| | ||
return it.size > 0 ? :matched : :unmatched | ||
} | ||
end | ||
|
||
def expand(input) | ||
lhs = key_mapping.keys.select { |lhs| input.start_with? lhs }.sort_by(&:size).reverse.first | ||
return input unless lhs | ||
rhs = key_mapping[lhs] | ||
|
||
case rhs | ||
when String | ||
rhs_bytes = rhs.bytes | ||
expand(expand(rhs_bytes) + expand(input.drop(lhs.size))) | ||
when Symbol | ||
[rhs] + expand(input.drop(lhs.size)) | ||
end | ||
end | ||
|
||
def key_mapping | ||
@config[:key_mapping].transform_keys(&:bytes) | ||
end | ||
|
||
def clear | ||
@buffer = [] | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
require 'helper' | ||
|
||
class Reline::KeyStroke::Test < Reline::TestCase | ||
using Module.new { | ||
refine Array do | ||
def as_s | ||
map(&:chr).join | ||
end | ||
end | ||
} | ||
|
||
def test_input_to! | ||
config = { | ||
key_mapping: { | ||
"a" => "xx", | ||
"ab" => "y", | ||
"abc" => "z", | ||
"x" => "rr" | ||
} | ||
} | ||
stroke = Reline::KeyStroke.new(config) | ||
result = ("abzwabk".bytes).map { |char| | ||
stroke.input_to!(char)&.then { |result| | ||
"#{result.as_s}" | ||
} | ||
} | ||
assert_equal(result, [nil, nil, "yz", "w", nil, nil, "yk"]) | ||
end | ||
|
||
def test_input_to | ||
config = { | ||
key_mapping: { | ||
"a" => "xx", | ||
"ab" => "y", | ||
"abc" => "z", | ||
"x" => "rr" | ||
} | ||
} | ||
stroke = Reline::KeyStroke.new(config) | ||
assert_equal(stroke.input_to("a".bytes)&.as_s, nil) | ||
assert_equal(stroke.input_to("ab".bytes)&.as_s, nil) | ||
assert_equal(stroke.input_to("abc".bytes)&.as_s, "z") | ||
assert_equal(stroke.input_to("abz".bytes)&.as_s, "yz") | ||
assert_equal(stroke.input_to("abx".bytes)&.as_s, "yrr") | ||
assert_equal(stroke.input_to("ac".bytes)&.as_s, "rrrrc") | ||
assert_equal(stroke.input_to("aa".bytes)&.as_s, "rrrrrrrr") | ||
assert_equal(stroke.input_to("x".bytes)&.as_s, "rr") | ||
assert_equal(stroke.input_to("m".bytes)&.as_s, "m") | ||
assert_equal(stroke.input_to("abzwabk".bytes)&.as_s, "yzwabk") | ||
end | ||
end |