Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update REPLy version #15328

Merged
merged 1 commit into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading