mirror of https://github.com/Hilbis/Hilbish
chore: merge from master
commit
f8d66f4b81
|
@ -0,0 +1,6 @@
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = tab
|
|
@ -25,7 +25,7 @@ jobs:
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v2
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '1.17.7'
|
go-version: '1.18.8'
|
||||||
- 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
|
||||||
|
|
|
@ -2,13 +2,14 @@ name: Generate docs
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [master]
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
gen:
|
gen:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
- name: Run docgen
|
- name: Run docgen
|
||||||
run: go run cmd/docgen/docgen.go
|
run: go run cmd/docgen/docgen.go
|
||||||
|
|
|
@ -33,10 +33,14 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Download Task
|
||||||
|
run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d'
|
||||||
- uses: wangyoucao577/go-release-action@v1.25
|
- uses: wangyoucao577/go-release-action@v1.25
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
goos: ${{ matrix.goos }}
|
goos: ${{ matrix.goos }}
|
||||||
goarch: ${{ matrix.goarch }}
|
goarch: ${{ matrix.goarch }}
|
||||||
|
ldflags: '-s -w'
|
||||||
binary_name: hilbish
|
binary_name: hilbish
|
||||||
extra_files: LICENSE README.md CHANGELOG.md .hilbishrc.lua nature libs docs emmyLuaDocs
|
extra_files: LICENSE README.md CHANGELOG.md .hilbishrc.lua nature libs docs emmyLuaDocs
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
name: Build website
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
- docs-refactor
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Hugo
|
||||||
|
uses: peaceiris/actions-hugo@v2
|
||||||
|
with:
|
||||||
|
hugo-version: 'latest'
|
||||||
|
extended: true
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: 'cd website && hugo --minify'
|
||||||
|
|
||||||
|
- name: Deploy
|
||||||
|
uses: peaceiris/actions-gh-pages@v3
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
publish_dir: ./website/public
|
|
@ -1,6 +1,9 @@
|
||||||
*.exe
|
*.exe
|
||||||
hilbish
|
hilbish
|
||||||
|
!docs/api/hilbish
|
||||||
docgen
|
docgen
|
||||||
|
!cmd/docgen
|
||||||
|
|
||||||
.vim
|
.vim
|
||||||
petals/
|
petals/
|
||||||
|
.hugo_build.lock
|
||||||
|
|
85
CHANGELOG.md
85
CHANGELOG.md
|
@ -1,7 +1,44 @@
|
||||||
# 🎀 Changelog
|
# 🎀 Changelog
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
**NOTE:** Hilbish now uses [Task] insead of Make for builds.
|
### Fixed
|
||||||
|
- Replaced `sed` in-place editing with `grep` and `mv` for compatibility with BSD utils
|
||||||
|
|
||||||
|
## [2.1.0] - 2022-02-10
|
||||||
|
### Added
|
||||||
|
- Documented custom userdata types (Job and Timer Objects)
|
||||||
|
- Coming with this fix is also adding the return types for some functions that were missing it
|
||||||
|
- Added a dedicated input and dedicated outputs for commanders (sinks - info at `doc api commander`).
|
||||||
|
- Local docs is used if one of Hilbish's branches is found
|
||||||
|
- Return 1 exit code on doc not found
|
||||||
|
- `hilbish.runner.getCurrent()` to get the current runner
|
||||||
|
- Initialize Hilbish Lua API before handling signals
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- `index` or `_index` subdocs should not show up anymore
|
||||||
|
- `hilbish.which` not working correctly with aliases
|
||||||
|
- Commanders not being able to pipe with commands or any related operator.
|
||||||
|
- Resolve symlinks in completions
|
||||||
|
- Updated `runner-mode` docs
|
||||||
|
- Fix `hilbish.completion` functions panicking when empty input is provided
|
||||||
|
|
||||||
|
## [2.0.1] - 2022-12-28
|
||||||
|
### Fixed
|
||||||
|
- Corrected documentation for hooks, removing outdated `command.no-perm`
|
||||||
|
- Fixed an issue where `cd` with no args would not update the old pwd
|
||||||
|
- Tiny documentation enhancements for the `hilbish.timer` interface
|
||||||
|
|
||||||
|
## [2.0.0] - 2022-12-20
|
||||||
|
**NOTES FOR USERS/PACKAGERS UPDATING:**
|
||||||
|
- Hilbish now uses [Task] insead of Make for builds.
|
||||||
|
- The doc format has been changed from plain text to markdown.
|
||||||
|
**YOU MUST reinstall Hilbish to remove the duplicate, old docs.**
|
||||||
|
- Hilbish will by default install to **`/usr/local`** instead of just `/usr/`
|
||||||
|
when building via Task. This is mainly to avoid conflict of distro packages
|
||||||
|
and local installs, and is the correct place when building from git either way.
|
||||||
|
To keep Hilbish in `/usr`, you must have `PREFIX="/usr/"` when running `task build` or `task install`
|
||||||
|
- Windows is no longer supported. It will build and run, but **will** have problems.
|
||||||
|
If you want to help fix the situation, start a discussion or open an issue and contribute.
|
||||||
|
|
||||||
[Task]: https://taskfile.dev/#/
|
[Task]: https://taskfile.dev/#/
|
||||||
|
|
||||||
|
@ -39,7 +76,7 @@ without arguments will disown the last job.
|
||||||
fields on a job object.
|
fields on a job object.
|
||||||
- Documentation for jobs is now available via `doc jobs`.
|
- Documentation for jobs is now available via `doc jobs`.
|
||||||
- `hilbish.alias.resolve(cmdstr)` to resolve a command alias.
|
- `hilbish.alias.resolve(cmdstr)` to resolve a command alias.
|
||||||
- `hilbish.opts` for shell options. Currently, the only opt is `autocd`.
|
- `hilbish.opts` for shell options.
|
||||||
- `hilbish.editor` interface for interacting with the line editor that
|
- `hilbish.editor` interface for interacting with the line editor that
|
||||||
Hilbish uses.
|
Hilbish uses.
|
||||||
- `hilbish.vim` interface to dynamically get/set vim registers.
|
- `hilbish.vim` interface to dynamically get/set vim registers.
|
||||||
|
@ -73,12 +110,20 @@ disables commands being added to history.
|
||||||
- A new and "safer" event emitter has been added. This causes a performance deficit, but avoids a lot of
|
- A new and "safer" event emitter has been added. This causes a performance deficit, but avoids a lot of
|
||||||
random errors introduced with the new Lua runtime (see [#197])
|
random errors introduced with the new Lua runtime (see [#197])
|
||||||
- `bait.release(name, catcher)` removes `handler` for the named `event`
|
- `bait.release(name, catcher)` removes `handler` for the named `event`
|
||||||
|
- `exec`, `clear` and `cat` builtin commands
|
||||||
|
- `hilbish.cancel` hook thrown when user cancels input with Ctrl-C
|
||||||
|
- 1st item on history is now inserted when history search menu is opened ([#148])
|
||||||
|
- Documentation has been improved vastly!
|
||||||
|
|
||||||
|
[#148]: https://github.com/Rosettea/Hilbish/issues/148
|
||||||
[#197]: https://github.com/Rosettea/Hilbish/issues/197
|
[#197]: https://github.com/Rosettea/Hilbish/issues/197
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- **Breaking Change:** Upgraded to Lua 5.4.
|
- **Breaking Change:** Upgraded to Lua 5.4.
|
||||||
This is probably one of (if not the) biggest things in this release.
|
This is probably one of (if not the) biggest things in this release.
|
||||||
|
To recap quickly on what matters (mostly):
|
||||||
|
- `os.execute` returns 3 values instead of 1 (but you should be using `hilbish.run`)
|
||||||
|
- I/O operations must be flushed (`io.flush()`)
|
||||||
- **Breaking Change:** MacOS config paths now match Linux.
|
- **Breaking Change:** MacOS config paths now match Linux.
|
||||||
- Overrides on the `hilbish` table are no longer permitted.
|
- Overrides on the `hilbish` table are no longer permitted.
|
||||||
- **Breaking Change:** Runner functions are now required to return a table.
|
- **Breaking Change:** Runner functions are now required to return a table.
|
||||||
|
@ -97,6 +142,7 @@ of a dot. (ie. `job.stop()` -> `job:stop()`)
|
||||||
- All `fs` module functions which take paths now implicitly expand ~ to home.
|
- All `fs` module functions which take paths now implicitly expand ~ to home.
|
||||||
- **Breaking Change:** `hilbish.greeting` has been moved to an opt (`hilbish.opts.greeting`) and is
|
- **Breaking Change:** `hilbish.greeting` has been moved to an opt (`hilbish.opts.greeting`) and is
|
||||||
always printed by default. To disable it, set the opt to false.
|
always printed by default. To disable it, set the opt to false.
|
||||||
|
- **Breaking Change:** `command.no-perm` hook has been replaced with `command.not-executable`
|
||||||
- History is now fetched from Lua, which means users can override `hilbish.history`
|
- History is now fetched from Lua, which means users can override `hilbish.history`
|
||||||
methods to make it act how they want.
|
methods to make it act how they want.
|
||||||
- `guide` has been removed. See the [website](https://rosettea.github.io/Hilbish/)
|
- `guide` has been removed. See the [website](https://rosettea.github.io/Hilbish/)
|
||||||
|
@ -112,7 +158,7 @@ replacing the last character.
|
||||||
- `hilbish.login` being the wrong value.
|
- `hilbish.login` being the wrong value.
|
||||||
- Put full input in history if prompted for continued input
|
- Put full input in history if prompted for continued input
|
||||||
- Don't put alias expanded command in history (sound familiar?)
|
- Don't put alias expanded command in history (sound familiar?)
|
||||||
- Handle cases of stdin being nonblocking (in the case of [#130](https://github.com/Rosettea/Hilbish/issues/130))
|
- Handle cases of stdin being nonblocking (in the case of [#136](https://github.com/Rosettea/Hilbish/issues/136))
|
||||||
- Don't prompt for continued input if non interactive
|
- Don't prompt for continued input if non interactive
|
||||||
- Don't insert unhandled control keys.
|
- Don't insert unhandled control keys.
|
||||||
- Handle sh syntax error in alias
|
- Handle sh syntax error in alias
|
||||||
|
@ -122,11 +168,12 @@ certain color rules.
|
||||||
- Home/End keys now go to the actual start/end of the input.
|
- Home/End keys now go to the actual start/end of the input.
|
||||||
- Input getting cut off on enter in certain cases.
|
- Input getting cut off on enter in certain cases.
|
||||||
- Go to the next line properly if input reaches end of terminal width.
|
- Go to the next line properly if input reaches end of terminal width.
|
||||||
- Cursor position with CJK characters. ([#145](https://github.com/Rosettea/Hilbish/pull/145))
|
- Cursor position with CJK characters has been corrected ([#145](https://github.com/Rosettea/Hilbish/pull/145))
|
||||||
- Files with same name as parent folder in completions getting cut off [#136](https://github.com/Rosettea/Hilbish/issues/136))
|
- Files with same name as parent folder in completions getting cut off [#130](https://github.com/Rosettea/Hilbish/issues/130))
|
||||||
- `hilbish.which` now works with commanders and aliases.
|
- `hilbish.which` now works with commanders and aliases.
|
||||||
- Background jobs no longer take stdin so they do not interfere with shell
|
- Background jobs no longer take stdin so they do not interfere with shell
|
||||||
input.
|
input.
|
||||||
|
- Full name of completion entry is used instead of being cut off
|
||||||
- Completions are fixed in cases where the query/line is an alias alone
|
- Completions are fixed in cases where the query/line is an alias alone
|
||||||
where it can also resolve to the beginning of command names.
|
where it can also resolve to the beginning of command names.
|
||||||
(reference [this commit](https://github.com/Rosettea/Hilbish/commit/2790982ad123115c6ddbc5764677fdca27668cea))
|
(reference [this commit](https://github.com/Rosettea/Hilbish/commit/2790982ad123115c6ddbc5764677fdca27668cea))
|
||||||
|
@ -145,6 +192,29 @@ menu is open.
|
||||||
- Escape codes now work.
|
- Escape codes now work.
|
||||||
- Escape percentage symbols in completion entries, so you will no longer see
|
- Escape percentage symbols in completion entries, so you will no longer see
|
||||||
an error of missing format variable
|
an error of missing format variable
|
||||||
|
- Fix an error with sh syntax in aliases
|
||||||
|
- Prompt now works with east asian characters (CJK)
|
||||||
|
- Set back the prompt to normal after exiting the continue prompt with ctrl-d
|
||||||
|
- Take into account newline in input when calculating input width. Prevents
|
||||||
|
extra reprinting of the prompt, but input with newlines inserted is still a problem
|
||||||
|
- Put cursor at the end of input when exiting $EDITOR with Vim mode bind
|
||||||
|
- Calculate width of virtual input properly (completion candidates)
|
||||||
|
- Users can now tab complete files with spaces while quoted or with escaped spaces.
|
||||||
|
This means a query of `Files\ to\ ` with file names of `Files to tab complete` and `Files to complete`
|
||||||
|
will result in the files being completed.
|
||||||
|
- Fixed grid menu display if cell width ends up being the width of the terminal
|
||||||
|
- Cut off item names in grid menu if its longer than cell width
|
||||||
|
- Fix completion search menu disappearing
|
||||||
|
- Make binary completion work with bins that have spaces in the name
|
||||||
|
- Completion paths having duplicated characters if it's escaped
|
||||||
|
- Get custom completion command properly to call from Lua
|
||||||
|
- Put proper command on the line when using up and down arrow keys to go through command history
|
||||||
|
- Don't do anything if length of input rune slice is 0 ([commit for explanation](https://github.com/Rosettea/Hilbish/commit/8d40179a73fe5942707cd43f9c0463dee53eedd8))
|
||||||
|
|
||||||
|
## [2.0.0-rc1] - 2022-09-14
|
||||||
|
This is a pre-release version of Hilbish for testing. To see the changelog,
|
||||||
|
refer to the `Unreleased` section of the [full changelog](CHANGELOG.md)
|
||||||
|
(version 2.0.0 for future reference).
|
||||||
|
|
||||||
## [1.2.0] - 2022-03-17
|
## [1.2.0] - 2022-03-17
|
||||||
### Added
|
### Added
|
||||||
|
@ -569,6 +639,11 @@ This input for example will prompt for more input to complete:
|
||||||
|
|
||||||
First "stable" release of Hilbish.
|
First "stable" release of Hilbish.
|
||||||
|
|
||||||
|
[2.1.0]: https://github.com/Rosettea/Hilbish/compare/v2.0.1...v2.1.0
|
||||||
|
[2.0.1]: https://github.com/Rosettea/Hilbish/compare/v2.0.0...v2.0.1
|
||||||
|
[2.0.0]: https://github.com/Rosettea/Hilbish/compare/v1.2.0...v2.0.0
|
||||||
|
[2.0.0-rc1]: https://github.com/Rosettea/Hilbish/compare/v1.2.0...v2.0.0-rc1
|
||||||
|
[1.2.0]: https://github.com/Rosettea/Hilbish/compare/v1.1.4...v1.2.0
|
||||||
[1.1.0]: https://github.com/Rosettea/Hilbish/compare/v1.0.4...v1.1.0
|
[1.1.0]: https://github.com/Rosettea/Hilbish/compare/v1.0.4...v1.1.0
|
||||||
[1.0.4]: https://github.com/Rosettea/Hilbish/compare/v1.0.3...v1.0.4
|
[1.0.4]: https://github.com/Rosettea/Hilbish/compare/v1.0.3...v1.0.4
|
||||||
[1.0.3]: https://github.com/Rosettea/Hilbish/compare/v1.0.2...v1.0.3
|
[1.0.3]: https://github.com/Rosettea/Hilbish/compare/v1.0.2...v1.0.3
|
||||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2022 Rosettea
|
Copyright (c) 2021-2023 Rosettea
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
43
README.md
43
README.md
|
@ -26,49 +26,30 @@ and aims to be infinitely configurable. If something isn't, open an issue!
|
||||||
|
|
||||||
# Table of Contents
|
# Table of Contents
|
||||||
- [Screenshots](#Screenshots)
|
- [Screenshots](#Screenshots)
|
||||||
- [Installation](#Installation)
|
- [Getting Hilbish](#Getting-Hilbish)
|
||||||
- [Prebuilt Bins](#Prebuilt-binaries)
|
|
||||||
- [AUR](#AUR)
|
|
||||||
- [Nixpkgs](#Nixpkgs)
|
|
||||||
- [Manual Build](#Manual-Build)
|
|
||||||
- [Getting Started](#Getting-Started)
|
|
||||||
- [Contributing](#Contributing)
|
- [Contributing](#Contributing)
|
||||||
|
|
||||||
# Screenshots
|
# Screenshots
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="gallery/default.png"><br><br>
|
|
||||||
<img src="gallery/terminal.png"><br><br>
|
<img src="gallery/terminal.png"><br><br>
|
||||||
|
<img src="gallery/tab.png"><br><br>
|
||||||
<img src="gallery/pillprompt.png">
|
<img src="gallery/pillprompt.png">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
# Installation
|
# Getting Hilbish
|
||||||
## Prebuilt binaries
|
**NOTE:** Hilbish is not guaranteed to work properly on Windows, starting
|
||||||
Go [here](https://nightly.link/Rosettea/Hilbish/workflows/build/master) for
|
from the 2.0 version. It will still be able to compile, but functionality
|
||||||
builds on the master branch.
|
may be lacking.
|
||||||
|
|
||||||
## AUR
|
You can check the [install page](https://rosettea.github.io/Hilbish/install/)
|
||||||
[![AUR maintainer](https://img.shields.io/aur/maintainer/hilbish?logo=arch-linux&style=flat-square)](https://aur.archlinux.org/packages/hilbish)
|
on the website for distributed binaries from GitHub or other package repositories.
|
||||||
Arch Linux users can install Hilbish from the AUR with the following command:
|
Otherwise, continue reading for steps on compiling.
|
||||||
```sh
|
|
||||||
yay -S hilbish
|
|
||||||
```
|
|
||||||
|
|
||||||
[![AUR maintainer](https://img.shields.io/aur/maintainer/hilbish?logo=arch-linux&style=flat-square)](https://aur.archlinux.org/packages/hilbish-git)
|
## Prerequisites
|
||||||
Or from the latest `master` commit with:
|
|
||||||
```sh
|
|
||||||
yay -S hilbish-git
|
|
||||||
```
|
|
||||||
|
|
||||||
## Nixpkgs
|
|
||||||
Nix/NixOS users can install Hilbish from the central repository, nixpkgs, through the usual ways.
|
|
||||||
If you're new to nix you should probably read up on how to do that [here](https://nixos.wiki/wiki/Cheatsheet).
|
|
||||||
|
|
||||||
## Manual Build
|
|
||||||
### Prerequisites
|
|
||||||
- [Go 1.17+](https://go.dev)
|
- [Go 1.17+](https://go.dev)
|
||||||
- [Task](https://taskfile.dev/#/)
|
- [Task](https://taskfile.dev/installation/) (**Go on the hyperlink here to see Task's install method for your OS.**)
|
||||||
|
|
||||||
### Build
|
## Build
|
||||||
First, clone Hilbish. The recursive is required, as some Lua libraries
|
First, clone Hilbish. The recursive is required, as some Lua libraries
|
||||||
are submodules.
|
are submodules.
|
||||||
```sh
|
```sh
|
||||||
|
|
|
@ -3,23 +3,24 @@
|
||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
vars:
|
vars:
|
||||||
PREFIX: '{{default "/usr" .PREFIX}}'
|
PREFIX: '{{default "/usr/local" .PREFIX}}'
|
||||||
bindir__: '{{.PREFIX}}/bin'
|
bindir__: '{{.PREFIX}}/bin'
|
||||||
BINDIR: '{{default .bindir__ .BINDIR}}'
|
BINDIR: '{{default .bindir__ .BINDIR}}'
|
||||||
libdir__: '{{.PREFIX}}/share/hilbish'
|
libdir__: '{{.PREFIX}}/share/hilbish'
|
||||||
LIBDIR: '{{default .libdir__ .LIBDIR}}'
|
LIBDIR: '{{default .libdir__ .LIBDIR}}'
|
||||||
GOFLAGS: '-ldflags "-s -w"'
|
goflags__: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"'
|
||||||
|
GOFLAGS: '{{default .goflags__ .GOFLAGS}}'
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
default:
|
default:
|
||||||
cmds:
|
cmds:
|
||||||
- go build {{.GOFLAGS}}
|
- CGO_ENABLED=0 go build {{.GOFLAGS}}
|
||||||
vars:
|
vars:
|
||||||
GOFLAGS: '-ldflags "-s -w -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"'
|
GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}} -X main.gitCommit=$(git rev-parse --short HEAD) -X main.gitBranch=$(git rev-parse --abbrev-ref HEAD)"'
|
||||||
|
|
||||||
build:
|
build:
|
||||||
cmds:
|
cmds:
|
||||||
- go build {{.GOFLAGS}}
|
- CGO_ENABLED=0 go build {{.GOFLAGS}}
|
||||||
|
|
||||||
install:
|
install:
|
||||||
cmds:
|
cmds:
|
||||||
|
@ -33,4 +34,4 @@ tasks:
|
||||||
- rm -vrf
|
- rm -vrf
|
||||||
"{{.DESTDIR}}{{.BINDIR}}/hilbish"
|
"{{.DESTDIR}}{{.BINDIR}}/hilbish"
|
||||||
"{{.DESTDIR}}{{.LIBDIR}}"
|
"{{.DESTDIR}}{{.LIBDIR}}"
|
||||||
- sed -i '/hilbish/d' /etc/shells
|
- grep -v 'hilbish' /etc/shells > /tmp/shells.hilbish_uninstall && mv /tmp/shells.hilbish_uninstall /etc/shells
|
||||||
|
|
47
aliases.go
47
aliases.go
|
@ -9,40 +9,40 @@ import (
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var aliases *aliasHandler
|
var aliases *aliasModule
|
||||||
|
|
||||||
type aliasHandler struct {
|
type aliasModule struct {
|
||||||
aliases map[string]string
|
aliases map[string]string
|
||||||
mu *sync.RWMutex
|
mu *sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize aliases map
|
// initialize aliases map
|
||||||
func newAliases() *aliasHandler {
|
func newAliases() *aliasModule {
|
||||||
return &aliasHandler{
|
return &aliasModule{
|
||||||
aliases: make(map[string]string),
|
aliases: make(map[string]string),
|
||||||
mu: &sync.RWMutex{},
|
mu: &sync.RWMutex{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) Add(alias, cmd string) {
|
func (a *aliasModule) Add(alias, cmd string) {
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
defer a.mu.Unlock()
|
defer a.mu.Unlock()
|
||||||
|
|
||||||
a.aliases[alias] = cmd
|
a.aliases[alias] = cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) All() map[string]string {
|
func (a *aliasModule) All() map[string]string {
|
||||||
return a.aliases
|
return a.aliases
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) Delete(alias string) {
|
func (a *aliasModule) Delete(alias string) {
|
||||||
a.mu.Lock()
|
a.mu.Lock()
|
||||||
defer a.mu.Unlock()
|
defer a.mu.Unlock()
|
||||||
|
|
||||||
delete(a.aliases, alias)
|
delete(a.aliases, alias)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) Resolve(cmdstr string) string {
|
func (a *aliasModule) Resolve(cmdstr string) string {
|
||||||
a.mu.RLock()
|
a.mu.RLock()
|
||||||
defer a.mu.RUnlock()
|
defer a.mu.RUnlock()
|
||||||
|
|
||||||
|
@ -66,7 +66,10 @@ func (a *aliasHandler) Resolve(cmdstr string) string {
|
||||||
|
|
||||||
// lua section
|
// lua section
|
||||||
|
|
||||||
func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
|
// #interface aliases
|
||||||
|
// command aliasing
|
||||||
|
// The alias interface deals with all command aliases in Hilbish.
|
||||||
|
func (a *aliasModule) Loader(rtm *rt.Runtime) *rt.Table {
|
||||||
// create a lua module with our functions
|
// create a lua module with our functions
|
||||||
hshaliasesLua := map[string]util.LuaExport{
|
hshaliasesLua := map[string]util.LuaExport{
|
||||||
"add": util.LuaExport{hlalias, 2, false},
|
"add": util.LuaExport{hlalias, 2, false},
|
||||||
|
@ -81,7 +84,18 @@ func (a *aliasHandler) Loader(rtm *rt.Runtime) *rt.Table {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
// #interface aliases
|
||||||
|
// add(alias, cmd)
|
||||||
|
// This is an alias (ha) for the `hilbish.alias` function.
|
||||||
|
// --- @param alias string
|
||||||
|
// --- @param cmd string
|
||||||
|
func _hlalias() {}
|
||||||
|
|
||||||
|
// #interface aliases
|
||||||
|
// list() -> table<string, string>
|
||||||
|
// Get a table of all aliases, with string keys as the alias and the value as the command.
|
||||||
|
// --- @returns table<string, string>
|
||||||
|
func (a *aliasModule) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
aliasesList := rt.NewTable()
|
aliasesList := rt.NewTable()
|
||||||
for k, v := range a.All() {
|
for k, v := range a.All() {
|
||||||
aliasesList.Set(rt.StringValue(k), rt.StringValue(v))
|
aliasesList.Set(rt.StringValue(k), rt.StringValue(v))
|
||||||
|
@ -90,7 +104,11 @@ func (a *aliasHandler) luaList(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(aliasesList)), nil
|
return c.PushingNext1(t.Runtime, rt.TableValue(aliasesList)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
// #interface aliases
|
||||||
|
// delete(name)
|
||||||
|
// Removes an alias.
|
||||||
|
// --- @param name string
|
||||||
|
func (a *aliasModule) luaDelete(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
|
||||||
}
|
}
|
||||||
|
@ -103,7 +121,12 @@ func (a *aliasHandler) luaDelete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *aliasHandler) luaResolve(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
// #interface aliases
|
||||||
|
// resolve(alias) -> command (string)
|
||||||
|
// Tries to resolve an alias to its command.
|
||||||
|
// --- @param alias string
|
||||||
|
// --- @returns string
|
||||||
|
func (a *aliasModule) luaResolve(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
|
||||||
}
|
}
|
||||||
|
|
139
api.go
139
api.go
|
@ -1,6 +1,14 @@
|
||||||
// Here is the core api for the hilbi shell itself
|
// the core Hilbish API
|
||||||
// Basically, stuff about the shell itself and other functions
|
// The Hilbish module includes the core API, containing
|
||||||
// go here.
|
// interfaces and functions which directly relate to shell functionality.
|
||||||
|
// #field ver The version of Hilbish
|
||||||
|
// #field user Username of the user
|
||||||
|
// #field host Hostname of the machine
|
||||||
|
// #field dataDir Directory for Hilbish data files, including the docs and default modules
|
||||||
|
// #field interactive Is Hilbish in an interactive shell?
|
||||||
|
// #field login Is Hilbish the login shell?
|
||||||
|
// #field vimMode Current Vim input mode of Hilbish (will be nil if not in Vim input mode)
|
||||||
|
// #field exitCode xit code of the last executed command
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -19,7 +27,6 @@ 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/maxlandon/readline"
|
"github.com/maxlandon/readline"
|
||||||
"github.com/blackfireio/osinfo"
|
|
||||||
"mvdan.cc/sh/v3/interp"
|
"mvdan.cc/sh/v3/interp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -102,78 +109,59 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
username = strings.Split(username, "\\")[1] // for some reason Username includes the hostname on windows
|
username = strings.Split(username, "\\")[1] // for some reason Username includes the hostname on windows
|
||||||
}
|
}
|
||||||
|
|
||||||
util.SetFieldProtected(fakeMod, mod, "ver", rt.StringValue(getVersion()), "Hilbish version")
|
util.SetFieldProtected(fakeMod, mod, "ver", rt.StringValue(getVersion()))
|
||||||
util.SetFieldProtected(fakeMod, mod, "user", rt.StringValue(username), "Username of user")
|
util.SetFieldProtected(fakeMod, mod, "user", rt.StringValue(username))
|
||||||
util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host), "Host name of the machine")
|
util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host))
|
||||||
util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir), "Home directory of the user")
|
util.SetFieldProtected(fakeMod, mod, "home", rt.StringValue(curuser.HomeDir))
|
||||||
util.SetFieldProtected(fakeMod, mod, "dataDir", rt.StringValue(dataDir), "Directory for Hilbish's data files")
|
util.SetFieldProtected(fakeMod, mod, "dataDir", rt.StringValue(dataDir))
|
||||||
util.SetFieldProtected(fakeMod, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive shell")
|
util.SetFieldProtected(fakeMod, mod, "interactive", rt.BoolValue(interactive))
|
||||||
util.SetFieldProtected(fakeMod, mod, "login", rt.BoolValue(login), "Whether this is a login shell")
|
util.SetFieldProtected(fakeMod, mod, "login", rt.BoolValue(login))
|
||||||
util.SetFieldProtected(fakeMod, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
util.SetFieldProtected(fakeMod, mod, "vimMode", rt.NilValue)
|
||||||
util.SetFieldProtected(fakeMod, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command")
|
util.SetFieldProtected(fakeMod, mod, "exitCode", rt.IntValue(0))
|
||||||
util.Document(fakeMod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.")
|
|
||||||
|
|
||||||
// hilbish.userDir table
|
// hilbish.userDir table
|
||||||
hshuser := rt.NewTable()
|
hshuser := userDirLoader(rtm)
|
||||||
|
|
||||||
util.SetField(rtm, hshuser, "config", rt.StringValue(confDir), "User's config directory")
|
|
||||||
util.SetField(rtm, hshuser, "data", rt.StringValue(userDataDir), "XDG data directory")
|
|
||||||
util.Document(hshuser, "User directories to store configs and/or modules.")
|
|
||||||
mod.Set(rt.StringValue("userDir"), rt.TableValue(hshuser))
|
mod.Set(rt.StringValue("userDir"), rt.TableValue(hshuser))
|
||||||
|
|
||||||
// hilbish.os table
|
// hilbish.os table
|
||||||
hshos := rt.NewTable()
|
hshos := hshosLoader(rtm)
|
||||||
info, _ := osinfo.GetOSInfo()
|
|
||||||
|
|
||||||
util.SetField(rtm, hshos, "family", rt.StringValue(info.Family), "Family name of the current OS")
|
|
||||||
util.SetField(rtm, hshos, "name", rt.StringValue(info.Name), "Pretty name of the current OS")
|
|
||||||
util.SetField(rtm, hshos, "version", rt.StringValue(info.Version), "Version of the current OS")
|
|
||||||
util.Document(hshos, "OS info interface")
|
|
||||||
mod.Set(rt.StringValue("os"), rt.TableValue(hshos))
|
mod.Set(rt.StringValue("os"), rt.TableValue(hshos))
|
||||||
|
|
||||||
// hilbish.aliases table
|
// hilbish.aliases table
|
||||||
aliases = newAliases()
|
aliases = newAliases()
|
||||||
aliasesModule := aliases.Loader(rtm)
|
aliasesModule := aliases.Loader(rtm)
|
||||||
util.Document(aliasesModule, "Alias inferface for Hilbish.")
|
|
||||||
mod.Set(rt.StringValue("aliases"), rt.TableValue(aliasesModule))
|
mod.Set(rt.StringValue("aliases"), rt.TableValue(aliasesModule))
|
||||||
|
|
||||||
// hilbish.history table
|
// hilbish.history table
|
||||||
historyModule := lr.Loader(rtm)
|
historyModule := lr.Loader(rtm)
|
||||||
mod.Set(rt.StringValue("history"), rt.TableValue(historyModule))
|
mod.Set(rt.StringValue("history"), rt.TableValue(historyModule))
|
||||||
util.Document(historyModule, "History interface for Hilbish.")
|
|
||||||
|
|
||||||
// hilbish.completion table
|
// hilbish.completion table
|
||||||
hshcomp := completionLoader(rtm)
|
hshcomp := completionLoader(rtm)
|
||||||
util.Document(hshcomp, "Completions interface for Hilbish.")
|
|
||||||
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
|
mod.Set(rt.StringValue("completion"), rt.TableValue(hshcomp))
|
||||||
|
|
||||||
// hilbish.runner table
|
// hilbish.runner table
|
||||||
runnerModule := runnerModeLoader(rtm)
|
runnerModule := runnerModeLoader(rtm)
|
||||||
util.Document(runnerModule, "Runner/exec interface for Hilbish.")
|
|
||||||
mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule))
|
mod.Set(rt.StringValue("runner"), rt.TableValue(runnerModule))
|
||||||
|
|
||||||
// hilbish.jobs table
|
// hilbish.jobs table
|
||||||
jobs = newJobHandler()
|
jobs = newJobHandler()
|
||||||
jobModule := jobs.loader(rtm)
|
jobModule := jobs.loader(rtm)
|
||||||
util.Document(jobModule, "(Background) job interface.")
|
|
||||||
mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
|
mod.Set(rt.StringValue("jobs"), rt.TableValue(jobModule))
|
||||||
|
|
||||||
// hilbish.timers table
|
// hilbish.timers table
|
||||||
timers = newTimerHandler()
|
timers = newTimersModule()
|
||||||
timerModule := timers.loader(rtm)
|
timersModule := timers.loader(rtm)
|
||||||
util.Document(timerModule, "Timer interface, for control of all intervals and timeouts.")
|
mod.Set(rt.StringValue("timers"), rt.TableValue(timersModule))
|
||||||
mod.Set(rt.StringValue("timers"), rt.TableValue(timerModule))
|
|
||||||
|
|
||||||
editorModule := editorLoader(rtm)
|
editorModule := editorLoader(rtm)
|
||||||
util.Document(editorModule, "")
|
|
||||||
mod.Set(rt.StringValue("editor"), rt.TableValue(editorModule))
|
mod.Set(rt.StringValue("editor"), rt.TableValue(editorModule))
|
||||||
|
|
||||||
versionModule := rt.NewTable()
|
versionModule := rt.NewTable()
|
||||||
util.SetField(rtm, versionModule, "branch", rt.StringValue(gitBranch), "Git branch Hilbish was compiled from")
|
util.SetField(rtm, versionModule, "branch", rt.StringValue(gitBranch))
|
||||||
util.SetField(rtm, versionModule, "full", rt.StringValue(getVersion()), "Full version info, including release name")
|
util.SetField(rtm, versionModule, "full", rt.StringValue(getVersion()))
|
||||||
util.SetField(rtm, versionModule, "commit", rt.StringValue(gitCommit), "Git commit Hilbish was compiled from")
|
util.SetField(rtm, versionModule, "commit", rt.StringValue(gitCommit))
|
||||||
util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName), "Release name")
|
util.SetField(rtm, versionModule, "release", rt.StringValue(releaseName))
|
||||||
util.Document(versionModule, "Version info interface.")
|
|
||||||
mod.Set(rt.StringValue("version"), rt.TableValue(versionModule))
|
mod.Set(rt.StringValue("version"), rt.TableValue(versionModule))
|
||||||
|
|
||||||
pluginModule := moduleLoader(rtm)
|
pluginModule := moduleLoader(rtm)
|
||||||
|
@ -192,19 +180,21 @@ func getenv(key, fallback string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func setVimMode(mode string) {
|
func setVimMode(mode string) {
|
||||||
util.SetField(l, hshMod, "vimMode", rt.StringValue(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
util.SetField(l, hshMod, "vimMode", rt.StringValue(mode))
|
||||||
hooks.Emit("hilbish.vimMode", mode)
|
hooks.Emit("hilbish.vimMode", mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unsetVimMode() {
|
func unsetVimMode() {
|
||||||
util.SetField(l, hshMod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)")
|
util.SetField(l, hshMod, "vimMode", rt.NilValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// run(cmd, returnOut) -> exitCode, stdout, stderr
|
// run(cmd, returnOut) -> exitCode (number), stdout (string), stderr (string)
|
||||||
// Runs `cmd` in Hilbish's sh interpreter.
|
// Runs `cmd` in Hilbish's sh interpreter.
|
||||||
// If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
// If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
||||||
// 3rd values instead of being outputted to the terminal.
|
// 3rd values instead of being outputted to the terminal.
|
||||||
// --- @param cmd string
|
// --- @param cmd string
|
||||||
|
// --- @param returnOut boolean
|
||||||
|
// --- @returns number, string, string
|
||||||
func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlrun(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
|
||||||
|
@ -245,8 +235,9 @@ func hlrun(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitcode)), rt.StringValue(stdoutStr), rt.StringValue(stderrStr)), nil
|
return c.PushingNext(t.Runtime, rt.IntValue(int64(exitcode)), rt.StringValue(stdoutStr), rt.StringValue(stderrStr)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// cwd()
|
// cwd() -> string
|
||||||
// Returns the current directory of the shell
|
// Returns the current directory of the shell
|
||||||
|
// --- @returns string
|
||||||
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
cwd, _ := os.Getwd()
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
|
@ -254,21 +245,28 @@ func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// read(prompt) -> input?
|
// read(prompt) -> input (string)
|
||||||
// Read input from the user, using Hilbish's line editor/input reader.
|
// Read input from the user, using Hilbish's line editor/input reader.
|
||||||
// This is a separate instance from the one Hilbish actually uses.
|
// This is a separate instance from the one Hilbish actually uses.
|
||||||
// Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
// Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
||||||
// --- @param prompt string
|
// --- @param prompt? string
|
||||||
|
// --- @returns string|nil
|
||||||
func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.Check1Arg(); err != nil {
|
luaprompt := c.Arg(0)
|
||||||
return nil, err
|
if typ := luaprompt.Type(); typ != rt.StringType && typ != rt.NilType {
|
||||||
|
return nil, errors.New("expected #1 to be a string")
|
||||||
}
|
}
|
||||||
luaprompt, err := c.StringArg(0)
|
prompt, ok := luaprompt.TryString()
|
||||||
if err != nil {
|
if !ok {
|
||||||
return nil, err
|
// if we are here and `luaprompt` is not a string, it's nil
|
||||||
|
// substitute with an empty string
|
||||||
|
prompt = ""
|
||||||
}
|
}
|
||||||
lualr := newLineReader("", true)
|
|
||||||
lualr.SetPrompt(luaprompt)
|
lualr := &lineReader{
|
||||||
|
rl: readline.NewInstance(),
|
||||||
|
}
|
||||||
|
lualr.SetPrompt(prompt)
|
||||||
|
|
||||||
input, err := lualr.Read()
|
input, err := lualr.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -279,7 +277,7 @@ func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
prompt(str, typ?)
|
prompt(str, typ)
|
||||||
Changes the shell prompt to `str`
|
Changes the shell prompt to `str`
|
||||||
There are a few verbs that can be used in the prompt text.
|
There are a few verbs that can be used in the prompt text.
|
||||||
These will be formatted and replaced with the appropriate values.
|
These will be formatted and replaced with the appropriate values.
|
||||||
|
@ -287,7 +285,7 @@ These will be formatted and replaced with the appropriate values.
|
||||||
`%u` - Name of current user
|
`%u` - Name of current user
|
||||||
`%h` - Hostname of device
|
`%h` - Hostname of device
|
||||||
--- @param str string
|
--- @param str string
|
||||||
--- @param typ string Type of prompt, being left or right. Left by default.
|
--- @param typ? string Type of prompt, being left or right. Left by default.
|
||||||
*/
|
*/
|
||||||
func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlprompt(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
err := c.Check1Arg()
|
err := c.Check1Arg()
|
||||||
|
@ -451,12 +449,12 @@ func hlgoro(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeout(cb, time)
|
// timeout(cb, time) -> @Timer
|
||||||
// Runs the `cb` function after `time` in milliseconds
|
// Runs the `cb` function after `time` in milliseconds.
|
||||||
// Returns a `timer` object (see `doc timers`).
|
// This creates a timer that starts immediately.
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
// --- @param time number
|
// --- @param time number
|
||||||
// --- @return table
|
// --- @returns Timer
|
||||||
func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hltimeout(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
|
||||||
|
@ -477,12 +475,12 @@ func hltimeout(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil
|
return c.PushingNext1(t.Runtime, rt.UserDataValue(timer.ud)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// interval(cb, time)
|
// interval(cb, time) -> @Timer
|
||||||
// Runs the `cb` function every `time` milliseconds.
|
// Runs the `cb` function every `time` milliseconds.
|
||||||
// Returns a `timer` object (see `doc timers`).
|
// This creates a timer that starts immediately.
|
||||||
// --- @param cb function
|
// --- @param cb function
|
||||||
// --- @param time number
|
// --- @param time number
|
||||||
// --- @return table
|
// --- @return Timer
|
||||||
func hlinterval(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlinterval(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
|
||||||
|
@ -543,9 +541,11 @@ func hlprependPath(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// which(name)
|
// which(name) -> string
|
||||||
// Checks if `name` is a valid command
|
// Checks if `name` is a valid command.
|
||||||
// --- @param binName string
|
// Will return the path of the binary, or a basename if it's a commander.
|
||||||
|
// --- @param name string
|
||||||
|
// --- @returns string
|
||||||
func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlwhich(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
|
||||||
|
@ -555,7 +555,10 @@ func hlwhich(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := aliases.Resolve(name)
|
// itll return either the original command or what was passed
|
||||||
|
// if name isnt empty its not an issue
|
||||||
|
alias := aliases.Resolve(name)
|
||||||
|
cmd := strings.Split(alias, " ")[0]
|
||||||
|
|
||||||
// check for commander
|
// check for commander
|
||||||
if commands[cmd] != nil {
|
if commands[cmd] != nil {
|
||||||
|
@ -630,7 +633,7 @@ func hlrunnerMode(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
// as the text for the hint. This is by default a shim. To set hints,
|
// as the text for the hint. This is by default a shim. To set hints,
|
||||||
// override this function with your custom handler.
|
// override this function with your custom handler.
|
||||||
// --- @param line string
|
// --- @param line string
|
||||||
// --- @param pos int
|
// --- @param pos number
|
||||||
func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func hlhinter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,28 +7,266 @@ import (
|
||||||
"go/doc"
|
"go/doc"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"os"
|
"os"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EmmyPiece struct {
|
var header = `---
|
||||||
FuncName string
|
title: %s %s
|
||||||
Docs []string
|
description: %s
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
type emmyPiece struct {
|
||||||
|
DocPiece *docPiece
|
||||||
|
Annotations []string
|
||||||
Params []string // we only need to know param name to put in function
|
Params []string // we only need to know param name to put in function
|
||||||
|
FuncName string
|
||||||
}
|
}
|
||||||
type DocPiece struct {
|
|
||||||
|
type module struct {
|
||||||
|
Types []docPiece
|
||||||
|
Docs []docPiece
|
||||||
|
Fields []docPiece
|
||||||
|
Properties []docPiece
|
||||||
|
ShortDescription string
|
||||||
|
Description string
|
||||||
|
ParentModule string
|
||||||
|
HasInterfaces bool
|
||||||
|
HasTypes bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type docPiece struct {
|
||||||
Doc []string
|
Doc []string
|
||||||
FuncSig string
|
FuncSig string
|
||||||
FuncName string
|
FuncName string
|
||||||
|
Interfacing string
|
||||||
|
ParentModule string
|
||||||
|
GoFuncName string
|
||||||
|
IsInterface bool
|
||||||
|
IsMember bool
|
||||||
|
IsType bool
|
||||||
|
Fields []docPiece
|
||||||
|
Properties []docPiece
|
||||||
|
}
|
||||||
|
|
||||||
|
type tag struct {
|
||||||
|
id string
|
||||||
|
fields []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var docs = make(map[string]module)
|
||||||
|
var interfaceDocs = make(map[string]module)
|
||||||
|
var emmyDocs = make(map[string][]emmyPiece)
|
||||||
|
var typeTable = make(map[string][]string) // [0] = parentMod, [1] = interfaces
|
||||||
|
var prefix = map[string]string{
|
||||||
|
"main": "hl",
|
||||||
|
"hilbish": "hl",
|
||||||
|
"fs": "f",
|
||||||
|
"commander": "c",
|
||||||
|
"bait": "b",
|
||||||
|
"terminal": "term",
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTagsAndDocs(docs string) (map[string][]tag, []string) {
|
||||||
|
pts := strings.Split(docs, "\n")
|
||||||
|
parts := []string{}
|
||||||
|
tags := make(map[string][]tag)
|
||||||
|
|
||||||
|
for _, part := range pts {
|
||||||
|
if strings.HasPrefix(part, "#") {
|
||||||
|
tagParts := strings.Split(strings.TrimPrefix(part, "#"), " ")
|
||||||
|
if tags[tagParts[0]] == nil {
|
||||||
|
var id string
|
||||||
|
if len(tagParts) > 1 {
|
||||||
|
id = tagParts[1]
|
||||||
|
}
|
||||||
|
tags[tagParts[0]] = []tag{
|
||||||
|
{id: id},
|
||||||
|
}
|
||||||
|
if len(tagParts) >= 2 {
|
||||||
|
tags[tagParts[0]][0].fields = tagParts[2:]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fleds := []string{}
|
||||||
|
if len(tagParts) >= 2 {
|
||||||
|
fleds = tagParts[2:]
|
||||||
|
}
|
||||||
|
tags[tagParts[0]] = append(tags[tagParts[0]], tag{
|
||||||
|
id: tagParts[1],
|
||||||
|
fields: fleds,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parts = append(parts, part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tags, parts
|
||||||
|
}
|
||||||
|
|
||||||
|
func docPieceTag(tagName string, tags map[string][]tag) []docPiece {
|
||||||
|
dps := []docPiece{}
|
||||||
|
for _, tag := range tags[tagName] {
|
||||||
|
dps = append(dps, docPiece{
|
||||||
|
FuncName: tag.id,
|
||||||
|
Doc: tag.fields,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return dps
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupDocType(mod string, typ *doc.Type) *docPiece {
|
||||||
|
docs := strings.TrimSpace(typ.Doc)
|
||||||
|
tags, doc := getTagsAndDocs(docs)
|
||||||
|
|
||||||
|
if tags["type"] == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
inInterface := tags["interface"] != nil
|
||||||
|
|
||||||
|
var interfaces string
|
||||||
|
typeName := strings.ToUpper(string(typ.Name[0])) + typ.Name[1:]
|
||||||
|
typeDoc := []string{}
|
||||||
|
|
||||||
|
if inInterface {
|
||||||
|
interfaces = tags["interface"][0].id
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := docPieceTag("field", tags)
|
||||||
|
properties := docPieceTag("property", tags)
|
||||||
|
|
||||||
|
for _, d := range doc {
|
||||||
|
if strings.HasPrefix(d, "---") {
|
||||||
|
// TODO: document types in lua
|
||||||
|
/*
|
||||||
|
emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
|
||||||
|
emmyLinePieces := strings.Split(emmyLine, " ")
|
||||||
|
emmyType := emmyLinePieces[0]
|
||||||
|
if emmyType == "@param" {
|
||||||
|
em.Params = append(em.Params, emmyLinePieces[1])
|
||||||
|
}
|
||||||
|
if emmyType == "@vararg" {
|
||||||
|
em.Params = append(em.Params, "...") // add vararg
|
||||||
|
}
|
||||||
|
em.Annotations = append(em.Annotations, d)
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
typeDoc = append(typeDoc, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMember bool
|
||||||
|
if tags["member"] != nil {
|
||||||
|
isMember = true
|
||||||
|
}
|
||||||
|
parentMod := mod
|
||||||
|
dps := &docPiece{
|
||||||
|
Doc: typeDoc,
|
||||||
|
FuncName: typeName,
|
||||||
|
Interfacing: interfaces,
|
||||||
|
IsInterface: inInterface,
|
||||||
|
IsMember: isMember,
|
||||||
|
IsType: true,
|
||||||
|
ParentModule: parentMod,
|
||||||
|
Fields: fields,
|
||||||
|
Properties: properties,
|
||||||
|
}
|
||||||
|
|
||||||
|
typeTable[strings.ToLower(typeName)] = []string{parentMod, interfaces}
|
||||||
|
|
||||||
|
return dps
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupDoc(mod string, fun *doc.Func) *docPiece {
|
||||||
|
docs := strings.TrimSpace(fun.Doc)
|
||||||
|
tags, parts := getTagsAndDocs(docs)
|
||||||
|
|
||||||
|
// i couldnt fit this into the condition below for some reason so here's a goto!
|
||||||
|
if tags["member"] != nil {
|
||||||
|
goto start
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strings.HasPrefix(fun.Name, prefix[mod]) && tags["interface"] == nil) || (strings.ToLower(fun.Name) == "loader" && tags["interface"] == nil) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
start:
|
||||||
|
inInterface := tags["interface"] != nil
|
||||||
|
var interfaces string
|
||||||
|
funcsig := parts[0]
|
||||||
|
doc := parts[1:]
|
||||||
|
funcName := strings.TrimPrefix(fun.Name, prefix[mod])
|
||||||
|
funcdoc := []string{}
|
||||||
|
|
||||||
|
if inInterface {
|
||||||
|
interfaces = tags["interface"][0].id
|
||||||
|
funcName = interfaces + "." + strings.Split(funcsig, "(")[0]
|
||||||
|
}
|
||||||
|
em := emmyPiece{FuncName: funcName}
|
||||||
|
|
||||||
|
fields := docPieceTag("field", tags)
|
||||||
|
properties := docPieceTag("property", tags)
|
||||||
|
|
||||||
|
for _, d := range doc {
|
||||||
|
if strings.HasPrefix(d, "---") {
|
||||||
|
emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
|
||||||
|
emmyLinePieces := strings.Split(emmyLine, " ")
|
||||||
|
emmyType := emmyLinePieces[0]
|
||||||
|
if emmyType == "@param" {
|
||||||
|
em.Params = append(em.Params, emmyLinePieces[1])
|
||||||
|
}
|
||||||
|
if emmyType == "@vararg" {
|
||||||
|
em.Params = append(em.Params, "...") // add vararg
|
||||||
|
}
|
||||||
|
em.Annotations = append(em.Annotations, d)
|
||||||
|
} else {
|
||||||
|
funcdoc = append(funcdoc, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMember bool
|
||||||
|
if tags["member"] != nil {
|
||||||
|
isMember = true
|
||||||
|
}
|
||||||
|
var parentMod string
|
||||||
|
if inInterface {
|
||||||
|
parentMod = mod
|
||||||
|
}
|
||||||
|
dps := &docPiece{
|
||||||
|
Doc: funcdoc,
|
||||||
|
FuncSig: funcsig,
|
||||||
|
FuncName: funcName,
|
||||||
|
Interfacing: interfaces,
|
||||||
|
GoFuncName: strings.ToLower(fun.Name),
|
||||||
|
IsInterface: inInterface,
|
||||||
|
IsMember: isMember,
|
||||||
|
ParentModule: parentMod,
|
||||||
|
Fields: fields,
|
||||||
|
Properties: properties,
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(dps.GoFuncName, strings.ToLower("loader")) {
|
||||||
|
dps.Doc = parts
|
||||||
|
}
|
||||||
|
em.DocPiece = dps
|
||||||
|
|
||||||
|
emmyDocs[mod] = append(emmyDocs[mod], em)
|
||||||
|
return dps
|
||||||
}
|
}
|
||||||
|
|
||||||
// feel free to clean this up
|
|
||||||
// it works, dont really care about the code
|
|
||||||
func main() {
|
func main() {
|
||||||
fset := token.NewFileSet()
|
fset := token.NewFileSet()
|
||||||
os.Mkdir("docs", 0777)
|
os.Mkdir("docs", 0777)
|
||||||
|
os.Mkdir("docs/api", 0777)
|
||||||
os.Mkdir("emmyLuaDocs", 0777)
|
os.Mkdir("emmyLuaDocs", 0777)
|
||||||
|
|
||||||
|
|
||||||
dirs := []string{"./"}
|
dirs := []string{"./"}
|
||||||
filepath.Walk("golibs/", func (path string, info os.FileInfo, err error) error {
|
filepath.Walk("golibs/", func (path string, info os.FileInfo, err error) error {
|
||||||
|
@ -51,120 +289,266 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix := map[string]string{
|
interfaceModules := make(map[string]*module)
|
||||||
"hilbish": "hl",
|
|
||||||
"fs": "f",
|
|
||||||
"commander": "c",
|
|
||||||
"bait": "b",
|
|
||||||
"terminal": "term",
|
|
||||||
}
|
|
||||||
docs := make(map[string][]DocPiece)
|
|
||||||
emmyDocs := make(map[string][]EmmyPiece)
|
|
||||||
|
|
||||||
for l, f := range pkgs {
|
for l, f := range pkgs {
|
||||||
p := doc.New(f, "./", doc.AllDecls)
|
p := doc.New(f, "./", doc.AllDecls)
|
||||||
|
pieces := []docPiece{}
|
||||||
|
typePieces := []docPiece{}
|
||||||
|
mod := l
|
||||||
|
if mod == "main" {
|
||||||
|
mod = "hilbish"
|
||||||
|
}
|
||||||
|
var hasInterfaces bool
|
||||||
for _, t := range p.Funcs {
|
for _, t := range p.Funcs {
|
||||||
mod := l
|
piece := setupDoc(mod, t)
|
||||||
if strings.HasPrefix(t.Name, "hl") { mod = "hilbish" }
|
if piece == nil {
|
||||||
if !strings.HasPrefix(t.Name, prefix[mod]) || t.Name == "Loader" { continue }
|
continue
|
||||||
parts := strings.Split(strings.TrimSpace(t.Doc), "\n")
|
|
||||||
funcsig := parts[0]
|
|
||||||
doc := parts[1:]
|
|
||||||
funcdoc := []string{}
|
|
||||||
em := EmmyPiece{FuncName: strings.TrimPrefix(t.Name, prefix[mod])}
|
|
||||||
for _, d := range doc {
|
|
||||||
if strings.HasPrefix(d, "---") {
|
|
||||||
emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
|
|
||||||
emmyLinePieces := strings.Split(emmyLine, " ")
|
|
||||||
emmyType := emmyLinePieces[0]
|
|
||||||
if emmyType == "@param" {
|
|
||||||
em.Params = append(em.Params, emmyLinePieces[1])
|
|
||||||
}
|
|
||||||
if emmyType == "@vararg" {
|
|
||||||
em.Params = append(em.Params, "...") // add vararg
|
|
||||||
}
|
|
||||||
em.Docs = append(em.Docs, d)
|
|
||||||
} else {
|
|
||||||
funcdoc = append(funcdoc, d)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dps := DocPiece{
|
pieces = append(pieces, *piece)
|
||||||
Doc: funcdoc,
|
if piece.IsInterface {
|
||||||
FuncSig: funcsig,
|
hasInterfaces = true
|
||||||
FuncName: strings.TrimPrefix(t.Name, prefix[mod]),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
docs[mod] = append(docs[mod], dps)
|
|
||||||
emmyDocs[mod] = append(emmyDocs[mod], em)
|
|
||||||
}
|
}
|
||||||
for _, t := range p.Types {
|
for _, t := range p.Types {
|
||||||
for _, m := range t.Methods {
|
typePiece := setupDocType(mod, t)
|
||||||
if !strings.HasPrefix(m.Name, prefix[l]) || m.Name == "Loader" { continue }
|
if typePiece != nil {
|
||||||
parts := strings.Split(strings.TrimSpace(m.Doc), "\n")
|
typePieces = append(typePieces, *typePiece)
|
||||||
funcsig := parts[0]
|
if typePiece.IsInterface {
|
||||||
doc := parts[1:]
|
hasInterfaces = true
|
||||||
funcdoc := []string{}
|
|
||||||
em := EmmyPiece{FuncName: strings.TrimPrefix(m.Name, prefix[l])}
|
|
||||||
for _, d := range doc {
|
|
||||||
if strings.HasPrefix(d, "---") {
|
|
||||||
emmyLine := strings.TrimSpace(strings.TrimPrefix(d, "---"))
|
|
||||||
emmyLinePieces := strings.Split(emmyLine, " ")
|
|
||||||
emmyType := emmyLinePieces[0]
|
|
||||||
if emmyType == "@param" {
|
|
||||||
em.Params = append(em.Params, emmyLinePieces[1])
|
|
||||||
}
|
|
||||||
if emmyType == "@vararg" {
|
|
||||||
em.Params = append(em.Params, "...") // add vararg
|
|
||||||
}
|
|
||||||
em.Docs = append(em.Docs, d)
|
|
||||||
} else {
|
|
||||||
funcdoc = append(funcdoc, d)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dps := DocPiece{
|
}
|
||||||
Doc: funcdoc,
|
|
||||||
FuncSig: funcsig,
|
for _, m := range t.Methods {
|
||||||
FuncName: strings.TrimPrefix(m.Name, prefix[l]),
|
piece := setupDoc(mod, m)
|
||||||
|
if piece == nil {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
docs[l] = append(docs[l], dps)
|
pieces = append(pieces, *piece)
|
||||||
emmyDocs[l] = append(emmyDocs[l], em)
|
if piece.IsInterface {
|
||||||
|
hasInterfaces = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tags, descParts := getTagsAndDocs(strings.TrimSpace(p.Doc))
|
||||||
|
shortDesc := descParts[0]
|
||||||
|
desc := descParts[1:]
|
||||||
|
filteredPieces := []docPiece{}
|
||||||
|
filteredTypePieces := []docPiece{}
|
||||||
|
for _, piece := range pieces {
|
||||||
|
if !piece.IsInterface {
|
||||||
|
filteredPieces = append(filteredPieces, piece)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
modname := piece.ParentModule + "." + piece.Interfacing
|
||||||
|
if interfaceModules[modname] == nil {
|
||||||
|
interfaceModules[modname] = &module{
|
||||||
|
ParentModule: piece.ParentModule,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasSuffix(piece.GoFuncName, strings.ToLower("loader")) {
|
||||||
|
shortDesc := piece.Doc[0]
|
||||||
|
desc := piece.Doc[1:]
|
||||||
|
interfaceModules[modname].ShortDescription = shortDesc
|
||||||
|
interfaceModules[modname].Description = strings.Join(desc, "\n")
|
||||||
|
interfaceModules[modname].Fields = piece.Fields
|
||||||
|
interfaceModules[modname].Properties = piece.Properties
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceModules[modname].Docs = append(interfaceModules[modname].Docs, piece)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, piece := range typePieces {
|
||||||
|
if !piece.IsInterface {
|
||||||
|
filteredTypePieces = append(filteredTypePieces, piece)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
modname := piece.ParentModule + "." + piece.Interfacing
|
||||||
|
if interfaceModules[modname] == nil {
|
||||||
|
interfaceModules[modname] = &module{
|
||||||
|
ParentModule: piece.ParentModule,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interfaceModules[modname].Types = append(interfaceModules[modname].Types, piece)
|
||||||
|
}
|
||||||
|
|
||||||
|
docs[mod] = module{
|
||||||
|
Types: filteredTypePieces,
|
||||||
|
Docs: filteredPieces,
|
||||||
|
ShortDescription: shortDesc,
|
||||||
|
Description: strings.Join(desc, "\n"),
|
||||||
|
HasInterfaces: hasInterfaces,
|
||||||
|
Properties: docPieceTag("property", tags),
|
||||||
|
Fields: docPieceTag("field", tags),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for key, mod := range interfaceModules {
|
||||||
|
docs[key] = *mod
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
wg.Add(len(docs) * 2)
|
||||||
|
|
||||||
for mod, v := range docs {
|
for mod, v := range docs {
|
||||||
if mod == "main" { continue }
|
docPath := "docs/api/" + mod + ".md"
|
||||||
f, _ := os.Create("docs/" + mod + ".txt")
|
if v.HasInterfaces {
|
||||||
for _, dps := range v {
|
os.Mkdir("docs/api/" + mod, 0777)
|
||||||
f.WriteString(dps.FuncSig + " > ")
|
os.Remove(docPath) // remove old doc path if it exists
|
||||||
for _, doc := range dps.Doc {
|
docPath = "docs/api/" + mod + "/_index.md"
|
||||||
if !strings.HasPrefix(doc, "---") {
|
}
|
||||||
f.WriteString(doc + "\n")
|
if v.ParentModule != "" {
|
||||||
|
docPath = "docs/api/" + v.ParentModule + "/" + mod + ".md"
|
||||||
|
}
|
||||||
|
|
||||||
|
go func(modname, docPath string, modu module) {
|
||||||
|
defer wg.Done()
|
||||||
|
modOrIface := "Module"
|
||||||
|
if modu.ParentModule != "" {
|
||||||
|
modOrIface = "Interface"
|
||||||
|
}
|
||||||
|
|
||||||
|
f, _ := os.Create(docPath)
|
||||||
|
f.WriteString(fmt.Sprintf(header, modOrIface, modname, modu.ShortDescription))
|
||||||
|
typeTag, _ := regexp.Compile(`@\w+`)
|
||||||
|
modDescription := typeTag.ReplaceAllStringFunc(strings.Replace(modu.Description, "<", `\<`, -1), func(typ string) string {
|
||||||
|
typName := typ[1:]
|
||||||
|
typLookup := typeTable[strings.ToLower(typName)]
|
||||||
|
ifaces := typLookup[0] + "." + typLookup[1] + "/"
|
||||||
|
if typLookup[1] == "" {
|
||||||
|
ifaces = ""
|
||||||
|
}
|
||||||
|
linkedTyp := fmt.Sprintf("/Hilbish/docs/api/%s/%s#%s", typLookup[0], ifaces, strings.ToLower(typName))
|
||||||
|
return fmt.Sprintf(`<a href="%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
|
||||||
|
})
|
||||||
|
f.WriteString(fmt.Sprintf("## Introduction\n%s\n\n", modDescription))
|
||||||
|
if len(modu.Fields) != 0 {
|
||||||
|
f.WriteString("## Interface fields\n")
|
||||||
|
for _, dps := range modu.Fields {
|
||||||
|
f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
|
||||||
|
f.WriteString(strings.Join(dps.Doc, " "))
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
if len(modu.Properties) != 0 {
|
||||||
|
f.WriteString("## Object properties\n")
|
||||||
|
for _, dps := range modu.Properties {
|
||||||
|
f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
|
||||||
|
f.WriteString(strings.Join(dps.Doc, " "))
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(modu.Docs) != 0 {
|
||||||
|
f.WriteString("## Functions\n")
|
||||||
|
for _, dps := range modu.Docs {
|
||||||
|
if dps.IsMember {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string {
|
||||||
|
typName := typ[1:]
|
||||||
|
typLookup := typeTable[strings.ToLower(typName)]
|
||||||
|
ifaces := typLookup[0] + "." + typLookup[1] + "/"
|
||||||
|
if typLookup[1] == "" {
|
||||||
|
ifaces = ""
|
||||||
|
}
|
||||||
|
linkedTyp := fmt.Sprintf("/Hilbish/docs/api/%s/%s#%s", typLookup[0], ifaces, strings.ToLower(typName))
|
||||||
|
return fmt.Sprintf(`<a href="%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
|
||||||
|
})
|
||||||
|
f.WriteString(fmt.Sprintf("### %s\n", htmlSig))
|
||||||
|
for _, doc := range dps.Doc {
|
||||||
|
if !strings.HasPrefix(doc, "---") {
|
||||||
|
f.WriteString(doc + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.WriteString("\n")
|
|
||||||
}
|
if len(modu.Types) != 0 {
|
||||||
}
|
f.WriteString("## Types\n")
|
||||||
|
for _, dps := range modu.Types {
|
||||||
for mod, v := range emmyDocs {
|
f.WriteString(fmt.Sprintf("## %s\n", dps.FuncName))
|
||||||
if mod == "main" { continue }
|
for _, doc := range dps.Doc {
|
||||||
f, _ := os.Create("emmyLuaDocs/" + mod + ".lua")
|
if !strings.HasPrefix(doc, "---") {
|
||||||
f.WriteString("--- @meta\n\nlocal " + mod + " = {}\n\n")
|
f.WriteString(doc + "\n")
|
||||||
for _, em := range v {
|
}
|
||||||
var funcdocs []string
|
}
|
||||||
for _, dps := range docs[mod] {
|
if len(dps.Properties) != 0 {
|
||||||
if dps.FuncName == em.FuncName {
|
f.WriteString("### Properties\n")
|
||||||
funcdocs = dps.Doc
|
for _, dps := range dps.Properties {
|
||||||
|
f.WriteString(fmt.Sprintf("- `%s`: ", dps.FuncName))
|
||||||
|
f.WriteString(strings.Join(dps.Doc, " "))
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
|
f.WriteString("### Methods\n")
|
||||||
|
for _, dps := range modu.Docs {
|
||||||
|
if !dps.IsMember {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
htmlSig := typeTag.ReplaceAllStringFunc(strings.Replace(dps.FuncSig, "<", `\<`, -1), func(typ string) string {
|
||||||
|
typName := regexp.MustCompile(`\w+`).FindString(typ[1:])
|
||||||
|
typLookup := typeTable[strings.ToLower(typName)]
|
||||||
|
fmt.Printf("%+q, \n", typLookup)
|
||||||
|
linkedTyp := fmt.Sprintf("/Hilbish/docs/api/%s/%s/#%s", typLookup[0], typLookup[0] + "." + typLookup[1], strings.ToLower(typName))
|
||||||
|
return fmt.Sprintf(`<a href="#%s" style="text-decoration: none;">%s</a>`, linkedTyp, typName)
|
||||||
|
})
|
||||||
|
f.WriteString(fmt.Sprintf("#### %s\n", htmlSig))
|
||||||
|
for _, doc := range dps.Doc {
|
||||||
|
if !strings.HasPrefix(doc, "---") {
|
||||||
|
f.WriteString(doc + "\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f.WriteString("\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
f.WriteString("--- " + strings.Join(funcdocs, "\n--- ") + "\n")
|
}(mod, docPath, v)
|
||||||
if len(em.Docs) != 0 {
|
|
||||||
f.WriteString(strings.Join(em.Docs, "\n") + "\n")
|
go func(md, modname string, modu module) {
|
||||||
|
defer wg.Done()
|
||||||
|
|
||||||
|
if modu.ParentModule != "" {
|
||||||
|
return
|
||||||
}
|
}
|
||||||
f.WriteString("function " + mod + "." + em.FuncName + "(" + strings.Join(em.Params, ", ") + ") end\n\n")
|
|
||||||
}
|
ff, _ := os.Create("emmyLuaDocs/" + modname + ".lua")
|
||||||
f.WriteString("return " + mod + "\n")
|
ff.WriteString("--- @meta\n\nlocal " + modname + " = {}\n\n")
|
||||||
|
for _, em := range emmyDocs[modname] {
|
||||||
|
if strings.HasSuffix(em.DocPiece.GoFuncName, strings.ToLower("loader")) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
dps := em.DocPiece
|
||||||
|
funcdocs := dps.Doc
|
||||||
|
ff.WriteString("--- " + strings.Join(funcdocs, "\n--- ") + "\n")
|
||||||
|
if len(em.Annotations) != 0 {
|
||||||
|
ff.WriteString(strings.Join(em.Annotations, "\n") + "\n")
|
||||||
|
}
|
||||||
|
accessor := "."
|
||||||
|
if dps.IsMember {
|
||||||
|
accessor = ":"
|
||||||
|
}
|
||||||
|
signature := strings.Split(dps.FuncSig, " ->")[0]
|
||||||
|
var intrface string
|
||||||
|
if dps.IsInterface {
|
||||||
|
intrface = "." + dps.Interfacing
|
||||||
|
}
|
||||||
|
ff.WriteString("function " + modname + intrface + accessor + signature + " end\n\n")
|
||||||
|
}
|
||||||
|
ff.WriteString("return " + modname + "\n")
|
||||||
|
}(mod, mod, v)
|
||||||
}
|
}
|
||||||
|
wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
122
complete.go
122
complete.go
|
@ -11,15 +11,49 @@ import (
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
func splitQuote(str string) []string {
|
var charEscapeMap = []string{
|
||||||
|
"\"", "\\\"",
|
||||||
|
"'", "\\'",
|
||||||
|
"`", "\\`",
|
||||||
|
" ", "\\ ",
|
||||||
|
"(", "\\(",
|
||||||
|
")", "\\)",
|
||||||
|
"[", "\\[",
|
||||||
|
"]", "\\]",
|
||||||
|
"$", "\\$",
|
||||||
|
"&", "\\&",
|
||||||
|
"*", "\\*",
|
||||||
|
">", "\\>",
|
||||||
|
"<", "\\<",
|
||||||
|
"|", "\\|",
|
||||||
|
}
|
||||||
|
var charEscapeMapInvert = invert(charEscapeMap)
|
||||||
|
var escapeReplaer = strings.NewReplacer(charEscapeMap...)
|
||||||
|
var escapeInvertReplaer = strings.NewReplacer(charEscapeMapInvert...)
|
||||||
|
|
||||||
|
func invert(m []string) []string {
|
||||||
|
newM := make([]string, len(charEscapeMap))
|
||||||
|
for i := range m {
|
||||||
|
if (i + 1) % 2 == 0 {
|
||||||
|
newM[i] = m[i - 1]
|
||||||
|
newM[i - 1] = m[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newM
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitForFile(str string) []string {
|
||||||
split := []string{}
|
split := []string{}
|
||||||
sb := &strings.Builder{}
|
sb := &strings.Builder{}
|
||||||
quoted := false
|
quoted := false
|
||||||
|
|
||||||
for _, r := range str {
|
for i, r := range str {
|
||||||
if r == '"' {
|
if r == '"' {
|
||||||
quoted = !quoted
|
quoted = !quoted
|
||||||
sb.WriteRune(r)
|
sb.WriteRune(r)
|
||||||
|
} else if r == ' ' && str[i - 1] == '\\' {
|
||||||
|
sb.WriteRune(r)
|
||||||
} else if !quoted && r == ' ' {
|
} else if !quoted && r == ' ' {
|
||||||
split = append(split, sb.String())
|
split = append(split, sb.String())
|
||||||
sb.Reset()
|
sb.Reset()
|
||||||
|
@ -39,12 +73,22 @@ func splitQuote(str string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func fileComplete(query, ctx string, fields []string) ([]string, string) {
|
func fileComplete(query, ctx string, fields []string) ([]string, string) {
|
||||||
q := splitQuote(ctx)
|
q := splitForFile(ctx)
|
||||||
|
path := ""
|
||||||
|
if len(q) != 0 {
|
||||||
|
path = q[len(q) - 1]
|
||||||
|
}
|
||||||
|
|
||||||
return matchPath(q[len(q) - 1])
|
return matchPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func binaryComplete(query, ctx string, fields []string) ([]string, string) {
|
func binaryComplete(query, ctx string, fields []string) ([]string, string) {
|
||||||
|
q := splitForFile(ctx)
|
||||||
|
query = ""
|
||||||
|
if len(q) != 0 {
|
||||||
|
query = q[len(q) - 1]
|
||||||
|
}
|
||||||
|
|
||||||
var completions []string
|
var completions []string
|
||||||
|
|
||||||
prefixes := []string{"./", "../", "/", "~/"}
|
prefixes := []string{"./", "../", "/", "~/"}
|
||||||
|
@ -54,7 +98,7 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) {
|
||||||
if len(fileCompletions) != 0 {
|
if len(fileCompletions) != 0 {
|
||||||
for _, f := range fileCompletions {
|
for _, f := range fileCompletions {
|
||||||
fullPath, _ := filepath.Abs(util.ExpandHome(query + strings.TrimPrefix(f, filePref)))
|
fullPath, _ := filepath.Abs(util.ExpandHome(query + strings.TrimPrefix(f, filePref)))
|
||||||
if err := findExecutable(fullPath, false, true); err != nil {
|
if err := findExecutable(escapeInvertReplaer.Replace(fullPath), false, true); err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
completions = append(completions, f)
|
completions = append(completions, f)
|
||||||
|
@ -66,7 +110,6 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) {
|
||||||
|
|
||||||
// filter out executables, but in path
|
// filter out executables, but in path
|
||||||
for _, dir := range filepath.SplitList(os.Getenv("PATH")) {
|
for _, dir := range filepath.SplitList(os.Getenv("PATH")) {
|
||||||
// print dir to stderr for debugging
|
|
||||||
// search for an executable which matches our query string
|
// search for an executable which matches our query string
|
||||||
if matches, err := filepath.Glob(filepath.Join(dir, query + "*")); err == nil {
|
if matches, err := filepath.Glob(filepath.Join(dir, query + "*")); err == nil {
|
||||||
// get basename from matches
|
// get basename from matches
|
||||||
|
@ -102,6 +145,7 @@ func matchPath(query string) ([]string, string) {
|
||||||
var entries []string
|
var entries []string
|
||||||
var baseName string
|
var baseName string
|
||||||
|
|
||||||
|
query = escapeInvertReplaer.Replace(query)
|
||||||
path, _ := filepath.Abs(util.ExpandHome(filepath.Dir(query)))
|
path, _ := filepath.Abs(util.ExpandHome(filepath.Dir(query)))
|
||||||
if string(query) == "" {
|
if string(query) == "" {
|
||||||
// filepath base below would give us "."
|
// filepath base below would give us "."
|
||||||
|
@ -112,7 +156,16 @@ func matchPath(query string) ([]string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
files, _ := os.ReadDir(path)
|
files, _ := os.ReadDir(path)
|
||||||
for _, file := range files {
|
for _, entry := range files {
|
||||||
|
// should we handle errors here?
|
||||||
|
file, err := entry.Info()
|
||||||
|
if err == nil && file.Mode() & os.ModeSymlink != 0 {
|
||||||
|
path, err := filepath.EvalSymlinks(filepath.Join(path, file.Name()))
|
||||||
|
if err == nil {
|
||||||
|
file, err = os.Lstat(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(file.Name(), baseName) {
|
if strings.HasPrefix(file.Name(), baseName) {
|
||||||
entry := file.Name()
|
entry := file.Name()
|
||||||
if file.IsDir() {
|
if file.IsDir() {
|
||||||
|
@ -124,32 +177,20 @@ func matchPath(query string) ([]string, string) {
|
||||||
entries = append(entries, entry)
|
entries = append(entries, entry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !strings.HasPrefix(oldQuery, "\"") {
|
||||||
|
baseName = escapeFilename(baseName)
|
||||||
|
}
|
||||||
|
|
||||||
return entries, baseName
|
return entries, baseName
|
||||||
}
|
}
|
||||||
|
|
||||||
func escapeFilename(fname string) string {
|
func escapeFilename(fname string) string {
|
||||||
args := []string{
|
return escapeReplaer.Replace(fname)
|
||||||
"\"", "\\\"",
|
|
||||||
"'", "\\'",
|
|
||||||
"`", "\\`",
|
|
||||||
" ", "\\ ",
|
|
||||||
"(", "\\(",
|
|
||||||
")", "\\)",
|
|
||||||
"[", "\\[",
|
|
||||||
"]", "\\]",
|
|
||||||
"$", "\\$",
|
|
||||||
"&", "\\&",
|
|
||||||
"*", "\\*",
|
|
||||||
">", "\\>",
|
|
||||||
"<", "\\<",
|
|
||||||
"|", "\\|",
|
|
||||||
}
|
|
||||||
|
|
||||||
r := strings.NewReplacer(args...)
|
|
||||||
return r.Replace(fname)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface completions
|
||||||
|
// tab completions
|
||||||
|
// The completions interface deals with tab completions.
|
||||||
func completionLoader(rtm *rt.Runtime) *rt.Table {
|
func completionLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
exports := map[string]util.LuaExport{
|
exports := map[string]util.LuaExport{
|
||||||
"files": {luaFileComplete, 3, false},
|
"files": {luaFileComplete, 3, false},
|
||||||
|
@ -164,11 +205,26 @@ func completionLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
// left as a shim, might doc in the same way as hilbish functions
|
// #interface completions
|
||||||
|
// handler(line, pos)
|
||||||
|
// The handler function is the callback for tab completion in Hilbish.
|
||||||
|
// You can check the completions doc for more info.
|
||||||
|
// --- @param line string
|
||||||
|
// --- @param pos string
|
||||||
func completionHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func completionHandler(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface completions
|
||||||
|
// call(name, query, ctx, fields) -> completionGroups (table), prefix (string)
|
||||||
|
// Calls a completer function. This is mainly used to call
|
||||||
|
// a command completer, which will have a `name` in the form
|
||||||
|
// of `command.name`, example: `command.git`.
|
||||||
|
// You can check `doc completions` for info on the `completionGroups` return value.
|
||||||
|
// --- @param name string
|
||||||
|
// --- @param query string
|
||||||
|
// --- @param ctx string
|
||||||
|
// --- @param fields table
|
||||||
func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.CheckNArgs(4); err != nil {
|
if err := c.CheckNArgs(4); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -208,6 +264,12 @@ func callLuaCompleter(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, completerReturn), nil
|
return c.PushingNext1(t.Runtime, completerReturn), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface completions
|
||||||
|
// files(query, ctx, fields) -> entries (table), prefix (string)
|
||||||
|
// Returns file completion candidates based on the provided query.
|
||||||
|
// --- @param query string
|
||||||
|
// --- @param ctx string
|
||||||
|
// --- @param fields table
|
||||||
func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
query, ctx, fds, err := getCompleteParams(t, c)
|
query, ctx, fds, err := getCompleteParams(t, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -224,6 +286,12 @@ func luaFileComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
|
return c.PushingNext(t.Runtime, rt.TableValue(luaComps), rt.StringValue(pfx)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface completions
|
||||||
|
// bins(query, ctx, fields) -> entries (table), prefix (string)
|
||||||
|
// Returns binary/executale completion candidates based on the provided query.
|
||||||
|
// --- @param query string
|
||||||
|
// --- @param ctx string
|
||||||
|
// --- @param fields table
|
||||||
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaBinaryComplete(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
query, ctx, fds, err := getCompleteParams(t, c)
|
query, ctx, fds, err := getCompleteParams(t, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
title: API
|
||||||
|
layout: doc
|
||||||
|
weight: -50
|
||||||
|
menu: docs
|
||||||
|
---
|
||||||
|
|
||||||
|
Welcome to the API documentation for Hilbish. This documents Lua functions
|
||||||
|
provided by Hilbish.
|
|
@ -0,0 +1,34 @@
|
||||||
|
---
|
||||||
|
title: Module bait
|
||||||
|
description: the event emitter
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
Bait is the event emitter for Hilbish. Why name it bait? Why not.
|
||||||
|
It throws hooks that you can catch. This is what you will use if
|
||||||
|
you want to listen in on hooks to know when certain things have
|
||||||
|
happened, like when you've changed directory, a command has failed,
|
||||||
|
etc. To find all available hooks thrown by Hilbish, see doc hooks.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### catch(name, cb)
|
||||||
|
Catches a hook with `name`. Runs the `cb` when it is thrown
|
||||||
|
|
||||||
|
### catchOnce(name, cb)
|
||||||
|
Same as catch, but only runs the `cb` once and then removes the hook
|
||||||
|
|
||||||
|
### hooks(name) -> table
|
||||||
|
Returns a table with hooks (callback functions) on the event with `name`.
|
||||||
|
|
||||||
|
### release(name, catcher)
|
||||||
|
Removes the `catcher` for the event with `name`.
|
||||||
|
For this to work, `catcher` has to be the same function used to catch
|
||||||
|
an event, like one saved to a variable.
|
||||||
|
|
||||||
|
### throw(name, ...args)
|
||||||
|
Throws a hook with `name` with the provided `args`
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
---
|
||||||
|
title: Module commander
|
||||||
|
description: library for custom commands
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Commander is a library for writing custom commands in Lua.
|
||||||
|
In order to make it easier to write commands for Hilbish,
|
||||||
|
not require separate scripts and to be able to use in a config,
|
||||||
|
the Commander library exists. This is like a very simple wrapper
|
||||||
|
that works with Hilbish for writing commands. Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local commander = require 'commander'
|
||||||
|
|
||||||
|
commander.register('hello', function(args, sinks)
|
||||||
|
sinks.out:writeln 'Hello world!'
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, a command with the name of `hello` is created
|
||||||
|
that will print `Hello world!` to output. One question you may
|
||||||
|
have is: What is the `sinks` parameter?
|
||||||
|
|
||||||
|
The `sinks` parameter is a table with 3 keys: `in`, `out`,
|
||||||
|
and `err`. The values of these is a <a href="/Hilbish/docs/api/hilbish/#sink" style="text-decoration: none;">Sink</a>.
|
||||||
|
|
||||||
|
- `in` is the standard input. You can read from this sink
|
||||||
|
to get user input. (**This is currently unimplemented.**)
|
||||||
|
- `out` is standard output. This is usually where text meant for
|
||||||
|
output should go.
|
||||||
|
- `err` is standard error. This sink is for writing errors, as the
|
||||||
|
name would suggest.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### deregister(name)
|
||||||
|
Deregisters any command registered with `name`
|
||||||
|
|
||||||
|
### register(name, cb)
|
||||||
|
Register a command with `name` that runs `cb` when ran
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
---
|
||||||
|
title: Module fs
|
||||||
|
description: filesystem interaction and functionality library
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The fs module provides easy and simple access to filesystem functions
|
||||||
|
and other things, and acts an addition to the Lua standard library's
|
||||||
|
I/O and filesystem functions.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### abs(path) -> string
|
||||||
|
Gives an absolute version of `path`.
|
||||||
|
|
||||||
|
### basename(path) -> string
|
||||||
|
Gives the basename of `path`. For the rules,
|
||||||
|
see Go's filepath.Base
|
||||||
|
|
||||||
|
### cd(dir)
|
||||||
|
Changes directory to `dir`
|
||||||
|
|
||||||
|
### dir(path) -> string
|
||||||
|
Returns the directory part of `path`. For the rules, see Go's
|
||||||
|
filepath.Dir
|
||||||
|
|
||||||
|
### glob(pattern) -> matches (table)
|
||||||
|
Glob all files and directories that match the pattern.
|
||||||
|
For the rules, see Go's filepath.Glob
|
||||||
|
|
||||||
|
### join(...) -> string
|
||||||
|
Takes paths and joins them together with the OS's
|
||||||
|
directory separator (forward or backward slash).
|
||||||
|
|
||||||
|
### mkdir(name, recursive)
|
||||||
|
Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
||||||
|
|
||||||
|
### readdir(dir) -> {}
|
||||||
|
Returns a table of files in `dir`.
|
||||||
|
|
||||||
|
### stat(path) -> {}
|
||||||
|
Returns a table of info about the `path`.
|
||||||
|
It contains the following keys:
|
||||||
|
name (string) - Name of the path
|
||||||
|
size (number) - Size of the path
|
||||||
|
mode (string) - Permission mode in an octal format string (with leading 0)
|
||||||
|
isDir (boolean) - If the path is a directory
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
---
|
||||||
|
title: Module hilbish
|
||||||
|
description: the core Hilbish API
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The Hilbish module includes the core API, containing
|
||||||
|
interfaces and functions which directly relate to shell functionality.
|
||||||
|
|
||||||
|
## Interface fields
|
||||||
|
- `ver`: The version of Hilbish
|
||||||
|
- `user`: Username of the user
|
||||||
|
- `host`: Hostname of the machine
|
||||||
|
- `dataDir`: Directory for Hilbish data files, including the docs and default modules
|
||||||
|
- `interactive`: Is Hilbish in an interactive shell?
|
||||||
|
- `login`: Is Hilbish the login shell?
|
||||||
|
- `vimMode`: Current Vim input mode of Hilbish (will be nil if not in Vim input mode)
|
||||||
|
- `exitCode`: xit code of the last executed command
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### alias(cmd, orig)
|
||||||
|
Sets an alias of `cmd` to `orig`
|
||||||
|
|
||||||
|
### appendPath(dir)
|
||||||
|
Appends `dir` to $PATH
|
||||||
|
|
||||||
|
### complete(scope, cb)
|
||||||
|
Registers a completion handler for `scope`.
|
||||||
|
A `scope` is currently only expected to be `command.<cmd>`,
|
||||||
|
replacing <cmd> with the name of the command (for example `command.git`).
|
||||||
|
`cb` must be a function that returns a table of "completion groups."
|
||||||
|
Check `doc completions` for more information.
|
||||||
|
|
||||||
|
### cwd() -> string
|
||||||
|
Returns the current directory of the shell
|
||||||
|
|
||||||
|
### exec(cmd)
|
||||||
|
Replaces running hilbish with `cmd`
|
||||||
|
|
||||||
|
### goro(fn)
|
||||||
|
Puts `fn` in a goroutine
|
||||||
|
|
||||||
|
### highlighter(line)
|
||||||
|
Line highlighter handler. This is mainly for syntax highlighting, but in
|
||||||
|
reality could set the input of the prompt to *display* anything. The
|
||||||
|
callback is passed the current line and is expected to return a line that
|
||||||
|
will be used as the input display.
|
||||||
|
|
||||||
|
### hinter(line, pos)
|
||||||
|
The command line hint handler. It gets called on every key insert to
|
||||||
|
determine what text to use as an inline hint. It is passed the current
|
||||||
|
line and cursor position. It is expected to return a string which is used
|
||||||
|
as the text for the hint. This is by default a shim. To set hints,
|
||||||
|
override this function with your custom handler.
|
||||||
|
|
||||||
|
### inputMode(mode)
|
||||||
|
Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
|
||||||
|
|
||||||
|
### interval(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
|
Runs the `cb` function every `time` milliseconds.
|
||||||
|
This creates a timer that starts immediately.
|
||||||
|
|
||||||
|
### multiprompt(str)
|
||||||
|
Changes the continued line prompt to `str`
|
||||||
|
|
||||||
|
### prependPath(dir)
|
||||||
|
Prepends `dir` to $PATH
|
||||||
|
|
||||||
|
### prompt(str, typ)
|
||||||
|
Changes the shell prompt to `str`
|
||||||
|
There are a few verbs that can be used in the prompt text.
|
||||||
|
These will be formatted and replaced with the appropriate values.
|
||||||
|
`%d` - Current working directory
|
||||||
|
`%u` - Name of current user
|
||||||
|
`%h` - Hostname of device
|
||||||
|
|
||||||
|
### read(prompt) -> input (string)
|
||||||
|
Read input from the user, using Hilbish's line editor/input reader.
|
||||||
|
This is a separate instance from the one Hilbish actually uses.
|
||||||
|
Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
||||||
|
|
||||||
|
### run(cmd, returnOut) -> exitCode (number), stdout (string), stderr (string)
|
||||||
|
Runs `cmd` in Hilbish's sh interpreter.
|
||||||
|
If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
||||||
|
3rd values instead of being outputted to the terminal.
|
||||||
|
|
||||||
|
### runnerMode(mode)
|
||||||
|
Sets the execution/runner mode for interactive Hilbish. This determines whether
|
||||||
|
Hilbish wll try to run input as Lua and/or sh or only do one of either.
|
||||||
|
Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
|
||||||
|
sh, and lua. It also accepts a function, to which if it is passed one
|
||||||
|
will call it to execute user input instead.
|
||||||
|
|
||||||
|
### timeout(cb, time) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
|
Runs the `cb` function after `time` in milliseconds.
|
||||||
|
This creates a timer that starts immediately.
|
||||||
|
|
||||||
|
### which(name) -> string
|
||||||
|
Checks if `name` is a valid command.
|
||||||
|
Will return the path of the binary, or a basename if it's a commander.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
## Sink
|
||||||
|
A sink is a structure that has input and/or output to/from
|
||||||
|
a desination.
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
#### write(str)
|
||||||
|
Writes data to a sink.
|
||||||
|
|
||||||
|
#### writeln(str)
|
||||||
|
Writes data to a sink with a newline at the end.
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.aliases
|
||||||
|
description: command aliasing
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The alias interface deals with all command aliases in Hilbish.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### add(alias, cmd)
|
||||||
|
This is an alias (ha) for the `hilbish.alias` function.
|
||||||
|
|
||||||
|
### delete(name)
|
||||||
|
Removes an alias.
|
||||||
|
|
||||||
|
### list() -> table\<string, string>
|
||||||
|
Get a table of all aliases, with string keys as the alias and the value as the command.
|
||||||
|
|
||||||
|
### resolve(alias) -> command (string)
|
||||||
|
Tries to resolve an alias to its command.
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.completions
|
||||||
|
description: tab completions
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The completions interface deals with tab completions.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### call(name, query, ctx, fields) -> completionGroups (table), prefix (string)
|
||||||
|
Calls a completer function. This is mainly used to call
|
||||||
|
a command completer, which will have a `name` in the form
|
||||||
|
of `command.name`, example: `command.git`.
|
||||||
|
You can check `doc completions` for info on the `completionGroups` return value.
|
||||||
|
|
||||||
|
### handler(line, pos)
|
||||||
|
The handler function is the callback for tab completion in Hilbish.
|
||||||
|
You can check the completions doc for more info.
|
||||||
|
|
||||||
|
### bins(query, ctx, fields) -> entries (table), prefix (string)
|
||||||
|
Returns binary/executale completion candidates based on the provided query.
|
||||||
|
|
||||||
|
### files(query, ctx, fields) -> entries (table), prefix (string)
|
||||||
|
Returns file completion candidates based on the provided query.
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.editor
|
||||||
|
description: interactions for Hilbish's line reader
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The hilbish.editor interface provides functions to
|
||||||
|
directly interact with the line editor in use.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### getLine() -> string
|
||||||
|
Returns the current input line.
|
||||||
|
|
||||||
|
### getVimRegister(register) -> string
|
||||||
|
Returns the text that is at the register.
|
||||||
|
|
||||||
|
### insert(text)
|
||||||
|
Inserts text into the line.
|
||||||
|
|
||||||
|
### setVimRegister(register, text)
|
||||||
|
Sets the vim register at `register` to hold the passed text.
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.history
|
||||||
|
description: command history
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The history interface deals with command history.
|
||||||
|
This includes the ability to override functions to change the main
|
||||||
|
method of saving history.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### add(cmd)
|
||||||
|
Adds a command to the history.
|
||||||
|
|
||||||
|
### all() -> table
|
||||||
|
Retrieves all history.
|
||||||
|
|
||||||
|
### clear()
|
||||||
|
Deletes all commands from the history.
|
||||||
|
|
||||||
|
### get(idx)
|
||||||
|
Retrieves a command from the history based on the `idx`.
|
||||||
|
|
||||||
|
### size() -> number
|
||||||
|
Returns the amount of commands in the history.
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.jobs
|
||||||
|
description: background job management
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
Manage interactive jobs in Hilbish via Lua.
|
||||||
|
|
||||||
|
Jobs are the name of background tasks/commands. A job can be started via
|
||||||
|
interactive usage or with the functions defined below for use in external runners.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### add(cmdstr, args, execPath)
|
||||||
|
Adds a new job to the job table. Note that this does not immediately run it.
|
||||||
|
|
||||||
|
### all() -> table\<<a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>>
|
||||||
|
Returns a table of all job objects.
|
||||||
|
|
||||||
|
### disown(id)
|
||||||
|
Disowns a job. This deletes it from the job table.
|
||||||
|
|
||||||
|
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
|
||||||
|
Get a job object via its ID.
|
||||||
|
|
||||||
|
### last() -> <a href="/Hilbish/docs/api/hilbish/hilbish.jobs/#job" style="text-decoration: none;">Job</a>
|
||||||
|
Returns the last added job from the table.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
## Job
|
||||||
|
The Job type describes a Hilbish job.
|
||||||
|
### Properties
|
||||||
|
- `cmd`: The user entered command string for the job.
|
||||||
|
- `running`: Whether the job is running or not.
|
||||||
|
- `id`: The ID of the job in the job table
|
||||||
|
- `pid`: The Process ID
|
||||||
|
- `exitCode`: The last exit code of the job.
|
||||||
|
- `stdout`: The standard output of the job. This just means the normal logs of the process.
|
||||||
|
- `stderr`: The standard error stream of the process. This (usually) includes error messages of the job.
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
#### background()
|
||||||
|
Puts a job in the background. This acts the same as initially running a job.
|
||||||
|
|
||||||
|
#### foreground()
|
||||||
|
Puts a job in the foreground. This will cause it to run like it was
|
||||||
|
executed normally and wait for it to complete.
|
||||||
|
|
||||||
|
#### start()
|
||||||
|
Starts running the job.
|
||||||
|
|
||||||
|
#### stop()
|
||||||
|
Stops the job from running.
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.os
|
||||||
|
description: OS Info
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The `os` interface provides simple text information properties about
|
||||||
|
the current OS on the systen. This mainly includes the name and
|
||||||
|
version.
|
||||||
|
|
||||||
|
## Interface fields
|
||||||
|
- `family`: Family name of the current OS
|
||||||
|
- `name`: Pretty name of the current OS
|
||||||
|
- `version`: Version of the current OS
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.runner
|
||||||
|
description: interactive command runner customization
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The runner interface contains functions that allow the user to change
|
||||||
|
how Hilbish interprets interactive input.
|
||||||
|
Users can add and change the default runner for interactive input to any
|
||||||
|
language or script of their choosing. A good example is using it to
|
||||||
|
write command in Fennel.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### setMode(cb)
|
||||||
|
This is the same as the `hilbish.runnerMode` function. It takes a callback,
|
||||||
|
which will be used to execute all interactive input.
|
||||||
|
In normal cases, neither callbacks should be overrided by the user,
|
||||||
|
as the higher level functions listed below this will handle it.
|
||||||
|
|
||||||
|
### lua(cmd)
|
||||||
|
Evaluates `cmd` as Lua input. This is the same as using `dofile`
|
||||||
|
or `load`, but is appropriated for the runner interface.
|
||||||
|
|
||||||
|
### sh(cmd)
|
||||||
|
Runs a command in Hilbish's shell script interpreter.
|
||||||
|
This is the equivalent of using `source`.
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.timers
|
||||||
|
description: timeout and interval API
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
If you ever want to run a piece of code on a timed interval, or want to wait
|
||||||
|
a few seconds, you don't have to rely on timing tricks, as Hilbish has a
|
||||||
|
timer API to set intervals and timeouts.
|
||||||
|
|
||||||
|
These are the simple functions `hilbish.interval` and `hilbish.timeout` (doc
|
||||||
|
accessible with `doc hilbish`). But if you want slightly more control over
|
||||||
|
them, there is the `hilbish.timers` interface. It allows you to get
|
||||||
|
a timer via ID and control them.
|
||||||
|
|
||||||
|
All functions documented with the `Timer` type refer to a Timer object.
|
||||||
|
|
||||||
|
An example of usage:
|
||||||
|
```
|
||||||
|
local t = hilbish.timers.create(hilbish.timers.TIMEOUT, 5000, function()
|
||||||
|
print 'hello!'
|
||||||
|
end)
|
||||||
|
|
||||||
|
t:start()
|
||||||
|
print(t.running) // true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Interface fields
|
||||||
|
- `INTERVAL`: Constant for an interval timer type
|
||||||
|
- `TIMEOUT`: Constant for a timeout timer type
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### create(type, time, callback) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
|
Creates a timer that runs based on the specified `time` in milliseconds.
|
||||||
|
The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
||||||
|
|
||||||
|
### get(id) -> <a href="/Hilbish/docs/api/hilbish/hilbish.timers/#timer" style="text-decoration: none;">Timer</a>
|
||||||
|
Retrieves a timer via its ID.
|
||||||
|
|
||||||
|
## Types
|
||||||
|
## Timer
|
||||||
|
The Job type describes a Hilbish timer.
|
||||||
|
### Properties
|
||||||
|
- `type`: What type of timer it is
|
||||||
|
- `running`: If the timer is running
|
||||||
|
- `duration`: The duration in milliseconds that the timer will run
|
||||||
|
|
||||||
|
### Methods
|
||||||
|
#### start()
|
||||||
|
Starts a timer.
|
||||||
|
|
||||||
|
#### stop()
|
||||||
|
Stops a timer.
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
title: Interface hilbish.userDir
|
||||||
|
description: user-related directories
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
This interface just contains properties to know about certain user directories.
|
||||||
|
It is equivalent to XDG on Linux and gets the user's preferred directories
|
||||||
|
for configs and data.
|
||||||
|
|
||||||
|
## Interface fields
|
||||||
|
- `config`: The user's config directory
|
||||||
|
- `data`: The user's directory for program data
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
---
|
||||||
|
title: Module terminal
|
||||||
|
description: low level terminal library
|
||||||
|
layout: doc
|
||||||
|
menu:
|
||||||
|
docs:
|
||||||
|
parent: "API"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
The terminal library is a simple and lower level library for certain terminal interactions.
|
||||||
|
|
||||||
|
## Functions
|
||||||
|
### restoreState()
|
||||||
|
Restores the last saved state of the terminal
|
||||||
|
|
||||||
|
### saveState()
|
||||||
|
Saves the current state of the terminal
|
||||||
|
|
||||||
|
### setRaw()
|
||||||
|
Puts the terminal in raw mode
|
||||||
|
|
||||||
|
### size()
|
||||||
|
Gets the dimensions of the terminal. Returns a table with `width` and `height`
|
||||||
|
Note: this is not the size in relation to the dimensions of the display
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
catch(name, cb) > Catches a hook with `name`. Runs the `cb` when it is thrown
|
|
||||||
|
|
||||||
catchOnce(name, cb) > Same as catch, but only runs the `cb` once and then removes the hook
|
|
||||||
|
|
||||||
release(name, catcher) > Removes the `catcher` for the event with `name`
|
|
||||||
For this to work, `catcher` has to be the same function used to catch
|
|
||||||
an event, like one saved to a variable.
|
|
||||||
|
|
||||||
throw(name, ...args) > Throws a hook with `name` with the provided `args`
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
deregister(name) > Deregisters any command registered with `name`
|
|
||||||
|
|
||||||
register(name, cb) > Register a command with `name` that runs `cb` when ran
|
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
Hilbish has a pretty good completion system. It has a nice looking
|
||||||
|
menu, with 2 types of menus: grid (like file completions) or
|
||||||
|
list.
|
||||||
|
|
||||||
|
Like most parts of Hilbish, it's made to be extensible and
|
||||||
|
customizable. The default handler for completions in general can
|
||||||
|
be overwritten to provide more advanced completions if needed.
|
||||||
|
|
||||||
|
# Completion Handler
|
||||||
|
By default, it provides 3 things: for the first argument,
|
||||||
|
binaries (with a plain name requested to complete, those in
|
||||||
|
$PATH), files, or command completions. With the default
|
||||||
|
completion handler, it will try to run a handler for the
|
||||||
|
command or fallback to file completions.
|
||||||
|
|
||||||
|
To overwrite it, just assign a function to
|
||||||
|
`hilbish.completion.handler` like so:
|
||||||
|
function hilbish.completion.handler(line, pos)
|
||||||
|
-- do things
|
||||||
|
end
|
||||||
|
|
||||||
|
It is passed 2 arguments, the entire line, and the current
|
||||||
|
cursor position. The functions in the completion interface
|
||||||
|
take 3 arguments: query, ctx, and fields.
|
||||||
|
|
||||||
|
- The `query`, which what the user is currently trying to complete
|
||||||
|
- `ctx`, being just the entire line
|
||||||
|
- `fields` being a table of arguments. It's just `ctx` split up,
|
||||||
|
delimited by spaces.
|
||||||
|
|
||||||
|
It's expected to return 2 things: a table of completion groups, and
|
||||||
|
a prefix. A completion group is defined as a table with 2 keys:
|
||||||
|
`items` and `type`.
|
||||||
|
|
||||||
|
- The `items` field is just a table of items to use for completions.
|
||||||
|
- The `type` is for the completion menu type, being either `grid` or
|
||||||
|
`list`.
|
||||||
|
|
||||||
|
The prefix is what all the completions start with. It should be empty
|
||||||
|
if the user doesn't have a query. If the beginning of the completion
|
||||||
|
item does not match the prefix, it will be replaced and fixed
|
||||||
|
properly in the line. It is case sensitive.
|
||||||
|
|
||||||
|
If you want to overwrite the functionality of the general completion
|
||||||
|
handler, or make your command completion have files as well
|
||||||
|
(and filter them), then there is the `files` function, which is
|
||||||
|
mentioned below.
|
||||||
|
|
||||||
|
# Completion Interface
|
||||||
|
## Functions
|
||||||
|
- `files(query, ctx, fields)` -> table, prefix: get file completions,
|
||||||
|
based on the user's query.
|
||||||
|
- `bins(query, ctx, fields)` -> table, prefix: get binary/executable
|
||||||
|
completions, based on user query.
|
||||||
|
- `call(scope, query, ctx, fields)` -> table, prefix: call a completion
|
||||||
|
handler with `scope`, usually being in the form of `command.<name>`
|
|
@ -1,44 +0,0 @@
|
||||||
Hilbish has a pretty good completion system. It has a nice looking menu,
|
|
||||||
with 2 types of menus: grid (like file completions) or list.
|
|
||||||
|
|
||||||
Like most parts of Hilbish, it's made to be extensible and customizable.
|
|
||||||
The default handler for completions in general can be overwritten to provide
|
|
||||||
more advanced completions if needed.
|
|
||||||
|
|
||||||
# Completion Handler
|
|
||||||
By default, it provides 3 things: for the first argument, binaries (with a
|
|
||||||
plain name requested to complete, those in $PATH), files, or command
|
|
||||||
completions. With the default completion handler, it will try to run a
|
|
||||||
handler for the command or fallback to file completions.
|
|
||||||
|
|
||||||
To overwrite it, just assign a function to `hilbish.completion.handler`
|
|
||||||
like so:
|
|
||||||
function hilbish.completion.handler(line, pos)
|
|
||||||
-- do things
|
|
||||||
end
|
|
||||||
It is passed 2 arguments, the entire line, and the current cursor position.
|
|
||||||
The functions in the completion interface take 3 arguments: query, ctx,
|
|
||||||
and fields. The `query`, which what the user is currently trying to complete,
|
|
||||||
`ctx`, being just the entire line, and `fields` being a table of arguments.
|
|
||||||
It's just `ctx` split up, delimited by spaces.
|
|
||||||
It's expected to return 2 things: a table of completion groups, and a prefix.
|
|
||||||
A completion group is defined as a table with 2 keys: `items` and `type`.
|
|
||||||
The `items` field is just a table of items to use for completions.
|
|
||||||
The `type` is for the completion menu type, being either `grid` or `list`.
|
|
||||||
The prefix is what all the completions start with. It should be empty
|
|
||||||
if the user doesn't have a query. If the beginning of the completion
|
|
||||||
item does not match the prefix, it will be replaced and fixed properly
|
|
||||||
in the line. It is case sensitive.
|
|
||||||
|
|
||||||
If you want to overwrite the functionality of the general completion handler,
|
|
||||||
or make your command completion have files as well (and filter them),
|
|
||||||
then there is the `files` function, which is mentioned below.
|
|
||||||
|
|
||||||
# Completion Interface
|
|
||||||
## Functions
|
|
||||||
- `files(query, ctx, fields)` -> table, prefix: get file completions, based
|
|
||||||
on the user's query.
|
|
||||||
- `bins(query, ctx, fields)` -> table, prefix: get binary/executable
|
|
||||||
completions, based on user query.
|
|
||||||
- `call(scope, query, ctx, fields)` -> table, prefix: call a completion handler
|
|
||||||
with `scope`, usually being in the form of `command.<name>`
|
|
22
docs/fs.txt
22
docs/fs.txt
|
@ -1,22 +0,0 @@
|
||||||
abs(path) > Gives an absolute version of `path`.
|
|
||||||
|
|
||||||
basename(path) > Gives the basename of `path`. For the rules,
|
|
||||||
see Go's filepath.Base
|
|
||||||
|
|
||||||
cd(dir) > Changes directory to `dir`
|
|
||||||
|
|
||||||
dir(path) > Returns the directory part of `path`. For the rules, see Go's
|
|
||||||
filepath.Dir
|
|
||||||
|
|
||||||
glob(pattern) > Glob all files and directories that match the pattern.
|
|
||||||
For the rules, see Go's filepath.Glob
|
|
||||||
|
|
||||||
join(paths...) > Takes paths and joins them together with the OS's
|
|
||||||
directory separator (forward or backward slash).
|
|
||||||
|
|
||||||
mkdir(name, recursive) > Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
|
||||||
|
|
||||||
readdir(dir) > Returns a table of files in `dir`
|
|
||||||
|
|
||||||
stat(path) > Returns info about `path`
|
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
alias(cmd, orig) > Sets an alias of `cmd` to `orig`
|
|
||||||
|
|
||||||
appendPath(dir) > Appends `dir` to $PATH
|
|
||||||
|
|
||||||
complete(scope, cb) > Registers a completion handler for `scope`.
|
|
||||||
A `scope` is currently only expected to be `command.<cmd>`,
|
|
||||||
replacing <cmd> with the name of the command (for example `command.git`).
|
|
||||||
`cb` must be a function that returns a table of "completion groups."
|
|
||||||
Check `doc completions` for more information.
|
|
||||||
|
|
||||||
cwd() > Returns the current directory of the shell
|
|
||||||
|
|
||||||
exec(cmd) > Replaces running hilbish with `cmd`
|
|
||||||
|
|
||||||
goro(fn) > Puts `fn` in a goroutine
|
|
||||||
|
|
||||||
highlighter(line) > Line highlighter handler. This is mainly for syntax highlighting, but in
|
|
||||||
reality could set the input of the prompt to *display* anything. The
|
|
||||||
callback is passed the current line and is expected to return a line that
|
|
||||||
will be used as the input display.
|
|
||||||
|
|
||||||
hinter(line, pos) > The command line hint handler. It gets called on every key insert to
|
|
||||||
determine what text to use as an inline hint. It is passed the current
|
|
||||||
line and cursor position. It is expected to return a string which is used
|
|
||||||
as the text for the hint. This is by default a shim. To set hints,
|
|
||||||
override this function with your custom handler.
|
|
||||||
|
|
||||||
inputMode(mode) > Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
|
|
||||||
|
|
||||||
interval(cb, time) > Runs the `cb` function every `time` milliseconds.
|
|
||||||
Returns a `timer` object (see `doc timers`).
|
|
||||||
|
|
||||||
multiprompt(str) > Changes the continued line prompt to `str`
|
|
||||||
|
|
||||||
prependPath(dir) > Prepends `dir` to $PATH
|
|
||||||
|
|
||||||
prompt(str, typ?) > Changes the shell prompt to `str`
|
|
||||||
There are a few verbs that can be used in the prompt text.
|
|
||||||
These will be formatted and replaced with the appropriate values.
|
|
||||||
`%d` - Current working directory
|
|
||||||
`%u` - Name of current user
|
|
||||||
`%h` - Hostname of device
|
|
||||||
|
|
||||||
read(prompt) -> input? > Read input from the user, using Hilbish's line editor/input reader.
|
|
||||||
This is a separate instance from the one Hilbish actually uses.
|
|
||||||
Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
|
||||||
|
|
||||||
run(cmd, returnOut) -> exitCode, stdout, stderr > Runs `cmd` in Hilbish's sh interpreter.
|
|
||||||
If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
|
||||||
3rd values instead of being outputted to the terminal.
|
|
||||||
|
|
||||||
runnerMode(mode) > Sets the execution/runner mode for interactive Hilbish. This determines whether
|
|
||||||
Hilbish wll try to run input as Lua and/or sh or only do one of either.
|
|
||||||
Accepted values for mode are hybrid (the default), hybridRev (sh first then Lua),
|
|
||||||
sh, and lua. It also accepts a function, to which if it is passed one
|
|
||||||
will call it to execute user input instead.
|
|
||||||
|
|
||||||
timeout(cb, time) > Runs the `cb` function after `time` in milliseconds
|
|
||||||
Returns a `timer` object (see `doc timers`).
|
|
||||||
|
|
||||||
which(name) > Checks if `name` is a valid command
|
|
||||||
|
|
|
@ -6,3 +6,8 @@ Here is the format for a doc for a hook:
|
||||||
|
|
||||||
`<args>` just means the arguments of the hook. If a hook doc has the format
|
`<args>` just means the arguments of the hook. If a hook doc has the format
|
||||||
of `arg...`, it means the hook can take/recieve any number of `arg`.
|
of `arg...`, it means the hook can take/recieve any number of `arg`.
|
||||||
|
|
||||||
|
+ error -> eventName, handler, err > Emitted when there is an error in
|
||||||
|
an event handler. The `eventName` is the name of the event the handler
|
||||||
|
is for, the `handler` is the callback function, and `err` is the error
|
||||||
|
message.
|
|
@ -3,5 +3,5 @@
|
||||||
|
|
||||||
+ `command.not-found` -> cmdStr > Thrown when a command is not found.
|
+ `command.not-found` -> cmdStr > Thrown when a command is not found.
|
||||||
|
|
||||||
+ `command.no-perm` -> cmdStr > Thrown when Hilbish attempts to execute a file but
|
+ `command.not-executable` -> cmdStr > Thrown when Hilbish attempts to run a file
|
||||||
has no permission.
|
that is not executable.
|
|
@ -5,3 +5,5 @@
|
||||||
|
|
||||||
+ `hilbish.vimAction` -> actionName, args > Sent when the user does a "vim action," being something
|
+ `hilbish.vimAction` -> actionName, args > Sent when the user does a "vim action," being something
|
||||||
like yanking or pasting text. See `doc vim-mode actions` for more info.
|
like yanking or pasting text. See `doc vim-mode actions` for more info.
|
||||||
|
|
||||||
|
+ `hilbish.cancel` > Sent when the user cancels their input with Ctrl-C.
|
|
@ -38,8 +38,22 @@ The exit code has to be a number, it will be 0 otherwise and the error can be
|
||||||
These are the "low level" functions for the `hilbish.runner` interface.
|
These are the "low level" functions for the `hilbish.runner` interface.
|
||||||
|
|
||||||
+ setMode(mode) > The same as `hilbish.runnerMode`
|
+ setMode(mode) > The same as `hilbish.runnerMode`
|
||||||
+ sh(input) -> input, code, err > Runs `input` in Hilbish's sh interpreter
|
+ sh(input) -> table > Runs `input` in Hilbish's sh interpreter
|
||||||
+ lua(input) -> input, code, err > Evals `input` as Lua code
|
+ lua(input) -> table > Evals `input` as Lua code
|
||||||
|
|
||||||
|
The table value that runners return can have at least 4 values:
|
||||||
|
+ input (string): The full input text.
|
||||||
|
+ exitCode (number): Exit code (usually from a command)
|
||||||
|
+ continue (boolean): Whether to prompt the user for more input
|
||||||
|
(in the case of incomplete syntax)
|
||||||
|
+ 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.
|
||||||
|
|
||||||
The others here are defined in Lua and have EmmyLua documentation.
|
The others here are defined in Lua and have EmmyLua documentation.
|
||||||
These functions should be preferred over the previous ones.
|
These functions should be preferred over the previous ones.
|
|
@ -1,9 +0,0 @@
|
||||||
restoreState() > Restores the last saved state of the terminal
|
|
||||||
|
|
||||||
saveState() > Saves the current state of the terminal
|
|
||||||
|
|
||||||
setRaw() > Puts the terminal in raw mode
|
|
||||||
|
|
||||||
size() > Gets the dimensions of the terminal. Returns a table with `width` and `height`
|
|
||||||
Note: this is not the size in relation to the dimensions of the display
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
This has been moved to the `hilbish.timers` API doc (accessible by `doc api hilbish.timers`)
|
|
@ -1,38 +0,0 @@
|
||||||
If you ever want to run a piece of code on a timed interval, or want to wait
|
|
||||||
a few seconds, you don't have to rely on timing tricks, as Hilbish has a
|
|
||||||
timer API to set intervals and timeouts.
|
|
||||||
|
|
||||||
These are the simple functions `hilbish.interval` and `hilbish.timeout` (doc
|
|
||||||
accessible with `doc hilbish`). But if you want slightly more control over
|
|
||||||
them, there is the `hilbish.timers` interface. It allows you to get
|
|
||||||
a timer via ID.
|
|
||||||
|
|
||||||
# Timer Interface
|
|
||||||
## Functions
|
|
||||||
- `get(id)` -> timer: get a timer via its id
|
|
||||||
- `create(type, ms, callback)` -> timer: creates a timer, adding it to the timer pool.
|
|
||||||
`type` is the type of timer it will be. 0 is an interval, 1 is a timeout.
|
|
||||||
`ms` is the time it will run for in seconds. callback is the function called
|
|
||||||
when the timer is triggered.
|
|
||||||
|
|
||||||
# Timer Object
|
|
||||||
All those previously mentioned functions return a `timer` object, to which
|
|
||||||
you can stop and start a timer again.
|
|
||||||
|
|
||||||
An example of usage:
|
|
||||||
local t = hilbish.timers.create(1, 5000, function()
|
|
||||||
print 'hello!'
|
|
||||||
end)
|
|
||||||
|
|
||||||
t:stop()
|
|
||||||
print(t.running, t.duration, t.type)
|
|
||||||
t:start()
|
|
||||||
|
|
||||||
## Properties
|
|
||||||
- `duration`: amount of time the timer runs for in milliseconds
|
|
||||||
- `running`: whether the timer is running or not
|
|
||||||
- `type`: the type of timer (0 is interval, 1 is timeout)
|
|
||||||
|
|
||||||
## Functions
|
|
||||||
- `stop()`: stops the timer. returns an error if it's already stopped
|
|
||||||
- `start()`: starts the timer. returns an error if it's already started
|
|
19
editor.go
19
editor.go
|
@ -6,6 +6,10 @@ import (
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// #interface editor
|
||||||
|
// interactions for Hilbish's line reader
|
||||||
|
// The hilbish.editor interface provides functions to
|
||||||
|
// directly interact with the line editor in use.
|
||||||
func editorLoader(rtm *rt.Runtime) *rt.Table {
|
func editorLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
exports := map[string]util.LuaExport{
|
exports := map[string]util.LuaExport{
|
||||||
"insert": {editorInsert, 1, false},
|
"insert": {editorInsert, 1, false},
|
||||||
|
@ -20,6 +24,9 @@ func editorLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface editor
|
||||||
|
// insert(text)
|
||||||
|
// Inserts text into the line.
|
||||||
func editorInsert(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func editorInsert(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
|
||||||
|
@ -35,6 +42,11 @@ func editorInsert(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface editor
|
||||||
|
// setVimRegister(register, text)
|
||||||
|
// Sets the vim register at `register` to hold the passed text.
|
||||||
|
// --- @param register string
|
||||||
|
// --- @param text string
|
||||||
func editorSetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func editorSetRegister(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
|
||||||
|
@ -55,6 +67,10 @@ func editorSetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface editor
|
||||||
|
// getVimRegister(register) -> string
|
||||||
|
// Returns the text that is at the register.
|
||||||
|
// --- @param register string
|
||||||
func editorGetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func editorGetRegister(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
|
||||||
|
@ -70,6 +86,9 @@ func editorGetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil
|
return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface editor
|
||||||
|
// getLine() -> string
|
||||||
|
// Returns the current input line.
|
||||||
func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
buf := lr.rl.GetLine()
|
buf := lr.rl.GetLine()
|
||||||
|
|
||||||
|
|
|
@ -12,14 +12,21 @@ function bait.catch(name, cb) end
|
||||||
--- @param cb function
|
--- @param cb function
|
||||||
function bait.catchOnce(name, cb) end
|
function bait.catchOnce(name, cb) end
|
||||||
|
|
||||||
--- Removes the `catcher` for the event with `name`
|
--- Returns a table with hooks (callback functions) on the event with `name`.
|
||||||
|
--- @param name string
|
||||||
|
--- @returns table<function>
|
||||||
|
function bait.hooks(name) end
|
||||||
|
|
||||||
|
--- Removes the `catcher` for the event with `name`.
|
||||||
--- For this to work, `catcher` has to be the same function used to catch
|
--- For this to work, `catcher` has to be the same function used to catch
|
||||||
--- an event, like one saved to a variable.
|
--- an event, like one saved to a variable.
|
||||||
function bait.release() end
|
--- @param name string
|
||||||
|
--- @param catcher function
|
||||||
|
function bait.release(name, catcher) end
|
||||||
|
|
||||||
--- Throws a hook with `name` with the provided `args`
|
--- Throws a hook with `name` with the provided `args`
|
||||||
--- @param name string
|
--- @param name string
|
||||||
--- @vararg any
|
--- @vararg any
|
||||||
function bait.throw(name, ...) end
|
function bait.throw(name, ...args) end
|
||||||
|
|
||||||
return bait
|
return bait
|
||||||
|
|
|
@ -4,11 +4,13 @@ local fs = {}
|
||||||
|
|
||||||
--- Gives an absolute version of `path`.
|
--- Gives an absolute version of `path`.
|
||||||
--- @param path string
|
--- @param path string
|
||||||
|
--- @returns string
|
||||||
function fs.abs(path) end
|
function fs.abs(path) end
|
||||||
|
|
||||||
--- Gives the basename of `path`. For the rules,
|
--- Gives the basename of `path`. For the rules,
|
||||||
--- see Go's filepath.Base
|
--- see Go's filepath.Base
|
||||||
function fs.basename() end
|
--- @returns string
|
||||||
|
function fs.basename(path) end
|
||||||
|
|
||||||
--- Changes directory to `dir`
|
--- Changes directory to `dir`
|
||||||
--- @param dir string
|
--- @param dir string
|
||||||
|
@ -16,28 +18,40 @@ function fs.cd(dir) end
|
||||||
|
|
||||||
--- Returns the directory part of `path`. For the rules, see Go's
|
--- Returns the directory part of `path`. For the rules, see Go's
|
||||||
--- filepath.Dir
|
--- filepath.Dir
|
||||||
function fs.dir() end
|
--- @param path string
|
||||||
|
--- @returns string
|
||||||
|
function fs.dir(path) end
|
||||||
|
|
||||||
--- Glob all files and directories that match the pattern.
|
--- Glob all files and directories that match the pattern.
|
||||||
--- For the rules, see Go's filepath.Glob
|
--- For the rules, see Go's filepath.Glob
|
||||||
function fs.glob() end
|
--- @param pattern string
|
||||||
|
--- @returns table
|
||||||
|
function fs.glob(pattern) end
|
||||||
|
|
||||||
--- Takes paths and joins them together with the OS's
|
--- Takes paths and joins them together with the OS's
|
||||||
--- directory separator (forward or backward slash).
|
--- directory separator (forward or backward slash).
|
||||||
function fs.join() end
|
--- @vararg string
|
||||||
|
--- @returns string
|
||||||
|
function fs.join(...) end
|
||||||
|
|
||||||
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
--- Makes a directory called `name`. If `recursive` is true, it will create its parent directories.
|
||||||
--- @param name string
|
--- @param name string
|
||||||
--- @param recursive boolean
|
--- @param recursive boolean
|
||||||
function fs.mkdir(name, recursive) end
|
function fs.mkdir(name, recursive) end
|
||||||
|
|
||||||
--- Returns a table of files in `dir`
|
--- Returns a table of files in `dir`.
|
||||||
--- @param dir string
|
--- @param dir string
|
||||||
--- @return table
|
--- @return table
|
||||||
function fs.readdir(dir) end
|
function fs.readdir(dir) end
|
||||||
|
|
||||||
--- Returns info about `path`
|
--- Returns a table of info about the `path`.
|
||||||
|
--- It contains the following keys:
|
||||||
|
--- name (string) - Name of the path
|
||||||
|
--- size (number) - Size of the path
|
||||||
|
--- mode (string) - Permission mode in an octal format string (with leading 0)
|
||||||
|
--- isDir (boolean) - If the path is a directory
|
||||||
--- @param path string
|
--- @param path string
|
||||||
|
--- @returns table
|
||||||
function fs.stat(path) end
|
function fs.stat(path) end
|
||||||
|
|
||||||
return fs
|
return fs
|
||||||
|
|
|
@ -2,6 +2,49 @@
|
||||||
|
|
||||||
local hilbish = {}
|
local hilbish = {}
|
||||||
|
|
||||||
|
--- This is an alias (ha) for the `hilbish.alias` function.
|
||||||
|
--- @param alias string
|
||||||
|
--- @param cmd string
|
||||||
|
function hilbish.aliases.add(alias, cmd) end
|
||||||
|
|
||||||
|
--- This is the same as the `hilbish.runnerMode` function. It takes a callback,
|
||||||
|
--- which will be used to execute all interactive input.
|
||||||
|
--- In normal cases, neither callbacks should be overrided by the user,
|
||||||
|
--- as the higher level functions listed below this will handle it.
|
||||||
|
--- @param cb function
|
||||||
|
function hilbish.runner.setMode(cb) end
|
||||||
|
|
||||||
|
--- Calls a completer function. This is mainly used to call
|
||||||
|
--- a command completer, which will have a `name` in the form
|
||||||
|
--- of `command.name`, example: `command.git`.
|
||||||
|
--- You can check `doc completions` for info on the `completionGroups` return value.
|
||||||
|
--- @param name string
|
||||||
|
--- @param query string
|
||||||
|
--- @param ctx string
|
||||||
|
--- @param fields table
|
||||||
|
function hilbish.completions.call(name, query, ctx, fields) end
|
||||||
|
|
||||||
|
--- The handler function is the callback for tab completion in Hilbish.
|
||||||
|
--- You can check the completions doc for more info.
|
||||||
|
--- @param line string
|
||||||
|
--- @param pos string
|
||||||
|
function hilbish.completions.handler(line, pos) end
|
||||||
|
|
||||||
|
--- Returns the current input line.
|
||||||
|
function hilbish.editor.getLine() end
|
||||||
|
|
||||||
|
--- Returns the text that is at the register.
|
||||||
|
--- @param register string
|
||||||
|
function hilbish.editor.getVimRegister(register) end
|
||||||
|
|
||||||
|
--- Inserts text into the line.
|
||||||
|
function hilbish.editor.insert(text) end
|
||||||
|
|
||||||
|
--- Sets the vim register at `register` to hold the passed text.
|
||||||
|
--- @param register string
|
||||||
|
--- @param text string
|
||||||
|
function hilbish.editor.setVimRegister(register, text) end
|
||||||
|
|
||||||
--- Sets an alias of `cmd` to `orig`
|
--- Sets an alias of `cmd` to `orig`
|
||||||
--- @param cmd string
|
--- @param cmd string
|
||||||
--- @param orig string
|
--- @param orig string
|
||||||
|
@ -21,6 +64,7 @@ function hilbish.appendPath(dir) end
|
||||||
function hilbish.complete(scope, cb) end
|
function hilbish.complete(scope, cb) end
|
||||||
|
|
||||||
--- Returns the current directory of the shell
|
--- Returns the current directory of the shell
|
||||||
|
--- @returns string
|
||||||
function hilbish.cwd() end
|
function hilbish.cwd() end
|
||||||
|
|
||||||
--- Replaces running hilbish with `cmd`
|
--- Replaces running hilbish with `cmd`
|
||||||
|
@ -44,7 +88,7 @@ function hilbish.highlighter(line) end
|
||||||
--- as the text for the hint. This is by default a shim. To set hints,
|
--- as the text for the hint. This is by default a shim. To set hints,
|
||||||
--- override this function with your custom handler.
|
--- override this function with your custom handler.
|
||||||
--- @param line string
|
--- @param line string
|
||||||
--- @param pos int
|
--- @param pos number
|
||||||
function hilbish.hinter(line, pos) end
|
function hilbish.hinter(line, pos) end
|
||||||
|
|
||||||
--- Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
|
--- Sets the input mode for Hilbish's line reader. Accepts either emacs or vim
|
||||||
|
@ -52,10 +96,10 @@ function hilbish.hinter(line, pos) end
|
||||||
function hilbish.inputMode(mode) end
|
function hilbish.inputMode(mode) end
|
||||||
|
|
||||||
--- Runs the `cb` function every `time` milliseconds.
|
--- Runs the `cb` function every `time` milliseconds.
|
||||||
--- Returns a `timer` object (see `doc timers`).
|
--- This creates a timer that starts immediately.
|
||||||
--- @param cb function
|
--- @param cb function
|
||||||
--- @param time number
|
--- @param time number
|
||||||
--- @return table
|
--- @return Timer
|
||||||
function hilbish.interval(cb, time) end
|
function hilbish.interval(cb, time) end
|
||||||
|
|
||||||
--- Changes the continued line prompt to `str`
|
--- Changes the continued line prompt to `str`
|
||||||
|
@ -73,20 +117,23 @@ function hilbish.prependPath(dir) end
|
||||||
--- `%u` - Name of current user
|
--- `%u` - Name of current user
|
||||||
--- `%h` - Hostname of device
|
--- `%h` - Hostname of device
|
||||||
--- @param str string
|
--- @param str string
|
||||||
--- @param typ string Type of prompt, being left or right. Left by default.
|
--- @param typ? string Type of prompt, being left or right. Left by default.
|
||||||
function hilbish.prompt(str, typ) end
|
function hilbish.prompt(str, typ) end
|
||||||
|
|
||||||
--- Read input from the user, using Hilbish's line editor/input reader.
|
--- Read input from the user, using Hilbish's line editor/input reader.
|
||||||
--- This is a separate instance from the one Hilbish actually uses.
|
--- This is a separate instance from the one Hilbish actually uses.
|
||||||
--- Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
--- Returns `input`, will be nil if ctrl + d is pressed, or an error occurs (which shouldn't happen)
|
||||||
--- @param prompt string
|
--- @param prompt? string
|
||||||
|
--- @returns string|nil
|
||||||
function hilbish.read(prompt) end
|
function hilbish.read(prompt) end
|
||||||
|
|
||||||
--- Runs `cmd` in Hilbish's sh interpreter.
|
--- Runs `cmd` in Hilbish's sh interpreter.
|
||||||
--- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
--- If returnOut is true, the outputs of `cmd` will be returned as the 2nd and
|
||||||
--- 3rd values instead of being outputted to the terminal.
|
--- 3rd values instead of being outputted to the terminal.
|
||||||
--- @param cmd string
|
--- @param cmd string
|
||||||
function hilbish.run(cmd) end
|
--- @param returnOut boolean
|
||||||
|
--- @returns number, string, string
|
||||||
|
function hilbish.run(cmd, returnOut) end
|
||||||
|
|
||||||
--- Sets the execution/runner mode for interactive Hilbish. This determines whether
|
--- Sets the execution/runner mode for interactive Hilbish. This determines whether
|
||||||
--- Hilbish wll try to run input as Lua and/or sh or only do one of either.
|
--- Hilbish wll try to run input as Lua and/or sh or only do one of either.
|
||||||
|
@ -96,15 +143,131 @@ function hilbish.run(cmd) end
|
||||||
--- @param mode string|function
|
--- @param mode string|function
|
||||||
function hilbish.runnerMode(mode) end
|
function hilbish.runnerMode(mode) end
|
||||||
|
|
||||||
--- Runs the `cb` function after `time` in milliseconds
|
--- Runs the `cb` function after `time` in milliseconds.
|
||||||
--- Returns a `timer` object (see `doc timers`).
|
--- This creates a timer that starts immediately.
|
||||||
--- @param cb function
|
--- @param cb function
|
||||||
--- @param time number
|
--- @param time number
|
||||||
--- @return table
|
--- @returns Timer
|
||||||
function hilbish.timeout(cb, time) end
|
function hilbish.timeout(cb, time) end
|
||||||
|
|
||||||
--- Checks if `name` is a valid command
|
--- Checks if `name` is a valid command.
|
||||||
--- @param binName string
|
--- Will return the path of the binary, or a basename if it's a commander.
|
||||||
function hilbish.which(binName) end
|
--- @param name string
|
||||||
|
--- @returns string
|
||||||
|
function hilbish.which(name) end
|
||||||
|
|
||||||
|
--- Puts a job in the background. This acts the same as initially running a job.
|
||||||
|
function hilbish.jobs:background() end
|
||||||
|
|
||||||
|
--- Returns binary/executale completion candidates based on the provided query.
|
||||||
|
--- @param query string
|
||||||
|
--- @param ctx string
|
||||||
|
--- @param fields table
|
||||||
|
function hilbish.completions.bins(query, ctx, fields) end
|
||||||
|
|
||||||
|
--- Returns file completion candidates based on the provided query.
|
||||||
|
--- @param query string
|
||||||
|
--- @param ctx string
|
||||||
|
--- @param fields table
|
||||||
|
function hilbish.completions.files(query, ctx, fields) end
|
||||||
|
|
||||||
|
--- Puts a job in the foreground. This will cause it to run like it was
|
||||||
|
--- executed normally and wait for it to complete.
|
||||||
|
function hilbish.jobs:foreground() end
|
||||||
|
|
||||||
|
--- Evaluates `cmd` as Lua input. This is the same as using `dofile`
|
||||||
|
--- or `load`, but is appropriated for the runner interface.
|
||||||
|
--- @param cmd string
|
||||||
|
function hilbish.runner.lua(cmd) end
|
||||||
|
|
||||||
|
--- Writes data to a sink.
|
||||||
|
function hilbish:write(str) end
|
||||||
|
|
||||||
|
--- Writes data to a sink with a newline at the end.
|
||||||
|
function hilbish:writeln(str) end
|
||||||
|
|
||||||
|
--- Starts running the job.
|
||||||
|
function hilbish.jobs:start() end
|
||||||
|
|
||||||
|
--- Stops the job from running.
|
||||||
|
function hilbish.jobs:stop() end
|
||||||
|
|
||||||
|
--- Runs a command in Hilbish's shell script interpreter.
|
||||||
|
--- This is the equivalent of using `source`.
|
||||||
|
--- @param cmd string
|
||||||
|
function hilbish.runner.sh(cmd) end
|
||||||
|
|
||||||
|
--- Starts a timer.
|
||||||
|
function hilbish.timers:start() end
|
||||||
|
|
||||||
|
--- Stops a timer.
|
||||||
|
function hilbish.timers:stop() end
|
||||||
|
|
||||||
|
--- Removes an alias.
|
||||||
|
--- @param name string
|
||||||
|
function hilbish.aliases.delete(name) end
|
||||||
|
|
||||||
|
--- Get a table of all aliases, with string keys as the alias and the value as the command.
|
||||||
|
--- @returns table<string, string>
|
||||||
|
function hilbish.aliases.list() end
|
||||||
|
|
||||||
|
--- Tries to resolve an alias to its command.
|
||||||
|
--- @param alias string
|
||||||
|
--- @returns string
|
||||||
|
function hilbish.aliases.resolve(alias) end
|
||||||
|
|
||||||
|
--- Adds a new job to the job table. Note that this does not immediately run it.
|
||||||
|
--- @param cmdstr string
|
||||||
|
--- @param args table
|
||||||
|
--- @param execPath string
|
||||||
|
function hilbish.jobs.add(cmdstr, args, execPath) end
|
||||||
|
|
||||||
|
--- Returns a table of all job objects.
|
||||||
|
--- @returns table<Job>
|
||||||
|
function hilbish.jobs.all() end
|
||||||
|
|
||||||
|
--- Disowns a job. This deletes it from the job table.
|
||||||
|
--- @param id number
|
||||||
|
function hilbish.jobs.disown(id) end
|
||||||
|
|
||||||
|
--- Get a job object via its ID.
|
||||||
|
--- @param id number
|
||||||
|
--- @returns Job
|
||||||
|
function hilbish.jobs.get(id) end
|
||||||
|
|
||||||
|
--- Returns the last added job from the table.
|
||||||
|
--- @returns Job
|
||||||
|
function hilbish.jobs.last() end
|
||||||
|
|
||||||
|
--- Adds a command to the history.
|
||||||
|
--- @param cmd string
|
||||||
|
function hilbish.history.add(cmd) end
|
||||||
|
|
||||||
|
--- Retrieves all history.
|
||||||
|
--- @returns table
|
||||||
|
function hilbish.history.all() end
|
||||||
|
|
||||||
|
--- Deletes all commands from the history.
|
||||||
|
function hilbish.history.clear() end
|
||||||
|
|
||||||
|
--- Retrieves a command from the history based on the `idx`.
|
||||||
|
--- @param idx number
|
||||||
|
function hilbish.history.get(idx) end
|
||||||
|
|
||||||
|
--- Returns the amount of commands in the history.
|
||||||
|
--- @returns number
|
||||||
|
function hilbish.history.size() end
|
||||||
|
|
||||||
|
--- Creates a timer that runs based on the specified `time` in milliseconds.
|
||||||
|
--- The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
||||||
|
--- @param type number
|
||||||
|
--- @param time number
|
||||||
|
--- @param callback function
|
||||||
|
function hilbish.timers.create(type, time, callback) end
|
||||||
|
|
||||||
|
--- Retrieves a timer via its ID.
|
||||||
|
--- @param id number
|
||||||
|
--- @returns Timer
|
||||||
|
function hilbish.timers.get(id) end
|
||||||
|
|
||||||
return hilbish
|
return hilbish
|
||||||
|
|
32
exec.go
32
exec.go
|
@ -96,23 +96,23 @@ func runInput(input string, priv bool) {
|
||||||
if currentRunner.Type() == rt.StringType {
|
if currentRunner.Type() == rt.StringType {
|
||||||
switch currentRunner.AsString() {
|
switch currentRunner.AsString() {
|
||||||
case "hybrid":
|
case "hybrid":
|
||||||
_, _, err = handleLua(cmdString)
|
_, _, err = handleLua(input)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
cmdFinish(0, input, priv)
|
cmdFinish(0, input, priv)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
input, exitCode, cont, err = handleSh(cmdString)
|
input, exitCode, cont, 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
|
||||||
}
|
}
|
||||||
input, exitCode, err = handleLua(cmdString)
|
input, exitCode, err = handleLua(input)
|
||||||
case "lua":
|
case "lua":
|
||||||
input, exitCode, err = handleLua(cmdString)
|
input, exitCode, err = handleLua(input)
|
||||||
case "sh":
|
case "sh":
|
||||||
input, exitCode, cont, err = handleSh(cmdString)
|
input, exitCode, cont, err = handleSh(input)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// can only be a string or function so
|
// can only be a string or function so
|
||||||
|
@ -141,9 +141,9 @@ func runInput(input string, priv bool) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
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)
|
||||||
err = exErr.sprint()
|
} else {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(os.Stderr, err)
|
|
||||||
}
|
}
|
||||||
cmdFinish(exitCode, input, priv)
|
cmdFinish(exitCode, input, priv)
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,8 @@ func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleLua(cmdString string) (string, uint8, error) {
|
func handleLua(input string) (string, uint8, error) {
|
||||||
|
cmdString := aliases.Resolve(input)
|
||||||
// First try to load input, essentially compiling to bytecode
|
// First try to load input, essentially compiling to bytecode
|
||||||
chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv()))
|
chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv()))
|
||||||
if err != nil && noexecute {
|
if err != nil && noexecute {
|
||||||
|
@ -322,8 +323,18 @@ func execHandle(bg bool) interp.ExecHandlerFunc {
|
||||||
luacmdArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(str))
|
luacmdArgs.Set(rt.IntValue(int64(i + 1)), rt.StringValue(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hc := interp.HandlerCtx(ctx)
|
||||||
if commands[args[0]] != nil {
|
if commands[args[0]] != nil {
|
||||||
luaexitcode, err := rt.Call1(l.MainThread(), rt.FunctionValue(commands[args[0]]), rt.TableValue(luacmdArgs))
|
stdin := newSinkInput(hc.Stdin)
|
||||||
|
stdout := newSinkOutput(hc.Stdout)
|
||||||
|
stderr := newSinkOutput(hc.Stderr)
|
||||||
|
|
||||||
|
sinks := rt.NewTable()
|
||||||
|
sinks.Set(rt.StringValue("in"), rt.UserDataValue(stdin.ud))
|
||||||
|
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(commands[args[0]]), rt.TableValue(luacmdArgs), rt.TableValue(sinks))
|
||||||
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)
|
||||||
|
@ -363,7 +374,6 @@ 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
|
||||||
hc := interp.HandlerCtx(ctx)
|
|
||||||
path, err := interp.LookPathDir(hc.Dir, hc.Env, args[0])
|
path, err := interp.LookPathDir(hc.Dir, hc.Env, args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(hc.Stderr, err)
|
fmt.Fprintln(hc.Stderr, err)
|
||||||
|
@ -551,7 +561,7 @@ func splitInput(input string) ([]string, string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func cmdFinish(code uint8, cmdstr string, private bool) {
|
func cmdFinish(code uint8, cmdstr string, private bool) {
|
||||||
util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)), "Exit code of last exected command")
|
util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)))
|
||||||
// using AsValue (to convert to lua type) on an interface which is an int
|
// using AsValue (to convert to lua type) on an interface which is an int
|
||||||
// results in it being unknown in lua .... ????
|
// results in it being unknown in lua .... ????
|
||||||
// so we allow the hook handler to take lua runtime Values
|
// so we allow the hook handler to take lua runtime Values
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
16
go.mod
16
go.mod
|
@ -3,11 +3,8 @@ module hilbish
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Rosettea/Malvales v0.0.0-20220707042337-37a9ee7758f9
|
|
||||||
github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86
|
github.com/arnodel/golua v0.0.0-20220221163911-dfcf252b6f86
|
||||||
github.com/blackfireio/osinfo v1.0.3
|
github.com/blackfireio/osinfo v1.0.3
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9
|
|
||||||
github.com/hashicorp/go-plugin v1.4.4
|
|
||||||
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
|
github.com/maxlandon/readline v0.1.0-beta.0.20211027085530-2b76cabb8036
|
||||||
github.com/pborman/getopt v1.1.0
|
github.com/pborman/getopt v1.1.0
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||||
|
@ -19,21 +16,10 @@ require (
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect
|
||||||
github.com/arnodel/strftime v0.1.6 // indirect
|
github.com/arnodel/strftime v0.1.6 // indirect
|
||||||
github.com/evilsocket/islazy v1.10.6 // indirect
|
github.com/evilsocket/islazy v1.10.6 // indirect
|
||||||
github.com/fatih/color v1.7.0 // indirect
|
|
||||||
github.com/golang/protobuf v1.3.4 // indirect
|
|
||||||
github.com/hashicorp/go-hclog v0.14.1 // indirect
|
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb // indirect
|
|
||||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
|
||||||
github.com/mattn/go-isatty v0.0.10 // indirect
|
|
||||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 // indirect
|
|
||||||
github.com/oklog/run v1.0.0 // 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.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect
|
|
||||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect
|
|
||||||
google.golang.org/grpc v1.27.1 // 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.20220524215627-dfd9a4fa219b
|
||||||
|
@ -42,4 +28,4 @@ replace github.com/maxlandon/readline => ./readline
|
||||||
|
|
||||||
replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10
|
replace layeh.com/gopher-luar => github.com/layeh/gopher-luar v1.0.10
|
||||||
|
|
||||||
replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3
|
replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345
|
||||||
|
|
89
go.sum
89
go.sum
|
@ -1,9 +1,5 @@
|
||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345 h1:QNYjYDogUSiNUkffbhFSrSCtpZhofeiVYGFN2FI4wSs=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE=
|
||||||
github.com/Rosettea/Malvales v0.0.0-20220707042337-37a9ee7758f9 h1:iVIheUFcp/EhUYaCo67eG4fhW5EHxQDUNYq319DPNmc=
|
|
||||||
github.com/Rosettea/Malvales v0.0.0-20220707042337-37a9ee7758f9/go.mod h1:vZdkshJ9RK/Hu1aUNa6suOC1XfaFOzxqQQ7OZFpNYbw=
|
|
||||||
github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3 h1:I/wWr40FFLFF9pbT3wLb1FAEZhKb/hUWE+nJ5uHBK2g=
|
|
||||||
github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3/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 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.20220524215627-dfd9a4fa219b/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs=
|
||||||
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8=
|
||||||
|
@ -14,44 +10,15 @@ github.com/arnodel/strftime v0.1.6/go.mod h1:5NbK5XqYK8QpRZpqKNt4OlxLtIB8cotkLk4
|
||||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c=
|
github.com/blackfireio/osinfo v1.0.3 h1:Yk2t2GTPjBcESv6nDSWZKO87bGMQgO+Hi9OoXPpxX8c=
|
||||||
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
|
github.com/blackfireio/osinfo v1.0.3/go.mod h1:Pd987poVNmd5Wsx6PRPw4+w7kLlf9iJxoRKPtPAjOrA=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9 h1:xz6Nv3zcwO2Lila35hcb0QloCQsc38Al13RNEzWRpX4=
|
|
||||||
github.com/chuckpreslar/emission v0.0.0-20170206194824-a7ddd980baf9/go.mod h1:2wSM9zJkl1UQEFZgSd68NfCgRz1VL1jzy/RjCg+ULrs=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
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 h1:cKRCLMj3Ddm54bKSpemfQ8AtYFBhAI2MPmdys22fBdc=
|
||||||
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
github.com/creack/pty v1.1.15/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/evilsocket/islazy v1.10.6 h1:MFq000a1ByoumoJWlytqg0qon0KlBeUfPsDjY0hK0bo=
|
github.com/evilsocket/islazy v1.10.6 h1:MFq000a1ByoumoJWlytqg0qon0KlBeUfPsDjY0hK0bo=
|
||||||
github.com/evilsocket/islazy v1.10.6/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
|
github.com/evilsocket/islazy v1.10.6/go.mod h1:OrwQGYg3DuZvXUfmH+KIZDjwTCbrjy48T24TUpGqVVw=
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
|
||||||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
|
||||||
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
github.com/gdamore/tcell/v2 v2.4.0/go.mod h1:cTTuF84Dlj/RqmaCIV5p4w8uG1zWdk0SF6oBpwHp4fU=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
|
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
|
||||||
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
|
||||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
|
||||||
github.com/hashicorp/go-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7JYWQ=
|
|
||||||
github.com/hashicorp/go-plugin v1.4.4/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s=
|
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
|
||||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
|
||||||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
|
||||||
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
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 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
|
@ -60,56 +27,21 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
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/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
|
||||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
|
||||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
|
||||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
|
|
||||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
|
||||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
|
||||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
|
||||||
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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
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 h1:d1PiN4RxzIFXCJTvRkvSkKqwtRAl5ZV4lATKtQI0B7I=
|
||||||
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
github.com/rogpeppe/go-internal v1.8.1-0.20210923151022-86f73c517451/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
|
||||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
||||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -126,23 +58,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
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=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
|
mvdan.cc/editorconfig v0.2.0/go.mod h1:lvnnD3BNdBYkhq+B4uBuFFKatfp02eB6HixDvEz91C0=
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
|
// the event emitter
|
||||||
|
// Bait is the event emitter for Hilbish. Why name it bait? Why not.
|
||||||
|
// It throws hooks that you can catch. This is what you will use if
|
||||||
|
// you want to listen in on hooks to know when certain things have
|
||||||
|
// happened, like when you've changed directory, a command has failed,
|
||||||
|
// etc. To find all available hooks thrown by Hilbish, see doc hooks.
|
||||||
package bait
|
package bait
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"hilbish/util"
|
"hilbish/util"
|
||||||
|
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
@ -72,8 +80,12 @@ func (b *Bait) Emit(event string, args ...interface{}) {
|
||||||
}
|
}
|
||||||
_, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...)
|
_, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// panicking here won't actually cause hilbish to panic and instead will
|
if event != "error" {
|
||||||
// print the error and remove the hook. reference the recoverer function in lua.go
|
b.Emit("error", event, handle.luaCaller, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// if there is an error in an error event handler, panic instead
|
||||||
|
// (calls the go recoverer function)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -187,19 +199,11 @@ func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
"catchOnce": util.LuaExport{b.bcatchOnce, 2, false},
|
"catchOnce": util.LuaExport{b.bcatchOnce, 2, false},
|
||||||
"throw": util.LuaExport{b.bthrow, 1, true},
|
"throw": util.LuaExport{b.bthrow, 1, true},
|
||||||
"release": util.LuaExport{b.brelease, 2, false},
|
"release": util.LuaExport{b.brelease, 2, false},
|
||||||
|
"hooks": util.LuaExport{b.bhooks, 1, false},
|
||||||
}
|
}
|
||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
|
|
||||||
util.Document(mod,
|
|
||||||
`Bait is the event emitter for Hilbish. Why name it bait?
|
|
||||||
Because it throws hooks that you can catch (emits events
|
|
||||||
that you can listen to) and because why not, fun naming
|
|
||||||
is fun. This is what you will use if you want to listen
|
|
||||||
in on hooks to know when certain things have happened,
|
|
||||||
like when you've changed directory, a command has
|
|
||||||
failed, etc. To find all available hooks, see doc hooks.`)
|
|
||||||
|
|
||||||
return rt.TableValue(mod), nil
|
return rt.TableValue(mod), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,9 +280,11 @@ func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// release(name, catcher)
|
// release(name, catcher)
|
||||||
// Removes the `catcher` for the event with `name`
|
// Removes the `catcher` for the event with `name`.
|
||||||
// For this to work, `catcher` has to be the same function used to catch
|
// For this to work, `catcher` has to be the same function used to catch
|
||||||
// an event, like one saved to a variable.
|
// an event, like one saved to a variable.
|
||||||
|
// --- @param name string
|
||||||
|
// --- @param catcher function
|
||||||
func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
name, catcher, err := util.HandleStrCallback(t, c)
|
name, catcher, err := util.HandleStrCallback(t, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -289,3 +295,35 @@ func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// hooks(name) -> table
|
||||||
|
// Returns a table with hooks (callback functions) on the event with `name`.
|
||||||
|
// --- @param name string
|
||||||
|
// --- @returns table<function>
|
||||||
|
func (b *Bait) bhooks(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.Check1Arg(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
evName, err := c.StringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
noHooks := errors.New("no hooks for event " + evName)
|
||||||
|
|
||||||
|
handlers := b.handlers[evName]
|
||||||
|
if handlers == nil {
|
||||||
|
return nil, noHooks
|
||||||
|
}
|
||||||
|
|
||||||
|
luaHandlers := rt.NewTable()
|
||||||
|
for _, handler := range handlers {
|
||||||
|
if handler.typ != luaListener { continue }
|
||||||
|
luaHandlers.Set(rt.IntValue(luaHandlers.Len() + 1), rt.FunctionValue(handler.luaCaller))
|
||||||
|
}
|
||||||
|
|
||||||
|
if luaHandlers.Len() == 0 {
|
||||||
|
return nil, noHooks
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, rt.TableValue(luaHandlers)), nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,33 @@
|
||||||
|
// library for custom commands
|
||||||
|
/*
|
||||||
|
Commander is a library for writing custom commands in Lua.
|
||||||
|
In order to make it easier to write commands for Hilbish,
|
||||||
|
not require separate scripts and to be able to use in a config,
|
||||||
|
the Commander library exists. This is like a very simple wrapper
|
||||||
|
that works with Hilbish for writing commands. Example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local commander = require 'commander'
|
||||||
|
|
||||||
|
commander.register('hello', function(args, sinks)
|
||||||
|
sinks.out:writeln 'Hello world!'
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, a command with the name of `hello` is created
|
||||||
|
that will print `Hello world!` to output. One question you may
|
||||||
|
have is: What is the `sinks` parameter?
|
||||||
|
|
||||||
|
The `sinks` parameter is a table with 3 keys: `in`, `out`,
|
||||||
|
and `err`. The values of these is a @Sink.
|
||||||
|
|
||||||
|
- `in` is the standard input. You can read from this sink
|
||||||
|
to get user input. (**This is currently unimplemented.**)
|
||||||
|
- `out` is standard output. This is usually where text meant for
|
||||||
|
output should go.
|
||||||
|
- `err` is standard error. This sink is for writing errors, as the
|
||||||
|
name would suggest.
|
||||||
|
*/
|
||||||
package commander
|
package commander
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -32,7 +62,6 @@ func (c *Commander) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
}
|
}
|
||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
util.Document(mod, "Commander is Hilbish's custom command library, a way to write commands in Lua.")
|
|
||||||
|
|
||||||
return rt.TableValue(mod), nil
|
return rt.TableValue(mod), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// filesystem interaction and functionality library
|
||||||
|
// The fs module provides easy and simple access to filesystem functions
|
||||||
|
// and other things, and acts an addition to the Lua standard library's
|
||||||
|
// I/O and filesystem functions.
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -35,10 +39,6 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
mod.Set(rt.StringValue("pathSep"), rt.StringValue(string(os.PathSeparator)))
|
mod.Set(rt.StringValue("pathSep"), rt.StringValue(string(os.PathSeparator)))
|
||||||
mod.Set(rt.StringValue("pathListSep"), rt.StringValue(string(os.PathListSeparator)))
|
mod.Set(rt.StringValue("pathListSep"), rt.StringValue(string(os.PathListSeparator)))
|
||||||
|
|
||||||
util.Document(mod, `The fs module provides easy and simple access to
|
|
||||||
filesystem functions and other things, and acts an
|
|
||||||
addition to the Lua standard library's I/O and filesystem functions.`)
|
|
||||||
|
|
||||||
return rt.TableValue(mod), nil
|
return rt.TableValue(mod), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,9 +93,15 @@ func fmkdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), err
|
return c.Next(), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// stat(path)
|
// stat(path) -> {}
|
||||||
// Returns info about `path`
|
// Returns a table of info about the `path`.
|
||||||
|
// It contains the following keys:
|
||||||
|
// name (string) - Name of the path
|
||||||
|
// size (number) - Size of the path
|
||||||
|
// mode (string) - Permission mode in an octal format string (with leading 0)
|
||||||
|
// isDir (boolean) - If the path is a directory
|
||||||
// --- @param path string
|
// --- @param path string
|
||||||
|
// --- @returns table
|
||||||
func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func 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
|
||||||
|
@ -119,8 +125,8 @@ func fstat(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
|
return c.PushingNext1(t.Runtime, rt.TableValue(statTbl)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readdir(dir)
|
// readdir(dir) -> {}
|
||||||
// Returns a table of files in `dir`
|
// Returns a table of files in `dir`.
|
||||||
// --- @param dir string
|
// --- @param dir string
|
||||||
// --- @return table
|
// --- @return table
|
||||||
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
@ -145,9 +151,10 @@ func freaddir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
|
return c.PushingNext1(t.Runtime, rt.TableValue(names)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// abs(path)
|
// abs(path) -> string
|
||||||
// Gives an absolute version of `path`.
|
// Gives an absolute version of `path`.
|
||||||
// --- @param path string
|
// --- @param path string
|
||||||
|
// --- @returns string
|
||||||
func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func 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 {
|
||||||
|
@ -163,9 +170,10 @@ func fabs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil
|
return c.PushingNext1(t.Runtime, rt.StringValue(abspath)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// basename(path)
|
// basename(path) -> string
|
||||||
// Gives the basename of `path`. For the rules,
|
// Gives the basename of `path`. For the rules,
|
||||||
// see Go's filepath.Base
|
// see Go's filepath.Base
|
||||||
|
// --- @returns string
|
||||||
func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func 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
|
||||||
|
@ -178,9 +186,11 @@ func fbasename(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Base(path))), nil
|
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Base(path))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// dir(path)
|
// dir(path) -> string
|
||||||
// Returns the directory part of `path`. For the rules, see Go's
|
// Returns the directory part of `path`. For the rules, see Go's
|
||||||
// filepath.Dir
|
// filepath.Dir
|
||||||
|
// --- @param path string
|
||||||
|
// --- @returns string
|
||||||
func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func 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
|
||||||
|
@ -193,9 +203,11 @@ func fdir(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil
|
return c.PushingNext(t.Runtime, rt.StringValue(filepath.Dir(path))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// glob(pattern)
|
// glob(pattern) -> matches (table)
|
||||||
// Glob all files and directories that match the pattern.
|
// Glob all files and directories that match the pattern.
|
||||||
// For the rules, see Go's filepath.Glob
|
// For the rules, see Go's filepath.Glob
|
||||||
|
// --- @param pattern string
|
||||||
|
// --- @returns table
|
||||||
func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func 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
|
||||||
|
@ -219,9 +231,11 @@ func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil
|
return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// join(paths...)
|
// join(...) -> string
|
||||||
// Takes paths and joins them together with the OS's
|
// Takes paths and joins them together with the OS's
|
||||||
// directory separator (forward or backward slash).
|
// directory separator (forward or backward slash).
|
||||||
|
// --- @vararg string
|
||||||
|
// --- @returns string
|
||||||
func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func 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() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// low level terminal library
|
||||||
|
// The terminal library is a simple and lower level library for certain terminal interactions.
|
||||||
package terminal
|
package terminal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
@ -26,7 +28,6 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) {
|
||||||
|
|
||||||
mod := rt.NewTable()
|
mod := rt.NewTable()
|
||||||
util.SetExports(rtm, mod, exports)
|
util.SetExports(rtm, mod, exports)
|
||||||
util.Document(mod, "The terminal library is a simple and lower level library for certain terminal interactions.")
|
|
||||||
|
|
||||||
return rt.TableValue(mod), nil
|
return rt.TableValue(mod), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
%global _missing_build_ids_terminate_build 0
|
||||||
|
%global debug_package %{nil}
|
||||||
|
|
||||||
|
Name: hilbish-git
|
||||||
|
Version: {{{ git_tag_version }}}.{{{ git_short_hash }}}
|
||||||
|
Release: 1%{?dist}
|
||||||
|
Summary: The flower shell. A comfy and nice little shell for Lua fans!
|
||||||
|
License: MIT
|
||||||
|
|
||||||
|
Source: {{{ git_dir_pack }}}
|
||||||
|
BuildRequires: git golang go-task
|
||||||
|
Requires: inspect succulent lunacolors
|
||||||
|
|
||||||
|
Url: https://github.com/Rosettea/Hilbish
|
||||||
|
VCS: {{{ git_dir_vcs }}}
|
||||||
|
|
||||||
|
%description
|
||||||
|
Hilbish is a extensible shell (framework). It was made to be very customizable
|
||||||
|
via the Lua programming language. It aims to be easy to use for the casual
|
||||||
|
people but powerful for those who want to tinker more with their shell,
|
||||||
|
the thing used to interface with most of the system.
|
||||||
|
|
||||||
|
The motivation for choosing Lua was that its simpler and better to use
|
||||||
|
than old shell script. It's fine for basic interactive shell uses,
|
||||||
|
but that's the only place Hilbish has shell script; everything else is Lua
|
||||||
|
and aims to be infinitely configurable. If something isn't, open an issue!
|
||||||
|
|
||||||
|
%prep
|
||||||
|
{{{ git_dir_setup_macro }}}
|
||||||
|
sed -i '\|/etc/shells|d' Taskfile.yaml
|
||||||
|
|
||||||
|
%build
|
||||||
|
go-task
|
||||||
|
|
||||||
|
%install
|
||||||
|
go-task install PREFIX=%{buildroot}/usr BINDIR=%{buildroot}/%{_bindir}
|
||||||
|
|
||||||
|
%post
|
||||||
|
if [ "$1" = 1 ]; then
|
||||||
|
if [ ! -f %{_sysconfdir}/shells ] ; then
|
||||||
|
echo "%{_bindir}/hilbish" > %{_sysconfdir}/shells
|
||||||
|
echo "/bin/hilbish" >> %{_sysconfdir}/shells
|
||||||
|
else
|
||||||
|
grep -q "^%{_bindir}/hilbish$" %{_sysconfdir}/shells || echo "%{_bindir}/hilbish" >> %{_sysconfdir}/shells
|
||||||
|
grep -q "^/bin/hilbish$" %{_sysconfdir}/shells || echo "/bin/hilbish" >> %{_sysconfdir}/shells
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
%postun
|
||||||
|
if [ "$1" = 0 ] && [ -f %{_sysconfdir}/shells ] ; then
|
||||||
|
sed -i '\!^%{_bindir}/hilbish$!d' %{_sysconfdir}/shells
|
||||||
|
sed -i '\!^/bin/hilbish$!d' %{_sysconfdir}/shells
|
||||||
|
fi
|
||||||
|
|
||||||
|
%files
|
||||||
|
%doc README.md
|
||||||
|
%license LICENSE
|
||||||
|
%{_bindir}/hilbish
|
||||||
|
%{_datadir}/hilbish
|
|
@ -73,13 +73,13 @@ func newFileHistory(path string) *fileHistory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
itms := []string{""}
|
|
||||||
lines := strings.Split(string(data), "\n")
|
lines := strings.Split(string(data), "\n")
|
||||||
|
itms := make([]string, len(lines) - 1)
|
||||||
for i, l := range lines {
|
for i, l := range lines {
|
||||||
if i == len(lines) - 1 {
|
if i == len(lines) - 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
itms = append(itms, l)
|
itms[i] = l
|
||||||
}
|
}
|
||||||
f, err := os.OpenFile(path, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755)
|
f, err := os.OpenFile(path, os.O_APPEND | os.O_WRONLY | os.O_CREATE, 0755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
57
job.go
57
job.go
|
@ -18,6 +18,16 @@ import (
|
||||||
var jobs *jobHandler
|
var jobs *jobHandler
|
||||||
var jobMetaKey = rt.StringValue("hshjob")
|
var jobMetaKey = rt.StringValue("hshjob")
|
||||||
|
|
||||||
|
// #type
|
||||||
|
// #interface jobs
|
||||||
|
// #property cmd The user entered command string for the job.
|
||||||
|
// #property running Whether the job is running or not.
|
||||||
|
// #property id The ID of the job in the job table
|
||||||
|
// #property pid The Process ID
|
||||||
|
// #property exitCode The last exit code of the job.
|
||||||
|
// #property stdout The standard output of the job. This just means the normal logs of the process.
|
||||||
|
// #property stderr The standard error stream of the process. This (usually) includes error messages of the job.
|
||||||
|
// The Job type describes a Hilbish job.
|
||||||
type job struct {
|
type job struct {
|
||||||
cmd string
|
cmd string
|
||||||
running bool
|
running bool
|
||||||
|
@ -110,6 +120,10 @@ func (j *job) getProc() *os.Process {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// #member
|
||||||
|
// start()
|
||||||
|
// Starts running the job.
|
||||||
func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaStartJob(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
|
||||||
|
@ -130,6 +144,10 @@ func luaStartJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// #member
|
||||||
|
// stop()
|
||||||
|
// Stops the job from running.
|
||||||
func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaStopJob(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
|
||||||
|
@ -148,6 +166,11 @@ func luaStopJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// #member
|
||||||
|
// foreground()
|
||||||
|
// Puts a job in the foreground. This will cause it to run like it was
|
||||||
|
// executed normally and wait for it to complete.
|
||||||
func luaForegroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaForegroundJob(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
|
||||||
|
@ -180,6 +203,10 @@ func luaForegroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// #member
|
||||||
|
// background()
|
||||||
|
// Puts a job in the background. This acts the same as initially running a job.
|
||||||
func luaBackgroundJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaBackgroundJob(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
|
||||||
|
@ -276,6 +303,13 @@ func (j *jobHandler) stopAll() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// background job management
|
||||||
|
/*
|
||||||
|
Manage interactive jobs in Hilbish via Lua.
|
||||||
|
|
||||||
|
Jobs are the name of background tasks/commands. A job can be started via
|
||||||
|
interactive usage or with the functions defined below for use in external runners. */
|
||||||
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
|
func (j *jobHandler) loader(rtm *rt.Runtime) *rt.Table {
|
||||||
jobMethods := rt.NewTable()
|
jobMethods := rt.NewTable()
|
||||||
jFuncs := map[string]util.LuaExport{
|
jFuncs := map[string]util.LuaExport{
|
||||||
|
@ -353,6 +387,11 @@ func jobUserData(j *job) *rt.UserData {
|
||||||
return rt.NewUserData(j, jobMeta.AsTable())
|
return rt.NewUserData(j, jobMeta.AsTable())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// get(id) -> @Job
|
||||||
|
// Get a job object via its ID.
|
||||||
|
// --- @param id number
|
||||||
|
// --- @returns Job
|
||||||
func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
j.mu.RLock()
|
j.mu.RLock()
|
||||||
defer j.mu.RUnlock()
|
defer j.mu.RUnlock()
|
||||||
|
@ -373,6 +412,12 @@ func (j *jobHandler) luaGetJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.UserDataValue(job.ud)), nil
|
return c.PushingNext(t.Runtime, rt.UserDataValue(job.ud)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// add(cmdstr, args, execPath)
|
||||||
|
// Adds a new job to the job table. Note that this does not immediately run it.
|
||||||
|
// --- @param cmdstr string
|
||||||
|
// --- @param args table
|
||||||
|
// --- @param execPath string
|
||||||
func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.CheckNArgs(3); err != nil {
|
if err := c.CheckNArgs(3); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -402,6 +447,10 @@ func (j *jobHandler) luaAddJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.UserDataValue(jb.ud)), nil
|
return c.PushingNext1(t.Runtime, rt.UserDataValue(jb.ud)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// all() -> table<@Job>
|
||||||
|
// Returns a table of all job objects.
|
||||||
|
// --- @returns table<Job>
|
||||||
func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
j.mu.RLock()
|
j.mu.RLock()
|
||||||
defer j.mu.RUnlock()
|
defer j.mu.RUnlock()
|
||||||
|
@ -414,6 +463,10 @@ func (j *jobHandler) luaAllJobs(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil
|
return c.PushingNext1(t.Runtime, rt.TableValue(jobTbl)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// disown(id)
|
||||||
|
// Disowns a job. This deletes it from the job table.
|
||||||
|
// --- @param id number
|
||||||
func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaDisownJob(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
|
||||||
|
@ -431,6 +484,10 @@ func (j *jobHandler) luaDisownJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface jobs
|
||||||
|
// last() -> @Job
|
||||||
|
// Returns the last added job from the table.
|
||||||
|
// --- @returns Job
|
||||||
func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (j *jobHandler) luaLastJob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
j.mu.RLock()
|
j.mu.RLock()
|
||||||
defer j.mu.RUnlock()
|
defer j.mu.RUnlock()
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 8467b87dd8d49c68b4100b2d129d5f071544b8cf
|
Subproject commit 34a57c964590f89aa065188a588c7b38aff99c28
|
3
lua.go
3
lua.go
|
@ -23,6 +23,7 @@ func luaInit() {
|
||||||
MessageHandler: debuglib.Traceback,
|
MessageHandler: debuglib.Traceback,
|
||||||
})
|
})
|
||||||
lib.LoadAll(l)
|
lib.LoadAll(l)
|
||||||
|
setupSinkType(l)
|
||||||
|
|
||||||
lib.LoadLibs(l, hilbishLoader)
|
lib.LoadLibs(l, hilbishLoader)
|
||||||
// yes this is stupid, i know
|
// yes this is stupid, i know
|
||||||
|
@ -49,7 +50,7 @@ func luaInit() {
|
||||||
|
|
||||||
hooks = bait.New(l)
|
hooks = bait.New(l)
|
||||||
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
|
hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) {
|
||||||
fmt.Println("Error in", event, "event:", err)
|
fmt.Println("Error in `error` hook handler:", err)
|
||||||
hooks.Off(event, handler)
|
hooks.Off(event, handler)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
11
main.go
11
main.go
|
@ -115,9 +115,11 @@ func main() {
|
||||||
os.Setenv("SHELL", os.Args[0])
|
os.Setenv("SHELL", os.Args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
go handleSignals()
|
|
||||||
lr = newLineReader("", false)
|
lr = newLineReader("", false)
|
||||||
luaInit()
|
luaInit()
|
||||||
|
|
||||||
|
go handleSignals()
|
||||||
|
|
||||||
// If user's config doesn't exixt,
|
// If user's config doesn't exixt,
|
||||||
if _, err := os.Stat(defaultConfPath); os.IsNotExist(err) && *configflag == defaultConfPath {
|
if _, err := os.Stat(defaultConfPath); os.IsNotExist(err) && *configflag == defaultConfPath {
|
||||||
// Read default from current directory
|
// Read default from current directory
|
||||||
|
@ -181,11 +183,14 @@ input:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err != readline.CtrlC {
|
if err == readline.CtrlC {
|
||||||
|
fmt.Println("^C")
|
||||||
|
hooks.Emit("hilbish.cancel")
|
||||||
|
} else {
|
||||||
// If we get a completely random error, print
|
// If we get a completely random error, print
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
}
|
}
|
||||||
fmt.Println("^C")
|
// TODO: Halt if any other error occurs
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
var priv bool
|
var priv bool
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
|
|
||||||
commander.register('bg', function()
|
commander.register('bg', function(_, sinks)
|
||||||
local job = hilbish.jobs.last()
|
local job = hilbish.jobs.last()
|
||||||
if not job then
|
if not job then
|
||||||
print 'bg: no last job'
|
sinks.out:writeln 'bg: no last job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local err = job.background()
|
local err = job:background()
|
||||||
if err then
|
if err then
|
||||||
print('bg: ' .. err)
|
sinks.out:writeln('bg: ' .. err)
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
local commander = require 'commander'
|
||||||
|
local fs = require 'fs'
|
||||||
|
|
||||||
|
commander.register('cat', function(args, sinks)
|
||||||
|
local exit = 0
|
||||||
|
|
||||||
|
if #args == 0 then
|
||||||
|
sinks.out:writeln [[
|
||||||
|
usage: cat [file]...]]
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, fName in ipairs(args) do
|
||||||
|
local f = io.open(fName)
|
||||||
|
if f == nil then
|
||||||
|
exit = 1
|
||||||
|
sinks.out:writeln(string.format('cat: %s: no such file or directory', fName))
|
||||||
|
goto continue
|
||||||
|
end
|
||||||
|
|
||||||
|
sinks.out:writeln(f:read '*a')
|
||||||
|
::continue::
|
||||||
|
end
|
||||||
|
io.flush()
|
||||||
|
return exit
|
||||||
|
end)
|
|
@ -4,32 +4,25 @@ local fs = require 'fs'
|
||||||
local dirs = require 'nature.dirs'
|
local dirs = require 'nature.dirs'
|
||||||
|
|
||||||
dirs.old = hilbish.cwd()
|
dirs.old = hilbish.cwd()
|
||||||
commander.register('cd', function (args)
|
commander.register('cd', function (args, sinks)
|
||||||
if #args > 1 then
|
if #args > 1 then
|
||||||
print("cd: too many arguments")
|
sinks.out:writeln("cd: too many arguments")
|
||||||
return 1
|
return 1
|
||||||
elseif #args > 0 then
|
|
||||||
local path = args[1]:gsub('$%$','\0'):gsub('${([%w_]+)}', os.getenv)
|
|
||||||
:gsub('$([%w_]+)', os.getenv):gsub('%z','$'):gsub('^%s*(.-)%s*$', '%1')
|
|
||||||
|
|
||||||
if path == '-' then
|
|
||||||
path = dirs.old
|
|
||||||
print(path)
|
|
||||||
end
|
|
||||||
dirs.setOld(hilbish.cwd())
|
|
||||||
dirs.push(path)
|
|
||||||
|
|
||||||
local ok, err = pcall(function() fs.cd(path) end)
|
|
||||||
if not ok then
|
|
||||||
print(err)
|
|
||||||
return 1
|
|
||||||
end
|
|
||||||
bait.throw('cd', path)
|
|
||||||
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
fs.cd(hilbish.home)
|
|
||||||
bait.throw('cd', hilbish.home)
|
|
||||||
|
|
||||||
dirs.push(hilbish.home)
|
local path = args[1] and args[1] or hilbish.home
|
||||||
|
if path == '-' then
|
||||||
|
path = dirs.old
|
||||||
|
sinks.out:writeln(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
dirs.setOld(hilbish.cwd())
|
||||||
|
dirs.push(path)
|
||||||
|
|
||||||
|
local ok, err = pcall(function() fs.cd(path) end)
|
||||||
|
if not ok then
|
||||||
|
sinks.out:writeln(err)
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
bait.throw('cd', path)
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -3,9 +3,9 @@ local fs = require 'fs'
|
||||||
local lunacolors = require 'lunacolors'
|
local lunacolors = require 'lunacolors'
|
||||||
local dirs = require 'nature.dirs'
|
local dirs = require 'nature.dirs'
|
||||||
|
|
||||||
commander.register('cdr', function(args)
|
commander.register('cdr', function(args, sinks)
|
||||||
if not args[1] then
|
if not args[1] then
|
||||||
print(lunacolors.format [[
|
sinks.out:writeln(lunacolors.format [[
|
||||||
cdr: change directory to one which has been recently visied
|
cdr: change directory to one which has been recently visied
|
||||||
|
|
||||||
usage: cdr <index>
|
usage: cdr <index>
|
||||||
|
@ -17,21 +17,21 @@ to get a list of recent directories, use {green}{underline}cdr list{reset}]])
|
||||||
if args[1] == 'list' then
|
if args[1] == 'list' then
|
||||||
local recentDirs = dirs.recentDirs
|
local recentDirs = dirs.recentDirs
|
||||||
if #recentDirs == 0 then
|
if #recentDirs == 0 then
|
||||||
print 'No directories have been visited.'
|
sinks.out:writeln 'No directories have been visited.'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
print(table.concat(recentDirs, '\n'))
|
sinks.out:writeln(table.concat(recentDirs, '\n'))
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local index = tonumber(args[1])
|
local index = tonumber(args[1])
|
||||||
if not index then
|
if not index then
|
||||||
print(string.format('Received %s as index, which isn\'t a number.', index))
|
sinks.out:writeln(string.format('Received %s as index, which isn\'t a number.', index))
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
if not dirs.recent(index) then
|
if not dirs.recent(index) then
|
||||||
print(string.format('No recent directory found at index %s.', index))
|
sinks.out:writeln(string.format('No recent directory found at index %s.', index))
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
local ansikit = require 'ansikit'
|
||||||
|
local commander = require 'commander'
|
||||||
|
|
||||||
|
commander.register('clear', function()
|
||||||
|
ansikit.clear(true)
|
||||||
|
ansikit.cursorTo(0, 0)
|
||||||
|
end)
|
|
@ -1,8 +1,8 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
|
|
||||||
commander.register('disown', function(args)
|
commander.register('disown', function(args, sinks)
|
||||||
if #hilbish.jobs.all() == 0 then
|
if #hilbish.jobs.all() == 0 then
|
||||||
print 'disown: no current job'
|
sinks.out:writeln 'disown: no current job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ commander.register('disown', function(args)
|
||||||
if #args < 0 then
|
if #args < 0 then
|
||||||
id = tonumber(args[1])
|
id = tonumber(args[1])
|
||||||
if not id then
|
if not id then
|
||||||
print 'disown: invalid id for job'
|
sinks.out:writeln 'disown: invalid id for job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -19,7 +19,7 @@ commander.register('disown', function(args)
|
||||||
|
|
||||||
local ok = pcall(hilbish.jobs.disown, id)
|
local ok = pcall(hilbish.jobs.disown, id)
|
||||||
if not ok then
|
if not ok then
|
||||||
print 'disown: job does not exist'
|
sinks.out:writeln 'disown: job does not exist'
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -2,94 +2,99 @@ local commander = require 'commander'
|
||||||
local fs = require 'fs'
|
local fs = require 'fs'
|
||||||
local lunacolors = require 'lunacolors'
|
local lunacolors = require 'lunacolors'
|
||||||
|
|
||||||
commander.register('doc', function(args)
|
commander.register('doc', function(args, sinks)
|
||||||
local moddocPath = hilbish.dataDir .. '/docs/'
|
local moddocPath = hilbish.dataDir .. '/docs/'
|
||||||
local modDocFormat = [[
|
local stat = pcall(fs.stat, '.git/refs/heads/extended-job-api')
|
||||||
%s
|
if stat then
|
||||||
%s
|
-- hilbish git
|
||||||
# Functions
|
moddocPath = './docs/'
|
||||||
|
end
|
||||||
|
local apidocHeader = [[
|
||||||
|
# %s
|
||||||
|
{grayBg} {white}{italic}%s {reset}
|
||||||
|
|
||||||
]]
|
]]
|
||||||
|
|
||||||
|
local modules = table.map(fs.readdir(moddocPath), function(f)
|
||||||
|
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.md', '')))
|
||||||
|
end)
|
||||||
|
local doc = [[
|
||||||
|
Welcome to Hilbish's documentation viewer! Here you can find
|
||||||
|
documentation for builtin functions and other things related
|
||||||
|
to Hilbish.
|
||||||
|
|
||||||
|
Usage: doc <section> [subdoc]
|
||||||
|
Available sections: ]] .. table.concat(modules, ', ')
|
||||||
if #args > 0 then
|
if #args > 0 then
|
||||||
local mod = args[1]
|
local mod = args[1]
|
||||||
|
|
||||||
local f = io.open(moddocPath .. mod .. '.txt', 'rb')
|
local f = io.open(moddocPath .. mod .. '.md', 'rb')
|
||||||
local funcdocs = nil
|
local funcdocs = nil
|
||||||
|
local subdocName = args[2]
|
||||||
if not f then
|
if not f then
|
||||||
-- assume subdir
|
-- assume subdir
|
||||||
-- dataDir/docs/<mod>/<mod>.txt
|
-- dataDir/docs/<mod>/<mod>.md
|
||||||
moddocPath = moddocPath .. mod .. '/'
|
moddocPath = moddocPath .. mod .. '/'
|
||||||
local subdocName = args[2]
|
|
||||||
if not subdocName then
|
if not subdocName then
|
||||||
subdocName = 'index'
|
subdocName = '_index'
|
||||||
end
|
end
|
||||||
f = io.open(moddocPath .. subdocName .. '.txt', 'rb')
|
f = io.open(moddocPath .. subdocName .. '.md', 'rb')
|
||||||
if not f then
|
if not f then
|
||||||
print('No documentation found for ' .. mod .. '.')
|
f = io.open(moddocPath .. subdocName:match '%w+' .. '/' .. subdocName .. '.md', 'rb')
|
||||||
return
|
|
||||||
end
|
end
|
||||||
funcdocs = f:read '*a'
|
if not f then
|
||||||
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= 'index.txt' end)
|
moddocPath = moddocPath .. subdocName .. '/'
|
||||||
local subdocs = table.map(moddocs, function(fname)
|
subdocName = args[3] or '_index'
|
||||||
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.txt', '')))
|
f = io.open(moddocPath .. subdocName .. '.md', 'rb')
|
||||||
end)
|
|
||||||
if subdocName == 'index' then
|
|
||||||
funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ')
|
|
||||||
end
|
end
|
||||||
|
if not f then
|
||||||
|
sinks.out:writeln('No documentation found for ' .. mod .. '.')
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
funcdocs = f:read '*a':gsub('-([%d]+)', '%1')
|
||||||
|
local moddocs = table.filter(fs.readdir(moddocPath), function(f) return f ~= '_index.md' and f ~= 'index.md' end)
|
||||||
|
local subdocs = table.map(moddocs, function(fname)
|
||||||
|
return lunacolors.underline(lunacolors.blue(string.gsub(fname, '.md', '')))
|
||||||
|
end)
|
||||||
|
if #moddocs ~= 0 then
|
||||||
|
funcdocs = funcdocs .. '\nSubdocs: ' .. table.concat(subdocs, ', ')
|
||||||
end
|
end
|
||||||
|
|
||||||
if not funcdocs then
|
local valsStr = funcdocs:match '%-%-%-\n([^%-%-%-]+)\n'
|
||||||
funcdocs = f:read '*a'
|
local vals = {}
|
||||||
end
|
if valsStr then
|
||||||
local desc = ''
|
local _, endpos = funcdocs:find('---\n' .. valsStr .. '\n---\n\n', 1, true)
|
||||||
local ok = pcall(require, mod)
|
funcdocs = funcdocs:sub(endpos + 1, #funcdocs)
|
||||||
local backtickOccurence = 0
|
|
||||||
local formattedFuncs = lunacolors.format(funcdocs:sub(1, #funcdocs - 1):gsub('`', function()
|
|
||||||
backtickOccurence = backtickOccurence + 1
|
|
||||||
if backtickOccurence % 2 == 0 then
|
|
||||||
return '{reset}'
|
|
||||||
else
|
|
||||||
return '{underline}{green}'
|
|
||||||
end
|
|
||||||
end))
|
|
||||||
|
|
||||||
if ok then
|
-- parse vals
|
||||||
local props = {}
|
local lines = string.split(valsStr, '\n')
|
||||||
local propstr = ''
|
for _, line in ipairs(lines) do
|
||||||
local modDesc = ''
|
local key = line:match '(%w+): '
|
||||||
local modmt = getmetatable(require(mod))
|
local val = line:match '^%w+: (.-)$'
|
||||||
if modmt then
|
|
||||||
modDesc = modmt.__doc
|
if key then
|
||||||
if modmt.__docProp then
|
vals[key] = val
|
||||||
-- not all modules have docs for properties
|
|
||||||
props = table.map(modmt.__docProp, function(v, k)
|
|
||||||
return lunacolors.underline(lunacolors.blue(k)) .. ' > ' .. v
|
|
||||||
end)
|
|
||||||
end
|
end
|
||||||
if #props > 0 then
|
|
||||||
propstr = '\n# Properties\n' .. table.concat(props, '\n') .. '\n'
|
|
||||||
end
|
|
||||||
desc = string.format(modDocFormat, modDesc, propstr)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
print(desc .. formattedFuncs)
|
if mod == 'api' then
|
||||||
|
funcdocs = string.format(apidocHeader, vals.title, vals.description or 'no description.') .. funcdocs
|
||||||
|
end
|
||||||
|
doc = funcdocs:sub(1, #funcdocs - 1)
|
||||||
f:close()
|
f:close()
|
||||||
|
|
||||||
return
|
|
||||||
end
|
end
|
||||||
local modules = table.map(fs.readdir(moddocPath), function(f)
|
|
||||||
return lunacolors.underline(lunacolors.blue(string.gsub(f, '.txt', '')))
|
|
||||||
end)
|
|
||||||
|
|
||||||
io.write [[
|
local backtickOccurence = 0
|
||||||
Welcome to Hilbish's doc tool! Here you can find documentation for builtin
|
sinks.out:writeln(lunacolors.format(doc:gsub('`', function()
|
||||||
functions and other things.
|
backtickOccurence = backtickOccurence + 1
|
||||||
|
if backtickOccurence % 2 == 0 then
|
||||||
Usage: doc <section> [subdoc]
|
return '{reset}'
|
||||||
A section is a module or a literal section and a subdoc is a subsection for it.
|
else
|
||||||
|
return '{underline}{green}'
|
||||||
Available sections: ]]
|
end
|
||||||
io.flush()
|
end):gsub('\n#+.-\n', function(t)
|
||||||
|
local signature = t:gsub('<.->(.-)</.->', '{underline}%1'):gsub('\\', '<')
|
||||||
print(table.concat(modules, ', '))
|
return '{bold}{yellow}' .. signature .. '{reset}'
|
||||||
|
end)))
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
local commander = require 'commander'
|
||||||
|
|
||||||
|
commander.register('exec', function(args)
|
||||||
|
hilbish.exec(args[1])
|
||||||
|
end)
|
|
@ -1,15 +1,15 @@
|
||||||
local commander = require 'commander'
|
local commander = require 'commander'
|
||||||
|
|
||||||
commander.register('fg', function()
|
commander.register('fg', function(_, sinks)
|
||||||
local job = hilbish.jobs.last()
|
local job = hilbish.jobs.last()
|
||||||
if not job then
|
if not job then
|
||||||
print 'fg: no last job'
|
sinks.out:writeln 'fg: no last job'
|
||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local err = job.foreground() -- waits for job; blocks
|
local err = job:foreground() -- waits for job; blocks
|
||||||
if err then
|
if err then
|
||||||
print('fg: ' .. err)
|
sinks.out:writeln('fg: ' .. err)
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -24,7 +24,7 @@ function hilbish.completion.handler(line, pos)
|
||||||
return {compGroup}, pfx
|
return {compGroup}, pfx
|
||||||
else
|
else
|
||||||
local ok, compGroups, pfx = pcall(hilbish.completion.call,
|
local ok, compGroups, pfx = pcall(hilbish.completion.call,
|
||||||
'command.' .. #fields[1], query, ctx, fields)
|
'command.' .. fields[1], query, ctx, fields)
|
||||||
if ok then
|
if ok then
|
||||||
return compGroups, pfx
|
return compGroups, pfx
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
-- Prelude initializes everything else for our shell
|
-- Prelude initializes everything else for our shell
|
||||||
local _ = require 'succulent' -- Function additions
|
local _ = require 'succulent' -- Function additions
|
||||||
|
local bait = require 'bait'
|
||||||
local fs = require 'fs'
|
local fs = require 'fs'
|
||||||
|
|
||||||
package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua'
|
package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua'
|
||||||
|
@ -28,7 +29,9 @@ do
|
||||||
return got_virt
|
return got_virt
|
||||||
end
|
end
|
||||||
|
|
||||||
virt_G[key] = os.getenv(key)
|
if type(key) == 'string' then
|
||||||
|
virt_G[key] = os.getenv(key)
|
||||||
|
end
|
||||||
return virt_G[key]
|
return virt_G[key]
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
@ -54,7 +57,6 @@ do
|
||||||
if ok then
|
if ok then
|
||||||
for _, module in ipairs(modules) do
|
for _, module in ipairs(modules) do
|
||||||
local entry = package.searchpath(module, startSearchPath)
|
local entry = package.searchpath(module, startSearchPath)
|
||||||
print(entry)
|
|
||||||
if entry then
|
if entry then
|
||||||
dofile(entry)
|
dofile(entry)
|
||||||
end
|
end
|
||||||
|
@ -63,3 +65,15 @@ do
|
||||||
|
|
||||||
package.path = package.path .. ';' .. startSearchPath
|
package.path = package.path .. ';' .. startSearchPath
|
||||||
end
|
end
|
||||||
|
|
||||||
|
bait.catch('error', function(event, handler, err)
|
||||||
|
print(string.format('Encountered an error in %s handler\n%s', event, err:sub(8)))
|
||||||
|
end)
|
||||||
|
|
||||||
|
bait.catch('command.not-found', function(cmd)
|
||||||
|
print(string.format('hilbish: %s not found', cmd))
|
||||||
|
end)
|
||||||
|
|
||||||
|
bait.catch('command.not-executable', function(cmd)
|
||||||
|
print(string.format('hilbish: %s: not executable', cmd))
|
||||||
|
end)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
local bait = require 'bait'
|
local bait = require 'bait'
|
||||||
|
|
||||||
bait.catch('command.exit', function(_, cmd, priv)
|
bait.catch('command.exit', function(_, cmd, priv)
|
||||||
|
if not cmd then return end
|
||||||
if not priv and hilbish.opts.history then hilbish.history.add(cmd) end
|
if not priv and hilbish.opts.history then hilbish.history.add(cmd) end
|
||||||
end)
|
end)
|
||||||
|
|
|
@ -2,8 +2,8 @@ local bait = require 'bait'
|
||||||
local lunacolors = require 'lunacolors'
|
local lunacolors = require 'lunacolors'
|
||||||
|
|
||||||
hilbish.motd = [[
|
hilbish.motd = [[
|
||||||
Hilbish 2.0 is a {red}major{reset} update! If your config doesn't work
|
1000 commits on the Hilbish repository brings us to {cyan}Version 2.1!{reset}
|
||||||
anymore, that will definitely be why! A MOTD, very message, much day.
|
Docs, docs, docs... At least builtins work with pipes now.
|
||||||
]]
|
]]
|
||||||
|
|
||||||
bait.catch('hilbish.init', function()
|
bait.catch('hilbish.init', function()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
--- hilbish.runner
|
||||||
local currentRunner = 'hybrid'
|
local currentRunner = 'hybrid'
|
||||||
local runners = {}
|
local runners = {}
|
||||||
|
|
||||||
|
@ -74,6 +75,12 @@ function hilbish.runner.setCurrent(name)
|
||||||
hilbish.runner.setMode(r.run)
|
hilbish.runner.setMode(r.run)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- Returns the current runner by name.
|
||||||
|
--- @returns string
|
||||||
|
function hilbish.runner.getCurrent()
|
||||||
|
return currentRunner
|
||||||
|
end
|
||||||
|
|
||||||
hilbish.runner.add('hybrid', function(input)
|
hilbish.runner.add('hybrid', function(input)
|
||||||
local cmdStr = hilbish.aliases.resolve(input)
|
local cmdStr = hilbish.aliases.resolve(input)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
"github.com/blackfireio/osinfo"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #interface os
|
||||||
|
// OS Info
|
||||||
|
// The `os` interface provides simple text information properties about
|
||||||
|
// the current OS on the systen. This mainly includes the name and
|
||||||
|
// version.
|
||||||
|
// #field family Family name of the current OS
|
||||||
|
// #field name Pretty name of the current OS
|
||||||
|
// #field version Version of the current OS
|
||||||
|
func hshosLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
|
info, _ := osinfo.GetOSInfo()
|
||||||
|
mod := rt.NewTable()
|
||||||
|
|
||||||
|
util.SetField(rtm, mod, "family", rt.StringValue(info.Family))
|
||||||
|
util.SetField(rtm, mod, "name", rt.StringValue(info.Name))
|
||||||
|
util.SetField(rtm, mod, "version", rt.StringValue(info.Version))
|
||||||
|
|
||||||
|
return mod
|
||||||
|
}
|
|
@ -4,7 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
"github.com/rivo/uniseg"
|
||||||
|
)
|
||||||
|
|
||||||
// initGrid - Grid display details. Called each time we want to be sure to have
|
// initGrid - Grid display details. Called each time we want to be sure to have
|
||||||
// a working completion group either immediately, or later on. Generally defered.
|
// a working completion group either immediately, or later on. Generally defered.
|
||||||
|
@ -13,8 +14,8 @@ func (g *CompletionGroup) initGrid(rl *Instance) {
|
||||||
// Compute size of each completion item box
|
// Compute size of each completion item box
|
||||||
tcMaxLength := 1
|
tcMaxLength := 1
|
||||||
for i := range g.Suggestions {
|
for i := range g.Suggestions {
|
||||||
if len(g.Suggestions[i]) > tcMaxLength {
|
if uniseg.GraphemeClusterCount(g.Suggestions[i]) > tcMaxLength {
|
||||||
tcMaxLength = len([]rune(g.Suggestions[i]))
|
tcMaxLength = uniseg.GraphemeClusterCount(g.Suggestions[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ func (g *CompletionGroup) writeGrid(rl *Instance) (comp string) {
|
||||||
rl.tcUsedY++
|
rl.tcUsedY++
|
||||||
}
|
}
|
||||||
|
|
||||||
cellWidth := strconv.Itoa((GetTermWidth() / g.tcMaxX) - 2)
|
cellWidth := strconv.Itoa((GetTermWidth() / g.tcMaxX) - 4)
|
||||||
x := 0
|
x := 0
|
||||||
y := 1
|
y := 1
|
||||||
|
|
||||||
|
@ -124,7 +125,15 @@ func (g *CompletionGroup) writeGrid(rl *Instance) (comp string) {
|
||||||
comp += seqInvert
|
comp += seqInvert
|
||||||
}
|
}
|
||||||
|
|
||||||
comp += fmt.Sprintf("%-"+cellWidth+"s %s", fmtEscape(g.Suggestions[i]), seqReset)
|
sugg := g.Suggestions[i]
|
||||||
|
if len(sugg) > GetTermWidth() {
|
||||||
|
sugg = sugg[:GetTermWidth() - 4] + "..."
|
||||||
|
}
|
||||||
|
formatStr := "%-"+cellWidth+"s%s "
|
||||||
|
if g.tcMaxX == 1 {
|
||||||
|
formatStr = "%s%s"
|
||||||
|
}
|
||||||
|
comp += fmt.Sprintf(formatStr, fmtEscape(sugg), seqReset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always add a newline to the group if the end if not punctuated with one
|
// Always add a newline to the group if the end if not punctuated with one
|
||||||
|
|
|
@ -123,23 +123,20 @@ func (rl *Instance) walkHistory(i int) {
|
||||||
|
|
||||||
// When we are exiting the current line buffer to move around
|
// When we are exiting the current line buffer to move around
|
||||||
// the history, we make buffer the current line
|
// the history, we make buffer the current line
|
||||||
if rl.histPos == 0 && (rl.histPos+i) == 1 {
|
if rl.histOffset == 0 && rl.histOffset + i == 1 {
|
||||||
rl.lineBuf = string(rl.line)
|
rl.lineBuf = string(rl.line)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch rl.histPos + i {
|
rl.histOffset += i
|
||||||
case 0, history.Len() + 1:
|
if rl.histOffset == 0 {
|
||||||
rl.histPos = 0
|
|
||||||
rl.line = []rune(rl.lineBuf)
|
rl.line = []rune(rl.lineBuf)
|
||||||
rl.pos = len(rl.lineBuf)
|
rl.pos = len(rl.lineBuf)
|
||||||
return
|
} else if rl.histOffset <= -1 {
|
||||||
case -1:
|
rl.histOffset = 0
|
||||||
rl.histPos = 0
|
} else {
|
||||||
rl.lineBuf = string(rl.line)
|
|
||||||
default:
|
|
||||||
dedup = true
|
dedup = true
|
||||||
old = string(rl.line)
|
old = string(rl.line)
|
||||||
new, err = history.GetLine(history.Len() - rl.histPos - 1)
|
new, err = history.GetLine(history.Len() - rl.histOffset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rl.resetHelpers()
|
rl.resetHelpers()
|
||||||
print("\r\n" + err.Error() + "\r\n")
|
print("\r\n" + err.Error() + "\r\n")
|
||||||
|
@ -148,7 +145,6 @@ func (rl *Instance) walkHistory(i int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
rl.clearLine()
|
rl.clearLine()
|
||||||
rl.histPos += i
|
|
||||||
rl.line = []rune(new)
|
rl.line = []rune(new)
|
||||||
rl.pos = len(rl.line)
|
rl.pos = len(rl.line)
|
||||||
if rl.pos > 0 {
|
if rl.pos > 0 {
|
||||||
|
|
|
@ -134,6 +134,7 @@ type Instance struct {
|
||||||
// history operating params
|
// history operating params
|
||||||
lineBuf string
|
lineBuf string
|
||||||
histPos int
|
histPos int
|
||||||
|
histOffset int
|
||||||
histNavIdx int // Used for quick history navigation.
|
histNavIdx int // Used for quick history navigation.
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -49,7 +49,7 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
|
|
||||||
// History Init
|
// History Init
|
||||||
// We need this set to the last command, so that we can access it quickly
|
// We need this set to the last command, so that we can access it quickly
|
||||||
rl.histPos = 0
|
rl.histOffset = 0
|
||||||
rl.viUndoHistory = []undoItem{{line: "", pos: 0}}
|
rl.viUndoHistory = []undoItem{{line: "", pos: 0}}
|
||||||
|
|
||||||
// Multisplit
|
// Multisplit
|
||||||
|
@ -238,7 +238,9 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
|
|
||||||
// Normal completion search does only refresh the search pattern and the comps
|
// Normal completion search does only refresh the search pattern and the comps
|
||||||
if rl.modeTabFind || rl.modeAutoFind {
|
if rl.modeTabFind || rl.modeAutoFind {
|
||||||
|
rl.resetVirtualComp(false)
|
||||||
rl.backspaceTabFind()
|
rl.backspaceTabFind()
|
||||||
|
rl.renderHelpers()
|
||||||
rl.viUndoSkipAppend = true
|
rl.viUndoSkipAppend = true
|
||||||
} else {
|
} else {
|
||||||
// Always cancel any virtual completion
|
// Always cancel any virtual completion
|
||||||
|
@ -331,6 +333,8 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
|
|
||||||
rl.modeTabFind = true
|
rl.modeTabFind = true
|
||||||
rl.updateTabFind([]rune{})
|
rl.updateTabFind([]rune{})
|
||||||
|
rl.updateVirtualComp()
|
||||||
|
rl.renderHelpers()
|
||||||
rl.viUndoSkipAppend = true
|
rl.viUndoSkipAppend = true
|
||||||
|
|
||||||
// Tab Completion & Completion Search ---------------------------------------------------------------
|
// Tab Completion & Completion Search ---------------------------------------------------------------
|
||||||
|
@ -484,7 +488,10 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
if string(r[:i]) != seqShiftTab &&
|
if string(r[:i]) != seqShiftTab &&
|
||||||
string(r[:i]) != seqForwards && string(r[:i]) != seqBackwards &&
|
string(r[:i]) != seqForwards && string(r[:i]) != seqBackwards &&
|
||||||
string(r[:i]) != seqUp && string(r[:i]) != seqDown {
|
string(r[:i]) != seqUp && string(r[:i]) != seqDown {
|
||||||
rl.resetVirtualComp(false)
|
// basically only applies except on 1st ctrl r open
|
||||||
|
// so if we have not explicitly selected something
|
||||||
|
// (tabCompletionSelect is false) drop virtual completion
|
||||||
|
rl.resetVirtualComp(!rl.tabCompletionSelect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,7 +524,9 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
if rl.modeAutoFind || rl.modeTabFind {
|
if rl.modeAutoFind || rl.modeTabFind {
|
||||||
rl.resetVirtualComp(false)
|
rl.resetVirtualComp(false)
|
||||||
rl.updateTabFind(r[:i])
|
rl.updateTabFind(r[:i])
|
||||||
|
rl.renderHelpers()
|
||||||
rl.viUndoSkipAppend = true
|
rl.viUndoSkipAppend = true
|
||||||
|
continue
|
||||||
} else {
|
} else {
|
||||||
rl.resetVirtualComp(false)
|
rl.resetVirtualComp(false)
|
||||||
rl.editorInput(r[:i])
|
rl.editorInput(r[:i])
|
||||||
|
@ -537,6 +546,10 @@ func (rl *Instance) Readline() (string, error) {
|
||||||
// entry readline is currently configured for and then update the line entries
|
// entry readline is currently configured for and then update the line entries
|
||||||
// accordingly.
|
// accordingly.
|
||||||
func (rl *Instance) editorInput(r []rune) {
|
func (rl *Instance) editorInput(r []rune) {
|
||||||
|
if len(r) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch rl.modeViMode {
|
switch rl.modeViMode {
|
||||||
case VimKeys:
|
case VimKeys:
|
||||||
rl.vi(r[0])
|
rl.vi(r[0])
|
||||||
|
@ -604,6 +617,7 @@ func (rl *Instance) escapeSeq(r []rune) {
|
||||||
case string(charEscape):
|
case string(charEscape):
|
||||||
switch {
|
switch {
|
||||||
case rl.modeAutoFind:
|
case rl.modeAutoFind:
|
||||||
|
rl.resetVirtualComp(true)
|
||||||
rl.resetTabFind()
|
rl.resetTabFind()
|
||||||
rl.clearHelpers()
|
rl.clearHelpers()
|
||||||
rl.resetTabCompletion()
|
rl.resetTabCompletion()
|
||||||
|
@ -611,6 +625,7 @@ func (rl *Instance) escapeSeq(r []rune) {
|
||||||
rl.renderHelpers()
|
rl.renderHelpers()
|
||||||
|
|
||||||
case rl.modeTabFind:
|
case rl.modeTabFind:
|
||||||
|
rl.resetVirtualComp(true)
|
||||||
rl.resetTabFind()
|
rl.resetTabFind()
|
||||||
rl.resetTabCompletion()
|
rl.resetTabCompletion()
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package readline
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
"github.com/rivo/uniseg"
|
||||||
)
|
)
|
||||||
|
|
||||||
// insertCandidateVirtual - When a completion candidate is selected, we insert it virtually in the input line:
|
// insertCandidateVirtual - When a completion candidate is selected, we insert it virtually in the input line:
|
||||||
|
@ -249,10 +250,10 @@ func (rl *Instance) viJumpEVirtual(tokeniser func([]rune, int) ([]string, int, i
|
||||||
return
|
return
|
||||||
case pos >= len(word)-1:
|
case pos >= len(word)-1:
|
||||||
word = rTrimWhiteSpace(split[index+1])
|
word = rTrimWhiteSpace(split[index+1])
|
||||||
adjust = len(split[index]) - pos
|
adjust = uniseg.GraphemeClusterCount(split[index]) - pos
|
||||||
adjust += len(word) - 1
|
adjust += uniseg.GraphemeClusterCount(word) - 1
|
||||||
default:
|
default:
|
||||||
adjust = len(word) - pos - 1
|
adjust = uniseg.GraphemeClusterCount(word) - pos - 1
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
package readline
|
package readline
|
||||||
|
|
||||||
import "golang.org/x/text/width"
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/text/width"
|
||||||
|
)
|
||||||
|
|
||||||
// updateHelpers is a key part of the whole refresh process:
|
// updateHelpers is a key part of the whole refresh process:
|
||||||
// it should coordinate reprinting the input line, any Infos and completions
|
// it should coordinate reprinting the input line, any Infos and completions
|
||||||
|
@ -52,19 +56,19 @@ func (rl *Instance) updateReferences() {
|
||||||
rl.posY = 0
|
rl.posY = 0
|
||||||
rl.fullY = 0
|
rl.fullY = 0
|
||||||
|
|
||||||
var fullLine, cPosLine int
|
var curLine []rune
|
||||||
if len(rl.currentComp) > 0 {
|
if len(rl.currentComp) > 0 {
|
||||||
fullLine = getWidth(rl.lineComp)
|
curLine = rl.lineComp
|
||||||
cPosLine = getWidth(rl.lineComp[:rl.pos])
|
|
||||||
} else {
|
} else {
|
||||||
fullLine = getWidth(rl.line)
|
curLine = rl.line
|
||||||
cPosLine = getWidth(rl.line[:rl.pos])
|
|
||||||
}
|
}
|
||||||
|
fullLine := getWidth(curLine)
|
||||||
|
cPosLine := getWidth(curLine[:rl.pos])
|
||||||
|
|
||||||
// We need the X offset of the whole line
|
// We need the X offset of the whole line
|
||||||
toEndLine := rl.promptLen + fullLine
|
toEndLine := rl.promptLen + fullLine
|
||||||
fullOffset := toEndLine / GetTermWidth()
|
fullOffset := toEndLine / GetTermWidth()
|
||||||
rl.fullY = fullOffset
|
rl.fullY = fullOffset + strings.Count(string(curLine), "\n")
|
||||||
fullRest := toEndLine % GetTermWidth()
|
fullRest := toEndLine % GetTermWidth()
|
||||||
rl.fullX = fullRest
|
rl.fullX = fullRest
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,7 @@ func (rl *Instance) vi(r rune) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep the previous cursor position
|
// Keep the previous cursor position
|
||||||
prev := rl.pos
|
//prev := rl.pos
|
||||||
|
|
||||||
new, err := rl.StartEditorWithBuffer(multiline, "")
|
new, err := rl.StartEditorWithBuffer(multiline, "")
|
||||||
if err != nil || len(new) == 0 || string(new) == string(multiline) {
|
if err != nil || len(new) == 0 || string(new) == string(multiline) {
|
||||||
|
@ -257,11 +257,11 @@ func (rl *Instance) vi(r rune) {
|
||||||
// Clean the shell and put the new buffer, with adjusted pos if needed.
|
// Clean the shell and put the new buffer, with adjusted pos if needed.
|
||||||
rl.clearLine()
|
rl.clearLine()
|
||||||
rl.line = new
|
rl.line = new
|
||||||
if prev > len(rl.line) {
|
rl.pos = len(rl.line)
|
||||||
rl.pos = len(rl.line) - 1
|
/*if prev > len(rl.line) {
|
||||||
} else {
|
} else {
|
||||||
rl.pos = prev
|
rl.pos = prev
|
||||||
}
|
}*/
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
// If we were not yanking
|
// If we were not yanking
|
||||||
|
|
25
rl.go
25
rl.go
|
@ -225,7 +225,11 @@ func (lr *lineReader) Resize() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// lua module
|
// #interface history
|
||||||
|
// command history
|
||||||
|
// The history interface deals with command history.
|
||||||
|
// This includes the ability to override functions to change the main
|
||||||
|
// method of saving history.
|
||||||
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
|
func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
|
||||||
lrLua := map[string]util.LuaExport{
|
lrLua := map[string]util.LuaExport{
|
||||||
"add": {lr.luaAddHistory, 1, false},
|
"add": {lr.luaAddHistory, 1, false},
|
||||||
|
@ -241,6 +245,10 @@ func (lr *lineReader) Loader(rtm *rt.Runtime) *rt.Table {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface history
|
||||||
|
// add(cmd)
|
||||||
|
// Adds a command to the history.
|
||||||
|
// --- @param cmd string
|
||||||
func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaAddHistory(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
|
||||||
|
@ -254,10 +262,18 @@ func (lr *lineReader) luaAddHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface history
|
||||||
|
// size() -> number
|
||||||
|
// Returns the amount of commands in the history.
|
||||||
|
// --- @returns number
|
||||||
func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaSize(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.IntValue(int64(lr.fileHist.Len()))), nil
|
return c.PushingNext1(t.Runtime, rt.IntValue(int64(lr.fileHist.Len()))), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface history
|
||||||
|
// get(idx)
|
||||||
|
// Retrieves a command from the history based on the `idx`.
|
||||||
|
// --- @param idx number
|
||||||
func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaGetHistory(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
|
||||||
|
@ -272,6 +288,10 @@ func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
|
||||||
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface history
|
||||||
|
// all() -> table
|
||||||
|
// Retrieves all history.
|
||||||
|
// --- @returns table
|
||||||
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
tbl := rt.NewTable()
|
tbl := rt.NewTable()
|
||||||
size := lr.fileHist.Len()
|
size := lr.fileHist.Len()
|
||||||
|
@ -284,6 +304,9 @@ func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error)
|
||||||
return c.PushingNext1(t.Runtime, rt.TableValue(tbl)), nil
|
return c.PushingNext1(t.Runtime, rt.TableValue(tbl)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface history
|
||||||
|
// clear()
|
||||||
|
// Deletes all commands from the history.
|
||||||
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
lr.fileHist.clear()
|
lr.fileHist.clear()
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
function git_short_hash {
|
||||||
|
short_hash="$(cached git_short_hash)"
|
||||||
|
|
||||||
|
if [ -z "$short_hash" ]; then
|
||||||
|
short_hash="$(git rev-parse --short HEAD)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
output "$short_hash"
|
||||||
|
}
|
||||||
|
|
||||||
|
function git_tag_version {
|
||||||
|
tag="$(cached git_tag_version)"
|
||||||
|
|
||||||
|
if [ -z "$tag" ]; then
|
||||||
|
tag="$(git describe --tags --abbrev=0)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the potential prefix of `v`
|
||||||
|
if [[ $tag =~ ^v[0-9].* ]]; then
|
||||||
|
tag="${tag:1}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
tag="${tag/"-"/"."}"
|
||||||
|
output "$tag"
|
||||||
|
}
|
|
@ -6,6 +6,13 @@ import (
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// #interface runner
|
||||||
|
// interactive command runner customization
|
||||||
|
// The runner interface contains functions that allow the user to change
|
||||||
|
// how Hilbish interprets interactive input.
|
||||||
|
// Users can add and change the default runner for interactive input to any
|
||||||
|
// language or script of their choosing. A good example is using it to
|
||||||
|
// write command in Fennel.
|
||||||
func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
|
func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
exports := map[string]util.LuaExport{
|
exports := map[string]util.LuaExport{
|
||||||
"sh": {shRunner, 1, false},
|
"sh": {shRunner, 1, false},
|
||||||
|
@ -19,6 +26,20 @@ func runnerModeLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
return mod
|
return mod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface runner
|
||||||
|
// setMode(cb)
|
||||||
|
// This is the same as the `hilbish.runnerMode` function. It takes a callback,
|
||||||
|
// which will be used to execute all interactive input.
|
||||||
|
// In normal cases, neither callbacks should be overrided by the user,
|
||||||
|
// as the higher level functions listed below this will handle it.
|
||||||
|
// --- @param cb function
|
||||||
|
func _runnerMode() {}
|
||||||
|
|
||||||
|
// #interface runner
|
||||||
|
// sh(cmd)
|
||||||
|
// Runs a command in Hilbish's shell script interpreter.
|
||||||
|
// This is the equivalent of using `source`.
|
||||||
|
// --- @param cmd string
|
||||||
func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func shRunner(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
|
||||||
|
@ -28,13 +49,13 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
input, exitCode, cont, err := execSh(cmd)
|
_, exitCode, cont, 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())
|
||||||
}
|
}
|
||||||
runnerRet := rt.NewTable()
|
runnerRet := rt.NewTable()
|
||||||
runnerRet.Set(rt.StringValue("input"), rt.StringValue(input))
|
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("err"), luaErr)
|
runnerRet.Set(rt.StringValue("err"), luaErr)
|
||||||
|
@ -42,6 +63,11 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil
|
return c.PushingNext(t.Runtime, rt.TableValue(runnerRet)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface runner
|
||||||
|
// lua(cmd)
|
||||||
|
// Evaluates `cmd` as Lua input. This is the same as using `dofile`
|
||||||
|
// or `load`, but is appropriated for the runner interface.
|
||||||
|
// --- @param cmd string
|
||||||
func luaRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func luaRunner(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
|
||||||
|
|
|
@ -0,0 +1,128 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var sinkMetaKey = rt.StringValue("hshsink")
|
||||||
|
|
||||||
|
// #type
|
||||||
|
// A sink is a structure that has input and/or output to/from
|
||||||
|
// a desination.
|
||||||
|
type sink struct{
|
||||||
|
writer io.Writer
|
||||||
|
reader io.Reader
|
||||||
|
ud *rt.UserData
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupSinkType(rtm *rt.Runtime) {
|
||||||
|
sinkMeta := rt.NewTable()
|
||||||
|
|
||||||
|
sinkMethods := rt.NewTable()
|
||||||
|
sinkFuncs := map[string]util.LuaExport{
|
||||||
|
"write": {luaSinkWrite, 2, false},
|
||||||
|
"writeln": {luaSinkWriteln, 2, false},
|
||||||
|
}
|
||||||
|
util.SetExports(l, sinkMethods, sinkFuncs)
|
||||||
|
|
||||||
|
sinkIndex := func(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
arg := c.Arg(1)
|
||||||
|
val := sinkMethods.Get(arg)
|
||||||
|
|
||||||
|
return c.PushingNext1(t.Runtime, val), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sinkMeta.Set(rt.StringValue("__index"), rt.FunctionValue(rt.NewGoFunction(sinkIndex, "__index", 2, false)))
|
||||||
|
l.SetRegistry(sinkMetaKey, rt.TableValue(sinkMeta))
|
||||||
|
}
|
||||||
|
|
||||||
|
// #member
|
||||||
|
// write(str)
|
||||||
|
// Writes data to a sink.
|
||||||
|
func luaSinkWrite(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := sinkArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.writer.Write([]byte(data))
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// #member
|
||||||
|
// writeln(str)
|
||||||
|
// Writes data to a sink with a newline at the end.
|
||||||
|
func luaSinkWriteln(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
|
if err := c.CheckNArgs(2); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := sinkArg(c, 0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := c.StringArg(1)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.writer.Write([]byte(data + "\n"))
|
||||||
|
|
||||||
|
return c.Next(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSinkInput(r io.Reader) *sink {
|
||||||
|
s := &sink{
|
||||||
|
reader: r,
|
||||||
|
}
|
||||||
|
s.ud = sinkUserData(s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func newSinkOutput(w io.Writer) *sink {
|
||||||
|
s := &sink{
|
||||||
|
writer: w,
|
||||||
|
}
|
||||||
|
s.ud = sinkUserData(s)
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func sinkArg(c *rt.GoCont, arg int) (*sink, error) {
|
||||||
|
s, ok := valueToSink(c.Arg(arg))
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("#%d must be a sink", arg + 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func valueToSink(val rt.Value) (*sink, bool) {
|
||||||
|
u, ok := val.TryUserData()
|
||||||
|
if !ok {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
s, ok := u.Value().(*sink)
|
||||||
|
return s, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func sinkUserData(s *sink) *rt.UserData {
|
||||||
|
sinkMeta := l.Registry(sinkMetaKey)
|
||||||
|
return rt.NewUserData(s, sinkMeta.AsTable())
|
||||||
|
}
|
16
timer.go
16
timer.go
|
@ -15,13 +15,19 @@ const (
|
||||||
timerTimeout
|
timerTimeout
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// #type
|
||||||
|
// #interface timers
|
||||||
|
// #property type What type of timer it is
|
||||||
|
// #property running If the timer is running
|
||||||
|
// #property duration The duration in milliseconds that the timer will run
|
||||||
|
// The Job type describes a Hilbish timer.
|
||||||
type timer struct{
|
type timer struct{
|
||||||
id int
|
id int
|
||||||
typ timerType
|
typ timerType
|
||||||
running bool
|
running bool
|
||||||
dur time.Duration
|
dur time.Duration
|
||||||
fun *rt.Closure
|
fun *rt.Closure
|
||||||
th *timerHandler
|
th *timersModule
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
ud *rt.UserData
|
ud *rt.UserData
|
||||||
channel chan struct{}
|
channel chan struct{}
|
||||||
|
@ -73,6 +79,10 @@ func (t *timer) stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface timers
|
||||||
|
// #member
|
||||||
|
// start()
|
||||||
|
// Starts a timer.
|
||||||
func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func timerStart(thr *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
|
||||||
|
@ -91,6 +101,10 @@ func timerStart(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #interface timers
|
||||||
|
// #member
|
||||||
|
// stop()
|
||||||
|
// Stops a timer.
|
||||||
func timerStop(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
func timerStop(thr *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
|
||||||
|
|
|
@ -10,10 +10,10 @@ import (
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
var timers *timerHandler
|
var timers *timersModule
|
||||||
var timerMetaKey = rt.StringValue("hshtimer")
|
var timerMetaKey = rt.StringValue("hshtimer")
|
||||||
|
|
||||||
type timerHandler struct {
|
type timersModule struct {
|
||||||
mu *sync.RWMutex
|
mu *sync.RWMutex
|
||||||
wg *sync.WaitGroup
|
wg *sync.WaitGroup
|
||||||
timers map[int]*timer
|
timers map[int]*timer
|
||||||
|
@ -21,8 +21,8 @@ type timerHandler struct {
|
||||||
running int
|
running int
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTimerHandler() *timerHandler {
|
func newTimersModule() *timersModule {
|
||||||
return &timerHandler{
|
return &timersModule{
|
||||||
timers: make(map[int]*timer),
|
timers: make(map[int]*timer),
|
||||||
latestID: 0,
|
latestID: 0,
|
||||||
mu: &sync.RWMutex{},
|
mu: &sync.RWMutex{},
|
||||||
|
@ -30,11 +30,11 @@ func newTimerHandler() *timerHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *timerHandler) wait() {
|
func (th *timersModule) wait() {
|
||||||
th.wg.Wait()
|
th.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *timerHandler) create(typ timerType, dur time.Duration, fun *rt.Closure) *timer {
|
func (th *timersModule) create(typ timerType, dur time.Duration, fun *rt.Closure) *timer {
|
||||||
th.mu.Lock()
|
th.mu.Lock()
|
||||||
defer th.mu.Unlock()
|
defer th.mu.Unlock()
|
||||||
|
|
||||||
|
@ -54,14 +54,21 @@ func (th *timerHandler) create(typ timerType, dur time.Duration, fun *rt.Closure
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *timerHandler) get(id int) *timer {
|
func (th *timersModule) get(id int) *timer {
|
||||||
th.mu.RLock()
|
th.mu.RLock()
|
||||||
defer th.mu.RUnlock()
|
defer th.mu.RUnlock()
|
||||||
|
|
||||||
return th.timers[id]
|
return th.timers[id]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *timerHandler) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
// #interface timers
|
||||||
|
// create(type, time, callback) -> @Timer
|
||||||
|
// Creates a timer that runs based on the specified `time` in milliseconds.
|
||||||
|
// The `type` can either be `hilbish.timers.INTERVAL` or `hilbish.timers.TIMEOUT`
|
||||||
|
// --- @param type number
|
||||||
|
// --- @param time number
|
||||||
|
// --- @param callback function
|
||||||
|
func (th *timersModule) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
if err := c.CheckNArgs(3); err != nil {
|
if err := c.CheckNArgs(3); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -83,7 +90,12 @@ func (th *timerHandler) luaCreate(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.PushingNext1(t.Runtime, rt.UserDataValue(tmr.ud)), nil
|
return c.PushingNext1(t.Runtime, rt.UserDataValue(tmr.ud)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *timerHandler) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
// #interface timers
|
||||||
|
// get(id) -> @Timer
|
||||||
|
// Retrieves a timer via its ID.
|
||||||
|
// --- @param id number
|
||||||
|
// --- @returns Timer
|
||||||
|
func (th *timersModule) luaGet(thr *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
|
||||||
}
|
}
|
||||||
|
@ -100,7 +112,34 @@ func (th *timerHandler) luaGet(thr *rt.Thread, c *rt.GoCont) (rt.Cont, error) {
|
||||||
return c.Next(), nil
|
return c.Next(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *timerHandler) loader(rtm *rt.Runtime) *rt.Table {
|
// #interface timers
|
||||||
|
// #field INTERVAL Constant for an interval timer type
|
||||||
|
// #field TIMEOUT Constant for a timeout timer type
|
||||||
|
// timeout and interval API
|
||||||
|
/*
|
||||||
|
If you ever want to run a piece of code on a timed interval, or want to wait
|
||||||
|
a few seconds, you don't have to rely on timing tricks, as Hilbish has a
|
||||||
|
timer API to set intervals and timeouts.
|
||||||
|
|
||||||
|
These are the simple functions `hilbish.interval` and `hilbish.timeout` (doc
|
||||||
|
accessible with `doc hilbish`). But if you want slightly more control over
|
||||||
|
them, there is the `hilbish.timers` interface. It allows you to get
|
||||||
|
a timer via ID and control them.
|
||||||
|
|
||||||
|
## Timer Object
|
||||||
|
All functions documented with the `Timer` type refer to a Timer object.
|
||||||
|
|
||||||
|
An example of usage:
|
||||||
|
```
|
||||||
|
local t = hilbish.timers.create(hilbish.timers.TIMEOUT, 5000, function()
|
||||||
|
print 'hello!'
|
||||||
|
end)
|
||||||
|
|
||||||
|
t:start()
|
||||||
|
print(t.running) // true
|
||||||
|
```
|
||||||
|
*/
|
||||||
|
func (th *timersModule) loader(rtm *rt.Runtime) *rt.Table {
|
||||||
timerMethods := rt.NewTable()
|
timerMethods := rt.NewTable()
|
||||||
timerFuncs := map[string]util.LuaExport{
|
timerFuncs := map[string]util.LuaExport{
|
||||||
"start": {timerStart, 1, false},
|
"start": {timerStart, 1, false},
|
||||||
|
@ -141,6 +180,9 @@ func (th *timerHandler) loader(rtm *rt.Runtime) *rt.Table {
|
||||||
luaTh := rt.NewTable()
|
luaTh := rt.NewTable()
|
||||||
util.SetExports(rtm, luaTh, thExports)
|
util.SetExports(rtm, luaTh, thExports)
|
||||||
|
|
||||||
|
util.SetField(rtm, luaTh, "INTERVAL", rt.IntValue(0))
|
||||||
|
util.SetField(rtm, luaTh, "TIMEOUT", rt.IntValue(1))
|
||||||
|
|
||||||
return luaTh
|
return luaTh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"hilbish/util"
|
||||||
|
|
||||||
|
rt "github.com/arnodel/golua/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
// #interface userDir
|
||||||
|
// user-related directories
|
||||||
|
// This interface just contains properties to know about certain user directories.
|
||||||
|
// It is equivalent to XDG on Linux and gets the user's preferred directories
|
||||||
|
// for configs and data.
|
||||||
|
// #field config The user's config directory
|
||||||
|
// #field data The user's directory for program data
|
||||||
|
func userDirLoader(rtm *rt.Runtime) *rt.Table {
|
||||||
|
mod := rt.NewTable()
|
||||||
|
|
||||||
|
util.SetField(rtm, mod, "config", rt.StringValue(confDir))
|
||||||
|
util.SetField(rtm, mod, "data", rt.StringValue(userDataDir))
|
||||||
|
|
||||||
|
return mod
|
||||||
|
}
|
39
util/util.go
39
util/util.go
|
@ -10,53 +10,18 @@ import (
|
||||||
rt "github.com/arnodel/golua/runtime"
|
rt "github.com/arnodel/golua/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Document adds a documentation string to a module.
|
|
||||||
// It is accessible via the __doc metatable.
|
|
||||||
func Document(module *rt.Table, doc string) {
|
|
||||||
mt := module.Metatable()
|
|
||||||
|
|
||||||
if mt == nil {
|
|
||||||
mt = rt.NewTable()
|
|
||||||
module.SetMetatable(mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
mt.Set(rt.StringValue("__doc"), rt.StringValue(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetField sets a field in a table, adding docs for it.
|
// SetField sets a field in a table, adding docs for it.
|
||||||
// It is accessible via the __docProp metatable. It is a table of the names of the fields.
|
// It is accessible via the __docProp metatable. It is a table of the names of the fields.
|
||||||
func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value, doc string) {
|
func SetField(rtm *rt.Runtime, module *rt.Table, field string, value rt.Value) {
|
||||||
// TODO: ^ rtm isnt needed, i should remove it
|
// TODO: ^ rtm isnt needed, i should remove it
|
||||||
SetFieldDoc(module, field, doc)
|
|
||||||
module.Set(rt.StringValue(field), value)
|
module.Set(rt.StringValue(field), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetFieldDoc sets the __docProp metatable for a field on the
|
|
||||||
// module.
|
|
||||||
func SetFieldDoc(module *rt.Table, field, doc string) {
|
|
||||||
mt := module.Metatable()
|
|
||||||
|
|
||||||
if mt == nil {
|
|
||||||
mt = rt.NewTable()
|
|
||||||
module.SetMetatable(mt)
|
|
||||||
}
|
|
||||||
|
|
||||||
docProp := mt.Get(rt.StringValue("__docProp"))
|
|
||||||
if docProp == rt.NilValue {
|
|
||||||
docPropTbl := rt.NewTable()
|
|
||||||
mt.Set(rt.StringValue("__docProp"), rt.TableValue(docPropTbl))
|
|
||||||
docProp = mt.Get(rt.StringValue("__docProp"))
|
|
||||||
}
|
|
||||||
|
|
||||||
docProp.AsTable().Set(rt.StringValue(field), rt.StringValue(doc))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetFieldProtected sets a field in a protected table. A protected table
|
// SetFieldProtected sets a field in a protected table. A protected table
|
||||||
// is one which has a metatable proxy to ensure no overrides happen to it.
|
// is one which has a metatable proxy to ensure no overrides happen to it.
|
||||||
// It sets the field in the table and sets the __docProp metatable on the
|
// It sets the field in the table and sets the __docProp metatable on the
|
||||||
// user facing table.
|
// user facing table.
|
||||||
func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Value, doc string) {
|
func SetFieldProtected(module, realModule *rt.Table, field string, value rt.Value) {
|
||||||
SetFieldDoc(module, field, doc)
|
|
||||||
realModule.Set(rt.StringValue(field), value)
|
realModule.Set(rt.StringValue(field), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
vars.go
4
vars.go
|
@ -11,8 +11,8 @@ var (
|
||||||
|
|
||||||
// Version info
|
// Version info
|
||||||
var (
|
var (
|
||||||
ver = "v2.0.0"
|
ver = "v2.2.0"
|
||||||
releaseName = "Hibiscus"
|
releaseName = "Poppy"
|
||||||
gitCommit string
|
gitCommit string
|
||||||
gitBranch string
|
gitBranch string
|
||||||
)
|
)
|
||||||
|
|
|
@ -14,7 +14,7 @@ var (
|
||||||
.. hilbish.userDir.config .. '/hilbish/?/init.lua;'
|
.. hilbish.userDir.config .. '/hilbish/?/init.lua;'
|
||||||
.. hilbish.userDir.config .. '/hilbish/?/?.lua;'
|
.. hilbish.userDir.config .. '/hilbish/?/?.lua;'
|
||||||
.. hilbish.userDir.config .. '/hilbish/?.lua'`
|
.. hilbish.userDir.config .. '/hilbish/?.lua'`
|
||||||
dataDir = "/usr/share/hilbish"
|
dataDir = "/usr/local/share/hilbish"
|
||||||
preloadPath = dataDir + "/nature/init.lua"
|
preloadPath = dataDir + "/nature/init.lua"
|
||||||
sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config
|
sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config
|
||||||
defaultConfDir = ""
|
defaultConfDir = ""
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue