mirror of https://github.com/Hilbis/Hilbish
Compare commits
31 Commits
1912bd1600
...
44cb577a2b
Author | SHA1 | Date |
---|---|---|
sammyette | 44cb577a2b | |
TorchedSammy | 824f5bd06d | |
sammyette | a7ba2fdf1a | |
sammyette | e6b88816fd | |
sammyette | db851cf4f8 | |
sammyette | fc6a9a33e1 | |
sammyette | 0582fbd30c | |
sammyette | 137efe5c62 | |
sammyette | 72324c27de | |
sammyette | ea233facc8 | |
sammyette | 19feda919e | |
sammyette | e4df61f020 | |
sammyette | 54b85b1c99 | |
sammyette | ddf5117fd9 | |
sammyette | 5b46158008 | |
sammyette | a41a5504f4 | |
Nathan J Helmig | 35a8d0eaa4 | |
sammyette | 8a1614ab59 | |
sammyette | cc43cb2d6e | |
sammyette | 1ba0dd183c | |
sammyette | 44d63a398a | |
sammyette | 92448eec67 | |
sammyette | 4e882b376b | |
sammyette | 5f8d942f0a | |
sammyette | 41e5e3f789 | |
sammyette | 826b0789cb | |
sammyette | bfa3b55542 | |
sammyette | f7e66bb957 | |
sammyette | d7ab887234 | |
youkwhd | b24fc4a422 | |
sammyette | a24bca3258 |
|
@ -29,7 +29,7 @@ jobs:
|
|||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.18.8'
|
||||
go-version: '1.22.2'
|
||||
- name: Download Task
|
||||
run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d'
|
||||
- name: Build
|
||||
|
|
|
@ -4,9 +4,12 @@ on:
|
|||
push:
|
||||
branches:
|
||||
- master
|
||||
tags:
|
||||
- v[0-9]+.*
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
|
@ -25,7 +28,7 @@ jobs:
|
|||
|
||||
- name: Set branch name
|
||||
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
|
||||
if: env.BRANCH_NAME != 'master' && github.repository_owner == 'Rosettea'
|
||||
|
|
36
CHANGELOG.md
36
CHANGELOG.md
|
@ -1,7 +1,30 @@
|
|||
# 🎀 Changelog
|
||||
|
||||
## Unreleased
|
||||
### Fixed
|
||||
- Heredocs having issues
|
||||
|
||||
### 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).
|
||||
- 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.
|
||||
|
@ -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
|
||||
- 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
|
||||
### Fixed
|
||||
|
@ -747,6 +780,9 @@ This input for example will prompt for more input to complete:
|
|||
|
||||
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.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
|
||||
|
|
|
@ -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>
|
||||
<blockquote>
|
||||
🌓 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.
|
||||
|
||||
## 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.**)
|
||||
|
||||
## Build
|
||||
|
|
|
@ -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.
|
||||
(So if there isn't an error, just omit `err`.)
|
||||
|
||||
- `exitCode` (number): A numerical code to indicate the exit result.
|
||||
- `input` (string): The user input. This will be used to add
|
||||
to the history.
|
||||
- `err` (string): A string to indicate an interal error for the runner.
|
||||
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 to prompt the user for more input.
|
||||
- `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
|
||||
- `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
|
||||
shell script if fennel eval has an error.
|
||||
|
|
|
@ -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`
|
||||
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
|
||||
These are the "low level" functions for the `hilbish.runner` interface.
|
||||
|
||||
|
|
113
exec.go
113
exec.go
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -97,6 +98,7 @@ func runInput(input string, priv bool) {
|
|||
var exitCode uint8
|
||||
var err error
|
||||
var cont bool
|
||||
var newline bool
|
||||
// save incase it changes while prompting (For some reason)
|
||||
currentRunner := runnerMode
|
||||
if currentRunner.Type() == rt.StringType {
|
||||
|
@ -107,9 +109,9 @@ func runInput(input string, priv bool) {
|
|||
cmdFinish(0, input, priv)
|
||||
return
|
||||
}
|
||||
input, exitCode, cont, err = handleSh(input)
|
||||
input, exitCode, cont, newline, err = handleSh(input)
|
||||
case "hybridRev":
|
||||
_, _, _, err = handleSh(input)
|
||||
_, _, _, _, err = handleSh(input)
|
||||
if err == nil {
|
||||
cmdFinish(0, input, priv)
|
||||
return
|
||||
|
@ -118,12 +120,12 @@ func runInput(input string, priv bool) {
|
|||
case "lua":
|
||||
input, exitCode, err = handleLua(input)
|
||||
case "sh":
|
||||
input, exitCode, cont, err = handleSh(input)
|
||||
input, exitCode, cont, newline, err = handleSh(input)
|
||||
}
|
||||
} else {
|
||||
// can only be a string or function so
|
||||
var runnerErr error
|
||||
input, exitCode, cont, runnerErr, err = runLuaRunner(currentRunner, input)
|
||||
input, exitCode, cont, newline, runnerErr, err = runLuaRunner(currentRunner, input)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
cmdFinish(124, input, priv)
|
||||
|
@ -136,15 +138,15 @@ func runInput(input string, priv bool) {
|
|||
}
|
||||
|
||||
if cont {
|
||||
input, err = reprompt(input)
|
||||
input, err = continuePrompt(input, newline)
|
||||
if err == nil {
|
||||
goto rerun
|
||||
} 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 {
|
||||
hooks.Emit("command." + exErr.typ, exErr.cmd)
|
||||
} else {
|
||||
|
@ -154,26 +156,28 @@ func runInput(input string, priv bool) {
|
|||
cmdFinish(exitCode, input, priv)
|
||||
}
|
||||
|
||||
func reprompt(input string) (string, error) {
|
||||
func reprompt(input string, newline bool) (string, error) {
|
||||
for {
|
||||
in, err := continuePrompt(strings.TrimSuffix(input, "\\"))
|
||||
/*
|
||||
if strings.HasSuffix(input, "\\") {
|
||||
input = strings.TrimSuffix(input, "\\") + "\n"
|
||||
}
|
||||
*/
|
||||
in, err := continuePrompt(input, newline)
|
||||
if err != nil {
|
||||
lr.SetPrompt(fmtPrompt(prompt))
|
||||
return input, err
|
||||
}
|
||||
|
||||
if strings.HasSuffix(in, "\\") {
|
||||
continue
|
||||
}
|
||||
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)
|
||||
err = rt.Call(l.MainThread(), runr, []rt.Value{rt.StringValue(userInput)}, term)
|
||||
if err != nil {
|
||||
return "", 124, false, nil, err
|
||||
return "", 124, false, false, nil, err
|
||||
}
|
||||
|
||||
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 {
|
||||
continued = c
|
||||
}
|
||||
|
||||
if nl, ok := runner.Get(rt.StringValue("newline")).TryBool(); ok {
|
||||
newline = nl
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -231,35 +239,40 @@ func handleLua(input string) (string, uint8, error) {
|
|||
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"))
|
||||
var err error
|
||||
input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString)
|
||||
input, exitCode, cont, newline, runErr, err = runLuaRunner(shRunner, cmdString)
|
||||
if err != nil {
|
||||
runErr = err
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
// If input is incomplete, start multiline prompting
|
||||
if syntax.IsIncomplete(err) {
|
||||
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 {
|
||||
if code, ok := interp.IsExitStatus(err); ok {
|
||||
return cmdString, code, false, nil
|
||||
return cmdString, code, false, false, nil
|
||||
} 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
|
||||
|
@ -269,8 +282,6 @@ func execCommand(cmd string, strms *streams) (io.Writer, io.Writer, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
runner, _ := interp.New()
|
||||
|
||||
if strms == nil {
|
||||
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.Env(nil)(runner)
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
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("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 {
|
||||
fmt.Fprintln(os.Stderr, "Error in command:\n" + err.Error())
|
||||
return interp.NewExitStatus(1)
|
||||
|
@ -372,7 +411,7 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
|||
return interp.NewExitStatus(exitcode)
|
||||
}
|
||||
|
||||
err := lookpath(args[0])
|
||||
path, err := lookpath(args[0])
|
||||
if err == errNotExec {
|
||||
return execError{
|
||||
typ: "not-executable",
|
||||
|
@ -393,15 +432,16 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
|||
killTimeout := 2 * time.Second
|
||||
// from here is basically copy-paste of the default exec handler from
|
||||
// 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
|
||||
envList := make([]string, 0, 64)
|
||||
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 a variable is set globally but unset in the
|
||||
// runner, we need to ensure it's not part of the final
|
||||
|
@ -419,6 +459,7 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
|||
}
|
||||
return true
|
||||
})
|
||||
|
||||
cmd := exec.Cmd{
|
||||
Path: path,
|
||||
Args: args,
|
||||
|
@ -501,7 +542,7 @@ func handleExecErr(err error) (exit uint8) {
|
|||
|
||||
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
|
||||
if runtime.GOOS == "windows" {
|
||||
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 {
|
||||
if strings.HasPrefix(file, s) {
|
||||
return findExecutable(file, false, false)
|
||||
return file, findExecutable(file, false, false)
|
||||
}
|
||||
}
|
||||
for _, dir := range filepath.SplitList(os.Getenv("PATH")) {
|
||||
path := filepath.Join(dir, file)
|
||||
err := findExecutable(path, true, false)
|
||||
if err == errNotExec {
|
||||
return err
|
||||
return "", err
|
||||
} else if err == nil {
|
||||
return nil
|
||||
return path, nil
|
||||
}
|
||||
}
|
||||
|
||||
return os.ErrNotExist
|
||||
return "", os.ErrNotExist
|
||||
}
|
||||
|
||||
func splitInput(input string) ([]string, string) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build linux darwin
|
||||
//go:build unix
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
|
|
11
go.mod
11
go.mod
|
@ -1,6 +1,8 @@
|
|||
module hilbish
|
||||
|
||||
go 1.18
|
||||
go 1.21
|
||||
|
||||
toolchain go1.22.2
|
||||
|
||||
require (
|
||||
github.com/arnodel/golua v0.0.0-20230215163904-e0b5347eaaa1
|
||||
|
@ -9,8 +11,8 @@ require (
|
|||
github.com/maxlandon/readline v1.0.14
|
||||
github.com/pborman/getopt v1.1.0
|
||||
github.com/sahilm/fuzzy v0.1.1
|
||||
golang.org/x/sys v0.19.0
|
||||
golang.org/x/term v0.19.0
|
||||
golang.org/x/sys v0.22.0
|
||||
golang.org/x/term v0.22.0
|
||||
mvdan.cc/sh/v3 v3.8.0
|
||||
)
|
||||
|
||||
|
@ -19,13 +21,14 @@ require (
|
|||
github.com/arnodel/strftime v0.1.6 // indirect
|
||||
github.com/evilsocket/islazy v1.11.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/rivo/uniseg v0.4.7 // indirect
|
||||
golang.org/x/sync v0.7.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
|
||||
|
||||
|
|
44
go.sum
44
go.sum
|
@ -1,7 +1,7 @@
|
|||
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/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.20220524215627-dfd9a4fa219b/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs=
|
||||
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.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/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
|
||||
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/blackfireio/osinfo v1.0.5 h1:6hlaWzfcpb87gRmznVf7wSdhysGqLRz9V/xuSdCEXrA=
|
||||
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.15 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
|
||||
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
|
||||
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||
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/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
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/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
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/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/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/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/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I=
|
||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||
github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
|
||||
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/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
|
||||
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
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=
|
||||
|
|
|
@ -19,25 +19,38 @@ import (
|
|||
rt "github.com/arnodel/golua/runtime"
|
||||
"github.com/arnodel/golua/lib/packagelib"
|
||||
"github.com/arnodel/golua/lib/iolib"
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
)
|
||||
|
||||
var Loader = packagelib.Loader{
|
||||
Load: loaderFunc,
|
||||
type fs struct{
|
||||
runner *interp.Runner
|
||||
Loader packagelib.Loader
|
||||
}
|
||||
|
||||
func New(runner *interp.Runner) *fs {
|
||||
f := &fs{
|
||||
runner: runner,
|
||||
}
|
||||
f.Loader = packagelib.Loader{
|
||||
Load: f.loaderFunc,
|
||||
Name: "fs",
|
||||
}
|
||||
|
||||
func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *fs) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||
exports := map[string]util.LuaExport{
|
||||
"cd": util.LuaExport{fcd, 1, false},
|
||||
"mkdir": util.LuaExport{fmkdir, 2, false},
|
||||
"stat": util.LuaExport{fstat, 1, false},
|
||||
"readdir": util.LuaExport{freaddir, 1, false},
|
||||
"abs": util.LuaExport{fabs, 1, false},
|
||||
"basename": util.LuaExport{fbasename, 1, false},
|
||||
"dir": util.LuaExport{fdir, 1, false},
|
||||
"glob": util.LuaExport{fglob, 1, false},
|
||||
"join": util.LuaExport{fjoin, 0, true},
|
||||
"pipe": util.LuaExport{fpipe, 0, false},
|
||||
"cd": util.LuaExport{f.fcd, 1, false},
|
||||
"mkdir": util.LuaExport{f.fmkdir, 2, false},
|
||||
"stat": util.LuaExport{f.fstat, 1, false},
|
||||
"readdir": util.LuaExport{f.freaddir, 1, false},
|
||||
"abs": util.LuaExport{f.fabs, 1, false},
|
||||
"basename": util.LuaExport{f.fbasename, 1, false},
|
||||
"dir": util.LuaExport{f.fdir, 1, false},
|
||||
"glob": util.LuaExport{f.fglob, 1, false},
|
||||
"join": util.LuaExport{f.fjoin, 0, true},
|
||||
"pipe": util.LuaExport{f.fpipe, 0, false},
|
||||
}
|
||||
mod := rt.NewTable()
|
||||
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`.
|
||||
// #param path 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -72,7 +85,7 @@ func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
// `.` will be returned.
|
||||
// #param path string Path to get the base name of.
|
||||
// #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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -87,7 +100,7 @@ func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
// cd(dir)
|
||||
// Changes Hilbish's directory to `dir`.
|
||||
// #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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -97,10 +110,12 @@ func fcd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
|||
}
|
||||
path = util.ExpandHome(strings.TrimSpace(path))
|
||||
|
||||
abspath, _ := filepath.Abs(path)
|
||||
err = os.Chdir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
interp.Dir(abspath)(f.runner)
|
||||
|
||||
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`.
|
||||
// #param path string Path to get the directory for.
|
||||
// #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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -141,7 +156,7 @@ print(matches)
|
|||
-- -> {'init.lua', 'code.lua'}
|
||||
#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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -175,7 +190,7 @@ print(fs.join(hilbish.userDir.config, 'hilbish'))
|
|||
-- -> '/home/user/.config/hilbish' on Linux
|
||||
#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()))
|
||||
for i, v := range c.Etc() {
|
||||
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)
|
||||
#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 {
|
||||
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.
|
||||
// #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()
|
||||
if err != nil {
|
||||
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.
|
||||
// #param dir string
|
||||
// #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 {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -296,7 +311,7 @@ Would print the following:
|
|||
]]--
|
||||
#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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build darwin linux
|
||||
//go:build unix
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
|
|
3
lua.go
3
lua.go
|
@ -30,7 +30,8 @@ func luaInit() {
|
|||
util.DoString(l, "hilbish = require 'hilbish'")
|
||||
|
||||
// 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)
|
||||
|
||||
cmds = commander.New(l)
|
||||
|
|
20
main.go
20
main.go
|
@ -21,6 +21,7 @@ import (
|
|||
"github.com/pborman/getopt"
|
||||
"github.com/maxlandon/readline"
|
||||
"golang.org/x/term"
|
||||
"mvdan.cc/sh/v3/interp"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -37,9 +38,11 @@ var (
|
|||
cmds *commander.Commander
|
||||
defaultConfPath string
|
||||
defaultHistPath string
|
||||
runner *interp.Runner
|
||||
)
|
||||
|
||||
func main() {
|
||||
runner, _ = interp.New()
|
||||
curuser, _ = user.Current()
|
||||
homedir := curuser.HomeDir
|
||||
confDir, _ = os.UserConfigDir()
|
||||
|
@ -220,8 +223,9 @@ input:
|
|||
}
|
||||
|
||||
if strings.HasSuffix(input, "\\") {
|
||||
print("\n")
|
||||
for {
|
||||
input, err = continuePrompt(input)
|
||||
input, err = continuePrompt(strings.TrimSuffix(input, "\\") + "\n", false)
|
||||
if err != nil {
|
||||
running = true
|
||||
lr.SetPrompt(fmtPrompt(prompt))
|
||||
|
@ -245,16 +249,24 @@ input:
|
|||
exit(0)
|
||||
}
|
||||
|
||||
func continuePrompt(prev string) (string, error) {
|
||||
func continuePrompt(prev string, newline bool) (string, error) {
|
||||
hooks.Emit("multiline", nil)
|
||||
lr.SetPrompt(multilinePrompt)
|
||||
|
||||
cont, err := lr.Read()
|
||||
if err != nil {
|
||||
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)
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
local commander = require 'commander'
|
||||
|
||||
commander.register('exec', function(args)
|
||||
if #args == 0 then
|
||||
return
|
||||
end
|
||||
hilbish.exec(args[1])
|
||||
end)
|
||||
|
|
|
@ -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
|
||||
})
|
|
@ -24,6 +24,7 @@ require 'nature.opts'
|
|||
require 'nature.vim'
|
||||
require 'nature.runner'
|
||||
require 'nature.hummingbird'
|
||||
require 'nature.env'
|
||||
|
||||
local shlvl = tonumber(os.getenv 'SHLVL')
|
||||
if shlvl ~= nil then
|
||||
|
@ -32,36 +33,6 @@ else
|
|||
os.setenv('SHLVL', '0')
|
||||
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
|
||||
local startSearchPath = hilbish.userDir.data .. '/hilbish/start/?/init.lua;'
|
||||
.. hilbish.userDir.data .. '/hilbish/start/?.lua'
|
||||
|
|
|
@ -14,7 +14,8 @@ The nice lil shell for {blue}Lua{reset} fanatics!
|
|||
motd = true,
|
||||
fuzzy = false,
|
||||
notifyJobFinish = true,
|
||||
crimmas = true
|
||||
crimmas = true,
|
||||
tips = true
|
||||
}
|
||||
|
||||
for optsName, default in pairs(defaultOpts) do
|
||||
|
|
|
@ -2,8 +2,7 @@ local bait = require 'bait'
|
|||
local lunacolors = require 'lunacolors'
|
||||
|
||||
hilbish.motd = [[
|
||||
Finally at {red}v2.2!{reset} So much {green}documentation improvements{reset}
|
||||
and 1 single fix for Windows! {blue}.. and a feature they can't use.{reset}
|
||||
{magenta}Hilbish{reset} blooms in the {blue}midnight.{reset}
|
||||
]]
|
||||
|
||||
bait.catch('hilbish.init', function()
|
||||
|
|
|
@ -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)
|
|
@ -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.
|
||||
(So if there isn't an error, just omit `err`.)
|
||||
|
||||
- `exitCode` (number): A numerical code to indicate the exit result.
|
||||
- `input` (string): The user input. This will be used to add
|
||||
to the history.
|
||||
- `err` (string): A string to indicate an interal error for the runner.
|
||||
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 to prompt the user for more input.
|
||||
- `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
|
||||
- `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
|
||||
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
|
||||
}
|
||||
|
||||
_, exitCode, cont, err := execSh(aliases.Resolve(cmd))
|
||||
_, exitCode, cont, newline, err := execSh(aliases.Resolve(cmd))
|
||||
var luaErr rt.Value = rt.NilValue
|
||||
if err != nil {
|
||||
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("exitCode"), rt.IntValue(int64(exitCode)))
|
||||
runnerRet.Set(rt.StringValue("continue"), rt.BoolValue(cont))
|
||||
runnerRet.Set(rt.StringValue("newline"), rt.BoolValue(newline))
|
||||
runnerRet.Set(rt.StringValue("err"), luaErr)
|
||||
|
||||
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build darwin linux
|
||||
//go:build unix
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
|
|
4
vars.go
4
vars.go
|
@ -11,8 +11,8 @@ var (
|
|||
|
||||
// Version info
|
||||
var (
|
||||
ver = "v2.2.3"
|
||||
releaseName = "Poppy"
|
||||
ver = "v2.4.0"
|
||||
releaseName = "Moonflower"
|
||||
|
||||
gitCommit string
|
||||
gitBranch string
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build darwin
|
||||
//go:build darwin
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build linux
|
||||
//go:build unix && !darwin
|
||||
|
||||
package main
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
// +build windows
|
||||
//go:build windows
|
||||
|
||||
package main
|
||||
|
||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue