Export $FZF_KEY environment variable to child processes

It's the name of the last key pressed.

Related #3412
This commit is contained in:
Junegunn Choi 2024-04-13 14:00:16 +09:00
parent a4745626dd
commit fd1ba46f77
No known key found for this signature in database
GPG Key ID: 254BC280FEF9C627
8 changed files with 315 additions and 121 deletions

View File

@ -1,6 +1,28 @@
CHANGELOG CHANGELOG
========= =========
0.50.0
------
- Added `jump` and `jump-cancel` events that are triggered when leaving `jump` mode
```sh
# Default behavior
fzf --bind space:jump
# Same as jump-accept action
fzf --bind space:jump,jump:accept
# Accept on jump, abort on cancel
fzf --bind space:jump,jump:accept,jump-cancel:abort
# Change header on jump-cancel
fzf --bind 'space:change-header(Type jump label)+jump,jump-cancel:change-header:Jump cancelled'
```
- Added a new environment variable `$FZF_KEY` exported to the child processes. It's the name of the last key pressed.
```sh
fzf --bind 'space:jump,jump:accept,jump-cancel:transform:[[ $FZF_KEY =~ ctrl-c ]] && echo abort'
```
- Bug fixes
0.49.0 0.49.0
------ ------
- Ingestion performance improved by around 40% (more or less depending on options) - Ingestion performance improved by around 40% (more or less depending on options)

View File

@ -191,7 +191,7 @@ actions are affected:
\fBkill-word\fR \fBkill-word\fR
.TP .TP
.BI "--jump-labels=" "CHARS" .BI "--jump-labels=" "CHARS"
Label characters for \fBjump\fR and \fBjump-accept\fR Label characters for \fBjump\fR mode.
.SS Layout .SS Layout
.TP .TP
.BI "--height=" "[~]HEIGHT[%]" .BI "--height=" "[~]HEIGHT[%]"
@ -982,6 +982,8 @@ fzf exports the following environment variables to its child processes.
.br .br
.BR FZF_ACTION " The name of the last action performed" .BR FZF_ACTION " The name of the last action performed"
.br .br
.BR FZF_KEY " The name of the last key pressed"
.br
.BR FZF_PORT " Port number when --listen option is used" .BR FZF_PORT " Port number when --listen option is used"
.br .br
@ -1052,21 +1054,21 @@ e.g.
.br .br
\fIctrl-]\fR \fIctrl-]\fR
.br .br
\fIctrl-^\fR (\fIctrl-6\fR) \fIctrl-^\fR (\fIctrl-6\fR)
.br .br
\fIctrl-/\fR (\fIctrl-_\fR) \fIctrl-/\fR (\fIctrl-_\fR)
.br .br
\fIctrl-alt-[a-z]\fR \fIctrl-alt-[a-z]\fR
.br .br
\fIalt-[*]\fR (Any case-sensitive single character is allowed) \fIalt-[*]\fR (Any case-sensitive single character is allowed)
.br .br
\fIf[1-12]\fR \fIf[1-12]\fR
.br .br
\fIenter\fR (\fIreturn\fR \fIctrl-m\fR) \fIenter\fR (\fIreturn\fR \fIctrl-m\fR)
.br .br
\fIspace\fR \fIspace\fR
.br .br
\fIbspace\fR (\fIbs\fR) \fIbackspace\fR (\fIbspace\fR \fIbs\fR)
.br .br
\fIalt-up\fR \fIalt-up\fR
.br .br
@ -1080,15 +1082,15 @@ e.g.
.br .br
\fIalt-space\fR \fIalt-space\fR
.br .br
\fIalt-bspace\fR (\fIalt-bs\fR) \fIalt-backspace\fR (\fIalt-bspace\fR \fIalt-bs\fR)
.br .br
\fItab\fR \fItab\fR
.br .br
\fIbtab\fR (\fIshift-tab\fR) \fIshift-tab\fR (\fIbtab\fR)
.br .br
\fIesc\fR \fIesc\fR
.br .br
\fIdel\fR \fIdelete\fR (\fIdel\fR)
.br .br
\fIup\fR \fIup\fR
.br .br
@ -1104,9 +1106,9 @@ e.g.
.br .br
\fIinsert\fR \fIinsert\fR
.br .br
\fIpgup\fR (\fIpage-up\fR) \fIpage-up\fR (\fIpgup\fR)
.br .br
\fIpgdn\fR (\fIpage-down\fR) \fIpage-down\fR (\fIpgdn\fR)
.br .br
\fIshift-up\fR \fIshift-up\fR
.br .br
@ -1248,7 +1250,7 @@ e.g.
\fIjump\fR \fIjump\fR
.RS .RS
Triggered when successfully jumped to the target item in \fB--jump\fR mode. Triggered when successfully jumped to the target item in \fBjump\fR mode.
e.g. e.g.
\fBfzf --bind space:jump,jump:accept\fR \fBfzf --bind space:jump,jump:accept\fR
@ -1256,7 +1258,7 @@ e.g.
\fIjump-cancel\fR \fIjump-cancel\fR
.RS .RS
Triggered when \fB--jump\fR mode is cancelled. Triggered when \fBjump\fR mode is cancelled.
e.g. e.g.
\fBfzf --bind space:jump,jump:accept,jump-cancel:abort\fR \fBfzf --bind space:jump,jump:accept,jump-cancel:abort\fR
@ -1304,7 +1306,6 @@ A key or an event can be bound to one or more of the following actions.
\fBforward-word\fR \fIalt-f shift-right\fR \fBforward-word\fR \fIalt-f shift-right\fR
\fBignore\fR \fBignore\fR
\fBjump\fR (EasyMotion-like 2-keystroke movement) \fBjump\fR (EasyMotion-like 2-keystroke movement)
\fBjump-accept\fR (jump and accept)
\fBkill-line\fR \fBkill-line\fR
\fBkill-word\fR \fIalt-d\fR \fBkill-word\fR \fIalt-d\fR
\fBlast\fR (move to the last match; same as \fBpos(-1)\fR) \fBlast\fR (move to the last match; same as \fBpos(-1)\fR)

View File

@ -52,7 +52,7 @@ const usage = `usage: fzf [options]
--hscroll-off=COLS Number of screen columns to keep to the right of the --hscroll-off=COLS Number of screen columns to keep to the right of the
highlighted substring (default: 10) highlighted substring (default: 10)
--filepath-word Make word-wise movements respect path separators --filepath-word Make word-wise movements respect path separators
--jump-labels=CHARS Label characters for jump and jump-accept --jump-labels=CHARS Label characters for jump mode
Layout Layout
--height=[~]HEIGHT[%] Display fzf window below the cursor with the given --height=[~]HEIGHT[%] Display fzf window below the cursor with the given
@ -666,8 +666,8 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E
add(tui.CtrlM) add(tui.CtrlM)
case "space": case "space":
chords[tui.Key(' ')] = key chords[tui.Key(' ')] = key
case "bspace", "bs": case "backspace", "bspace", "bs":
add(tui.BSpace) add(tui.Backspace)
case "ctrl-space": case "ctrl-space":
add(tui.CtrlSpace) add(tui.CtrlSpace)
case "ctrl-delete": case "ctrl-delete":
@ -706,8 +706,8 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E
chords[tui.CtrlAltKey('m')] = key chords[tui.CtrlAltKey('m')] = key
case "alt-space": case "alt-space":
chords[tui.AltKey(' ')] = key chords[tui.AltKey(' ')] = key
case "alt-bs", "alt-bspace": case "alt-bs", "alt-bspace", "alt-backspace":
add(tui.AltBS) add(tui.AltBackspace)
case "alt-up": case "alt-up":
add(tui.AltUp) add(tui.AltUp)
case "alt-down": case "alt-down":
@ -719,11 +719,11 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E
case "tab": case "tab":
add(tui.Tab) add(tui.Tab)
case "btab", "shift-tab": case "btab", "shift-tab":
add(tui.BTab) add(tui.ShiftTab)
case "esc": case "esc":
add(tui.ESC) add(tui.Esc)
case "del": case "delete", "del":
add(tui.Del) add(tui.Delete)
case "home": case "home":
add(tui.Home) add(tui.Home)
case "end": case "end":
@ -731,27 +731,27 @@ func parseKeyChordsImpl(str string, message string, exit func(string)) map[tui.E
case "insert": case "insert":
add(tui.Insert) add(tui.Insert)
case "pgup", "page-up": case "pgup", "page-up":
add(tui.PgUp) add(tui.PageUp)
case "pgdn", "page-down": case "pgdn", "page-down":
add(tui.PgDn) add(tui.PageDown)
case "alt-shift-up", "shift-alt-up": case "alt-shift-up", "shift-alt-up":
add(tui.AltSUp) add(tui.AltShiftUp)
case "alt-shift-down", "shift-alt-down": case "alt-shift-down", "shift-alt-down":
add(tui.AltSDown) add(tui.AltShiftDown)
case "alt-shift-left", "shift-alt-left": case "alt-shift-left", "shift-alt-left":
add(tui.AltSLeft) add(tui.AltShiftLeft)
case "alt-shift-right", "shift-alt-right": case "alt-shift-right", "shift-alt-right":
add(tui.AltSRight) add(tui.AltShiftRight)
case "shift-up": case "shift-up":
add(tui.SUp) add(tui.ShiftUp)
case "shift-down": case "shift-down":
add(tui.SDown) add(tui.ShiftDown)
case "shift-left": case "shift-left":
add(tui.SLeft) add(tui.ShiftLeft)
case "shift-right": case "shift-right":
add(tui.SRight) add(tui.ShiftRight)
case "shift-delete": case "shift-delete":
add(tui.SDelete) add(tui.ShiftDelete)
case "left-click": case "left-click":
add(tui.LeftClick) add(tui.LeftClick)
case "right-click": case "right-click":

View File

@ -293,6 +293,7 @@ type Terminal struct {
executing *util.AtomicBool executing *util.AtomicBool
termSize tui.TermSize termSize tui.TermSize
lastAction actionType lastAction actionType
lastKey string
lastFocus int32 lastFocus int32
areaLines int areaLines int
areaColumns int areaColumns int
@ -408,7 +409,7 @@ const (
actOffsetUp actOffsetUp
actOffsetDown actOffsetDown
actJump actJump
actJumpAccept actJumpAccept // XXX Deprecated in favor of jump:accept binding
actPrintQuery actPrintQuery
actRefreshPreview actRefreshPreview
actReplaceQuery actReplaceQuery
@ -460,14 +461,7 @@ const (
) )
func (a actionType) Name() string { func (a actionType) Name() string {
name := "" return util.ToKebabCase(a.String()[3:])
for i, r := range a.String()[3:] {
if i > 0 && r >= 'A' && r <= 'Z' {
name += "-"
}
name += string(r)
}
return strings.ToLower(name)
} }
func processExecution(action actionType) bool { func processExecution(action actionType) bool {
@ -546,14 +540,14 @@ func defaultKeymap() map[tui.Event][]*action {
add(tui.CtrlC, actAbort) add(tui.CtrlC, actAbort)
add(tui.CtrlG, actAbort) add(tui.CtrlG, actAbort)
add(tui.CtrlQ, actAbort) add(tui.CtrlQ, actAbort)
add(tui.ESC, actAbort) add(tui.Esc, actAbort)
add(tui.CtrlD, actDeleteCharEof) add(tui.CtrlD, actDeleteCharEof)
add(tui.CtrlE, actEndOfLine) add(tui.CtrlE, actEndOfLine)
add(tui.CtrlF, actForwardChar) add(tui.CtrlF, actForwardChar)
add(tui.CtrlH, actBackwardDeleteChar) add(tui.CtrlH, actBackwardDeleteChar)
add(tui.BSpace, actBackwardDeleteChar) add(tui.Backspace, actBackwardDeleteChar)
add(tui.Tab, actToggleDown) add(tui.Tab, actToggleDown)
add(tui.BTab, actToggleUp) add(tui.ShiftTab, actToggleUp)
add(tui.CtrlJ, actDown) add(tui.CtrlJ, actDown)
add(tui.CtrlK, actUp) add(tui.CtrlK, actUp)
add(tui.CtrlL, actClearScreen) add(tui.CtrlL, actClearScreen)
@ -568,11 +562,11 @@ func defaultKeymap() map[tui.Event][]*action {
} }
addEvent(tui.AltKey('b'), actBackwardWord) addEvent(tui.AltKey('b'), actBackwardWord)
add(tui.SLeft, actBackwardWord) add(tui.ShiftLeft, actBackwardWord)
addEvent(tui.AltKey('f'), actForwardWord) addEvent(tui.AltKey('f'), actForwardWord)
add(tui.SRight, actForwardWord) add(tui.ShiftRight, actForwardWord)
addEvent(tui.AltKey('d'), actKillWord) addEvent(tui.AltKey('d'), actKillWord)
add(tui.AltBS, actBackwardKillWord) add(tui.AltBackspace, actBackwardKillWord)
add(tui.Up, actUp) add(tui.Up, actUp)
add(tui.Down, actDown) add(tui.Down, actDown)
@ -581,12 +575,12 @@ func defaultKeymap() map[tui.Event][]*action {
add(tui.Home, actBeginningOfLine) add(tui.Home, actBeginningOfLine)
add(tui.End, actEndOfLine) add(tui.End, actEndOfLine)
add(tui.Del, actDeleteChar) add(tui.Delete, actDeleteChar)
add(tui.PgUp, actPageUp) add(tui.PageUp, actPageUp)
add(tui.PgDn, actPageDown) add(tui.PageDown, actPageDown)
add(tui.SUp, actPreviewUp) add(tui.ShiftUp, actPreviewUp)
add(tui.SDown, actPreviewDown) add(tui.ShiftDown, actPreviewDown)
add(tui.Mouse, actMouse) add(tui.Mouse, actMouse)
add(tui.LeftClick, actClick) add(tui.LeftClick, actClick)
@ -851,6 +845,7 @@ func (t *Terminal) environ() []string {
} }
env = append(env, "FZF_QUERY="+string(t.input)) env = append(env, "FZF_QUERY="+string(t.input))
env = append(env, "FZF_ACTION="+t.lastAction.Name()) env = append(env, "FZF_ACTION="+t.lastAction.Name())
env = append(env, "FZF_KEY="+t.lastKey)
env = append(env, "FZF_PROMPT="+string(t.promptString)) env = append(env, "FZF_PROMPT="+string(t.promptString))
env = append(env, "FZF_PREVIEW_LABEL="+t.previewLabelOpts.label) env = append(env, "FZF_PREVIEW_LABEL="+t.previewLabelOpts.label)
env = append(env, "FZF_BORDER_LABEL="+t.borderLabelOpts.label) env = append(env, "FZF_BORDER_LABEL="+t.borderLabelOpts.label)
@ -3290,6 +3285,7 @@ func (t *Terminal) Loop() {
t.mutex.Lock() t.mutex.Lock()
previousInput := t.input previousInput := t.input
previousCx := t.cx previousCx := t.cx
t.lastKey = event.KeyName()
events := []util.EventType{} events := []util.EventType{}
req := func(evts ...util.EventType) { req := func(evts ...util.EventType) {
for _, event := range evts { for _, event := range evts {

120
src/tui/eventtype_string.go Normal file
View File

@ -0,0 +1,120 @@
// Code generated by "stringer -type=EventType"; DO NOT EDIT.
package tui
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[Rune-0]
_ = x[CtrlA-1]
_ = x[CtrlB-2]
_ = x[CtrlC-3]
_ = x[CtrlD-4]
_ = x[CtrlE-5]
_ = x[CtrlF-6]
_ = x[CtrlG-7]
_ = x[CtrlH-8]
_ = x[Tab-9]
_ = x[CtrlJ-10]
_ = x[CtrlK-11]
_ = x[CtrlL-12]
_ = x[CtrlM-13]
_ = x[CtrlN-14]
_ = x[CtrlO-15]
_ = x[CtrlP-16]
_ = x[CtrlQ-17]
_ = x[CtrlR-18]
_ = x[CtrlS-19]
_ = x[CtrlT-20]
_ = x[CtrlU-21]
_ = x[CtrlV-22]
_ = x[CtrlW-23]
_ = x[CtrlX-24]
_ = x[CtrlY-25]
_ = x[CtrlZ-26]
_ = x[Esc-27]
_ = x[CtrlSpace-28]
_ = x[CtrlDelete-29]
_ = x[CtrlBackSlash-30]
_ = x[CtrlRightBracket-31]
_ = x[CtrlCaret-32]
_ = x[CtrlSlash-33]
_ = x[ShiftTab-34]
_ = x[Backspace-35]
_ = x[Delete-36]
_ = x[PageUp-37]
_ = x[PageDown-38]
_ = x[Up-39]
_ = x[Down-40]
_ = x[Left-41]
_ = x[Right-42]
_ = x[Home-43]
_ = x[End-44]
_ = x[Insert-45]
_ = x[ShiftUp-46]
_ = x[ShiftDown-47]
_ = x[ShiftLeft-48]
_ = x[ShiftRight-49]
_ = x[ShiftDelete-50]
_ = x[F1-51]
_ = x[F2-52]
_ = x[F3-53]
_ = x[F4-54]
_ = x[F5-55]
_ = x[F6-56]
_ = x[F7-57]
_ = x[F8-58]
_ = x[F9-59]
_ = x[F10-60]
_ = x[F11-61]
_ = x[F12-62]
_ = x[AltBackspace-63]
_ = x[AltUp-64]
_ = x[AltDown-65]
_ = x[AltLeft-66]
_ = x[AltRight-67]
_ = x[AltShiftUp-68]
_ = x[AltShiftDown-69]
_ = x[AltShiftLeft-70]
_ = x[AltShiftRight-71]
_ = x[Alt-72]
_ = x[CtrlAlt-73]
_ = x[Invalid-74]
_ = x[Mouse-75]
_ = x[DoubleClick-76]
_ = x[LeftClick-77]
_ = x[RightClick-78]
_ = x[SLeftClick-79]
_ = x[SRightClick-80]
_ = x[ScrollUp-81]
_ = x[ScrollDown-82]
_ = x[SScrollUp-83]
_ = x[SScrollDown-84]
_ = x[PreviewScrollUp-85]
_ = x[PreviewScrollDown-86]
_ = x[Resize-87]
_ = x[Change-88]
_ = x[BackwardEOF-89]
_ = x[Start-90]
_ = x[Load-91]
_ = x[Focus-92]
_ = x[One-93]
_ = x[Zero-94]
_ = x[Result-95]
_ = x[Jump-96]
_ = x[JumpCancel-97]
}
const _EventType_name = "RuneCtrlACtrlBCtrlCCtrlDCtrlECtrlFCtrlGCtrlHTabCtrlJCtrlKCtrlLCtrlMCtrlNCtrlOCtrlPCtrlQCtrlRCtrlSCtrlTCtrlUCtrlVCtrlWCtrlXCtrlYCtrlZEscCtrlSpaceCtrlDeleteCtrlBackSlashCtrlRightBracketCtrlCaretCtrlSlashShiftTabBackspaceDeletePageUpPageDownUpDownLeftRightHomeEndInsertShiftUpShiftDownShiftLeftShiftRightShiftDeleteF1F2F3F4F5F6F7F8F9F10F11F12AltBackspaceAltUpAltDownAltLeftAltRightAltShiftUpAltShiftDownAltShiftLeftAltShiftRightAltCtrlAltInvalidMouseDoubleClickLeftClickRightClickSLeftClickSRightClickScrollUpScrollDownSScrollUpSScrollDownPreviewScrollUpPreviewScrollDownResizeChangeBackwardEOFStartLoadFocusOneZeroResultJumpJumpCancel"
var _EventType_index = [...]uint16{0, 4, 9, 14, 19, 24, 29, 34, 39, 44, 47, 52, 57, 62, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117, 122, 127, 132, 135, 144, 154, 167, 183, 192, 201, 209, 218, 224, 230, 238, 240, 244, 248, 253, 257, 260, 266, 273, 282, 291, 301, 312, 314, 316, 318, 320, 322, 324, 326, 328, 330, 333, 336, 339, 351, 356, 363, 370, 378, 388, 400, 412, 425, 428, 435, 442, 447, 458, 467, 477, 487, 498, 506, 516, 525, 536, 551, 568, 574, 580, 591, 596, 600, 605, 608, 612, 618, 622, 632}
func (i EventType) String() string {
if i < 0 || i >= EventType(len(_EventType_index)-1) {
return "EventType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _EventType_name[_EventType_index[i]:_EventType_index[i+1]]
}

View File

@ -245,7 +245,7 @@ func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) []byte {
} }
retries := 0 retries := 0
if c == ESC.Int() || nonblock { if c == Esc.Int() || nonblock {
retries = r.escDelay / escPollInterval retries = r.escDelay / escPollInterval
} }
buffer = append(buffer, byte(c)) buffer = append(buffer, byte(c))
@ -260,7 +260,7 @@ func (r *LightRenderer) getBytesInternal(buffer []byte, nonblock bool) []byte {
continue continue
} }
break break
} else if c == ESC.Int() && pc != c { } else if c == Esc.Int() && pc != c {
retries = r.escDelay / escPollInterval retries = r.escDelay / escPollInterval
} else { } else {
retries = 0 retries = 0
@ -300,7 +300,7 @@ func (r *LightRenderer) GetChar() Event {
case CtrlQ.Byte(): case CtrlQ.Byte():
return Event{CtrlQ, 0, nil} return Event{CtrlQ, 0, nil}
case 127: case 127:
return Event{BSpace, 0, nil} return Event{Backspace, 0, nil}
case 0: case 0:
return Event{CtrlSpace, 0, nil} return Event{CtrlSpace, 0, nil}
case 28: case 28:
@ -311,7 +311,7 @@ func (r *LightRenderer) GetChar() Event {
return Event{CtrlCaret, 0, nil} return Event{CtrlCaret, 0, nil}
case 31: case 31:
return Event{CtrlSlash, 0, nil} return Event{CtrlSlash, 0, nil}
case ESC.Byte(): case Esc.Byte():
ev := r.escSequence(&sz) ev := r.escSequence(&sz)
// Second chance // Second chance
if ev.Type == Invalid { if ev.Type == Invalid {
@ -327,7 +327,7 @@ func (r *LightRenderer) GetChar() Event {
} }
char, rsz := utf8.DecodeRune(r.buffer) char, rsz := utf8.DecodeRune(r.buffer)
if char == utf8.RuneError { if char == utf8.RuneError {
return Event{ESC, 0, nil} return Event{Esc, 0, nil}
} }
sz = rsz sz = rsz
return Event{Rune, char, nil} return Event{Rune, char, nil}
@ -335,7 +335,7 @@ func (r *LightRenderer) GetChar() Event {
func (r *LightRenderer) escSequence(sz *int) Event { func (r *LightRenderer) escSequence(sz *int) Event {
if len(r.buffer) < 2 { if len(r.buffer) < 2 {
return Event{ESC, 0, nil} return Event{Esc, 0, nil}
} }
loc := offsetRegexpBegin.FindIndex(r.buffer) loc := offsetRegexpBegin.FindIndex(r.buffer)
@ -349,15 +349,15 @@ func (r *LightRenderer) escSequence(sz *int) Event {
return CtrlAltKey(rune(r.buffer[1] + 'a' - 1)) return CtrlAltKey(rune(r.buffer[1] + 'a' - 1))
} }
alt := false alt := false
if len(r.buffer) > 2 && r.buffer[1] == ESC.Byte() { if len(r.buffer) > 2 && r.buffer[1] == Esc.Byte() {
r.buffer = r.buffer[1:] r.buffer = r.buffer[1:]
alt = true alt = true
} }
switch r.buffer[1] { switch r.buffer[1] {
case ESC.Byte(): case Esc.Byte():
return Event{ESC, 0, nil} return Event{Esc, 0, nil}
case 127: case 127:
return Event{AltBS, 0, nil} return Event{AltBackspace, 0, nil}
case '[', 'O': case '[', 'O':
if len(r.buffer) < 3 { if len(r.buffer) < 3 {
return Event{Invalid, 0, nil} return Event{Invalid, 0, nil}
@ -386,7 +386,7 @@ func (r *LightRenderer) escSequence(sz *int) Event {
} }
return Event{Up, 0, nil} return Event{Up, 0, nil}
case 'Z': case 'Z':
return Event{BTab, 0, nil} return Event{ShiftTab, 0, nil}
case 'H': case 'H':
return Event{Home, 0, nil} return Event{Home, 0, nil}
case 'F': case 'F':
@ -434,7 +434,7 @@ func (r *LightRenderer) escSequence(sz *int) Event {
return Event{Invalid, 0, nil} // INS return Event{Invalid, 0, nil} // INS
case '3': case '3':
if r.buffer[3] == '~' { if r.buffer[3] == '~' {
return Event{Del, 0, nil} return Event{Delete, 0, nil}
} }
if len(r.buffer) == 6 && r.buffer[5] == '~' { if len(r.buffer) == 6 && r.buffer[5] == '~' {
*sz = 6 *sz = 6
@ -442,16 +442,16 @@ func (r *LightRenderer) escSequence(sz *int) Event {
case '5': case '5':
return Event{CtrlDelete, 0, nil} return Event{CtrlDelete, 0, nil}
case '2': case '2':
return Event{SDelete, 0, nil} return Event{ShiftDelete, 0, nil}
} }
} }
return Event{Invalid, 0, nil} return Event{Invalid, 0, nil}
case '4': case '4':
return Event{End, 0, nil} return Event{End, 0, nil}
case '5': case '5':
return Event{PgUp, 0, nil} return Event{PageUp, 0, nil}
case '6': case '6':
return Event{PgDn, 0, nil} return Event{PageDown, 0, nil}
case '7': case '7':
return Event{Home, 0, nil} return Event{Home, 0, nil}
case '8': case '8':
@ -489,16 +489,29 @@ func (r *LightRenderer) escSequence(sz *int) Event {
} }
*sz = 6 *sz = 6
switch r.buffer[4] { switch r.buffer[4] {
case '1', '2', '3', '5': case '1', '2', '3', '4', '5':
// Kitty iTerm2 WezTerm
// SHIFT-ARROW "\e[1;2D"
// ALT-SHIFT-ARROW "\e[1;4D" "\e[1;10D" "\e[1;4D"
// CTRL-SHIFT-ARROW "\e[1;6D" N/A
// CMD-SHIFT-ARROW "\e[1;10D" N/A N/A ("\e[1;2D")
alt := r.buffer[4] == '3' alt := r.buffer[4] == '3'
altShift := r.buffer[4] == '1' && r.buffer[5] == '0'
char := r.buffer[5] char := r.buffer[5]
if altShift { altShift := false
if r.buffer[4] == '1' && r.buffer[5] == '0' {
altShift = true
if len(r.buffer) < 7 { if len(r.buffer) < 7 {
return Event{Invalid, 0, nil} return Event{Invalid, 0, nil}
} }
*sz = 7 *sz = 7
char = r.buffer[6] char = r.buffer[6]
} else if r.buffer[4] == '4' {
altShift = true
if len(r.buffer) < 6 {
return Event{Invalid, 0, nil}
}
*sz = 6
char = r.buffer[5]
} }
switch char { switch char {
case 'A': case 'A':
@ -506,33 +519,33 @@ func (r *LightRenderer) escSequence(sz *int) Event {
return Event{AltUp, 0, nil} return Event{AltUp, 0, nil}
} }
if altShift { if altShift {
return Event{AltSUp, 0, nil} return Event{AltShiftUp, 0, nil}
} }
return Event{SUp, 0, nil} return Event{ShiftUp, 0, nil}
case 'B': case 'B':
if alt { if alt {
return Event{AltDown, 0, nil} return Event{AltDown, 0, nil}
} }
if altShift { if altShift {
return Event{AltSDown, 0, nil} return Event{AltShiftDown, 0, nil}
} }
return Event{SDown, 0, nil} return Event{ShiftDown, 0, nil}
case 'C': case 'C':
if alt { if alt {
return Event{AltRight, 0, nil} return Event{AltRight, 0, nil}
} }
if altShift { if altShift {
return Event{AltSRight, 0, nil} return Event{AltShiftRight, 0, nil}
} }
return Event{SRight, 0, nil} return Event{ShiftRight, 0, nil}
case 'D': case 'D':
if alt { if alt {
return Event{AltLeft, 0, nil} return Event{AltLeft, 0, nil}
} }
if altShift { if altShift {
return Event{AltSLeft, 0, nil} return Event{AltShiftLeft, 0, nil}
} }
return Event{SLeft, 0, nil} return Event{ShiftLeft, 0, nil}
} }
} // r.buffer[4] } // r.buffer[4]
} // r.buffer[3] } // r.buffer[3]

View File

@ -6,10 +6,13 @@ import (
"strconv" "strconv"
"time" "time"
"github.com/junegunn/fzf/src/util"
"github.com/rivo/uniseg" "github.com/rivo/uniseg"
) )
// Types of user action // Types of user action
//
//go:generate stringer -type=EventType
type EventType int type EventType int
const ( const (
@ -41,7 +44,7 @@ const (
CtrlX CtrlX
CtrlY CtrlY
CtrlZ CtrlZ
ESC Esc
CtrlSpace CtrlSpace
CtrlDelete CtrlDelete
@ -51,27 +54,12 @@ const (
CtrlCaret CtrlCaret
CtrlSlash CtrlSlash
Invalid ShiftTab
Resize Backspace
Mouse
DoubleClick
LeftClick
RightClick
SLeftClick
SRightClick
ScrollUp
ScrollDown
SScrollUp
SScrollDown
PreviewScrollUp
PreviewScrollDown
BTab Delete
BSpace PageUp
PageDown
Del
PgUp
PgDn
Up Up
Down Down
@ -81,11 +69,11 @@ const (
End End
Insert Insert
SUp ShiftUp
SDown ShiftDown
SLeft ShiftLeft
SRight ShiftRight
SDelete ShiftDelete
F1 F1
F2 F2
@ -100,6 +88,38 @@ const (
F11 F11
F12 F12
AltBackspace
AltUp
AltDown
AltLeft
AltRight
AltShiftUp
AltShiftDown
AltShiftLeft
AltShiftRight
Alt
CtrlAlt
Invalid
Mouse
DoubleClick
LeftClick
RightClick
SLeftClick
SRightClick
ScrollUp
ScrollDown
SScrollUp
SScrollDown
PreviewScrollUp
PreviewScrollDown
// Events
Resize
Change Change
BackwardEOF BackwardEOF
Start Start
@ -110,21 +130,6 @@ const (
Result Result
Jump Jump
JumpCancel JumpCancel
AltBS
AltUp
AltDown
AltLeft
AltRight
AltSUp
AltSDown
AltSLeft
AltSRight
Alt
CtrlAlt
) )
func (t EventType) AsEvent() Event { func (t EventType) AsEvent() Event {
@ -144,6 +149,31 @@ func (e Event) Comparable() Event {
return Event{e.Type, e.Char, nil} return Event{e.Type, e.Char, nil}
} }
func (e Event) KeyName() string {
if e.Type >= Invalid {
return ""
}
switch e.Type {
case Rune:
return string(e.Char)
case Alt:
return "alt-" + string(e.Char)
case CtrlAlt:
return "ctrl-alt-" + string(e.Char)
case CtrlBackSlash:
return "ctrl-\\"
case CtrlRightBracket:
return "ctrl-]"
case CtrlCaret:
return "ctrl-^"
case CtrlSlash:
return "ctrl-/"
}
return util.ToKebabCase(e.Type.String())
}
func Key(r rune) Event { func Key(r rune) Event {
return Event{Rune, r, nil} return Event{Rune, r, nil}
} }

View File

@ -176,3 +176,15 @@ func RepeatToFill(str string, length int, limit int) string {
} }
return output return output
} }
// ToKebabCase converts the given CamelCase string to kebab-case
func ToKebabCase(s string) string {
name := ""
for i, r := range s {
if i > 0 && r >= 'A' && r <= 'Z' {
name += "-"
}
name += string(r)
}
return strings.ToLower(name)
}