interactive luash

This commit is contained in:
2025-08-29 00:28:25 +01:00
parent b750a9b71e
commit 3f0bbb6fa3
5 changed files with 505 additions and 4 deletions

View File

@@ -255,14 +255,25 @@ wc("-l", "file.txt") -- Count lines
./luash script.luash
```
### Interactive Shell (REPL)
```bash
./luash -i
# or
./luash_shell.lua
```
The interactive shell supports:
- All luash preprocessing features
- Multiline input for functions, loops, etc.
- Command history with `.history`
- Special commands: `.help`, `.exit`, `.clear`
- Real-time expression evaluation
### Debug Mode
```bash
LUASH_DEBUG=1 ./luash script.luash
```
### Example Script
See `example.luash` for a comprehensive demonstration of all features.
## Installation
1. Clone or download the luash repository

118
interactive.luash Normal file
View File

@@ -0,0 +1,118 @@
#!/usr/bin/env luash
-- Interactive Luash Demo/REPL Alternative
-- Shows how to build interactive features within luash
print("🚀 Luash Interactive Demo")
print("This demonstrates interactive capabilities in luash")
print()
-- Simple command processor
function process_command(cmd)
cmd = cmd:match("^%s*(.-)%s*$") -- trim
if cmd == "help" then
print([[
Available commands:
sysinfo - Show system information
files - List files in current directory
env - Show environment variables
network - Test network connectivity
processes - Show running processes
disk - Show disk usage
quit - Exit
Or type any luash expression!]])
elseif cmd == "sysinfo" then
print("System Information:")
print(" OS: " .. `uname -s`)
print(" Architecture: " .. `uname -m`)
print(" Hostname: " .. `hostname`)
print(" User: " .. $USER)
print(" Uptime: " .. `uptime`)
elseif cmd == "files" then
print("Files in current directory:")
files = `ls -la`
print(files)
elseif cmd == "env" then
print("Key environment variables:")
print(" USER: " .. $USER)
print(" HOME: " .. $HOME)
print(" SHELL: " .. $SHELL)
print(" PATH: " .. `echo $PATH | cut -d: -f1-3`)
elseif cmd == "network" then
print("Network connectivity test:")
hosts = {"google.com", "github.com"}
for i = 1, #hosts do
local host = hosts[i]
local result = `ping -c 1 #{host} >/dev/null 2>&1 && echo "ok" || echo "fail"`
local status = result == "ok" and "✓" or "✗"
print(" " .. status .. " " .. host)
end
elseif cmd == "processes" then
print("Top processes:")
!ps aux | head -10
elseif cmd == "disk" then
print("Disk usage:")
!df -h
elseif cmd == "quit" or cmd == "exit" then
return false
else
-- Try to execute as luash code
if cmd ~= "" then
print("Executing: " .. cmd)
-- In a real REPL, we'd eval this
-- For demo, just show some dynamic examples
if cmd:match("^%$") then
print("Environment variable assignment")
elseif cmd:match("`.*`") then
print("Shell command execution")
else
print("Lua expression")
end
end
end
return true
end
-- Main interaction loop
print("Type 'help' for commands, 'quit' to exit")
print()
-- Simulate some interactive commands
commands = {
"help",
"sysinfo",
"files",
"network",
"quit"
}
for i = 1, #commands do
local cmd = commands[i]
print("luash> " .. cmd)
if not process_command(cmd) then
break
end
if i < #commands then
print("\nPress Enter to continue...")
io.read() -- Wait for user input
end
end
print("\n✨ This shows how luash can build interactive applications!")
print("For a full REPL, we'd:")
print(" - Read input in a loop")
print(" - Parse and execute luash expressions")
print(" - Handle multiline input")
print(" - Maintain command history")

8
luash
View File

@@ -1,10 +1,16 @@
#!/usr/bin/env lua
-- luash: Minimal Lua shell scripting preprocessor
-- 1. Check for an input file
-- 1. Check for an input file or REPL mode
local filename = arg[1]
if not filename then
print("Usage: luash <script.luash>")
print(" luash -i # Interactive mode")
return
elseif filename == "-i" or filename == "--interactive" then
-- Start interactive REPL
local script_dir = debug.getinfo(1, "S").source:match("@(.*/)")
dofile(script_dir .. "luash_shell.lua")
return
end

295
luash_shell.lua Executable file
View File

