mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-14 12:28:56 +00:00
Scripts: File and Folder read files in the script's own folder
Scripts get the File and Folder classes as built-ins of the script engine. A script run from a file can test whether files exist, read their properties, list folders with getFiles (a mask or a function), and open files to read them with read, readln, readch, seek and tell. - Reads stay inside the script's folder and, when automation read roots are set, inside them too. A script given as text reads no files. Network and device paths, and paths outside the folder by their names, are refused before anything is looked up. Links and junctions that lead out are refused, and getFiles leaves them out. - The encoding comes from the byte order mark, then the encoding the script set, then UTF-8 when the bytes are valid, then CP1252. - Limits: 8 MiB a file, 32 MiB a run, 256 files open at once, 2,048 getFiles entries and 65,536 names looked at, and paths of at most 32,767 characters. - Writing, the file dialogs and execute are not available yet: they return false or null and set error. The report's hostCallCounts gains fileCalls and fileExecutes. Docs: docs/mcp.md, docs/target-app-parity.md.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -251,6 +251,11 @@ impl Files {
|
||||
self.include_path.join(";")
|
||||
}
|
||||
|
||||
/// The folders the run's own files are read from.
|
||||
pub(crate) fn scope(&self) -> &ScriptScope {
|
||||
&self.scope
|
||||
}
|
||||
|
||||
/// The script's own text, `text`, with its preprocessor lines read.
|
||||
pub(crate) fn expand_script(&mut self, text: &str) -> Result<Expanded, Failure> {
|
||||
self.bytes = self.bytes.saturating_add(text.len());
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
//!
|
||||
//! `alert`, `confirm` and `prompt` open dialogs ([`dialogs`]): in the app the run waits for the
|
||||
//! person's answer, and a run with nobody to ask takes its answers from `script.run`'s `answers`.
|
||||
//!
|
||||
//! `File` and `Folder` read files inside the script's own folder ([`files`]).
|
||||
|
||||
pub mod console;
|
||||
pub mod dialogs;
|
||||
@@ -56,6 +58,7 @@ use crate::{
|
||||
Clipboard, DocState, DrawMode, EngineError, Journal, NodeId, PaintDefaults, Result, Session, cmd, command_specs, guard, waits_for_tool_edit,
|
||||
};
|
||||
|
||||
pub mod files;
|
||||
pub mod folder;
|
||||
|
||||
/// The most bytes of source a run takes, as a file or as `source`.
|
||||
@@ -492,6 +495,8 @@ struct Host {
|
||||
dialogs: dialogs::Dialogs,
|
||||
/// The files the run reads: its includes and `$.evalFile`'s.
|
||||
files: RefCell<include::Files>,
|
||||
/// What `File` and `Folder` have open and have read.
|
||||
disk: RefCell<files::Disk>,
|
||||
/// Where the lines of the script's expanded source came from.
|
||||
script_map: RefCell<include::SourceMap>,
|
||||
/// The same for each source `$.evalFile` gave, in order.
|
||||
@@ -511,6 +516,10 @@ struct Counts {
|
||||
command_list_reads: Cell<u64>,
|
||||
vc_log: Cell<u64>,
|
||||
console_writes: Cell<u64>,
|
||||
/// Calls of `File` and `Folder` that reach the host ([`files`]).
|
||||
file_calls: Cell<u64>,
|
||||
/// `execute` calls, which open nothing.
|
||||
file_executes: Cell<u64>,
|
||||
}
|
||||
|
||||
impl Counts {
|
||||
@@ -521,6 +530,8 @@ impl Counts {
|
||||
"commandListReads": self.command_list_reads.get(),
|
||||
"vcLog": self.vc_log.get(),
|
||||
"consoleWrites": self.console_writes.get(),
|
||||
"fileCalls": self.file_calls.get(),
|
||||
"fileExecutes": self.file_executes.get(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1082,7 +1093,7 @@ fn kind_id(kind: &RunErrorKind) -> &'static str {
|
||||
|
||||
/// `message`, with what to do about a failure that comes from a script written for another program.
|
||||
fn explained(kind: &RunErrorKind, message: &str) -> String {
|
||||
const HOST_OBJECTS: &[&str] = &["app", "File", "Folder", "Window", "BridgeTalk", "activeDocument", "documents"];
|
||||
const HOST_OBJECTS: &[&str] = &["app", "Window", "BridgeTalk", "activeDocument", "documents"];
|
||||
let names_host_object =
|
||||
message.strip_prefix("ReferenceError: ").is_some_and(|m| HOST_OBJECTS.iter().any(|o| m.split_whitespace().next() == Some(o)));
|
||||
if *kind == RunErrorKind::Thrown && names_host_object {
|
||||
@@ -1311,6 +1322,7 @@ impl Session {
|
||||
commands: RefCell::default(),
|
||||
run_nanos: Cell::new(0),
|
||||
dialogs: dialogs::Dialogs::new(self.script_frames, &realm, request.answers),
|
||||
disk: RefCell::new(files::Disk::new(files.scope())),
|
||||
files: RefCell::new(files),
|
||||
script_map: RefCell::default(),
|
||||
eval_maps: RefCell::default(),
|
||||
@@ -1330,6 +1342,7 @@ impl Session {
|
||||
.define_host_object("vc", vc_object(&host, args))
|
||||
.and_then(|()| realm.define_host_object("$", dollar_object(&host)))
|
||||
.and_then(|()| dialogs::install(&mut realm, &host))
|
||||
.and_then(|()| files::install(&mut realm, &host))
|
||||
.and_then(|()| realm.start(&expanded.source))
|
||||
.map_err(|e| located(&host, realm.error_source(), realm.error_mark(), &e))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user