From 7b822746d3c662170699872265f8345355d14253 Mon Sep 17 00:00:00 2001 From: Joppe Blondel Date: Thu, 23 Oct 2025 21:27:46 +0200 Subject: [PATCH] Added toolbar with start and stop button --- .gitignore | 1 + .lite_project.lua | 2 +- init.lua | 114 +++++++++++++++++++++++++++++++++++++------ runners/shell.lua | 26 ++++++++++ test.lua | 5 +- toolbar_commands.ttf | Bin 0 -> 6532 bytes 6 files changed, 131 insertions(+), 17 deletions(-) create mode 100644 .gitignore create mode 100644 toolbar_commands.ttf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b987d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +logs.txt diff --git a/.lite_project.lua b/.lite_project.lua index e0f6d3c..3a629b2 100644 --- a/.lite_project.lua +++ b/.lite_project.lua @@ -9,7 +9,7 @@ config.plugins.jpdebug = { ["test"] = { type = "shell", cmd = {"lua", "test.lua"} - } + } }, default_target = "test" } diff --git a/init.lua b/init.lua index dde8cb6..ac5bc9e 100644 --- a/init.lua +++ b/init.lua @@ -5,6 +5,8 @@ local command = require "core.command" local View = require "core.view" local process = require "process" local config = require "core.config" +local TreeView = require "plugins.treeview" +local ToolbarView = require "plugins.toolbarview" core.jpdebug = core.jpdebug or {} @@ -13,16 +15,28 @@ core.jpdebug.runners = core.jpdebug.runners or {} local runner_shell = require("plugins.jpdebug.runners.shell") core.jpdebug.runners[runner_shell.name] = runner_shell --- A list of created views -local active_views = {} +-- Currently used view +local active_view = nil -- The selected target local selected_target = nil --- Local helper functions for debugging -------------------------- +-- The running system +local running_proc = nil +local running_runner = nil + +-- Check if required plugins are installed +local required_toolbar_plugins = true +if TreeView == nil or ToolbarView == nil then + required_toolbar_plugins = false +end + +-- Local helper functions ---------------------------------------- + ---@diagnostic disable-next-line: unused-function -local function dump(o) - if type(o) == 'table' then +local function dump(o, force) + force = force or false + if type(o) == 'table' or force then local s = '{ ' for k,v in pairs(o) do if type(k) ~= 'number' then k = '"'..k..'"' end @@ -30,10 +44,23 @@ local function dump(o) end return s .. '} ' else - return tostring(o) + return type(o)..": "..tostring(o) end end +local function get_plugin_directory() + local paths = { + USERDIR .. PATHSEP .. "plugins" .. PATHSEP .. "jpdebug", + DATADIR .. PATHSEP .. "plugins" .. PATHSEP .. "jpdebug" + } + for i, v in ipairs(paths) do + if system.get_file_info(v) then + return v + end + end + return nil +end + -- ---------- JPDebugView: a simple scrollable log view ---------- ---@class JPDebugView : core.view local JPDebugView = View:extend() @@ -94,6 +121,11 @@ function JPDebugView:draw() self:draw_scrollbar() end +function JPDebugView:try_close(do_close) + JPDebugView.super.try_close(self, do_close) + active_view = nil +end + -- ---------- helper: pick a target from project module ---------- local function get_targets() local t = (config.plugins and config.plugins.jpdebug and config.plugins.jpdebug.targets) or {} @@ -110,28 +142,29 @@ local function run_target(target, name) local title = ("JP Debug: %s"):format(name) local view = nil - if active_views[title] then + if active_view then -- If there is already a view use that one - view = active_views[title] + view = active_view else -- Otherwhise lets make one view = JPDebugView(title) core.root_view:get_active_node():add_view(view) - active_views[title] = view + active_view = view end -- Check if we have a runner for runner_name,runner in pairs(core.jpdebug.runners) do if runner_name == target.type then -- Found a runner - local proc = runner:run(target.cmd, { + running_proc = runner:run(target.cmd, { cwd = target.cwd or ".", env = target.env or {}, stdout = process.REDIRECT_PIPE, stderr = process.REDIRECT_PIPE }, name) + running_runner = runner - if proc == nil then + if running_proc == nil then core.error("[jpdebug] Could not run the target") return end @@ -141,19 +174,24 @@ local function run_target(target, name) core.add_thread(function() while true do coroutine.yield(0.016) -- ~60fps - local out = proc:read_stdout() + if running_proc == nil then + return + end + local out = running_proc:read_stdout() if out == nil then -- stdout pipe closed: try drain stderr and break when both closed - local err = proc:read_stderr() + local err = runner:read_stderr(running_proc) if err ~= nil and err ~= "" then view:push("stderr", err) end break end if out ~= "" then view:push("stdout", out) end - local err = proc:read_stderr() + local err = runner:read_stderr(running_proc) if err ~= nil and err ~= "" then view:push("stderr", err) end end - local code = proc:wait(process.WAIT_INFINITE) + local code = runner:wait(process.WAIT_INFINITE) view:push("stdout", ("\n[exit] code=%s\n"):format(tostring(code))) + running_proc = nil + running_runner = nil end) return view @@ -163,6 +201,39 @@ local function run_target(target, name) core.error("[jpdebug] No suitable runners found for target %s", name) end +-- ---------- Add toolbar to treeview if plugins are installed ------ +if required_toolbar_plugins then + + ---@class Toolbar: core.view + local Toolbar = ToolbarView:extend() + function Toolbar:new() + Toolbar.super.new(self) + self.toolbar_font = renderer.font.load(get_plugin_directory() .. PATHSEP .. "toolbar_commands.ttf", style.icon_big_font:get_size()) + self.toolbar_commands = {} + end + + function Toolbar:_rebuild() + local t = { + {symbol = "A", command = "jpdebug:settarget"}, + } + if running_proc == nil then + table.insert(t, {symbol = "B", command = "jpdebug:run"}) + else + table.insert(t, {symbol = "D", command = "jpdebug:stop"}) + end + self.toolbar_commands = t + end + + function Toolbar:update() + Toolbar.super.update(self) + self:_rebuild() + end + + local toolbar_view = Toolbar() + local toolbar_node = TreeView.node.b:split("up", toolbar_view, {y = true}) + +end + ---@diagnostic disable-next-line: param-type-mismatch command.add(nil, { @@ -184,6 +255,18 @@ command.add(nil, { end end, + ["jpdebug:stop"] = function() + core.log(dump(running_proc)) + running_proc:kill() + running_runner:kill(running_proc) + core.log("[jpdebug] Stopped runner") + if active_view then + active_view:push("stdout", " ... Stopped") + end + running_proc = nil + running_runner = nil + end, + -- The set target command ["jpdebug:settarget"] = function() core.command_view:enter("Select target", { @@ -204,5 +287,6 @@ command.add(nil, { end }) end, + }) diff --git a/runners/shell.lua b/runners/shell.lua index 5622ed3..617282e 100644 --- a/runners/shell.lua +++ b/runners/shell.lua @@ -6,6 +6,7 @@ local M = { name = "shell" } +-- Run a shell command function M:run(cmd, opts, name) core.log("[jpdebug] Running shell command") if cmd then @@ -16,5 +17,30 @@ function M:run(cmd, opts, name) end end +-- Wait untill it ends, possibly with timeout +function M:wait(proc, time) + return proc:wait(time) +end + +-- Read the stdout, returns nil if process has stopped +function M:read_stdout(proc) + return proc:read_stdout() +end + +-- Read the stderr +function M:read_stderr(proc) + return proc:read_stderr() +end + +-- Kill the process +function M:kill(proc) + proc:kill() +end + +-- Terminate the process +function M:terminate(proc) + proc:terminate() +end + return M diff --git a/test.lua b/test.lua index 6d72ab0..677bb2a 100644 --- a/test.lua +++ b/test.lua @@ -1,5 +1,8 @@ +local socket = require 'socket' + print("Starting loop: test 123") -for i = 1, 4 do +for i = 1,100 do + socket.sleep(0.5) print("i =", i) -- we'll stop here end print("Yaaayyyy it works perfectly fine :)") diff --git a/toolbar_commands.ttf b/toolbar_commands.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9e5b30bf9674e3e2eca0d4c67a8829166f59d679 GIT binary patch literal 6532 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 literal 0 HcmV?d00001