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

REPL: transpose words with Alt-t #23378

Merged
merged 2 commits into from
Aug 22, 2017
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
34 changes: 31 additions & 3 deletions base/repl/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,9 @@ function edit_kill_line(s::MIState)
refresh_line(s)
end

edit_transpose(s) = edit_transpose(buffer(s)) && refresh_line(s)
function edit_transpose(buf::IOBuffer)
edit_transpose_chars(s) = edit_transpose_chars(buffer(s)) && refresh_line(s)

function edit_transpose_chars(buf::IOBuffer)
position(buf) == 0 && return false
eof(buf) && char_move_left(buf)
char_move_left(buf)
Expand All @@ -599,6 +600,32 @@ function edit_transpose(buf::IOBuffer)
return true
end

edit_transpose_words(s) = edit_transpose_words(buffer(s)) && refresh_line(s)

function edit_transpose_words(buf::IOBuffer, mode=:emacs)
mode in [:readline, :emacs] ||
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be possible to describe what the difference in behavior is in words somewhere? this doesn't have a docstring, but a comment would do if anyone is going to be customizing these

throw(ArgumentError("`mode` must be `:readline` or `:emacs`"))
pos = position(buf)
if mode == :emacs
char_move_word_left(buf)
char_move_word_right(buf)
end
char_move_word_right(buf)
e2 = position(buf)
char_move_word_left(buf)
b2 = position(buf)
char_move_word_left(buf)
b1 = position(buf)
char_move_word_right(buf)
e1 = position(buf)
e1 >= b2 && (seek(buf, pos); return false)
word2 = splice!(buf.data, b2+1:e2, buf.data[b1+1:e1])
splice!(buf.data, b1+1:e1, word2)
seek(buf, e2)
true
end


edit_clear(buf::IOBuffer) = truncate(buf, 0)

function edit_clear(s::MIState)
Expand Down Expand Up @@ -1492,7 +1519,8 @@ AnyDict(
input = bracketed_paste(s)
edit_insert(s, input)
end,
"^T" => (s,o...)->edit_transpose(s)
"^T" => (s,o...)->edit_transpose_chars(s),
"\et" => (s,o...)->edit_transpose_words(s),
)

const history_keymap = AnyDict(
Expand Down
28 changes: 13 additions & 15 deletions base/strings/basic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -277,16 +277,7 @@ julia> chr2ind(str, 2)
"""
function ind2chr(s::AbstractString, i::Integer)
s[i] # throws error if invalid
j = 1
k = start(s)
while true
c, l = next(s,k)
if i <= k
return j
end
j += 1
k = l
end
unsafe_ind2chr(s, i)
end

"""
Expand All @@ -309,18 +300,25 @@ julia> ind2chr(str, 3)
"""
function chr2ind(s::AbstractString, i::Integer)
i < start(s) && throw(BoundsError(s, i))
k = unsafe_chr2ind(s, i)
s[k] # throws error if invalid
k
end

function map_chr_ind(s::AbstractString, i::Integer, stop, ret)
j = 1
k = start(s)
while true
c, l = next(s,k)
if i == j
return k
end
i == stop((j, k)) && return ret((j, k)) # k could point after the last character
_, k = next(s, k)
j += 1
k = l
end
end

unsafe_ind2chr(s::AbstractString, i::Integer) = map_chr_ind(s, i, last, first)
unsafe_chr2ind(s::AbstractString, i::Integer) = map_chr_ind(s, i, first, last)


struct EachStringIndex{T<:AbstractString}
s::T
end
Expand Down
58 changes: 47 additions & 11 deletions test/lineedit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -308,41 +308,77 @@ let buf = IOBuffer()
@test String(buf.data[1:buf.size]) == "a"
end

## edit_transpose ##
## edit_transpose_chars ##
let buf = IOBuffer()
LineEdit.edit_insert(buf, "abcde")
seek(buf,0)
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "abcde"
LineEdit.char_move_right(buf)
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "bacde"
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "bcade"
seekend(buf)
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "bcaed"
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "bcade"

seek(buf, 0)
LineEdit.edit_clear(buf)
LineEdit.edit_insert(buf, "αβγδε")
seek(buf,0)
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "αβγδε"
LineEdit.char_move_right(buf)
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "βαγδε"
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "βγαδε"
seekend(buf)
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "βγαεδ"
LineEdit.edit_transpose(buf)
LineEdit.edit_transpose_chars(buf)
@test String(buf.data[1:buf.size]) == "βγαδε"
end

@testset "edit_word_transpose" begin
buf = IOBuffer()
mode = Ref{Symbol}()
function transpose!(i) # i: char indice
seek(buf, Base.unsafe_chr2ind(String(take!(copy(buf))), i+1)-1)
LineEdit.edit_transpose_words(buf, mode[])
str = String(take!(copy(buf)))
str, Base.unsafe_ind2chr(str, position(buf)+1)-1
end

mode[] = :readline
LineEdit.edit_insert(buf, "àbç def gh ")
@test transpose!(0) == ("àbç def gh ", 0)
@test transpose!(1) == ("àbç def gh ", 1)
@test transpose!(2) == ("àbç def gh ", 2)
@test transpose!(3) == ("def àbç gh ", 7)
@test transpose!(4) == ("àbç def gh ", 7)
@test transpose!(5) == ("def àbç gh ", 7)
@test transpose!(6) == ("àbç def gh ", 7)
@test transpose!(7) == ("àbç gh def ", 11)
@test transpose!(10) == ("àbç def gh ", 11)
@test transpose!(11) == ("àbç gh def", 12)
LineEdit.edit_insert(buf, " ")
@test transpose!(13) == ("àbç def gh", 13)

take!(buf)
mode[] = :emacs
LineEdit.edit_insert(buf, "àbç def gh ")
@test transpose!(0) == ("def àbç gh ", 7)
@test transpose!(4) == ("àbç def gh ", 7)
@test transpose!(5) == ("àbç gh def ", 11)
@test transpose!(10) == ("àbç def gh", 12)
LineEdit.edit_insert(buf, " ")
@test transpose!(13) == ("àbç gh def", 13)
end

let
term = TestHelpers.FakeTerminal(IOBuffer(), IOBuffer(), IOBuffer())
s = LineEdit.init_state(term, ModalInterface([Prompt("test> ")]))
Expand Down