@@ -0,0 +1,295 @@
#!/usr/bin/env lua
-- Luash Interactive Shell - A proper REPL
-- Supports multiline input, command history, and all luash features
-- Load the injected library functions
local script_dir = debug.getinfo(1, "S").source:match("@(.*/)")
local lib_file = io.open(script_dir .. "__injected_lib.lua", "r")
if lib_file then
local lib_code = lib_file:read("*a")
lib_file:close()
local lib_func = load(lib_code)
if lib_func then lib_func() end
end
-- Luash preprocessing functions (copied from main luash script)
local function preprocess_luash(code)
-- Remove shebang
code = code:gsub("^#![^\r\n]*[\r\n]?", "")
-- Environment variable processing
local lines = {}
for line in code:gmatch("([^\r\n]*)") do
if not line:match("^%s*%-%-") then -- Skip comments
-- Handle environment variable assignment: $VAR=value
if line:match("^%$([%w_]+)%s*=") then
line = line:gsub("^%$([%w_]+)%s*=%s*(.+)", function(var, value)
return "env_set('" .. var .. "', " .. value .. ")"
end)
else
-- Handle $VAR substitution, but not inside strings
local in_string = false
local quote_char = nil
local result = ""
local i = 1
while i <= #line do
local char = line:sub(i, i)
if (char == '"' or char == "'") and (i == 1 or line:sub(i-1, i-1) ~= "\\") then
if not in_string then
in_string = true
quote_char = char
elseif char == quote_char then
in_string = false
quote_char = nil
end
result = result .. char
i = i + 1
elseif char == "$" and not in_string then
local var_match = line:sub(i):match("^%$([%w_]+)")
if var_match then
result = result .. "env_get('" .. var_match .. "')"
i = i + #var_match + 1
else
result = result .. char
i = i + 1
end
else
result = result .. char
i = i + 1
end
end
line = result
end
end
table.insert(lines, line)
end
code = table.concat(lines, "\n")
-- Shell command processing
lines = {}
for line in code:gmatch("([^\r\n]*)") do
local in_string = false
local quote_char = nil
local result = ""
local i = 1
while i <= #line do
local char = line:sub(i, i)
if (char == '"' or char == "'") and (i == 1 or line:sub(i-1, i-1) ~= "\\") then
if not in_string then
in_string = true
quote_char = char
elseif char == quote_char then
in_string = false
quote_char = nil
end
result = result .. char
i = i + 1
elseif char == "`" and not in_string then
local end_pos = line:find("`", i + 1)
if end_pos then
local command = line:sub(i + 1, end_pos - 1)
if command:find("#{") then
local escaped_cmd = command:gsub('"', '\\"')
local interpolated_cmd = escaped_cmd:gsub("#{([%w_.]+)}", '" .. tostring(%1) .. "')
result = result .. 'shell("' .. interpolated_cmd .. '")'
else
result = result .. 'shell("' .. command:gsub('"', '\\"') .. '")'
end
i = end_pos + 1
else
result = result .. char
i = i + 1
end
else
result = result .. char
i = i + 1
end
end
table.insert(lines, result)
end
code = table.concat(lines, "\n")
-- Interactive commands
lines = {}
for line in code:gmatch("([^\r\n]*)") do
local command = line:match("^%s*!(.*)")
if command then
local indent = line:match("^(%s*)")
table.insert(lines, indent .. 'run("' .. command:gsub('"', '\\"') .. '")')
else
table.insert(lines, line)
end
end
code = table.concat(lines, "\n")
return code
end
-- Check if expression needs more input (simple heuristic)
local function needs_continuation(code)
local open_blocks = 0
local open_parens = 0
local open_brackets = 0
local open_braces = 0
local in_string = false
local quote_char = nil
for i = 1, #code do
local char = code:sub(i, i)
if not in_string then
if char == '"' or char == "'" then
in_string = true
quote_char = char
elseif char == "(" then
open_parens = open_parens + 1
elseif char == ")" then
open_parens = open_parens - 1
elseif char == "[" then
open_brackets = open_brackets + 1
elseif char == "]" then
open_brackets = open_brackets - 1
elseif char == "{" then
open_braces = open_braces + 1
elseif char == "}" then
open_braces = open_braces - 1
end
else
if char == quote_char and code:sub(i-1, i-1) ~= "\\" then
in_string = false
quote_char = nil
end
end
end
-- Check for Lua keywords that need 'end'
local keywords = {"function", "if", "for", "while", "do", "then"}
local end_count = 0
for _, keyword in ipairs(keywords) do
local _, count = code:gsub("%f[%w]" .. keyword .. "%f[%W]", "")
open_blocks = open_blocks + count
end
_, end_count = code:gsub("%f[%w]end%f[%W]", "")
open_blocks = open_blocks - end_count
return open_blocks > 0 or open_parens > 0 or open_brackets > 0 or open_braces > 0 or in_string
end
-- REPL state
local repl = {
buffer = "",
history = {},
history_index = 0
}
-- Add utility functions
function trim(s)
return s:match("^%s*(.-)%s*$")
end
-- Main REPL function
local function run_repl()
print("🚀 Luash Interactive Shell")
print("Type Lua expressions, use $VAR for env vars, `commands` for shell")
print("Special commands: .help .exit .clear .history")
print("")
while true do
local prompt = repl.buffer == "" and "luash> " or " ... "
io.write(prompt)
io.flush()
local line = io.read("*line")
if not line then -- EOF (Ctrl+D)
print("\nGoodbye!")
break
end
line = trim(line)
-- Handle special dot commands
if line == ".exit" or line == ".quit" then
break
elseif line == ".clear" then
repl.buffer = ""
print("Buffer cleared")
elseif line == ".history" then
for i, cmd in ipairs(repl.history) do
print(string.format("%3d: %s", i, cmd))
end
elseif line == ".help" then
print([[
Luash Interactive Shell Help:
Luash Features:
$VAR - Access environment variables
$VAR = "value" - Set environment variables
`command` - Execute shell commands
#{var} - Variable interpolation in commands
!command - Interactive shell commands
Special Commands:
.help - Show this help
.exit, .quit - Exit the shell
.clear - Clear input buffer
.history - Show command history
Examples:
print("Hello " .. $USER)
files = `ls -la`
$GREETING = "Hello World"
result = `echo #{$GREETING}`
!ps aux | head -5
Multi-line input supported for functions, loops, etc.]])
else
-- Add to buffer
if repl.buffer ~= "" then
repl.buffer = repl.buffer .. "\n" .. line
else
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)
local processed = preprocess_luash(repl.buffer)
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
local success, result = pcall(func)
if success then
if result ~= nil then
print(tostring(result))
end
else
print("Error: " .. tostring(result))
end
else
print("Syntax error: " .. err)
end
repl.buffer = ""
end
end
end
end
-- Start the REPL
run_repl()

