From 5050bad8ac0a41d066d1aa5842d99acd34094690 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Sat, 4 Mar 2023 12:52:46 +0100 Subject: [PATCH 1/6] lua: Scroll large dialogs automatically --- src/auto4_base.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/auto4_base.cpp b/src/auto4_base.cpp index 388e1fa3de..043d6ad6ea 100644 --- a/src/auto4_base.cpp +++ b/src/auto4_base.cpp @@ -216,6 +216,7 @@ namespace Automation4 { wxWindow *ww = config_dialog->CreateWindow(&w); // generate actual dialog contents s->Add(ww, 0, wxALL, 5); // add contents to dialog w.SetSizerAndFit(s); + w.SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); w.CenterOnParent(); w.ShowModal(); }); From 43d65b906b69afca2ec7109e8fe10ac17513e62d Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Fri, 7 Apr 2023 18:49:09 +0200 Subject: [PATCH 2/6] Also detect fonts used in drawings in font collector --- src/font_file_lister.cpp | 8 +++++++- src/font_file_lister.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/font_file_lister.cpp b/src/font_file_lister.cpp index 813e2ca967..a98c582647 100644 --- a/src/font_file_lister.cpp +++ b/src/font_file_lister.cpp @@ -139,6 +139,8 @@ void FontCollector::ProcessDialogueLine(const AssDialogue *line, int index) { break; } case AssBlockType::DRAWING: + used_styles[style].drawing = true; + break; case AssBlockType::COMMENT: break; } @@ -146,7 +148,11 @@ void FontCollector::ProcessDialogueLine(const AssDialogue *line, int index) { } void FontCollector::ProcessChunk(std::pair const& style) { - if (style.second.chars.empty()) return; + if (style.second.chars.empty() && !style.second.drawing) return; + + if (style.second.chars.empty() && style.second.drawing) { + status_callback(fmt_tl("Font '%s' is used in a drawing, but not in any text.\n", style.first.facename), 3); + } auto res = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second.chars); diff --git a/src/font_file_lister.h b/src/font_file_lister.h index 9c7cd51ad7..82f02cca9d 100644 --- a/src/font_file_lister.h +++ b/src/font_file_lister.h @@ -127,6 +127,7 @@ class FontCollector { /// Data about where each style is used struct UsageData { std::vector chars; ///< Characters used in this style which glyphs will be needed for + bool drawing = false; ///< Whether this style is used for a drawing std::vector lines; ///< Lines on which this style is used via overrides std::vector styles; ///< ASS styles which use this style }; From 79050dfdfb26789fd6496e34f2255ccbcf4cb0e5 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Sun, 21 May 2023 20:26:20 +0200 Subject: [PATCH 3/6] lua: Fix memory leak on aegisub.cancel() --- src/auto4_lua.h | 4 ++++ src/auto4_lua_assfile.cpp | 15 +++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/auto4_lua.h b/src/auto4_lua.h index 46068173ef..787ce3a6bd 100644 --- a/src/auto4_lua.h +++ b/src/auto4_lua.h @@ -78,6 +78,8 @@ namespace Automation4 { std::deque pending_commits; /// Lines to delete once processing complete successfully std::vector> lines_to_delete; + /// Lines that were allocated here and need to be deleted if the script is cancelled. + std::vector allocated_lines; /// Create copies of all of the lines in the script info section if it /// hasn't already happened. This is done lazily, since it only needs @@ -118,6 +120,8 @@ namespace Automation4 { /// assumes a Lua representation of AssEntry on the top of the stack, and creates an AssEntry object of it static std::unique_ptr LuaToAssEntry(lua_State *L, AssFile *ass=nullptr); + std::unique_ptr LuaToTrackedAssEntry(lua_State *L); + /// @brief Signal that the script using this file is now done running /// @param set_undo If there's any uncommitted changes to the file, /// they will be automatically committed with this diff --git a/src/auto4_lua_assfile.cpp b/src/auto4_lua_assfile.cpp index 3aef3b7694..e73a48920e 100644 --- a/src/auto4_lua_assfile.cpp +++ b/src/auto4_lua_assfile.cpp @@ -328,6 +328,12 @@ namespace Automation4 { return result; } + std::unique_ptr LuaAssFile::LuaToTrackedAssEntry(lua_State *L) { + std::unique_ptr e = LuaToAssEntry(L, ass); + allocated_lines.push_back(e.get()); + return e; + } + int LuaAssFile::ObjectIndexRead(lua_State *L) { switch (lua_type(L, 2)) { @@ -453,7 +459,7 @@ namespace Automation4 { // insert CheckBounds(n); - auto e = LuaToAssEntry(L, ass); + auto e = LuaToTrackedAssEntry(L); modification_type |= modification_mask(e.get()); QueueLineForDeletion(n - 1); AssignLine(n - 1, std::move(e)); @@ -542,7 +548,7 @@ namespace Automation4 { for (int i = 1; i <= n; i++) { lua_pushvalue(L, i); - auto e = LuaToAssEntry(L, ass); + auto e = LuaToTrackedAssEntry(L); modification_type |= modification_mask(e.get()); if (lines.empty()) { @@ -586,7 +592,7 @@ namespace Automation4 { new_entries.reserve(n - 1); for (int i = 2; i <= n; i++) { lua_pushvalue(L, i); - auto e = LuaToAssEntry(L, ass); + auto e = LuaToTrackedAssEntry(L); modification_type |= modification_mask(e.get()); InsertLine(new_entries, i - 2, std::move(e)); lua_pop(L, 1); @@ -625,7 +631,7 @@ namespace Automation4 { int LuaAssFile::LuaParseKaraokeData(lua_State *L) { - auto e = LuaToAssEntry(L, ass); + auto e = LuaToTrackedAssEntry(L); auto dia = check_cast_constptr(e.get()); argcheck(L, !!dia, 1, "Subtitle line must be a dialogue line"); @@ -734,6 +740,7 @@ namespace Automation4 { void LuaAssFile::Cancel() { for (auto& line : lines_to_delete) line.release(); + for (AssEntry *line : allocated_lines) delete line; references--; if (!references) delete this; } From 42f7e53e92b5329aa802436fb4ac643eaddc136d Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 22 May 2023 09:11:46 +0200 Subject: [PATCH 4/6] lua: Don't check_stack in LuaCheckStack destructor This would cause an assertion failure in functions like lua_for_each when the given closure throws an error and thus leaves some values on the stack. This can make Aegisub crash entirely instead of just catching and reporting the error. Instead, these stack_checks can be done manually. --- libaegisub/include/libaegisub/lua/utils.h | 1 - src/auto4_lua.cpp | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libaegisub/include/libaegisub/lua/utils.h b/libaegisub/include/libaegisub/lua/utils.h index c5a65d6e44..cf55e3f4d5 100644 --- a/libaegisub/include/libaegisub/lua/utils.h +++ b/libaegisub/include/libaegisub/lua/utils.h @@ -129,7 +129,6 @@ struct LuaStackcheck { void dump(); LuaStackcheck(lua_State *L) : L(L), startstack(lua_gettop(L)) { } - ~LuaStackcheck() { check_stack(0); } }; #else struct LuaStackcheck { diff --git a/src/auto4_lua.cpp b/src/auto4_lua.cpp index 36156288bb..370a791e3b 100644 --- a/src/auto4_lua.cpp +++ b/src/auto4_lua.cpp @@ -680,6 +680,7 @@ namespace { if (lua_isnumber(L, -1) && lua_tointeger(L, -1) == 3) { lua_pop(L, 1); // just to avoid tripping the stackcheck in debug description = "Attempted to load an Automation 3 script as an Automation 4 Lua script. Automation 3 is no longer supported."; + stackcheck.check_stack(0); return; } @@ -692,6 +693,7 @@ namespace { name = GetPrettyFilename().string(); lua_pop(L, 1); + stackcheck.check_stack(0); // if we got this far, the script should be ready loaded = true; } From 7e08970b2c4e67101a1259df283554157d58bf6f Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Fri, 26 May 2023 03:04:20 +0200 Subject: [PATCH 5/6] WIP lua: Add on_change callback for dialogs --- libaegisub/common/dispatch.cpp | 11 +++ libaegisub/include/libaegisub/dispatch.h | 5 ++ src/auto4_base.cpp | 2 +- src/auto4_lua.cpp | 6 +- src/auto4_lua_dialog.cpp | 99 +++++++++++++++++++++--- src/auto4_lua_progresssink.cpp | 14 +++- 6 files changed, 119 insertions(+), 18 deletions(-) diff --git a/libaegisub/common/dispatch.cpp b/libaegisub/common/dispatch.cpp index 434195836e..da7b169f01 100644 --- a/libaegisub/common/dispatch.cpp +++ b/libaegisub/common/dispatch.cpp @@ -29,6 +29,7 @@ namespace { boost::asio::io_service *service; std::function invoke_main; std::atomic threads_running; + thread_local bool is_main_thread; class MainQueue final : public agi::dispatch::Queue { void DoInvoke(agi::dispatch::Thunk thunk) override { @@ -78,10 +79,12 @@ void Init(std::function invoke_main) { static IOServiceThreadPool thread_pool; ::service = &thread_pool.io_service; ::invoke_main = invoke_main; + ::is_main_thread = true; thread_pool.threads.reserve(std::max(4, std::thread::hardware_concurrency())); for (size_t i = 0; i < thread_pool.threads.capacity(); ++i) { thread_pool.threads.emplace_back([]{ + ::is_main_thread = false; ++threads_running; agi::util::SetThreadName("Dispatch Worker"); service->run(); @@ -123,6 +126,14 @@ void Queue::Sync(Thunk thunk) { if (e) std::rethrow_exception(e); } +void EnsureMain(Thunk thunk) { + if (::is_main_thread) { + thunk(); + } else { + Main().Sync(thunk); + } +} + Queue& Main() { static MainQueue q; return q; diff --git a/libaegisub/include/libaegisub/dispatch.h b/libaegisub/include/libaegisub/dispatch.h index d8be32fe3d..47d148afe9 100644 --- a/libaegisub/include/libaegisub/dispatch.h +++ b/libaegisub/include/libaegisub/dispatch.h @@ -41,6 +41,11 @@ namespace agi { /// Get the main queue, which runs on the GUI thread Queue& Main(); + + /// Ensure that the thunk is run on the main thread, without deadlocking + /// when already on the main thread + void EnsureMain(Thunk thunk); + /// Get the generic background queue, which runs thunks in parallel Queue& Background(); diff --git a/src/auto4_base.cpp b/src/auto4_base.cpp index ff9615c90a..b7a27b0304 100644 --- a/src/auto4_base.cpp +++ b/src/auto4_base.cpp @@ -208,7 +208,7 @@ namespace Automation4 { void ProgressSink::ShowDialog(ScriptDialog *config_dialog) { - agi::dispatch::Main().Sync([=] { + agi::dispatch::EnsureMain([=] { wxDialog w; // container dialog box w.SetExtraStyle(wxWS_EX_VALIDATE_RECURSIVELY); w.Create(bsr->GetParentWindow(), -1, to_wx(bsr->GetTitle())); diff --git a/src/auto4_lua.cpp b/src/auto4_lua.cpp index c3f60b8ca6..ca7849d2c4 100644 --- a/src/auto4_lua.cpp +++ b/src/auto4_lua.cpp @@ -128,7 +128,7 @@ namespace { const char *clipboard_get() { std::string data; - agi::dispatch::Main().Sync([&] { data = GetClipboard(); }); + agi::dispatch::EnsureMain([&] { data = GetClipboard(); }); if (data.empty()) return nullptr; return strndup(data); @@ -138,7 +138,7 @@ namespace { { bool succeeded = false; - agi::dispatch::Main().Sync([&] { + agi::dispatch::EnsureMain([&] { wxClipboard &cb = *wxTheClipboard; if (cb.Open()) { succeeded = cb.SetData(new wxTextDataObject(wxString::FromUTF8(str))); @@ -1138,7 +1138,7 @@ namespace { // config if (has_config && config_dialog) { - int results_produced = config_dialog->LuaReadBack(L); + int results_produced = config_dialog->LuaReadBack(); assert(results_produced == 1); (void) results_produced; // avoid warning on release builds // TODO, write back stored options here diff --git a/src/auto4_lua_dialog.cpp b/src/auto4_lua_dialog.cpp index 7b4b5fa0c2..d50c3e7850 100644 --- a/src/auto4_lua_dialog.cpp +++ b/src/auto4_lua_dialog.cpp @@ -141,7 +141,7 @@ namespace Automation4 { public: Label(lua_State *L) : LuaDialogControl(L), label(get_field(L, "label")) { } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { return new wxStaticText(parent, -1, to_wx(label)); } @@ -174,11 +174,12 @@ namespace Automation4 { std::string SerialiseValue() const override { return inline_string_encode(text); } void UnserialiseValue(const std::string &serialised) override { text = inline_string_decode(serialised); } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { cw = new wxTextCtrl(parent, -1, to_wx(text)); cw->SetMaxLength(0); cw->SetValidator(StringBinder(&text)); cw->SetToolTip(to_wx(hint)); + cw->Bind(wxEVT_TEXT, [=](wxCommandEvent&) { callback(); }); return cw; } @@ -204,8 +205,9 @@ namespace Automation4 { std::string SerialiseValue() const override { return inline_string_encode(color.GetHexFormatted(alpha)); } void UnserialiseValue(const std::string &serialised) override { color = inline_string_decode(serialised); } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { wxControl *cw = new ColourButton(parent, wxSize(50*width,10*height), alpha, color, ColorValidator(&color)); + cw->Bind(EVT_COLOR, [=](ValueEvent&) { callback(); }); cw->SetToolTip(to_wx(hint)); return cw; } @@ -221,10 +223,11 @@ namespace Automation4 { Textbox(lua_State *L) : Edit(L) { } // Same serialisation interface as single-line edit - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { cw = new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE, StringBinder(&text)); cw->SetMinSize(wxSize(0, 30)); cw->SetToolTip(to_wx(hint)); + cw->Bind(wxEVT_TEXT, [=](wxCommandEvent&) { callback(); }); return cw; } }; @@ -252,10 +255,12 @@ namespace Automation4 { std::string SerialiseValue() const override { return std::to_string(value); } void UnserialiseValue(const std::string &serialised) override { value = atoi(serialised.c_str()); } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { cw = new wxSpinCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, value); cw->SetValidator(wxGenericValidator(&value)); cw->SetToolTip(to_wx(hint)); + cw->Bind(wxEVT_SPINCTRL, [=](wxCommandEvent&) { callback(); }); + cw->Bind(wxEVT_TEXT, [=](wxCommandEvent&) { callback(); }); return cw; } @@ -294,17 +299,20 @@ namespace Automation4 { std::string SerialiseValue() const override { return std::to_string(value); } void UnserialiseValue(const std::string &serialised) override { value = atof(serialised.c_str()); } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { if (step > 0) { scd = new wxSpinCtrlDouble(parent, -1, "", wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, min, max, value, step); scd->SetValidator(DoubleSpinValidator(&value)); scd->SetToolTip(to_wx(hint)); + scd->Bind(wxEVT_SPINCTRLDOUBLE, [=](wxCommandEvent&) { callback(); }); + scd->Bind(wxEVT_TEXT, [=](wxCommandEvent&) { callback(); }); return scd; } DoubleValidator val(&value, min, max); cw = new wxTextCtrl(parent, -1, "", wxDefaultPosition, wxDefaultSize, 0, val); cw->SetToolTip(to_wx(hint)); + cw->Bind(wxEVT_TEXT, [=](wxCommandEvent&) { callback(); }); return cw; } @@ -332,9 +340,10 @@ namespace Automation4 { std::string SerialiseValue() const override { return inline_string_encode(value); } void UnserialiseValue(const std::string &serialised) override { value = inline_string_decode(serialised); } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { cw = new wxComboBox(parent, -1, to_wx(value), wxDefaultPosition, wxDefaultSize, to_wx(items), wxCB_READONLY, StringBinder(&value)); cw->SetToolTip(to_wx(hint)); + cw->Bind(wxEVT_COMBOBOX, [=](wxCommandEvent&) { callback(); }); return cw; } @@ -360,11 +369,12 @@ namespace Automation4 { std::string SerialiseValue() const override { return value ? "1" : "0"; } void UnserialiseValue(const std::string &serialised) override { value = serialised != "0"; } - wxControl *Create(wxWindow *parent) override { + wxControl *Create(wxWindow *parent, ChangeCallback callback) override { cw = new wxCheckBox(parent, -1, to_wx(label)); cw->SetValidator(wxGenericValidator(&value)); cw->SetToolTip(to_wx(hint)); cw->SetValue(value); + cw->Bind(wxEVT_CHECKBOX, [=](wxCommandEvent&) { callback(); }); return cw; } @@ -375,8 +385,10 @@ namespace Automation4 { } // LuaDialog - LuaDialog::LuaDialog(lua_State *L, bool include_buttons) + LuaDialog::LuaDialog(lua_State *L, bool include_buttons, ErrorLogger logger) : use_buttons(include_buttons) + , L(L) + , error_logger(logger) { LOG_D("automation/lua/dialog") << "creating LuaDialoug, addr: " << this; @@ -384,6 +396,9 @@ namespace Automation4 { if (!lua_istable(L, 1)) error(L, "Cannot create config dialog from something non-table"); + lua_createtable(L, 0, 1); + myid = luaL_ref(L, LUA_REGISTRYINDEX); + // Ok, so there is a table with controls lua_pushvalue(L, 1); lua_for_each(L, [&] { @@ -442,14 +457,75 @@ namespace Automation4 { btn->first = id; }); } + + if (include_buttons && lua_istable(L, 4)) { + lua_pushvalue(L, 4); + lua_for_each(L, [&]{ + std::string key = check_string(L, -2); + if (key == "on_change") { + if (!lua_isfunction(L, -1)) + error(L, "The dialog change callback must be a function"); + + lua_rawgeti(L, LUA_REGISTRYINDEX, myid); + lua_pushvalue(L, -2); + lua_setfield(L, -2, "dialog_change_callback"); + lua_pop(L, 1); + has_callback = true; + } + // Don't error on invalid keys to be somewhat forward-compatible + }); + } + } + + LuaDialog::~LuaDialog() { + luaL_unref(L, LUA_REGISTRYINDEX, myid); } wxWindow* LuaDialog::CreateWindow(wxWindow *parent) { + auto dialog = static_cast(parent); window = new wxPanel(parent); + // Some hacks to prevent false positive events when first showing the dialog + window->Bind(wxEVT_ENTER_WINDOW, [&, this](wxEvent&) { this->can_call_callback = true; }); + window->Bind(wxEVT_MOTION, [&, this](wxEvent&) { this->can_call_callback = true; }); + LuaDialogControl::ChangeCallback cb = [&, dialog, this] { + if (has_callback && can_call_callback) { + LuaStackcheck stackcheck(L); + + window->TransferDataFromWindow(); + + lua_pushcclosure(L, add_stack_trace, 0); + + lua_rawgeti(L, LUA_REGISTRYINDEX, myid); + lua_getfield(L, -1, "dialog_change_callback"); + lua_remove(L, -2); + assert(lua_isfunction(L, -1)); + + LuaReadBack(); + lua_remove(L, -2); // Remove button + + if (lua_pcall(L, 1, 0, -3)) { + if (!lua_isnil(L, -1) && error_logger != nullptr) { + // if the call failed, log the error here + error_logger("\n\nLua reported a runtime error in dialog change callback:\n", false); + error_logger(get_string_or_default(L, -1), false); + } else { // Cancel + error_logger("", true); + dialog->EndModal(0); + } + lua_pop(L, 2); + return; + } + + lua_pop(L, 1); // pop error handler again + + stackcheck.check_stack(0); + } + }; + auto s = new wxGridBagSizer(4, 4); for (auto& c : controls) - s->Add(c->Create(window), wxGBPosition(c->y, c->x), + s->Add(c->Create(window, cb), wxGBPosition(c->y, c->x), wxGBSpan(c->height, c->width), c->GetSizerFlags()); if (!use_buttons) { @@ -462,7 +538,6 @@ namespace Automation4 { buttons.emplace_back(wxID_CANCEL, ""); } - auto dialog = static_cast(parent); auto bs = new wxStdDialogButtonSizer; auto make_button = [&](wxWindowID id, int button_pushed, std::string const& text) -> wxButton *{ @@ -502,7 +577,7 @@ namespace Automation4 { return window; } - int LuaDialog::LuaReadBack(lua_State *L) { + int LuaDialog::LuaReadBack() { // First read back which button was pressed, if any if (use_buttons) { if (button_pushed == -1 || buttons[button_pushed].first == wxID_CANCEL) diff --git a/src/auto4_lua_progresssink.cpp b/src/auto4_lua_progresssink.cpp index 8569121311..084ca1818d 100644 --- a/src/auto4_lua_progresssink.cpp +++ b/src/auto4_lua_progresssink.cpp @@ -189,11 +189,21 @@ namespace Automation4 { { ProgressSink *ps = GetObjPointer(L, lua_upvalueindex(1)); - LuaDialog dlg(L, true); // magically creates the config dialog structure etc + bool cancelled = false; + LuaDialog dlg(L, true, [&] (std::string const& error, bool cancel) { + ps->Log(error); + cancelled = cancelled || cancel; + }); // magically creates the config dialog structure etc + ps->ShowDialog(&dlg); + if (cancelled) { + lua_pushnil(L); + throw error_tag(); + } + // more magic: puts two values on stack: button pushed and table with control results - return dlg.LuaReadBack(L); + return dlg.LuaReadBack(); } int LuaProgressSink::LuaDisplayOpenDialog(lua_State *L) From f3d6eea3b90d76b313fc297ada79b72ba174a856 Mon Sep 17 00:00:00 2001 From: arch1t3cht Date: Mon, 29 May 2023 14:43:34 +0200 Subject: [PATCH 6/6] Fix AppImage build on CI --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f55dc56bdf..f0ad7bdf92 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,7 +118,7 @@ jobs: if: startsWith(matrix.config.os, 'ubuntu-') run: | sudo apt-get update - sudo apt-get install ninja-build build-essential libx11-dev libwxgtk3.0-gtk3-dev libfreetype6-dev pkg-config libfontconfig1-dev libass-dev libasound2-dev libffms2-dev intltool libboost-all-dev + sudo apt-get install ninja-build build-essential libx11-dev libwxgtk3.0-gtk3-dev libfreetype6-dev pkg-config libfontconfig1-dev libass-dev libasound2-dev libffms2-dev intltool libboost-all-dev libhunspell-dev libuchardet-dev libpulse-dev libopenal-dev libjansson-dev - name: Configure run: meson setup build ${{ matrix.config.args }} -Dbuildtype=${{ matrix.config.buildtype }} @@ -186,7 +186,6 @@ jobs: ./linuxdeploy --appdir appdir --desktop-file=appdir/aegisub.desktop ./appimagetool appdir - # ./appimagetool -g -s appdir --comp xz - name: Upload artifacts - Linux AppImage uses: actions/upload-artifact@v3