mirror of https://github.com/vitalif/openscad
Minor refactoring, no longer automatically reloads if a dependency disappears
parent
c0fa353e06
commit
5722dd9e41
|
@ -77,7 +77,6 @@ private:
|
|||
void refreshDocument();
|
||||
void updateTemporalVariables();
|
||||
bool fileChangedOnDisk();
|
||||
bool includesChanged();
|
||||
void compileTopLevelDocument();
|
||||
void compile(bool reload, bool forcedone = false);
|
||||
void compileCSG(bool procevents);
|
||||
|
|
|
@ -38,6 +38,9 @@ FileModule *ModuleCache::evaluate(const std::string &filename)
|
|||
memset(&st, 0, sizeof(struct stat));
|
||||
bool valid = (stat(filename.c_str(), &st) == 0);
|
||||
|
||||
// If file isn't there, just return and let the cache retain the old module
|
||||
if (!valid) return NULL;
|
||||
|
||||
std::string cache_id = str(boost::format("%x.%x") % st.st_mtime % st.st_size);
|
||||
|
||||
// Lookup in cache
|
||||
|
@ -46,12 +49,9 @@ FileModule *ModuleCache::evaluate(const std::string &filename)
|
|||
if (this->entries[filename].cache_id == cache_id) {
|
||||
shouldCompile = false;
|
||||
|
||||
BOOST_FOREACH(const FileModule::IncludeContainer::value_type &include, lib_mod->includes) {
|
||||
if (lib_mod->include_modified(include.second)) {
|
||||
if (lib_mod->includesChanged()) {
|
||||
lib_mod = NULL;
|
||||
shouldCompile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -636,11 +636,12 @@ void MainWindow::compile(bool reload, bool forcedone)
|
|||
shouldcompiletoplevel = true;
|
||||
}
|
||||
|
||||
if (!shouldcompiletoplevel && includesChanged()) {
|
||||
if (!shouldcompiletoplevel && this->root_module && this->root_module->includesChanged()) {
|
||||
shouldcompiletoplevel = true;
|
||||
}
|
||||
|
||||
if (shouldcompiletoplevel) {
|
||||
console->clear();
|
||||
compileTopLevelDocument();
|
||||
didcompile = true;
|
||||
}
|
||||
|
@ -655,8 +656,8 @@ void MainWindow::compile(bool reload, bool forcedone)
|
|||
// If we're auto-reloading, listen for a cascade of changes by starting a timer
|
||||
// if something changed _and_ there are any external dependencies
|
||||
if (reload && didcompile && this->root_module) {
|
||||
if (this->root_module->includes.size() > 0 ||
|
||||
this->root_module->usedlibs.size() > 0) {
|
||||
if (this->root_module->hasIncludes() ||
|
||||
this->root_module->usesLibraries()) {
|
||||
this->waitAfterReloadTimer->start();
|
||||
return;
|
||||
}
|
||||
|
@ -1116,23 +1117,11 @@ bool MainWindow::fileChangedOnDisk()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool MainWindow::includesChanged()
|
||||
{
|
||||
if (this->root_module) {
|
||||
BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, this->root_module->includes) {
|
||||
if (this->root_module->include_modified(item.second)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if anything was compiled.
|
||||
*/
|
||||
void MainWindow::compileTopLevelDocument()
|
||||
{
|
||||
console->clear();
|
||||
|
||||
updateTemporalVariables();
|
||||
|
||||
this->last_compiled_doc = editor->toPlainText();
|
||||
|
@ -1233,7 +1222,6 @@ void MainWindow::actionRenderCSG()
|
|||
GuiLocker::lock();
|
||||
autoReloadTimer->stop();
|
||||
setCurrentOutput();
|
||||
console->clear();
|
||||
|
||||
PRINT("Parsing design (AST generation)...");
|
||||
QApplication::processEvents();
|
||||
|
@ -1278,7 +1266,6 @@ void MainWindow::actionRenderCGAL()
|
|||
GuiLocker::lock();
|
||||
autoReloadTimer->stop();
|
||||
setCurrentOutput();
|
||||
console->clear();
|
||||
|
||||
PRINT("Parsing design (AST generation)...");
|
||||
QApplication::processEvents();
|
||||
|
|
|
@ -207,6 +207,28 @@ void FileModule::registerInclude(const std::string &localpath,
|
|||
this->includes[localpath] = inc;
|
||||
}
|
||||
|
||||
bool FileModule::includesChanged() const
|
||||
{
|
||||
BOOST_FOREACH(const FileModule::IncludeContainer::value_type &item, this->includes) {
|
||||
if (include_modified(item.second)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileModule::include_modified(const IncludeFile &inc) const
|
||||
{
|
||||
struct stat st;
|
||||
memset(&st, 0, sizeof(struct stat));
|
||||
|
||||
fs::path fullpath = find_valid_path(this->path, inc.filename);
|
||||
bool valid = !fullpath.empty() ? (stat(boosty::stringy(fullpath).c_str(), &st) == 0) : false;
|
||||
|
||||
if (valid && !inc.valid) return true; // Detect appearance of file but not removal
|
||||
if (valid && st.st_mtime > inc.mtime) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Check if any dependencies have been modified and recompile them.
|
||||
Returns true if anything was recompiled.
|
||||
|
@ -217,12 +239,13 @@ bool FileModule::handleDependencies()
|
|||
this->is_handling_dependencies = true;
|
||||
|
||||
bool changed = false;
|
||||
// Iterating manually since we want to modify the container while iterating
|
||||
|
||||
|
||||
// If a lib in usedlibs was previously missing, we need to relocate it
|
||||
// by searching the applicable paths. We can identify a previously missing module
|
||||
// as it will have a relative path.
|
||||
|
||||
// Iterating manually since we want to modify the container while iterating
|
||||
std::vector<std::pair<std::string, FileModule*> > modified_modules;
|
||||
FileModule::ModuleContainer::iterator iter = this->usedlibs.begin();
|
||||
while (iter != this->usedlibs.end()) {
|
||||
FileModule::ModuleContainer::iterator curr = iter++;
|
||||
|
@ -237,17 +260,28 @@ bool FileModule::handleDependencies()
|
|||
if (!fullpath.empty()) filename = boosty::stringy(fullpath);
|
||||
}
|
||||
|
||||
curr->second = ModuleCache::instance()->evaluate(filename);
|
||||
if (curr->second != oldmodule) {
|
||||
FileModule *newmodule = ModuleCache::instance()->evaluate(filename);
|
||||
// Detect appearance but not removal of files
|
||||
if (newmodule && oldmodule != newmodule) {
|
||||
changed = true;
|
||||
#ifdef DEBUG
|
||||
PRINTB_NOCACHE(" %s: %p", filename % curr->second);
|
||||
PRINTB_NOCACHE(" %s: %p", filename % newmodule);
|
||||
#endif
|
||||
}
|
||||
if (!curr->second && !wasmissing) {
|
||||
if (newmodule) {
|
||||
modified_modules.push_back(std::make_pair(filename, newmodule));
|
||||
this->usedlibs.erase(curr);
|
||||
}
|
||||
else {
|
||||
// Only print warning if we're not part of an automatic reload
|
||||
if (!oldmodule && !wasmissing) {
|
||||
PRINTB_NOCACHE("WARNING: Failed to compile library '%s'.", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const FileModule::ModuleContainer::value_type &mod, modified_modules) {
|
||||
this->usedlibs[mod.first] = mod.second;
|
||||
}
|
||||
|
||||
this->is_handling_dependencies = false;
|
||||
return changed;
|
||||
|
@ -269,17 +303,3 @@ AbstractNode *FileModule::instantiate(const Context *ctx, const ModuleInstantiat
|
|||
|
||||
return node;
|
||||
}
|
||||
|
||||
bool FileModule::include_modified(IncludeFile inc)
|
||||
{
|
||||
struct stat st;
|
||||
memset(&st, 0, sizeof(struct stat));
|
||||
|
||||
fs::path fullpath = find_valid_path(this->path, inc.filename);
|
||||
bool valid = !fullpath.empty() ? (stat(boosty::stringy(fullpath).c_str(), &st) == 0) : false;
|
||||
|
||||
if (valid != inc.valid) return true;
|
||||
if (valid && st.st_mtime > inc.mtime) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
23
src/module.h
23
src/module.h
|
@ -77,12 +77,6 @@ public:
|
|||
LocalScope scope;
|
||||
};
|
||||
|
||||
struct IncludeFile {
|
||||
std::string filename;
|
||||
bool valid;
|
||||
time_t mtime;
|
||||
};
|
||||
|
||||
// FIXME: A FileModule doesn't have definition arguments, so we shouldn't really
|
||||
// inherit from a Module
|
||||
class FileModule : public Module
|
||||
|
@ -94,15 +88,28 @@ public:
|
|||
void setModulePath(const std::string &path) { this->path = path; }
|
||||
const std::string &modulePath() const { return this->path; }
|
||||
void registerInclude(const std::string &localpath, const std::string &fullpath);
|
||||
bool includesChanged() const;
|
||||
bool handleDependencies();
|
||||
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
|
||||
|
||||
bool hasIncludes() const { return !this->includes.empty(); }
|
||||
bool usesLibraries() const { return !this->usedlibs.empty(); }
|
||||
|
||||
|
||||
typedef boost::unordered_map<std::string, class FileModule*> ModuleContainer;
|
||||
ModuleContainer usedlibs;
|
||||
private:
|
||||
struct IncludeFile {
|
||||
std::string filename;
|
||||
bool valid;
|
||||
time_t mtime;
|
||||
};
|
||||
|
||||
bool include_modified(const IncludeFile &inc) const;
|
||||
|
||||
typedef boost::unordered_map<std::string, struct IncludeFile> IncludeContainer;
|
||||
IncludeContainer includes;
|
||||
bool include_modified(struct IncludeFile inc);
|
||||
private:
|
||||
|
||||
bool is_handling_dependencies;
|
||||
std::string path;
|
||||
};
|
||||
|
|
|
@ -26,13 +26,6 @@ o Open use-mcad.scad
|
|||
o Compile (F5)
|
||||
o Check that you get a rounded box
|
||||
|
||||
Test4: USE Non-existing file
|
||||
------
|
||||
|
||||
o Open usenonexsistingfile.scad
|
||||
o Compile (F5)
|
||||
o Verify that you get: WARNING: Can't open 'use' file 'nofile.scad'.
|
||||
|
||||
Test5: Overload USEd module
|
||||
------
|
||||
|
||||
|
@ -86,8 +79,11 @@ o Open includemissing.scad
|
|||
o Compile (F5)
|
||||
o Verify that you get: WARNING: Can't open include file 'missing.scad'.
|
||||
o echo "module missing() { sphere(10); }" > missing.scad
|
||||
o Reload and Compile (F4) - verify that the sphere appeared
|
||||
o rm missing.scad
|
||||
o Reload and Compile (F4) - verify that the sphere is gone
|
||||
o Reload and Compile (F4) - verify that the sphere is still there
|
||||
o echo "module missing() { sphere(20); }" > missing.scad
|
||||
o Reload and Compile (F4) - verify that the sphere increased in size
|
||||
|
||||
Test12: Missing include file in subpath appears
|
||||
------
|
||||
|
@ -96,25 +92,33 @@ o Open includemissingsub.scad
|
|||
o Compile (F5)
|
||||
o Verify that you get: WARNING: Can't open include file 'subdir/missingsub.scad'.
|
||||
o echo "module missingsub() { sphere(10); }" > subdir/missingsub.scad
|
||||
o Reload and Compile (F4) - verify that the sphere appeared
|
||||
o rm subdir/missingsub.scad
|
||||
o Reload and Compile (F4) - verify that the sphere is gone
|
||||
o Reload and Compile (F4) - verify that the sphere is still there
|
||||
o echo "module missingsub() { sphere(20); }" > subdir/missingsub.scad
|
||||
o Reload and Compile (F4) - verify that the sphere increased in size
|
||||
|
||||
Test13: Missing library file appears
|
||||
-------
|
||||
o rm missing.scad
|
||||
o Open usemissing.scad
|
||||
o Compile (F5)
|
||||
o Verify that you get: WARNING: Can't open 'use' file 'missing.scad'.
|
||||
o Verify that you get: WARNING: Can't open library file 'missing.scad'.
|
||||
o echo "module missing() { sphere(10); }" > missing.scad
|
||||
o Reload and Compile (F4) - verify that the sphere appeared
|
||||
o rm missing.scad
|
||||
o Compile (F5) - verify that the sphere is gone
|
||||
o Reload and Compile (F4) - verify that the sphere is still there
|
||||
o echo "module missing() { sphere(20); }" > missing.scad
|
||||
o Reload and Compile (F4) - verify that the sphere increased in size
|
||||
|
||||
Test14: Automatic reload of cascading changes
|
||||
-------
|
||||
|
||||
o rm cascade-*.scad
|
||||
o ./cascade.sh
|
||||
o Open cascadetest.scad
|
||||
o Turn on Automatic Reload and Compile
|
||||
o Verify that the 4 objects render correctly
|
||||
o ./cascade.sh
|
||||
o rm cascade-*.scad
|
||||
o Verify that no rerendering was triggered (the 4 objects are still there)
|
||||
o ./cascade2.sh
|
||||
o Verify that everything reloads at once without flickering
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm cascade-*.scad
|
||||
sleep 0.1
|
||||
echo "module A() { sphere(6); }" > cascade-A.scad
|
||||
sleep 0.1
|
||||
echo "module B() { cube([10,10,10], center=true); }" > cascade-B.scad
|
||||
sleep 0.1
|
||||
echo "module C() { cylinder(h=10, r=6, center=true); }" > cascade-C.scad
|
||||
sleep 0.1
|
||||
echo "module D() { cylinder(h=12, r1=6, r2=0, center=true); }" > cascade-D.scad
|
Loading…
Reference in New Issue