From bf11b888c37dda8f446e8ad572c36f475132e9d2 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Tue, 11 Mar 2025 00:52:16 -0300 Subject: [PATCH] scripting tool: Use project buffers in `io.open` (#26425) This PR makes `io.open` use our own implementation again, but instead of the real filesystem, it will now use the project's to check file metadata and perform read and writes using project buffers. This also cleans up the `io.open` implementation by splitting it into multiple methods, adds tests for various File I/O patterns, and fixes a few bugs in read formats. Release Notes: - N/A --- Cargo.lock | 1 + crates/scripting_tool/Cargo.toml | 2 + .../scripting_tool/src/sandbox_preamble.lua | 17 +- crates/scripting_tool/src/scripting_tool.rs | 2 +- crates/scripting_tool/src/session.rs | 765 +++++++++++------- 5 files changed, 477 insertions(+), 310 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 582104b215c93f77c5845e58d26ef81260e00417..38859829b07183ac0ef3161b79553adb3e757e9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11918,6 +11918,7 @@ dependencies = [ "collections", "futures 0.3.31", "gpui", + "language", "log", "mlua", "parking_lot", diff --git a/crates/scripting_tool/Cargo.toml b/crates/scripting_tool/Cargo.toml index d2ee28b4e6c8d25116c456d5daa94146fe51c382..c02abcf650329ece391eafcb7482acf64bf3763f 100644 --- a/crates/scripting_tool/Cargo.toml +++ b/crates/scripting_tool/Cargo.toml @@ -17,6 +17,7 @@ anyhow.workspace = true collections.workspace = true futures.workspace = true gpui.workspace = true +language.workspace = true log.workspace = true mlua.workspace = true parking_lot.workspace = true @@ -31,6 +32,7 @@ util.workspace = true [dev-dependencies] collections = { workspace = true, features = ["test-support"] } gpui = { workspace = true, features = ["test-support"] } +language = { workspace = true, features = ["test-support"] } project = { workspace = true, features = ["test-support"] } rand.workspace = true settings = { workspace = true, features = ["test-support"] } diff --git a/crates/scripting_tool/src/sandbox_preamble.lua b/crates/scripting_tool/src/sandbox_preamble.lua index fe4445ed6a1d226776d8f1281e59887908d7eca3..5e31fbdd9539f2cc9fbc95d430b7546c488570d1 100644 --- a/crates/scripting_tool/src/sandbox_preamble.lua +++ b/crates/scripting_tool/src/sandbox_preamble.lua @@ -8,9 +8,9 @@ local sandbox = {} -- to our in-memory log rather than to stdout, we will delete this loop (and re-enable -- the I/O module being sandboxed below) to have things be sandboxed again. for k, v in pairs(_G) do - if sandbox[k] == nil then - sandbox[k] = v - end + if sandbox[k] == nil then + sandbox[k] = v + end end -- Allow access to standard libraries (safe subset) @@ -29,24 +29,27 @@ sandbox.search = search sandbox.outline = outline -- Create a sandboxed version of LuaFileIO -local io = {} +-- local io = {}; +-- +-- For now we are using unsandboxed io +local io = _G.io; -- File functions io.open = sb_io_open -- Add the sandboxed io library to the sandbox environment --- sandbox.io = io -- Uncomment this line to re-enable sandboxed file I/O. +sandbox.io = io -- Load the script with the sandbox environment local user_script_fn, err = load(user_script, nil, "t", sandbox) if not user_script_fn then - error("Failed to load user script: " .. tostring(err)) + error("Failed to load user script: " .. tostring(err)) end -- Execute the user script within the sandbox local success, result = pcall(user_script_fn) if not success then - error("Error executing user script: " .. tostring(result)) + error("Error executing user script: " .. tostring(result)) end diff --git a/crates/scripting_tool/src/scripting_tool.rs b/crates/scripting_tool/src/scripting_tool.rs index efb5c8855518351a118130d07b48a77b2db9de6f..3179467f26f8b1d0f670496f1256f098ea1a9f5e 100644 --- a/crates/scripting_tool/src/scripting_tool.rs +++ b/crates/scripting_tool/src/scripting_tool.rs @@ -36,7 +36,7 @@ impl ScriptingTool { }; // TODO: Store a session per thread - let session = cx.new(|cx| ScriptSession::new(project, cx)); + let session = cx.new(|cx| ScriptingSession::new(project, cx)); let lua_script = input.lua_script; let (script_id, script_task) = diff --git a/crates/scripting_tool/src/session.rs b/crates/scripting_tool/src/session.rs index 1f92214fe8a37ad19ac602d323aec74b26218d35..6cf862c669c1008ca9c92a6b03c29987428a5b2c 100644 --- a/crates/scripting_tool/src/session.rs +++ b/crates/scripting_tool/src/session.rs @@ -1,5 +1,5 @@ use anyhow::anyhow; -use collections::{HashMap, HashSet}; +use collections::HashSet; use futures::{ channel::{mpsc, oneshot}, pin_mut, SinkExt, StreamExt, @@ -7,32 +7,28 @@ use futures::{ use gpui::{AppContext, AsyncApp, Context, Entity, Task, WeakEntity}; use mlua::{ExternalResult, Lua, MultiValue, Table, UserData, UserDataMethods}; use parking_lot::Mutex; -use project::{search::SearchQuery, Fs, Project}; +use project::{search::SearchQuery, Fs, Project, ProjectPath, WorktreeId}; use regex::Regex; use std::{ - cell::RefCell, path::{Path, PathBuf}, sync::Arc, }; use util::{paths::PathMatcher, ResultExt}; -struct ForegroundFn(Box, AsyncApp) + Send>); +struct ForegroundFn(Box, AsyncApp) + Send>); -pub struct ScriptSession { +pub struct ScriptingSession { project: Entity, - // TODO Remove this - fs_changes: Arc>>>, foreground_fns_tx: mpsc::Sender, _invoke_foreground_fns: Task<()>, scripts: Vec