Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,74 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.1.17] - 2026-05-31

### Fixed

- **Git Bash: Ctrl+C is lost after an expansion (#7).** Under Git Bash
(cygwin/msys bash) the readline `bind -x` handler is invoked on top
of the cygwin signal layer. Spawning a Win32 `.exe` from inside that
handler — which is exactly what every `runex hook` call did at
trigger time — caused the very next `SIGINT` to be lost, so the
user's reflexive `Ctrl+C` after an unwanted expansion no longer
cleared the line buffer, and pressing `Enter` ran the stale
expanded command. Reproduced on Windows 11 + Git Bash 2.50 with
every abbreviation, regardless of cursor position or whether the
subprocess output was consumed via `$(...)` or a temp file. The
root cause is the spawn itself, not how the output is read.

The bash integration cache now ships a **bake-mode dispatcher**
selected at source time by `case "${OSTYPE-}"`. Under
`msys*`/`cygwin*` the trigger handler resolves the abbreviation
from a static table baked into the cache file (associative
arrays for exact + condition + pattern rules, plus a tiny
pure-bash renderer for `{}` cursor placement and `{number}`
repetition). No subprocess is spawned, so the next `SIGINT`
reaches the shell as it should and `Ctrl+C` clears the line as
on every other platform.

### Changed

- **Shell taxonomy: `Shell::CygwinBash` variant dropped from the
plan.** The 0.1.16 CHANGELOG mentioned that 0.1.17 would
introduce a `Shell::CygwinBash` enum variant. After PoC we found
the difference is purely a runtime-environment quirk, not a
language-level shell distinction, and that taxonomy expansion
would have pushed across the enum, config, export, init, and
infra layers for a problem that fits in one runtime `case`
block. The shipping approach keeps `Shell` unchanged and routes
through `$OSTYPE` inside the cache file instead. Linux bash,
WSL bash, zsh, pwsh, and nu users see no change.

- **Bash integration cache version bumped 1 → 2.** Caches written
by 0.1.16 still source cleanly under 0.1.17 (the legacy exec
path is still the `*)` arm of the `case`), but `runex doctor`
now flags v1 caches as stale so users get nudged into
`runex init bash` to pick up the bake dispatcher on Git Bash.

### Known interim trade-off (tracked for closure in 0.1.18)

- **Git Bash only: argument-position tokens also expand in 0.1.17.**
The exec-path hook understood that `echo gst` does not expand
`gst` because it is in argument position, not command position.
The 0.1.17 bake path skips that check — re-implementing the
state machine in pure bash is straightforward but adds enough
surface that it was carved out into 0.1.18 so the Ctrl+C fix
could ship first. Until 0.1.18 lands, the bake path expands
any trailing token that matches an abbreviation regardless of
the preceding word. Note that `docs/recipes.md`'s explicit
command-position rules (`sudo gst`, tokens after `|`/`||`/
`&&`/`;`) keep working on both paths because those positions
*are* command positions. Documented in `docs/setup.{md,ja.md}`
and pinned by a regression test
(`tests/bash_cygwin_bake_pty.rs::cygwin_bake_expands_even_when_token_is_not_in_command_position`)
so the 0.1.18 fix is a deliberate behaviour change, not a
stealth regression. Workarounds while 0.1.17 is current:
quote literals you don't want expanded (`echo "gst"`) or pick
abbreviation keys that won't collide with English words. Every
other shell (including Linux bash and WSL bash) retains full
command-position detection.

## [0.1.16] - 2026-05-23

### Fixed
Expand Down
40 changes: 40 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,46 @@ https://github.com/ShortArrow/runex/releases/tag/vX.Y.Z.
to "literal space" when `runex hook` errors out as an unknown
subcommand, and it's hard to debug from the user side. Don't skip.

The helper edits `packaging/aur-bin/PKGBUILD` and writes
`packaging/aur-bin/.SRCINFO` **in this repo as well** (the AUR
clone copy is taken from those). Commit the in-repo changes as
part of the back-merge step so the template stays in sync with
the published AUR version — otherwise the in-repo PKGBUILD
drifts (it stayed pinned at 0.1.11 across the 0.1.12–0.1.14
cycle before this rule was added).

- [ ] **AUR `runex` (source).** Sibling of `runex-bin` (binary);
this package builds from the `runex` crate published to crates.io
by `release.yml`. It is **not interchangeable** with `runex-bin`
— users pick one, and the PKGBUILD declares
`conflicts=('runex-bin')` (and `runex-bin` declares
`conflicts=('runex')`) to enforce that. Use the helper:

```bash
packaging/aur/release.sh X.Y.Z ~/aur/runex
```

Same sha-fetch + PKGBUILD + .SRCINFO + local-commit flow as
`runex-bin`, but the source is the `.crate` from crates.io —
so the script must run **after** the crates.io publish completes
(= same gate as Homebrew). Push manually:

```bash
cd ~/aur/runex
GIT_SSH_COMMAND='ssh -i ~/.ssh/aur' git push origin master
```

The helper also edits `packaging/aur/PKGBUILD` and writes
`packaging/aur/.SRCINFO` in this repo. Commit those in the
back-merge step alongside the `runex-bin` updates — same rule,
same reason (the in-repo template stays the source of truth so
it doesn't drift like `runex-bin`'s did across 0.1.12–0.1.14).

Historical note: `runex` was a third-party AUR package
(maintainer: Rafael Dominiquini) through 0.1.16. Maintainership
was transferred to ShortArrow on 2026-05-25. Dominiquini is
preserved as `Contributor:` in the PKGBUILD header.

- [ ] **Homebrew tap.** Use the helper:

```bash
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion docs/setup.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,4 @@ $ runex doctor
4. **clink: `lsd` がインストール済なのに `command:lsd not found`**: clink-injection された cmd の PATH が User-scope のレジストリエントリを欠いている可能性があります。runex は Windows ではレジストリでコマンド解決を補強しますが、HKCU/HKLM の `Environment\Path` どちらにも入っていないディレクトリを使っている場合は、いずれかに追加する必要があります (`RUNEX_CLINK_LUA_PATH` で lua ファイル自体の場所を上書きすることも可能)。
5. **pwsh: marker found なのに Space が反応しない**: ほぼ次の 3 つのどれかです。(a) PSReadLine が load されていない — `Get-Module PSReadLine` で行が出るか確認、出なければインストール or import。(b) Windows PowerShell 5 の実行ポリシーが `Restricted` でキャッシュファイルの dot-source が拒否されている — `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` で解消。(c) `AllSigned` ポリシーで `Documents\PowerShell\Modules` 配下の新しい PSReadLine が拒否されている — 一度 `[A] Always run` を選ぶか `$env:PSModulePath` から該当ディレクトリを除外。[PowerShell セットアップセクション](#powershell) に詳細コマンドあり。
6. **pwsh: キャッシュヘッダが二重 / `__runex_queued_key_count` が認識されない**: キャッシュファイルに `# runex-integration-version` ヘッダが 2 段ある状態 (例: 何かが `runex export pwsh` の出力に独自ヘッダを連結した結果)。キャッシュの interactive guard が function 定義より前で評価されるため、不正なキャッシュは function 定義をスキップします。`runex init pwsh` を再実行してキャッシュを書き直してください。
7. **Git Bash: `{}` プレースホルダ展開後に Ctrl+C で行が消えない** (cygwin/msys readline の制約)。Windows の Git Bash 特有の問題で、`expand` に `{}` を含む abbreviation を展開した直後 (カーソルが行の中間で止まる状態) に `Ctrl+C` を押しても line buffer がクリアされません。続けて `Enter` を押すと、展開済みのコマンド (例: 空の `git commit -am ''`) がそのまま実行されます。Linux bash / WSL bash / zsh / pwsh / nu では正しく動作し、Git Bash の cygwin readline backend だけがこの挙動を示します。回避策: `Ctrl+C` の前に `Backspace` (または何か 1 文字) を入力する、または行全体を手で消す。runex 0.1.16 で cygwin/msys bash を独立した shell variant として認識し、template 側で workaround を入れる予定です
7. **Git Bash: 0.1.17 暫定 trade-off — argument 位置の token も展開される**: Git Bash 環境では runex 0.1.17 は cache file 内の静的な abbreviation table を直接参照する *bake mode* dispatcher に切り替わり、trigger 押下時に Windows の `runex` バイナリを spawn しません。これは 0.1.16 の Ctrl+C bug (cygwin の readline が `bind -x` 内の Win32 process spawn 後に次の SIGINT を失っていた) を根絶するためです。0.1.17 dispatcher は trailing token がいずれかの abbreviation key と一致すれば argument 位置でも展開します。例: Linux bash では `echo gst<Space>` の `gst` は command 位置でないので展開されませんが、Git Bash では展開されます。`docs/recipes.md` の command-position ルール (`sudo gst`、`|`/`||`/`&&`/`;` の後の `<token>`) はそれらの位置が **元々 command 位置である** ため両 path で従来通り動作します。0.1.17 が現行版である間の回避策はリテラルを引用符で囲む (`echo "gst"`) か、英単語と衝突しない key を選ぶこと。**0.1.18 で解消予定**: pure bash で command-position 判定を再実装し、bake path を exec path と完全一致させます。Linux bash / WSL bash / zsh / pwsh / nu では従来通り runtime hook + 完全な command-position 判定が動きます
32 changes: 20 additions & 12 deletions docs/setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,23 @@ If a trigger key produces a literal space instead of expanding:
output with its own header). The cache's interactive guard runs
before the function definitions, so a malformed cache silently
skips them. Re-run `runex init pwsh` to rewrite the cache cleanly.
7. **Git Bash: Ctrl+C does not clear the line after a `{}`-placeholder
expansion** (cygwin/msys readline limitation). On Git Bash specifically,
pressing `Ctrl+C` immediately after expanding an abbreviation whose
`expand` contained `{}` (so the cursor lands in the middle of the
line) does **not** clear the line buffer. A subsequent `Enter` then
runs the stale expanded command, e.g. an empty `git commit -am ''`.
The same flow works correctly on Linux bash, WSL bash, zsh, pwsh,
and nu — only Git Bash's cygwin readline is affected. Workaround:
press `Backspace` (or any character key) before `Ctrl+C`, or just
delete the line manually. Runex 0.1.16 will treat cygwin/msys bash
as a distinct shell variant so the bash template can apply a
workaround tailored to that backend.
7. **Git Bash: 0.1.17 interim trade-off — argument-position tokens
also expand.** On Git Bash specifically, runex 0.1.17 switches
to a *bake-mode* dispatcher that looks expansions up from a
static table baked into the cache file, never spawning the
`runex` Windows binary from inside the trigger handler. That is
what fixes the 0.1.16 Ctrl+C-after-expansion bug (cygwin
readline lost the next SIGINT whenever a `bind -x` handler
spawned a Win32 process). The 0.1.17 dispatcher expands any
trailing token that matches an abbreviation, including in
argument position — e.g. `echo gst<Space>` expands `gst` on
Git Bash even though Linux bash leaves it alone. The
command-position rules from `docs/recipes.md` (`sudo gst`,
`<token>` after `|` / `||` / `&&` / `;`) still hold on both
paths because those positions *are* command positions.
Workarounds while 0.1.17 is current: quote the literal
(`echo "gst"`) or pick abbreviation keys that won't collide
with English words. **Tracked for closure in 0.1.18**:
re-implementing command-position detection in pure bash so the
bake path matches the exec path. Linux bash, WSL bash, zsh,
pwsh, and nu retain full command-position detection.
18 changes: 9 additions & 9 deletions packaging/aur-bin/.SRCINFO
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pkgbase = runex-bin
pkgdesc = Cross-shell abbreviation engine that expands short tokens into full commands
pkgver = 0.1.11
pkgver = 0.1.16
pkgrel = 1
url = https://github.com/ShortArrow/runex
arch = x86_64
Expand All @@ -9,13 +9,13 @@ pkgbase = runex-bin
license = Apache-2.0
provides = runex
conflicts = runex
source = LICENSE-0.1.11::https://raw.githubusercontent.com/ShortArrow/runex/v0.1.11/LICENSE
source = README-0.1.11.md::https://raw.githubusercontent.com/ShortArrow/runex/v0.1.11/README.md
sha256sums = 19614dcc7dc2af82331a66d30ab79d5674be3ce73ef853ed76e1743b2830f4d0
sha256sums = b5d6502f8cf0088b3d75cc79a1fad78ca7da3374803a49e70b7709f991410439
source_x86_64 = runex-0.1.11-x86_64.tar.gz::https://github.com/ShortArrow/runex/releases/download/v0.1.11/runex-x86_64-unknown-linux-gnu.tar.gz
sha256sums_x86_64 = 1d2767e51ae575739ef97a048a27334c3d7c8b46550cd5ee400c85444b91e5fe
source_aarch64 = runex-0.1.11-aarch64.tar.gz::https://github.com/ShortArrow/runex/releases/download/v0.1.11/runex-aarch64-unknown-linux-gnu.tar.gz
sha256sums_aarch64 = 14f94242f7d151158ffaefbf90541e78d828d620b3a0588a8bbac6c2d9361422
source = LICENSE-0.1.16::https://raw.githubusercontent.com/ShortArrow/runex/v0.1.16/LICENSE
source = README-0.1.16.md::https://raw.githubusercontent.com/ShortArrow/runex/v0.1.16/README.md
sha256sums = 735fa89d57bbf22a8c85d829aa1ed791cce81ffdb900467333025ab7b2feee1c
sha256sums = 6841cfc9dce7aabf01df2cfc36c8f9ee030c16eae6e50f877f8311538c735942
source_x86_64 = runex-0.1.16-x86_64.tar.gz::https://github.com/ShortArrow/runex/releases/download/v0.1.16/runex-x86_64-unknown-linux-gnu.tar.gz
sha256sums_x86_64 = 3857d2ded00a0c5b2d8c18e6357aea6e6f2c07854cf5c2a28a79ec3d5a4d16b7
source_aarch64 = runex-0.1.16-aarch64.tar.gz::https://github.com/ShortArrow/runex/releases/download/v0.1.16/runex-aarch64-unknown-linux-gnu.tar.gz
sha256sums_aarch64 = 171f1cd715f0420c6058769d45c6dcdcbbda0f6eae65cfd947c34e8995255858

