diff --git a/README.md b/README.md index b196a8f..2bf6b62 100644 --- a/README.md +++ b/README.md @@ -110,144 +110,20 @@ Explore organized examples that demonstrate Luash features: See [examples/README.md](examples/README.md) for the complete learning path. -### What You Get +### Built-ins -#### File System Operations -```lua --- Check file existence -if fs.exists("config.txt") then - content = fs.read("config.txt") -end - --- File operations -fs.write("output.txt", "Hello World") -fs.append("log.txt", "New entry\n") - --- Advanced file operations -file.copy("source.txt", "backup.txt") -file.move("old.txt", "new.txt") -lines = file.lines("data.txt") -- Read as array of lines -``` - -#### Directory Operations -```lua --- Directory management -dir.create("new_folder") -- mkdir -p equivalent -files = dir.list("/tmp") -- List directory contents -current = dir.pwd() -- Get current directory - --- Convenience aliases -mkdir("test") -cd("/home/user") -ls("/var/log") -``` - -#### String Utilities -```lua --- String manipulation -parts = str.split("a,b,c", ",") -clean = str.trim(" whitespace ") -bool = str.starts_with("hello", "hel") - --- Text processing -result = text.grep("pattern", "file.txt") -lines = text.head(10, "large_file.txt") -count = text.wc("-l", "data.txt") -- Line count -``` - -#### Array/Table Operations -```lua --- Array utilities -found = array.contains({"a", "b", "c"}, "b") -doubled = array.map({1, 2, 3}, function(x) return x * 2 end) -evens = array.filter({1, 2, 3, 4}, function(x) return x % 2 == 0 end) -``` - -#### Path Utilities -```lua --- Path manipulation -full_path = path.join("/usr", "local", "bin", "luash") -dir_name = path.dirname("/path/to/file.txt") -- "/path/to" -base_name = path.basename("/path/to/file.txt") -- "file.txt" -extension = path.ext("document.pdf") -- "pdf" -``` - -#### System Information -```lua --- System utilities -os_name = sys.os() -- "linux", "darwin", etc. -arch = sys.arch() -- "x86_64", "arm64", etc. -hostname = sys.hostname() -- Get machine name -user = sys.whoami() -- Current username -memory_info = sys.memory() -- Memory usage -disk_info = sys.disk("/") -- Disk usage -``` - -#### Network Operations -```lua --- Network utilities -success = net.download("https://example.com/file.txt", "local_file.txt") -response = net.get("https://api.example.com/data") -post_result = net.post("https://api.example.com/submit", "key=value") -reachable = net.ping("google.com", 3) -- Ping 3 times -``` - -#### Process Management -```lua --- Process operations -my_pid = proc.pid() -git_path = proc.which("git") -- Find executable path - --- Job control -job.background("long_running_command") -job.kill(1234, "TERM") -- Kill process by PID -job.killall("firefox") -- Kill all processes by name -processes = job.ps() -- Get process list -``` - -#### Logging and Colors -```lua --- Colored logging -log.info("Information message") -log.warn("Warning message") -log.error("Error message") -log.success("Success message") - --- Color output -print(color.red("Error text")) -print(color.green("Success text")) -print(color.bold(color.yellow("Important notice"))) -``` - -#### Archive Operations -```lua --- Compression utilities -archive.tar_create("backup.tar.gz", {"file1.txt", "file2.txt"}) -archive.tar_extract("backup.tar.gz", "/destination") -archive.zip_create("archive.zip", {"folder1", "folder2"}) -archive.zip_extract("archive.zip", "/extract_here") -``` - -### Convenience Aliases - -Common shell commands are available as Lua functions: +Luash intentionally stays minimal. The injected helpers are: ```lua -ls() -- ls -la -pwd() -- Get current directory -cd("/path") -- Change directory -mkdir("folder") -- Create directory -rm("file") -- Remove file -cp("src", "dst") -- Copy file -mv("old", "new") -- Move/rename file -cat("file.txt") -- Read file contents -echo("Hello") -- Print and return text -grep("pattern", "file.txt") -- Search in file -head(5, "file.txt") -- First 5 lines -tail(10, "file.txt") -- Last 10 lines -wc("-l", "file.txt") -- Count lines +-- Minimal helpers available globally +env_get(name) -- Get environment variable (with session overrides) +env_set(name, value) -- Set environment variable (session + subprocess export) +shell(cmd) -- Run shell command and return trimmed stdout +run(cmd) -- Run shell command and stream output (exit code returned) ``` +Everything else is standard Lua. + ## Usage ### Basic Usage @@ -266,7 +142,6 @@ The interactive shell supports: - All luash preprocessing features - Multiline input for functions, loops, etc. - Command history with `.history` -- Screen clearing with `.clear` - Special commands: `.help`, `.exit`, `.clear` - Real-time expression evaluation @@ -329,13 +204,14 @@ file.write_lines("output.txt", processed) ## Preprocessor Pipeline -Luash applies several preprocessing steps: +Luash applies these preprocessing steps: -1. **Environment Variable Substitution**: `$VAR` and `${VAR}` → `env.get('VAR')` -2. **Interactive Command Processing**: `!command` → `run('command')` -3. **Shell Command Substitution**: `` `command` `` → `shell('command')` -4. **Variable Interpolation**: `#{var}` in commands → Lua string concatenation -5. **Library Injection**: Comprehensive shell utilities loaded automatically +1. **Shebang removal (line-preserving)**: `#!/usr/bin/env luash` is removed and replaced by a blank line to preserve line numbers. +2. **Environment variable assignment**: `$VAR = value` → `env_set('VAR', value)` (outside strings only) +3. **Environment variable substitution**: `$VAR` → `env_get('VAR')` (outside strings only; `${VAR}` is not supported) +4. **Interactive commands**: lines starting with `!cmd` → `run("cmd")` +5. **Command substitution**: `` `command` `` → `shell("command")` +6. **Lua variable interpolation in commands**: inside backticks, `#{var}` is replaced with the Lua value of `var`, with proper quoting handled by the caller ## License diff --git a/luash b/luash index 5bda66c..8afb447 100755 --- a/luash +++ b/luash @@ -273,20 +273,44 @@ Multi-line input supported for functions, loops, etc.]]) repl.buffer = line end - -- Check if we have a complete expression - if not needs_continuation(repl.buffer) and line ~= "" then - -- Process and execute - table.insert(repl.history, repl.buffer) - + -- Try to compile to determine if we need continuation (parser-driven) + if line ~= "" then local processed = preprocess_luash_repl(repl.buffer) + + -- First, try as an expression (so results print automatically) local func, err = load("return " .. processed, "@repl") - if not func then - -- Try without return (for statements) - func, err = load(processed, "@repl") - end - - if func then + if err and err:match("") then + -- Incomplete chunk; wait for more input + -- keep buffer as-is + else + -- Try as a statement block + func, err = load(processed, "@repl") + if not func then + if err and err:match("") then + -- Incomplete; wait for more input + else + -- Definitive syntax error; report and clear buffer + print("Syntax error: " .. err) + repl.buffer = "" + end + else + -- Executable statement block + table.insert(repl.history, repl.buffer) + local success, result = pcall(func) + if success then + if result ~= nil then + print(tostring(result)) + end + else + print("Error: " .. tostring(result)) + end + repl.buffer = "" + end + end + else + -- Executable expression + table.insert(repl.history, repl.buffer) local success, result = pcall(func) if success then if result ~= nil then @@ -295,11 +319,8 @@ Multi-line input supported for functions, loops, etc.]]) else print("Error: " .. tostring(result)) end - else - print("Syntax error: " .. err) + repl.buffer = "" end - - repl.buffer = "" end end end