2
2
mirror of https://github.com/Hilbis/Hilbish synced 2025-07-01 16:52:03 +00:00
Hilbish/nature/hilbish.lua

234 lines
6.4 KiB
Lua

-- @module hilbish
local bait = require 'bait'
local fs = require 'fs'
local readline = require 'readline'
local snail = require 'snail'
hilbish.snail = snail.new()
hilbish.snail:run 'true' -- to "initialize" snail
bait.catch('hilbish.cd', function(path)
hilbish.snail:dir(path)
end)
local function abbrevHome(path)
if path:sub(1, hilbish.home:len()) == hilbish.home then
return fs.join('~', path:sub(hilbish.home:len() + 1))
end
return path
end
local function expandHome(path)
if path:sub(1, 1) == '~' then
return fs.join(hilbish.home, path:sub(2))
end
return path
end
local function fmtPrompt(p)
return p:gsub('%%(%w)', function(c)
if c == 'd' then
return abbrevHome(hilbish.cwd())
elseif c == 'D' then
return fs.basename(abbrevHome(hilbish.cwd()))
elseif c == 'u' then
return hilbish.user
elseif c == 'h' then
return hilbish.host
end
end)
end
--- prompt(str, typ)
--- Changes the shell prompt to the provided string.
--- There are a few verbs that can be used in the prompt text.
--- These will be formatted and replaced with the appropriate values.
--- `%d` - Current working directory
--- `%D` - Basename of working directory ()
--- `%u` - Name of current user
--- `%h` - Hostname of device
--- #param str string
--- #param typ? string Type of prompt, being left or right. Left by default.
--- #example
--- -- the default hilbish prompt without color
--- hilbish.prompt '%u %d ∆'
--- -- or something of old:
--- hilbish.prompt '%u@%h :%d $'
--- -- prompt: user@hostname: ~/directory $
--- #example
-- @param p string
-- @param typ string Type of prompt, either left or right
function hilbish.prompt(p, typ)
if type(p) ~= 'string' then
error('expected #1 to be string, got ' .. type(p))
end
if not typ or typ == 'left' then
hilbish.editor:prompt(fmtPrompt(p))
if not hilbish.running then
hilbish.editor:refreshPrompt()
end
elseif typ == 'right' then
hilbish.editor:rightPrompt(fmtPrompt(p))
if not hilbish.running then
hilbish.editor:refreshPrompt()
end
else
error('expected prompt type to be right or left, got ' .. tostring(typ))
end
end
local pathSep = ':'
if hilbish.os.family == 'windows' then
pathSep = ';'
end
local function appendPath(path)
os.setenv('PATH', os.getenv 'PATH' .. pathSep .. expandHome(path))
end
--- appendPath(path)
--- Appends the provided dir to the command path (`$PATH`)
--- @param path string|table Directory (or directories) to append to path
--- #example
--- hilbish.appendPath '~/go/bin'
--- -- Will add ~/go/bin to the command path.
---
--- -- Or do multiple:
--- hilbish.appendPath {
--- '~/go/bin',
--- '~/.local/bin'
--- }
--- #example
function hilbish.appendPath(path)
if type(path) == 'table' then
for _, p in ipairs(path) do
appendPath(p)
end
elseif type(path) == 'string' then
appendPath(path)
else
error('bad argument to appendPath (expected string or table, got ' .. type(path) .. ')')
end
end
local function prependPath(path)
print('prepending', path, expandHome(path))
os.setenv('PATH', expandHome(path) .. pathSep .. os.getenv 'PATH')
end
--- prependPath(path)
--- Prepends the provided dir to the command path (`$PATH`)
--- @param path string|table Directory (or directories) to append to path
--- #example
--- hilbish.prependPath '~/go/bin'
--- -- Will add ~/go/bin to the command path.
---
--- -- Or do multiple:
--- hilbish.prependPath {
--- '~/go/bin',
--- '~/.local/bin'
--- }
--- #example
function hilbish.prependPath(path)
if type(path) == 'table' then
for _, p in ipairs(path) do
prependPath(p)
end
elseif type(path) == 'string' then
prependPath(path)
else
error('bad argument to prependPath (expected string or table, got ' .. type(path) .. ')')
end
end
--- read(prompt) -> input (string)
--- Read input from the user, using Hilbish's line editor/input reader.
--- This is a separate instance from the one Hilbish actually uses.
--- Returns `input`, will be nil if Ctrl-D is pressed, or an error occurs.
-- @param prompt? string Text to print before input, can be empty.
-- @returns string|nil
function hilbish.read(prompt)
prompt = prompt or ''
if type(prompt) ~= 'string' then
error 'expected #1 to be a string'
end
local rl = readline.new()
rl:prompt(prompt)
return rl:read()
end
--- Runs `cmd` in Hilbish's shell script interpreter.
--- The `streams` parameter specifies the output and input streams the command should use.
--- For example, to write command output to a sink.
--- As a table, the caller can directly specify the standard output, error, and input
--- streams of the command with the table keys `out`, `err`, and `input` respectively.
--- As a boolean, it specifies whether the command should use standard output or return its output streams.
--- #example
--- -- This code is the same as `ls -l | wc -l`
--- local fs = require 'fs'
--- local pr, pw = fs.pipe()
--- hilbish.run('ls -l', {
--- stdout = pw,
--- stderr = pw,
--- })
--- pw:close()
--- hilbish.run('wc -l', {
--- stdin = pr
--- })
--- #example
-- @param cmd string
-- @param streams table|boolean
-- @returns number, string, string
function hilbish.run(cmd, streams)
local sinks = {}
if type(streams) == 'boolean' then
if not streams then
sinks = {
out = hilbish.sink.new(),
err = hilbish.sink.new(),
input = io.stdin
}
end
elseif type(streams) == 'table' then
sinks = streams
end
local out = hilbish.snail:run(cmd, {sinks = sinks})
local returns = {out.exitCode}
if type(streams) == 'boolean' and not streams then
table.insert(returns, sinks.out:readAll())
table.insert(returns, sinks.err:readAll())
end
return table.unpack(returns)
end
--- Sets the execution/runner mode for interactive Hilbish.
--- **NOTE: This function is deprecated and will be removed in 3.0**
--- Use `hilbish.runner.setCurrent` instead.
--- This determines whether Hilbish wll try to run input as Lua
--- and/or sh or only do one of either.
--- Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
--- sh, and lua. It also accepts a function, to which if it is passed one
--- will call it to execute user input instead.
--- Read [about runner mode](../features/runner-mode) for more information.
-- @param mode string|function
function hilbish.runnerMode(mode)
if type(mode) == 'string' then
hilbish.runner.setCurrent(mode)
elseif type(mode) == 'function' then
hilbish.runner.set('_', {
run = mode
})
hilbish.runner.setCurrent '_'
else
error('expected runner mode type to be either string or function, got', type(mode))
end
end