mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Terminal: add shortcuts for re-useable commands (#6609)
To be able to quickly repeat often used terminal commands
This commit is contained in:
@@ -77,7 +77,7 @@ local settingsList = {
|
||||
calibre_search = { category="none", event="CalibreSearch", title=_("Search in calibre metadata"), device=true,},
|
||||
calibre_browse_tags = { category="none", event="CalibreBrowseTags", title=_("Browse all calibre tags"), device=true,},
|
||||
calibre_browse_series = { category="none", event="CalibreBrowseSeries", title=_("Browse all calibre series"), device=true, separator=true,},
|
||||
edit_last_edited_file = { category = "none", event = "OpenLastEditedFile", title = 'Texteditor: open last file', device = true, separator = true, },
|
||||
edit_last_edited_file = { category = "none", event = "OpenLastEditedFile", title = _("Texteditor: open last file"), device = true, separator = true, },
|
||||
favorites = { category="none", event="ShowColl", arg="favorites", title=_("Favorites"), device=true,},
|
||||
|
||||
-- filemanager settings
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
local ButtonDialog = require("ui/widget/buttondialog")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local DataStorage = require("datastorage")
|
||||
local Font = require("ui/font")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local InputDialog = require("ui/widget/inputdialog")
|
||||
local LuaSettings = require("luasettings")
|
||||
local Menu = require("ui/widget/menu")
|
||||
local Screen = require("device").screen
|
||||
local T = require("ffi/util").template
|
||||
local TextViewer = require("ui/widget/textviewer")
|
||||
local Trapper = require("ui/trapper")
|
||||
local UIManager = require("ui/uimanager")
|
||||
@@ -9,49 +15,388 @@ local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local logger = require("logger")
|
||||
local util = require("ffi/util")
|
||||
local _ = require("gettext")
|
||||
local Screen = require("device").screen
|
||||
|
||||
local Terminal = WidgetContainer:new{
|
||||
name = "terminal",
|
||||
dump_file = util.realpath(DataStorage:getDataDir()) .. "/terminal_output.txt",
|
||||
command = "",
|
||||
dump_file = util.realpath(DataStorage:getDataDir()) .. "/terminal_output.txt",
|
||||
items_per_page = G_reader_settings:readSetting("items_per_page") or 16,
|
||||
settings = LuaSettings:open(DataStorage:getSettingsDir() .. "/terminal_shortcuts.lua"),
|
||||
shortcuts_dialog = nil,
|
||||
shortcuts_menu = nil,
|
||||
-- shortcuts_file = DataStorage:getSettingsDir() .. "/terminal_shortcuts.lua",
|
||||
shortcuts = {},
|
||||
source = "terminal",
|
||||
}
|
||||
|
||||
function Terminal:init()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
self.shortcuts = self.settings:readSetting("shortcuts") or {}
|
||||
end
|
||||
|
||||
function Terminal:saveShortcuts()
|
||||
self.settings:saveSetting("shortcuts", self.shortcuts)
|
||||
self.settings:flush()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Shortcuts saved"),
|
||||
timeout = 2
|
||||
})
|
||||
end
|
||||
|
||||
function Terminal:manageShortcuts()
|
||||
self.shortcuts_dialog = CenterContainer:new {
|
||||
dimen = Screen:getSize(),
|
||||
}
|
||||
self.shortcuts_menu = Menu:new{
|
||||
show_parent = self.ui,
|
||||
width = Screen:getWidth(),
|
||||
height = Screen:getHeight(),
|
||||
covers_fullscreen = true, -- hint for UIManager:_repaint()
|
||||
is_borderless = true,
|
||||
is_popout = false,
|
||||
perpage = self.items_per_page,
|
||||
onMenuHold = self.onMenuHoldShortcuts,
|
||||
_manager = self,
|
||||
}
|
||||
table.insert(self.shortcuts_dialog, self.shortcuts_menu)
|
||||
self.shortcuts_menu.close_callback = function()
|
||||
UIManager:close(self.shortcuts_dialog)
|
||||
end
|
||||
|
||||
-- sort the shortcuts:
|
||||
if #self.shortcuts > 0 then
|
||||
table.sort(self.shortcuts, function(v1, v2)
|
||||
return v1.text < v2.text
|
||||
end)
|
||||
end
|
||||
self:updateItemTable()
|
||||
end
|
||||
|
||||
function Terminal:updateItemTable()
|
||||
local item_table = {}
|
||||
if #self.shortcuts > 0 then
|
||||
local actions_count = 3 -- separator + actions
|
||||
for nr, f in ipairs(self.shortcuts) do
|
||||
local item = {
|
||||
nr = nr,
|
||||
text = f.text,
|
||||
commands = f.commands,
|
||||
editable = true,
|
||||
deletable = true,
|
||||
callback = function()
|
||||
-- so we know which middle button to display in the results:
|
||||
self.source = "shortcut"
|
||||
-- execute immediately, skip terminal dialog:
|
||||
self.command = self:ensureWhitelineAfterCommands(f.commands)
|
||||
Trapper:wrap(function()
|
||||
self:execute()
|
||||
end)
|
||||
end
|
||||
}
|
||||
table.insert(item_table, item)
|
||||
-- add page actions at end of each page with shortcuts:
|
||||
local factor = self.items_per_page - actions_count
|
||||
if nr % factor == 0 or nr == #self.shortcuts then
|
||||
-- insert "separator":
|
||||
table.insert(item_table, {
|
||||
text = " ",
|
||||
deletable = false,
|
||||
editable = false,
|
||||
callback = function()
|
||||
self:manageShortcuts()
|
||||
end,
|
||||
})
|
||||
-- actions:
|
||||
self:insertPageActions(item_table)
|
||||
end
|
||||
end
|
||||
-- no shortcuts defined yet:
|
||||
else
|
||||
self:insertPageActions(item_table)
|
||||
end
|
||||
local title = #self.shortcuts == 1 and _("Terminal shortcut") or _("Terminal shortcuts")
|
||||
self.shortcuts_menu:switchItemTable(tostring(#self.shortcuts) .. " " .. title, item_table)
|
||||
UIManager:show(self.shortcuts_dialog)
|
||||
end
|
||||
|
||||
function Terminal:insertPageActions(item_table)
|
||||
table.insert(item_table, {
|
||||
text = " " .. _("to terminal…"),
|
||||
deletable = false,
|
||||
editable = false,
|
||||
callback = function()
|
||||
self:terminal()
|
||||
end,
|
||||
})
|
||||
table.insert(item_table, {
|
||||
text = " " .. _("close…"),
|
||||
deletable = false,
|
||||
editable = false,
|
||||
callback = function()
|
||||
return false
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
||||
function Terminal:onMenuHoldShortcuts(item)
|
||||
if item.deletable or item.editable then
|
||||
local shortcut_shortcuts_dialog
|
||||
shortcut_shortcuts_dialog = ButtonDialog:new{
|
||||
buttons = {{
|
||||
{
|
||||
text = _("Edit name"),
|
||||
enabled = item.editable,
|
||||
callback = function()
|
||||
UIManager:close(shortcut_shortcuts_dialog)
|
||||
if self._manager.shortcuts_dialog ~= nil then
|
||||
UIManager:close(self._manager.shortcuts_dialog)
|
||||
self._manager.shortcuts_dialog = nil
|
||||
end
|
||||
self._manager:editName(item)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Edit commands"),
|
||||
enabled = item.editable,
|
||||
callback = function()
|
||||
UIManager:close(shortcut_shortcuts_dialog)
|
||||
if self._manager.shortcuts_dialog ~= nil then
|
||||
UIManager:close(self._manager.shortcuts_dialog)
|
||||
self._manager.shortcuts_dialog = nil
|
||||
end
|
||||
self._manager:editCommands(item)
|
||||
end
|
||||
},
|
||||
},
|
||||
{
|
||||
{
|
||||
text = _("Copy"),
|
||||
enabled = item.editable,
|
||||
callback = function()
|
||||
UIManager:close(shortcut_shortcuts_dialog)
|
||||
if self._manager.shortcuts_dialog ~= nil then
|
||||
UIManager:close(self._manager.shortcuts_dialog)
|
||||
self._manager.shortcuts_dialog = nil
|
||||
end
|
||||
self._manager:copyCommands(item)
|
||||
end
|
||||
},
|
||||
{
|
||||
text = _("Delete"),
|
||||
enabled = item.deletable,
|
||||
callback = function()
|
||||
UIManager:close(shortcut_shortcuts_dialog)
|
||||
if self._manager.shortcuts_dialog ~= nil then
|
||||
UIManager:close(self._manager.shortcuts_dialog)
|
||||
self._manager.shortcuts_dialog = nil
|
||||
end
|
||||
self._manager:deleteShortcut(item)
|
||||
end
|
||||
}
|
||||
}}
|
||||
}
|
||||
UIManager:show(shortcut_shortcuts_dialog)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function Terminal:copyCommands(item)
|
||||
local new_item = {
|
||||
text = item.text .. " (copy)",
|
||||
commands = item.commands
|
||||
}
|
||||
table.insert(self.shortcuts, new_item)
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = _("Shortcut copied"),
|
||||
timeout = 2
|
||||
})
|
||||
self:saveShortcuts()
|
||||
self:manageShortcuts()
|
||||
end
|
||||
|
||||
function Terminal:editCommands(item)
|
||||
local edit_dialog
|
||||
edit_dialog = InputDialog:new{
|
||||
title = T(_('Edit commands for "%1"'), item.text),
|
||||
input = item.commands,
|
||||
width = Screen:getWidth() * 0.9,
|
||||
para_direction_rtl = false, -- force LTR
|
||||
input_type = "string",
|
||||
allow_newline = true,
|
||||
cursor_at_end = true,
|
||||
fullscreen = true,
|
||||
buttons = {{{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(edit_dialog)
|
||||
edit_dialog = nil
|
||||
self:manageShortcuts()
|
||||
end,
|
||||
}, {
|
||||
text = _("Save"),
|
||||
callback = function()
|
||||
local input = edit_dialog:getInputText()
|
||||
UIManager:close(edit_dialog)
|
||||
edit_dialog = nil
|
||||
if input:match("[A-Za-z]") then
|
||||
self.shortcuts[item.nr]["commands"] = input
|
||||
self:saveShortcuts()
|
||||
self:manageShortcuts()
|
||||
end
|
||||
end,
|
||||
}}},
|
||||
}
|
||||
UIManager:show(edit_dialog)
|
||||
edit_dialog:onShowKeyboard()
|
||||
end
|
||||
|
||||
function Terminal:editName(item)
|
||||
local edit_dialog
|
||||
edit_dialog = InputDialog:new{
|
||||
title = _("Edit name"),
|
||||
input = item.text,
|
||||
width = Screen:getWidth() * 0.9,
|
||||
para_direction_rtl = false, -- force LTR
|
||||
input_type = "string",
|
||||
allow_newline = false,
|
||||
cursor_at_end = true,
|
||||
fullscreen = true,
|
||||
buttons = {{{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(edit_dialog)
|
||||
edit_dialog = nil
|
||||
self:manageShortcuts()
|
||||
end,
|
||||
}, {
|
||||
text = _("Save"),
|
||||
callback = function()
|
||||
local input = edit_dialog:getInputText()
|
||||
UIManager:close(edit_dialog)
|
||||
edit_dialog = nil
|
||||
if input:match("[A-Za-z]") then
|
||||
self.shortcuts[item.nr]["text"] = input
|
||||
self:saveShortcuts()
|
||||
self:manageShortcuts()
|
||||
end
|
||||
end,
|
||||
}}},
|
||||
}
|
||||
UIManager:show(edit_dialog)
|
||||
edit_dialog:onShowKeyboard()
|
||||
end
|
||||
|
||||
function Terminal:deleteShortcut(item)
|
||||
local shortcuts = {}
|
||||
for _, element in ipairs(self.shortcuts) do
|
||||
if element.text ~= item.text and element.commands ~= item.commands then
|
||||
table.insert(shortcuts, element)
|
||||
end
|
||||
end
|
||||
self.shortcuts = shortcuts
|
||||
self:saveShortcuts()
|
||||
self:manageShortcuts()
|
||||
end
|
||||
|
||||
function Terminal:onTerminalStart()
|
||||
-- if shortcut commands are defined, go directly to the the shortcuts manager (so we can execute scripts more quickly):
|
||||
if #self.shortcuts == 0 then
|
||||
self:terminal()
|
||||
else
|
||||
self:manageShortcuts()
|
||||
end
|
||||
end
|
||||
|
||||
function Terminal:terminal()
|
||||
self.input = InputDialog:new{
|
||||
title = _("Enter a command and press \"Execute\""),
|
||||
input = self.command,
|
||||
title = _("Enter a command and press \"Execute\""),
|
||||
input = self.command:gsub("\n+$", ""),
|
||||
para_direction_rtl = false, -- force LTR
|
||||
text_height = math.floor(Screen:getHeight() * 0.4),
|
||||
input_type = "string",
|
||||
-- allow multiple lines with commands:
|
||||
allow_newline = true,
|
||||
cursor_at_end = true,
|
||||
fullscreen = true,
|
||||
buttons = {{{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(self.input)
|
||||
end,
|
||||
}, {
|
||||
text = _("Execute"),
|
||||
callback = function()
|
||||
UIManager:close(self.input)
|
||||
Trapper:wrap(function()
|
||||
self:execute()
|
||||
end)
|
||||
end,
|
||||
}}},
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(self.input)
|
||||
end,
|
||||
}, {
|
||||
text = _("Shortcuts"),
|
||||
callback = function()
|
||||
UIManager:close(self.input)
|
||||
self:manageShortcuts()
|
||||
end,
|
||||
}, {
|
||||
text = _("Save"),
|
||||
callback = function()
|
||||
local input = self.input:getInputText()
|
||||
if input:match("[A-Za-z]") then
|
||||
|
||||
local function callback(name)
|
||||
local new_shortcut = {
|
||||
text = name,
|
||||
commands = input,
|
||||
}
|
||||
table.insert(self.shortcuts, new_shortcut)
|
||||
self:saveShortcuts()
|
||||
end
|
||||
|
||||
local prompt
|
||||
prompt = InputDialog:new{
|
||||
title = _("Name"),
|
||||
input = "",
|
||||
input_type = "text",
|
||||
fullscreen = true,
|
||||
condensed = true,
|
||||
allow_newline = false,
|
||||
cursor_at_end = true,
|
||||
buttons = {{{
|
||||
text = _("Cancel"),
|
||||
callback = function()
|
||||
UIManager:close(prompt)
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Save"),
|
||||
is_enter_default = true,
|
||||
callback = function()
|
||||
local newval = prompt:getInputText()
|
||||
UIManager:close(prompt)
|
||||
callback(newval)
|
||||
end,
|
||||
}}}
|
||||
}
|
||||
UIManager:show(prompt)
|
||||
prompt:onShowKeyboard()
|
||||
end
|
||||
end,
|
||||
}, {
|
||||
text = _("Execute"),
|
||||
callback = function()
|
||||
UIManager:close(self.input)
|
||||
-- so we know which middle button to display in the results:
|
||||
self.source = "terminal"
|
||||
self.command = self:ensureWhitelineAfterCommands(self.input:getInputText())
|
||||
Trapper:wrap(function()
|
||||
self:execute()
|
||||
end)
|
||||
end,
|
||||
}}},
|
||||
}
|
||||
UIManager:show(self.input)
|
||||
self.input:onShowKeyboard()
|
||||
end
|
||||
|
||||
-- for prettier formatting of output by separating commands and result thereof with a whiteline:
|
||||
function Terminal:ensureWhitelineAfterCommands(commands)
|
||||
if string.sub(commands, -1) ~= "\n" then
|
||||
commands = commands .. "\n"
|
||||
end
|
||||
return commands
|
||||
end
|
||||
|
||||
function Terminal:execute()
|
||||
self.command = self.input:getInputText()
|
||||
local wait_msg = InfoMessage:new{
|
||||
text = _("Executing…"),
|
||||
}
|
||||
@@ -69,29 +414,61 @@ function Terminal:execute()
|
||||
end
|
||||
UIManager:close(wait_msg)
|
||||
local viewer
|
||||
viewer = TextViewer:new {
|
||||
local buttons_table
|
||||
local back_button = {
|
||||
text = _("Back"),
|
||||
callback = function()
|
||||
UIManager:close(viewer)
|
||||
if self.source == "terminal" then
|
||||
self:terminal()
|
||||
else
|
||||
self:manageShortcuts()
|
||||
end
|
||||
end,
|
||||
}
|
||||
local close_button = {
|
||||
text = _("Close"),
|
||||
callback = function()
|
||||
UIManager:close(viewer)
|
||||
end,
|
||||
}
|
||||
if self.source == "terminal" then
|
||||
buttons_table = {
|
||||
{
|
||||
back_button,
|
||||
{
|
||||
text = _("Shortcuts"),
|
||||
-- switch to shortcuts:
|
||||
callback = function()
|
||||
UIManager:close(viewer)
|
||||
self:manageShortcuts()
|
||||
end,
|
||||
},
|
||||
close_button,
|
||||
},
|
||||
}
|
||||
else
|
||||
buttons_table = {
|
||||
{
|
||||
back_button,
|
||||
{
|
||||
text = _("Terminal"),
|
||||
-- switch to terminal:
|
||||
callback = function()
|
||||
UIManager:close(viewer)
|
||||
self:terminal()
|
||||
end,
|
||||
},
|
||||
close_button,
|
||||
},
|
||||
}
|
||||
end
|
||||
viewer = TextViewer:new{
|
||||
title = _("Command output"),
|
||||
text = table.concat(entries, "\n"),
|
||||
justified = false,
|
||||
text_face = Font:getFace("smallinfont"),
|
||||
-- support re-invoking the terminal with a button:
|
||||
buttons_table = {
|
||||
{
|
||||
{
|
||||
text = _("Back"),
|
||||
callback = function()
|
||||
UIManager:close(viewer)
|
||||
self:onTerminalStart()
|
||||
end,
|
||||
},
|
||||
{
|
||||
text = _("Close"),
|
||||
callback = function()
|
||||
UIManager:close(viewer)
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
buttons_table = buttons_table,
|
||||
}
|
||||
UIManager:show(viewer)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user