-
Notifications
You must be signed in to change notification settings - Fork 35
/
Copy pathscript.hpp
211 lines (174 loc) · 5.62 KB
/
script.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
#pragma once
#define QSCRIPTS_LOCAL ".qscripts"
static constexpr char UNLOAD_SCRIPT_FUNC_NAME[] = "__quick_unload_script";
static constexpr auto DEFAULT_CELLS_RE = R"(\d{4}.*\.py$)";
//-------------------------------------------------------------------------
// File modification state
enum class filemod_status_e
{
not_found,
not_modified,
modified
};
// Structure to describe a file and its metadata
struct fileinfo_t
{
qstring file_path;
qtime64_t modified_time;
fileinfo_t(const char* file_path = nullptr): modified_time(0)
{
if (file_path != nullptr)
this->file_path = file_path;
}
inline const bool empty() const
{
return file_path.empty();
}
inline const char* c_str()
{
return file_path.c_str();
}
bool operator==(const fileinfo_t &rhs) const
{
return file_path == rhs.file_path;
}
virtual void clear()
{
file_path.clear();
modified_time = 0;
}
bool refresh(const char *file_path = nullptr)
{
if (file_path != nullptr)
this->file_path = file_path;
return get_file_modification_time(this->file_path, &modified_time);
}
// Checks if the current script has been modified
// Optionally updates the time stamp to the latest one if modified
filemod_status_e get_modification_status(bool update_mtime=true)
{
qtime64_t cur_mtime;
const char *script_file = this->file_path.c_str();
if (!get_file_modification_time(script_file, &cur_mtime))
{
if (update_mtime)
modified_time = 0;
return filemod_status_e::not_found;
}
// Script is up to date, no need to execute it again
if (cur_mtime == modified_time)
return filemod_status_e::not_modified;
if (update_mtime)
modified_time = cur_mtime;
return filemod_status_e::modified;
}
void invalidate()
{
modified_time = 0;
}
};
//-------------------------------------------------------------------------
// Dependency script info
struct script_info_t: fileinfo_t
{
using fileinfo_t::fileinfo_t;
// Each dependency script can have its own reload command
qstring reload_cmd;
// Base path if this dependency is part of a package
qstring pkg_base;
const bool has_reload_directive() const { return !reload_cmd.empty(); }
};
// Script files
using scripts_info_t = qvector<script_info_t>;
//-------------------------------------------------------------------------
// Notebook context
struct notebook_ctx_t
{
enum activate_action_e
{
act_exec_none,
act_exec_main,
act_exec_all
};
std::string base_path;
std::string title;
std::regex cells_re = std::regex(DEFAULT_CELLS_RE);
std::map<std::string, qtime64_t> cell_files;
std::string last_active_cell;
int activation_action = act_exec_none;
void clear()
{
title.clear();
cell_files.clear();
last_active_cell.clear();
cells_re = std::regex(DEFAULT_CELLS_RE);
}
};
//-------------------------------------------------------------------------
// Active script information along with its dependencies
struct active_script_info_t : script_info_t
{
// Notebook options
bool b_is_notebook = false;
const bool is_notebook() const {
return b_is_notebook;
}
notebook_ctx_t notebook;
// Trigger file options
fileinfo_t trigger_file;
bool b_keep_trigger_file;
// The dependencies index files. First entry is for the main script's deps
qvector<fileinfo_t> dep_indices;
// The list of dependency scripts
std::unordered_map<std::string, script_info_t> dep_scripts;
// Checks to see if we have a dependency on a given file
const script_info_t* has_dep(const qstring& dep_file) const
{
auto p = dep_scripts.find(dep_file.c_str());
return p == dep_scripts.end() ? nullptr : &p->second;
}
// Is this trigger based or dependency based?
const bool trigger_based() const { return !trigger_file.empty(); }
// If no dependency index files have been modified, return 0.
// Return 1 if one of them has been modified or -1 if one of them has gone missing.
// In both latter cases, we have to recompute our dependencies
filemod_status_e is_any_dep_index_modified(bool update_mtime = true)
{
filemod_status_e r = filemod_status_e::not_modified;
for (auto& dep_file : dep_indices)
{
r = dep_file.get_modification_status(update_mtime);
if (r != filemod_status_e::not_modified)
break;
}
return r;
}
bool add_dep_index(const char* dep_file)
{
fileinfo_t fi;
if (!get_file_modification_time(dep_file, &fi.modified_time))
return false;
fi.file_path = dep_file;
dep_indices.push_back(std::move(fi));
return true;
}
void clear() override
{
script_info_t::clear();
dep_indices.qclear();
dep_scripts.clear();
trigger_file.clear();
b_keep_trigger_file = false;
b_is_notebook = false;
notebook.clear();
reload_cmd.clear();
pkg_base.clear();
}
void invalidate_all_scripts()
{
invalidate();
// Invalidate all but the index file itself
for (auto& kv : dep_scripts)
kv.second.invalidate();
}
};