fix(prompt): handle multibyte character in Backspace, ^h, ^b and ^f
This commit is contained in:
parent
b63399f656
commit
bbaccb05bc
|
@ -114,7 +114,6 @@ local io = io
|
||||||
local table = table
|
local table = table
|
||||||
local math = math
|
local math = math
|
||||||
local ipairs = ipairs
|
local ipairs = ipairs
|
||||||
local pcall = pcall
|
|
||||||
local capi =
|
local capi =
|
||||||
{
|
{
|
||||||
selection = selection
|
selection = selection
|
||||||
|
@ -258,6 +257,11 @@ local function history_add(id, command)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
local function have_multibyte_char_at(text, position)
|
||||||
|
return text:sub(position, position):wlen() == -1
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Draw the prompt text with a cursor.
|
--- Draw the prompt text with a cursor.
|
||||||
-- @tparam table args The table of arguments.
|
-- @tparam table args The table of arguments.
|
||||||
-- @field text The text.
|
-- @field text The text.
|
||||||
|
@ -285,10 +289,14 @@ local function prompt_text_with_cursor(args)
|
||||||
text_start = gstring.xml_escape(text)
|
text_start = gstring.xml_escape(text)
|
||||||
text_end = ""
|
text_end = ""
|
||||||
else
|
else
|
||||||
char = gstring.xml_escape(text:sub(args.cursor_pos, args.cursor_pos))
|
local offset = 0
|
||||||
|
if have_multibyte_char_at(text, args.cursor_pos) then
|
||||||
|
offset = 1
|
||||||
|
end
|
||||||
|
char = gstring.xml_escape(text:sub(args.cursor_pos, args.cursor_pos + offset))
|
||||||
spacer = " "
|
spacer = " "
|
||||||
text_start = gstring.xml_escape(text:sub(1, args.cursor_pos - 1))
|
text_start = gstring.xml_escape(text:sub(1, args.cursor_pos - 1))
|
||||||
text_end = gstring.xml_escape(text:sub(args.cursor_pos + 1))
|
text_end = gstring.xml_escape(text:sub(args.cursor_pos + 1 + offset))
|
||||||
end
|
end
|
||||||
|
|
||||||
local cursor_color = gcolor.ensure_pango_color(args.cursor_color)
|
local cursor_color = gcolor.ensure_pango_color(args.cursor_color)
|
||||||
|
@ -663,6 +671,9 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
||||||
elseif key == "b" then
|
elseif key == "b" then
|
||||||
if cur_pos > 1 then
|
if cur_pos > 1 then
|
||||||
cur_pos = cur_pos - 1
|
cur_pos = cur_pos - 1
|
||||||
|
if have_multibyte_char_at(command, cur_pos) then
|
||||||
|
cur_pos = cur_pos - 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
elseif key == "d" then
|
elseif key == "d" then
|
||||||
if cur_pos <= #command then
|
if cur_pos <= #command then
|
||||||
|
@ -711,12 +722,20 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
||||||
end
|
end
|
||||||
elseif key == "f" then
|
elseif key == "f" then
|
||||||
if cur_pos <= #command then
|
if cur_pos <= #command then
|
||||||
|
if have_multibyte_char_at(command, cur_pos) then
|
||||||
|
cur_pos = cur_pos + 2
|
||||||
|
else
|
||||||
cur_pos = cur_pos + 1
|
cur_pos = cur_pos + 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
elseif key == "h" then
|
elseif key == "h" then
|
||||||
if cur_pos > 1 then
|
if cur_pos > 1 then
|
||||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
local offset = 0
|
||||||
cur_pos = cur_pos - 1
|
if have_multibyte_char_at(command, cur_pos - 1) then
|
||||||
|
offset = 1
|
||||||
|
end
|
||||||
|
command = command:sub(1, cur_pos - 2 - offset) .. command:sub(cur_pos)
|
||||||
|
cur_pos = cur_pos - 1 - offset
|
||||||
end
|
end
|
||||||
elseif key == "k" then
|
elseif key == "k" then
|
||||||
command = command:sub(1, cur_pos - 1)
|
command = command:sub(1, cur_pos - 1)
|
||||||
|
@ -844,8 +863,12 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
||||||
cur_pos = #command + 1
|
cur_pos = #command + 1
|
||||||
elseif key == "BackSpace" then
|
elseif key == "BackSpace" then
|
||||||
if cur_pos > 1 then
|
if cur_pos > 1 then
|
||||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
local offset = 0
|
||||||
cur_pos = cur_pos - 1
|
if have_multibyte_char_at(command, cur_pos - 1) then
|
||||||
|
offset = 1
|
||||||
|
end
|
||||||
|
command = command:sub(1, cur_pos - 2 - offset) .. command:sub(cur_pos)
|
||||||
|
cur_pos = cur_pos - 1 - offset
|
||||||
end
|
end
|
||||||
elseif key == "Delete" then
|
elseif key == "Delete" then
|
||||||
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
command = command:sub(1, cur_pos - 1) .. command:sub(cur_pos + 1)
|
||||||
|
@ -889,22 +912,7 @@ function prompt.run(args, textbox, exe_callback, completion_callback,
|
||||||
selectall = nil
|
selectall = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local success = pcall(update)
|
update()
|
||||||
while not success do
|
|
||||||
-- TODO UGLY HACK TODO
|
|
||||||
-- Setting the text failed. Most likely reason is that the user
|
|
||||||
-- entered a multibyte character and pressed backspace which only
|
|
||||||
-- removed the last byte. Let's remove another byte.
|
|
||||||
if cur_pos <= 1 then
|
|
||||||
-- No text left?!
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
command = command:sub(1, cur_pos - 2) .. command:sub(cur_pos)
|
|
||||||
cur_pos = cur_pos - 1
|
|
||||||
success = pcall(update)
|
|
||||||
end
|
|
||||||
|
|
||||||
if changed_callback then
|
if changed_callback then
|
||||||
changed_callback(command)
|
changed_callback(command)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue