diff --git a/docs/scripting-api.rst b/docs/scripting-api.rst index 1261538ddd..49dd1bc851 100644 --- a/docs/scripting-api.rst +++ b/docs/scripting-api.rst @@ -1622,6 +1622,48 @@ unlike in GUI, where row numbers start from 1 by default. config("style", styleName) +.. js:function:: onItemsAdded() + + Called when items are added to a tab. + + The target tab is returned by `selectedTab()`. + + The new items can be accessed with `selectedItemsData()`, + `selectedItemData()`, `selectedItems()` and `ItemSelection().current()`. + +.. js:function:: onItemsRemoved() + + Called when items are being removed from a tab. + + The target tab is returned by `selectedTab()`. + + The removed items can be accessed with `selectedItemsData()`, + `selectedItemData()`, `selectedItems()` and `ItemSelection().current()`. + +.. js:function:: onItemsChanged() + + Called when data in items change. + + The target tab is returned by `selectedTab()`. + + The modified items can be accessed with `selectedItemsData()`, + `selectedItemData()`, `selectedItems()` and `ItemSelection().current()`. + +.. js:function:: onTabSelected() + + Called when another tab is open. + + The newly selected tab is returned by `selectedTab()`. + + The changed items can be accessed with `selectedItemsData()`, + `selectedItemData()`, `selectedItems()` and `ItemSelection().current()`. + +.. js:function:: onItemsLoaded() + + Called when items a loaded to a tab. + + The target tab is returned by `selectedTab()`. + Types ----- diff --git a/src/app/clipboardserver.cpp b/src/app/clipboardserver.cpp index 1da06f3f5f..779ada6a2f 100644 --- a/src/app/clipboardserver.cpp +++ b/src/app/clipboardserver.cpp @@ -163,6 +163,8 @@ ClipboardServer::ClipboardServer(QApplication *app, const QString &sessionName) connect( m_wnd, &MainWindow::commandsSaved, this, &ClipboardServer::onCommandsSaved ); + m_server->start(); + { AppConfig appConfig; loadSettings(&appConfig); @@ -173,8 +175,6 @@ ClipboardServer::ClipboardServer(QApplication *app, const QString &sessionName) qApp->installEventFilter(this); - m_server->start(); - // Ignore global shortcut key presses in any widget. m_ignoreKeysTimer.setInterval(100); m_ignoreKeysTimer.setSingleShot(true); diff --git a/src/common/action.cpp b/src/common/action.cpp index 9bf8731738..3ecf6da9da 100644 --- a/src/common/action.cpp +++ b/src/common/action.cpp @@ -310,7 +310,7 @@ bool Action::waitForFinished(int msecs) t.setSingleShot(true); t.start(msecs); } - loop.exec(QEventLoop::ExcludeUserInputEvents); + loop.exec(QEventLoop::AllEvents); // Loop stopped because application is exiting? while ( self && isRunning() && (msecs < 0 || t.isActive()) ) diff --git a/src/gui/clipboardbrowser.cpp b/src/gui/clipboardbrowser.cpp index 9a9e509ea8..f51a555064 100644 --- a/src/gui/clipboardbrowser.cpp +++ b/src/gui/clipboardbrowser.cpp @@ -1671,6 +1671,7 @@ bool ClipboardBrowser::loadItems() return false; d.rowsInserted(QModelIndex(), 0, m.rowCount()); + emit itemsLoaded(this); if ( hasFocus() ) setCurrent(0); onItemCountChanged(); diff --git a/src/gui/clipboardbrowser.h b/src/gui/clipboardbrowser.h index 1010850605..c37ef88633 100644 --- a/src/gui/clipboardbrowser.h +++ b/src/gui/clipboardbrowser.h @@ -242,6 +242,8 @@ class ClipboardBrowser final : public QListView void itemsChanged(const ClipboardBrowser *self); + void itemsLoaded(const ClipboardBrowser *self); + void itemSelectionChanged(const ClipboardBrowser *self); void internalEditorStateChanged(const ClipboardBrowser *self); diff --git a/src/gui/commandcompleterdocumentation.h b/src/gui/commandcompleterdocumentation.h index 8727574154..e6e1a3f389 100644 --- a/src/gui/commandcompleterdocumentation.h +++ b/src/gui/commandcompleterdocumentation.h @@ -118,6 +118,7 @@ void addDocumentation(AddDocumentationCallback addDocumentation) addDocumentation("open", "open(url, ...) -> bool", "Tries to open URLs in appropriate applications."); addDocumentation("execute", "execute(argument, ..., null, stdinData, ...) -> `FinishedCommand` or `undefined`", "Executes a command."); addDocumentation("currentWindowTitle", "String currentWindowTitle() -> string", "Returns window title of currently focused window."); + addDocumentation("currentClipboardOwner", "String currentClipboardOwner() -> string", "Returns name of the current clipboard owner."); addDocumentation("dialog", "dialog(...)", "Shows messages or asks user for input."); addDocumentation("menuItems", "menuItems(text...) -> string", "Opens menu with given items and returns selected item or an empty string."); addDocumentation("menuItems", "menuItems(items[]) -> int", "Opens menu with given items and returns index of selected item or -1."); @@ -171,6 +172,11 @@ void addDocumentation(AddDocumentationCallback addDocumentation) addDocumentation("hideDataNotification", "hideDataNotification()", "Hide notification for current data."); addDocumentation("setClipboardData", "setClipboardData()", "Sets clipboard data for menu commands."); addDocumentation("styles", "styles() -> array of strings", "List available styles for `style` option."); + addDocumentation("onItemsAdded", "onItemsAdded()", "Called when items are added to a tab."); + addDocumentation("onItemsRemoved", "onItemsRemoved()", "Called when items are being removed from a tab."); + addDocumentation("onItemsChanged", "onItemsChanged()", "Called when data in items change."); + addDocumentation("onTabSelected", "onTabSelected()", "Called when another tab is open."); + addDocumentation("onItemsLoaded", "onItemsLoaded()", "Called when items a loaded to a tab."); addDocumentation("ByteArray", "ByteArray", "Wrapper for QByteArray Qt class."); addDocumentation("File", "File", "Wrapper for QFile Qt class."); addDocumentation("Dir", "Dir", "Wrapper for QDir Qt class."); diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index ac0b8e0f88..83115975ef 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -187,6 +187,18 @@ void disableActionWhenTabGroupSelected(WidgetOrAction *action, MainWindow *windo action, &WidgetOrAction::setDisabled ); } +void addSelectionData( + QVariantMap *result, + const QModelIndexList &selectedIndexes) +{ + QList selected; + selected.reserve(selectedIndexes.size()); + for (const auto &index : selectedIndexes) + selected.append(index); + std::sort(selected.begin(), selected.end()); + result->insert(mimeSelectedItems, QVariant::fromValue(selected)); +} + /// Adds information about current tab and selection if command is triggered by user. QVariantMap addSelectionData( const ClipboardBrowser &c, @@ -203,12 +215,7 @@ QVariantMap addSelectionData( } if ( !selectedIndexes.isEmpty() ) { - QList selected; - selected.reserve(selectedIndexes.size()); - for (const auto &index : selectedIndexes) - selected.append(index); - std::sort(selected.begin(), selected.end()); - result.insert(mimeSelectedItems, QVariant::fromValue(selected)); + addSelectionData(&result, selectedIndexes); } return result; @@ -1065,15 +1072,21 @@ bool MainWindow::isItemPreviewVisible() const return m_showItemPreview; } -void MainWindow::setScriptOverrides(const QVector &overrides) +void MainWindow::setScriptOverrides(const QVector &overrides, int actionId) { + if (!m_actionCollectOverrides || m_actionCollectOverrides->id() != actionId) + return; + m_overrides = overrides; std::sort(m_overrides.begin(), m_overrides.end()); } bool MainWindow::isScriptOverridden(int id) const { - return std::binary_search(m_overrides.begin(), m_overrides.end(), id); + return + // Assume everything is overridden until collectOverrides() finishes + (m_actionCollectOverrides && m_actionCollectOverrides->isRunning() && m_overrides.isEmpty()) + || std::binary_search(m_overrides.begin(), m_overrides.end(), id); } void MainWindow::onAboutToQuit() @@ -1253,6 +1266,8 @@ void MainWindow::onBrowserCreated(ClipboardBrowser *browser) this, &MainWindow::onSearchShowRequest ); connect( browser, &ClipboardBrowser::itemWidgetCreated, this, &MainWindow::onItemWidgetCreated ); + connect( browser, &ClipboardBrowser::itemsLoaded, + this, &MainWindow::onBrowserItemsLoaded ); if (browserOrNull() == browser) { const int index = ui->tabWidget->currentIndex(); @@ -1268,6 +1283,34 @@ void MainWindow::onBrowserDestroyed(ClipboardBrowserPlaceholder *placeholder) } } +void MainWindow::onBrowserItemsLoaded(const ClipboardBrowser *browser) +{ + if (isScriptOverridden(ScriptOverrides::OnItemsLoaded)) { + runEventHandlerScript( + QStringLiteral("onItemsLoaded()"), + createDataMap(mimeCurrentTab, browser->tabName())); + } + + connect( browser->model(), &QAbstractItemModel::rowsAboutToBeRemoved, + browser, [this, browser](const QModelIndex &, int first, int last) { + if (isScriptOverridden(ScriptOverrides::OnItemsRemoved)) + runItemHandlerScript(QStringLiteral("onItemsRemoved()"), browser, first, last); + } ); + connect( browser->model(), &QAbstractItemModel::rowsInserted, + browser, [this, browser](const QModelIndex &, int first, int last) { + if (isScriptOverridden(ScriptOverrides::OnItemsAdded)) + runItemHandlerScript(QStringLiteral("onItemsAdded()"), browser, first, last); + } ); + connect( browser->model(), &QAbstractItemModel::dataChanged, + browser, [this, browser](const QModelIndex &topLeft, const QModelIndex &bottomRight) { + if (isScriptOverridden(ScriptOverrides::OnItemsChanged)) { + runItemHandlerScript( + QStringLiteral("onItemsChanged()"), + browser, topLeft.row(), bottomRight.row()); + } + } ); +} + void MainWindow::onItemSelectionChanged(const ClipboardBrowser *browser) { if (browser == browserOrNull()) { @@ -1346,7 +1389,7 @@ void MainWindow::runDisplayCommands() if ( !isInternalActionId(m_displayActionId) ) { m_currentDisplayItem = m_displayItemList.takeFirst(); - const auto action = runScript("runDisplayCommands()", m_currentDisplayItem.data()); + const auto action = runScript(QStringLiteral("runDisplayCommands()"), m_currentDisplayItem.data()); m_displayActionId = action->id(); } @@ -1613,7 +1656,7 @@ void MainWindow::runMenuCommandFilters(MenuMatchCommands *menuMatchCommands, QVa if (isRunning) { m_sharedData->actions->setActionData(menuMatchCommands->actionId, data); } else { - const auto act = runScript("runMenuCommandFilters()", data); + const auto act = runScript(QStringLiteral("runMenuCommandFilters()"), data); menuMatchCommands->actionId = act->id(); } @@ -1884,7 +1927,7 @@ void MainWindow::activateMenuItem(ClipboardBrowserPlaceholder *placeholder, cons if ( m_options.trayItemPaste && !omitPaste && canPaste() ) { if (isScriptOverridden(ScriptOverrides::Paste)) { COPYQ_LOG("Pasting item with paste()"); - runScript("paste()"); + runScript(QStringLiteral("paste()")); } else if (lastWindow) { COPYQ_LOG( QStringLiteral("Pasting item from tray menu to: %1") .arg(lastWindow->getTitle()) ); @@ -2306,6 +2349,9 @@ void MainWindow::updateEnabledCommands() void MainWindow::updateCommands(QVector allCommands, bool forceSave) { + m_overrides = {}; + m_actionCollectOverrides = runScript(QStringLiteral("collectScriptOverrides()")); + m_automaticCommands.clear(); m_menuCommands.clear(); m_scriptCommands.clear(); @@ -2348,10 +2394,9 @@ void MainWindow::updateCommands(QVector allCommands, bool forceSave) reloadBrowsers(); } - runScript("collectOverrides()"); - updateContextMenu(contextMenuUpdateIntervalMsec); updateTrayMenuCommands(); + emit commandsSaved(commands); } @@ -2404,12 +2449,43 @@ const Theme &MainWindow::theme() const Action *MainWindow::runScript(const QString &script, const QVariantMap &data) { auto act = new Action(); - act->setCommand(QStringList() << "copyq" << "eval" << "--" << script); + act->setCommand( + {QStringLiteral("copyq"), QStringLiteral("eval"), QStringLiteral("--"), script}); act->setData(data); runInternalAction(act); return act; } +void MainWindow::runEventHandlerScript(const QString &script, const QVariantMap &data) +{ + if (m_maxEventHandlerScripts == 0) + return; + + --m_maxEventHandlerScripts; + if (m_maxEventHandlerScripts == 0) + log("Event handler maximum recursion reached", LogWarning); + + const auto action = runScript(script, data); + action->waitForFinished(); + ++m_maxEventHandlerScripts; +} + +void MainWindow::runItemHandlerScript( + const QString &script, const ClipboardBrowser *browser, int firstRow, int lastRow) +{ + QModelIndexList indexes; + indexes.reserve(lastRow - firstRow + 1); + for (int row = firstRow; row <= lastRow; ++row) { + const auto index = browser->model()->index(row, 0); + if (index.isValid()) + indexes.append(index); + } + + QVariantMap data = createDataMap(mimeCurrentTab, browser->tabName()); + addSelectionData(&data, indexes); + runEventHandlerScript(script, data); +} + int MainWindow::findTabIndex(const QString &name) { TabWidget *w = ui->tabWidget; @@ -2984,6 +3060,12 @@ void MainWindow::tabChanged(int current, int) } setTabOrder(ui->searchBar, c); + + if (isScriptOverridden(ScriptOverrides::OnTabSelected)) { + runEventHandlerScript( + QStringLiteral("onTabSelected()"), + createDataMap(mimeCurrentTab, c->tabName())); + } } } @@ -3333,7 +3415,7 @@ void MainWindow::activateCurrentItemHelper() if (paste) { if (isScriptOverridden(ScriptOverrides::Paste)) { COPYQ_LOG("Pasting item with paste()"); - runScript("paste()"); + runScript(QStringLiteral("paste()")); } else if (lastWindow) { COPYQ_LOG( QStringLiteral("Pasting item from main window to: %1") .arg(lastWindow->getTitle()) ); @@ -3366,7 +3448,7 @@ void MainWindow::disableClipboardStoring(bool disable) updateIcon(); - runScript("setTitle(); showDataNotification()"); + runScript(QStringLiteral("setTitle(); showDataNotification()")); COPYQ_LOG( QString("Clipboard monitoring %1.") .arg(m_clipboardStoringDisabled ? "disabled" : "enabled") ); diff --git a/src/gui/mainwindow.h b/src/gui/mainwindow.h index 7bf762f473..1e55ce4b1d 100644 --- a/src/gui/mainwindow.h +++ b/src/gui/mainwindow.h @@ -412,7 +412,7 @@ class MainWindow final : public QMainWindow void setItemPreviewVisible(bool visible); bool isItemPreviewVisible() const; - void setScriptOverrides(const QVector &overrides); + void setScriptOverrides(const QVector &overrides, int actionId); bool isScriptOverridden(int id) const; signals: @@ -500,6 +500,7 @@ class MainWindow final : public QMainWindow void onBrowserCreated(ClipboardBrowser *browser); void onBrowserDestroyed(ClipboardBrowserPlaceholder *placeholder); + void onBrowserItemsLoaded(const ClipboardBrowser *browser); void onItemSelectionChanged(const ClipboardBrowser *browser); void onItemsChanged(const ClipboardBrowser *browser); @@ -630,6 +631,9 @@ class MainWindow final : public QMainWindow const Theme &theme() const; Action *runScript(const QString &script, const QVariantMap &data = QVariantMap()); + void runEventHandlerScript(const QString &script, const QVariantMap &data = QVariantMap()); + void runItemHandlerScript( + const QString &script, const ClipboardBrowser *browser, int firstRow, int lastRow); void activateCurrentItemHelper(); void onItemClicked(); @@ -699,6 +703,8 @@ class MainWindow final : public QMainWindow bool m_enteringSearchMode = false; QVector m_overrides; + int m_maxEventHandlerScripts = 10; + QPointer m_actionCollectOverrides; }; #endif // MAINWINDOW_H diff --git a/src/scriptable/scriptable.cpp b/src/scriptable/scriptable.cpp index 356d696579..d2dcb8f93b 100644 --- a/src/scriptable/scriptable.cpp +++ b/src/scriptable/scriptable.cpp @@ -653,6 +653,11 @@ bool isGuiApplication() return qobject_cast(qApp); } +bool isOverridden(const QJSValue &globalObject, const QString &property) +{ + return globalObject.property(property).property(QStringLiteral("_copyq")).toInt() != 1; +} + } // namespace Scriptable::Scriptable( @@ -2947,15 +2952,24 @@ QJSValue Scriptable::styles() return toScriptValue( m_proxy->styles(), this ); } -void Scriptable::collectOverrides() +void Scriptable::collectScriptOverrides() { m_skipArguments = 1; auto globalObject = engine()->globalObject(); QVector overrides; - const auto pasteFn = globalObject.property("paste"); - if (pasteFn.property("_copyq").toInt() != 1) + if (isOverridden(globalObject, QStringLiteral("paste"))) overrides.append(ScriptOverrides::Paste); + if (isOverridden(globalObject, QStringLiteral("onItemsAdded"))) + overrides.append(ScriptOverrides::OnItemsAdded); + if (isOverridden(globalObject, QStringLiteral("onItemsRemoved"))) + overrides.append(ScriptOverrides::OnItemsRemoved); + if (isOverridden(globalObject, QStringLiteral("onItemsChanged"))) + overrides.append(ScriptOverrides::OnItemsChanged); + if (isOverridden(globalObject, QStringLiteral("onTabSelected"))) + overrides.append(ScriptOverrides::OnTabSelected); + if (isOverridden(globalObject, QStringLiteral("onItemsLoaded"))) + overrides.append(ScriptOverrides::OnItemsLoaded); m_proxy->setScriptOverrides(overrides); } diff --git a/src/scriptable/scriptable.h b/src/scriptable/scriptable.h index dd21f48180..89294c57dd 100644 --- a/src/scriptable/scriptable.h +++ b/src/scriptable/scriptable.h @@ -389,7 +389,12 @@ public slots: QJSValue styles(); - void collectOverrides(); + void onItemsAdded() {} + void onItemsRemoved() {} + void onItemsChanged() {} + void onTabSelected() {} + void onItemsLoaded() {} + void collectScriptOverrides(); signals: void finished(); diff --git a/src/scriptable/scriptableproxy.cpp b/src/scriptable/scriptableproxy.cpp index cf7b368d12..91b67ad4be 100644 --- a/src/scriptable/scriptableproxy.cpp +++ b/src/scriptable/scriptableproxy.cpp @@ -2604,7 +2604,7 @@ QStringList ScriptableProxy::styles() void ScriptableProxy::setScriptOverrides(const QVector &overrides) { INVOKE2(setScriptOverrides, (overrides)); - m_wnd->setScriptOverrides(overrides); + m_wnd->setScriptOverrides(overrides, m_actionId); } ClipboardBrowser *ScriptableProxy::fetchBrowser(const QString &tabName) diff --git a/src/scriptable/scriptoverrides.h b/src/scriptable/scriptoverrides.h index 4197f630d0..147d4dd101 100644 --- a/src/scriptable/scriptoverrides.h +++ b/src/scriptable/scriptoverrides.h @@ -4,5 +4,10 @@ namespace ScriptOverrides { enum ScriptOverrides { Paste = 0, + OnItemsAdded = 1, + OnItemsRemoved = 2, + OnItemsChanged = 3, + OnTabSelected = 4, + OnItemsLoaded = 5, }; } diff --git a/src/tests/tests.cpp b/src/tests/tests.cpp index 644840f30d..3cc233acb0 100644 --- a/src/tests/tests.cpp +++ b/src/tests/tests.cpp @@ -152,6 +152,8 @@ bool testStderr(const QByteArray &stderrData, TestInterface::ReadStderrFlag flag static const std::vector ignoreList{ regex(R"(CopyQ Note \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}\] setEnv("COPYQ_TEST_THROW", "0"); } +void Tests::scriptPaste() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: 'global.paste = function() { add("PASTE") }' + }, + ]) + )"; + RUN(script, ""); + RUN("add(1)", ""); + RUN("keys" << clipboardBrowserId << "ENTER", ""); + WAIT_ON_OUTPUT("read(0)", "PASTE"); +} + +void Tests::scriptOnTabSelected() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: 'global.onTabSelected = function() { add(selectedTab()) }' + }, + ]) + )"; + RUN(script, ""); + + const auto tab1 = testTab(1); + const auto tab2 = testTab(2); + RUN("show" << tab1, ""); + WAIT_ON_OUTPUT("tab" << tab1 << "read(0)", tab1); + RUN("show" << tab2, ""); + WAIT_ON_OUTPUT("tab" << tab2 << "read(0)", tab2); +} + +void Tests::scriptOnItemsRemoved() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: ` + global.onItemsRemoved = function() { + items = ItemSelection().current().items(); + tab(tab()[0]); + add("R0:" + str(items[0][mimeText])); + add("R1:" + str(items[1][mimeText])); + } + ` + }, + ]) + )"; + RUN(script, ""); + const auto tab1 = testTab(1); + RUN("tab" << tab1 << "add(3,2,1,0)", ""); + RUN("tab" << tab1 << "remove(1,2)", ""); + WAIT_ON_OUTPUT("separator" << "," << "read(0,1,2,)", "R1:2,R0:1,"); +} + +void Tests::scriptOnItemsAdded() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: ` + global.onItemsAdded = function() { + if (selectedTab() == tab()[0]) abort(); + items = ItemSelection().current().items(); + tab(tab()[0]); + add("A:" + str(items[0][mimeText])); + } + ` + }, + ]) + )"; + RUN(script, ""); + const auto tab1 = testTab(1); + RUN("tab" << tab1 << "add(1,0)", ""); + WAIT_ON_OUTPUT("separator" << "," << "read(0,1,2)", "A:0,A:1,"); +} + +void Tests::scriptOnItemsChanged() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: ` + global.onItemsChanged = function() { + if (selectedTab() == tab()[0]) abort(); + items = ItemSelection().current().items(); + tab(tab()[0]); + add("C:" + str(items[0][mimeText])); + } + ` + }, + ]) + )"; + RUN(script, ""); + const auto tab1 = testTab(1); + RUN("tab" << tab1 << "add(0)", ""); + RUN("tab" << tab1 << "change(0, mimeText, 'A')", ""); + WAIT_ON_OUTPUT("separator" << "," << "read(0,1,2)", "C:A,,"); + RUN("tab" << tab1 << "change(0, mimeText, 'B')", ""); + WAIT_ON_OUTPUT("separator" << "," << "read(0,1,2)", "C:B,C:A,"); +} + +void Tests::scriptOnItemsLoaded() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: ` + global.onItemsLoaded = function() { + if (selectedTab() == tab()[0]) abort(); + tab(tab()[0]); + add(selectedTab()); + } + ` + }, + ]) + )"; + RUN(script, ""); + + const auto tab1 = testTab(1); + RUN("show" << tab1, ""); + WAIT_ON_OUTPUT("separator" << "," << "read(0,1,2)", tab1 + ",,"); + + const auto tab2 = testTab(2); + RUN("show" << tab2, ""); + WAIT_ON_OUTPUT("separator" << "," << "read(0,1,2)", tab2 + "," + tab1 + ","); +} + +void Tests::scriptEventMaxRecursion() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: 'global.onItemsAdded = function() { add("A") }' + }, + ]) + )"; + RUN(script, ""); + RUN("add(1,0)", ""); + WAIT_ON_OUTPUT("length", "22\n"); + waitFor(200); + RUN("separator" << "," << "read(0,1,2)", "A,A,A"); + RUN("length", "22\n"); +} + +void Tests::scriptSlowCollectOverrides() +{ + const auto script = R"( + setCommands([ + { + isScript: true, + cmd: 'global.onTabSelected = function() { add(selectedTab()) }' + }, + { + isScript: true, + cmd: ` + var collectOverrides_ = global.collectOverrides; + global.collectOverrides = function() { sleep(1000); collectOverrides_() } + ` + }, + ]) + )"; + RUN(script, ""); + + const auto tab1 = testTab(1); + RUN("show" << tab1, ""); + WAIT_ON_OUTPUT("tab" << tab1 << "read(0)", tab1); +} + void Tests::displayCommand() { const auto testMime = COPYQ_MIME_PREFIX "test"; diff --git a/src/tests/tests.h b/src/tests/tests.h index 41b98a2a9b..aa9abb4b2a 100644 --- a/src/tests/tests.h +++ b/src/tests/tests.h @@ -250,6 +250,16 @@ private slots: void scriptCommandEnhanceFunction(); void scriptCommandEndingWithComment(); void scriptCommandWithError(); + + void scriptPaste(); + void scriptOnTabSelected(); + void scriptOnItemsRemoved(); + void scriptOnItemsAdded(); + void scriptOnItemsChanged(); + void scriptOnItemsLoaded(); + void scriptEventMaxRecursion(); + void scriptSlowCollectOverrides(); + void displayCommand(); void displayCommandForMenu();