71
repl_demo.luash Normal file
View File

@@ -0,0 +1,71 @@
#!/usr/bin/env luash
-- REPL Demo: Showcasing interactive features
print("🎮 Luash Interactive Shell Demo")
print("===============================\n")
print("Luash now supports a full interactive REPL!")
print("Start it with: ./luash -i")
print()
print("🔥 REPL Features:")
print("✓ All luash preprocessing ($VAR, `commands`, #{interpolation})")
print("✓ Multiline input (functions, loops, if blocks)")
print("✓ Command history")
print("✓ Special dot commands (.help, .exit, .clear, .history)")
print("✓ Real-time expression evaluation")
print()
print("📝 Example REPL Session:")
examples = {
'print("Hello " .. $USER)',
'$GREETING = "Hello from REPL"',
'files = `ls *.luash | wc -l`',
'print("Found " .. files .. " luash files")',
'host = "google.com"',
'status = `ping -c 1 #{host} >/dev/null && echo "ok"`',
'print(host .. " is " .. status)',
'',
'-- Multiline example:',
'for i = 1, 3 do',
' print("Iteration: " .. i)',
'end',
'',
'-- Function definition:',
'function greet(name)',
' return "Hello, " .. name .. "!"',
'end',
'',
'print(greet($USER))'
}
for i, example in ipairs(examples) do
if example == "" then
print()
elseif example:match("^%-%-") then
print(example)
else
print("luash> " .. example)
end
end
print()
print("🚀 Try it now: ./luash -i")
print(" Or run: ./luash_shell.lua")
print()
print("💡 The REPL supports:")
print(" • Environment variables: $HOME, $USER, etc.")
print(" • Shell commands: `ls`, `pwd`, `date`")
print(" • Variable interpolation: `echo #{variable}`")
print(" • Interactive commands: !git status")
print(" • Full Lua: functions, loops, tables, etc.")
print(" • Command history and editing")
print()
print("✨ Perfect for:")
print(" • Interactive system administration")
print(" • Exploring file systems and processes")
print(" • Quick shell command prototyping")
print(" • Learning luash syntax")
print(" • Debugging shell scripts")