Skip to content

Cancel key reading when 'execute' triggered via a server request#4653

Merged
junegunn merged 9 commits into
masterfrom
cancel-key-reading
Jan 8, 2026
Merged

Cancel key reading when 'execute' triggered via a server request#4653
junegunn merged 9 commits into
masterfrom
cancel-key-reading

Conversation

@junegunn

@junegunn junegunn commented Jan 2, 2026

Copy link
Copy Markdown
Owner

Fix #4524
Close #4648

Note:

Using poll() would simplify the code, but on macOS it just returns POLLNVAL for /dev/tty.

The poll() system call currently does not support devices.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the ability to cancel blocking key reading operations when an 'execute' action is triggered via a server request, addressing issue #4524. The implementation is complete for Unix-like systems but remains unimplemented for Windows (as noted in the TODO comments).

  • Added CancelGetChar() method to the Renderer interface
  • Implemented cancellation mechanism for Unix using pipes and select system call
  • Updated return types from bool to getCharResult enum to handle cancellation state
  • Modified terminal event loop to call CancelGetChar() when execute actions arrive from server

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/tui/tui.go Added CancelGetChar() method to Renderer interface
src/tui/tcell.go Added stub CancelGetChar() implementation with TODO for future work
src/tui/light_windows.go Updated getch() return type from bool to getCharResult enum
src/tui/light_unix.go Implemented getch() cancellation using pipes and select, updated return type to getCharResult enum
src/tui/light.go Added getCharResult type, cancel function field, and CancelGetChar() implementation; updated all related functions to handle cancellation
src/tui/dummy.go Added empty CancelGetChar() stub for dummy renderer
src/terminal.go Added logic to call CancelGetChar() when execute action is received from server

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tui/light_unix.go Outdated
@junegunn junegunn added the bug Something isn't working label Jan 3, 2026
@junegunn junegunn marked this pull request as ready for review January 3, 2026 07:59
@junegunn junegunn force-pushed the cancel-key-reading branch from 47df19c to 57f2ed4 Compare January 4, 2026 00:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/tui/tcell.go
}

func (r *FullscreenRenderer) CancelGetChar() {
// TODO

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CancelGetChar method for tcell renderer is not implemented (marked as TODO). This means that when using the tcell-based renderer, the execute action triggered via server requests will not be able to cancel a blocking GetChar call. Consider implementing this using tcell's event posting mechanism or document this limitation.

Suggested change
// TODO
// Use tcell's event posting mechanism to interrupt a blocking PollEvent/GetChar.
if _screen != nil {
_screen.PostEvent(tcell.NewEventInterrupt(nil))
}

Copilot uses AI. Check for mistakes.
Comment thread src/tui/tcell.go
}

