mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-23 23:16:31 +00:00
Watch python extensions for changes on disk and update status bar
* We show a button to quickly reload changed extensions.
This commit is contained in:
@@ -220,6 +220,13 @@ CaptureContext::CaptureContext(PersistantConfig &cfg) : m_Config(cfg)
|
||||
dir.mkpath(dir.absolutePath());
|
||||
}
|
||||
|
||||
m_ExtensionWatcher = new QFileSystemWatcher({}, GetMainWindow()->Widget());
|
||||
|
||||
QObject::connect(m_ExtensionWatcher, &QFileSystemWatcher::directoryChanged,
|
||||
[this](const QString &path) { ExtensionTouched(path); });
|
||||
QObject::connect(m_ExtensionWatcher, &QFileSystemWatcher::fileChanged,
|
||||
[this](const QString &path) { ExtensionTouched(path); });
|
||||
|
||||
rdcarray<ExtensionMetadata> exts = CaptureContext::GetInstalledExtensions();
|
||||
|
||||
for(const ExtensionMetadata &e : exts)
|
||||
@@ -234,6 +241,8 @@ CaptureContext::CaptureContext(PersistantConfig &cfg) : m_Config(cfg)
|
||||
|
||||
CaptureContext::~CaptureContext()
|
||||
{
|
||||
delete m_ExtensionWatcher;
|
||||
|
||||
delete m_QtHelper;
|
||||
RENDERDOC_UnregisterMemoryRegion(this);
|
||||
delete m_Icon;
|
||||
@@ -340,6 +349,8 @@ rdcarray<ExtensionMetadata> CaptureContext::GetInstalledExtensions()
|
||||
ext.package = package;
|
||||
ext.filePath = fileinfo.absolutePath();
|
||||
|
||||
ext.hasChanges = m_DirtyExtensions.contains(rdcstr(package));
|
||||
|
||||
if(json.contains(lit("name")))
|
||||
{
|
||||
ext.name = json[lit("name")].toString();
|
||||
@@ -483,6 +494,12 @@ rdcstr CaptureContext::LoadExtension(rdcstr name)
|
||||
if(ret.isEmpty())
|
||||
{
|
||||
m_ExtensionObjects[name].swap(m_PendingExtensionObjects);
|
||||
|
||||
m_DirtyExtensions.removeOne(name);
|
||||
|
||||
for(const ExtensionMetadata &e : GetInstalledExtensions())
|
||||
if(e.package == name)
|
||||
AddExtensionWatches(e.filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2804,6 +2821,47 @@ void CaptureContext::setupDockWindow(QWidget *shad, bool hide)
|
||||
shad->hide();
|
||||
}
|
||||
|
||||
void CaptureContext::AddExtensionWatches(rdcstr filePath)
|
||||
{
|
||||
QDir dir(filePath);
|
||||
|
||||
// ignore directories with no python files
|
||||
QStringList pyfiles = dir.entryList(QStringList() << lit("*.py"));
|
||||
if(pyfiles.empty())
|
||||
return;
|
||||
|
||||
// don't watch the directory itself. New files will not be usable and we will already catch
|
||||
// renames.
|
||||
// m_ExtensionWatcher->addPath(filePath);
|
||||
for(QString pyfile : pyfiles)
|
||||
m_ExtensionWatcher->addPath(dir.absoluteFilePath(pyfile));
|
||||
|
||||
for(QString subdir : dir.entryList(QStringList(), QDir::Dirs | QDir::NoDotAndDotDot))
|
||||
AddExtensionWatches(dir.absoluteFilePath(subdir));
|
||||
}
|
||||
|
||||
void CaptureContext::ExtensionTouched(const QString &extensionPath)
|
||||
{
|
||||
// find the root extension dir containing this path
|
||||
for(const ExtensionMetadata &m : GetInstalledExtensions())
|
||||
{
|
||||
if(extensionPath.contains(m.filePath))
|
||||
{
|
||||
// remove all watched paths underneath
|
||||
QStringList paths = m_ExtensionWatcher->directories();
|
||||
paths.append(m_ExtensionWatcher->files());
|
||||
for(QString path : paths)
|
||||
{
|
||||
if(path.contains(m.filePath))
|
||||
m_ExtensionWatcher->removePath(path);
|
||||
}
|
||||
|
||||
// mark it as 'dirty' / needing reload
|
||||
m_DirtyExtensions.push_back(m.package);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureContext::RaiseDockWindow(QWidget *dockWindow)
|
||||
{
|
||||
ToolWindowManager::raiseToolWindow(dockWindow);
|
||||
|
||||
@@ -342,6 +342,9 @@ private:
|
||||
bool SaveEdits();
|
||||
void LoadEdits(const QString &data);
|
||||
|
||||
void AddExtensionWatches(rdcstr filePath);
|
||||
void ExtensionTouched(const QString &path);
|
||||
|
||||
void CacheResources();
|
||||
rdcstr GetResourceNameUnsuffixed(const ResourceDescription *desc) const;
|
||||
|
||||
@@ -428,6 +431,7 @@ private:
|
||||
|
||||
QList<QObject *> m_PendingExtensionObjects;
|
||||
QMap<rdcstr, QList<QObject *>> m_ExtensionObjects;
|
||||
rdcarray<rdcstr> m_DirtyExtensions;
|
||||
|
||||
QList<QPointer<RegisteredMenuItem>> m_RegisteredMenuItems;
|
||||
|
||||
@@ -436,6 +440,7 @@ private:
|
||||
MiniQtHelper *m_QtHelper = NULL;
|
||||
|
||||
QFileSystemWatcher *m_Watcher = NULL;
|
||||
QFileSystemWatcher *m_ExtensionWatcher = NULL;
|
||||
|
||||
// Windows
|
||||
MainWindow *m_MainWindow = NULL;
|
||||
|
||||
@@ -357,6 +357,14 @@ struct ExtensionMetadata
|
||||
:type: str
|
||||
)");
|
||||
rdcstr description;
|
||||
|
||||
DOCUMENT(R"(A flag indicating that the extension has changed on disk since the last time it was loaded.
|
||||
|
||||
This will always be false if the extension is unloaded.
|
||||
|
||||
:type: bool
|
||||
)");
|
||||
bool hasChanges = false;
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(ExtensionMetadata);
|
||||
|
||||
@@ -234,17 +234,32 @@ MainWindow::MainWindow(ICaptureContext &ctx) : QMainWindow(NULL), ui(new Ui::Mai
|
||||
extensionStatus->setIcon(Icons::plugin());
|
||||
extensionStatus->setVisible(false);
|
||||
|
||||
extensionReload = new RDToolButton(this);
|
||||
extensionReload->setAutoRaise(true);
|
||||
extensionReload->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
ui->statusBar->addWidget(extensionReload);
|
||||
|
||||
extensionReload->setIcon(Icons::update());
|
||||
extensionReload->setText(tr("Reload changed extensions"));
|
||||
extensionReload->setVisible(false);
|
||||
|
||||
QObject::connect(extensionStatus, &RDToolButton::clicked, this,
|
||||
&MainWindow::on_action_Manage_Extensions_triggered);
|
||||
QObject::connect(extensionReload, &RDToolButton::clicked, [this]() {
|
||||
rdcarray<ExtensionMetadata> exts = m_Ctx.Extensions().GetInstalledExtensions();
|
||||
for(const ExtensionMetadata &m : exts)
|
||||
if(m.hasChanges)
|
||||
m_Ctx.Extensions().LoadExtension(m.package);
|
||||
});
|
||||
QObject::connect(PythonContext::GetExtensionContext(), &PythonContext::extensionLoaded, this,
|
||||
&MainWindow::PythonStatusUpdate);
|
||||
|
||||
QTimer *debuggerTimer = new QTimer(this);
|
||||
QObject::connect(debuggerTimer, &QTimer::timeout, this, &MainWindow::PythonStatusUpdate);
|
||||
QTimer *pyStatusTimer = new QTimer(this);
|
||||
QObject::connect(pyStatusTimer, &QTimer::timeout, this, &MainWindow::PythonStatusUpdate);
|
||||
|
||||
debuggerTimer->setSingleShot(false);
|
||||
debuggerTimer->setInterval(500);
|
||||
debuggerTimer->start();
|
||||
pyStatusTimer->setSingleShot(false);
|
||||
pyStatusTimer->setInterval(500);
|
||||
pyStatusTimer->start();
|
||||
|
||||
QObject::connect(&m_MessageTick, &QTimer::timeout, this, &MainWindow::messageCheck);
|
||||
m_MessageTick.setSingleShot(false);
|
||||
@@ -1348,6 +1363,19 @@ void MainWindow::PythonStatusUpdate()
|
||||
extensionStatus->setVisible(true);
|
||||
|
||||
QString text = tr("%n extension(s) active", NULL, num);
|
||||
|
||||
bool reloadVisible = false;
|
||||
for(const ExtensionMetadata &m : m_Ctx.Extensions().GetInstalledExtensions())
|
||||
{
|
||||
if(m.hasChanges)
|
||||
{
|
||||
text += tr(" (changed on disk)");
|
||||
reloadVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
extensionReload->setVisible(reloadVisible);
|
||||
|
||||
if(PythonContext::IsDebuggerConnected())
|
||||
text += tr(": Python debugger connected");
|
||||
extensionStatus->setText(text);
|
||||
|
||||
@@ -252,6 +252,7 @@ private:
|
||||
RDLabel *statusIcon;
|
||||
RDLabel *statusText;
|
||||
RDToolButton *extensionStatus;
|
||||
RDToolButton *extensionReload;
|
||||
QProgressBar *statusProgress;
|
||||
RDMenu *contextChooserMenu;
|
||||
QToolButton *contextChooser;
|
||||
|
||||
Reference in New Issue
Block a user