@@ -7,7 +7,7 @@ use futures::{
};
use gpui::{AppContext, AsyncApp, Context, Entity, Task, WeakEntity};
use language::Buffer;
-use mlua::{ExternalResult, Lua, MultiValue, Table, UserData, UserDataMethods};
+use mlua::{ExternalResult, Lua, MultiValue, ObjectLike, Table, UserData, UserDataMethods};
use parking_lot::Mutex;
use project::{search::SearchQuery, Fs, Project, ProjectPath, WorktreeId};
use regex::Regex;
@@ -308,6 +308,10 @@ impl ScriptingSession {
let read_fn = lua.create_function(Self::io_file_read)?;
file.set("read", read_fn)?;
+ // lines method
+ let lines_fn = lua.create_function(Self::io_file_lines)?;
+ file.set("lines", lines_fn)?;
+
// write method
let write_fn = lua.create_function(Self::io_file_write)?;
file.set("write", write_fn)?;
@@ -566,6 +570,17 @@ impl ScriptingSession {
}
}
+ fn io_file_lines(lua: &Lua, file_userdata: Table) -> mlua::Result<mlua::Function> {
+ let read_perm = file_userdata.get::<bool>("__read_perm")?;
+ if !read_perm {
+ return Err(mlua::Error::runtime("File not open for reading"));
+ }
+
+ lua.create_function::<_, _, mlua::Value>(move |lua, _: ()| {
+ file_userdata.call_method("read", lua.create_string("*l")?)
+ })
+ }
+
fn io_file_read_format(format: Option<mlua::Value>) -> mlua::Result<FileReadFormat> {
let format = match format {
Some(mlua::Value::String(s)) => {
@@ -991,6 +1006,34 @@ mod tests {
assert_eq!(test_session.diff(cx), Vec::new());
}
+ #[gpui::test]
+ async fn test_lines_iterator(cx: &mut TestAppContext) {
+ let script = r#"
+ -- Create a test file with multiple lines
+ local file = io.open("lines_test.txt", "w")
+ file:write("Line 1\nLine 2\nLine 3\nLine 4\nLine 5")
+ file:close()
+
+ -- Read it back using the lines iterator
+ local read_file = io.open("lines_test.txt", "r")
+ local count = 0
+ for line in read_file:lines() do
+ count = count + 1
+ print(count .. ": " .. line)
+ end
+ read_file:close()
+
+ print("Total lines:", count)
+ "#;
+
+ let test_session = TestSession::init(cx).await;
+ let output = test_session.test_success(script, cx).await;
+ assert_eq!(
+ output,
+ "1: Line 1\n2: Line 2\n3: Line 3\n4: Line 4\n5: Line 5\nTotal lines:\t5\n"
+ );
+ }
+
#[gpui::test]
async fn test_read_write_roundtrip(cx: &mut TestAppContext) {
let script = r#"
@@ -15,7 +15,7 @@ pub struct ScriptingTool;
impl ScriptingTool {
pub const NAME: &str = "lua-interpreter";
- pub const DESCRIPTION: &str = include_str!("scripting_tool_description.txt");
+ pub const DESCRIPTION: &str = include_str!("scripting_tool_description.md");
pub fn input_schema() -> serde_json::Value {
let schema = schemars::schema_for!(ScriptingToolInput);
@@ -0,0 +1,21 @@
+Evaluates the given Lua script in an interpreter with access to the Lua standard library. The tool returns the scripts output to stdout and any error that may have occurred.
+
+Use this tool to explore the current project and edit the user's codebase or operating system as requested.
+
+Additional functions provided:
+
+```lua
+--- Search for matches of a regular expression in files.
+-- @param pattern The regex pattern to search for (uses Rust's regex syntax)
+-- @return An array of tables with 'path' (file path) and 'matches' (array of matching strings)
+-- @usage local results = search("function\\s+\\w+")
+function search(pattern)
+ -- Implementation provided by the tool
+end
+
+--- Generates an outline for the given file path, extracting top-level symbols such as functions, classes, exports, and other significant declarations. This provides a structural overview of the file's contents.
+-- @param path
+function outline(path)
+ -- Implementation provided by the tool
+end
+```
@@ -1,22 +0,0 @@
-You can write a Lua script and I'll run it on my codebase and tell you what its
-output was, including both stdout as well as the git diff of changes it made to
-the filesystem. That way, you can get more information about the code base, or
-make changes to the code base directly.
-
-The Lua script will have access to `io` and it will run with the current working
-directory being in the root of the code base, so you can use it to explore,
-search, make changes, etc. You can also have the script print things, and I'll
-tell you what the output was. Note that `io` only has `open`, and then the file
-it returns only has the methods read, write, and close - it doesn't have popen
-or anything else.
-
-Also, I'm going to be putting this Lua script into JSON, so please don't use
-Lua's double quote syntax for string literals - use one of Lua's other syntaxes
-for string literals, so I don't have to escape the double quotes.
-
-There will be a global called `search` which accepts a regex (it's implemented
-using Rust's regex crate, so use that regex syntax) and runs that regex on the
-contents of every file in the code base (aside from gitignored files), then
-returns an array of tables with two fields: "path" (the path to the file that
-had the matches) and "matches" (an array of strings, with each string being a
-match that was found within the file).