require "./spec_helper" module Reply describe ExpressionEditor do it "computes expression_height" do editor = SpecHelper.expression_editor editor.current_line = ":Hi" editor.expression_height.should eq 1 editor.current_line = "print :Hel" \ "lo" editor.expression_height.should eq 2 editor.current_line = ":at_edge__" editor.expression_height.should eq 2 editor << "#{""}puts :this" \ "symbol_is_a_too" \ "_mutch_long_sym" \ "bol" editor.insert_new_line(indent: 0) editor << ":with_a_ne" \ "line" editor.expression_height.should eq 4 + 2 end it "gives previous, current, and next line" do editor = SpecHelper.expression_editor editor << "aaa" editor.previous_line?.should be_nil editor.current_line.should eq "aaa" editor.next_line?.should be_nil editor.insert_new_line(indent: 0) editor << "bbb" editor.insert_new_line(indent: 0) editor << "ccc" editor.move_cursor_up editor.previous_line?.should eq "aaa" editor.current_line.should eq "bbb" editor.next_line?.should eq "ccc" end it "tells if cursor is on last line" do editor = SpecHelper.expression_editor editor.cursor_on_last_line?.should be_true editor << "aaa" editor.insert_new_line(indent: 0) editor.cursor_on_last_line?.should be_true editor << "bbb" 2.times { editor.move_cursor_left } editor.cursor_on_last_line?.should be_true editor.move_cursor_up editor.cursor_on_last_line?.should be_false end it "gets expression_before_cursor" do editor = SpecHelper.expression_editor editor << "print :Hel" \ "lo" editor.insert_new_line(indent: 0) editor << "puts :Bye" editor.expression_before_cursor.should eq "print :Hello\nputs :Bye" editor.expression_before_cursor(x: 0, y: 0).should eq "" editor.expression_before_cursor(x: 9, y: 0).should eq "print :He" end it "modify previous, current, and next line" do editor = SpecHelper.expression_editor editor << "aaa" editor.current_line = "AAA" editor.verify("AAA", x: 3, y: 0) editor.insert_new_line(indent: 0) editor << "bbb" editor.insert_new_line(indent: 0) editor << "ccc" editor.move_cursor_up editor.previous_line = "AAA" editor.current_line = "BBB" editor.next_line = "CCC" editor.verify("AAA\nBBB\nCCC", x: 3, y: 1) end it "deletes line" do editor = SpecHelper.expression_editor editor << "aaa\nbbb\nccc\n" editor.delete_line(1) editor.verify("aaa\nccc\n") editor.delete_line(0) editor.verify("ccc\n") editor.delete_line(1) editor.verify("ccc") editor.delete_line(0) editor.verify("") end it "clears expression" do editor = SpecHelper.expression_editor editor << "aaa\nbbb\nccc\n" editor.clear_expression editor.expression.should be_empty end it "insert chars" do editor = SpecHelper.expression_editor editor << 'a' editor.verify("a", x: 1, y: 0) editor.move_cursor_left editor << 'b' editor.verify("ba", x: 1, y: 0) editor << '\n' editor.verify("b\na", x: 0, y: 1) end it "ignores control characters" do editor = SpecHelper.expression_editor editor << "abc" editor << '\b' editor.verify("abc", x: 3, y: 0) editor << '\u007F' << '\u0002' editor.verify("abc", x: 3, y: 0) editor << "def\u007F\b\eghi\u0007" editor.verify("abcdefghi", x: 9, y: 0) end it "inserts new line" do editor = SpecHelper.expression_editor editor << "aaa" editor.insert_new_line(indent: 1) editor.verify("aaa\n ", x: 2, y: 1) editor << "bbb" editor.move_cursor_up editor.insert_new_line(indent: 5) editor.insert_new_line(indent: 0) editor.verify("aaa\n \n\n bbb", x: 0, y: 2) end it "does delete & back" do editor = SpecHelper.expression_editor editor << "abc\n\ndef\nghi" editor.move_cursor_up 2.times { editor.move_cursor_left } editor.delete editor.verify("abc\n\ndf\nghi", x: 1, y: 2) editor.back editor.verify("abc\n\nf\nghi", x: 0, y: 2) editor.back editor.verify("abc\nf\nghi", x: 0, y: 1) editor.back editor.verify("abcf\nghi", x: 3, y: 0) editor.delete editor.verify("abc\nghi", x: 3, y: 0) editor.delete editor.verify("abcghi", x: 3, y: 0) end # Empty interpolations `#{""}` are used to better show the influence of the prompt to line wrapping. '#{""}' takes 5 characters, like the prompt used for this spec: 'p:00>'. it "moves cursor left" do editor = SpecHelper.expression_editor editor << "#{""}print :Hel" \ "lo\n" editor << "#{""}print :loo" \ "ooooooooooooooo" \ "oooooong\n" editor << "#{""}:end" editor.verify(x: 4, y: 2) 4.times { editor.move_cursor_left } editor.verify(x: 0, y: 2) editor.move_cursor_left editor.verify(x: 33, y: 1) 34.times { editor.move_cursor_left } editor.verify(x: 12, y: 0) 20.times { editor.move_cursor_left } editor.verify(x: 0, y: 0, scroll_offset: 1) end # Empty interpolations `#{""}` are used to better show the influence of the prompt to line wrapping. '#{""}' takes 5 characters, like the prompt used for this spec: 'p:00>'. it "moves cursor right" do editor = SpecHelper.expression_editor editor << "#{""}print :Hel" \ "lo\n" editor << "#{""}print :loo" \ "ooooooooooooooo" \ "oooooong\n" editor << "#{""}:end" editor.move_cursor_to_begin 12.times { editor.move_cursor_right } editor.verify(x: 12, y: 0, scroll_offset: 1) editor.move_cursor_right editor.verify(x: 0, y: 1, scroll_offset: 1) 34.times { editor.move_cursor_right } editor.verify(x: 0, y: 2) 10.times { editor.move_cursor_right } editor.verify(x: 4, y: 2) end # Empty interpolations `#{""}` are used to better show the influence of the prompt to line wrapping. '#{""}' takes 5 characters, like the prompt used for this spec: 'p:00>'. it "moves cursor up" do editor = SpecHelper.expression_editor editor << "#{""}print :Hel" \ "lo\n" editor << "#{""}print :loo" \ "ooooooooooooooo" \ "oooooong\n" editor << "#{""}:end" editor.verify(x: 4, y: 2) editor.move_cursor_up editor.verify(x: 33, y: 1) editor.move_cursor_up editor.verify(x: 18, y: 1) editor.move_cursor_up editor.verify(x: 3, y: 1) editor.move_cursor_up editor.verify(x: 12, y: 0) editor.move_cursor_up editor.verify(x: 0, y: 0, scroll_offset: 1) end # Empty interpolations `#{""}` are used to better show the influence of the prompt to line wrapping. '#{""}' takes 5 characters, like the prompt used for this spec: 'p:00>'. it "moves cursor down" do editor = SpecHelper.expression_editor editor << "#{""}print :Hel" \ "lo\n" editor << "#{""}print :loo" \ "ooooooooooooooo" \ "oooooong\n" editor << "#{""}:end" editor.move_cursor_to_begin editor.move_cursor_down editor.verify(x: 12, y: 0, scroll_offset: 1) editor.move_cursor_down editor.verify(x: 0, y: 1, scroll_offset: 1) editor.move_cursor_down editor.verify(x: 15, y: 1, scroll_offset: 1) editor.move_cursor_down editor.verify(x: 30, y: 1, scroll_offset: 1) editor.move_cursor_down editor.verify(x: 0, y: 2, scroll_offset: 0) end it "moves cursor to" do editor = SpecHelper.expression_editor editor << "#{""}print :Hel" \ "lo\n" editor << "#{""}print :loo" \ "ooooooooooooooo" \ "oooooong\n" editor << "#{""}:end" editor.move_cursor_to(x: 0, y: 1, allow_scrolling: false) editor.verify(x: 0, y: 1) editor.move_cursor_to(x: 3, y: 2, allow_scrolling: false) editor.verify(x: 3, y: 2) editor.move_cursor_to_begin(allow_scrolling: false) editor.verify(x: 0, y: 0) editor.move_cursor_to(x: 21, y: 1, allow_scrolling: false) editor.verify(x: 21, y: 1) editor.move_cursor_to(x: 12, y: 0, allow_scrolling: false) editor.verify(x: 12, y: 0) editor.move_cursor_to_end(allow_scrolling: false) editor.verify(x: 4, y: 2) editor.move_cursor_to_end_of_line(y: 0, allow_scrolling: false) editor.verify(x: 12, y: 0) editor.move_cursor_to_end_of_line(y: 1, allow_scrolling: false) editor.verify(x: 33, y: 1) end it "replaces" do editor = SpecHelper.expression_editor editor << "aaa\nbbb\nccc" editor.replace(["AAA", "BBBCCC"]) editor.verify("AAA\nBBBCCC", x: 3, y: 1) editor.lines.should eq ["AAA", "BBBCCC"] editor.replace(["aaa", "", "ccc", "ddd"]) editor.verify("aaa\n\nccc\nddd", x: 0, y: 1) editor.lines.should eq ["aaa", "", "ccc", "ddd"] editor.replace([""]) editor.verify("", x: 0, y: 0) editor.lines.should eq [""] end it "ends editing" do editor = SpecHelper.expression_editor editor << "aaa" editor.end_editing editor.verify("aaa", x: 3, y: 0) editor.end_editing(["aaa", "bbb", "ccc"]) editor.verify("aaa\nbbb\nccc", x: 3, y: 2) end it "prompts next" do editor = SpecHelper.expression_editor editor << "aaa" editor.prompt_next editor.verify("", x: 0, y: 0) end it "scroll up and down" do editor = SpecHelper.expression_editor editor << "#{""}print :Hel" \ "lo\n" editor << "#{""}print :Wor" \ "ld\n" editor << "#{""}print :loo" \ "ooooooooooooooo" \ "oooooong\n" editor << "#{""}:end" 4.times { editor.move_cursor_up } editor.expression_height.should eq 8 editor.verify(x: 12, y: 1, scroll_offset: 0) editor.scroll_up editor.verify(x: 12, y: 1, scroll_offset: 1) editor.scroll_down editor.verify(x: 12, y: 1, scroll_offset: 0) editor.scroll_down editor.verify(x: 12, y: 1, scroll_offset: 0) editor.scroll_up editor.scroll_up editor.scroll_up editor.verify(x: 12, y: 1, scroll_offset: 3) editor.scroll_up editor.verify(x: 12, y: 1, scroll_offset: 3) editor.scroll_down editor.verify(x: 12, y: 1, scroll_offset: 2) end it "is aligned when prompt size change" do editor = ExpressionEditor.new do |line_number, _color| "*" * line_number + ">" # A prompt that increase its size at each line end editor.output = IO::Memory.new editor.color = false editor.height = 50 editor.width = 15 editor.update { editor << '1' } editor.verify_output "\e[1G\e[J" + <<-END >1 END editor.update { editor << '\n' << '2' } editor.output = IO::Memory.new # Reset the output because we want verify only the last update editor.update # It currently need an extra update for the alignment to be taken in account. editor.verify_output "\e[1A\e[1G\e[J" \ "> 1\n" \ "*>2" editor.update do editor << '\n' << '3' editor << '\n' << '4' editor << '\n' << '5' end editor.output = IO::Memory.new editor.update editor.verify_output "\e[4A\e[1G\e[J" \ "> 1\n" \ "*> 2\n" \ "**> 3\n" \ "***> 4\n" \ "****>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 end