summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2026-02-01 01:51:20 -0800
committerDavid Vazgenovich Shakaryan <dvshakaryan@gmail.com>2026-02-01 01:51:20 -0800
commitf7e64e9c6a7dd22d16ac15adf4f86714b5b993ef (patch)
tree413416e8cbddd082c158161d2e482753fb442a6d
parent925aa695b437325d48abc484f2769c6787ebf3f5 (diff)
downloadmpv-iptv-menu-f7e64e9c6a7dd22d16ac15adf4f86714b5b993ef.tar.gz
mpv-iptv-menu-f7e64e9c6a7dd22d16ac15adf4f86714b5b993ef.tar.xz
add readline-style text manipulation
-rw-r--r--main.lua30
-rw-r--r--rt.lua126
-rw-r--r--state.lua3
3 files changed, 140 insertions, 19 deletions
diff --git a/main.lua b/main.lua
index dd046de..6a7974a 100644
--- a/main.lua
+++ b/main.lua
@@ -176,16 +176,34 @@ input.define_mapping('MENU', {
},
})
input.define_mapping('SEARCH', {
- ['ANY_UNICODE'] = {rt.search_input_char, 'complex'},
- ['BS'] = {rt.search_input_bs, 'repeat'},
- ['DEL'] = {rt.search_input_del, 'repeat'},
-
['ENTER'] = {rt.end_search},
['ESC'] = {rt.cancel_search},
['Ctrl+c'] = {rt.cancel_search},
- ['LEFT'] = {rt.search_cursor_left, 'repeat'},
- ['RIGHT'] = {rt.search_cursor_right, 'repeat'},
+ ['ANY_UNICODE'] = {rt.search_text_insert_char, 'complex'},
+ ['BS'] = {rt.search_text_del_prev_char, 'repeat'},
+ ['DEL'] = {rt.search_text_del_next_char, 'repeat'},
+ ['Alt+BS'] = {rt.search_text_del_prev_word, 'repeat'},
+ ['Alt+DEL'] = {rt.search_text_del_next_word, 'repeat'},
+ ['Ctrl+h'] = {rt.search_text_del_prev_char, 'repeat'},
+ ['Ctrl+d'] = {rt.search_text_del_next_char, 'repeat'},
+ ['Ctrl+w'] = {rt.search_text_del_prev_word, 'repeat'},
+ ['Alt+d'] = {rt.search_text_del_next_word, 'repeat'},
+ ['Ctrl+u'] = {rt.search_text_del_to_start},
+ ['Ctrl+k'] = {rt.search_text_del_to_end},
+ ['Ctrl+t'] = {rt.search_text_transpose_chars, 'repeat'},
+ ['Alt+t'] = {rt.search_text_transpose_words, 'repeat'},
+
+ ['LEFT'] = {rt.search_cursor_prev_char, 'repeat'},
+ ['RIGHT'] = {rt.search_cursor_next_char, 'repeat'},
+ ['Alt+LEFT'] = {rt.search_cursor_prev_word, 'repeat'},
+ ['Alt+RIGHT'] = {rt.search_cursor_next_word, 'repeat'},
+ ['Ctrl+b'] = {rt.search_cursor_prev_char, 'repeat'},
+ ['Ctrl+f'] = {rt.search_cursor_next_char, 'repeat'},
+ ['Alt+b'] = {rt.search_cursor_prev_word, 'repeat'},
+ ['Alt+f'] = {rt.search_cursor_next_word, 'repeat'},
+ ['HOME'] = {rt.search_cursor_start},
+ ['END'] = {rt.search_cursor_end},
['Ctrl+a'] = {rt.search_cursor_start},
['Ctrl+e'] = {rt.search_cursor_end},
diff --git a/rt.lua b/rt.lua
index 502cf83..da6c238 100644
--- a/rt.lua
+++ b/rt.lua
@@ -535,7 +535,7 @@ function rt.open_option_info(opt)
end
end
-function rt.search_input_char(ev)
+function rt.search_text_insert_char(ev)
if ev.event ~= 'down' and ev.event ~= 'repeat' then
return
end
@@ -543,13 +543,13 @@ function rt.search_input_char(ev)
local menu = state:menu()
menu:set_search_text(
menu.search_text:sub(1, menu.search_cursor - 1) ..
- ev.key_text ..
- menu.search_text:sub(menu.search_cursor))
- menu:set_search_cursor(menu.search_cursor + #ev.key_text)
+ ev.key_text ..
+ menu.search_text:sub(menu.search_cursor),
+ menu.search_cursor + #ev.key_text)
osd:dirty()
end
-function rt.search_input_bs()
+function rt.search_text_del_prev_char()
local menu = state:menu()
if menu.search_cursor <= 1 then
return
@@ -558,12 +558,12 @@ function rt.search_input_bs()
local pos = util.utf8_seek(menu.search_text, menu.search_cursor, -1)
menu:set_search_text(
menu.search_text:sub(1, pos - 1) ..
- menu.search_text:sub(menu.search_cursor))
- menu:set_search_cursor(pos)
+ menu.search_text:sub(menu.search_cursor),
+ pos)
osd:dirty()
end
-function rt.search_input_del()
+function rt.search_text_del_next_char()
local menu = state:menu()
if menu.search_cursor > #menu.search_text then
return
@@ -571,8 +571,97 @@ function rt.search_input_del()
menu:set_search_text(
menu.search_text:sub(1, menu.search_cursor - 1) ..
- menu.search_text:sub(util.utf8_seek(
- menu.search_text, menu.search_cursor, 1)))
+ menu.search_text:sub(util.utf8_seek(
+ menu.search_text, menu.search_cursor, 1)))
+ osd:dirty()
+end
+
+function rt.search_text_del_prev_word()
+ local menu = state:menu()
+ if menu.search_cursor <= 1 then
+ return
+ end
+
+ local pos = menu.search_text:sub(1, menu.search_cursor - 1):match(
+ '()%S*%s*$')
+ menu:set_search_text(
+ menu.search_text:sub(1, pos - 1) ..
+ menu.search_text:sub(menu.search_cursor),
+ pos)
+ osd:dirty()
+end
+
+function rt.search_text_del_next_word()
+ local menu = state:menu()
+ if menu.search_cursor > #menu.search_text then
+ return
+ end
+
+ local pos = menu.search_text:match('%s*%S*()', menu.search_cursor)
+ menu:set_search_text(
+ menu.search_text:sub(1, menu.search_cursor - 1) ..
+ menu.search_text:sub(pos))
+ osd:dirty()
+end
+
+function rt.search_text_del_to_start()
+ local menu = state:menu()
+ if menu.search_cursor <= 1 then
+ return
+ end
+
+ menu:set_search_text(menu.search_text:sub(menu.search_cursor), 1)
+ osd:dirty()
+end
+
+function rt.search_text_del_to_end()
+ local menu = state:menu()
+ if menu.search_cursor > #menu.search_text then
+ return
+ end
+
+ menu:set_search_text(menu.search_text:sub(1, menu.search_cursor - 1))
+ osd:dirty()
+end
+
+function rt.search_text_transpose_chars()
+ local menu = state:menu()
+ if menu.search_cursor <= 1 then
+ return
+ end
+
+ local pos = util.utf8_seek(menu.search_text, menu.search_cursor, 1)
+ local cp2 = util.utf8_seek(menu.search_text, pos, -1)
+ if cp2 <= 1 then
+ return
+ end
+ local cp1 = util.utf8_seek(menu.search_text, cp2, -1)
+
+ menu:set_search_text(
+ menu.search_text:sub(1, cp1 - 1) ..
+ menu.search_text:sub(cp2, pos - 1) ..
+ menu.search_text:sub(cp1, cp2 - 1) ..
+ menu.search_text:sub(pos),
+ pos)
+ osd:dirty()
+end
+
+function rt.search_text_transpose_words()
+ local menu = state:menu()
+ if menu.search_cursor <= 1 then
+ return
+ end
+
+ local pos = menu.search_text:match('%s*%S*()', menu.search_cursor)
+ local pre, w1, sp, w2 = menu.search_text:sub(1, pos - 1):match(
+ '^(.-)(%S+)(%s+)(%S+%s*)$')
+ if not pre then
+ return
+ end
+
+ menu:set_search_text(
+ pre .. w2 .. sp .. w1 .. menu.search_text:sub(pos),
+ pos)
osd:dirty()
end
@@ -582,18 +671,31 @@ local function set_search_cursor(pos)
end
end
-function rt.search_cursor_left()
+function rt.search_cursor_prev_char()
local menu = state:menu()
set_search_cursor(util.utf8_seek(
menu.search_text, menu.search_cursor, -1))
end
-function rt.search_cursor_right()
+function rt.search_cursor_next_char()
local menu = state:menu()
set_search_cursor(util.utf8_seek(
menu.search_text, menu.search_cursor, 1))
end
+function rt.search_cursor_prev_word()
+ local menu = state:menu()
+ set_search_cursor(
+ menu.search_text:sub(1, menu.search_cursor - 1):match(
+ '()%S*%s*$'))
+end
+
+function rt.search_cursor_next_word()
+ local menu = state:menu()
+ set_search_cursor(
+ menu.search_text:match('%s*%S*()', menu.search_cursor))
+end
+
function rt.search_cursor_start()
set_search_cursor(1)
end
diff --git a/state.lua b/state.lua
index 3abb892..b5e07f5 100644
--- a/state.lua
+++ b/state.lua
@@ -201,8 +201,9 @@ function menu_mt:set_search_cursor(pos)
return true
end
-function menu_mt:set_search_text(str)
+function menu_mt:set_search_text(str, pos)
self.search_text = str
+ self:set_search_cursor(pos or self.search_cursor)
self:update_search_matches()
end