Lantern Terminal includes Lua 5.4.9 on Linux and Windows. Select Script → Run, choose a .lua file and supply any arguments. Logon scripts, saved script commands and –script also accept Lua. No separate Lua or Python installation is required.
local app = require("lantern").app local tab = app:GetScriptTab() tab.Screen:Send("printf '%s%s\\n' 'terminal-' 'ready'\r") assert(tab.Screen:WaitForString("terminal-ready", 5), "Endpoint did not respond") print(tab.Caption, tab.Screen.Rows, tab.Screen.Columns)
Use colon syntax for methods and dot syntax for properties. Split a test response across command arguments so the wait cannot match the echoed command itself. Each script stays attached to its originating tab when focus changes. A tab runs one script at a time. Script → Cancel terminates the worker and leaves the connection open. Output and tracebacks appear in Activity; errors open that pane automatically.
app.Version, app.Arguments.Count, app.Arguments:GetArg(0); argument indexes are zero-based. Lua arg[0] is the script filename and arg[1] is the first argument; … contains the arguments too.app:GetScriptTab(), app:GetActiveTab(), app:GetTabCount(), app:GetTab(1) (one-based), app:GetProfiles(), app:Sleep(milliseconds), app:Quit().id, Caption (writable), Index (one-based), Screen, Session.Activate(), Clone(), Close(), ConnectSftp(), ResetCaption(). Clone and SFTP return a new tab.tab:ZmodemUpload({path, …}) queues files that are sent when the host starts its Zmodem receiver (returns the number queued), tab:ZmodemCancel() stops a transfer, tab:ZmodemActive() is true while one runs. Downloads start by themselves.
Prefer GetScriptTab() for automation. GetActiveTab() deliberately targets the tab currently in focus.
Rows, Columns, CurrentRow, CurrentColumn, Selection, MatchIndex are read-only. Screen coordinates are one-based.Send(text) sends UTF-8 text through the session’s configured encoding. SendBytes(bytes) transmits the exact bytes, including NUL. Lua strings can hold binary data: screen:SendBytes(string.char(0, 255)).WaitForString(text, timeout, ignoreCase, milliseconds) returns a boolean. WaitForStrings({“ready”, “error”}, timeout, ignoreCase, milliseconds) returns a one-based match index or zero on timeout. The earliest incoming match wins; table order resolves ties.ReadString({“prompt> ”}, timeout, ignoreCase) returns text before the delimiter, excluding the delimiter, or an empty string on timeout. MatchIndex identifies the delimiter.milliseconds flag is true. Zero or omitted timeout waits until a match, disconnection or cancellation. app:Sleep always uses milliseconds.IgnoreCase enables Unicode case-insensitive matching. IgnoreEscape strips terminal escape sequences from captured text. Synchronous is always true; setting it false raises an error.Get2(top,left,bottom,right) preserves line separators; Get(…) concatenates the lines. Invalid coordinates raise an error.Clear(), WaitForCursor(timeout), SendKeys(text) and SendSpecial(action) provide terminal controls. SendKeys expands {ENTER}, {TAB}, {ESC}, {UP}, {DOWN}, {LEFT} and {RIGHT}; other text remains literal. SendSpecial uses application action identifiers.
Sending marks the incoming stream before transmission, retaining immediate replies. Successful waits consume through the matched delimiter. Matching uses the incoming text stream, rather than repeatedly searching old screen contents. Disconnection, locked sessions and capture-buffer overflow raise errors. Use pcall or xpcall when a script needs to recover.
tab.Session exposes Connected, Status, Path (saved profile ID), Logging, LogFileName (writable) and Config.
session:Connect(profile) and ConnectInTab(profile) open and return a new tab. Supply a saved profile ID string or a profile table.session:Disconnect() closes the connection.session:Log(true, append, raw) starts logging; Log(false) stops it. Set LogFileName first. raw=true records received bytes.config:GetOption(key), SetOption(key,value) and Save() access typed profile settings. Examples include fontSize, logPath, host, port, keyFile. Save() persists a saved profile. config:ConnectInTab() clones the configured tab.
app.Clipboard.Text reads/writes text. app.Dialog:MessageBox(text,title) shows a message; Prompt(text,title,default,password) returns text and a cancellation boolean. FileOpenDialog(title) returns the selected path or an empty string on cancellation. Dialogs run in the desktop application.
Standard Lua libraries are available. The entry script directory is added to package.path for local Lua modules. UTF-8 BOMs and an initial shebang are accepted. Use UTF-8 source and text strings.
For portable Unicode filenames, use the Qt-backed helpers:
local lantern = require("lantern") lantern.write_file("capture-café.txt", "saved bytes\0") local bytes = lantern.read_file("capture-café.txt")
These helpers preserve bytes, accept UTF-8 paths, cap each file at 16 MiB and raise errors on failure. Writes replace the file atomically. Ordinary Lua io functions follow the operating system’s filename conventions. Third-party binary Lua modules are not bundled.
Scripts execute with your user privileges, including standard Lua filesystem/process access. Run trusted code and review recordings for secrets. Do not embed passwords or key passphrases. The worker is a separate cancellable process, not a security sandbox.
Scripts written for the SyncTERM 1.9 Lua scripting fork run unchanged. The first time a script uses one of its global names (send, expect, screen, regex, bbs and so on), Lantern loads a compatibility layer that provides them on top of the API above. Ordinary Lantern scripts are not affected, and the same file still runs in SyncTERM.
Supported: expect, expect_pattern, expect_regex (PCRE2), must_expect, waitfor, readline, quiet, sleep, idle, set_timeout, on/off triggers, send, sendln, screen, screen_size, cursor, buffer, clear, raw, connected, disconnect, quit, now, message, input, confirm, log/print, regex.find/regex.match, the before/matched globals, script_path and the bbs table. They behave as in SyncTERM: received text has ANSI codes and stray control characters removed before matching, expect uses up text up to its match, quiet(s) waits at least s seconds of silence counted from the call, and the script stops when the connection closes.
bbs.user, bbs.name, bbs.address, bbs.port and bbs.conn_type come from the session (Username, name, Hostname, Port, Protocol: Telnet, RLogin, SSH2, Raw TCP). bbs.password is always nil.–script when opening a session, sees everything received since the connection started, like a SyncTERM dialing-directory script. A script started with Script → Run mid-session starts with an empty buffer, like SyncTERM's script hotkey.log and print write to the Activity pane. message, input and confirm show dialogs. For unattended runs, set syncterm_answers = {confirm = {…}, input = {…}, message = {…}} before the first SyncTERM call; each question takes the next answer.
Script → Record captures outgoing sends. Save as .lua to generate a Lua replay or .py for Python. Recordings distinguish text from raw byte sends and omit recognised secret-prompt input. They do not infer expected prompts or detect every secret; add waits and review before saving/sharing.
The bundled lantern-lua –version reports the runtime. The application supplies its private local API connection to workers; launching an automation script directly without those details produces an explicit connection error. Low-level lantern.rpc(operation, tabId, values) is available for application API operations; prefer the documented facade for normal scripts. The broader SCRIPTING-API.md describes a larger feature contract, not a promise that all its members are implemented.