mirror of
				https://github.com/sammy-ette/Hilbish
				synced 2025-08-10 02:52:03 +00:00 
			
		
		
		
	Compare commits
	
		
			88 Commits
		
	
	
		
			7af90eb1f1
			...
			aae70ff42e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| aae70ff42e | |||
| 5c748daaa3 | |||
| 7b3dc951c9 | |||
| 0a49e1a4ef | |||
|  | 6ca36847f1 | ||
|  | 5ca728ba06 | ||
| 813354b662 | |||
|  | 8d40179a73 | ||
|  | f7e725b5b9 | ||
| 4ee160fb66 | |||
|  | 1024f93446 | ||
|  | 9c8d7692bc | ||
|  | 9131c72501 | ||
|  | 26ff6c9a46 | ||
|  | 604dedb36d | ||
|  | 395f3c0742 | ||
|  | 0c44531a7f | ||
|  | 4e850bb322 | ||
|  | 09d04a7850 | ||
|  | 4df37b4341 | ||
|  | 5e2b3367de | ||
|  | b6aecb12f6 | ||
|  | 3f9b230381 | ||
|  | b395b70ecd | ||
|  | 06102ebdae | ||
|  | bd4e0df7b3 | ||
|  | ebec585690 | ||
|  | ff4609e432 | ||
|  | ef3e7d92bc | ||
|  | d6338fc021 | ||
|  | 3eaeb6a5da | ||
|  | 8b547f2af0 | ||
|  | 1febe66f84 | ||
|  | 6ffcc498ac | ||
|  | fe47c6c7a1 | ||
|  | 0d32a10ca3 | ||
|  | cc6e5d01dd | ||
|  | 068a5b5149 | ||
|  | 117a4580b4 | ||
|  | 0db7f96fd7 | ||
|  | 300248de54 | ||
|  | 3ee2b03330 | ||
|  | 3bec2c91a8 | ||
|  | b4ca5bfda3 | ||
|  | 308e257872 | ||
|  | 7db2a2c826 | ||
|  | 22f6ea8a3e | ||
|  | 91596fa81c | ||
|  | e5c8e5eaff | ||
|  | 8647dc57a1 | ||
|  | 8f41005da7 | ||
|  | 7108523a4c | ||
|  | ee34ccdbc3 | ||
|  | 959030f70d | ||
|  | 59cec0ffa5 | ||
|  | 1eed4cc7ee | ||
|  | c13889592f | ||
|  | 2e192be2e1 | ||
|  | c96605e79c | ||
|  | a1ce2ecba6 | ||
|  | a1410ae7ad | ||
|  | 20870b9004 | ||
|  | 3dcd99563a | ||
|  | 2337f9ab60 | ||
|  | 6ce4fb3973 | ||
|  | 387d7d2243 | ||
|  | 7de835fab4 | ||
|  | 3e0a2d630b | ||
|  | 09a8b41063 | ||
|  | 349380ae6b | ||
|  | f7806f5479 | ||
|  | c8c30e9861 | ||
|  | 083c266438 | ||
|  | dd9bdca5e0 | ||
|  | 9902560061 | ||
|  | dd9aa4b6ea | ||
|  | be8bdef9c8 | ||
|  | e185a32685 | ||
|  | 2b480e50e6 | ||
|  | b65acca903 | ||
|  | 08e2951513 | ||
|  | 83a2ce38ea | ||
|  | 60dd5f598a | ||
|  | 6eea5bce47 | ||
|  | a106f4aea0 | ||
|  | 90ed12d551 | ||
|  | e0694c8862 | ||
|  | d27ce26be0 | 
							
								
								
									
										6
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| root = true | ||||
| 
 | ||||
| [*] | ||||
| charset = utf-8 | ||||
| indent_size = 4 | ||||
| indent_style = tab | ||||
							
								
								
									
										6
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
								
							| @ -25,9 +25,11 @@ jobs: | ||||
|       - name: Setup Go | ||||
|         uses: actions/setup-go@v2 | ||||
|         with: | ||||
|           go-version: '1.17.7' | ||||
|           go-version: '1.18.8' | ||||
|       - name: Download Task | ||||
|         run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d' | ||||
|       - name: Build | ||||
|         run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} make | ||||
|         run: GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} ./bin/task | ||||
|       - uses: actions/upload-artifact@v2 | ||||
|         if: matrix.goos == 'windows' | ||||
|         with: | ||||
|  | ||||
							
								
								
									
										3
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/workflows/release.yml
									
									
									
									
										vendored
									
									
								
							| @ -33,10 +33,13 @@ jobs: | ||||
|     - uses: actions/checkout@v3 | ||||
|       with: | ||||
|         submodules: true | ||||
|     - name: Download Task | ||||
|       run: 'sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d' | ||||
|     - uses: wangyoucao577/go-release-action@v1.25 | ||||
|       with: | ||||
|         github_token: ${{ secrets.GITHUB_TOKEN }} | ||||
|         goos: ${{ matrix.goos }} | ||||
|         goarch: ${{ matrix.goarch }} | ||||
|         build_command: task | ||||
|         binary_name: hilbish | ||||
|         extra_files: LICENSE README.md CHANGELOG.md .hilbishrc.lua nature libs docs emmyLuaDocs | ||||
|  | ||||
							
								
								
									
										31
									
								
								.github/workflows/website.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								.github/workflows/website.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| name: Build website | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|       - website | ||||
| 
 | ||||
| jobs: | ||||
|   deploy: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v2 | ||||
|         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 | ||||
| @ -9,8 +9,6 @@ local function doPrompt(fail) | ||||
| 	)) | ||||
| end | ||||
| 
 | ||||
| print(lunacolors.format(hilbish.greeting)) | ||||
| 
 | ||||
| doPrompt() | ||||
| 
 | ||||
