Skip to content

Commit

Permalink
✨ Implement wk widget features (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
844196 authored Sep 8, 2024
2 parents 7392d6d + 17ca9da commit 3ffdef3
Show file tree
Hide file tree
Showing 9 changed files with 221 additions and 70 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.task/
dist/
src/version.generated.json
src/widget.generated.json
184 changes: 122 additions & 62 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,66 +7,126 @@

## :package: Installation

<https://github.com/844196/wk/releases>

## :gear: Configuration example (zsh)

```shell
# $ZDOTDIR/.zshrc

space-wk() {
case $BUFFER in
'')
# Avoid cursor flickering
echo -n $'\x1b[?25l\x1b[0`' >$TTY

local res=''
res=$(wk run --no-validation 2>&1)
local wk_exit=$?

zle redisplay

case $wk_exit in
0)
# NOOP
;;
1|2)
# Abort, Timeout
return
;;
*)
zle -M "wk: $res"
return $wk_exit
;;
esac

res=("${(@ps:\t:)res}")

if [[ "${res[(rb:2:)eval:*]}" == 'eval:true' ]]; then
BUFFER=${(e)res[1]}
else
BUFFER=${res[1]}
fi
CURSOR=${#BUFFER}

case "${res[(rb:2:)trigger:*]}" in
trigger:ACCEPT)
zle accept-line
;;
trigger:COMPLETE)
zle expand-or-complete
;;
esac

zle redisplay
;;

*)
zle self-insert
;;
esac
}

zle -N space-wk
bindkey ' ' space-wk
1. Download the latest release and put into your `$PATH`:

<https://github.com/844196/wk/releases/latest>

2. Activate in `$ZDOTDIR/.zshrc`:

```shell
# Register a widget with the name "_wk_widget", and bind it to the ^G.
eval "$(wk widget zsh)"
```

3. Restart zsh.

> [!TIP]
> If you want to change the trigger key, change it as follows:
>
> ```shell
> eval "$(wk widget zsh --bindkey '^T')"
> ```
>
> If you want to register only the widget, change it as follows:
>
> ```shell
> eval "$(wk widget zsh --no-bindkey)"
> ```
## :gear: Configuration
### Config
`${XDG_CONFIG_HOME:-$HOME/.config}/wk/config.yaml`
```yaml
---
timeout: 60000
symbols:
prompt: ""
colors:
prompt: 8
inputKeys:
color: 8
attrs: [dim]
breadcrumb:
color: 8
attrs: [dim]
lastInputKey:
color: 6
attrs: [underline]
bindingKey: 5
separator:
color: 5
attrs: [dim]
group: 8
bindingIcon: 8
bindingDescription: 8
```
See [schemas/config.json](./schemas/config.json) for more details.

### Global bindings

`${XDG_CONFIG_HOME:-$HOME/.config}/wk/bindings.yaml`

```yaml
---
- key: g
desc: Git
type: bindings
bindings:
- key: p
desc: Push/Pull
type: bindings
bindings:
- key: return
desc: git push
type: command
buffer: 'git push origin $(git symbolic-ref --short HEAD)'
eval: true
- key: f
desc: git push -f
type: command
buffer: 'git push --force-with-lease --force-if-includes origin $(git symbolic-ref --short HEAD)'
eval: true
- key: l
type: command
buffer: 'git pull'
accept: true
- key: y
desc: Yank
type: bindings
bindings:
- key: .
desc: Copy $PWD
type: command
buffer: ' echo -ne "\e]52;c;$(base64 <(pwd | tee >$TTY | sed -z ''$s/\n$//''))\a"'
accept: true
```
See [schemas/bindings.json](./schemas/bindings.json) for more details.
### Local bindings
`$PWD/wk.bindings.yaml`

```yaml
---
- key: m
desc: Major
type: bindings
bindings:
- key: b
type: command
buffer: 'npm run build'
accept: true
- key: l
type: command
buffer: 'npm run lint'
accept: true
- key: t
type: command
buffer: 'npm run test'
accept: true
```
9 changes: 9 additions & 0 deletions Taskfile.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ tasks:
check:
deps:
- version_file
- widget_file
cmds:
- deno fmt --check
- deno lint
Expand All @@ -17,6 +18,7 @@ tasks:
compile:
deps:
- version_file
- widget_file
vars:
TARGETS:
- x86_64-unknown-linux-gnu
Expand All @@ -35,3 +37,10 @@ tasks:
vars:
VERSION: '{{.VERSION | default "development"}}'
cmd: echo '"{{.VERSION}}"' > src/version.generated.json

