Lua: Allow creating and running user defined scripts

Change-Id: I227d55105fde53f22885793b4bfae69da90e8fa6
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
David Schulz
2024-10-10 14:58:11 +02:00
parent af44a93f35
commit 5d1d4d9f54
6 changed files with 159 additions and 11 deletions

View File

@@ -3,6 +3,7 @@
#include "corejsextensions.h"
#include "icore.h"
#include "messagemanager.h"
#include <utils/appinfo.h>
@@ -35,6 +36,11 @@ QString UtilsJsExtension::qtCreatorIdeVersion() const
return QCoreApplication::applicationVersion();
}
QString UtilsJsExtension::qtCreatorSettingsPath() const
{
return Core::ICore::userResourcePath().toString();
}
QString UtilsJsExtension::toNativeSeparators(const QString &in) const
{
return QDir::toNativeSeparators(in);

View File

@@ -21,6 +21,7 @@ public:
Q_INVOKABLE QString qtVersion() const;
Q_INVOKABLE QString qtCreatorVersion() const;
Q_INVOKABLE QString qtCreatorIdeVersion() const;
Q_INVOKABLE QString qtCreatorSettingsPath() const;
// File name conversions:
Q_INVOKABLE QString toNativeSeparators(const QString &in) const;

View File

@@ -5,6 +5,8 @@
#include "luapluginspec.h"
#include "luatr.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icore.h>
#include <coreplugin/ioutputpane.h>
#include <coreplugin/jsexpander.h>
@@ -14,6 +16,7 @@
#include <extensionsystem/pluginmanager.h>
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/layoutbuilder.h>
#include <utils/macroexpander.h>
#include <utils/qtcprocess.h>
@@ -25,6 +28,7 @@
#include <QLineEdit>
#include <QListView>
#include <QPainter>
#include <QMenu>
#include <QStringListModel>
#include <QStyledItemDelegate>
@@ -34,6 +38,11 @@ using namespace ExtensionSystem;
namespace Lua::Internal {
const char M_SCRIPT[] = "Lua.Script";
const char G_SCRIPTS[] = "Lua.Scripts";
const char ACTION_SCRIPTS_BASE[] = "Lua.Scripts.";
const char ACTION_NEW_SCRIPT[] = "Lua.NewScript";
void setupActionModule();
void setupCoreModule();
void setupFetchModule();
@@ -270,6 +279,7 @@ class LuaPlugin : public IPlugin
private:
LuaPane *m_pane = nullptr;
std::unique_ptr<FilePathWatcher> m_userScriptsWatcher;
public:
LuaPlugin() {}
@@ -319,6 +329,44 @@ public:
});
m_pane = new LuaPane(this);
//register actions
ActionContainer *toolsContainer = ActionManager::actionContainer(Core::Constants::M_TOOLS);
ActionContainer *scriptContainer = ActionManager::createMenu(M_SCRIPT);
Command *newScriptCommand = ActionBuilder(this, ACTION_NEW_SCRIPT)
.setScriptable(true)
.setText(tr("New Script..."))
.addToContainer(M_SCRIPT)
.addOnTriggered([](){
auto command = Core::ActionManager::command(Utils::Id("Wizard.Impl.Q.QCreatorScript"));
if (command && command->action())
command->action()->trigger();
else
qWarning("Failed to get wizard command. UI changed?");
})
.command();
scriptContainer->addAction(newScriptCommand);
scriptContainer->addSeparator();
scriptContainer->appendGroup(G_SCRIPTS);
scriptContainer->menu()->setTitle(Tr::tr("Scripting"));
toolsContainer->addMenu(scriptContainer);
const Utils::FilePath userScriptsPath = Core::ICore::userResourcePath("scripts");
userScriptsPath.ensureWritableDir();
if (auto watch = userScriptsPath.watch()) {
m_userScriptsWatcher.swap(*watch);
connect(
m_userScriptsWatcher.get(),
&FilePathWatcher::pathChanged,
this,
&LuaPlugin::scanForScripts);
}
scanForScripts();
}
bool delayedInitialize() final
@@ -355,6 +403,49 @@ public:
PluginManager::addPlugins({plugins.begin(), plugins.end()});
PluginManager::loadPluginsAtRuntime(plugins);
}
void scanForScripts()
{
const FilePath scriptsPath = Core::ICore::userResourcePath("scripts");
if (!scriptsPath.exists())
return;
ActionContainer *scriptContainer = ActionManager::actionContainer(M_SCRIPT);
const FilePaths scripts = scriptsPath.dirEntries(FileFilter({"*.lua"}, QDir::Files));
for (const FilePath &script : scripts) {
const Id base = Id(ACTION_SCRIPTS_BASE).withSuffix(script.baseName());
const Id menuId = base.withSuffix(".Menu");
if (!ActionManager::actionContainer(menuId)) {
ActionContainer *container = ActionManager::createMenu(menuId);
scriptContainer->addMenu(container);
auto menu = container->menu();
menu->setTitle(script.baseName());
ActionBuilder(this, base)
.setText(Tr::tr("%1").arg(script.baseName()))
.setToolTip(Tr::tr("Run script '%1'").arg(script.toUserOutput()))
.addOnTriggered([this, script]() { runScript(script); });
connect(menu->addAction(Tr::tr("Run")), &QAction::triggered, this, [this, script]() {
runScript(script);
});
connect(menu->addAction(Tr::tr("Edit")), &QAction::triggered, this, [script]() {
Core::EditorManager::openEditor(script);
});
}
}
}
void runScript(const FilePath &script)
{
expected_str<QByteArray> content = script.fileContents();
if (content) {
Lua::runScript(QString::fromUtf8(*content), script.fileName());
} else {
MessageManager::writeFlashing(Tr::tr("Failed to read script %1: %2")
.arg(script.toUserOutput())
.arg(content.error()));
}
}
};
} // namespace Lua::Internal

View File

@@ -0,0 +1,4 @@
T = require'TextEditor'
editor = T.currentEditor()
cursor = editor:cursor()
cursor:insertText('-- Hello World!')

View File

@@ -0,0 +1,44 @@
{
"version": 1,
"supportedProjectTypes": [],
"id": "Q.QCreatorScript",
"category": "R.Lua",
"trDescription": "Creates a script that can access Qt Creator internals and be triggered by an action.",
"trDisplayName": "Qt Creator Script",
"trDisplayCategory": "Lua",
"iconText": "ts",
"enabled": "%{JS: value('Plugins').indexOf('Lua') >= 0}",
"options": [
{
"key": "DefaultSuffix",
"value": "%{JS: Util.preferredSuffix('text/x-lua')}"
},
{
"key": "InitialPath",
"value": "%{JS: Util.qtCreatorSettingsPath()}/scripts"
},
{
"key": "PathVisible",
"value": "false"
}
],
"pages": [
{
"trDisplayName": "Location",
"trShortTitle": "Location",
"typeId": "File"
}
],
"generators": [
{
"typeId": "File",
"data": [
{
"source": "script.lua",
"target": "%{JS: Util.fileName(value('TargetPath'), value('DefaultSuffix'))}",
"openInEditor": true
}
]
}
]
}

View File

@@ -9,5 +9,7 @@
<file>plugin/.luarc.json</file>
<file>plugin/icon.png</file>
<file>plugin/icon@2x.png</file>
<file>qcscript/script.lua</file>
<file>qcscript/wizard.json</file>
</qresource>
</RCC>