Compare commits

...

31 Commits

Author SHA1 Message Date
sammyette 44cb577a2b
Merge a24bca3258 into 824f5bd06d 2024-08-16 15:32:48 -04:00
TorchedSammy 824f5bd06d docs: [ci] generate new docs 2024-08-16 19:26:30 +00:00
sammyette a7ba2fdf1a
fix: add newline at the end of input if in an unfinished heredoc (#322)
and define (or fix) the behavior of input ending with a slash
it will now add a newline at the end of input always
2024-08-16 15:26:10 -04:00
sammyette e6b88816fd
chore: add 2.4 motd (work in progress) 2024-08-16 15:25:35 -04:00
sammyette db851cf4f8
chore: bump to 2.4 2024-08-16 15:23:55 -04:00
sammyette fc6a9a33e1
chore: update dependencies (fixes #318) 2024-08-15 12:38:35 -04:00
sammyette 0582fbd30c
chore: prepare v2.3.2 2024-07-30 19:26:35 -04:00
sammyette 137efe5c62
fix: motd typo 2024-07-30 19:24:57 -04:00
sammyette 72324c27de
fix: command path searching 2024-07-30 17:57:59 -04:00
sammyette ea233facc8
fix: get absolute path in fs.cd function 2024-07-27 14:28:09 -04:00
sammyette 19feda919e
chore: update changelog 2024-07-27 14:27:54 -04:00
sammyette e4df61f020
fix(nature/tips): cleanup tips display 2024-07-27 14:19:53 -04:00
sammyette 54b85b1c99
fix: add 2.3 motd 2024-07-27 14:10:21 -04:00
sammyette ddf5117fd9
chore: bump version 2024-07-26 18:08:43 -04:00
sammyette 5b46158008
fix(commands/cd): use absolute paths to cd 2024-07-26 18:08:26 -04:00
sammyette a41a5504f4
fix(nature/tips): opt typo 2024-07-26 18:07:55 -04:00
Nathan J Helmig 35a8d0eaa4
feat: adds some friendly tips (#315)
Co-authored-by: Nathan Helmig <nathanhelmig@pop-os.attlocal.net>
2024-07-21 19:02:46 -04:00
sammyette 8a1614ab59
ci: use wildcard for refs on branch name 2024-07-20 10:24:56 -04:00
sammyette cc43cb2d6e
fix: make website build on tag pushes 2024-07-20 10:19:22 -04:00
sammyette 1ba0dd183c
blog: add v2.3 release blog 2024-07-20 10:14:16 -04:00
sammyette 44d63a398a
chore: update changelog 2024-07-20 10:03:36 -04:00
sammyette 92448eec67
ci: add workflow dispatch to website 2024-07-20 09:57:51 -04:00
sammyette 4e882b376b
chore: update version info 2024-07-20 09:36:42 -04:00
sammyette 5f8d942f0a
fix: reuse shell runner instance (#312) 2024-07-20 09:31:57 -04:00
sammyette 41e5e3f789
feat: commanders can exit via ctrl c (#313) 2024-07-19 18:46:46 -04:00
sammyette 826b0789cb
docs: promote midnight edition on main readme 2024-07-19 17:43:49 -04:00
sammyette bfa3b55542
chore: merge 2024-07-19 09:51:12 -04:00
sammyette f7e66bb957
docs: bump version requirement 2024-07-19 09:48:40 -04:00
sammyette d7ab887234
feat: allow builds for unix (#311) 2024-07-19 09:48:01 -04:00
youkwhd b24fc4a422
fix: check if no command passed to exec (#310)
* fix: check if no command passed to exec

* docs: add exec fixes

* chore: remove extra space
2024-07-10 10:04:15 -04:00
sammyette a24bca3258
fix!: get/set env variables via env table
this removes the old "virtual global table" which allows
getting environment variables via just their names in lua.

this means:
an environment variable (like TERM) would need to be accessed
via the `env` table instead of just using TERM in lua.

`TERM` -> `env.TERM`
they can also be set via `env.VARIABLE = 'value'
2024-05-02 22:09:04 -04:00
32 changed files with 343 additions and 178 deletions

View File

@ -29,7 +29,7 @@ jobs:
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: '1.18.8' go-version: '1.22.2'
- name: Download Task - name: Download Task
run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d' run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d'
- name: Build - name: Build

View File

@ -4,9 +4,12 @@ on:
push: push:
branches: branches:
- master - master
tags:
- v[0-9]+.*
pull_request: pull_request:
branches: branches:
- master - master
workflow_dispatch:
jobs: jobs:
deploy: deploy:
@ -25,7 +28,7 @@ jobs:
- name: Set branch name - name: Set branch name
id: branch id: branch
run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> "$GITHUB_ENV" run: echo "BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/*/}}" >> "$GITHUB_ENV"
- name: Fix base URL - name: Fix base URL
if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea' if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea'

View File

@ -1,7 +1,30 @@
# 🎀 Changelog # 🎀 Changelog
## Unreleased ## Unreleased
### Fixed
- Heredocs having issues
### Added ### Added
- Adding `\` at the end of input will add a newline and prompt for more input.
## [2.3.2] - 2024-07-30
### Fixed
- Command path searching due to 2.3 changes to the shell interpreter
## [2.3.1] - 2024-07-27
[hehe when you see it release](https://youtu.be/AaAF51Gwbxo?si=rhj2iYuQRkqDa693&t=64)
### Added
- `hilbish.opts.tips` was added to display random tips on start up.
Displayed tips can be modified via the `hilbish.tips` table.
### Fixed
- Fix a minor regression related to the cd command not working with relative paths
- Updated the motd for 2.3
## [2.3.0] - 2024-07-20
### Added
- `commander.registry` function to get all registered commanders.
- `fs.pipe` function to get a pair of connected files (a pipe). - `fs.pipe` function to get a pair of connected files (a pipe).
- Added an alternative 2nd parameter to `hilbish.run`, which is `streams`. - Added an alternative 2nd parameter to `hilbish.run`, which is `streams`.
`streams` is a table of input and output streams to run the command with. `streams` is a table of input and output streams to run the command with.
@ -28,8 +51,18 @@ hilbish.run('wc -l', {
}) })
``` ```
### Changed
- The `-S` flag will be set to Hilbish's absolute path
- Hilbish now builds on any Unix (if any dependencies also work, which should.)
### Fixed ### Fixed
- Fix ansi attributes causing issues with text when cut off in greenhouse - Fix ansi attributes causing issues with text when cut off in greenhouse
- Fix greenhouse appearing on terminal resize
- Fix crashes when history goes out of bounds when using history navigation
- `exec` command should return if no arg presented
- Commanders can now be cancelled by Ctrl-C and wont hang the shell anymore.
See [issue 198](https://github.com/Rosettea/Hilbish/issues/198).
- Shell interpreter can now preserve its environment and set PWD properly.
## [2.2.3] - 2024-04-27 ## [2.2.3] - 2024-04-27
### Fixed ### Fixed
@ -747,6 +780,9 @@ This input for example will prompt for more input to complete:
First "stable" release of Hilbish. First "stable" release of Hilbish.
[2.3.1]: https://github.com/Rosettea/Hilbish/compare/v2.3.1...v2.3.2
[2.3.1]: https://github.com/Rosettea/Hilbish/compare/v2.3.0...v2.3.1
[2.3.0]: https://github.com/Rosettea/Hilbish/compare/v2.2.3...v2.3.0
[2.2.3]: https://github.com/Rosettea/Hilbish/compare/v2.2.2...v2.2.3 [2.2.3]: https://github.com/Rosettea/Hilbish/compare/v2.2.2...v2.2.3
[2.2.2]: https://github.com/Rosettea/Hilbish/compare/v2.2.1...v2.2.2 [2.2.2]: https://github.com/Rosettea/Hilbish/compare/v2.2.1...v2.2.2
[2.2.1]: https://github.com/Rosettea/Hilbish/compare/v2.2.0...v2.2.1 [2.2.1]: https://github.com/Rosettea/Hilbish/compare/v2.2.0...v2.2.1

View File

@ -1,3 +1,6 @@
> [!TIP]
> Check out [Hilbish: Midnight Edition](https://github.com/Rosettea/Hilbish/tree/midnight-edition) if you want to use C Lua, LuaJIT or anything related!
<img src="./assets/hilbish-logo-and-text.png" width=512><br> <img src="./assets/hilbish-logo-and-text.png" width=512><br>
<blockquote> <blockquote>
🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨ 🌓 The Moon-powered shell! A comfy and extensible shell for Lua fans! 🌺 ✨
@ -36,7 +39,7 @@ on the website for distributed binaries from GitHub or other package repositorie
Otherwise, continue reading for steps on compiling. Otherwise, continue reading for steps on compiling.
## Prerequisites ## Prerequisites
- [Go 1.17+](https://go.dev) - [Go 1.22+](https://go.dev)
- [Task](https://taskfile.dev/installation/) (**Go on the hyperlink here to see Task's install method for your OS.**) - [Task](https://taskfile.dev/installation/) (**Go on the hyperlink here to see Task's install method for your OS.**)
## Build ## Build

View File

@ -21,16 +21,18 @@ A runner is passed the input and has to return a table with these values.
All are not required, only the useful ones the runner needs to return. All are not required, only the useful ones the runner needs to return.
(So if there isn't an error, just omit `err`.) (So if there isn't an error, just omit `err`.)
- `exitCode` (number): A numerical code to indicate the exit result. - `exitCode` (number): Exit code of the command
- `input` (string): The user input. This will be used to add - `input` (string): The text input of the user. This is used by Hilbish to append extra input, in case
to the history. more is requested.
- `err` (string): A string to indicate an interal error for the runner. - `err` (string): A string that represents an error from the runner.
It can be set to a few special values for Hilbish to throw the right hooks and have a better looking message: This should only be set when, for example, there is a syntax error.
It can be set to a few special values for Hilbish to throw the right
`[command]: not-found` will throw a command.not-found hook based on what `[command]` is. hooks and have a better looking message.
- `\<command>: not-found` will throw a `command.not-found` hook
`[command]: not-executable` will throw a command.not-executable hook. based on what `\<command>` is.
- `continue` (boolean): Whether to prompt the user for more input. - `\<command>: not-executable` will throw a `command.not-executable` hook.
- `continue` (boolean): Whether Hilbish should prompt the user for no input
- `newline` (boolean): Whether a newline should be added at the end of `input`.
Here is a simple example of a fennel runner. It falls back to Here is a simple example of a fennel runner. It falls back to
shell script if fennel eval has an error. shell script if fennel eval has an error.

View File

@ -33,19 +33,6 @@ needs to run interactive input. For more detail, see the [API documentation](../
The `hilbish.runner` interface is an alternative to using `hilbish.runnerMode` The `hilbish.runner` interface is an alternative to using `hilbish.runnerMode`
and also provides the shell script and Lua runner functions that Hilbish itself uses. and also provides the shell script and Lua runner functions that Hilbish itself uses.
A runner function is expected to return a table with the following values:
- `exitCode` (number): Exit code of the command
- `input` (string): The text input of the user. This is used by Hilbish to append extra input, in case
more is requested.
- `err` (string): A string that represents an error from the runner.
This should only be set when, for example, there is a syntax error.
It can be set to a few special values for Hilbish to throw the right
hooks and have a better looking message.
- `<command>: not-found` will throw a `command.not-found` hook
based on what `<command>` is.
- `<command>: not-executable` will throw a `command.not-executable` hook.
- `continue` (boolean): Whether Hilbish should prompt the user for no input
## Functions ## Functions
These are the "low level" functions for the `hilbish.runner` interface. These are the "low level" functions for the `hilbish.runner` interface.

113
exec.go
View File

@ -8,6 +8,7 @@ import (
"fmt" "fmt"
"io" "io"
"os" "os"
"os/signal"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
@ -97,6 +98,7 @@ func runInput(input string, priv bool) {
var exitCode uint8 var exitCode uint8
var err error var err error
var cont bool var cont bool
var newline bool
// save incase it changes while prompting (For some reason) // save incase it changes while prompting (For some reason)
currentRunner := runnerMode currentRunner := runnerMode
if currentRunner.Type() == rt.StringType { if currentRunner.Type() == rt.StringType {
@ -107,9 +109,9 @@ func runInput(input string, priv bool) {
cmdFinish(0, input, priv) cmdFinish(0, input, priv)
return return
} }
input, exitCode, cont, err = handleSh(input) input, exitCode, cont, newline, err = handleSh(input)
case "hybridRev": case "hybridRev":
_, _, _, err = handleSh(input) _, _, _, _, err = handleSh(input)
if err == nil { if err == nil {
cmdFinish(0, input, priv) cmdFinish(0, input, priv)
return return
@ -118,12 +120,12 @@ func runInput(input string, priv bool) {
case "lua": case "lua":
input, exitCode, err = handleLua(input) input, exitCode, err = handleLua(input)
case "sh": case "sh":
input, exitCode, cont, err = handleSh(input) input, exitCode, cont, newline, err = handleSh(input)
} }
} else { } else {
// can only be a string or function so // can only be a string or function so
var runnerErr error var runnerErr error
input, exitCode, cont, runnerErr, err = runLuaRunner(currentRunner, input) input, exitCode, cont, newline, runnerErr, err = runLuaRunner(currentRunner, input)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
cmdFinish(124, input, priv) cmdFinish(124, input, priv)
@ -136,15 +138,15 @@ func runInput(input string, priv bool) {
} }
if cont { if cont {
input, err = reprompt(input) input, err = continuePrompt(input, newline)
if err == nil { if err == nil {
goto rerun goto rerun
} else if err == io.EOF { } else if err == io.EOF {
return lr.SetPrompt(fmtPrompt(prompt))
} }
} }
if err != nil { if err != nil && err != io.EOF {
if exErr, ok := isExecError(err); ok { if exErr, ok := isExecError(err); ok {
hooks.Emit("command." + exErr.typ, exErr.cmd) hooks.Emit("command." + exErr.typ, exErr.cmd)
} else { } else {
@ -154,26 +156,28 @@ func runInput(input string, priv bool) {
cmdFinish(exitCode, input, priv) cmdFinish(exitCode, input, priv)
} }
func reprompt(input string) (string, error) { func reprompt(input string, newline bool) (string, error) {
for { for {
in, err := continuePrompt(strings.TrimSuffix(input, "\\")) /*
if strings.HasSuffix(input, "\\") {
input = strings.TrimSuffix(input, "\\") + "\n"
}
*/
in, err := continuePrompt(input, newline)
if err != nil { if err != nil {
lr.SetPrompt(fmtPrompt(prompt)) lr.SetPrompt(fmtPrompt(prompt))
return input, err return input, err
} }
if strings.HasSuffix(in, "\\") {
continue
}
return in, nil return in, nil
} }
} }
func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8, continued bool, runnerErr, err error) { func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8, continued bool, newline bool, runnerErr, err error) {
term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 3, false) term := rt.NewTerminationWith(l.MainThread().CurrentCont(), 3, false)
err = rt.Call(l.MainThread(), runr, []rt.Value{rt.StringValue(userInput)}, term) err = rt.Call(l.MainThread(), runr, []rt.Value{rt.StringValue(userInput)}, term)
if err != nil { if err != nil {
return "", 124, false, nil, err return "", 124, false, false, nil, err
} }
var runner *rt.Table var runner *rt.Table
@ -201,6 +205,10 @@ func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8
if c, ok := runner.Get(rt.StringValue("continue")).TryBool(); ok { if c, ok := runner.Get(rt.StringValue("continue")).TryBool(); ok {
continued = c continued = c
} }
if nl, ok := runner.Get(rt.StringValue("newline")).TryBool(); ok {
newline = nl
}
return return
} }
@ -231,35 +239,40 @@ func handleLua(input string) (string, uint8, error) {
return cmdString, 125, err return cmdString, 125, err
} }
func handleSh(cmdString string) (input string, exitCode uint8, cont bool, runErr error) { func handleSh(cmdString string) (input string, exitCode uint8, cont bool, newline bool, runErr error) {
shRunner := hshMod.Get(rt.StringValue("runner")).AsTable().Get(rt.StringValue("sh")) shRunner := hshMod.Get(rt.StringValue("runner")).AsTable().Get(rt.StringValue("sh"))
var err error var err error
input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString) input, exitCode, cont, newline, runErr, err = runLuaRunner(shRunner, cmdString)
if err != nil { if err != nil {
runErr = err runErr = err
} }
return return
} }
func execSh(cmdString string) (string, uint8, bool, error) { func execSh(cmdString string) (input string, exitcode uint8, cont bool, newline bool, e error) {
_, _, err := execCommand(cmdString, nil) _, _, err := execCommand(cmdString, nil)
if err != nil { if err != nil {
// If input is incomplete, start multiline prompting // If input is incomplete, start multiline prompting
if syntax.IsIncomplete(err) { if syntax.IsIncomplete(err) {
if !interactive { if !interactive {
return cmdString, 126, false, err return cmdString, 126, false, false, err
} }
return cmdString, 126, true, err
newline := false
if strings.Contains(err.Error(), "unclosed here-document") {
newline = true
}
return cmdString, 126, true, newline, err
} else { } else {
if code, ok := interp.IsExitStatus(err); ok { if code, ok := interp.IsExitStatus(err); ok {
return cmdString, code, false, nil return cmdString, code, false, false, nil
} else { } else {
return cmdString, 126, false, err return cmdString, 126, false, false, err
} }
} }
} }
return cmdString, 0, false, nil return cmdString, 0, false, false, nil
} }
// Run command in sh interpreter // Run command in sh interpreter
@ -269,8 +282,6 @@ func execCommand(cmd string, strms *streams) (io.Writer, io.Writer, error) {
return nil, nil, err return nil, nil, err
} }
runner, _ := interp.New()
if strms == nil { if strms == nil {
strms = &streams{} strms = &streams{}
} }
@ -288,6 +299,7 @@ func execCommand(cmd string, strms *streams) (io.Writer, io.Writer, error) {
} }
interp.StdIO(strms.stdin, strms.stdout, strms.stderr)(runner) interp.StdIO(strms.stdin, strms.stdout, strms.stderr)(runner)
interp.Env(nil)(runner)
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
printer := syntax.NewPrinter() printer := syntax.NewPrinter()
@ -353,7 +365,34 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
sinks.Set(rt.StringValue("out"), rt.UserDataValue(stdout.ud)) sinks.Set(rt.StringValue("out"), rt.UserDataValue(stdout.ud))
sinks.Set(rt.StringValue("err"), rt.UserDataValue(stderr.ud)) sinks.Set(rt.StringValue("err"), rt.UserDataValue(stderr.ud))
luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(cmd), rt.TableValue(luacmdArgs), rt.TableValue(sinks)) t := rt.NewThread(l)
sig := make(chan os.Signal)
exit := make(chan bool)
luaexitcode := rt.IntValue(63)
var err error
go func() {
defer func() {
if r := recover(); r != nil {
exit <- true
}
}()
signal.Notify(sig, os.Interrupt)
select {
case <-sig:
t.KillContext()
return
}
}()
go func() {
luaexitcode, err = rt.Call1(t, rt.FunctionValue(cmd), rt.TableValue(luacmdArgs), rt.TableValue(sinks))
exit <- true
}()
<-exit
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error()) fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error())
return interp.NewExitStatus(1) return interp.NewExitStatus(1)
@ -372,7 +411,7 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
return interp.NewExitStatus(exitcode) return interp.NewExitStatus(exitcode)
} }
err := lookpath(args[0]) path, err := lookpath(args[0])
if err == errNotExec { if err == errNotExec {
return execError{ return execError{
typ: "not-executable", typ: "not-executable",
@ -393,15 +432,16 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
killTimeout := 2 * time.Second killTimeout := 2 * time.Second
// from here is basically copy-paste of the default exec handler from // from here is basically copy-paste of the default exec handler from
// sh/interp but with our job handling // sh/interp but with our job handling
path, err := interp.LookPathDir(hc.Dir, hc.Env, args[0])
if err != nil {
fmt.Fprintln(hc.Stderr, err)
return interp.NewExitStatus(127)
}
env := hc.Env env := hc.Env
envList := make([]string, 0, 64) envList := make([]string, 0, 64)
env.Each(func(name string, vr expand.Variable) bool { env.Each(func(name string, vr expand.Variable) bool {
if name == "PATH" {
pathEnv := os.Getenv("PATH")
envList = append(envList, "PATH="+pathEnv)
return true
}
if !vr.IsSet() { if !vr.IsSet() {
// If a variable is set globally but unset in the // If a variable is set globally but unset in the
// runner, we need to ensure it's not part of the final // runner, we need to ensure it's not part of the final
@ -419,6 +459,7 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
} }
return true return true
}) })
cmd := exec.Cmd{ cmd := exec.Cmd{
Path: path, Path: path,
Args: args, Args: args,
@ -501,7 +542,7 @@ func handleExecErr(err error) (exit uint8) {
return return
} }
func lookpath(file string) error { // custom lookpath function so we know if a command is found *and* is executable func lookpath(file string) (string, error) { // custom lookpath function so we know if a command is found *and* is executable
var skip []string var skip []string
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
skip = []string{"./", "../", "~/", "C:"} skip = []string{"./", "../", "~/", "C:"}
@ -510,20 +551,20 @@ func lookpath(file string) error { // custom lookpath function so we know if a c
} }
for _, s := range skip { for _, s := range skip {
if strings.HasPrefix(file, s) { if strings.HasPrefix(file, s) {
return findExecutable(file, false, false) return file, findExecutable(file, false, false)
} }
} }
for _, dir := range filepath.SplitList(os.Getenv("PATH")) { for _, dir := range filepath.SplitList(os.Getenv("PATH")) {
path := filepath.Join(dir, file) path := filepath.Join(dir, file)
err := findExecutable(path, true, false) err := findExecutable(path, true, false)
if err == errNotExec { if err == errNotExec {
return err return "", err
} else if err == nil { } else if err == nil {
return nil return path, nil
} }
} }
return os.ErrNotExist return "", os.ErrNotExist
} }
func splitInput(input string) ([]string, string) { func splitInput(input string) ([]string, string) {

View File

@ -1,4 +1,4 @@
// +build linux darwin //go:build unix
package main package main

View File

@ -1,4 +1,4 @@
// +build windows //go:build windows
package main package main

11
go.mod
View File

@ -1,6 +1,8 @@
module hilbish module hilbish
go 1.18 go 1.21
toolchain go1.22.2
require ( require (
github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1 github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1
@ -9,8 +11,8 @@ require (
github.com/maxlandon/readline v1.0.14 github.com/maxlandon/readline v1.0.14
github.com/pborman/getopt v1.1.0 github.com/pborman/getopt v1.1.0
github.com/sahilm/fuzzy v0.1.1 github.com/sahilm/fuzzy v0.1.1
golang.org/x/sys v0.19.0 golang.org/x/sys v0.22.0
golang.org/x/term v0.19.0 golang.org/x/term v0.22.0
mvdan.cc/sh/v3 v3.8.0 mvdan.cc/sh/v3 v3.8.0
) )
@ -19,13 +21,14 @@ require (
github.com/arnodel/strftime v0.1.6 // indirect github.com/arnodel/strftime v0.1.6 // indirect
github.com/evilsocket/islazy v1.11.0 // indirect github.com/evilsocket/islazy v1.11.0 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect github.com/kylelemons/godebug v1.1.0 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
golang.org/x/sync v0.7.0 // indirect golang.org/x/sync v0.7.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
) )
replace mvdan.cc/sh/v3 => github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b replace mvdan.cc/sh/v3 => github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240815163633-562273e09b73
replace github.com/maxlandon/readline => ./readline replace github.com/maxlandon/readline => ./readline

44
go.sum
View File

@ -1,7 +1,7 @@
github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749 h1:jIFnWBTsYw8s7RX7H2AOXjDVhWP3ol7OzUVaPN2KnGI= github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749 h1:jIFnWBTsYw8s7RX7H2AOXjDVhWP3ol7OzUVaPN2KnGI=
github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= github.com/Rosettea/golua v0.0.0-20240427174124-d239074c1749/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE=
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b h1:s5eDMhBk6H1BgipgLub/gv9qeyBaTuiHM0k3h2/9TSE= github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240815163633-562273e09b73 h1:zTTUJqNnrF2qf4LgygN8Oae5Uxn6ewH0hA8jyTCHfXw=
github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs= github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20240815163633-562273e09b73/go.mod h1:YZalN5H7WNQw3DGij6IvHsEhn5YMW7M2FCwG6gnfKy4=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw= github.com/arnodel/strftime v0.1.6 h1:0hc0pUvk8KhEMXE+htyaOUV42zNcf/csIbjzEFCJqsw=
@ -10,45 +10,37 @@ github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504 h
github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504/go.mod h1:kHBCvAXJIatTX1pw6tLiOspjGc3MhUDRlog9yrCUS+k= github.com/atsushinee/go-markdown-generator v0.0.0-20191121114853-83f9e1f68504/go.mod h1:kHBCvAXJIatTX1pw6tLiOspjGc3MhUDRlog9yrCUS+k=
github.com/blackfireio/osinfo v1.0.5 h1:6hlaWzfcpb87gRmznVf7wSdhysGqLRz9V/xuSdCEXrA= github.com/blackfireio/osinfo v1.0.5 h1:6hlaWzfcpb87gRmznVf7wSdhysGqLRz9V/xuSdCEXrA=
github.com/blackfireio/osinfo v1.0.5/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA= github.com/blackfireio/osinfo v1.0.5/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/evilsocket/islazy v1.11.0 h1:B5w6uuS6ki6iDG+aH/RFeoMb8ijQh/pGabewqp2UeJ0= github.com/evilsocket/islazy v1.11.0 h1:B5w6uuS6ki6iDG+aH/RFeoMb8ijQh/pGabewqp2UeJ0=
github.com/evilsocket/islazy v1.11.0/go.mod h1:muYH4x5MB5YRdkxnrOtrXLIBX6LySj1uFIqys94LKdo= github.com/evilsocket/islazy v1.11.0/go.mod h1:muYH4x5MB5YRdkxnrOtrXLIBX6LySj1uFIqys94LKdo=
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw= github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0 h1:LiZB1h0GIcudcDci2bxbqI6DXV8bF8POAnArqvRrIyw=
github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0= github.com/olekukonko/ts v0.0.0-20171002115256-78ecb04241c0/go.mod h1:F/7q8/HZz+TXjlsoZQQKVYvXTZaFH4QRa3y+j1p7MS0=
github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0= github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0=
github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk= github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/term v0.0.0-20210916214954-140adaaadfaf/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=

View File

@ -19,25 +19,38 @@ import (
rt "github.com/arnodel/golua/runtime" rt "github.com/arnodel/golua/runtime"
"github.com/arnodel/golua/lib/packagelib" "github.com/arnodel/golua/lib/packagelib"
"github.com/arnodel/golua/lib/iolib" "github.com/arnodel/golua/lib/iolib"
"mvdan.cc/sh/v3/interp"
) )
var Loader = packagelib.Loader{ type fs struct{
Load: loaderFunc, runner *interp.Runner
Name: "fs", Loader packagelib.Loader
} }
func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { func New(runner *interp.Runner) *fs {
f := &fs{
runner: runner,
}
f.Loader = packagelib.Loader{
Load: f.loaderFunc,
Name: "fs",
}
return f
}
func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
exports := map[string]util.LuaExport{ exports := map[string]util.LuaExport{
"cd": util.LuaExport{fcd, 1, false}, "cd": util.LuaExport{f.fcd, 1, false},
"mkdir": util.LuaExport{fmkdir, 2, false}, "mkdir": util.LuaExport{f.fmkdir, 2, false},
"stat": util.LuaExport{fstat, 1, false}, "stat": util.LuaExport{f.fstat, 1, false},
"readdir": util.LuaExport{freaddir, 1, false}, "readdir": util.LuaExport{f.freaddir, 1, false},
"abs": util.LuaExport{fabs, 1, false}, "abs": util.LuaExport{f.fabs, 1, false},
"basename": util.LuaExport{fbasename, 1, false}, "basename": util.LuaExport{f.fbasename, 1, false},
"dir": util.LuaExport{fdir, 1, false}, "dir": util.LuaExport{f.fdir, 1, false},
"glob": util.LuaExport{fglob, 1, false}, "glob": util.LuaExport{f.fglob, 1, false},
"join": util.LuaExport{fjoin, 0, true}, "join": util.LuaExport{f.fjoin, 0, true},
"pipe": util.LuaExport{fpipe, 0, false}, "pipe": util.LuaExport{f.fpipe, 0, false},
} }
mod := rt.NewTable() mod := rt.NewTable()
util.SetExports(rtm, mod, exports) util.SetExports(rtm, mod, exports)
@ -52,7 +65,7 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
// This can be used to resolve short paths like `..` to `/home/user`. // This can be used to resolve short paths like `..` to `/home/user`.
// #param path string // #param path string
// #returns string // #returns string
func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
path, err := c.StringArg(0) path, err := c.StringArg(0)
if err != nil { if err != nil {
return nil, err return nil, err
@ -72,7 +85,7 @@ func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// `.` will be returned. // `.` will be returned.
// #param path string Path to get the base name of. // #param path string Path to get the base name of.
// #returns string // #returns string
func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err
} }
@ -87,7 +100,7 @@ func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// cd(dir) // cd(dir)
// Changes Hilbish's directory to `dir`. // Changes Hilbish's directory to `dir`.
// #param dir string Path to change directory to. // #param dir string Path to change directory to.
func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err
} }
@ -97,10 +110,12 @@ func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
} }
path = util.ExpandHome(strings.TrimSpace(path)) path = util.ExpandHome(strings.TrimSpace(path))
abspath, _ := filepath.Abs(path)
err = os.Chdir(path) err = os.Chdir(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
interp.Dir(abspath)(f.runner)
return c.Next(), err return c.Next(), err
} }
@ -110,7 +125,7 @@ func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// `~/Documents/doc.txt` then this function will return `~/Documents`. // `~/Documents/doc.txt` then this function will return `~/Documents`.
// #param path string Path to get the directory for. // #param path string Path to get the directory for.
// #returns string // #returns string
func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err
} }
@ -141,7 +156,7 @@ print(matches)
-- -> {'init.lua', 'code.lua'} -- -> {'init.lua', 'code.lua'}
#example #example
*/ */
func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err
} }
@ -175,7 +190,7 @@ print(fs.join(hilbish.userDir.config, 'hilbish'))
-- -> '/home/user/.config/hilbish' on Linux -- -> '/home/user/.config/hilbish' on Linux
#example #example
*/ */
func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
strs := make([]string, len(c.Etc())) strs := make([]string, len(c.Etc()))
for i, v := range c.Etc() { for i, v := range c.Etc() {
if v.Type() != rt.StringType { if v.Type() != rt.StringType {
@ -202,7 +217,7 @@ func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
fs.mkdir('./foo/bar', true) fs.mkdir('./foo/bar', true)
#example #example
*/ */
func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.CheckNArgs(2); err != nil { if err := c.CheckNArgs(2); err != nil {
return nil, err return nil, err
} }
@ -233,7 +248,7 @@ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// The type returned is a Lua file, same as returned from `io` functions. // The type returned is a Lua file, same as returned from `io` functions.
// #returns File // #returns File
// #returns File // #returns File
func fpipe(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fpipe(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
rf, wf, err := os.Pipe() rf, wf, err := os.Pipe()
if err != nil { if err != nil {
return nil, err return nil, err
@ -248,7 +263,7 @@ func fpipe(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
// Returns a list of all files and directories in the provided path. // Returns a list of all files and directories in the provided path.
// #param dir string // #param dir string
// #returns table // #returns table
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err
} }
@ -296,7 +311,7 @@ Would print the following:
]]-- ]]--
#example #example
*/ */
func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { func (f *fs) fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
if err := c.Check1Arg(); err != nil { if err := c.Check1Arg(); err != nil {
return nil, err return nil, err
} }

View File

@ -1,4 +1,4 @@
// +build windows //go:build windows
package main package main

View File

@ -1,4 +1,4 @@
// +build darwin linux //go:build unix
package main package main

View File

@ -1,4 +1,4 @@
// +build windows //go:build windows
package main package main

3
lua.go
View File

@ -30,7 +30,8 @@ func luaInit() {
util.DoString(l, "hilbish = require 'hilbish'") util.DoString(l, "hilbish = require 'hilbish'")
// Add fs and terminal module module to Lua // Add fs and terminal module module to Lua
lib.LoadLibs(l, fs.Loader) f := fs.New(runner)
lib.LoadLibs(l, f.Loader)
lib.LoadLibs(l, terminal.Loader) lib.LoadLibs(l, terminal.Loader)
cmds = commander.New(l) cmds = commander.New(l)

20
main.go
View File

@ -21,6 +21,7 @@ import (
"github.com/pborman/getopt" "github.com/pborman/getopt"
"github.com/maxlandon/readline" "github.com/maxlandon/readline"
"golang.org/x/term" "golang.org/x/term"
"mvdan.cc/sh/v3/interp"
) )
var ( var (
@ -37,9 +38,11 @@ var (
cmds *commander.Commander cmds *commander.Commander
defaultConfPath string defaultConfPath string
defaultHistPath string defaultHistPath string
runner *interp.Runner
) )
func main() { func main() {
runner, _ = interp.New()
curuser, _ = user.Current() curuser, _ = user.Current()
homedir := curuser.HomeDir homedir := curuser.HomeDir
confDir, _ = os.UserConfigDir() confDir, _ = os.UserConfigDir()
@ -220,8 +223,9 @@ input:
} }
if strings.HasSuffix(input, "\\") { if strings.HasSuffix(input, "\\") {
print("\n")
for { for {
input, err = continuePrompt(input) input, err = continuePrompt(strings.TrimSuffix(input, "\\") + "\n", false)
if err != nil { if err != nil {
running = true running = true
lr.SetPrompt(fmtPrompt(prompt)) lr.SetPrompt(fmtPrompt(prompt))
@ -245,16 +249,24 @@ input:
exit(0) exit(0)
} }
func continuePrompt(prev string) (string, error) { func continuePrompt(prev string, newline bool) (string, error) {
hooks.Emit("multiline", nil) hooks.Emit("multiline", nil)
lr.SetPrompt(multilinePrompt) lr.SetPrompt(multilinePrompt)
cont, err := lr.Read() cont, err := lr.Read()
if err != nil { if err != nil {
return "", err return "", err
} }
cont = strings.TrimSpace(cont)
return prev + strings.TrimSuffix(cont, "\n"), nil if newline {
cont = "\n" + cont
}
if strings.HasSuffix(cont, "\\") {
cont = strings.TrimSuffix(cont, "\\") + "\n"
}
return prev + cont, nil
} }
// This semi cursed function formats our prompt (obviously) // This semi cursed function formats our prompt (obviously)

View File

@ -1,5 +1,8 @@
local commander = require 'commander' local commander = require 'commander'
commander.register('exec', function(args) commander.register('exec', function(args)
if #args == 0 then
return
end
hilbish.exec(args[1]) hilbish.exec(args[1])
end) end)

10
nature/env.lua 100644
View File

@ -0,0 +1,10 @@
env = {}
setmetatable(env, {
__index = function(_, k)
return os.getenv(k)
end,
__newindex = function(_, k, v)
os.setenv(k, tostring(v))
end
})

View File

@ -24,6 +24,7 @@ require 'nature.opts'
require 'nature.vim' require 'nature.vim'
require 'nature.runner' require 'nature.runner'
require 'nature.hummingbird' require 'nature.hummingbird'
require 'nature.env'
local shlvl = tonumber(os.getenv 'SHLVL') local shlvl = tonumber(os.getenv 'SHLVL')
if shlvl ~= nil then if shlvl ~= nil then
@ -32,36 +33,6 @@ else
os.setenv('SHLVL', '0') os.setenv('SHLVL', '0')
end end
do
local virt_G = { }
setmetatable(_G, {
__index = function (_, key)
local got_virt = virt_G[key]
if got_virt ~= nil then
return got_virt
end
if type(key) == 'string' then
virt_G[key] = os.getenv(key)
end
return virt_G[key]
end,
__newindex = function (_, key, value)
if type(value) == 'string' then
os.setenv(key, value)
virt_G[key] = value
else
if type(virt_G[key]) == 'string' then
os.setenv(key, '')
end
virt_G[key] = value
end
end,
})
end
do do
local startSearchPath = hilbish.userDir.data .. '/hilbish/start/?/init.lua;' local startSearchPath = hilbish.userDir.data .. '/hilbish/start/?/init.lua;'
.. hilbish.userDir.data .. '/hilbish/start/?.lua' .. hilbish.userDir.data .. '/hilbish/start/?.lua'

View File

@ -14,7 +14,8 @@ The nice lil shell for {blue}Lua{reset} fanatics!
motd = true, motd = true,
fuzzy = false, fuzzy = false,
notifyJobFinish = true, notifyJobFinish = true,
crimmas = true crimmas = true,
tips = true
} }
for optsName, default in pairs(defaultOpts) do for optsName, default in pairs(defaultOpts) do

View File

@ -2,8 +2,7 @@ local bait = require 'bait'
local lunacolors = require 'lunacolors' local lunacolors = require 'lunacolors'
hilbish.motd = [[ hilbish.motd = [[
Finally at {red}v2.2!{reset} So much {green}documentation improvements{reset} {magenta}Hilbish{reset} blooms in the {blue}midnight.{reset}
and 1 single fix for Windows! {blue}.. and a feature they can't use.{reset}
]] ]]
bait.catch('hilbish.init', function() bait.catch('hilbish.init', function()

View File

@ -0,0 +1,35 @@
local bait = require 'bait'
local lunacolors = require 'lunacolors'
local postamble = [[
{yellow}These tips can be disabled with {reset}{invert} hilbish.opts.tips = false {reset}
]]
hilbish.tips = {
'Join the discord and say hi! {blue}https://discord.gg/3PDdcQz{reset}',
'{green}hilbish.alias{reset} interface manages shell aliases. See more detail by running {blue}doc api hilbish.alias.',
'{green}hilbish.appendPath(\'path\'){reset} -> Appends the provided dir to the command path ($PATH)',
'{green}hilbish.completions{reset} -> Used to control suggestions when tab completing.',
'{green}hilbish.message{reset} -> Simple notification system which can be used by other plugins and parts of the shell to notify the user of various actions.',
[[
{green}hilbish.opts{reset} -> Simple toggle or value options a user can set.
You may disable the startup greeting by {invert}hilbish.opts.greeting = false{reset}
]],
[[
{green}hilbish.runner{reset} -> The runner interface contains functions to
manage how Hilbish interprets interactive input. The default runners can run
shell script and Lua code!
]],
[[
Add Lua-written commands with the commander module!
Check the command {blue}doc api commander{reset} or the web docs:
https://rosettea.github.io/Hilbish/docs/api/commander/
]]
}
bait.catch('hilbish.init', function()
if hilbish.interactive and hilbish.opts.tips then
local idx = math.random(1, #hilbish.tips)
print(lunacolors.format('{yellow}🛈 Tip:{reset} ' .. hilbish.tips[idx] .. '\n' .. postamble))
end
end)

View File

@ -1,4 +1,4 @@
// +build pprof //go:build pprof
package main package main

View File

@ -21,16 +21,18 @@ A runner is passed the input and has to return a table with these values.
All are not required, only the useful ones the runner needs to return. All are not required, only the useful ones the runner needs to return.
(So if there isn't an error, just omit `err`.) (So if there isn't an error, just omit `err`.)
- `exitCode` (number): A numerical code to indicate the exit result. - `exitCode` (number): Exit code of the command
- `input` (string): The user input. This will be used to add - `input` (string): The text input of the user. This is used by Hilbish to append extra input, in case
to the history. more is requested.
- `err` (string): A string to indicate an interal error for the runner. - `err` (string): A string that represents an error from the runner.
It can be set to a few special values for Hilbish to throw the right hooks and have a better looking message: This should only be set when, for example, there is a syntax error.
It can be set to a few special values for Hilbish to throw the right
`[command]: not-found` will throw a command.not-found hook based on what `[command]` is. hooks and have a better looking message.
- `<command>: not-found` will throw a `command.not-found` hook
`[command]: not-executable` will throw a command.not-executable hook. based on what `<command>` is.
- `continue` (boolean): Whether to prompt the user for more input. - `<command>: not-executable` will throw a `command.not-executable` hook.
- `continue` (boolean): Whether Hilbish should prompt the user for no input
- `newline` (boolean): Whether a newline should be added at the end of `input`.
Here is a simple example of a fennel runner. It falls back to Here is a simple example of a fennel runner. It falls back to
shell script if fennel eval has an error. shell script if fennel eval has an error.
@ -85,7 +87,7 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
return nil, err return nil, err
} }
_, exitCode, cont, err := execSh(aliases.Resolve(cmd)) _, exitCode, cont, newline, err := execSh(aliases.Resolve(cmd))
var luaErr rt.Value = rt.NilValue var luaErr rt.Value = rt.NilValue
if err != nil { if err != nil {
luaErr = rt.StringValue(err.Error()) luaErr = rt.StringValue(err.Error())
@ -94,6 +96,7 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
runnerRet.Set(rt.StringValue("input"), rt.StringValue(cmd)) runnerRet.Set(rt.StringValue("input"), rt.StringValue(cmd))
runnerRet.Set(rt.StringValue("exitCode"), rt.IntValue(int64(exitCode))) runnerRet.Set(rt.StringValue("exitCode"), rt.IntValue(int64(exitCode)))
runnerRet.Set(rt.StringValue("continue"), rt.BoolValue(cont)) runnerRet.Set(rt.StringValue("continue"), rt.BoolValue(cont))
runnerRet.Set(rt.StringValue("newline"), rt.BoolValue(newline))
runnerRet.Set(rt.StringValue("err"), luaErr) runnerRet.Set(rt.StringValue("err"), luaErr)
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil

View File

@ -1,4 +1,4 @@
// +build darwin linux //go:build unix
package main package main

View File

@ -1,4 +1,4 @@
// +build windows //go:build windows
package main package main

View File

@ -11,8 +11,8 @@ var (
// Version info // Version info
var ( var (
ver = "v2.2.3" ver = "v2.4.0"
releaseName = "Poppy" releaseName = "Moonflower"
gitCommit string gitCommit string
gitBranch string gitBranch string

View File

@ -1,4 +1,4 @@
// +build darwin //go:build darwin
package main package main

View File

@ -1,4 +1,4 @@
// +build linux //go:build unix && !darwin
package main package main

View File

@ -1,4 +1,4 @@
// +build windows //go:build windows
package main package main

View File

@ -0,0 +1,48 @@
---
title: "v2.3 Release"
date: 2024-07-20T10:05:17-04:00
draft: false
---
> The release with full changelogs and prebuilt binaries can be
seen at the [v2.3.0](https://github.com/Rosettea/Hilbish/releases/tag/v2.3.0)
tag.
Hilbish v2.3 has now been released! This is small feature and bug fix release
which took a while to cme ut since I took a long break from programming in general.
The next release will be great, so stay tuned for that.
# Features
## Pipes (via Lua)
Commands can now be piped to each other via the Lua API with the `hilbish.run`
function and an `fs.pipe`.
Here is a minimal example of the new usage which allows users to now pipe commands
directly via Lua functions:
```lua
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
})
```
This also means it's easier to make commands output to any stream output,
including in commanders.
# Bug Fixes
- Commanders can now be cancelled with Ctrl-C, which means if they froze for some reason
they can now be exited.
- The shell script interpreter now keeps its environment, and this also fixes the
current working directory being wrong with some commands.
- Some greenhouse bugs have been fixed, like randomly appearing when resizing the terminal
and some text attributes like color appearing where they weren't supposed to.