Skip to content

Commit

Permalink
Update REPLy 13f7eba083f138dd063c68b859c8e315f44fb523 (#15328)
Browse files Browse the repository at this point in the history
  • Loading branch information
oprypin authored Jan 13, 2025
1 parent dbdf548 commit 410a6c8
Show file tree
Hide file tree
Showing 18 changed files with 404 additions and 37 deletions.
2 changes: 1 addition & 1 deletion lib/.shards.info
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ shards:
version: 0.5.0
reply:
git: https://github.com/i3oris/reply.git
version: 0.3.1+git.commit.db423dae3dd34c6ba5e36174653a0c109117a167
version: 0.3.1+git.commit.13f7eba083f138dd063c68b859c8e315f44fb523
4 changes: 2 additions & 2 deletions lib/reply/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ It includes the following features:
* Hook for Auto formatting
* Hook for Auto indentation
* Hook for Auto completion (Experimental)
* History Reverse i-search
* Work on Windows 10

It doesn't support yet:
* History reverse i-search
* Customizable hotkeys
* Unicode characters

Expand Down Expand Up @@ -53,7 +53,7 @@ end
require "reply"
class MyReader < Reply::Reader
def prompt(io : IO, line_number : Int32, color? : Bool) : Nil
def prompt(io : IO, line_number : Int32, color : Bool) : Nil
# Display a custom prompt
end
Expand Down
4 changes: 2 additions & 2 deletions lib/reply/examples/crystal_repl.cr
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ CONTINUE_ERROR = [
WORD_DELIMITERS = {{" \n\t+-*/,;@&%<>^\\[](){}|.~".chars}}

class CrystalReader < Reply::Reader
def prompt(io : IO, line_number : Int32, color? : Bool) : Nil
io << "crystal".colorize.blue.toggle(color?)
def prompt(io : IO, line_number : Int32, color : Bool) : Nil
io << "crystal".colorize.blue.toggle(color)
io << ':'
io << sprintf("%03d", line_number)
io << "> "
Expand Down
35 changes: 34 additions & 1 deletion lib/reply/spec/expression_editor_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ module Reply
end

it "is aligned when prompt size change" do
editor = ExpressionEditor.new do |line_number, _color?|
editor = ExpressionEditor.new do |line_number, _color|
"*" * line_number + ">" # A prompt that increase its size at each line
end
editor.output = IO::Memory.new
Expand Down Expand Up @@ -428,6 +428,39 @@ module Reply
"****>5"
end

it "Don't mess up the terminal when the prompt is empty" do
editor = ExpressionEditor.new { "" }
editor.output = IO::Memory.new
editor.color = false
editor.height = 5
editor.width = 15

editor.update { editor << "Hello,\nWorld" }
editor.verify_output "\e[1G\e[J" \
"Hello,\n" \
"World"

editor.output = IO::Memory.new
editor.update { editor << '\n' }
editor.verify_output "\e[1A\e[1G\e[J" \
"Hello,\n" \
"World\n"

editor.output = IO::Memory.new
editor.update { editor << "1+1" }
editor.verify_output "\e[2A\e[1G\e[J" \
"Hello,\n" \
"World\n" \
"1+1"

editor.output = IO::Memory.new
editor.update { editor << '\n' }
editor.verify_output "\e[2A\e[1G\e[J" \
"Hello,\n" \
"World\n" \
"1+1\n"
end

# TODO:
# header
end
Expand Down
54 changes: 54 additions & 0 deletions lib/reply/spec/reader_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,60 @@ module Reply
SpecHelper.send(pipe_in, '\0')
end

it "searches on ctrl-r" do
reader = SpecHelper.reader(type: SpecReaderWithSearch)
pipe_out, pipe_in = IO.pipe

SEARCH_ENTRIES.each { |e| reader.history << e }

spawn do
reader.read_next(from: pipe_out)
end

SpecHelper.send(pipe_in, '\u0012') # Ctrl-r (search)
reader.search.verify("", open: true, failed: true)

SpecHelper.send(pipe_in, 'p')
reader.search.verify("p", open: true, failed: false)
reader.editor.verify("pp! i")
reader.history.index.should eq 3

SpecHelper.send(pipe_in, "ut")
reader.search.verify("put", open: true, failed: false)
reader.editor.verify(<<-END)
while i < 10
puts i
i += 1
end
END
reader.history.index.should eq 2

SpecHelper.send(pipe_in, "ss")
reader.search.verify("putss", open: true, failed: true)
reader.editor.verify("")
reader.history.index.should eq 5

SpecHelper.send(pipe_in, '\u{7f}') # back
reader.search.verify("puts", open: true, failed: false)
reader.editor.verify(<<-END)
while i < 10
puts i
i += 1
end
END
reader.history.index.should eq 2

SpecHelper.send(pipe_in, '\e') # back
reader.search.verify("", open: false, failed: false)
reader.editor.verify(<<-END)
while i < 10
puts i
i += 1
end
END
reader.history.index.should eq 2
end

it "resets" do
reader = SpecHelper.reader
pipe_out, pipe_in = IO.pipe
Expand Down
84 changes: 84 additions & 0 deletions lib/reply/spec/search_spec.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
module Reply
SEARCH_ENTRIES = [
[%(puts "Hello World")],
[%(i = 0)],
[
%(while i < 10),
%( puts i),
%( i += 1),
%(end),
],
[%(pp! i)],
[%("Bye")],
]

describe Search do
it "displays footer" do
search = SpecHelper.search
search.verify_footer("search: _", height: 1)

search.query = "foo"
search.verify_footer("search: foo_", height: 1)

search.failed = true
search.verify_footer("search: #{"foo".colorize.bold.red}_", height: 1)

search.failed = false
search.query = "foobar"
search.verify_footer("search: foobar_", height: 1)

search.close
search.verify_footer("", height: 0)
end

it "opens and closes" do
search = SpecHelper.search
search.query = "foo"
search.failed = true
search.verify(query: "foo", open: true, failed: true)

search.close
search.verify(query: "", open: false, failed: false)

search.query = "bar"
search.failed = true

search.open
search.verify(query: "bar", open: true, failed: false)
end

it "searches" do
search = SpecHelper.search
history = SpecHelper.history(SEARCH_ENTRIES)

search.search(history).should be_nil
search.verify("", failed: true)
history.verify(SEARCH_ENTRIES, index: 5)

search.query = "p"
search.search(history).should eq Search::SearchResult.new(3, [%(pp! i)], x: 0, y: 0)
history.verify(SEARCH_ENTRIES, index: 3)

search.query = "put"
search.search(history).should eq Search::SearchResult.new(2, SEARCH_ENTRIES[2], x: 2, y: 1)
history.verify(SEARCH_ENTRIES, index: 2)

search.query = "i"
search.search(history).should eq Search::SearchResult.new(1, ["i = 0"], x: 0, y: 0)
history.verify(SEARCH_ENTRIES, index: 1)

search.open
search.search(history).should eq Search::SearchResult.new(3, ["pp! i"], x: 4, y: 0)
history.verify(SEARCH_ENTRIES, index: 3)

search.open
search.search(history).should eq Search::SearchResult.new(2, SEARCH_ENTRIES[2], x: 2, y: 0)
history.verify(SEARCH_ENTRIES, index: 2)

search.query = "baz"
search.search(history).should be_nil
search.verify("baz", failed: true)
history.verify(SEARCH_ENTRIES, index: 5)
end
end
end
32 changes: 30 additions & 2 deletions lib/reply/spec/spec_helper.cr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module Reply
height_got = nil

display_got = String.build do |io|
height_got = self.display_entries(io, color?: false, width: with_width, max_height: max_height, min_height: min_height)
height_got = self.display_entries(io, color: false, width: with_width, max_height: max_height, min_height: min_height)
end
display_got.should eq display
height_got.should eq height
Expand Down Expand Up @@ -54,6 +54,22 @@ module Reply
end
end

class Search
setter failed

def verify(query, open = true, failed = false)
@query.should eq query
@open.should eq open
@failed.should eq failed
end

def verify_footer(footer, height)
String.build do |io|
footer(io, true).should eq height
end.should eq footer
end
end

struct CharReader
def verify_read(to_read, expect : CharReader::Sequence)
verify_read(to_read, [expect])
Expand Down Expand Up @@ -81,6 +97,14 @@ module Reply
getter auto_completion
end

class SpecReaderWithSearch < Reader
def disable_search?
false
end

getter search
end

class SpecReaderWithEqual < Reader
def initialize
super
Expand Down Expand Up @@ -124,7 +148,7 @@ module Reply
end

def self.expression_editor
editor = ExpressionEditor.new do |line_number, _color?|
editor = ExpressionEditor.new do |line_number, _color|
# Prompt size = 5
"p:#{sprintf("%02d", line_number)}>"
end
Expand All @@ -141,6 +165,10 @@ module Reply
history
end

def self.search
Search.new.tap &.open
end

def self.char_reader(buffer_size = 64)
CharReader.new(buffer_size)
end
Expand Down
10 changes: 5 additions & 5 deletions lib/reply/src/auto_completion.cr
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module Reply
# If closed, do nothing.
#
# Returns the actual displayed height.
def display_entries(io, color? = true, width = Term::Size.width, max_height = 10, min_height = 0) : Int32 # ameba:disable Metrics/CyclomaticComplexity
def display_entries(io, color = true, width = Term::Size.width, max_height = 10, min_height = 0) : Int32 # ameba:disable Metrics/CyclomaticComplexity
if cleared?
min_height.times { io.puts }
return min_height
Expand All @@ -68,7 +68,7 @@ module Reply
height = 0

# Print title:
if color?
if color
@display_title.call(io, @title)
else
io << @title << ":"
Expand Down Expand Up @@ -116,23 +116,23 @@ module Reply

if r + c*nb_rows == @selection_pos
# Colorize selection:
if color?
if color
@display_selected_entry.call(io, entry_str)
else
io << ">" + entry_str[...-1] # if no color, remove last spaces to let place to '*'.
end
else
# Display entry_str, with @name_filter prefix in bright:
unless entry.empty?
if color?
if color
io << @display_entry.call(io, @name_filter, entry_str.lchop(@name_filter))
else
io << entry_str
end
end
end
end
io << Term::Cursor.clear_line_after if color?
io << Term::Cursor.clear_line_after if color
io.puts
end

Expand Down
7 changes: 5 additions & 2 deletions lib/reply/src/char_reader.cr
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ module Reply
CTRL_K
CTRL_N
CTRL_P
CTRL_R
CTRL_U
CTRL_X
CTRL_UP
Expand All @@ -44,8 +45,8 @@ module Reply
end

def read_char(from io : IO = STDIN)
nb_read = raw(io, &.read(@slice_buffer))
parse_escape_sequence(@slice_buffer[0...nb_read])
nb_read = raw(io, &.read(@slice_buffer))
parse_escape_sequence(@slice_buffer[0...nb_read])
end

private def parse_escape_sequence(chars : Bytes) : Char | Sequence | String?
Expand Down Expand Up @@ -141,6 +142,8 @@ module Reply
Sequence::CTRL_N
when ctrl('p')
Sequence::CTRL_P
when ctrl('r')
Sequence::CTRL_R
when ctrl('u')
Sequence::CTRL_U
when ctrl('x')
Expand Down
Loading

0 comments on commit 410a6c8

Please sign in to comment.