func (r *FullscreenRenderer) GetChar() Event {
func (r *FullscreenRenderer) GetChar(cancellable bool) Event {

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cancellable parameter is not used in this implementation. Since CancelGetChar is not implemented for tcell (marked as TODO), this parameter should either be documented as unused or the cancellation functionality should be implemented.

Suggested change
func (r *FullscreenRenderer) GetChar(cancellable bool) Event {
// GetChar blocks until an event is available. The cancellable parameter is
// ignored in the tcell implementation; cancellation is not supported here.
func (r *FullscreenRenderer) GetChar(_ bool) Event {

Copilot uses AI. Check for mistakes.
Comment thread src/tui/light.go
showCursor bool
mutex sync.Mutex

// Windows only

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment "// Windows only" is now misleading since the mutex field (line 135) is used on all platforms for protecting the cancel function. Consider updating this comment to reflect that only the fields from ttyinChannel onwards are Windows-specific.

Suggested change
// Windows only
// Windows-specific fields (from ttyinChannel onwards)

Copilot uses AI. Check for mistakes.
Comment thread src/tui/light_unix.go
return getter()
}
r.setCancel(func() {
wpipe.Write([]byte{0})

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The write to wpipe in the cancel function does not check for errors. While this is generally acceptable for a cancellation signal, if the write fails (e.g., pipe buffer full or pipe closed due to a race condition), it will silently fail. Consider ignoring the error explicitly with a blank identifier to make the intention clear.

Suggested change
wpipe.Write([]byte{0})
_, _ = wpipe.Write([]byte{0})

Copilot uses AI. Check for mistakes.
Comment thread src/tui/light_test.go
Comment on lines +18 to +28
go func() {
for {
light_renderer.mutex.Lock()
ready := light_renderer.cancel != nil
light_renderer.mutex.Unlock()

if ready {
light_renderer.CancelGetChar()
break
}
}

Copilot AI Jan 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test uses a busy-wait loop that repeatedly locks and unlocks the mutex, which is inefficient and could cause unnecessary CPU usage. Consider using a synchronization primitive like a channel or sync.WaitGroup to signal when the cancel function is ready, or add a small sleep in the loop to reduce CPU usage.

Copilot uses AI. Check for mistakes.
@junegunn junegunn merged commit 3f94bcb into master Jan 8, 2026
11 checks passed
@junegunn junegunn deleted the cancel-key-reading branch January 8, 2026 15:29
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Feb 25, 2026
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [junegunn/fzf](https://github.com/junegunn/fzf) | minor | `v0.67.0` → `v0.68.0` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>junegunn/fzf (junegunn/fzf)</summary>

### [`v0.68.0`](https://github.com/junegunn/fzf/releases/tag/v0.68.0): 0.68.0

[Compare Source](junegunn/fzf@v0.67.0...v0.68.0)

<https://github.com/user-attachments/assets/8d9e6e29-1bde-49d3-b580-c560da394a5d>

- Implemented word wrapping in the list section
  - Added `--wrap=word` (or `--wrap-word`) option and `toggle-wrap-word` action for word-level line wrapping in the list section
  - Changed default binding of `ctrl-/` and `alt-/` from `toggle-wrap` to `toggle-wrap-word`
  ```sh
  fzf --wrap=word
  ```
- Implemented word wrapping in the preview window
  - Added `wrap-word` flag for `--preview-window` to enable word-level wrapping
  - Added `toggle-preview-wrap-word` action
  ```sh
  fzf --preview 'bat --style=plain --color=always {}' \
      --preview-window wrap-word \
      --bind space:toggle-preview-wrap-word
  ```
- Added support for underline style variants in `--color`: `underline-double`, `underline-curly`, `underline-dotted`, `underline-dashed`
  ```sh
  fzf --color 'fg:underline-curly,current-fg:underline-dashed'
  ```
- Added support for underline styles (`4:N`) and underline colors (SGR 58/59)
  ```sh
  # In the list section
  printf '\e[4:3;58;2;255;0;0mRed curly underline\e[0m\n' | fzf --ansi

  # In the preview window
  fzf --preview "printf '\e[4:3;58;2;255;0;0mRed curly underline\e[0m\n'"
  ```
- Added `--preview-wrap-sign` to set a different wrap indicator for the preview window
- Added `alt-gutter` color option ([#&#8203;4602](junegunn/fzf#4602)) ([@&#8203;hedgieinsocks](https://github.com/hedgieinsocks))
- Added `$FZF_WRAP` environment variable to child processes (`char` or `word` when wrapping is enabled) ([#&#8203;4672](junegunn/fzf#4672)) ([@&#8203;bitraid](https://github.com/bitraid))
- fish: Improved command history (CTRL-R) ([#&#8203;4672](junegunn/fzf#4672)) ([@&#8203;bitraid](https://github.com/bitraid))
  - Enabled syntax highlighting in the list on fish 4.3.3+
  - Added syntax-highlighted preview window that auto-shows for long or multi-line commands
  - Added `ALT-ENTER` to reformat and insert selected commands
  - Improved handling of bulk deletion of selected history entries (`SHIFT-DELETE`)
- Added fish completion support ([#&#8203;4605](junegunn/fzf#4605)) ([@&#8203;lalvarezt](https://github.com/lalvarezt))
- zsh: Handle multi-line history selection ([#&#8203;4595](junegunn/fzf#4595)) ([@&#8203;LangLangBart](https://github.com/LangLangBart))
- Bug fixes
  - Fixed `_fzf_compgen_{path,dir}` to respect `FZF_COMPLETION_{PATH,DIR}_OPTS` ([#&#8203;4592](junegunn/fzf#4592)) ([@&#8203;shtse8](https://github.com/shtse8), [@&#8203;LangLangBart](https://github.com/LangLangBart))
  - Fixed `--preview-window follow` not working correctly with wrapping ([#&#8203;3243](junegunn/fzf#3243), [#&#8203;4258](junegunn/fzf#4258))
  - Fixed symlinks to directories being returned as files ([#&#8203;4676](junegunn/fzf#4676)) ([@&#8203;skk64](https://github.com/skk64))
  - Fixed SIGHUP signal handling ([#&#8203;4668](junegunn/fzf#4668)) ([@&#8203;LangLangBart](https://github.com/LangLangBart))
  - Fixed preview process not killed on exit ([#&#8203;4667](junegunn/fzf#4667))
  - Fixed coloring of items with zero-width characters ([#&#8203;4620](junegunn/fzf#4620))
  - Fixed `track-current` unset after a combined movement action ([#&#8203;4649](junegunn/fzf#4649))
  - Fixed `--accept-nth` being ignored in filter mode ([#&#8203;4636](junegunn/fzf#4636)) ([@&#8203;charemma](https://github.com/charemma))
  - Fixed display width calculation with `maxWidth` ([#&#8203;4596](junegunn/fzf#4596)) ([@&#8203;LangLangBart](https://github.com/LangLangBart))
  - Fixed clearing of the rest of the current line on start ([#&#8203;4652](junegunn/fzf#4652))
  - Fixed `x-api-key` header not required for GET requests ([#&#8203;4627](junegunn/fzf#4627))
  - Fixed key reading not cancelled when `execute` triggered via a server request ([#&#8203;4653](junegunn/fzf#4653))
  - Fixed rebind of readline command `redraw-current-line` ([#&#8203;4635](junegunn/fzf#4635)) ([@&#8203;jameslazo](https://github.com/jameslazo))
  - Fixed `fzf-tmux` `TERM` quoting and added `mktemp` usage ([#&#8203;4664](junegunn/fzf#4664)) ([@&#8203;Goofygiraffe06](https://github.com/Goofygiraffe06))
  - Do not allow very long queries in `FuzzyMatchV2` ([#&#8203;4608](junegunn/fzf#4608))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yNS44IiwidXBkYXRlZEluVmVyIjoiNDMuMjYuNCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiUmVub3ZhdGUgQm90IiwiYXV0b21hdGlvbjpib3QtYXV0aG9yZWQiLCJkZXBlbmRlbmN5LXR5cGU6Om1pbm9yIl19-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Problem using 'execute' action invoked via HTTP POST-request

2 participants