widget_file:
sources:
- src/widget.eta
generates:
- src/widget.generated.json
cmd: jq --raw-input --slurp < src/widget.eta > src/widget.generated.json
1 change: 1 addition & 0 deletions aqua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ registries:
ref: v4.212.0
packages:
- name: go-task/task@v3.38.0
- name: jqlang/jq@jq-1.7.1
5 changes: 3 additions & 2 deletions deno.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
"@cliffy/command": "jsr:@cliffy/command@1.0.0-rc.5",
"@cliffy/keycode": "jsr:@cliffy/keycode@1.0.0-rc.5",
"@cliffy/table": "jsr:@cliffy/table@1.0.0-rc.5",
"@dunosaurs/color": "https://deno.land/x/color@v0.3.0/mod.ts",
"@eta-dev/eta": "jsr:@eta-dev/eta@^3.5.0",
"@lambdalisue/github-emoji": "jsr:@lambdalisue/github-emoji@1.0.0",
"@std/collections": "jsr:@std/collections@1.0.5",
"@std/path": "jsr:@std/path@1.0.2",
"rc-config-loader": "npm:rc-config-loader@4.1.3",
"xdg-basedir": "npm:xdg-basedir@5.1.0",
"zod": "npm:zod@3.23.8",
"@dunosaurs/color": "https://deno.land/x/color@v0.3.0/mod.ts"
"zod": "npm:zod@3.23.8"
}
}
5 changes: 5 additions & 0 deletions deno.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions schemas/bindings.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@
},
"delimiter": {
"type": "string"
},
"eval": {
"type": "boolean"
},
"accept": {
"type": "boolean"
}
},
"additionalProperties": {
Expand Down
29 changes: 23 additions & 6 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,30 @@ import { getKeySymbol } from './ui.ts'
import version from './version.generated.json' with { type: 'json' }
import { renderPrompt } from './ui.ts'
import { renderTable } from './ui.ts'
import { Eta } from '@eta-dev/eta'
import widgetTemplate from './widget.generated.json' with { type: 'json' }

const cli = new Command()
.name('wk')
.version(version)
.versionOption('-v, --version', 'Show the version number for this program.', { global: true })

const widget = new Command()
.description('Outputs shell widget source code.')
.arguments('<shell:string>')
.option('--bindkey <key>', 'Bind the widget to the key.', { default: '^G' })
.option('--no-bindkey', 'Do not bind the widget to the key.')
.action(({ bindkey }) => {
const eta = new Eta()

const rendered = eta.renderString(widgetTemplate, {
wk_path: Deno.execPath(),
bindkey,
})

console.log(rendered)
})

const run = new Command()
.description('Run the workflow.')
.option('--no-validation', 'Skip validation of the configuration files.')
Expand Down Expand Up @@ -76,8 +94,7 @@ const run = new Command()
let timeoutTimerId: number | undefined
const handleTimeout = () => {
tui.close()
console.error('Timeout')
Deno.exit(2)
Deno.exit(4)
}

const deps: Dependencies = {
Expand Down Expand Up @@ -128,16 +145,15 @@ const run = new Command()
} catch (e: unknown) {
if (e instanceof AbortError) {
tui.close()
console.error('Abort')
Deno.exit(1)
Deno.exit(3)
} else if (e instanceof UndefinedKeyError) {
tui.close()
console.error(`"${e.getInputKeys().map((k) => getKeySymbol(ctx, k)).join(' ')}" is undefined`)
Deno.exit(3)
Deno.exit(5)
} else if (e instanceof KeyParseError) {
tui.close()
console.error('Failed to parse key', e.getKey())
Deno.exit(4)
Deno.exit(6)
} else {
throw e
}
Expand All @@ -147,5 +163,6 @@ const run = new Command()
})

await cli
.command('widget', widget)
.command('run', run)
.parse(Deno.args)
50 changes: 50 additions & 0 deletions src/widget.eta
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
_wk_widget() {
local opts
zstyle -a ':wk:*' options opts || opts=()

local res=''
res=$(<%= it.wk_path %> run ${=opts} 2>&1)
local wk_exit=$?

zle redisplay
echo -n $'\x1b[?25h' >$TTY # Ensure cursor is visible

case $wk_exit in
0)
# NOOP
;;
3|4)
# Abort, Timeout
return
;;
*)
# 1: General errors
# 2: Invalid arguments or options error
# 5: No match error
# 6: Key parse error
# *: Unknown errors
zle -M "wk: $res"
return $wk_exit
;;
esac

reply=("${(@ps:\t:)res}")

if [[ "${reply[(rb:2:)eval:*]}" == 'eval:true' ]]; then
BUFFER=${(e)reply[1]}
else
BUFFER=${reply[1]}
fi
CURSOR=${#BUFFER}

if [[ "${reply[(rb:2:)accept:*]}" == 'accept:true' ]]; then
local accept_widget
zstyle -s ':wk:*' accept-widget accept_widget || accept_widget='accept-line'
zle $accept_widget
fi
}

zle -N _wk_widget
<% if (typeof it.bindkey === 'string') { %>
bindkey '<%= it.bindkey %>' _wk_widget
<% } %>

0 comments on commit 3ffdef3

Please sign in to comment.