-
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Completions for storing and navigating completion suggestions
- Loading branch information
1 parent
ccb1869
commit aa4606e
Showing
3 changed files
with
208 additions
and
0 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,107 @@ | ||
# frozen_string_literal: true | ||
|
||
require "forwardable" | ||
|
||
module TTY | ||
class Reader | ||
# Responsible for storing and navigating completion suggestions | ||
# | ||
# @api private | ||
class Completions | ||
include Enumerable | ||
extend Forwardable | ||
|
||
def_delegators :@completions, :size, :empty? | ||
|
||
# Create a Completions collection | ||
# | ||
# @api public | ||
def initialize | ||
@completions = [] | ||
@index = 0 | ||
end | ||
|
||
# Clear current completions | ||
# | ||
# @api public | ||
def clear | ||
@completions.clear | ||
@index = 0 | ||
end | ||
|
||
# Check whether the current index is at the first completion or not | ||
# | ||
# @return [Boolean] | ||
# | ||
# @api public | ||
def first? | ||
@index.zero? | ||
end | ||
|
||
# Check whether the current index is at the last completion or not | ||
# | ||
# @return [Boolean] | ||
# | ||
# @api public | ||
def last? | ||
@index == size - 1 | ||
end | ||
|
||
# Add completion suggestions | ||
# | ||
# @param [Array<String>] suggestions | ||
# the suggestions to add | ||
# | ||
# @api public | ||
def concat(suggestions) | ||
suggestions.each { |suggestion| @completions << suggestion.dup } | ||
end | ||
|
||
# Iterate over all completions | ||
# | ||
# @api public | ||
def each(&block) | ||
if block_given? | ||
@completions.each(&block) | ||
else | ||
@completions.to_enum | ||
end | ||
end | ||
|
||
# Retrieve completion at the current index | ||
# | ||
# @return [String] | ||
# | ||
# @api public | ||
def get | ||
@completions[@index] | ||
end | ||
|
||
# Move index to the next completion | ||
# | ||
# @api public | ||
def next | ||
return if size.zero? | ||
|
||
if @index == size - 1 | ||
@index = 0 | ||
else | ||
@index += 1 | ||
end | ||
end | ||
|
||
# Move index to the previous completion | ||
# | ||
# @api public | ||
def previous | ||
return if size.zero? | ||
|
||
if @index.zero? | ||
@index = size - 1 | ||
else | ||
@index -= 1 | ||
end | ||
end | ||
end # Completions | ||
end # Reader | ||
end # TTY |
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,100 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe TTY::Reader::Completions do | ||
it "has no suggestions by default" do | ||
completions = described_class.new | ||
|
||
expect(completions.empty?).to eq(true) | ||
expect(completions.size).to eq(0) | ||
end | ||
|
||
it "adds suggestions making copies of each one" do | ||
completions = described_class.new | ||
suggestions = %w[aa ab ac] | ||
|
||
completions.concat(suggestions) | ||
|
||
suggestions[0] = "ax" | ||
|
||
expect(completions.to_a).to eq(%w[aa ab ac]) | ||
expect(completions.to_a).to_not eq(suggestions) | ||
end | ||
|
||
it "clears all suggestions" do | ||
completions = described_class.new | ||
suggestions = %w[aa ab ac] | ||
|
||
completions.concat(suggestions) | ||
|
||
expect(completions.empty?).to eq(false) | ||
expect(completions.size).to eq(3) | ||
|
||
completions.clear | ||
|
||
expect(completions.empty?).to eq(true) | ||
expect(completions.size).to eq(0) | ||
end | ||
|
||
it "navigates to the next completion" do | ||
completions = described_class.new | ||
completions.concat(%w[aa ab ac]) | ||
|
||
expect(completions.get).to eq("aa") | ||
|
||
completions.next | ||
expect(completions.get).to eq("ab") | ||
end | ||
|
||
it "navigates to the previous completion" do | ||
completions = described_class.new | ||
completions.concat(%w[aa ab ac]) | ||
|
||
completions.next | ||
expect(completions.get).to eq("ab") | ||
|
||
completions.previous | ||
expect(completions.get).to eq("aa") | ||
end | ||
|
||
it "cycles through completions forward" do | ||
completions = described_class.new | ||
suggestions = %w[aa ab ac] | ||
completions.concat(suggestions) | ||
|
||
suggestions.size.times { completions.next } | ||
|
||
expect(completions.get).to eq("aa") | ||
end | ||
|
||
it "cycles through completions backward" do | ||
completions = described_class.new | ||
suggestions = %w[aa ab ac] | ||
completions.concat(suggestions) | ||
|
||
suggestions.size.times { completions.previous } | ||
|
||
expect(completions.get).to eq("aa") | ||
end | ||
|
||
it "checks whether index is at the first completion" do | ||
completions = described_class.new | ||
suggestions = %w[aa ab ac] | ||
completions.concat(suggestions) | ||
|
||
expect(completions.first?).to eq(true) | ||
|
||
completions.next | ||
expect(completions.first?).to eq(false) | ||
end | ||
|
||
it "checks whether index is at the last completion" do | ||
completions = described_class.new | ||
suggestions = %w[aa ab ac] | ||
completions.concat(suggestions) | ||
|
||
expect(completions.last?).to eq(false) | ||
|
||
2.times { completions.next } | ||
expect(completions.last?).to eq(true) | ||
end | ||
end |