diff --git a/lib/.shards.info b/lib/.shards.info index b6371e9397c4..ef916ec3e753 100644 --- a/lib/.shards.info +++ b/lib/.shards.info @@ -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 diff --git a/lib/reply/README.md b/lib/reply/README.md index ae33523e4824..3874e85483fb 100644 --- a/lib/reply/README.md +++ b/lib/reply/README.md @@ -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 @@ -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 diff --git a/lib/reply/examples/crystal_repl.cr b/lib/reply/examples/crystal_repl.cr index 97cf3a1d88e7..ce469aeff07f 100644 --- a/lib/reply/examples/crystal_repl.cr +++ b/lib/reply/examples/crystal_repl.cr @@ -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 << "> " diff --git a/lib/reply/spec/expression_editor_spec.cr b/lib/reply/spec/expression_editor_spec.cr index b37354a827d0..5fd5e9b50515 100644 --- a/lib/reply/spec/expression_editor_spec.cr +++ b/lib/reply/spec/expression_editor_spec.cr @@ -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 @@ -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 diff --git a/lib/reply/spec/reader_spec.cr b/lib/reply/spec/reader_spec.cr index 4dbc53cbb51b..3a1b6d357c91 100644 --- a/lib/reply/spec/reader_spec.cr +++ b/lib/reply/spec/reader_spec.cr @@ -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 diff --git a/lib/reply/spec/search_spec.cr b/lib/reply/spec/search_spec.cr new file mode 100644 index 000000000000..fa08f44c7b79 --- /dev/null +++ b/lib/reply/spec/search_spec.cr @@ -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 diff --git a/lib/reply/spec/spec_helper.cr b/lib/reply/spec/spec_helper.cr index 7e0a93052320..aedd8cd73190 100644 --- a/lib/reply/spec/spec_helper.cr +++ b/lib/reply/spec/spec_helper.cr @@ -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 @@ -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]) @@ -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 @@ -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 @@ -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 diff --git a/lib/reply/src/auto_completion.cr b/lib/reply/src/auto_completion.cr index ee4940fac71c..8048efe0a482 100644 --- a/lib/reply/src/auto_completion.cr +++ b/lib/reply/src/auto_completion.cr @@ -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 @@ -68,7 +68,7 @@ module Reply height = 0 # Print title: - if color? + if color @display_title.call(io, @title) else io << @title << ":" @@ -116,7 +116,7 @@ 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 '*'. @@ -124,7 +124,7 @@ module Reply 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 @@ -132,7 +132,7 @@ module Reply end end end - io << Term::Cursor.clear_line_after if color? + io << Term::Cursor.clear_line_after if color io.puts end diff --git a/lib/reply/src/char_reader.cr b/lib/reply/src/char_reader.cr index c4ab01ca802e..9d547e6f4ee3 100644 --- a/lib/reply/src/char_reader.cr +++ b/lib/reply/src/char_reader.cr @@ -19,6 +19,7 @@ module Reply CTRL_K CTRL_N CTRL_P + CTRL_R CTRL_U CTRL_X CTRL_UP @@ -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? @@ -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') diff --git a/lib/reply/src/expression_editor.cr b/lib/reply/src/expression_editor.cr index 5c3d7aec24b9..00fc13ec0b4b 100644 --- a/lib/reply/src/expression_editor.cr +++ b/lib/reply/src/expression_editor.cr @@ -83,8 +83,10 @@ module Reply @scroll_offset = 0 @header_height = 0 + @footer_height = 0 @header : IO, Int32 -> Int32 = ->(io : IO, previous_height : Int32) { 0 } + @footer : IO, Int32 -> Int32 = ->(io : IO, previous_height : Int32) { 0 } @highlight = ->(code : String) { code } # The list of characters delimiting words. @@ -95,16 +97,25 @@ module Reply # Creates a new `ExpressionEditor` with the given *prompt*. def initialize(&@prompt : Int32, Bool -> String) @prompt_size = @prompt.call(0, false).size # uncolorized size + @prompt_size = 1 if @prompt_size == 0 end # Sets a `Proc` allowing to display a header above the prompt. (used by auto-completion) # # *io*: The IO in which the header should be displayed. - # *previous_hight*: Previous header height, useful to keep a header size constant. + # *previous_height*: Previous header height, useful to keep a header size constant. # Should returns the exact *height* printed in the io. def set_header(&@header : IO, Int32 -> Int32) end + # Sets a `Proc` allowing to display a footer under the prompt. (used by search) + # + # *io*: The IO in which the footer should be displayed. + # *previous_height*: Previous footer height. + # Should returns the exact *height* printed in the io. + def set_footer(&@footer : IO, Int32 -> Int32) + end + # Sets the `Proc` to highlight the expression. def set_highlight(&@highlight : String -> String) end @@ -382,7 +393,7 @@ module Reply # # The expression scrolls if it's higher than epression_max_height. private def epression_max_height - self.height - @header_height + self.height - @header_height - @footer_height end def move_cursor_left(allow_scrolling = true) @@ -723,6 +734,13 @@ module Reply end end + # Calls the footer proc and saves the *footer_height* + private def update_footer : String + String.build do |io| + @footer_height = @footer.call(io, @footer_height) + end + end + def replace(lines : Array(String)) update { @lines = lines } end @@ -753,6 +771,8 @@ module Reply private def print_prompt(io, line_index) line_prompt_size = @prompt.call(line_index, false).size # uncolorized size + line_prompt_size = 1 if line_prompt_size == 0 + @prompt_size = {line_prompt_size, @prompt_size}.max io.print @prompt.call(line_index, color?) @@ -826,9 +846,9 @@ module Reply {start, end_} end - private def print_line(io, colorized_line, line_index, line_size, prompt?, first?, is_last_part?) - if prompt? - io.puts unless first? + private def print_line(io, colorized_line, line_index, line_size, prompt, first, is_last_part) + if prompt + io.puts unless first print_prompt(io, line_index) end io.print colorized_line @@ -840,10 +860,10 @@ module Reply # prompt> bar | extra line feed, so computes based on `%` or `//` stay exact. # prompt>end | # ``` - io.puts if is_last_part? && last_part_size(line_size) == 0 + io.puts if is_last_part && last_part_size(line_size) == 0 end - private def sync_output + private def sync_output(&) if (output = @output).is_a?(IO::FileDescriptor) && output.tty? # Disallowing the synchronization reduce blinking on some terminal like vscode (#10) output.sync = false @@ -870,6 +890,7 @@ module Reply private def print_expression_and_header(height_to_clear, force_full_view = false) height_to_clear += @header_height header = update_header() + footer = update_footer() if force_full_view start, end_ = 0, Int32::MAX @@ -907,7 +928,7 @@ module Reply if start <= y && y + line_height - 1 <= end_ # The line can hold entirely between the view bounds, print it: - print_line(io, colorized_lines[line_index], line_index, line.size, prompt?: true, first?: first, is_last_part?: true) + print_line(io, colorized_lines[line_index], line_index, line.size, prompt: true, first: first, is_last_part: true) first = false cursor_move_x = line.size @@ -922,7 +943,7 @@ module Reply colorized_parts.each_with_index do |colorized_part, part_number| if start <= y <= end_ # The part holds on the view, we can print it. - print_line(io, colorized_part, line_index, line.size, prompt?: part_number == 0, first?: first, is_last_part?: part_number == line_height - 1) + print_line(io, colorized_part, line_index, line.size, prompt: part_number == 0, first: first, is_last_part: part_number == line_height - 1) first = false cursor_move_x = {line.size, (part_number + 1)*self.width - @prompt_size - 1}.min @@ -942,6 +963,17 @@ module Reply @output.print header @output.print display + if @footer_height != 0 + # Display footer, then rewind cursor at the top left of the footer + @output.puts + @output.print footer + @output.print Term::Cursor.column(1) + move_real_cursor(x: @prompt_size, y: 1 - @footer_height) + + cursor_move_y += 1 + cursor_move_x = 0 + end + # Retrieve the real cursor at its corresponding cursor position (`@x`, `@y`) x_save, y_save = @x, @y @y = cursor_move_y diff --git a/lib/reply/src/history.cr b/lib/reply/src/history.cr index 3f12f0f01f95..c0426b85eccb 100644 --- a/lib/reply/src/history.cr +++ b/lib/reply/src/history.cr @@ -2,12 +2,16 @@ module Reply class History getter history = Deque(Array(String)).new getter max_size = 10_000 - @index = 0 + getter index = 0 # Hold the history lines being edited, always contains one element more than @history # because it can also contain the current line (not yet in history) @edited_history = [nil] of Array(String)? + def size + @history.size + end + def <<(lines) lines = lines.dup # make history elements independent @@ -45,7 +49,15 @@ module Reply @edited_history[@index] = current_edited_lines @index += 1 - (@edited_history[@index]? || @history[@index]).dup + (@edited_history[@index]? || @history[@index]? || [""]).dup + end + end + + def go_to(index) + if 0 <= index < @history.size + @index = index + + @history[@index].dup end end diff --git a/lib/reply/src/reader.cr b/lib/reply/src/reader.cr index 01228cf7027a..5894f4b493fe 100644 --- a/lib/reply/src/reader.cr +++ b/lib/reply/src/reader.cr @@ -2,6 +2,7 @@ require "./history" require "./expression_editor" require "./char_reader" require "./auto_completion" +require "./search" module Reply # Reader for your REPL. @@ -10,7 +11,7 @@ module Reply # # ``` # class MyReader < Reply::Reader - # def prompt(io, line_number, color?) + # def prompt(io, line_number, color) # io << "reply> " # end # end @@ -45,21 +46,23 @@ module Reply # ^ ^ # | | # History AutoCompletion + # +Search # ``` getter history = History.new getter editor : ExpressionEditor @auto_completion : AutoCompletion @char_reader = CharReader.new + @search = Search.new getter line_number = 1 delegate :color?, :color=, :lines, :output, :output=, to: @editor delegate :word_delimiters, :word_delimiters=, to: @editor def initialize - @editor = ExpressionEditor.new do |expr_line_number, color?| + @editor = ExpressionEditor.new do |expr_line_number, color| String.build do |io| - prompt(io, @line_number + expr_line_number, color?) + prompt(io, @line_number + expr_line_number, color) end end @@ -72,6 +75,10 @@ module Reply @auto_completion.display_entries(io, color?, max_height: {10, Term::Size.height - 1}.min, min_height: previous_height) end + @editor.set_footer do |io, _previous_height| + @search.footer(io, color?) + end + @editor.set_highlight(&->highlight(String)) if file = self.history_file @@ -81,10 +88,10 @@ module Reply # Override to customize the prompt. # - # Toggle the colorization following *color?*. + # Toggle the colorization following *color*. # # default: `$:001> ` - def prompt(io : IO, line_number : Int32, color? : Bool) + def prompt(io : IO, line_number : Int32, color : Bool) io << "$:" io << sprintf("%03d", line_number) io << "> " @@ -118,7 +125,7 @@ module Reply 0 end - # Override to select with expression is saved in history. + # Override to select which expression is saved in history. # # default: `!expression.blank?` def save_in_history?(expression : String) @@ -132,6 +139,13 @@ module Reply nil end + # Override with `true` to disable the reverse i-search (ctrl-r). + # + # default: `true` (disabled) if `history_file` not set. + def disable_search? + history_file.nil? + end + # Override to integrate auto-completion. # # *current_word* is picked following `word_delimiters`. @@ -232,6 +246,7 @@ module Reply in .ctrl_delete? then @editor.update { delete_word } in .alt_d? then @editor.update { delete_word } in .ctrl_c? then on_ctrl_c + in .ctrl_r? then on_ctrl_r in .ctrl_d? if @editor.empty? output.puts @@ -244,6 +259,12 @@ module Reply return nil end + if (read.is_a?(CharReader::Sequence) && (read.ctrl_r? || read.backspace?)) || read.is_a?(Char) || read.is_a?(String) + else + @search.close + @editor.update + end + if read.is_a?(CharReader::Sequence) && (read.tab? || read.enter? || read.alt_enter? || read.shift_tab? || read.escape? || read.backspace? || read.ctrl_c?) else if @auto_completion.open? @@ -278,6 +299,8 @@ module Reply end private def on_char(char) + return search_and_replace(@search.query + char) if @search.open? + @editor.update do @editor << char line = @editor.current_line.rstrip(' ') @@ -294,6 +317,8 @@ module Reply end private def on_string(string) + return search_and_replace(@search.query + string) if @search.open? + @editor.update do @editor << string end @@ -301,6 +326,12 @@ module Reply private def on_enter(alt_enter = false, ctrl_enter = false, &) @auto_completion.close + if @search.open? + @search.close + @editor.update + return + end + if alt_enter || ctrl_enter || (@editor.cursor_on_last_line? && continue?(@editor.expression)) @editor.update do insert_new_line(indent: self.indentation_level(@editor.expression_before_cursor)) @@ -338,6 +369,8 @@ module Reply end private def on_back + return search_and_replace(@search.query.rchop) if @search.open? + auto_complete_remove_char if @auto_completion.open? @editor.update { back } end @@ -365,12 +398,21 @@ module Reply private def on_ctrl_c @auto_completion.close + @search.close @editor.end_editing output.puts "^C" @history.set_to_last @editor.prompt_next end + private def on_ctrl_r + return if disable_search? + + @auto_completion.close + @search.open + search_and_replace(reuse_index: true) + end + private def on_tab(shift_tab = false) if @auto_completion.open? if shift_tab @@ -390,6 +432,7 @@ module Reply private def on_escape @auto_completion.close + @search.close @editor.update end @@ -446,6 +489,21 @@ module Reply end end + private def search_and_replace(query = nil, reuse_index = false) + @search.query = query if query + + from_index = reuse_index ? @history.index - 1 : @history.size - 1 + + result = @search.search(@history, from_index) + if result + @editor.replace(result.result) + + @editor.move_cursor_to(result.x + @search.query.size, result.y) + else + @editor.replace([""]) + end + end + private def submit_expr(*, history = true) formated = format(@editor.expression).try &.split('\n') @editor.end_editing(replacement: formated) diff --git a/lib/reply/src/search.cr b/lib/reply/src/search.cr new file mode 100644 index 000000000000..f1011aaffb0a --- /dev/null +++ b/lib/reply/src/search.cr @@ -0,0 +1,63 @@ +module Reply + class Search + getter? open = false + property query = "" + getter? failed = false + + record SearchResult, + index : Int32, + result : Array(String), + x : Int32, + y : Int32 + + def footer(io : IO, color : Bool) + if open? + io << "search: #{@query.colorize.toggle(failed? && color).bold.red}_" + 1 + else + 0 + end + end + + def open + @open = true + @failed = false + end + + def close + @open = false + @query = "" + @failed = false + end + + def search(history, from_index = history.index - 1) + if search_result = search_up(history, @query, from_index: from_index) + @failed = false + history.go_to search_result.index + return search_result + end + + @failed = true + history.set_to_last + nil + end + + private def search_up(history, query, from_index) + return if query.empty? + return unless 0 <= from_index < history.size + + # Search the history starting by `from_index` until first entry, + # then cycle the search by searching from last entry to `from_index` + from_index.downto(0).chain( + (history.size - 1).downto(from_index + 1) + ).each do |i| + history.history[i].each_with_index do |line, y| + x = line.index query + return SearchResult.new(i, history.history[i], x, y) if x + end + end + + nil + end + end +end diff --git a/lib/reply/src/term_cursor.cr b/lib/reply/src/term_cursor.cr index 64eaf87db5cd..06a43722e3b5 100644 --- a/lib/reply/src/term_cursor.cr +++ b/lib/reply/src/term_cursor.cr @@ -20,7 +20,7 @@ module Reply::Term end # Switch off cursor for the block - def invisible(stream = STDOUT, &block) + def invisible(stream = STDOUT, &) stream.print(hide) yield ensure diff --git a/shard.lock b/shard.lock index 697bfe23b3c3..cebaa45723d4 100644 --- a/shard.lock +++ b/shard.lock @@ -6,5 +6,5 @@ shards: reply: git: https://github.com/i3oris/reply.git - version: 0.3.1+git.commit.db423dae3dd34c6ba5e36174653a0c109117a167 + version: 0.3.1+git.commit.13f7eba083f138dd063c68b859c8e315f44fb523 diff --git a/shard.yml b/shard.yml index f3e66fea65cc..e979cf04bbec 100644 --- a/shard.yml +++ b/shard.yml @@ -14,7 +14,7 @@ dependencies: github: icyleaf/markd reply: github: I3oris/reply - commit: db423dae3dd34c6ba5e36174653a0c109117a167 + commit: 13f7eba083f138dd063c68b859c8e315f44fb523 license: Apache-2.0 diff --git a/src/compiler/crystal/interpreter/pry_reader.cr b/src/compiler/crystal/interpreter/pry_reader.cr index 4e0a9f64d33b..353caa31f915 100644 --- a/src/compiler/crystal/interpreter/pry_reader.cr +++ b/src/compiler/crystal/interpreter/pry_reader.cr @@ -3,7 +3,7 @@ require "./repl_reader" class Crystal::PryReader < Crystal::ReplReader property prompt_info = "" - def prompt(io, line_number, color?) + def prompt(io, line_number, color) io << "pry(" io << @prompt_info io << ')' diff --git a/src/compiler/crystal/interpreter/repl_reader.cr b/src/compiler/crystal/interpreter/repl_reader.cr index 535ec53e64a9..6ca3b5615097 100644 --- a/src/compiler/crystal/interpreter/repl_reader.cr +++ b/src/compiler/crystal/interpreter/repl_reader.cr @@ -50,7 +50,7 @@ class Crystal::ReplReader < Reply::Reader self.word_delimiters = {{" \n\t+-*/,;@&%<>^\\[](){}|.~".chars}} end - def prompt(io : IO, line_number : Int32, color? : Bool) : Nil + def prompt(io : IO, line_number : Int32, color : Bool) : Nil io << "icr:" io << line_number