pkgname = runex-bin
10 changes: 5 additions & 5 deletions packaging/aur-bin/PKGBUILD
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Maintainer: ShortArrow <bamboogeneral@gmail.com>
pkgname=runex-bin
pkgver=0.1.11
pkgver=0.1.16
pkgrel=1
pkgdesc="Cross-shell abbreviation engine that expands short tokens into full commands"
arch=('x86_64' 'aarch64')
Expand All @@ -12,10 +12,10 @@ source_x86_64=("runex-${pkgver}-x86_64.tar.gz::https://github.com/ShortArrow/run
source_aarch64=("runex-${pkgver}-aarch64.tar.gz::https://github.com/ShortArrow/runex/releases/download/v${pkgver}/runex-aarch64-unknown-linux-gnu.tar.gz")
source=("LICENSE-${pkgver}::https://raw.githubusercontent.com/ShortArrow/runex/v${pkgver}/LICENSE"
"README-${pkgver}.md::https://raw.githubusercontent.com/ShortArrow/runex/v${pkgver}/README.md")
sha256sums_x86_64=('1d2767e51ae575739ef97a048a27334c3d7c8b46550cd5ee400c85444b91e5fe')
sha256sums_aarch64=('14f94242f7d151158ffaefbf90541e78d828d620b3a0588a8bbac6c2d9361422')
sha256sums=('19614dcc7dc2af82331a66d30ab79d5674be3ce73ef853ed76e1743b2830f4d0'
'b5d6502f8cf0088b3d75cc79a1fad78ca7da3374803a49e70b7709f991410439')
sha256sums_x86_64=('3857d2ded00a0c5b2d8c18e6357aea6e6f2c07854cf5c2a28a79ec3d5a4d16b7')
sha256sums_aarch64=('171f1cd715f0420c6058769d45c6dcdcbbda0f6eae65cfd947c34e8995255858')
sha256sums=('735fa89d57bbf22a8c85d829aa1ed791cce81ffdb900467333025ab7b2feee1c'
'6841cfc9dce7aabf01df2cfc36c8f9ee030c16eae6e50f877f8311538c735942')

package() {
install -Dm755 "${srcdir}/runex" "${pkgdir}/usr/bin/runex"
Expand Down
Empty file modified packaging/aur-bin/release.sh
100644 → 100755
Empty file.
22 changes: 22 additions & 0 deletions packaging/aur/.SRCINFO
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
pkgbase = runex
pkgdesc = Cross-shell abbreviation engine that expands short tokens into full commands
pkgver = 0.1.16
pkgrel = 1
url = https://github.com/ShortArrow/runex
arch = x86_64
arch = aarch64
license = MIT
license = Apache-2.0
makedepends = rust
makedepends = pkgconf
depends = glibc
depends = libgcc
depends = openssl
provides = runex
conflicts = runex-bin
source = runex-0.1.16.crate::https://crates.io/api/v1/crates/runex/0.1.16/download
source = LICENSE
sha256sums = 0c13a94189c9a38430c940488bf4f99df8d4cdae129d0b8cf7035beae5e2a958
sha256sums = 735fa89d57bbf22a8c85d829aa1ed791cce81ffdb900467333025ab7b2feee1c

pkgname = runex
3 changes: 3 additions & 0 deletions packaging/aur/.nvchecker.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[runex]
source = "cratesio"
cratesio = "runex"
48 changes: 48 additions & 0 deletions packaging/aur/PKGBUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Maintainer: ShortArrow <bamboogeneral@gmail.com>
# Contributor: Rafael Dominiquini <rafaeldominiquini at gmail dot com>

_pkgauthor=ShortArrow
_pkgname=runex
_cratename=${_pkgname}
_appname=runex
pkgname=${_cratename}
pkgdesc="Cross-shell abbreviation engine that expands short tokens into full commands"

pkgver=0.1.16
pkgrel=1
_pkgvername=${pkgver}

arch=('x86_64' 'aarch64')
_barch=('x86_64' 'aarch64')

url="https://github.com/${_pkgauthor}/${_pkgname}"

license=('MIT' 'Apache-2.0')

makedepends=('rust' 'pkgconf')
depends=('glibc' 'libgcc' 'openssl')

provides=("${_appname}")
conflicts=('runex-bin')

source=("${_pkgname}-${_pkgvername}.crate::https://crates.io/api/v1/crates/${_cratename}/${_pkgvername}/download"
"LICENSE")
sha256sums=('0c13a94189c9a38430c940488bf4f99df8d4cdae129d0b8cf7035beae5e2a958'
'735fa89d57bbf22a8c85d829aa1ed791cce81ffdb900467333025ab7b2feee1c')


build() {
cd ${srcdir}/${_cratename}-${_pkgvername} || exit 1

RUSTFLAGS="--remap-path-prefix=$(pwd)=/build/" cargo build --release --locked
}

package() {
cd ${srcdir}/${_cratename}-${_pkgvername} || exit 1

install -Dm755 "target/release/${_appname}" "${pkgdir}/usr/bin/${_appname}"

install -Dm644 "README.md" "${pkgdir}/usr/share/doc/${pkgname}/README.md"

install -Dm644 "../LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
}
Loading
Loading