| bait.catch('command.exit', function(code) | ||||
|  | ||||
							
								
								
									
										68
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @ -1,6 +1,19 @@ | ||||
| # 🎀 Changelog | ||||
| 
 | ||||
| ## Unreleased | ||||
| **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/#/ | ||||
| 
 | ||||
| ### Added | ||||
| - Inline hints, akin to fish and the others. | ||||
| To make a handler for hint text, you can set the `hilbish.hinter` function. | ||||
| @ -52,11 +65,29 @@ having and using multiple runners. | ||||
|   - `fs.basename(path)` gets the basename of path | ||||
|   - `fs.dir(path)` gets the directory part of path | ||||
|   - `fs.glob(pattern)` globs files and directories based on patterns | ||||
|   - `fs.join(dirs...)` joins directories by OS dir separator | ||||
| - .. and 2 properties | ||||
|   - `fs.pathSep` is the separator for filesystem paths and directories | ||||
|   - `fs.pathListSep` is the separator for $PATH env entries | ||||
| - Lua modules located in `hilbish.userDir.data .. '/hilbish/start'` (like `~/.local/share/hilbish/start/foo/init.lua`) | ||||
| will be ran on startup | ||||
| - `hilbish.init` hook, thrown after Hilbish has initialized Lua side | ||||
| - Message of the day on startup (`hilbish.motd`), mainly intended as quick | ||||
| small news pieces for releases. It is printed by default. To disable it, | ||||
| set `hilbish.opts.motd` to false. | ||||
| - `history` opt has been added and is true by default. Setting it to false | ||||
| disables commands being added to history. | ||||
| - `hilbish.rawInput` hook for input from the readline library | ||||
| - Completion of files in quotes | ||||
| - 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]) | ||||
| - `bait.release(name, catcher)` removes `handler` for the named `event` | ||||
| - `exec`, `clear` and `cat` builtin commands | ||||
| - `hilbish.cancel` hook | ||||
| - 1st item on history is now inserted when history search menu is opened ([#148]) | ||||
| 
 | ||||
| [#148]: https://github.com/Rosettea/Hilbish/issues/148 | ||||
| [#197]: https://github.com/Rosettea/Hilbish/issues/197 | ||||
| 
 | ||||
| ### Changed | ||||
| - **Breaking Change:** Upgraded to Lua 5.4. | ||||
| @ -73,11 +104,17 @@ User input has been added to the return to account for runners wanting to | ||||
| prompt for continued input, and to add it properly to history. `continue` | ||||
| got added so that it would be easier for runners to get continued input | ||||
| without having to actually handle it at all.   | ||||
| 
 | ||||
| - **Breaking Change:** Job objects and timers are now Lua userdata instead | ||||
| of a table, so their functions require you to call them with a colon instead | ||||
| of a dot. (ie. `job.stop()` -> `job:stop()`) | ||||
| - 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 | ||||
| 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` | ||||
| methods to make it act how they want. | ||||
| - `guide` has been removed. See the [website](https://rosettea.github.io/Hilbish/) | ||||
| for general tips and documentation | ||||
| 
 | ||||
| ### Fixed | ||||
| - If in Vim replace mode, input at the end of the line inserts instead of | ||||
| @ -112,6 +149,33 @@ for explanation. | ||||
| Lua `job.stop` function. | ||||
| - Jobs are always started in sh exec handler now instead of only successful start. | ||||
| - SIGTERM is handled properly now, which means stopping jobs and timers. | ||||
| - Fix panic on trailing newline on pasted multiline text. | ||||
| - Completions will no longer be refreshed if the prompt refreshes while the | ||||
| menu is open. | ||||
| - Print error on search fail instead of panicking | ||||
| - Windows related fixes: | ||||
|   - `hilbish.dataDir` now has tilde (`~`) expanded. | ||||
|   - Arrow keys now work on Windows terminals. | ||||
|   - Escape codes now work. | ||||
| - Escape percentage symbols in completion entries, so you will no longer see | ||||
| 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 | ||||
| - 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 | ||||
| - 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 | ||||
| 
 | ||||
| ## [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 | ||||
| ### Added | ||||
| @ -536,6 +600,8 @@ This input for example will prompt for more input to complete: | ||||
| 
 | ||||
| First "stable" release of Hilbish. | ||||
| 
 | ||||
| [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.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 | ||||
|  | ||||
							
								
								
									
										30
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								Makefile
									
									
									
									
									
								
							| @ -1,30 +0,0 @@ | ||||
| PREFIX ?= /usr | ||||
| BINDIR ?= $(PREFIX)/bin | ||||
| LIBDIR ?= $(PREFIX)/share/hilbish | ||||
| 
 | ||||
| MY_GOFLAGS = -ldflags "-s -w" | ||||
| 
 | ||||
| all: dev | ||||
| 
 | ||||
| dev: MY_GOFLAGS = -ldflags "-s -w -X main.gitCommit=$(shell git rev-parse --short HEAD) -X main.gitBranch=$(shell git rev-parse --abbrev-ref HEAD)" | ||||
| dev: build | ||||
| 
 | ||||
| build: | ||||
| 	go build $(MY_GOFLAGS) | ||||
| 
 | ||||
| install: | ||||
| 	install -v -d "$(DESTDIR)$(BINDIR)/" && install -m 0755 -v hilbish "$(DESTDIR)$(BINDIR)/hilbish" | ||||
| 	mkdir -p "$(DESTDIR)$(LIBDIR)" | ||||
| 	cp -r libs docs emmyLuaDocs nature .hilbishrc.lua "$(DESTDIR)$(LIBDIR)" | ||||
| 	grep -qxF "$(DESTDIR)$(BINDIR)/hilbish" /etc/shells || echo "$(DESTDIR)$(BINDIR)/hilbish" >> /etc/shells | ||||
| 
 | ||||
| uninstall: | ||||
| 	rm -vrf \
 | ||||
| 			"$(DESTDIR)$(BINDIR)/hilbish" \
 | ||||
| 			"$(DESTDIR)$(LIBDIR)" | ||||
| 	sed -i '/hilbish/d' /etc/shells | ||||
| 
 | ||||
| clean: | ||||
| 	go clean | ||||
| 
 | ||||
| .PHONY: all dev build install uninstall clean | ||||
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @ -31,7 +31,6 @@ and aims to be infinitely configurable. If something isn't, open an issue! | ||||
|   - [AUR](#AUR) | ||||
|   - [Nixpkgs](#Nixpkgs) | ||||
|   - [Manual Build](#Manual-Build) | ||||
| - [Getting Started](#Getting-Started) | ||||
| - [Contributing](#Contributing) | ||||
| 
 | ||||
| # Screenshots | ||||
| @ -42,6 +41,10 @@ and aims to be infinitely configurable. If something isn't, open an issue! | ||||
| </div> | ||||
| 
 | ||||
| # Installation | ||||
| **NOTE:** Hilbish is not guaranteed to work properly on Windows, starting | ||||
| from the 2.0 version. It will still be able to compile, but functionality | ||||
| may be lacking. | ||||
| 
 | ||||
| ## Prebuilt binaries | ||||
| Go [here](https://nightly.link/Rosettea/Hilbish/workflows/build/master) for | ||||
| builds on the master branch. | ||||
| @ -66,6 +69,7 @@ If you're new to nix you should probably read up on how to do that [here](https: | ||||
| ## Manual Build | ||||
| ### Prerequisites | ||||
| - [Go 1.17+](https://go.dev) | ||||
| - [Task](https://taskfile.dev/installation/) (**Go on the hyperlink here to see Task's install method for your OS.**) | ||||
| 
 | ||||
| ### Build | ||||
| First, clone Hilbish. The recursive is required, as some Lua libraries | ||||
| @ -78,30 +82,16 @@ go get -d ./... | ||||
| 
 | ||||
| To build, run: | ||||
| ``` | ||||
| make dev | ||||
| task | ||||
| ```   | ||||
| 
 | ||||
| Or, if you want a stable branch, run these commands: | ||||
| ``` | ||||
| git checkout $(git describe --tags `git rev-list --tags --max-count=1`) | ||||
| make build | ||||
| task build | ||||
| ```   | ||||
| 
 | ||||
| After you did all that, run `sudo make install` to install Hilbish globally. | ||||
| 
 | ||||
| # Getting Started | ||||
| At startup, you should see a message which says to run a `guide` command. | ||||
| This guide is a *very* simple and basic step through text of what Hilbish is | ||||
| and where to find documentation. | ||||
| 
 | ||||
| Documentation is primarily viewed via the in shell `doc` command. | ||||
| Autogenerated function docs and general docs about other things are included | ||||
| there, so be sure to read it. | ||||
| 
 | ||||
| Using Hilbish is the same as using any other Linux shell, with an addition | ||||
| that you can also run Lua. Hilbish can also act as an enhanced Lua REPL | ||||
| via `hilbish.runnerMode 'lua'`. To switch back to normal, use | ||||
| `hilbish.runnerMode 'hybrid'`. | ||||
| After you did all that, run `sudo task install` to install Hilbish globally. | ||||
| 
 | ||||
| # Contributing | ||||
| Any kind of contributions are welcome! Hilbish is very easy to contribute to. | ||||
|  | ||||
							
								
								
									
										36
									
								
								Taskfile.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								Taskfile.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | ||||
| # https://taskfile.dev | ||||
| 
 | ||||
| version: '3' | ||||
| 
 | ||||
| vars: | ||||
|   PREFIX: '{{default "/usr/local" .PREFIX}}' | ||||
|   bindir__: '{{.PREFIX}}/bin' | ||||
|   BINDIR: '{{default .bindir__ .BINDIR}}' | ||||
|   libdir__: '{{.PREFIX}}/share/hilbish' | ||||
|   LIBDIR: '{{default .libdir__ .LIBDIR}}' | ||||
|   GOFLAGS: '-ldflags "-s -w -X main.dataDir={{.LIBDIR}}"' | ||||
| 
 | ||||
| tasks: | ||||
|   default: | ||||
|     cmds: | ||||
|       - CGO_ENABLED=0 go build {{.GOFLAGS}} | ||||
|     vars: | ||||
|       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: | ||||
|     cmds: | ||||
|       - CGO_ENABLED=0 go build {{.GOFLAGS}} | ||||
| 
 | ||||
|   install: | ||||
|     cmds: | ||||
|       - install -v -d "{{.DESTDIR}}{{.BINDIR}}/" && install -m 0755 -v hilbish "{{.DESTDIR}}{{.BINDIR}}/hilbish" | ||||
|       - mkdir -p "{{.DESTDIR}}{{.LIBDIR}}" | ||||
|       - cp -r libs docs emmyLuaDocs nature .hilbishrc.lua {{.DESTDIR}}{{.LIBDIR}} | ||||
|       - grep -qxF "{{.DESTDIR}}{{.BINDIR}}/hilbish" /etc/shells || echo "{{.DESTDIR}}{{.BINDIR}}/hilbish" >> /etc/shells | ||||
| 
 | ||||
|   uninstall: | ||||
|     cmds: | ||||
|       - rm -vrf | ||||
|         "{{.DESTDIR}}{{.BINDIR}}/hilbish" | ||||
|         "{{.DESTDIR}}{{.LIBDIR}}" | ||||
|       - sed -i '/hilbish/d' /etc/shells | ||||
							
								
								
									
										30
									
								
								api.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								api.go
									
									
									
									
									
								
							| @ -44,7 +44,6 @@ var exports = map[string]util.LuaExport{ | ||||
| 	"which": {hlwhich, 1, false}, | ||||
| } | ||||
| 
 | ||||
| var greeting string | ||||
| var hshMod *rt.Table | ||||
| var hilbishLoader = packagelib.Loader{ | ||||
| 	Load: hilbishLoad, | ||||
| @ -103,10 +102,6 @@ func hilbishLoad(rtm *rt.Runtime) (rt.Value, func()) { | ||||
| 		username = strings.Split(username, "\\")[1] // for some reason Username includes the hostname on windows | ||||
| 	} | ||||
| 
 | ||||
| 	greeting = `Welcome to {magenta}Hilbish{reset}, {cyan}` + username + `{reset}. | ||||
| The nice lil shell for {blue}Lua{reset} fanatics! | ||||
| Check out the {blue}{bold}guide{reset} command to get started. | ||||
| ` | ||||
| 	util.SetFieldProtected(fakeMod, mod, "ver", rt.StringValue(getVersion()), "Hilbish version") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "user", rt.StringValue(username), "Username of user") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "host", rt.StringValue(host), "Host name of the machine") | ||||
| @ -114,7 +109,6 @@ Check out the {blue}{bold}guide{reset} command to get started. | ||||
| 	util.SetFieldProtected(fakeMod, mod, "dataDir", rt.StringValue(dataDir), "Directory for Hilbish's data files") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "interactive", rt.BoolValue(interactive), "If this is an interactive shell") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "login", rt.BoolValue(login), "Whether this is a login shell") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "greeting", rt.StringValue(greeting), "Hilbish's welcome message for interactive shells. It has Lunacolors formatting.") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "vimMode", rt.NilValue, "Current Vim mode of Hilbish (nil if not in Vim mode)") | ||||
| 	util.SetFieldProtected(fakeMod, mod, "exitCode", rt.IntValue(0), "Exit code of last exected command") | ||||
| 	util.Document(fakeMod, "Hilbish's core API, containing submodules and functions which relate to the shell itself.") | ||||
| @ -195,7 +189,7 @@ func getenv(key, fallback string) string { | ||||
| 
 | ||||
| func setVimMode(mode string) { | ||||
| 	util.SetField(l, hshMod, "vimMode", rt.StringValue(mode), "Current Vim mode of Hilbish (nil if not in Vim mode)") | ||||
| 	hooks.Em.Emit("hilbish.vimMode", mode) | ||||
| 	hooks.Emit("hilbish.vimMode", mode) | ||||
| } | ||||
| 
 | ||||
| func unsetVimMode() { | ||||
| @ -256,21 +250,27 @@ func hlcwd(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // read(prompt) -> input? | ||||
| // 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) | ||||
| // --- @param prompt string | ||||
| func hlread(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	if err := c.Check1Arg(); err != nil { | ||||
| 		return nil, err | ||||
| 	luaprompt := c.Arg(0) | ||||
| 	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) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	prompt, ok := luaprompt.TryString() | ||||
| 	if !ok { | ||||
| 		// 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() | ||||
| 	if err != nil { | ||||
|  | ||||
							
								
								
									
										99
									
								
								complete.go
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								complete.go
									
									
									
									
									
								
							| @ -11,11 +11,77 @@ import ( | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| ) | ||||
| 
 | ||||
| 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{} | ||||
| 	sb := &strings.Builder{} | ||||
| 	quoted := false | ||||
| 
 | ||||
| 	for i, r := range str { | ||||
| 		if r == '"' { | ||||
| 			quoted = !quoted | ||||
| 			sb.WriteRune(r) | ||||
| 		} else if r == ' ' && str[i - 1] == '\\' { | ||||
| 			sb.WriteRune(r) | ||||
| 		} else if !quoted && r == ' ' { | ||||
| 			split = append(split, sb.String()) | ||||
| 			sb.Reset() | ||||
| 		} else { | ||||
| 			sb.WriteRune(r) | ||||
| 		} | ||||
| 	} | ||||
| 	if strings.HasSuffix(str, " ") { | ||||
| 		split = append(split, "") | ||||
| 	} | ||||
| 
 | ||||
| 	if sb.Len() > 0 { | ||||
| 		split = append(split, sb.String()) | ||||
| 	} | ||||
| 
 | ||||
| 	return split | ||||
| } | ||||
| 
 | ||||
| func fileComplete(query, ctx string, fields []string) ([]string, string) { | ||||
| 	return matchPath(query) | ||||
| 	q := splitForFile(ctx) | ||||
| 
 | ||||
| 	return matchPath(q[len(q) - 1]) | ||||
| } | ||||
| 
 | ||||
| func binaryComplete(query, ctx string, fields []string) ([]string, string) { | ||||
| 	q := splitForFile(ctx) | ||||
| 	query = q[len(q) - 1] | ||||
| 
 | ||||
| 	var completions []string | ||||
| 
 | ||||
| 	prefixes := []string{"./", "../", "/", "~/"} | ||||
| @ -25,7 +91,7 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) { | ||||
| 			if len(fileCompletions) != 0 { | ||||
| 				for _, f := range fileCompletions { | ||||
| 					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 | ||||
| 					} | ||||
| 					completions = append(completions, f) | ||||
| @ -37,7 +103,6 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) { | ||||
| 
 | ||||
| 	// filter out executables, but in path | ||||
| 	for _, dir := range filepath.SplitList(os.Getenv("PATH")) { | ||||
| 		// print dir to stderr for debugging | ||||
| 		// search for an executable which matches our query string | ||||
| 		if matches, err := filepath.Glob(filepath.Join(dir, query + "*")); err == nil { | ||||
| 			// get basename from matches | ||||
| @ -68,9 +133,12 @@ func binaryComplete(query, ctx string, fields []string) ([]string, string) { | ||||
| } | ||||
| 
 | ||||
| func matchPath(query string) ([]string, string) { | ||||
| 	oldQuery := query | ||||
| 	query = strings.TrimPrefix(query, "\"") | ||||
| 	var entries []string | ||||
| 	var baseName string | ||||
| 
 | ||||
| 	query = escapeInvertReplaer.Replace(query) | ||||
| 	path, _ := filepath.Abs(util.ExpandHome(filepath.Dir(query))) | ||||
| 	if string(query) == "" { | ||||
| 		// filepath base below would give us "." | ||||
| @ -87,34 +155,21 @@ func matchPath(query string) ([]string, string) { | ||||
| 			if file.IsDir() { | ||||
| 				entry = entry + string(os.PathSeparator) | ||||
| 			} | ||||
| 			if !strings.HasPrefix(oldQuery, "\"") { | ||||
| 				entry = escapeFilename(entry) | ||||
| 			} | ||||
| 			entries = append(entries, entry) | ||||
| 		} | ||||
| 	} | ||||
| 	if !strings.HasPrefix(oldQuery, "\"") { | ||||
| 		baseName = escapeFilename(baseName) | ||||
| 	} | ||||
| 
 | ||||
| 	return entries, baseName | ||||
| } | ||||
| 
 | ||||
| func escapeFilename(fname string) string { | ||||
| 	args := []string{ | ||||
| 		"\"", "\\\"", | ||||
| 		"'", "\\'", | ||||
| 		"`", "\\`", | ||||
| 		" ", "\\ ", | ||||
| 		"(", "\\(", | ||||
| 		")", "\\)", | ||||
| 		"[", "\\[", | ||||
| 		"]", "\\]", | ||||
| 		"$", "\\$", | ||||
| 		"&", "\\&", | ||||
| 		"*", "\\*", | ||||
| 		">", "\\>", | ||||
| 		"<", "\\<", | ||||
| 		"|", "\\|", | ||||
| 	} | ||||
| 
 | ||||
| 	r := strings.NewReplacer(args...) | ||||
| 	return r.Replace(fname) | ||||
| 	return escapeReplaer.Replace(fname) | ||||
| } | ||||
| 
 | ||||
| func completionLoader(rtm *rt.Runtime) *rt.Table { | ||||
|  | ||||
| @ -2,5 +2,11 @@ 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) -> {cb, cb...} > Returns a table with hooks 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` | ||||
| 
 | ||||
|  | ||||
| @ -11,6 +11,9 @@ 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` | ||||
|  | ||||
| @ -41,7 +41,7 @@ These will be formatted and replaced with the appropriate values. | ||||
| `%u` - Name of current user | ||||
| `%h` - Hostname of device | ||||
| 
 | ||||
| read(prompt) -> input? > Read input from the user, using Hilbish's line editor/input reader. | ||||
| 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) | ||||
| 
 | ||||
|  | ||||
| @ -5,3 +5,5 @@ | ||||
| 
 | ||||
| + `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. | ||||
| 
 | ||||
| + `hilbish.cancel` > Sent when the user cancels their input with Ctrl-C. | ||||
|  | ||||
| @ -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 | ||||
| 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. | ||||
|  | ||||
| @ -11,6 +11,7 @@ func editorLoader(rtm *rt.Runtime) *rt.Table { | ||||
| 		"insert": {editorInsert, 1, false}, | ||||
| 		"setVimRegister": {editorSetRegister, 1, false}, | ||||
| 		"getVimRegister": {editorGetRegister, 2, false}, | ||||
| 		"getLine": {editorGetLine, 0, false}, | ||||
| 	} | ||||
| 
 | ||||
| 	mod := rt.NewTable() | ||||
| @ -68,3 +69,9 @@ func editorGetRegister(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil | ||||
| } | ||||
| 
 | ||||
| func editorGetLine(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	buf := lr.rl.GetLine() | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, rt.StringValue(string(buf))), nil | ||||
| } | ||||
|  | ||||
| @ -12,6 +12,18 @@ function bait.catch(name, cb) end | ||||
| --- @param cb function | ||||
| function bait.catchOnce(name, cb) end | ||||
| 
 | ||||
| --- Returns a table with hooks on the event with `name`. | ||||
| --- @param name string | ||||
| --- @returns table | ||||
| 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 | ||||
| --- an event, like one saved to a variable. | ||||
| --- @param name string | ||||
| --- @param catcher function | ||||
| function bait.release(name, catcher) end | ||||
| 
 | ||||
| --- Throws a hook with `name` with the provided `args` | ||||
| --- @param name string | ||||
| --- @vararg any | ||||
|  | ||||
| @ -22,6 +22,10 @@ function fs.dir() end | ||||
| --- For the rules, see Go's filepath.Glob | ||||
| function fs.glob() end | ||||
| 
 | ||||
| --- Takes paths and joins them together with the OS's | ||||
| --- directory separator (forward or backward slash). | ||||
| function fs.join() end | ||||
| 
 | ||||
| --- Makes a directory called `name`. If `recursive` is true, it will create its parent directories. | ||||
| --- @param name string | ||||
| --- @param recursive boolean | ||||
|  | ||||
							
								
								
									
										36
									
								
								exec.go
									
									
									
									
									
								
							
							
						
						
									
										36
									
								
								exec.go
									
									
									
									
									
								
							| @ -85,7 +85,7 @@ func isExecError(err error) (execError, bool) { | ||||
| func runInput(input string, priv bool) { | ||||
| 	running = true | ||||
| 	cmdString := aliases.Resolve(input) | ||||
| 	hooks.Em.Emit("command.preexec", input, cmdString) | ||||
| 	hooks.Emit("command.preexec", input, cmdString) | ||||
| 
 | ||||
| 	rerun: | ||||
| 	var exitCode uint8 | ||||
| @ -96,7 +96,7 @@ func runInput(input string, priv bool) { | ||||
| 	if currentRunner.Type() == rt.StringType { | ||||
| 		switch currentRunner.AsString() { | ||||
| 			case "hybrid": | ||||
| 				_, _, err = handleLua(cmdString) | ||||
| 				_, _, err = handleLua(input) | ||||
| 				if err == nil { | ||||
| 					cmdFinish(0, input, priv) | ||||
| 					return | ||||
| @ -108,9 +108,9 @@ func runInput(input string, priv bool) { | ||||
| 					cmdFinish(0, input, priv) | ||||
| 					return | ||||
| 				} | ||||
| 				input, exitCode, err = handleLua(cmdString) | ||||
| 				input, exitCode, err = handleLua(input) | ||||
| 			case "lua": | ||||
| 				input, exitCode, err = handleLua(cmdString) | ||||
| 				input, exitCode, err = handleLua(input) | ||||
| 			case "sh": | ||||
| 				input, exitCode, cont, err = handleSh(input) | ||||
| 		} | ||||
| @ -140,11 +140,11 @@ func runInput(input string, priv bool) { | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		if exErr, ok := isExecError(err); ok { | ||||
| 			hooks.Em.Emit("command." + exErr.typ, exErr.cmd) | ||||
| 			err = exErr.sprint() | ||||
| 		} | ||||
| 			hooks.Emit("command." + exErr.typ, exErr.cmd) | ||||
| 		} else { | ||||
| 			fmt.Fprintln(os.Stderr, err) | ||||
| 		} | ||||
| 	} | ||||
| 	cmdFinish(exitCode, input, priv) | ||||
| } | ||||
| 
 | ||||
| @ -152,6 +152,7 @@ func reprompt(input string) (string, error) { | ||||
| 	for { | ||||
| 		in, err := continuePrompt(strings.TrimSuffix(input, "\\")) | ||||
| 		if err != nil { | ||||
| 			lr.SetPrompt(fmtPrompt(prompt)) | ||||
| 			return input, err | ||||
| 		} | ||||
| 
 | ||||
| @ -194,7 +195,8 @@ func runLuaRunner(runr rt.Value, userInput string) (input string, exitCode uint8 | ||||
| 	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 | ||||
| 	chunk, err := l.CompileAndLoadLuaChunk("", []byte(cmdString), rt.TableValue(l.GlobalEnv())) | ||||
| 	if err != nil && noexecute { | ||||
| @ -220,7 +222,17 @@ func handleLua(cmdString string) (string, uint8, error) { | ||||
| 	return cmdString, 125, err | ||||
| } | ||||
| 
 | ||||
| func handleSh(cmdString string) (string, uint8, bool, error) { | ||||
| func handleSh(cmdString string) (input string, exitCode uint8, cont bool, runErr error) { | ||||
| 	shRunner := hshMod.Get(rt.StringValue("runner")).AsTable().Get(rt.StringValue("sh")) | ||||
| 	var err error | ||||
| 	input, exitCode, cont, runErr, err = runLuaRunner(shRunner, cmdString) | ||||
| 	if err != nil { | ||||
| 		runErr = err | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func execSh(cmdString string) (string, uint8, bool, error) { | ||||
| 	_, _, err := execCommand(cmdString, true) | ||||
| 	if err != nil { | ||||
| 		// If input is incomplete, start multiline prompting | ||||
| @ -540,13 +552,9 @@ func splitInput(input string) ([]string, string) { | ||||
| } | ||||
| 
 | ||||
| func cmdFinish(code uint8, cmdstr string, private bool) { | ||||
| 	// if input has space at the beginning, dont put in history | ||||
| 	if interactive && !private { | ||||
| 		handleHistory(cmdstr) | ||||
| 	} | ||||
| 	util.SetField(l, hshMod, "exitCode", rt.IntValue(int64(code)), "Exit code of last exected command") | ||||
| 	// using AsValue (to convert to lua type) on an interface which is an int | ||||
| 	// results in it being unknown in lua .... ???? | ||||
| 	// so we allow the hook handler to take lua runtime Values | ||||
| 	hooks.Em.Emit("command.exit", rt.IntValue(int64(code)), cmdstr) | ||||
| 	hooks.Emit("command.exit", rt.IntValue(int64(code)), cmdstr, private) | ||||
| } | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
									
									
									
									
								
							| @ -29,4 +29,4 @@ replace github.com/maxlandon/readline => ./readline | ||||
| 
 | ||||
| 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-20220621002945-b05143999437 | ||||
| replace github.com/arnodel/golua => github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345 | ||||
|  | ||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							| @ -4,6 +4,8 @@ github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3 h1:I/wWr40FFLFF9pbT | ||||
| github.com/Rosettea/golua v0.0.0-20220518005949-116371948fe3/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/golua v0.0.0-20220621002945-b05143999437 h1:6lWu4YVLeKuZ8jR9xwHONhkHBsrIbw5dpfG1gtOVw0A= | ||||
| github.com/Rosettea/golua v0.0.0-20220621002945-b05143999437/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345 h1:QNYjYDogUSiNUkffbhFSrSCtpZhofeiVYGFN2FI4wSs= | ||||
| github.com/Rosettea/golua v0.0.0-20221213193027-cbf6d4e4d345/go.mod h1:9jzpYPiU2is0HVGCiuIOBSXdergHUW44IEjmuN1UrIE= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e h1:P2XupP8SaylWaudD1DqbWtZ3mIa8OsE9635LmR+Q+lg= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220306140409-795a84b00b4e/go.mod h1:R09vh/04ILvP2Gj8/Z9Jd0Dh0ZIvaucowMEs6abQpWs= | ||||
| github.com/Rosettea/sh/v3 v3.4.0-0.dev.0.20220524215627-dfd9a4fa219b h1:s5eDMhBk6H1BgipgLub/gv9qeyBaTuiHM0k3h2/9TSE= | ||||
|  | ||||
| @ -1,27 +1,43 @@ | ||||
| package bait | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"errors" | ||||
| 
 | ||||
| 	"hilbish/util" | ||||
| 
 | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| 	"github.com/arnodel/golua/lib/packagelib" | ||||
| 	"github.com/chuckpreslar/emission" | ||||
| ) | ||||
| 
 | ||||
| type Bait struct{ | ||||
| 	Em *emission.Emitter | ||||
| 	Loader packagelib.Loader | ||||
| type listenerType int | ||||
| const ( | ||||
| 	goListener listenerType = iota | ||||
| 	luaListener | ||||
| ) | ||||
| 
 | ||||
| // Recoverer is a function which is called when a panic occurs in an event. | ||||
| type Recoverer func(event string, handler *Listener, err interface{}) | ||||
| 
 | ||||
| // Listener is a struct that holds the handler for an event. | ||||
| type Listener struct{ | ||||
| 	typ listenerType | ||||
| 	once bool | ||||
| 	caller func(...interface{}) | ||||
| 	luaCaller *rt.Closure | ||||
| } | ||||
| 
 | ||||
| func New() Bait { | ||||
| 	emitter := emission.NewEmitter() | ||||
| 	emitter.RecoverWith(func(hookname, hookfunc interface{}, err error) { | ||||
| 		emitter.Off(hookname, hookfunc) | ||||
| 		fmt.Println(err) | ||||
| 	}) | ||||
| 	b := Bait{ | ||||
| 		Em: emitter, | ||||
| type Bait struct{ | ||||
| 	Loader packagelib.Loader | ||||
| 	recoverer Recoverer | ||||
| 	handlers map[string][]*Listener | ||||
| 	rtm *rt.Runtime | ||||
| } | ||||
| 
 | ||||
| // New creates a new Bait instance. | ||||
| func New(rtm *rt.Runtime) *Bait { | ||||
| 	b := &Bait{ | ||||
| 		handlers: make(map[string][]*Listener), | ||||
| 		rtm: rtm, | ||||
| 	} | ||||
| 	b.Loader = packagelib.Loader{ | ||||
| 		Load: b.loaderFunc, | ||||
| @ -31,11 +47,153 @@ func New() Bait { | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| // Emit throws an event. | ||||
| func (b *Bait) Emit(event string, args ...interface{}) { | ||||
| 	handles := b.handlers[event] | ||||
| 	if handles == nil { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	for idx, handle := range handles { | ||||
| 		defer func() { | ||||
| 			if err := recover(); err != nil { | ||||
| 				b.callRecoverer(event, handle, err) | ||||
| 			} | ||||
| 		}() | ||||
| 
 | ||||
| 		if handle.typ == luaListener { | ||||
| 			funcVal := rt.FunctionValue(handle.luaCaller) | ||||
| 			var luaArgs []rt.Value | ||||
| 			for _, arg := range args { | ||||
| 				var luarg rt.Value | ||||
| 				switch arg.(type) { | ||||
| 					case rt.Value: luarg = arg.(rt.Value) | ||||
| 					default: luarg = rt.AsValue(arg) | ||||
| 				} | ||||
| 				luaArgs = append(luaArgs, luarg) | ||||
| 			} | ||||
| 			_, err := rt.Call1(b.rtm.MainThread(), funcVal, luaArgs...) | ||||
| 			if err != nil { | ||||
| 				if event != "error" { | ||||
| 					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) | ||||
| 			} | ||||
| 		} else { | ||||
| 			handle.caller(args...) | ||||
| 		} | ||||
| 
 | ||||
| 		if handle.once { | ||||
| 			b.removeListener(event, idx) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // On adds a Go function handler for an event. | ||||
| func (b *Bait) On(event string, handler func(...interface{})) *Listener { | ||||
| 	listener := &Listener{ | ||||
| 		typ: goListener, | ||||
| 		caller: handler, | ||||
| 	} | ||||
| 
 | ||||
| 	b.addListener(event, listener) | ||||
| 	return listener | ||||
| } | ||||
| 
 | ||||
| // OnLua adds a Lua function handler for an event. | ||||
| func (b *Bait) OnLua(event string, handler *rt.Closure) *Listener { | ||||
| 	listener :=&Listener{ | ||||
| 		typ: luaListener, | ||||
| 		luaCaller: handler, | ||||
| 	} | ||||
| 	b.addListener(event, listener) | ||||
| 
 | ||||
| 	return listener | ||||
| } | ||||
| 
 | ||||
| // Off removes a Go function handler for an event. | ||||
| func (b *Bait) Off(event string, listener *Listener) { | ||||
| 	handles := b.handlers[event] | ||||
| 
 | ||||
| 	for i, handle := range handles { | ||||
| 		if handle == listener { | ||||
| 			b.removeListener(event, i) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // OffLua removes a Lua function handler for an event. | ||||
| func (b *Bait) OffLua(event string, handler *rt.Closure) { | ||||
| 	handles := b.handlers[event] | ||||
| 
 | ||||
| 	for i, handle := range handles { | ||||
| 		if handle.luaCaller == handler { | ||||
| 			b.removeListener(event, i) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Once adds a Go function listener for an event that only runs once. | ||||
| func (b *Bait) Once(event string, handler func(...interface{})) *Listener { | ||||
| 	listener := &Listener{ | ||||
| 		typ: goListener, | ||||
| 		once: true, | ||||
| 		caller: handler, | ||||
| 	} | ||||
| 	b.addListener(event, listener) | ||||
| 
 | ||||
| 	return listener | ||||
| } | ||||
| 
 | ||||
| // OnceLua adds a Lua function listener for an event that only runs once. | ||||
| func (b *Bait) OnceLua(event string, handler *rt.Closure) *Listener { | ||||
| 	listener := &Listener{ | ||||
| 		typ: luaListener, | ||||
| 		once: true, | ||||
| 		luaCaller: handler, | ||||
| 	} | ||||
| 	b.addListener(event, listener) | ||||
| 
 | ||||
| 	return listener | ||||
| } | ||||
| 
 | ||||
| // SetRecoverer sets the function to be executed when a panic occurs in an event. | ||||
| func (b *Bait) SetRecoverer(recoverer Recoverer) { | ||||
| 	b.recoverer = recoverer | ||||
| } | ||||
| 
 | ||||
| func (b *Bait) addListener(event string, listener *Listener) { | ||||
| 	if b.handlers[event] == nil { | ||||
| 		b.handlers[event] = []*Listener{} | ||||
| 	} | ||||
| 
 | ||||
| 	b.handlers[event] = append(b.handlers[event], listener) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| func (b *Bait) removeListener(event string, idx int) { | ||||
| 	b.handlers[event][idx] = b.handlers[event][len(b.handlers[event]) - 1] | ||||
| 
 | ||||
| 	b.handlers[event] = b.handlers[event][:len(b.handlers[event]) - 1] | ||||
| } | ||||
| 
 | ||||
| func (b *Bait) callRecoverer(event string, handler *Listener, err interface{}) { | ||||
| 	if b.recoverer == nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 	b.recoverer(event, handler, err) | ||||
| } | ||||
| 
 | ||||
| func (b *Bait) loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { | ||||
| 	exports := map[string]util.LuaExport{ | ||||
| 		"catch": util.LuaExport{b.bcatch, 2, false}, | ||||
| 		"catchOnce": util.LuaExport{b.bcatchOnce, 2, false}, | ||||
| 		"throw": util.LuaExport{b.bthrow, 1, true}, | ||||
| 		"release": util.LuaExport{b.brelease, 2, false}, | ||||
| 		"hooks": util.LuaExport{b.bhooks, 1, false}, | ||||
| 	} | ||||
| 	mod := rt.NewTable() | ||||
| 	util.SetExports(rtm, mod, exports) | ||||
| @ -89,7 +247,7 @@ func (b *Bait) bthrow(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	for i, v := range c.Etc() { | ||||
| 		ifaceSlice[i] = v | ||||
| 	} | ||||
| 	b.Em.Emit(name, ifaceSlice...) | ||||
| 	b.Emit(name, ifaceSlice...) | ||||
| 
 | ||||
| 	return c.Next(), nil | ||||
| } | ||||
| @ -104,9 +262,7 @@ func (b *Bait) bcatch(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	b.Em.On(name, func(args ...interface{}) { | ||||
| 		handleHook(t, c, name, catcher, args...) | ||||
| 	}) | ||||
| 	b.OnLua(name, catcher) | ||||
| 
 | ||||
| 	return c.Next(), nil | ||||
| } | ||||
| @ -121,9 +277,56 @@ func (b *Bait) bcatchOnce(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	b.Em.Once(name, func(args ...interface{}) { | ||||
| 		handleHook(t, c, name, catcher, args...) | ||||
| 	}) | ||||
| 	b.OnceLua(name, catcher) | ||||
| 
 | ||||
| 	return c.Next(), nil | ||||
| } | ||||
| 
 | ||||
| // 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. | ||||
| // --- @param name string | ||||
| // --- @param catcher function | ||||
| func (b *Bait) brelease(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	name, catcher, err := util.HandleStrCallback(t, c) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	b.OffLua(name, catcher) | ||||
| 
 | ||||
| 	return c.Next(), nil | ||||
| } | ||||
| 
 | ||||
| // hooks(name) -> {cb, cb...} | ||||
| // Returns a table with hooks on the event with `name`. | ||||
| // --- @param name string | ||||
| // --- @returns table | ||||
| 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 | ||||
| } | ||||
|  | ||||
| @ -2,20 +2,20 @@ package commander | ||||
| 
 | ||||
| import ( | ||||
| 	"hilbish/util" | ||||
| 	"hilbish/golibs/bait" | ||||
| 
 | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| 	"github.com/arnodel/golua/lib/packagelib" | ||||
| 	"github.com/chuckpreslar/emission" | ||||
| ) | ||||
| 
 | ||||
| type Commander struct{ | ||||
| 	Events *emission.Emitter | ||||
| 	Events *bait.Bait | ||||
| 	Loader packagelib.Loader | ||||
| } | ||||
| 
 | ||||
| func New() Commander { | ||||
| func New(rtm *rt.Runtime) Commander { | ||||
| 	c := Commander{ | ||||
| 		Events: emission.NewEmitter(), | ||||
| 		Events: bait.New(rtm), | ||||
| 	} | ||||
| 	c.Loader = packagelib.Loader{ | ||||
| 		Load: c.loaderFunc, | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| package fs | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| 	"os" | ||||
| @ -27,6 +28,7 @@ func loaderFunc(rtm *rt.Runtime) (rt.Value, func()) { | ||||
| 		"basename": util.LuaExport{fbasename, 1, false}, | ||||
| 		"dir": util.LuaExport{fdir, 1, false}, | ||||
| 		"glob": util.LuaExport{fglob, 1, false}, | ||||
| 		"join": util.LuaExport{fjoin, 0, true}, | ||||
| 	} | ||||
| 	mod := rt.NewTable() | ||||
| 	util.SetExports(rtm, mod, exports) | ||||
| @ -216,3 +218,21 @@ func fglob(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	 | ||||
| 	return c.PushingNext(t.Runtime, rt.TableValue(luaMatches)), nil | ||||
| } | ||||
| 
 | ||||
| // join(paths...) | ||||
| // Takes paths and joins them together with the OS's | ||||
| // directory separator (forward or backward slash). | ||||
| func fjoin(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	strs := make([]string, len(c.Etc())) | ||||
| 	for i, v := range c.Etc() { | ||||
| 		if v.Type() != rt.StringType { | ||||
| 			// +2; go indexes of 0 and first arg from above | ||||
| 			return nil, fmt.Errorf("bad argument #%d to run (expected string, got %s)", i + 1, v.TypeName()) | ||||
| 		} | ||||
| 		strs[i] = v.AsString() | ||||
| 	} | ||||
| 
 | ||||
| 	res := filepath.Join(strs...) | ||||
| 
 | ||||
| 	return c.PushingNext(t.Runtime, rt.StringValue(res)), nil | ||||
| } | ||||
|  | ||||
							
								
								
									
										60
									
								
								history.go
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								history.go
									
									
									
									
									
								
							| @ -4,36 +4,84 @@ import ( | ||||
| 	"errors" | ||||
| 	"io/fs" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| ) | ||||
| 
 | ||||
| type luaHistory struct {} | ||||
| 
 | ||||
| func (h *luaHistory) Write(line string) (int, error) { | ||||
| 	histWrite := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("add")) | ||||
| 	ln, err := rt.Call1(l.MainThread(), histWrite, rt.StringValue(line)) | ||||
| 
 | ||||
| 	var num int64 | ||||
| 	if ln.Type() == rt.IntType { | ||||
| 		num = ln.AsInt() | ||||
| 	} | ||||
| 
 | ||||
| 	return int(num), err | ||||
| } | ||||
| 
 | ||||
| func (h *luaHistory) GetLine(idx int) (string, error) { | ||||
| 	histGet := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("get")) | ||||
| 	lcmd, err := rt.Call1(l.MainThread(), histGet, rt.IntValue(int64(idx))) | ||||
| 
 | ||||
| 	var cmd string | ||||
| 	if lcmd.Type() == rt.StringType { | ||||
| 		cmd = lcmd.AsString() | ||||
| 	} | ||||
| 
 | ||||
| 	return cmd, err | ||||
| } | ||||
| 
 | ||||
| func (h *luaHistory) Len() int { | ||||
| 	histSize := hshMod.Get(rt.StringValue("history")).AsTable().Get(rt.StringValue("size")) | ||||
| 	ln, _ := rt.Call1(l.MainThread(), histSize) | ||||
| 
 | ||||
| 	var num int64 | ||||
| 	if ln.Type() == rt.IntType { | ||||
| 		num = ln.AsInt() | ||||
| 	} | ||||
| 
 | ||||
| 	return int(num) | ||||
| } | ||||
| 
 | ||||
| func (h *luaHistory) Dump() interface{} { | ||||
| 	// hilbish.history interface already has all function, this isnt used in readline | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type fileHistory struct { | ||||
| 	items []string | ||||
| 	f *os.File | ||||
| } | ||||
| 
 | ||||
| func newFileHistory() *fileHistory { | ||||
| 	err := os.MkdirAll(defaultHistDir, 0755) | ||||
| func newFileHistory(path string) *fileHistory { | ||||
| 	dir := filepath.Dir(path) | ||||
| 
 | ||||
| 	err := os.MkdirAll(dir, 0755) | ||||
| 	if err != nil { | ||||
| 		panic(err) | ||||
| 	} | ||||
| 
 | ||||
| 	data, err := os.ReadFile(defaultHistPath) | ||||
| 	data, err := os.ReadFile(path) | ||||
| 	if err != nil { | ||||
| 		if !errors.Is(err, fs.ErrNotExist) { | ||||
| 			panic(err) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	itms := []string{""} | ||||
| 	lines := strings.Split(string(data), "\n") | ||||
| 	itms := make([]string, len(lines) - 1) | ||||
| 	for i, l := range lines { | ||||
| 		if i == len(lines) - 1 { | ||||
| 			continue | ||||
| 		} | ||||
| 		itms = append(itms, l) | ||||
| 		itms[i] = l | ||||
| 	} | ||||
| 	f, err := os.OpenFile(defaultHistPath, 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 { | ||||
| 		panic(err) | ||||
| 	} | ||||
|  | ||||
| @ -5,7 +5,13 @@ package main | ||||
| import "golang.org/x/sys/windows" | ||||
| 
 | ||||
| func init() { | ||||
| 	var mode uint32 | ||||
| 	windows.GetConsoleMode(windows.Stdout, &mode) | ||||
| 	windows.SetConsoleMode(windows.Stdout, mode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) | ||||
| 	// vt output (escape codes) | ||||
| 	var outMode uint32 | ||||
| 	windows.GetConsoleMode(windows.Stdout, &outMode) | ||||
| 	windows.SetConsoleMode(windows.Stdout, outMode | windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING) | ||||
| 
 | ||||
| 	// vt input | ||||
| 	var inMode uint32 | ||||
| 	windows.GetConsoleMode(windows.Stdin, &inMode) | ||||
| 	windows.SetConsoleMode(windows.Stdin, inMode | windows.ENABLE_VIRTUAL_TERMINAL_INPUT) | ||||
| } | ||||
|  | ||||
							
								
								
									
										6
									
								
								job.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								job.go
									
									
									
									
									
								
							| @ -67,7 +67,7 @@ func (j *job) start() error { | ||||
| 	j.pid = proc.Pid | ||||
| 	j.running = true | ||||
| 
 | ||||
| 	hooks.Em.Emit("job.start", rt.UserDataValue(j.ud)) | ||||
| 	hooks.Emit("job.start", rt.UserDataValue(j.ud)) | ||||
| 
 | ||||
| 	return err | ||||
| } | ||||
| @ -82,7 +82,7 @@ func (j *job) stop() { | ||||
| 
 | ||||
| func (j *job) finish() { | ||||
| 	j.running = false | ||||
| 	hooks.Em.Emit("job.done", rt.UserDataValue(j.ud)) | ||||
| 	hooks.Emit("job.done", rt.UserDataValue(j.ud)) | ||||
| } | ||||
| 
 | ||||
| func (j *job) wait() { | ||||
| @ -236,7 +236,7 @@ func (j *jobHandler) add(cmd string, args []string, path string) *job { | ||||
| 	jb.ud = jobUserData(jb) | ||||
| 
 | ||||
| 	j.jobs[j.latestID] = jb | ||||
| 	hooks.Em.Emit("job.add", rt.UserDataValue(jb.ud)) | ||||
| 	hooks.Emit("job.add", rt.UserDataValue(jb.ud)) | ||||
| 
 | ||||
| 	return jb | ||||
| } | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| Subproject commit d60cd77c73875b5bb55e5a2fdc30bae01a7ac499 | ||||
| Subproject commit 34a57c964590f89aa065188a588c7b38aff99c28 | ||||
							
								
								
									
										28
									
								
								lua.go
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								lua.go
									
									
									
									
									
								
							| @ -12,12 +12,16 @@ import ( | ||||
| 
 | ||||
| 	rt "github.com/arnodel/golua/runtime" | ||||
| 	"github.com/arnodel/golua/lib" | ||||
| 	"github.com/arnodel/golua/lib/debuglib" | ||||
| ) | ||||
| 
 | ||||
| var minimalconf = `hilbish.prompt '& '` | ||||
| 
 | ||||
| func luaInit() { | ||||
| 	l = rt.New(os.Stdout) | ||||
| 	l.PushContext(rt.RuntimeContextDef{ | ||||
| 		MessageHandler: debuglib.Traceback, | ||||
| 	}) | ||||
| 	lib.LoadAll(l) | ||||
| 
 | ||||
| 	lib.LoadLibs(l, hilbishLoader) | ||||
| @ -28,26 +32,40 @@ func luaInit() { | ||||
| 	lib.LoadLibs(l, fs.Loader) | ||||
| 	lib.LoadLibs(l, terminal.Loader) | ||||
| 
 | ||||
| 	cmds := commander.New() | ||||
| 	cmds := commander.New(l) | ||||
| 	// When a command from Lua is added, register it for use | ||||
| 	cmds.Events.On("commandRegister", func(cmdName string, cmd *rt.Closure) { | ||||
| 	cmds.Events.On("commandRegister", func(args ...interface{}) { | ||||
| 		cmdName := args[0].(string) | ||||
| 		cmd := args[1].(*rt.Closure) | ||||
| 
 | ||||
| 		commands[cmdName] = cmd | ||||
| 	}) | ||||
| 	cmds.Events.On("commandDeregister", func(cmdName string) { | ||||
| 	cmds.Events.On("commandDeregister", func(args ...interface{}) { | ||||
| 		cmdName := args[0].(string) | ||||
| 
 | ||||
| 		delete(commands, cmdName) | ||||
| 	}) | ||||
| 	lib.LoadLibs(l, cmds.Loader) | ||||
| 
 | ||||
| 	hooks = bait.New() | ||||
| 	hooks = bait.New(l) | ||||
| 	hooks.SetRecoverer(func(event string, handler *bait.Listener, err interface{}) { | ||||
| 		fmt.Println("Error in `error` hook handler:", err) | ||||
| 		hooks.Off(event, handler) | ||||
| 	}) | ||||
| 
 | ||||
| 	lib.LoadLibs(l, hooks.Loader) | ||||
| 
 | ||||
| 	// Add Ctrl-C handler | ||||
| 	hooks.Em.On("signal.sigint", func() { | ||||
| 	hooks.On("signal.sigint", func(...interface{}) { | ||||
| 		if !interactive { | ||||
| 			os.Exit(0) | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	lr.rl.RawInputCallback = func(r []rune) { | ||||
| 		hooks.Emit("hilbish.rawInput", string(r)) | ||||
| 	} | ||||
| 
 | ||||
| 	// Add more paths that Lua can require from | ||||
| 	err := util.DoString(l, "package.path = package.path .. " + requirePaths) | ||||
| 	if err != nil { | ||||
|  | ||||
							
								
								
									
										23
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								main.go
									
									
									
									
									
								
							| @ -30,7 +30,7 @@ var ( | ||||
| 	userDataDir string | ||||
| 	curuser *user.User | ||||
| 
 | ||||
| 	hooks bait.Bait | ||||
| 	hooks *bait.Bait | ||||
| 	defaultConfPath string | ||||
| 	defaultHistPath string | ||||
| ) | ||||
| @ -116,8 +116,8 @@ func main() { | ||||
| 	} | ||||
| 
 | ||||
| 	go handleSignals() | ||||
| 	luaInit() | ||||
| 	lr = newLineReader("", false) | ||||
| 	luaInit() | ||||
| 	// If user's config doesn't exixt, | ||||
| 	if _, err := os.Stat(defaultConfPath); os.IsNotExist(err) && *configflag == defaultConfPath { | ||||
| 		// Read default from current directory | ||||
| @ -138,6 +138,7 @@ func main() { | ||||
| 	} else { | ||||
| 		runConfig(*configflag) | ||||
| 	} | ||||
| 	hooks.Emit("hilbish.init") | ||||
| 
 | ||||
| 	if fileInfo, _ := os.Stdin.Stat(); (fileInfo.Mode() & os.ModeCharDevice) == 0 { | ||||
| 		scanner := bufio.NewScanner(bufio.NewReader(os.Stdin)) | ||||
| @ -176,15 +177,18 @@ input: | ||||
| 
 | ||||
| 		if err == io.EOF { | ||||
| 			// Exit if user presses ^D (ctrl + d) | ||||
| 			hooks.Em.Emit("hilbish.exit") | ||||
| 			hooks.Emit("hilbish.exit") | ||||
| 			break | ||||
| 		} | ||||
| 		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 | ||||
| 				fmt.Fprintln(os.Stderr, err) | ||||
| 			} | ||||
| 			fmt.Println("^C") | ||||
| 			// TODO: Halt if any other error occurs | ||||
| 			continue | ||||
| 		} | ||||
| 		var priv bool | ||||
| @ -195,7 +199,7 @@ input: | ||||
| 		input = strings.TrimSpace(input) | ||||
| 		if len(input) == 0 { | ||||
| 			running = true | ||||
| 			hooks.Em.Emit("command.exit", 0) | ||||
| 			hooks.Emit("command.exit", 0) | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| @ -226,7 +230,7 @@ input: | ||||
| } | ||||
| 
 | ||||
| func continuePrompt(prev string) (string, error) { | ||||
| 	hooks.Em.Emit("multiline", nil) | ||||
| 	hooks.Emit("multiline", nil) | ||||
| 	lr.SetPrompt(multilinePrompt) | ||||
| 	cont, err := lr.Read() | ||||
| 	if err != nil { | ||||
| @ -268,11 +272,6 @@ func fmtPrompt(prompt string) string { | ||||
| 	return nprompt | ||||
| } | ||||
| 
 | ||||
| func handleHistory(cmd string) { | ||||
| 	lr.AddHistory(cmd) | ||||
| 	// TODO: load history again (history shared between sessions like this ye) | ||||
| } | ||||
| 
 | ||||
| func removeDupes(slice []string) []string { | ||||
| 	all := make(map[string]bool) | ||||
| 	newSlice := []string{} | ||||
|  | ||||
							
								
								
									
										25
									
								
								nature/commands/cat.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								nature/commands/cat.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| local commander = require 'commander' | ||||
| local fs = require 'fs' | ||||
| 
 | ||||
| commander.register('cat', function(args) | ||||
| 	local exit = 0 | ||||
| 
 | ||||
| 	if #args == 0 then | ||||
| 		print [[ | ||||
| usage: cat [file]...]] | ||||
| 	end | ||||
| 
 | ||||
| 	for _, fName in ipairs(args) do | ||||
| 		local f = io.open(fName) | ||||
| 		if f == nil then | ||||
| 			exit = 1 | ||||
| 			print(string.format('cat: %s: no such file or directory', fName)) | ||||
| 			goto continue | ||||
| 		end | ||||
| 
 | ||||
| 		io.write(f:read '*a') | ||||
| 		::continue:: | ||||
| 	end | ||||
| 	io.flush() | ||||
| 	return exit | ||||
| end) | ||||
							
								
								
									
										7
									
								
								nature/commands/clear.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								nature/commands/clear.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| local ansikit = require 'ansikit' | ||||
| local commander = require 'commander' | ||||
| 
 | ||||
| commander.register('clear', function() | ||||
| 	ansikit.clear(true) | ||||
| 	ansikit.cursorTo(0, 0) | ||||
| end) | ||||
							
								
								
									
										5
									
								
								nature/commands/exec.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								nature/commands/exec.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| local commander = require 'commander' | ||||
| 
 | ||||
| commander.register('exec', function(args) | ||||
| 	hilbish.exec(args[1]) | ||||
| end) | ||||
| @ -1,54 +0,0 @@ | ||||
| local ansikit = require 'ansikit' | ||||
| local commander = require 'commander' | ||||
| 
 | ||||
| local helpTexts = { | ||||
| [[ | ||||
| Hello there! Welcome to Hilbish, the comfy and nice little shell for | ||||
| Lua users and fans. Hilbish is configured with Lua, and its | ||||
| scripts are also in Lua. It also runs both Lua and shell script when | ||||
| interactive (aka normal usage). | ||||
| ]], | ||||
| [[ | ||||
| What does that mean for you, the user? It means that if you prefer to | ||||
| use Lua for scripting instead of shell script but still have ordinary | ||||
| shell usage for interactive use. | ||||
| ]], | ||||
| [[ | ||||
| If this is your first time using Hilbish and Lua, check out the | ||||
| Programming in Lua book here: https://www.lua.org/pil | ||||
| After (or if you already know Lua) check out the doc command. | ||||
| It is an in shell tool for documentation about Hilbish provided | ||||
| functions and modules. | ||||
| ]], | ||||
| [[ | ||||
| If you've updated from a pre-1.0 version (0.7.1 as an example) | ||||
| you'll want to move your config from ~/.hilbishrc.lua to | ||||
| ]] .. | ||||
| hilbish.userDir.config .. '/hilbish/init.lua' .. | ||||
| [[ | ||||
| 
 | ||||
| and also change all global functions (prompt, alias) to be | ||||
| in the hilbish module (hilbish.prompt, hilbish.alias as examples). | ||||
| 
 | ||||
| And if this is your first time (most likely), you can copy a config | ||||
| from ]] .. hilbish.dataDir, | ||||
| [[ | ||||
| Since 1.0 is a big release, you'll want to check the changelog | ||||
| at https://github.com/Rosettea/Hilbish/releases/tag/v1.0.0 | ||||
| to find more breaking changes. | ||||
| ]] | ||||
| } | ||||
| commander.register('guide', function() | ||||
| 	ansikit.clear() | ||||
| 	ansikit.cursorTo(0, 0) | ||||
| 	for _, text in ipairs(helpTexts) do | ||||
| 		print(text) | ||||
| 		local out = hilbish.read('Hit enter to continue ') | ||||
| 		ansikit.clear() | ||||
| 		ansikit.cursorTo(0, 0) | ||||
| 		if not out then | ||||
| 			return | ||||
| 		end | ||||
| 	end | ||||
| 	print 'Hope you enjoy using Hilbish!' | ||||
| end) | ||||
| @ -1,9 +1,19 @@ | ||||
| -- Add command builtins | ||||
| require 'nature.commands.cd' | ||||
| require 'nature.commands.cdr' | ||||
| require 'nature.commands.doc' | ||||
| require 'nature.commands.exit' | ||||
| require 'nature.commands.guide' | ||||
| require 'nature.commands.disown' | ||||
| require 'nature.commands.fg' | ||||
| require 'nature.commands.bg' | ||||
| local fs = require 'fs' | ||||
| 
 | ||||
| -- explanation: this specific function gives to us info about | ||||
| -- the currently running source. this includes a path to the | ||||
| -- source file (info.source) | ||||
| -- we will use that to automatically load all commands by reading | ||||
| -- all the files in this dir and just requiring it. | ||||
| local info = debug.getinfo(1) | ||||
| local commandDir = fs.dir(info.source) | ||||
| if commandDir == '.' then return end | ||||
| 
 | ||||
| local commands = fs.readdir(commandDir) | ||||
| for _, command in ipairs(commands) do | ||||
| 	local name = command:gsub('%.lua', '') -- chop off extension | ||||
| 	if name ~= 'init' then | ||||
| 		-- skip this file (for obvious reasons) | ||||
| 		require('nature.commands.' .. name) | ||||
| 	end | ||||
| end | ||||
|  | ||||
| @ -24,7 +24,7 @@ function hilbish.completion.handler(line, pos) | ||||
| 		return {compGroup}, pfx | ||||
| 	else | ||||
| 		local ok, compGroups, pfx = pcall(hilbish.completion.call, | ||||
| 		'command.' .. #fields[1], query, ctx, fields) | ||||
| 		'command.' .. fields[1], query, ctx, fields) | ||||
| 		if ok then | ||||
| 			return compGroups, pfx | ||||
| 		end | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| -- Prelude initializes everything else for our shell | ||||
| local _ = require 'succulent' -- Function additions | ||||
| local bait = require 'bait' | ||||
| local fs = require 'fs' | ||||
| 
 | ||||
| package.path = package.path .. ';' .. hilbish.dataDir .. '/?/init.lua' | ||||
| @ -28,7 +29,9 @@ do | ||||
| 				return got_virt | ||||
| 			end | ||||
| 
 | ||||
| 			if type(key) == 'string' then | ||||
| 				virt_G[key] = os.getenv(key) | ||||
| 			end | ||||
| 			return virt_G[key] | ||||
| 		end, | ||||
| 
 | ||||
| @ -54,7 +57,6 @@ do | ||||
| 	if ok then | ||||
| 		for _, module in ipairs(modules) do | ||||
| 			local entry = package.searchpath(module, startSearchPath) | ||||
| 			print(entry) | ||||
| 			if entry then | ||||
| 				dofile(entry) | ||||
| 			end | ||||
| @ -63,3 +65,15 @@ do | ||||
| 
 | ||||
| 	package.path = package.path .. ';' .. startSearchPath | ||||
| end | ||||
| 
 | ||||
| bait.catch('error', function(event, handler, err) | ||||
| 	bait.release(event, handler) | ||||
| 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,13 +1,8 @@ | ||||
| local fs = require 'fs' | ||||
| 
 | ||||
| function cdHandle(inp) | ||||
| 	local res = hilbish.runner.lua(inp) | ||||
| 
 | ||||
| 	if not res.err then | ||||
| 		return res | ||||
| 	end | ||||
| 
 | ||||
| 	res = hilbish.runner.sh(inp) | ||||
| local oldShRunner = hilbish.runner.sh | ||||
| function hilbish.runner.sh(input) | ||||
| 	local res = oldShRunner(input) | ||||
| 
 | ||||
| 	if res.exit ~= 0 and hilbish.opts.autocd then | ||||
| 		local ok, stat = pcall(fs.stat, res.input) | ||||
| @ -21,5 +16,3 @@ function cdHandle(inp) | ||||
| 
 | ||||
| 	return res | ||||
| end | ||||
| 
 | ||||
| hilbish.runner.setMode(cdHandle) | ||||
|  | ||||
							
								
								
									
										8
									
								
								nature/opts/greeting.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								nature/opts/greeting.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| local bait = require 'bait' | ||||
| local lunacolors = require 'lunacolors' | ||||
| 
 | ||||
| bait.catch('hilbish.init', function() | ||||
| 	if hilbish.interactive and type(hilbish.opts.greeting) == 'string' then | ||||
| 		print(lunacolors.format(hilbish.opts.greeting)) | ||||
| 	end | ||||
| end) | ||||
							
								
								
									
										6
									
								
								nature/opts/history.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								nature/opts/history.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| local bait = require 'bait' | ||||
| 
 | ||||
| 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 | ||||
| end) | ||||
| @ -20,7 +20,12 @@ local function setupOpt(name, default) | ||||
| end | ||||
| 
 | ||||
| local defaultOpts = { | ||||
| 	autocd = false | ||||
| 	autocd = false, | ||||
| 	history = true, | ||||
| 	greeting = string.format([[Welcome to {magenta}Hilbish{reset}, {cyan}%s{reset}. | ||||
| The nice lil shell for {blue}Lua{reset} fanatics! | ||||
| ]], hilbish.user), | ||||
| 	motd = true | ||||
| } | ||||
| 
 | ||||
| for optsName, default in pairs(defaultOpts) do | ||||
|  | ||||
							
								
								
									
										13
									
								
								nature/opts/motd.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								nature/opts/motd.lua
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| local bait = require 'bait' | ||||
| local lunacolors = require 'lunacolors' | ||||
| 
 | ||||
| hilbish.motd = [[ | ||||
| Hilbish 2.0 is a {red}major{reset} update! If your config doesn't work | ||||
| anymore, that will definitely be why! A MOTD, very message, much day. | ||||
| ]] | ||||
| 
 | ||||
| bait.catch('hilbish.init', function() | ||||
| 	if hilbish.interactive and hilbish.opts.motd then | ||||
| 		print(lunacolors.format(hilbish.motd)) | ||||
| 	end | ||||
| end) | ||||
| @ -4,6 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"github.com/rivo/uniseg" | ||||
| )	 | ||||
| 
 | ||||
| // initGrid - Grid display details. Called each time we want to be sure to have | ||||
| @ -13,8 +14,8 @@ func (g *CompletionGroup) initGrid(rl *Instance) { | ||||
| 	// Compute size of each completion item box | ||||
| 	tcMaxLength := 1 | ||||
| 	for i := range g.Suggestions { | ||||
| 		if len(g.Suggestions[i]) > tcMaxLength { | ||||
| 			tcMaxLength = len([]rune(g.Suggestions[i])) | ||||
| 		if uniseg.GraphemeClusterCount(g.Suggestions[i]) > tcMaxLength { | ||||
| 			tcMaxLength = uniseg.GraphemeClusterCount(g.Suggestions[i]) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -99,11 +100,11 @@ func (g *CompletionGroup) writeGrid(rl *Instance) (comp string) { | ||||
| 
 | ||||
| 	// If group title, print it and adjust offset. | ||||
| 	if g.Name != "" { | ||||
| 		comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, g.Name, RESET) | ||||
| 		comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, fmtEscape(g.Name), RESET) | ||||
| 		rl.tcUsedY++ | ||||
| 	} | ||||
| 
 | ||||
| 	cellWidth := strconv.Itoa((GetTermWidth() / g.tcMaxX) - 2) | ||||
| 	cellWidth := strconv.Itoa((GetTermWidth() / g.tcMaxX) - 4) | ||||
| 	x := 0 | ||||
| 	y := 1 | ||||
| 
 | ||||
| @ -124,7 +125,15 @@ func (g *CompletionGroup) writeGrid(rl *Instance) (comp string) { | ||||
| 			comp += seqInvert | ||||
| 		} | ||||
| 
 | ||||
| 		comp += fmt.Sprintf("%-"+cellWidth+"s %s", 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 | ||||
|  | ||||
| @ -1,5 +1,7 @@ | ||||
| package readline | ||||
| 
 | ||||
| import "strings" | ||||
| 
 | ||||
| // CompletionGroup - A group/category of items offered to completion, with its own | ||||
| // name, descriptions and completion display format/type. | ||||
| // The output, if there are multiple groups available for a given completion input, | ||||
| @ -285,3 +287,7 @@ func (g *CompletionGroup) goLastCell() { | ||||
| 		g.tcPosX = 0 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func fmtEscape(s string) string { | ||||
| 	return strings.Replace(s, "%", "%%", -1) | ||||
| } | ||||
|  | ||||
| @ -206,12 +206,12 @@ func (g *CompletionGroup) writeList(rl *Instance) (comp string) { | ||||
| 		if len(item) > maxLength { | ||||
| 			item = item[:maxLength-3] + "..." | ||||
| 		} | ||||
| 		sugg := fmt.Sprintf("\r%s%-"+cellWidth+"s", highlight(y, 0), item) | ||||
| 		sugg := fmt.Sprintf("\r%s%-"+cellWidth+"s", highlight(y, 0), fmtEscape(item)) | ||||
| 
 | ||||
| 		// Alt suggestion | ||||
| 		alt, ok := g.Aliases[item] | ||||
| 		if ok { | ||||
| 			alt = fmt.Sprintf(" %s%"+cellWidthAlt+"s", highlight(y, 1), alt) | ||||
| 			alt = fmt.Sprintf(" %s%"+cellWidthAlt+"s", highlight(y, 1), fmtEscape(alt)) | ||||
| 		} else { | ||||
| 			// Else, make an empty cell | ||||
| 			alt = strings.Repeat(" ", maxLengthAlt+1) // + 2 to keep account of spaces | ||||
|  | ||||
| @ -76,7 +76,7 @@ func (g *CompletionGroup) writeMap(rl *Instance) (comp string) { | ||||
| 
 | ||||
| 	if g.Name != "" { | ||||
| 		// Print group title (changes with line returns depending on type) | ||||
| 		comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, g.Name, RESET) | ||||
| 		comp += fmt.Sprintf("%s%s%s %s\n", BOLD, YELLOW, fmtEscape(g.Name), RESET) | ||||
| 		rl.tcUsedY++ | ||||
| 	} | ||||
| 
 | ||||
| @ -126,7 +126,7 @@ func (g *CompletionGroup) writeMap(rl *Instance) (comp string) { | ||||
| 		} | ||||
| 
 | ||||
| 		comp += fmt.Sprintf("\r%-"+cellWidth+"s %s %-"+itemWidth+"s %s\n", | ||||
| 			description, highlight(y), item, seqReset) | ||||
| 			description, highlight(y), fmtEscape(item), seqReset) | ||||
| 	} | ||||
| 
 | ||||
| 	// Add the equivalent of this group's size to final screen clearing | ||||
|  | ||||
| @ -123,23 +123,20 @@ func (rl *Instance) walkHistory(i int) { | ||||
| 
 | ||||
| 	// When we are exiting the current line buffer to move around | ||||
| 	// 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) | ||||
| 	} | ||||
| 
 | ||||
| 	switch rl.histPos + i { | ||||
| 	case 0, history.Len() + 1: | ||||
| 		rl.histPos = 0 | ||||
| 	rl.histOffset += i | ||||
| 	if rl.histOffset == 0 { | ||||
| 		rl.line = []rune(rl.lineBuf) | ||||
| 		rl.pos = len(rl.lineBuf) | ||||
| 		return | ||||
| 	case -1: | ||||
| 		rl.histPos = 0 | ||||
| 		rl.lineBuf = string(rl.line) | ||||
| 	default: | ||||
| 	} else if rl.histOffset <= -1 { | ||||
| 		rl.histOffset = 0 | ||||
| 	} else { | ||||
| 		dedup = true | ||||
| 		old = string(rl.line) | ||||
| 		new, err = history.GetLine(history.Len() - rl.histPos - 1) | ||||
| 		new, err = history.GetLine(history.Len() - rl.histOffset) | ||||
| 		if err != nil { | ||||
| 			rl.resetHelpers() | ||||
| 			print("\r\n" + err.Error() + "\r\n") | ||||
| @ -148,7 +145,6 @@ func (rl *Instance) walkHistory(i int) { | ||||
| 		} | ||||
| 
 | ||||
| 		rl.clearLine() | ||||
| 		rl.histPos += i | ||||
| 		rl.line = []rune(new) | ||||
| 		rl.pos = len(rl.line) | ||||
| 		if rl.pos > 0 { | ||||
|  | ||||
| @ -134,6 +134,7 @@ type Instance struct { | ||||
| 	// history operating params | ||||
| 	lineBuf    string | ||||
| 	histPos    int | ||||
| 	histOffset int | ||||
| 	histNavIdx int // Used for quick history navigation. | ||||
| 
 | ||||
| 	// | ||||
| @ -198,6 +199,8 @@ type Instance struct { | ||||
| 
 | ||||
| 	ViModeCallback func(ViMode) | ||||
| 	ViActionCallback func(ViAction, []string) | ||||
| 
 | ||||
| 	RawInputCallback func([]rune) // called on all input | ||||
| } | ||||
| 
 | ||||
| // NewInstance is used to create a readline instance and initialise it with sane defaults. | ||||
|  | ||||
| @ -18,7 +18,7 @@ func (rl *Instance) updateLine(line []rune) { | ||||
| 
 | ||||
| // getLine - In many places we need the current line input. We either return the real line, | ||||
| // or the one that includes the current completion candidate, if there is any. | ||||
| func (rl *Instance) getLine() []rune { | ||||
| func (rl *Instance) GetLine() []rune { | ||||
| 	if len(rl.currentComp) > 0 { | ||||
| 		return rl.lineComp | ||||
| 	} | ||||
|  | ||||
| @ -4,7 +4,6 @@ import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	ansi "github.com/acarl005/stripansi" | ||||
| 	"github.com/rivo/uniseg" | ||||
| ) | ||||
| 
 | ||||
| // SetPrompt will define the readline prompt string. | ||||
| @ -209,7 +208,7 @@ func (rl *Instance) colorizeVimPrompt(p []rune) (cp []rune) { | ||||
| // getting its real-printed length. | ||||
| func getRealLength(s string) (l int) { | ||||
| 	stripped := ansi.Strip(s) | ||||
| 	return uniseg.GraphemeClusterCount(stripped) | ||||
| 	return getWidth([]rune(stripped)) | ||||
| } | ||||
| 
 | ||||
| func (rl *Instance) echoRightPrompt() { | ||||
|  | ||||
| @ -49,7 +49,7 @@ func (rl *Instance) Readline() (string, error) { | ||||
| 
 | ||||
| 	// History Init | ||||
| 	// 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}} | ||||
| 
 | ||||
| 	// Multisplit | ||||
| @ -94,6 +94,9 @@ func (rl *Instance) Readline() (string, error) { | ||||
| 
 | ||||
| 		rl.skipStdinRead = false | ||||
| 		r := []rune(string(b)) | ||||
| 		if rl.RawInputCallback != nil { | ||||
| 			rl.RawInputCallback(r[:i]) | ||||
| 		} | ||||
| 
 | ||||
| 		if isMultiline(r[:i]) || len(rl.multiline) > 0 { | ||||
| 			rl.multiline = append(rl.multiline, b[:i]...) | ||||
| @ -235,7 +238,9 @@ func (rl *Instance) Readline() (string, error) { | ||||
| 
 | ||||
| 			// Normal completion search does only refresh the search pattern and the comps | ||||
| 			if rl.modeTabFind || rl.modeAutoFind { | ||||
| 				rl.resetVirtualComp(false) | ||||
| 				rl.backspaceTabFind() | ||||
| 				rl.renderHelpers() | ||||
| 				rl.viUndoSkipAppend = true | ||||
| 			} else { | ||||
| 				// Always cancel any virtual completion | ||||
| @ -328,6 +333,8 @@ func (rl *Instance) Readline() (string, error) { | ||||
| 
 | ||||
| 			rl.modeTabFind = true | ||||
| 			rl.updateTabFind([]rune{}) | ||||
| 			rl.updateVirtualComp() | ||||
| 			rl.renderHelpers() | ||||
| 			rl.viUndoSkipAppend = true | ||||
| 
 | ||||
| 		// Tab Completion & Completion Search --------------------------------------------------------------- | ||||
| @ -481,7 +488,10 @@ func (rl *Instance) Readline() (string, error) { | ||||
| 				if string(r[:i]) != seqShiftTab && | ||||
| 					string(r[:i]) != seqForwards && string(r[:i]) != seqBackwards && | ||||
| 					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) | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| @ -514,7 +524,9 @@ func (rl *Instance) Readline() (string, error) { | ||||
| 			if rl.modeAutoFind || rl.modeTabFind { | ||||
| 				rl.resetVirtualComp(false) | ||||
| 				rl.updateTabFind(r[:i]) | ||||
| 				rl.renderHelpers() | ||||
| 				rl.viUndoSkipAppend = true | ||||
| 				continue | ||||
| 			} else { | ||||
| 				rl.resetVirtualComp(false) | ||||
| 				rl.editorInput(r[:i]) | ||||
| @ -534,6 +546,10 @@ func (rl *Instance) Readline() (string, error) { | ||||
| // entry readline is currently configured for and then update the line entries | ||||
| // accordingly. | ||||
| func (rl *Instance) editorInput(r []rune) { | ||||
| 	if len(r) == 0 { | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	switch rl.modeViMode { | ||||
| 	case VimKeys: | ||||
| 		rl.vi(r[0]) | ||||
| @ -601,6 +617,7 @@ func (rl *Instance) escapeSeq(r []rune) { | ||||
| 	case string(charEscape): | ||||
| 		switch { | ||||
| 		case rl.modeAutoFind: | ||||
| 			rl.resetVirtualComp(true) | ||||
| 			rl.resetTabFind() | ||||
| 			rl.clearHelpers() | ||||
| 			rl.resetTabCompletion() | ||||
| @ -608,6 +625,7 @@ func (rl *Instance) escapeSeq(r []rune) { | ||||
| 			rl.renderHelpers() | ||||
| 
 | ||||
| 		case rl.modeTabFind: | ||||
| 			rl.resetVirtualComp(true) | ||||
| 			rl.resetTabFind() | ||||
| 			rl.resetTabCompletion() | ||||
| 
 | ||||
|  | ||||
| @ -2,6 +2,7 @@ package readline | ||||
| 
 | ||||
| import ( | ||||
| 	"strings" | ||||
| 	"github.com/rivo/uniseg" | ||||
| ) | ||||
| 
 | ||||
| // 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 | ||||
| 	case pos >= len(word)-1: | ||||
| 		word = rTrimWhiteSpace(split[index+1]) | ||||
| 		adjust = len(split[index]) - pos | ||||
| 		adjust += len(word) - 1 | ||||
| 		adjust = uniseg.GraphemeClusterCount(split[index]) - pos | ||||
| 		adjust += uniseg.GraphemeClusterCount(word) - 1 | ||||
| 	default: | ||||
| 		adjust = len(word) - pos - 1 | ||||
| 		adjust = uniseg.GraphemeClusterCount(word) - pos - 1 | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| @ -24,7 +24,7 @@ func delayedSyntaxTimer(rl *Instance, i int64) { | ||||
| 	// } | ||||
| 
 | ||||
| 	// We pass either the current line or the one with the current completion. | ||||
| 	newLine := rl.DelayedSyntaxWorker(rl.getLine()) | ||||
| 	newLine := rl.DelayedSyntaxWorker(rl.GetLine()) | ||||
| 	var sLine string | ||||
| 	count := atomic.LoadInt64(&rl.delayedSyntaxCount) | ||||
| 	if count != i { | ||||
|  | ||||
| @ -1,6 +1,10 @@ | ||||
| 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: | ||||
| // it should coordinate reprinting the input line, any Infos and completions | ||||
| @ -52,19 +56,19 @@ func (rl *Instance) updateReferences() { | ||||
| 	rl.posY = 0 | ||||
| 	rl.fullY = 0 | ||||
| 
 | ||||
| 	var fullLine, cPosLine int | ||||
| 	var curLine []rune | ||||
| 	if len(rl.currentComp) > 0 { | ||||
| 		fullLine = getWidth(rl.lineComp) | ||||
| 		cPosLine = getWidth(rl.lineComp[:rl.pos]) | ||||
| 		curLine = rl.lineComp | ||||
| 	} else { | ||||
| 		fullLine = getWidth(rl.line) | ||||
| 		cPosLine = getWidth(rl.line[:rl.pos]) | ||||
| 		curLine = rl.line | ||||
| 	} | ||||
| 	fullLine := getWidth(curLine) | ||||
| 	cPosLine := getWidth(curLine[:rl.pos]) | ||||
| 
 | ||||
| 	// We need the X offset of the whole line | ||||
| 	toEndLine := rl.promptLen + fullLine | ||||
| 	fullOffset := toEndLine / GetTermWidth() | ||||
| 	rl.fullY = fullOffset | ||||
| 	rl.fullY = fullOffset + strings.Count(string(curLine), "\n") | ||||
| 	fullRest := toEndLine % GetTermWidth() | ||||
| 	rl.fullX = fullRest | ||||
| 
 | ||||
|  | ||||
| @ -245,7 +245,7 @@ func (rl *Instance) vi(r rune) { | ||||
| 		} | ||||
| 
 | ||||
| 		// Keep the previous cursor position | ||||
| 		prev := rl.pos | ||||
| 		//prev := rl.pos | ||||
| 
 | ||||
| 		new, err := rl.StartEditorWithBuffer(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. | ||||
| 		rl.clearLine() | ||||
| 		rl.line = new | ||||
| 		if prev > len(rl.line) { | ||||
| 			rl.pos = len(rl.line) - 1 | ||||
| 		rl.pos = len(rl.line) | ||||
| 		/*if prev > len(rl.line) { | ||||
| 		} else { | ||||
| 			rl.pos = prev | ||||
| 		} | ||||
| 		}*/ | ||||
| 
 | ||||
| 	case 'w': | ||||
| 		// If we were not yanking | ||||
|  | ||||
							
								
								
									
										32
									
								
								rl.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								rl.go
									
									
									
									
									
								
							| @ -13,18 +13,22 @@ import ( | ||||
| 
 | ||||
| type lineReader struct { | ||||
| 	rl *readline.Instance | ||||
| 	fileHist *fileHistory | ||||
| } | ||||
| var fileHist *fileHistory | ||||
| var hinter *rt.Closure | ||||
| var highlighter *rt.Closure | ||||
| 
 | ||||
| func newLineReader(prompt string, noHist bool) *lineReader { | ||||
| 	rl := readline.NewInstance() | ||||
| 	lr := &lineReader{ | ||||
| 		rl: rl, | ||||
| 	} | ||||
| 
 | ||||
| 	// we don't mind hilbish.read rl instances having completion, | ||||
| 	// but it cant have shared history | ||||
| 	if !noHist { | ||||
| 		fileHist = newFileHistory() | ||||
| 		rl.SetHistoryCtrlR("History", fileHist) | ||||
| 		lr.fileHist = newFileHistory(defaultHistPath) | ||||
| 		rl.SetHistoryCtrlR("History", &luaHistory{}) | ||||
| 		rl.HistoryAutoWrite = false | ||||
| 	} | ||||
| 	rl.ShowVimMode = false | ||||
| @ -44,14 +48,14 @@ func newLineReader(prompt string, noHist bool) *lineReader { | ||||
| 			case readline.VimActionPaste: actionStr = "paste" | ||||
| 			case readline.VimActionYank: actionStr = "yank" | ||||
| 		} | ||||
| 		hooks.Em.Emit("hilbish.vimAction", actionStr, args) | ||||
| 		hooks.Emit("hilbish.vimAction", actionStr, args) | ||||
| 	} | ||||
| 	rl.HintText = func(line []rune, pos int) []rune { | ||||
| 		if hinter == nil { | ||||
| 			return []rune{} | ||||
| 		} | ||||
| 
 | ||||
| 		retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(highlighter), | ||||
| 		retVal, err := rt.Call1(l.MainThread(), rt.FunctionValue(hinter), | ||||
| 		rt.StringValue(string(line)), rt.IntValue(int64(pos))) | ||||
| 		if err != nil { | ||||
| 			fmt.Println(err) | ||||
| @ -171,13 +175,11 @@ func newLineReader(prompt string, noHist bool) *lineReader { | ||||
| 		return pfx, compGroups | ||||
| 	} | ||||
| 
 | ||||
| 	return &lineReader{ | ||||
| 		rl, | ||||
| 	} | ||||
| 	return lr | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) Read() (string, error) { | ||||
| 	hooks.Em.Emit("command.precmd", nil) | ||||
| 	hooks.Emit("command.precmd", nil) | ||||
| 	s, err := lr.rl.Readline() | ||||
| 	// this is so dumb | ||||
| 	if err == readline.EOF { | ||||
| @ -212,7 +214,7 @@ func (lr *lineReader) SetRightPrompt(p string) { | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) AddHistory(cmd string) { | ||||
| 	fileHist.Write(cmd) | ||||
| 	lr.fileHist.Write(cmd) | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) ClearInput() { | ||||
| @ -253,7 +255,7 @@ func (lr *lineReader) luaAddHistory(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(fileHist.Len()))), nil | ||||
| 	return c.PushingNext1(t.Runtime, rt.IntValue(int64(lr.fileHist.Len()))), nil | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| @ -265,17 +267,17 @@ func (lr *lineReader) luaGetHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	cmd, _ := fileHist.GetLine(int(idx)) | ||||
| 	cmd, _ := lr.fileHist.GetLine(int(idx)) | ||||
| 
 | ||||
| 	return c.PushingNext1(t.Runtime, rt.StringValue(cmd)), nil | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	tbl := rt.NewTable() | ||||
| 	size := fileHist.Len() | ||||
| 	size := lr.fileHist.Len() | ||||
| 
 | ||||
| 	for i := 1; i < size; i++ { | ||||
| 		cmd, _ := fileHist.GetLine(i) | ||||
| 		cmd, _ := lr.fileHist.GetLine(i) | ||||
| 		tbl.Set(rt.IntValue(int64(i)), rt.StringValue(cmd)) | ||||
| 	} | ||||
| 
 | ||||
| @ -283,6 +285,6 @@ func (lr *lineReader) luaAllHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) | ||||
| } | ||||
| 
 | ||||
| func (lr *lineReader) luaClearHistory(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 	fileHist.clear() | ||||
| 	lr.fileHist.clear() | ||||
| 	return c.Next(), nil | ||||
| } | ||||
|  | ||||
| @ -28,13 +28,13 @@ func shRunner(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	input, exitCode, cont, err := handleSh(cmd) | ||||
| 	_, exitCode, cont, err := execSh(aliases.Resolve(cmd)) | ||||
| 	var luaErr rt.Value = rt.NilValue | ||||
| 	if err != nil { | ||||
| 		luaErr = rt.StringValue(err.Error()) | ||||
| 	} | ||||
| 	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("continue"), rt.BoolValue(cont)) | ||||
| 	runnerRet.Set(rt.StringValue("err"), luaErr) | ||||
|  | ||||
| @ -15,11 +15,11 @@ func handleSignals() { | ||||
| 
 | ||||
| 	for s := range c { | ||||
| 		switch s { | ||||
| 		case os.Interrupt: hooks.Em.Emit("signal.sigint") | ||||
| 		case os.Interrupt: hooks.Emit("signal.sigint") | ||||
| 		case syscall.SIGTERM: exit(0) | ||||
| 		case syscall.SIGWINCH: hooks.Em.Emit("signal.resize") | ||||
| 		case syscall.SIGUSR1: hooks.Em.Emit("signal.sigusr1") | ||||
| 		case syscall.SIGUSR2: hooks.Em.Emit("signal.sigusr2") | ||||
| 		case syscall.SIGWINCH: hooks.Emit("signal.resize") | ||||
| 		case syscall.SIGUSR1: hooks.Emit("signal.sigusr1") | ||||
| 		case syscall.SIGUSR2: hooks.Emit("signal.sigusr2") | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -14,7 +14,7 @@ func handleSignals() { | ||||
| 	for s := range c { | ||||
| 		switch s { | ||||
| 		case os.Interrupt: | ||||
| 			hooks.Em.Emit("signal.sigint") | ||||
| 			hooks.Emit("signal.sigint") | ||||
| 			if !running && interactive { | ||||
| 				lr.ClearInput() | ||||
| 			} | ||||
|  | ||||
							
								
								
									
										2
									
								
								vars.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								vars.go
									
									
									
									
									
								
							| @ -11,7 +11,7 @@ var ( | ||||
| 
 | ||||
| // Version info | ||||
| var ( | ||||
| 	ver = "v2.0.0" | ||||
| 	ver = "v2.0.0-rc1" | ||||
| 	releaseName = "Hibiscus" | ||||
| 	gitCommit string | ||||
| 	gitBranch string | ||||
|  | ||||
| @ -14,7 +14,7 @@ var ( | ||||
| 	.. hilbish.userDir.config	.. '/hilbish/?/init.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" | ||||
| 	sampleConfPath = dataDir + "/.hilbishrc.lua" // Path to default/sample config | ||||
| 	defaultConfDir = "" | ||||
|  | ||||
| @ -2,14 +2,16 @@ | ||||
| 
 | ||||
| package main | ||||
| 
 | ||||
| import "hilbish/util" | ||||
| 
 | ||||
| // String vars that are free to be changed at compile time | ||||
| var ( | ||||
| 	requirePaths = commonRequirePaths + `.. ';' | ||||
| 	.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\init.lua;' | ||||
| 	.. hilbish.userDir.config .. '\\Hilbish\\libs\\?\\?.lua;' | ||||
| 	.. hilbish.userDir.config .. '\\Hilbish\\libs\\?.lua;'` | ||||
| 	dataDir = "~\\Appdata\\Roaming\\Hilbish" // ~ and \ gonna cry? | ||||
| 	dataDir = util.ExpandHome("~\\Appdata\\Roaming\\Hilbish") // ~ and \ gonna cry? | ||||
| 	preloadPath = dataDir + "\\nature\\init.lua" | ||||
| 	sampleConfPath = dataDir + "\\hilbishrc.lua" // Path to default/sample config | ||||
| 	sampleConfPath = dataDir + "\\.hilbishrc.lua" // Path to default/sample config | ||||
| 	defaultConfDir = "" | ||||
| ) | ||||
|  | ||||
							
								
								
									
										0
									
								
								website/.hugo_build.lock
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								website/.hugo_build.lock
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								website/archetypes/default.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								website/archetypes/default.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| --- | ||||
| title: "{{ replace .Name "-" " " | title }}" | ||||
| date: {{ .Date }} | ||||
| draft: true | ||||
| --- | ||||
| 
 | ||||
							
								
								
									
										25
									
								
								website/config.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								website/config.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| baseURL = 'https://rosettea.github.io/Hilbish/' | ||||
| languageCode = 'en-us' | ||||
| title = 'Hilbish' | ||||
| theme = 'hsh' | ||||
| enableGitInfo = true | ||||
| 
 | ||||
| [menu] | ||||
| [[menu.nav]] | ||||
| 	identifier = 'home' | ||||
| 	name = 'Home' | ||||
| 	pageref = '/' | ||||
| 	weight = 1 | ||||
| [[menu.nav]] | ||||
| 	identifier = 'install' | ||||
| 	name = 'Install' | ||||
| 	pageref = '/install' | ||||
| 	weight = 2 | ||||
| [[menu.nav]] | ||||
| 	identifier = 'docs' | ||||
| 	name = 'Docs' | ||||
| 	pageref = '/docs' | ||||
| 	weight = 3 | ||||
| 	 | ||||
| [markup.goldmark.renderer] | ||||
| unsafe = true | ||||
							
								
								
									
										134
									
								
								website/content/_index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								website/content/_index.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | ||||
| --- | ||||
| description: 'Something Unique. Hilbish is the new interactive shell for Lua fans. Extensible, scriptable, configurable: All in Lua.' | ||||
| --- | ||||
| 
 | ||||
| [//]: <> | ||||
| 
 | ||||
| <!-- hugo (prob goldmark) is funny; the html wont work if its the first thing --> | ||||
| <div class="text-center"> | ||||
| 	<h1 class="fw-light">Something Unique.</h1> | ||||
| 		<p> | ||||
| 			<strong>Hilbish</strong> is the new interactive shell for Lua fans.<br> | ||||
| 			Extensible, scriptable, configurable: All in Lua. | ||||
| 		</p> | ||||
| 	<a href="install" class="btn btn-primary">Install</a> | ||||
| 	<a href="https://github.com/Rosettea/Hilbish" class="btn btn-secondary" target="_blank">Github</a> | ||||
| </div> | ||||
| 
 | ||||
| <hr> | ||||
| 
 | ||||
| <div class="row row-cols-1 row-cols-md-2 g-4"> | ||||
| 	<div class="col"> | ||||
| 		<div class="card border-light mb-3"> | ||||
| 			<div class="row g-0"> | ||||
| 				<div class="col-md-4"> | ||||
| 					<a href="https://safe.kashima.moe/6njmopm47u1x.png"> | ||||
| 						<img src="https://safe.kashima.moe/6njmopm47u1x.png" class="img-fluid rounded-start"> | ||||
| 					</a> | ||||
| 				</div> | ||||
| 				<div class="col-md-8"> | ||||
| 					<h5 class="card-header">Simple and Easy Scripting</h5> | ||||
| 					<div class="card-body"> | ||||
| 						<p class="card-text"> | ||||
| 							Hilbish is configured and scripted in the Lua programming language. | ||||
| 							This removes all the old, ugly things about Shell script and introduces | ||||
| 							everything good about Lua, including other languages (Moonscript & Fennel). | ||||
| 						</p> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="col"> | ||||
| 		<div class="card border-light mb-3"> | ||||
| 			<div class="row g-0"> | ||||
| 				<div class="col-md-4"> | ||||
| 					<a href="https://safe.kashima.moe/jkndbi636lzj.png"> | ||||
| 						<img src="https://safe.kashima.moe/jkndbi636lzj.png" class="img-fluid rounded-start"> | ||||
| 					</a> | ||||
| 				</div> | ||||
| 				<div class="col-md-8"> | ||||
| 					<h5 class="card-header">History and Completion Menus</h5> | ||||
| 					<div class="card-body"> | ||||
| 						<p class="card-text"> | ||||
| 							Hilbish provides the user with proper menus for completions, | ||||
| 							history searching. Want to see your previous commands? Hit Ctrl-R. | ||||
| 						</p> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="col"> | ||||
| 		<div class="card border-light mb-3"> | ||||
| 			<div class="row g-0"> | ||||
| 				<div class="col-md-4"> | ||||
| 					<a href="https://safe.kashima.moe/6yfeooamzro4.png"> | ||||
| 						<img src="https://safe.kashima.moe/6yfeooamzro4.png" class="img-fluid rounded-start"> | ||||
| 					</a> | ||||
| 				</div> | ||||
| 				<div class="col-md-8"> | ||||
| 					<h5 class="card-header">Tons of Features, and More to Come</h5> | ||||
| 					<div class="card-body"> | ||||
| 						<p class="card-text"> | ||||
| 							Hilbish offers a bunch of features to make your interactive | ||||
| 							shell experience rich. Things like syntax highlighting and hinting | ||||
| 							available via the Lua API. | ||||
| 						</p> | ||||
| 						<p class="card-small text-muted">* Command hints shown in photo are not default.</p> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<!-- uncomment, replace top when editor interface can be replaced (and replace the images) --> | ||||
| 	<!-- | ||||
| 	<div class="col"> | ||||
| 		<div class="card border-light mb-3"> | ||||
| 			<div class="row g-0"> | ||||
| 				<div class="col-md-4"> | ||||
| 					<a href="https://safe.kashima.moe/6yfeooamzro4.png"> | ||||
| 						<img src="https://safe.kashima.moe/6yfeooamzro4.png" class="img-fluid rounded-start"> | ||||
| 					</a> | ||||
| 				</div> | ||||
| 				<div class="col-md-8"> | ||||
| 					<h5 class="card-header">Highly Extensible</h5> | ||||
| 					<div class="card-body"> | ||||
| 						<p class="card-text"> | ||||
| 							Hilbish can be turned into an all new shell if wanted. One of our | ||||
| 							main goals is that most (if not all) interfaces can be replaced. | ||||
| 						</p> | ||||
| 					</div> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	--> | ||||
| </div> | ||||
| 
 | ||||
| <hr> | ||||
| 
 | ||||
| <h1 class="fw-light">Why not just Lua?</h1> | ||||
| <p> | ||||
| 	Hilbish is your interactive shell as well as a just a Lua interpreter | ||||
| 	and enhanced REPL.<br> | ||||
| </p> | ||||
| <ul class="list-group" style="max-width: 64em;"> | ||||
| 	<li class="list-group-item"><i class="fa-solid fa-battery-full"></i> Batteries included Lua runtime that's also your user shell!</li> | ||||
| 	<li class="list-group-item"><i class="fa-solid fa-network-wired"></i> Hilbish is easily cross platform. It has OS agnostic interfaces for easy cross platform Lua code.</li> | ||||
| </ul> | ||||
| 
 | ||||
| <hr> | ||||
| 
 | ||||
| <h1 class="fw-light">Try It Today!</h1> | ||||
| <p> | ||||
| 	Hilbish is known to run on the 3 major platforms (Windows, MacOS, Linux) | ||||
| 	but likely builds on other Unixes! | ||||
| 	<br> | ||||
| 	Windows doesn't work as well as it should, so if you're a Windows user, | ||||
| 	<a href="https://github.com/Rosettea/Hilbish/discussions/165">say something</a>! | ||||
| 	<ul class="list-group" style="max-width: 64em;"> | ||||
| 		<li class="list-group-item"><i class="fa-solid fa-cloud-arrow-down"></i> <a href="/Hilbish/install" style="text-decoration: none;"><strong>Download</strong></a> the binary</li> | ||||
| 		<li class="list-group-item"><i class="fa-solid fa-screwdriver-wrench"></i> <a href="https://github.com/Rosettea/Hilbish#manual-build" style="text-decoration: none;"><strong>Build</strong></a> from source</li> | ||||
| 	</ul> | ||||
| </p> | ||||
							
								
								
									
										19
									
								
								website/content/docs/_index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								website/content/docs/_index.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| --- | ||||
| title: Introduction | ||||
| layout: doc | ||||
| weight: -1 | ||||
| menu: docs | ||||
| --- | ||||
| 
 | ||||
| Here lies the documentation for Hilbish, the hyper extensible Lua shell.   | ||||
| Hilbish provides you with a few quality of life features and useful | ||||
| functions to ensure you can make the shell fully yours. | ||||
| 
 | ||||
| These features include: | ||||
| - Completion and history search menus | ||||
| - Hinting and syntax highlighting (scripted by user) | ||||
| 
 | ||||
| # Installation | ||||
| Steps on installing Hilbish will be at the Install page in the navigation bar | ||||
| at the top. This also included getting development builds from the GitHub | ||||
| repository. | ||||
							
								
								
									
										25
									
								
								website/content/docs/faq.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								website/content/docs/faq.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| --- | ||||
| title: Frequently Asked Questions | ||||
| layout: doc | ||||
| weight: -20 | ||||
| menu: docs | ||||
| --- | ||||
| 
 | ||||
| # Is Hilbish POSIX compliant? | ||||
| No, it is not. POSIX compliance is a non-goal. Perhaps in the future, | ||||
| someone would be able to write a native plugin to support shell scripting | ||||
| (which would be against it's main goal, but ....) | ||||
| 
 | ||||
| # Windows Support? | ||||
| It compiles for Windows (CI ensures it does), but otherwise it is not | ||||
| directly supported. If you'd like to improve this situation, | ||||
| checkout [the discussion](https://github.com/Rosettea/Hilbish/discussions/165). | ||||
| 
 | ||||
| # Where is the API documentation? | ||||
| The builtin `doc` command supplies all documentation of Hilbish provided | ||||
| APIs. This will be on the website in the near future. | ||||
| 
 | ||||
| # Why? | ||||
| Hilbish emerged from the desire of a Lua configured shell. | ||||
| It was the initial reason that it was created, but now it's more: | ||||
| to be hyper extensible, simpler and more user friendly. | ||||
							
								
								
									
										11
									
								
								website/content/docs/features/_index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								website/content/docs/features/_index.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| --- | ||||
| title: Features | ||||
| layout: doc | ||||
| weight: -40 | ||||
| menu: docs | ||||
| --- | ||||
| 
 | ||||
| Hilbish has a wide range of features to enhance the user's experience and | ||||
| is always adding new ones. If there is something missing here or something | ||||
| you would like to see, please [start a discussion](https://github.com/Rosettea/Hilbish/discussions) | ||||
| or comment on any existing ones which match your request. | ||||
							
								
								
									
										17
									
								
								website/content/docs/features/runner-mode.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								website/content/docs/features/runner-mode.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| --- | ||||
| title: Runner Mode | ||||
| description: Customize the interactive script/command runner. | ||||
| layout: doc | ||||
| menu:  | ||||
|   docs: | ||||
|     parent: "Features" | ||||
| --- | ||||
| 
 | ||||
| Hilbish allows you to change how interactive text can be interpreted. | ||||
| This is mainly due to the fact that the default method Hilbish uses | ||||
| is that it runs Lua first and then falls back to shell script. | ||||
| 
 | ||||
| In some cases, someone might want to switch to just shell script to avoid | ||||
| it while interactive but still have a Lua config, or go full Lua to use | ||||
| Hilbish as a REPL. This also allows users to add alternative languages, | ||||
| instead of either like Fennel. | ||||
							
								
								
									
										59
									
								
								website/content/docs/getting-started.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								website/content/docs/getting-started.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| --- | ||||
| title: Getting Started | ||||
| layout: doc | ||||
| weight: -10 | ||||
| menu: docs | ||||
| --- | ||||
| 
 | ||||
| To start Hilbish, open a terminal. If Hilbish has been installed and is not the | ||||
| default shell, you can simply run `hilbish` to start it. This will launch | ||||
| a normal interactive session. | ||||
| To exit, you can either run the `exit` command or hit Ctrl+D. | ||||
| 
 | ||||
| # Setting as Default | ||||
| ## Login shell | ||||
| There are a few ways to make Hilbish your default shell. A simple way is  | ||||
| to make it your user/login shell. | ||||
| 
 | ||||
| {{< warning `It is not recommended to set Hilbish as your login shell. That is expected to be a  | ||||
| POSIX compliant shell, which Hilbish is not. At most, there will just be a  | ||||
| few variables missing in your environment` >}} | ||||
| 
 | ||||
| To do that, simply run `chsh -s /usr/bin/hilbish`. | ||||
| Some distros (namely Fedora) might have `lchsh` instead, which is used like `lchsh <user>`. | ||||
| When prompted, you can put the path for Hilbish. | ||||
| 
 | ||||
| ## Default with terminal | ||||
| The simpler way is to set the default shell for your terminal. The way of  | ||||
| doing this depends on how your terminal settings are configured. | ||||
| 
 | ||||
| ## Run after login shell | ||||
| Some shells (like zsh) have an rc file, like `.zlogin`, which is ran when the shell session | ||||
| is a login shell. In that file, you can run Hilbish. Example: | ||||
| 
 | ||||
| ``` | ||||
| exec hilbish -S -l | ||||
| ``` | ||||
| 
 | ||||
| This will replace the shell with Hilbish, set $SHELL to Hilbish and launch it as a login shell. | ||||
| 
 | ||||
| # Configuration | ||||
| Once installation and setup has been done, you can then configure Hilbish. | ||||
| It is configured and scripted via Lua, so the config file is a Lua file. | ||||
| You can use any pure Lua library to do whatever you want. | ||||
| 
 | ||||
| Hilbish's sample configuration is usually located in `hilbish.dataDir .. '/.hilbishrc.lua'`. | ||||
| You can print that path via Lua to see what it is: `print(hilbish.dataDir .. '/.hilbishrc.lua')`. | ||||
| As an example, it will usually will result in `/usr/share/hilbish/.hilbishrc.lua` on Linux. | ||||
| 
 | ||||
| To edit your user configuration, you can copy that file to `hilbish.userDir.config .. '/hilbish/init.lua'`, | ||||
| which follows XDG on Linux and MacOS, and is located in %APPDATA% on Windows. | ||||
| 
 | ||||
| As the directory is usually `~/.config` on Linux, you can run this command to copy it:   | ||||
| `cp /usr/share/hilbish/.hilbishrc.lua ~/.config/hilbish/init.lua` | ||||
| 
 | ||||
| Now you can get to editing it. Since it's just a Lua file, having basic | ||||
| knowledge of Lua would help. All of Lua's standard libraries and functions | ||||
| from Lua 5.4 are available. Hilbish has some custom and modules that are | ||||
| available. To see them, you can run the `doc` command. This also works as | ||||
| general documentation for other things. | ||||
							
								
								
									
										38
									
								
								website/content/install.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								website/content/install.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| --- | ||||
| title: Install | ||||
| description: Steps on how to install Hilbish on all the OSes and distros supported. | ||||
| layout: page | ||||
| --- | ||||
| 
 | ||||
| ## Official Binaries | ||||
| The best way to get Hilbish is to get a build directly from GitHub. | ||||
| At any time, there are 2 versions of Hilbish recommended for download: | ||||
| the latest stable release, and development builds from the master branch. | ||||
| 
 | ||||
| You can download both at any time, but note that the development builds may | ||||
| have breaking changes. | ||||
| 
 | ||||
| For the latest **stable release**, check here: https://github.com/Rosettea/Hilbish/releases/latest   | ||||
| For a **development build**: https://nightly.link/Rosettea/Hilbish/workflows/build/master | ||||
| 
 | ||||
| ## Package Repositories | ||||
| ### Arch Linux (AUR) | ||||
| Hilbish is on the AUR. Setup an AUR helper, and install. | ||||
| Example with yay:   | ||||
| 
 | ||||
| ``` | ||||
| yay -S hilbish | ||||
| ``` | ||||
| 
 | ||||
| Or, from master branch:   | ||||
| ``` | ||||
| yay -S hilbish-git | ||||
| ``` | ||||
| 
 | ||||
| ### Alpine Linux | ||||
| Hilbish is currentlty in the testing/edge repository for Alpine. | ||||
| Follow the steps [here](https://wiki.alpinelinux.org/wiki/Enable_Community_Repository) | ||||
| (Using testing repositories) and install:   | ||||
| ``` | ||||
| apk add hilbish | ||||
| ``` | ||||
							
								
								
									
										
											BIN
										
									
								
								website/static/hilbish-flower.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								website/static/hilbish-flower.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 16 KiB | 
							
								
								
									
										21
									
								
								website/themes/hsh/LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								website/themes/hsh/LICENSE
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| MIT License | ||||
| 
 | ||||
| Copyright (c) 2022 Rosettea | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
| 
 | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
| 
 | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										2
									
								
								website/themes/hsh/archetypes/default.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								website/themes/hsh/archetypes/default.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| +++ | ||||
| +++ | ||||
							
								
								
									
										7
									
								
								website/themes/hsh/layouts/404.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								website/themes/hsh/layouts/404.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| {{ define "main"}} | ||||
| 	<main id="main"> | ||||
| 		<div> | ||||
| 			<h1><a href="{{ "/" | relURL }}">Go Home</a></h1> | ||||
| 		</div> | ||||
| 	</main> | ||||
| {{ end }} | ||||
| @ -0,0 +1,6 @@ | ||||
| <h{{ (add .Level 1) }} id="{{ .Anchor | safeURL }}"> | ||||
| 	{{ .Text | safeHTML }} | ||||
| </h{{ (add .Level 1) }}> | ||||
| {{ if eq .Text ""}} | ||||
| <hr> | ||||
| {{ end }} | ||||
| @ -0,0 +1,4 @@ | ||||
| <a href="{{ .Destination | safeURL }}"{{ with .Title}} title="{{ . }}"{{ end }}{{ if eq (substr .Destination 0 4) "http" }} target="_blank" rel="noopener"{{ end }}> | ||||
| 	{{ .Text | safeHTML }} | ||||
| </a> | ||||
| 
 | ||||
							
								
								
									
										21
									
								
								website/themes/hsh/layouts/_default/baseof.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								website/themes/hsh/layouts/_default/baseof.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     {{- partial "head.html" . -}} | ||||
|     <body class="d-flex flex-column min-vh-100" style="overflow-x: hidden;"> | ||||
|         <svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> | ||||
|             <symbol id="check-circle-fill" fill="currentColor" viewBox="0 0 16 16"> | ||||
|                 <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/> | ||||
|             </symbol> | ||||
|             <symbol id="info-fill" fill="currentColor" viewBox="0 0 16 16"> | ||||
|                 <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/> | ||||
|             </symbol> | ||||
|             <symbol id="exclamation-triangle-fill" fill="currentColor" viewBox="0 0 16 16"> | ||||
|                 <path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/> | ||||
|             </symbol> | ||||
|         </svg> | ||||
| 
 | ||||
|         {{- partial "header.html" . -}} | ||||
|         {{- block "main" . }}{{- end }} | ||||
|         {{- partial "footer.html" . -}} | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										53
									
								
								website/themes/hsh/layouts/_default/doc.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								website/themes/hsh/layouts/_default/doc.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| {{ define "main" }} | ||||
| <div class="container py-3 row"> | ||||
| 	<div class="container" style="width: 240px;"> | ||||
| 		<div class="p-3 col"> | ||||
| 			<ul class="nav nav-pills mb-auto"> | ||||
| 				{{ $currentPage := . }} | ||||
| 				{{ range .Site.Menus.docs.ByWeight.Reverse }} | ||||
| 					<li class="nav-item"> | ||||
| 						<a href="{{ .URL }}" class="nav-link"> | ||||
| 							<strong>{{ .Title }}</strong> | ||||
| 						</a> | ||||
| 					</li> | ||||
| 					{{ if .Children }} | ||||
| 						<ul style="list-style: none;"> | ||||
| 							{{ range .Children }} | ||||
| 								<li class="nav-item"> | ||||
| 									<a href="{{ .URL }}" class="nav-link"> | ||||
| 										{{ .Title }} | ||||
| 									</a> | ||||
| 								</li> | ||||
| 							{{ end }} | ||||
| 						</ul> | ||||
| 					{{ end }} | ||||
| 				{{ end }} | ||||
| 			</ul> | ||||
| 		</div> | ||||
| 	</div> | ||||
| 	<div class="p-3 col"> | ||||
| 		<div> | ||||
| 			<h1>{{ .Title }}</h1> | ||||
| 			<p><em> | ||||
| 			{{ $date := .Date.UTC.Format "Jan 2, 2006" }} | ||||
| 			{{ $lastmod := .Lastmod.UTC.Format "Jan 2, 2006" }} | ||||
| 			{{ if and (ne $lastmod $date) (gt .Lastmod .Date) }} | ||||
| 				Last updated {{ $lastmod }}<br> | ||||
| 			{{ end }} | ||||
| 
 | ||||
| 			{{ if .Description }} | ||||
| 				{{ .Description }}<br> | ||||
| 			{{ end}} | ||||
| 			</em></p> | ||||
| 			{{.Content}} | ||||
| 		</div> | ||||
| 
 | ||||
| 		<div class="footer mt-auto"> | ||||
| 			<p class="card-small text-muted"> | ||||
| 				Want to help improve this page? <a href="https://github.com/Rosettea/Hilbish/issues/new/choose">Create an issue.</a> | ||||
| 			</p> | ||||
| 		</div> | ||||
| 	</div> | ||||
| </div> | ||||
| {{ end }} | ||||
| 
 | ||||
							
								
								
									
										0
									
								
								website/themes/hsh/layouts/_default/list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								website/themes/hsh/layouts/_default/list.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										7
									
								
								website/themes/hsh/layouts/_default/page.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								website/themes/hsh/layouts/_default/page.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| {{ define "main" }} | ||||
| <main> | ||||
| 	<div class="container mt-2"> | ||||
| 	{{.Content}} | ||||
| 	</div> | ||||
| </main> | ||||
| {{ end }} | ||||
							
								
								
									
										8
									
								
								website/themes/hsh/layouts/_default/single.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								website/themes/hsh/layouts/_default/single.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| {{ define "main" }} | ||||
| <main> | ||||
| 	<div class="container mt-2"> | ||||
| 		<h1>{{ .Title }}</h1> | ||||
| 		{{.Content}} | ||||
| 	</div> | ||||
| </main> | ||||
| {{ end }} | ||||
							
								
								
									
										6
									
								
								website/themes/hsh/layouts/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								website/themes/hsh/layouts/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| {{ define "main" }} | ||||
| <main style="max-width: 80em; margin: auto;"> | ||||
| 	{{.Content}} | ||||
| </main> | ||||
| {{ end }} | ||||
| 
 | ||||
							
								
								
									
										32
									
								
								website/themes/hsh/layouts/partials/footer.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								website/themes/hsh/layouts/partials/footer.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| <footer class="footer mt-auto mt-auto py-3 bg-light row"> | ||||
| 	<div class="col mb-3"> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div class="col mb-3"> | ||||
| 		<a href="/Hilbish" class="d-flex align-items-center mb-3 link-dark text-decoration-none"> | ||||
| 		<img src="/Hilbish/hilbish-flower.png" alt="" height="48" class="d-inline-block align-text-top"> | ||||
| 		</a> | ||||
| 		<p class="text-muted"> | ||||
| 			Rosettea © 2022 | ||||
| 			<br> | ||||
| 			Made with <i class="fa-solid fa-heart" style="color: #f6345b;"></i> | ||||
| 		</p> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div class="col mb-3"></div> | ||||
| 	<div class="col mb-3"></div> | ||||
| 	<div class="col mb-3"></div> | ||||
| 
 | ||||
| 	<div class="col mb-3"> | ||||
| 		<h5>Hilbish</h5> | ||||
| 		<ul class="nav flex-column"> | ||||
| 			<li class="nav-item mb-2"><a href="/Hilbish" class="nav-link p-0 text-muted">Home</a></li> | ||||
| 			<li class="nav-item mb-2"><a href="/Hilbish/docs/faq" class="nav-link p-0 text-muted">FAQ</a></li> | ||||
| 			<li class="nav-item mb-2"><a href="https://github.com/Rosettea/Hilbish" class="nav-link p-0 text-muted">Source</a></li> | ||||
| 			<li class="nav-item mb-2"><a href="https://github.com/Rosettea/Hilbish/releases" class="nav-link p-0 text-muted">Releases</a></li> | ||||
| 			<li class="nav-item mb-2"><a href="/Hilbish/docs" class="nav-link p-0 text-muted">Documentation</a></li> | ||||
| 		</ul> | ||||
| 	</div> | ||||
| 
 | ||||
| 	<div class="col mb-3"></div> | ||||
| </footer> | ||||
							
								
								
									
										26
									
								
								website/themes/hsh/layouts/partials/head.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								website/themes/hsh/layouts/partials/head.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,26 @@ | ||||
| <head> | ||||
| 	{{ $title := print .Title " — " .Site.Title }} | ||||
|     {{ if .IsHome }}{{ $title = .Site.Title }}{{ end }} | ||||
|     <title>{{ $title }}</title> | ||||
| 	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||||
| 	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"/> | ||||
| 	 | ||||
| 	<meta name="theme-color" content="#ff89dd"> | ||||
| 	<meta content="/Hilbish/hilbish-flower.png" property="og:image" /> | ||||
| 
 | ||||
| 	<meta property="og:site_name" content="Hilbish" /> | ||||
| 	<meta content="{{ $title }}" property="og:title" /> | ||||
| 	<meta content="{{if .Description}}{{ .Description }}{{ else }}{{ .Summary }}{{ end }}" property="og:description" /> | ||||
| 	<meta content="{{if .Description}}{{ .Description }}{{ else }}{{ .Summary }}{{ end }}" name="description" /> | ||||
| 	 | ||||
| 	<meta name="revisit-after" content="2 days"> | ||||
| 	<meta name="keywords" content="Lua, Hilbish, Linux, Shell"> | ||||
| 	 | ||||
| 	<meta property="og:locale" content="en_GB" /> | ||||
| 	<link rel="canonical" href="https://rosettea.github.io/Hilbish/" /> | ||||
| 	<meta property="og:url" content="https://rosettea.github.io/Hilbish/" /> | ||||
| 
 | ||||
| 	<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous"> | ||||
| 	<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-pprn3073KE6tl6bjs2QrFaJGz5/SUsLqktiwsUTF55Jfv3qYSDhgCecCxMW52nD2" crossorigin="anonymous"></script> | ||||
| 	<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" /> | ||||
| </head> | ||||
							
								
								
									
										25
									
								
								website/themes/hsh/layouts/partials/header.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								website/themes/hsh/layouts/partials/header.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| <header> | ||||
| 	<nav class="navbar navbar-expand-md sticky-top bg-light"> | ||||
| 		<div class="container-fluid"> | ||||
| 			<a class="navbar-brand" href="/Hilbish"> | ||||
| 				<img src="/Hilbish/hilbish-flower.png" alt="" height="24" class="d-inline-block align-text-top"> | ||||
| 				Hilbish | ||||
| 			</a> | ||||
| 			<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> | ||||
| 				<span class="navbar-toggler-icon"></span> | ||||
| 			</button> | ||||
| 			<div class="collapse navbar-collapse" id="navbarSupportedContent"> | ||||
| 				<ul class="navbar-nav me-auto mb-2 mb-lg-0"> | ||||
| 					{{ $currentPage := . }} | ||||
| 					{{ range .Site.Menus.nav }} | ||||
| 						<li class="nav-item"> | ||||
| 							<a href="{{ .URL }}" class="nav-link {{ if $currentPage.IsMenuCurrent "nav" . }}active{{ end }}"> | ||||
| 								{{ .Name }} | ||||
| 							</a> | ||||
| 						</li> | ||||
| 					{{ end }} | ||||
| 				</ul> | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	</nav> | ||||
| </header> | ||||
							
								
								
									
										6
									
								
								website/themes/hsh/layouts/shortcodes/warning.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								website/themes/hsh/layouts/shortcodes/warning.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| <div class="alert alert-warning d-flex align-items-center" role="alert"> | ||||
| 	<svg class="bi flex-shrink-0 me-2" width="24" height="24" role="img" aria-label="Warning:"><use xlink:href="#exclamation-triangle-fill"/></svg> | ||||
| 	<div> | ||||
| 		{{ .Get 0 }} | ||||
| 	</div> | ||||
| </div> | ||||
							
								
								
									
										21
									
								
								website/themes/hsh/theme.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								website/themes/hsh/theme.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | ||||
| # theme.toml template for a Hugo theme | ||||
| # See https://github.com/gohugoio/hugoThemes#themetoml for an example | ||||
| 
 | ||||
| name = "Hsh" | ||||
| license = "MIT" | ||||
| licenselink = "https://github.com/yourname/yourtheme/blob/master/LICENSE" | ||||
| description = "" | ||||
| homepage = "http://example.com/" | ||||
| tags = [] | ||||
| features = [] | ||||
| min_version = "0.41.0" | ||||
| 
 | ||||
| [author] | ||||
|   name = "" | ||||
|   homepage = "" | ||||
| 
 | ||||
| # If porting an existing theme | ||||
| [original] | ||||
|   name = "" | ||||
|   homepage = "" | ||||
|   repo = "" | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user