From 6960190d145157542995b2f5368e8d1f5572f7f6 Mon Sep 17 00:00:00 2001 From: caleb-allen Date: Tue, 20 Feb 2024 14:30:24 +0000 Subject: [PATCH 1/5] Set index of testbuf with bytes, not length(str) --- src/buffer.jl | 14 ++++++++++---- src/operator.jl | 5 ++++- test/command.jl | 18 ++++++++++++++++-- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/buffer.jl b/src/buffer.jl index 1964ff6..f5fdf52 100644 --- a/src/buffer.jl +++ b/src/buffer.jl @@ -35,8 +35,11 @@ function testbuf(s::AbstractString)::VimBuffer end (a, mode, b) = (m[1], m[2], m[3]) buf = IOBuffer(; read=true, write=true, append=true) - write(buf, a * b) - seek(buf, length(a)) + cursor_index = write(buf, a) + after_cursor = write(buf, b) + # @debug "creating testbuf" cursor_index after_cursor + + seek(buf, cursor_index) vim_mode = VimMode(mode) return VimBuffer(buf, vim_mode) end @@ -50,6 +53,9 @@ VimBuffer(str::String)::VimBuffer = testbuf(str) mode(vb::VimBuffer) = vb.mode # TODO modify VimBuffer operations to operate on Characters rather than bytes +# Status: Removed uses of +# - [ ] length() +# - [ ] skip() in favor of skipchars, or else ensure skip operatoes on characters only Base.position(vb::VimBuffer) = position(vb.buf) Base.seek(vb::VimBuffer, n) = seek(vb.buf, n) Base.mark(vb::VimBuffer) = mark(vb.buf) @@ -106,7 +112,7 @@ end """ Read 1 valid UTF-8 character right of the current position and leave the buffer in the same position. """ -function peek_right(buf::IO)::Union{Char, Nothing} +function peek_right(buf::IO)::Union{Char,Nothing} origin = position(buf) while !eof(buf) c = read(buf, Char) @@ -124,7 +130,7 @@ Read 1 valid UTF-8 character right of the current position. Place the cursor after the char that is read, if any. """ -function read_right(buf::IO)::Union{Char, Nothing} +function read_right(buf::IO)::Union{Char,Nothing} origin = position(buf) while !eof(buf) c = read(buf, Char) diff --git a/src/operator.jl b/src/operator.jl index ea319ff..47445aa 100644 --- a/src/operator.jl +++ b/src/operator.jl @@ -35,8 +35,11 @@ end # and "cw" only removes the inner word function delete(buf::IO, motion::Motion) #, motion_type :: MotionType) text = String(take!(copy(buf))) + @debug "delete range:" min(motion) max(motion) length(text) textwidth(text) left = min(motion) - right = min(max(motion), length(text)) + # right = min(max(motion), length(text)) + right = max(motion) + @debug "delete range:" left right # if motion.motiontype == linewise # end move_cursor = Motion(buf) diff --git a/test/command.jl b/test/command.jl index 1f550fb..65c2142 100644 --- a/test/command.jl +++ b/test/command.jl @@ -147,10 +147,24 @@ end end @testset "unicode" begin + # https://github.com/caleb-allen/VimBindings.jl/issues/95 + @test run("(0b0000 ⊻ 0b000|0)", "x") == testbuf("(0b0000 ⊻ 0b000|)") + @test run("0b0000 ⊻ 0b000|0", "x") == testbuf("0b0000 ⊻ 0b00|0") + s = "\u2200 x \u2203 y" s = "∀ x ∃ y" - @test_broken run("|∀ x ∃ y", "w") == testbuf("∀ |x ∃ y") - @test_broken run("∀ x |∃ y", "w") == testbuf("∀ x |∃ y") + @test run("|∀ x ∃ y", "w") == testbuf("∀ |x ∃ y") + @test run("∀ x |∃ y", "w") == testbuf("∀ x |∃ y") + + + +end + +@testset "x on last char should move left" begin + # https://github.com/caleb-allen/VimBindings.jl/issues/92 + + @test run("foo() = :ba|r", "x") == testbuf("foo() = :b|a") + end @testset "replace character" begin From 2d019db783319692a6e910094c5dcc3b9519e784 Mon Sep 17 00:00:00 2001 From: caleb-allen Date: Tue, 20 Feb 2024 16:27:20 +0000 Subject: [PATCH 2/5] Removed unnecessary constructor for `VimBuffer` Also added tests which should pass if the issue is fixed --- src/buffer.jl | 2 +- src/changes.jl | 2 +- src/motion.jl | 13 ++++++++++++- src/operator.jl | 6 +++--- src/textutils.jl | 2 ++ test/changes.jl | 10 +++++----- test/command.jl | 15 +++++++++++++-- test/motion.jl | 4 ++-- 8 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/buffer.jl b/src/buffer.jl index f5fdf52..8ab49e1 100644 --- a/src/buffer.jl +++ b/src/buffer.jl @@ -49,7 +49,7 @@ struct VimBuffer <: IO mode::VimMode end -VimBuffer(str::String)::VimBuffer = testbuf(str) +VimBuffer() = VimBuffer(IOBuffer(), normal_mode) mode(vb::VimBuffer) = vb.mode # TODO modify VimBuffer operations to operate on Characters rather than bytes diff --git a/src/changes.jl b/src/changes.jl index df9bdc9..f970bc1 100644 --- a/src/changes.jl +++ b/src/changes.jl @@ -81,7 +81,7 @@ end # blank entry. Both `prev` and `next` reference itself. id of 1. # for the root of a list (the first entry) function Entry() - record = VimBuffer("|") |> freeze + record = IOBuffer() |> freeze return Entry(record) end diff --git a/src/motion.jl b/src/motion.jl index 8426aaa..24072b3 100644 --- a/src/motion.jl +++ b/src/motion.jl @@ -11,7 +11,7 @@ export Motion, MotionType, simple_motions, complex_motions, partial_complex_moti is_stationary, down, up, word_next, word_big_next, word_end, word_back, word_big_back, word_big_end, line_end, line_begin, line_zero, find_c, find_c_back, get_safe_name, all_keys, special_keys, exclusive, inclusive, linewise, endd, - left, right + left, right, snap_into_line # text objects export line @@ -323,6 +323,17 @@ function line_zero(buf::IO)::Motion return Motion(start, endd) end +""" +Ensure the cursor is within the current line. In other words, +move left if that will put us on text that is within the line. +""" +snap_into_line(buf::IO)::Motion = + if is_line_end(buf) && !is_line_start(buf) + left(buf) + else + Motion(buf) + end + function endd(buf::IO)::Motion end diff --git a/src/operator.jl b/src/operator.jl index 47445aa..bc6de79 100644 --- a/src/operator.jl +++ b/src/operator.jl @@ -37,11 +37,8 @@ function delete(buf::IO, motion::Motion) #, motion_type :: MotionType) text = String(take!(copy(buf))) @debug "delete range:" min(motion) max(motion) length(text) textwidth(text) left = min(motion) - # right = min(max(motion), length(text)) right = max(motion) @debug "delete range:" left right - # if motion.motiontype == linewise - # end move_cursor = Motion(buf) if motion.motiontype == linewise # if we're deleting a line, include the '\n' at the beginning @@ -71,7 +68,10 @@ function delete(buf::IO, motion::Motion) #, motion_type :: MotionType) if motion.motiontype == linewise move_cursor(buf) + elseif is_line_end(buf) && !is_line_start(buf) + snap_into_line(buf) end + return nothing end diff --git a/src/textutils.jl b/src/textutils.jl index 9495d65..6e58243 100644 --- a/src/textutils.jl +++ b/src/textutils.jl @@ -172,6 +172,8 @@ junction_type(char1::NewlineChar, char2::SpaceChar) = Set([Start{Line}(), Start{ junction_type(char1::Nothing, char2::NewlineChar) = Set([Start{Line}(), End{Line}()]) junction_type(char1::NewlineChar, char2::Nothing) = Set([Start{Line}(), End{Line}()]) +junction_type(char1::NewlineChar, char2::NewlineChar) = Set([Start{Line}(), End{Line}()]) + junction_type(char1::WordChar, char2::PunctuationChar) = Set([Start{Word}(), End{Word}(), In{Object}()]) junction_type(char1::PunctuationChar, char2::WordChar) = Set([Start{Word}(), End{Word}(), In{Object}()]) diff --git a/test/changes.jl b/test/changes.jl index 5799187..9477d8c 100644 --- a/test/changes.jl +++ b/test/changes.jl @@ -5,13 +5,13 @@ import VimBindings.PkgTools: run as run_command @testset "BufferRecord and freeze" begin reset!() - a = freeze(VimBuffer("Hello world|!")) - b = freeze(VimBuffer("Hello worl|d")) + a = freeze(testbuf("Hello world|!")) + b = freeze(testbuf("Hello worl|d")) @test a != b - @test freeze(VimBuffer("Hello world|!")) != BufferRecord("Hello |!", 1) - @test freeze(VimBuffer("Hello world|!")) == BufferRecord("Hello world!", 11) - @test freeze(VimBuffer("Hello|i| world!")) == BufferRecord("Hello world!", 5) + @test freeze(testbuf("Hello world|!")) != BufferRecord("Hello |!", 1) + @test freeze(testbuf("Hello world|!")) == BufferRecord("Hello world!", 11) + @test freeze(testbuf("Hello|i| world!")) == BufferRecord("Hello world!", 5) # The record includes the cursor location but does not include it in equality @test BufferRecord("Hello world!", 7) == BufferRecord("Hello world!", 5) diff --git a/test/command.jl b/test/command.jl index 65c2142..84de416 100644 --- a/test/command.jl +++ b/test/command.jl @@ -95,6 +95,8 @@ end @test run("a %%%|asdf b", "ciw") == testbuf("a %%%|i| b") @test run("a |asdf b", "ciw") == testbuf("a |i| b") + @test run("{3: three|}", "daw") == testbuf("3: thre|e") + @test run("{3: thre|e}", "daw") == testbuf("3:|}") end @testset "fFtT" begin @@ -160,17 +162,26 @@ end end -@testset "x on last char should move left" begin +@testset "delete at end of line should move left" begin # https://github.com/caleb-allen/VimBindings.jl/issues/92 @test run("foo() = :ba|r", "x") == testbuf("foo() = :b|a") + @test run("foo() = :ba|r\nbaz", "x") == testbuf("foo() = :b|a\nbaz") + @test run("foo() = :ba|r\nbaz", "x") != testbuf("foo() = :ba|\nbaz") + + # with text objects, too + @test run("abcd\nxyz ef|g", "daw") == testbuf("abcd\nxyz| ") + + @test run("abcd\nef|g", "daw") == testbuf("abcd\n|") end @testset "replace character" begin @test run("abcd|e 12345", "rx") == testbuf("abcd|x 12345") @test run("|abcde", "3rx") == testbuf("xx|xde") - @test_broken run("∀ x |∃ y", "rx") == testbuf("∀ x |x y") + @test run("∀ x |∃ y", "rx") == testbuf("∀ x |x y") + + @test run("∀ x ∃ |y", "rx") == testbuf("∀ x |∃ |x") end @testset "yank / put" begin diff --git a/test/motion.jl b/test/motion.jl index d2ac2cf..7966fe1 100644 --- a/test/motion.jl +++ b/test/motion.jl @@ -24,10 +24,10 @@ end motion = word_next(buf) @test motion == Motion(0, 5, exclusive) - buf = VimBuffer("hell|o world!") + buf = testbuf("hell|o world!") motion = word_next(buf) motion(buf) - @test buf == VimBuffer("hello |world!") + @test buf == testbuf("hello |world!") end @testset "word end" begin From c3f67a91c821de4bb02eb5258c6c8ff2cf1bb3e8 Mon Sep 17 00:00:00 2001 From: caleb-allen Date: Thu, 28 Mar 2024 18:02:40 +0000 Subject: [PATCH 3/5] Fix line snapping issue --- development.md | 7 +++++++ src/operator.jl | 4 +++- test/changes.jl | 16 ++++++++-------- test/command.jl | 10 ++++++---- test/motion.jl | 10 ++++++++++ test/textutils.jl | 15 +++++++++++++++ 6 files changed, 49 insertions(+), 13 deletions(-) diff --git a/development.md b/development.md index 7b185e1..8801928 100644 --- a/development.md +++ b/development.md @@ -44,6 +44,13 @@ Once logging is enabled, you should see something like this from `nc`: └ @ VimBindings ~/.julia/dev/VimBindings/src/VimBindings.jl:161 ``` +# Disabling precompile + +``` +using VimBindings, Preferences +set_preferences!(VimBindings, "precompile_workload" => false; force=true) +``` + # Useful References ### Vim plugins for other editors - https://github.com/JetBrains/ideavim diff --git a/src/operator.jl b/src/operator.jl index bc6de79..a8cd543 100644 --- a/src/operator.jl +++ b/src/operator.jl @@ -69,7 +69,9 @@ function delete(buf::IO, motion::Motion) #, motion_type :: MotionType) if motion.motiontype == linewise move_cursor(buf) elseif is_line_end(buf) && !is_line_start(buf) - snap_into_line(buf) + let motion = snap_into_line(buf) + motion(buf) + end end return nothing diff --git a/test/changes.jl b/test/changes.jl index 9477d8c..9a50d31 100644 --- a/test/changes.jl +++ b/test/changes.jl @@ -153,22 +153,22 @@ end @testset "undo/redo cursor" begin reset!() - buf = testbuf("Hello worl|d") + buf = testbuf("Hello w|orld") record(buf) - run_command("daw", buf) + run_command("dw", buf) # test that `dw` records an entry - @test buf == testbuf("Hello |") + @test buf == testbuf("Hello |w") record(buf) - @test Changes.latest[].record == BufferRecord("Hello ", 6) + @test Changes.latest[].record == BufferRecord("Hello w", 6) run_command("u", buf) @test Changes.latest[].record == BufferRecord("Hello world", 6) # running undo records the record as `next` - @test Changes.latest[].next[].record == BufferRecord("Hello ", 6) + @test Changes.latest[].next[].record == BufferRecord("Hello w", 6) # \x12 == C-r for redo run_command("\x12", buf) - @test buf == testbuf("Hello |") - @test Changes.latest[].record == BufferRecord("Hello ", 6) - @test Changes.latest[].next[].record == BufferRecord("Hello ", 6) + @test buf == testbuf("Hello |w") + @test Changes.latest[].record == BufferRecord("Hello w", 6) + @test Changes.latest[].next[].record == BufferRecord("Hello w", 6) end diff --git a/test/command.jl b/test/command.jl index 84de416..a642522 100644 --- a/test/command.jl +++ b/test/command.jl @@ -62,11 +62,13 @@ end @testset "hl with delete" begin @test run("asdf|", "h") == testbuf("asd|f") - @test run("asdf|", "l") == testbuf("asdf|") - @test run("asdf|", "dh") == testbuf("asd|") - @test run("asdf|", "dl") == testbuf("asdf|") + @test run("asd|f", "l") == testbuf("asd|f") + @test run("asd|f", "dh") == testbuf("as|f") + @test run("asd|f", "dl") == testbuf("as|d") @test run("|asdf", "dl") == testbuf("|sdf") - @test run("asdf|", "X") == testbuf("asd|") + @test run("|asdf", "dh") == testbuf("|asdf") + @test run("asd|f", "X") == testbuf("as|f") + @test run("asd|f", "x") == testbuf("as|d") end @testset "de" begin diff --git a/test/motion.jl b/test/motion.jl index 7966fe1..75dcb27 100644 --- a/test/motion.jl +++ b/test/motion.jl @@ -90,6 +90,16 @@ First line @test line_begin(buf) == Motion(4, 0, exclusive) end +@testset "snap into line" begin + s = """Hello!| + world""" + buf = testbuf(s) + m = snap_into_line(buf) + m(buf) + @test buf == testbuf("""Hello|! + world""") +end + @testset "exclusive / inclusive motions" begin m = Motion(1, 2, exclusive) @test min(m) == 1 diff --git a/test/textutils.jl b/test/textutils.jl index 82bc9a8..bb477e9 100644 --- a/test/textutils.jl +++ b/test/textutils.jl @@ -173,3 +173,18 @@ end end + + +@testset "is text in a line" begin + s = """Hello!| + world""" + buf = testbuf(s) + @test is_line_end(buf) == true + @test is_line_start(buf) == false + + s = """Hello! + |world""" + buf = testbuf(s) + @test is_line_end(buf) == false + @test is_line_start(buf) == true +end From 1134bae194dab05134f6d9beacab411317e1a1bd Mon Sep 17 00:00:00 2001 From: caleb-allen Date: Thu, 28 Mar 2024 19:22:44 +0000 Subject: [PATCH 4/5] Add an `is_line_max` function to clarify right ward motions - Change `s` to be a synonym, rather than its own function - swap ordering of `at_junction_type` params so that the last arg can be more flexible (different number of args) --- src/buffer.jl | 15 ++++++++++++++- src/execute.jl | 17 ++++++++++------- src/motion.jl | 2 +- src/parse.jl | 4 ++-- src/textutils.jl | 44 +++++++++++++++++++++++++++++++------------- test/command.jl | 7 ++++++- test/textutils.jl | 14 +++++++++++++- 7 files changed, 77 insertions(+), 26 deletions(-) diff --git a/src/buffer.jl b/src/buffer.jl index 8ab49e1..5353447 100644 --- a/src/buffer.jl +++ b/src/buffer.jl @@ -1,7 +1,7 @@ module Buffer import REPL.LineEdit as LE export VimBuffer, mode, VimMode, normal_mode, insert_mode, testbuf, readall, freeze, - BufferRecord, chars, peek_left, peek_right, read_left, read_right + BufferRecord, chars, peek_left, peek_right, peek_two_right, read_left, read_right @enum VimMode begin normal_mode @@ -125,6 +125,19 @@ function peek_right(buf::IO)::Union{Char,Nothing} return nothing end +""" +Read up to 2 valid UTF-8 character right of the current position and leave the buffer in the same position. + +Returns a tuple with each successful character (or nothing for a character not read successfully) +""" +function peek_two_right(buf::IO) + origin = position(buf) + c1 = read_right(buf) + c2 = read_right(buf) + seek(buf, origin) + return (c1, c2) +end + """ Read 1 valid UTF-8 character right of the current position. diff --git a/src/execute.jl b/src/execute.jl index 2d2fed4..a150792 100644 --- a/src/execute.jl +++ b/src/execute.jl @@ -37,8 +37,13 @@ function execute(buf, command::MotionCommand)::Union{VimMode,ReplAction,Nothing} nothing end else - # execute the motion object - motion(buf) + k = key(command) + if !(k == 'l' && is_line_max(buf)) + # we shouldn't move past the last character of the line + + # execute the motion object + motion(buf) + end end end return repl_action @@ -89,9 +94,6 @@ const insert_functions = Dict{Char,Function}( motion end end, - 's' => buf -> begin - delete(buf, right(buf)) - end # _ => gen_motion(buf, command) ) @@ -119,7 +121,7 @@ function execute(buf, command::OperatorCommand)::Union{VimMode,Nothing} # see vim help :h cw regarding this exception if command.operator == 'c' && command.action.name in ['w', 'W'] # in the middle of a word - if at_junction_type(buf, In{>:Word}) || at_junction_type(buf, Start{>:Word}) + if at_junction_type(In{>:Word}, buf) || at_junction_type(Start{>:Word}, buf) new_name = if command.action.name == 'w' 'e' else @@ -172,7 +174,8 @@ function execute(buf, command::SynonymCommand)::Union{VimMode,Nothing} 'X' => "dh", 'C' => "c\$", 'D' => "d\$", - 'S' => "cc" + 'S' => "cc", + 's' => "cl", ) new_command = parse_command("$(command.r1)$(synonyms[command.operator])") diff --git a/src/motion.jl b/src/motion.jl index 24072b3..01a3164 100644 --- a/src/motion.jl +++ b/src/motion.jl @@ -113,7 +113,7 @@ end function left(buf::IO)::Motion start = position(buf) - @loop_guard while position(buf) > 0 + @loop_guard while position(buf) > 0 && !is_line_start(buf) seek(buf, position(buf) - 1) c = peek(buf) (((c & 0x80) == 0) || ((c & 0xc0) == 0xc0)) && break diff --git a/src/parse.jl b/src/parse.jl index b97a8b2..a1ccc74 100644 --- a/src/parse.jl +++ b/src/parse.jl @@ -53,8 +53,8 @@ end const UNDO_REDO = "(?|(u)|(\x12))" const TEXTOBJECT = "$REPEAT[ai][wWsp]" const PARTIALTEXTOBJECT = "$REPEAT[ai]([wWsp])?" -const DELETECHARS = "[xXDCS]" -const INSERTCHARS = "[aAiIoOs]" +const DELETECHARS = "[xXDCSs]" +const INSERTCHARS = "[aAiIoO]" const OPERATOR = "[ydc]" const RULES = TupleDict( "^(?$INSERTCHARS)\$" |> Regex => InsertCommand, # insert commands diff --git a/src/textutils.jl b/src/textutils.jl index 6e58243..cc3b6b1 100644 --- a/src/textutils.jl +++ b/src/textutils.jl @@ -1,3 +1,6 @@ +""" +Getting carried away with types and multiple dispatch: text utility style +""" module TextUtils import Base: * using REPL @@ -9,33 +12,41 @@ export is_newline, is_whitespace, is_word_char, TextChar, WordChar, WhitespaceCh chars_by_cursor, junction_type, at_junction_type, Text, Object, Word, Line, Whitespace, Junction, Start, End, In, is_alphanumeric, is_alphabetic, is_uppercase, is_lowercase, is_punctuation, is_line_start, is_line_end, is_word_end, is_word_start, is_object_start, is_object_end, is_in_object, is_whitespace_end, is_whitespace_start, is_in_word, chars, - peek_left, peek_right, read_left, read_right + peek_left, peek_right, read_left, read_right, is_line_max """ Determine whether the buffer is currently at the start of a text object. Whitespace is not included as a text object. """ -is_word_start(buf) = at_junction_type(buf, Start{>:Word}) -is_whitespace_start(buf) = at_junction_type(buf, Start{>:Whitespace}) +is_word_start(buf) = at_junction_type(Start{>:Word}, buf) +is_whitespace_start(buf) = at_junction_type(Start{>:Whitespace}, buf) """ Whether the buffer is currently at the start of a non-whitespace block """ -is_object_start(buf) = at_junction_type(buf, Start{>:Object}) +is_object_start(buf) = at_junction_type(Start{>:Object}, buf) """ Whether the buffer is currently at the end of a text object. Whitespace is not included as a text object. """ -is_word_end(buf) = at_junction_type(buf, End{>:Word}) -is_object_end(buf) = at_junction_type(buf, End{>:Object}) -is_whitespace_end(buf) = at_junction_type(buf, End{>:Whitespace}) +is_word_end(buf) = at_junction_type(End{>:Word}, buf) +is_object_end(buf) = at_junction_type(End{>:Object}, buf) +is_whitespace_end(buf) = at_junction_type(End{>:Whitespace}, buf) """ Whether the buffer is at the start of a line, in the literal sense In other words, is the char before the cursor a newline """ -is_line_start(buf) = at_junction_type(buf, Start{>:Line}) -is_line_end(buf) = at_junction_type(buf, End{>:Line}) +is_line_start(buf) = at_junction_type(Start{>:Line}, buf) +is_line_end(buf) = at_junction_type(End{>:Line}, buf) + +""" +Whether the buffer's location is the right-most that the cursor is allowed to go; the "end of the line" so that the cursor does not get placed at a newline where there is not actually a character to operate on. +""" +function is_line_max(buf) + c1, c2 = peek_two_right(buf) + return at_junction_type(End{>:Line}, c1, c2) +end """ @@ -44,10 +55,10 @@ Whether the buffer is currently in an object of a continuous type (not between t function is_in_word(buf) a, b = chars_by_cursor(buf) typeof(a) == typeof(b) || return false - at_junction_type(buf, In{>:Word}) + at_junction_type(In{>:Word}, buf) end -is_in_object(buf) = at_junction_type(buf, In{<:Object}) +is_in_object(buf) = at_junction_type(In{<:Object}, buf) """ Get the @@ -183,8 +194,15 @@ junction_type(char1::T, char2::T) where {T<:SpaceChar} = Set([In{Whitespace}()]) """ Whether the given buffer is currently at a junction of type junc """ -function at_junction_type(buf, junc_type) - for junc in junction_type(buf) +function at_junction_type(junc_type, obj::Vararg) + juncs = junction_type(obj...) + # return at_junction_type(junction_type(obj, junc_type...)) + return at_junction_type(junc_type, juncs) +end + +function at_junction_type(junc_type, juncs::Set) + # TODO nuke this whole thing + for junc in juncs if junc isa junc_type @debug "at_junction_type?" junc_type chars_by_cursor(buf) at_junction_type = true return true diff --git a/test/command.jl b/test/command.jl index a642522..21b6d7e 100644 --- a/test/command.jl +++ b/test/command.jl @@ -41,7 +41,8 @@ end @testset "basic movements" begin @test run("asdf|", "h") == testbuf("asd|f") @test run("asdf|", "l") == testbuf("asdf|") - @test run("asd|f", "l") == testbuf("asdf|") + @test run("asd|f", "l") == testbuf("asd|f") + @test run("|asdf", "l") == testbuf("a|sdf") @test run("a|sdf", "\$") == testbuf("asd|f") @test run("asd|f", "\$") == testbuf("asd|f") @@ -69,6 +70,9 @@ end @test run("|asdf", "dh") == testbuf("|asdf") @test run("asd|f", "X") == testbuf("as|f") @test run("asd|f", "x") == testbuf("as|d") + + @test run("|asdf", "s") == testbuf("|i|sdf") + @test run("asd|f", "s") == testbuf("asd|i|") end @testset "de" begin @@ -152,6 +156,7 @@ end @testset "unicode" begin # https://github.com/caleb-allen/VimBindings.jl/issues/95 + @test run("fo|o", "x") == testbuf("f|o") @test run("(0b0000 ⊻ 0b000|0)", "x") == testbuf("(0b0000 ⊻ 0b000|)") @test run("0b0000 ⊻ 0b000|0", "x") == testbuf("0b0000 ⊻ 0b00|0") diff --git a/test/textutils.jl b/test/textutils.jl index bb477e9..8640657 100644 --- a/test/textutils.jl +++ b/test/textutils.jl @@ -128,7 +128,7 @@ end @test is_in_object(testbuf("hello%%|%%")) == true @test is_in_object(testbuf("|hello%%%%")) == false end -@testset "is line start " begin +@testset "start and end of lines" begin @test is_line_end(testbuf("|\n")) == true @test is_line_end(testbuf("one line\t|\nhello")) == true @test is_line_end(testbuf("one line\t\nhello|")) == true @@ -141,6 +141,18 @@ end @test is_line_start(testbuf("one line|\nhello")) == false @test is_line_start(testbuf("one line \n|hello")) == true + @test is_line_max(testbuf(""" + |hello world! + """)) == false + + @test is_line_max(testbuf(""" + hello world|! + """)) == true + + @test is_line_max(testbuf("|")) == true + @test is_line_max(testbuf("foo|")) == true + @test is_line_max(testbuf("fo|o")) == true + @test is_line_max(testbuf("f|oo")) == false end @testset "test buffer" begin From e70a3bf5ce69ecfb350a71a0993855068ed64ee4 Mon Sep 17 00:00:00 2001 From: caleb-allen Date: Wed, 3 Apr 2024 17:59:34 +0100 Subject: [PATCH 5/5] Modify tests to account for end of line spaces --- src/changes.jl | 2 +- src/execute.jl | 6 ++++++ src/operator.jl | 4 ++-- test/command.jl | 24 +++++++++++++++--------- test/textobject.jl | 4 ++++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/changes.jl b/src/changes.jl index f970bc1..8583dad 100644 --- a/src/changes.jl +++ b/src/changes.jl @@ -61,7 +61,7 @@ struct Entry end -Entry(s::String) = Entry(freeze(testbuf("|"))) +Entry(s::String) = Entry(freeze(VimBuffer())) # entry where both `prev` and `next` reference itself function Entry(record::BufferRecord) e = Entry(1, Ref{Entry}(), Ref{Entry}(), record) diff --git a/src/execute.jl b/src/execute.jl index a150792..ec2f012 100644 --- a/src/execute.jl +++ b/src/execute.jl @@ -185,7 +185,13 @@ end function execute(buf, command::ReplaceCommand)::Union{VimMode,Nothing} inserted = 0 for r1 in 1:command.r1 + move_right = is_line_max(buf) delete(buf, right(buf)) + if move_right + let motion = right(buf) + motion(buf) + end + end inserted += LE.edit_insert(buf, command.replacement) end if inserted > 0 diff --git a/src/operator.jl b/src/operator.jl index a8cd543..375733c 100644 --- a/src/operator.jl +++ b/src/operator.jl @@ -23,8 +23,8 @@ end function change(buf::IO, motion::Motion) #, motion_type :: MotionType) text = String(take!(copy(buf))) left = min(motion) - right = min(max(motion), length(text)) - @debug "change operator" buf motion text left right + right = min(max(motion), sizeof(text)) + @debug "change operator" buf motion text left right max(motion) length(text) yank(buf, motion) move(buf, motion) #, motion_type) LE.edit_splice!(buf, left => right) diff --git a/test/command.jl b/test/command.jl index 21b6d7e..f7b20e7 100644 --- a/test/command.jl +++ b/test/command.jl @@ -70,18 +70,20 @@ end @test run("|asdf", "dh") == testbuf("|asdf") @test run("asd|f", "X") == testbuf("as|f") @test run("asd|f", "x") == testbuf("as|d") - + @test run("|asdf", "s") == testbuf("|i|sdf") @test run("asd|f", "s") == testbuf("asd|i|") end @testset "de" begin - @test run("a|sdf", "de") == testbuf("a|") + @test run("a|sdf qwerty", "de") == testbuf("a| qwerty") + @test run("a|sdf", "de") == testbuf("|a") @test run("a|sdf abcd", "de") == testbuf("a| abcd") end @testset "dw" begin - @test run("a|", "dw") == testbuf("a|") + @test run("|", "dw") == testbuf("|") + @test run("|a", "dw") == testbuf("|") @test run("a|sdf abcd", "dw") == testbuf("a|abcd") end @testset "distinct behavior of dw and cw" begin @@ -101,8 +103,8 @@ end @test run("a %%%|asdf b", "ciw") == testbuf("a %%%|i| b") @test run("a |asdf b", "ciw") == testbuf("a |i| b") - @test run("{3: three|}", "daw") == testbuf("3: thre|e") - @test run("{3: thre|e}", "daw") == testbuf("3:|}") + @test_skip run("{3: three|}", "daw") == testbuf("{3: thre|e") + @test_skip run("{3: thre|e}", "daw") == testbuf("{3:|}") end @testset "fFtT" begin @@ -122,8 +124,8 @@ end end @testset "D" begin - @test run("aaaa bbbb |ccc ddd", "d\$") == testbuf("aaaa bbbb |") - @test run("aaaa bbbb |ccc ddd", "D") == testbuf("aaaa bbbb |") + @test run("aaaa bbbb |ccc ddd", "d\$") == testbuf("aaaa bbbb| ") + @test run("aaaa bbbb |ccc ddd", "D") == testbuf("aaaa bbbb| ") @test run("aaaa bbbb |ccc ddd", "D") == run("aaaa bbbb |ccc ddd", "d\$") end @@ -163,7 +165,7 @@ end s = "\u2200 x \u2203 y" s = "∀ x ∃ y" @test run("|∀ x ∃ y", "w") == testbuf("∀ |x ∃ y") - @test run("∀ x |∃ y", "w") == testbuf("∀ x |∃ y") + @test run("∀ x |∃ y", "w") == testbuf("∀ x ∃ |y") @@ -188,7 +190,11 @@ end @test run("|abcde", "3rx") == testbuf("xx|xde") @test run("∀ x |∃ y", "rx") == testbuf("∀ x |x y") - @test run("∀ x ∃ |y", "rx") == testbuf("∀ x |∃ |x") + t = run("∀ x ∃ |n|y", "rx") + result = testbuf("∀ x ∃ |n|x") + + @test_broken t == result + end @testset "yank / put" begin diff --git a/test/textobject.jl b/test/textobject.jl index 1f16ca1..70cf5f9 100644 --- a/test/textobject.jl +++ b/test/textobject.jl @@ -24,3 +24,7 @@ end # @test space(testbuf("this | space")) == (4, 5) # @test space(testbuf("this |space")) == (6, 6) end + +@testset "inner/outer" begin + +end \ No newline at end of file