diff --git a/data/core/commands/doc.lua b/data/core/commands/doc.lua index 65c92e28..66e88eea 100644 --- a/data/core/commands/doc.lua +++ b/data/core/commands/doc.lua @@ -93,6 +93,13 @@ local function cut_or_copy(delete) system.set_clipboard(full_text) end +local function set_primary_selection(doc) + -- Doesn't work on Windows, so avoid spending time getting the text + if PLATFORM ~= "Windows" then + system.set_primary_selection(doc:get_selection_text()) + end +end + local function split_cursor(dv, direction) local new_cursors = {} local dv_translate = direction < 0 @@ -297,6 +304,15 @@ local commands = { end end, + ["doc:paste-primary-selection"] = function(dv, x, y) + if type(x) == "number" and type(y) == "number" then + set_cursor(dv, x, y, "set") + -- Workaround to avoid that a middle mouse drag starts selecting + dv.mouse_selecting = nil + end + dv.doc:text_input(system.get_primary_selection() or "") + end, + ["doc:newline"] = function(dv) for idx, line, col in dv.doc:get_selections(false, true) do local indent = dv.doc.lines[line]:match("^[\t ]*") @@ -353,6 +369,7 @@ local commands = { ["doc:select-all"] = function(dv) dv.doc:set_selection(1, 1, math.huge, math.huge) + set_primary_selection(dv.doc) -- avoid triggering DocView:scroll_to_make_visible dv.last_line1 = 1 dv.last_col1 = 1 @@ -365,6 +382,7 @@ local commands = { append_line_if_last_line(line2) dv.doc:set_selections(idx, line2 + 1, 1, line1, 1) end + set_primary_selection(dv.doc) end, ["doc:select-word"] = function(dv) @@ -373,6 +391,7 @@ local commands = { local line2, col2 = translate.end_of_word(dv.doc, line1, col1) dv.doc:set_selections(idx, line2, col2, line1, col1) end + set_primary_selection(dv.doc) end, ["doc:join-lines"] = function(dv) @@ -626,6 +645,7 @@ local commands = { local line2, col2 = dv:resolve_screen_position(x, y) dv.mouse_selecting = { line1, col1, nil } dv.doc:set_selection(line2, col2, line1, col1) + set_primary_selection(dv.doc) end, ["doc:create-cursor-previous-line"] = function(dv) @@ -696,9 +716,16 @@ local translations = { } for name, obj in pairs(translations) do - commands["doc:move-to-" .. name] = function(dv) dv.doc:move_to(obj[name:gsub("-", "_")], dv) end - commands["doc:select-to-" .. name] = function(dv) dv.doc:select_to(obj[name:gsub("-", "_")], dv) end - commands["doc:delete-to-" .. name] = function(dv) dv.doc:delete_to(obj[name:gsub("-", "_")], dv) end + commands["doc:move-to-" .. name] = function(dv) + dv.doc:move_to(obj[name:gsub("-", "_")], dv) + end + commands["doc:select-to-" .. name] = function(dv) + dv.doc:select_to(obj[name:gsub("-", "_")], dv) + set_primary_selection(dv.doc) + end + commands["doc:delete-to-" .. name] = function(dv) + dv.doc:delete_to(obj[name:gsub("-", "_")], dv) + end end commands["doc:move-to-previous-char"] = function(dv) diff --git a/data/core/keymap.lua b/data/core/keymap.lua index 9f19cfb7..844a97e9 100644 --- a/data/core/keymap.lua +++ b/data/core/keymap.lua @@ -393,6 +393,7 @@ keymap.add_direct { ["1lclick"] = "doc:set-cursor", ["2lclick"] = { "doc:set-cursor-word", "emptyview:new-doc", "tabbar:new-doc" }, ["3lclick"] = "doc:set-cursor-line", + ["mclick"] = "doc:paste-primary-selection", ["shift+left"] = "doc:select-to-previous-char", ["shift+right"] = "doc:select-to-next-char", ["shift+up"] = "doc:select-to-previous-line", diff --git a/docs/api/system.lua b/docs/api/system.lua index e7f2d2e1..55f79163 100644 --- a/docs/api/system.lua +++ b/docs/api/system.lua @@ -260,6 +260,18 @@ function system.get_clipboard() end ---@param text string function system.set_clipboard(text) end +--- +---Retrieve the text currently stored in the primary selection. +--- +---@return string +function system.get_primary_selection() end + +--- +---Set the content of the primary selection. +--- +---@param text string +function system.set_primary_selection(text) end + --- ---Get the process id of lite-xl itself. --- diff --git a/src/api/system.c b/src/api/system.c index f3af9570..7baf3eab 100644 --- a/src/api/system.c +++ b/src/api/system.c @@ -897,6 +897,28 @@ static int f_set_clipboard(lua_State *L) { } +static int f_get_primary_selection(lua_State *L) { +#if SDL_VERSION_ATLEAST(2, 26, 0) + char *text = SDL_GetPrimarySelectionText(); + if (!text) { return 0; } + lua_pushstring(L, text); + SDL_free(text); + return 1; +#else + return 0; +#endif +} + + +static int f_set_primary_selection(lua_State *L) { +#if SDL_VERSION_ATLEAST(2, 26, 0) + const char *text = luaL_checkstring(L, 1); + SDL_SetPrimarySelectionText(text); +#endif + return 0; +} + + static int f_get_process_id(lua_State *L) { #ifdef _WIN32 lua_pushinteger(L, GetCurrentProcessId()); @@ -1227,40 +1249,42 @@ static int f_setenv(lua_State* L) { static const luaL_Reg lib[] = { - { "poll_event", f_poll_event }, - { "wait_event", f_wait_event }, - { "set_cursor", f_set_cursor }, - { "set_window_title", f_set_window_title }, - { "set_window_mode", f_set_window_mode }, - { "get_window_mode", f_get_window_mode }, - { "set_window_bordered", f_set_window_bordered }, - { "set_window_hit_test", f_set_window_hit_test }, - { "get_window_size", f_get_window_size }, - { "set_window_size", f_set_window_size }, - { "set_text_input_rect", f_set_text_input_rect }, - { "clear_ime", f_clear_ime }, - { "window_has_focus", f_window_has_focus }, - { "raise_window", f_raise_window }, - { "show_fatal_error", f_show_fatal_error }, - { "rmdir", f_rmdir }, - { "chdir", f_chdir }, - { "mkdir", f_mkdir }, - { "list_dir", f_list_dir }, - { "absolute_path", f_absolute_path }, - { "get_file_info", f_get_file_info }, - { "get_clipboard", f_get_clipboard }, - { "set_clipboard", f_set_clipboard }, - { "get_process_id", f_get_process_id }, - { "get_time", f_get_time }, - { "sleep", f_sleep }, - { "exec", f_exec }, - { "fuzzy_match", f_fuzzy_match }, - { "set_window_opacity", f_set_window_opacity }, - { "load_native_plugin", f_load_native_plugin }, - { "path_compare", f_path_compare }, - { "get_fs_type", f_get_fs_type }, - { "text_input", f_text_input }, - { "setenv", f_setenv }, + { "poll_event", f_poll_event }, + { "wait_event", f_wait_event }, + { "set_cursor", f_set_cursor }, + { "set_window_title", f_set_window_title }, + { "set_window_mode", f_set_window_mode }, + { "get_window_mode", f_get_window_mode }, + { "set_window_bordered", f_set_window_bordered }, + { "set_window_hit_test", f_set_window_hit_test }, + { "get_window_size", f_get_window_size }, + { "set_window_size", f_set_window_size }, + { "set_text_input_rect", f_set_text_input_rect }, + { "clear_ime", f_clear_ime }, + { "window_has_focus", f_window_has_focus }, + { "raise_window", f_raise_window }, + { "show_fatal_error", f_show_fatal_error }, + { "rmdir", f_rmdir }, + { "chdir", f_chdir }, + { "mkdir", f_mkdir }, + { "list_dir", f_list_dir }, + { "absolute_path", f_absolute_path }, + { "get_file_info", f_get_file_info }, + { "get_clipboard", f_get_clipboard }, + { "set_clipboard", f_set_clipboard }, + { "get_primary_selection", f_get_primary_selection }, + { "set_primary_selection", f_set_primary_selection }, + { "get_process_id", f_get_process_id }, + { "get_time", f_get_time }, + { "sleep", f_sleep }, + { "exec", f_exec }, + { "fuzzy_match", f_fuzzy_match }, + { "set_window_opacity", f_set_window_opacity }, + { "load_native_plugin", f_load_native_plugin }, + { "path_compare", f_path_compare }, + { "get_fs_type", f_get_fs_type }, + { "text_input", f_text_input }, + { "setenv", f_setenv }, { NULL, NULL } };