local DataStorage = require("datastorage") local Font = require("ui/font") local InfoMessage = require("ui/widget/infomessage") local InputDialog = require("ui/widget/inputdialog") local TextViewer = require("ui/widget/textviewer") local Trapper = require("ui/trapper") local UIManager = require("ui/uimanager") 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 = "", } function Terminal:init() self.ui.menu:registerToMainMenu(self) end function Terminal:start() self.input = InputDialog:new{ title = _("Enter a command and press \"Execute\""), input = self.command, para_direction_rtl = false, -- force LTR text_height = math.floor(Screen:getHeight() * 0.4), input_type = "string", buttons = {{{ text = _("Cancel"), callback = function() UIManager:close(self.input) end, }, { text = _("Execute"), is_enter_default = true, callback = function() UIManager:close(self.input) Trapper:wrap(function() self:execute() end) end, }}}, } UIManager:show(self.input) self.input:onShowKeyboard() end function Terminal:execute() self.command = self.input:getInputText() local wait_msg = InfoMessage:new{ text = _("Executing…"), } UIManager:show(wait_msg) local entries = { self.command } local command = self.command .. " 2>&1 ; echo" -- ensure we get stderr and output something local completed, result_str = Trapper:dismissablePopen(command, wait_msg) if completed then table.insert(entries, result_str) self:dump(entries) table.insert(entries, _("Output was also written to")) table.insert(entries, self.dump_file) else table.insert(entries, _("Execution canceled.")) end UIManager:close(wait_msg) UIManager:show(TextViewer:new{ title = _("Command output"), text = table.concat(entries, "\n"), justified = false, text_face = Font:getFace("smallinfont"), }) end function Terminal:dump(entries) local content = table.concat(entries, "\n") local file = io.open(self.dump_file, "w") if file then file:write(content) file:close() else logger.warn("Failed to dump terminal output " .. content .. " to " .. self.dump_file) end end function Terminal:addToMainMenu(menu_items) menu_items.terminal = { text = _("Terminal emulator"), keep_menu_open = true, callback = function() self:start() end, } end return Terminal