Add bindable double-click event (#374)
This commit is contained in:
parent
b4ce89bbf5
commit
f80ff8c917
@ -50,6 +50,7 @@ const (
|
|||||||
|
|
||||||
Invalid
|
Invalid
|
||||||
Mouse
|
Mouse
|
||||||
|
DoubleClick
|
||||||
|
|
||||||
BTab
|
BTab
|
||||||
BSpace
|
BSpace
|
||||||
|
@ -343,6 +343,8 @@ func parseKeyChords(str string, message string) map[int]string {
|
|||||||
chord = curses.SLeft
|
chord = curses.SLeft
|
||||||
case "shift-right":
|
case "shift-right":
|
||||||
chord = curses.SRight
|
chord = curses.SRight
|
||||||
|
case "double-click":
|
||||||
|
chord = curses.DoubleClick
|
||||||
default:
|
default:
|
||||||
if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
if len(key) == 6 && strings.HasPrefix(lkey, "ctrl-") && isAlphabet(lkey[5]) {
|
||||||
chord = curses.CtrlA + int(lkey[5]) - 'a'
|
chord = curses.CtrlA + int(lkey[5]) - 'a'
|
||||||
|
376
src/terminal.go
376
src/terminal.go
@ -180,6 +180,7 @@ func defaultKeymap() map[int]actionType {
|
|||||||
|
|
||||||
keymap[C.Rune] = actRune
|
keymap[C.Rune] = actRune
|
||||||
keymap[C.Mouse] = actMouse
|
keymap[C.Mouse] = actMouse
|
||||||
|
keymap[C.DoubleClick] = actAccept
|
||||||
return keymap
|
return keymap
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -858,204 +859,211 @@ func (t *Terminal) Loop() {
|
|||||||
action = act
|
action = act
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch action {
|
var doAction func(actionType) bool
|
||||||
case actIgnore:
|
doAction = func(action actionType) bool {
|
||||||
case actExecute:
|
switch action {
|
||||||
if t.cy >= 0 && t.cy < t.merger.Length() {
|
case actIgnore:
|
||||||
item := t.merger.Get(t.cy)
|
case actExecute:
|
||||||
executeCommand(t.execmap[mapkey], item.AsString(t.ansi))
|
if t.cy >= 0 && t.cy < t.merger.Length() {
|
||||||
}
|
item := t.merger.Get(t.cy)
|
||||||
case actInvalid:
|
executeCommand(t.execmap[mapkey], item.AsString(t.ansi))
|
||||||
t.mutex.Unlock()
|
}
|
||||||
continue
|
case actInvalid:
|
||||||
case actToggleSort:
|
t.mutex.Unlock()
|
||||||
t.sort = !t.sort
|
return false
|
||||||
t.eventBox.Set(EvtSearchNew, t.sort)
|
case actToggleSort:
|
||||||
t.mutex.Unlock()
|
t.sort = !t.sort
|
||||||
continue
|
t.eventBox.Set(EvtSearchNew, t.sort)
|
||||||
case actBeginningOfLine:
|
t.mutex.Unlock()
|
||||||
t.cx = 0
|
return false
|
||||||
case actBackwardChar:
|
case actBeginningOfLine:
|
||||||
if t.cx > 0 {
|
|
||||||
t.cx--
|
|
||||||
}
|
|
||||||
case actAbort:
|
|
||||||
req(reqQuit)
|
|
||||||
case actDeleteChar:
|
|
||||||
t.delChar()
|
|
||||||
case actDeleteCharEOF:
|
|
||||||
if !t.delChar() && t.cx == 0 {
|
|
||||||
req(reqQuit)
|
|
||||||
}
|
|
||||||
case actEndOfLine:
|
|
||||||
t.cx = len(t.input)
|
|
||||||
case actCancel:
|
|
||||||
if len(t.input) == 0 {
|
|
||||||
req(reqQuit)
|
|
||||||
} else {
|
|
||||||
t.yanked = t.input
|
|
||||||
t.input = []rune{}
|
|
||||||
t.cx = 0
|
t.cx = 0
|
||||||
}
|
case actBackwardChar:
|
||||||
case actForwardChar:
|
if t.cx > 0 {
|
||||||
if t.cx < len(t.input) {
|
t.cx--
|
||||||
t.cx++
|
|
||||||
}
|
|
||||||
case actBackwardDeleteChar:
|
|
||||||
if t.cx > 0 {
|
|
||||||
t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
|
|
||||||
t.cx--
|
|
||||||
}
|
|
||||||
case actSelectAll:
|
|
||||||
if t.multi {
|
|
||||||
for i := 0; i < t.merger.Length(); i++ {
|
|
||||||
item := t.merger.Get(i)
|
|
||||||
selectItem(item)
|
|
||||||
}
|
}
|
||||||
req(reqList, reqInfo)
|
case actAbort:
|
||||||
}
|
req(reqQuit)
|
||||||
case actDeselectAll:
|
case actDeleteChar:
|
||||||
if t.multi {
|
t.delChar()
|
||||||
for i := 0; i < t.merger.Length(); i++ {
|
case actDeleteCharEOF:
|
||||||
item := t.merger.Get(i)
|
if !t.delChar() && t.cx == 0 {
|
||||||
delete(t.selected, item.index)
|
req(reqQuit)
|
||||||
}
|
}
|
||||||
req(reqList, reqInfo)
|
case actEndOfLine:
|
||||||
}
|
|
||||||
case actToggle:
|
|
||||||
if t.multi && t.merger.Length() > 0 {
|
|
||||||
toggle()
|
|
||||||
req(reqList)
|
|
||||||
}
|
|
||||||
case actToggleAll:
|
|
||||||
if t.multi {
|
|
||||||
for i := 0; i < t.merger.Length(); i++ {
|
|
||||||
toggleY(i)
|
|
||||||
}
|
|
||||||
req(reqList, reqInfo)
|
|
||||||
}
|
|
||||||
case actToggleDown:
|
|
||||||
if t.multi && t.merger.Length() > 0 {
|
|
||||||
toggle()
|
|
||||||
t.vmove(-1)
|
|
||||||
req(reqList)
|
|
||||||
}
|
|
||||||
case actToggleUp:
|
|
||||||
if t.multi && t.merger.Length() > 0 {
|
|
||||||
toggle()
|
|
||||||
t.vmove(1)
|
|
||||||
req(reqList)
|
|
||||||
}
|
|
||||||
case actDown:
|
|
||||||
t.vmove(-1)
|
|
||||||
req(reqList)
|
|
||||||
case actUp:
|
|
||||||
t.vmove(1)
|
|
||||||
req(reqList)
|
|
||||||
case actAccept:
|
|
||||||
req(reqClose)
|
|
||||||
case actClearScreen:
|
|
||||||
req(reqRedraw)
|
|
||||||
case actUnixLineDiscard:
|
|
||||||
if t.cx > 0 {
|
|
||||||
t.yanked = copySlice(t.input[:t.cx])
|
|
||||||
t.input = t.input[t.cx:]
|
|
||||||
t.cx = 0
|
|
||||||
}
|
|
||||||
case actUnixWordRubout:
|
|
||||||
if t.cx > 0 {
|
|
||||||
t.rubout("\\s\\S")
|
|
||||||
}
|
|
||||||
case actBackwardKillWord:
|
|
||||||
if t.cx > 0 {
|
|
||||||
t.rubout("[^[:alnum:]][[:alnum:]]")
|
|
||||||
}
|
|
||||||
case actYank:
|
|
||||||
suffix := copySlice(t.input[t.cx:])
|
|
||||||
t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
|
|
||||||
t.cx += len(t.yanked)
|
|
||||||
case actPageUp:
|
|
||||||
t.vmove(t.maxItems() - 1)
|
|
||||||
req(reqList)
|
|
||||||
case actPageDown:
|
|
||||||
t.vmove(-(t.maxItems() - 1))
|
|
||||||
req(reqList)
|
|
||||||
case actBackwardWord:
|
|
||||||
t.cx = findLastMatch("[^[:alnum:]][[:alnum:]]", string(t.input[:t.cx])) + 1
|
|
||||||
case actForwardWord:
|
|
||||||
t.cx += findFirstMatch("[[:alnum:]][^[:alnum:]]|(.$)", string(t.input[t.cx:])) + 1
|
|
||||||
case actKillWord:
|
|
||||||
ncx := t.cx +
|
|
||||||
findFirstMatch("[[:alnum:]][^[:alnum:]]|(.$)", string(t.input[t.cx:])) + 1
|
|
||||||
if ncx > t.cx {
|
|
||||||
t.yanked = copySlice(t.input[t.cx:ncx])
|
|
||||||
t.input = append(t.input[:t.cx], t.input[ncx:]...)
|
|
||||||
}
|
|
||||||
case actKillLine:
|
|
||||||
if t.cx < len(t.input) {
|
|
||||||
t.yanked = copySlice(t.input[t.cx:])
|
|
||||||
t.input = t.input[:t.cx]
|
|
||||||
}
|
|
||||||
case actRune:
|
|
||||||
prefix := copySlice(t.input[:t.cx])
|
|
||||||
t.input = append(append(prefix, event.Char), t.input[t.cx:]...)
|
|
||||||
t.cx++
|
|
||||||
case actPreviousHistory:
|
|
||||||
if t.history != nil {
|
|
||||||
t.history.override(string(t.input))
|
|
||||||
t.input = []rune(t.history.previous())
|
|
||||||
t.cx = len(t.input)
|
t.cx = len(t.input)
|
||||||
}
|
case actCancel:
|
||||||
case actNextHistory:
|
if len(t.input) == 0 {
|
||||||
if t.history != nil {
|
req(reqQuit)
|
||||||
t.history.override(string(t.input))
|
} else {
|
||||||
t.input = []rune(t.history.next())
|
t.yanked = t.input
|
||||||
t.cx = len(t.input)
|
t.input = []rune{}
|
||||||
}
|
t.cx = 0
|
||||||
case actMouse:
|
}
|
||||||
me := event.MouseEvent
|
case actForwardChar:
|
||||||
mx, my := me.X, me.Y
|
if t.cx < len(t.input) {
|
||||||
if me.S != 0 {
|
t.cx++
|
||||||
// Scroll
|
}
|
||||||
if t.merger.Length() > 0 {
|
case actBackwardDeleteChar:
|
||||||
if t.multi && me.Mod {
|
if t.cx > 0 {
|
||||||
toggle()
|
t.input = append(t.input[:t.cx-1], t.input[t.cx:]...)
|
||||||
|
t.cx--
|
||||||
|
}
|
||||||
|
case actSelectAll:
|
||||||
|
if t.multi {
|
||||||
|
for i := 0; i < t.merger.Length(); i++ {
|
||||||
|
item := t.merger.Get(i)
|
||||||
|
selectItem(item)
|
||||||
}
|
}
|
||||||
t.vmove(me.S)
|
req(reqList, reqInfo)
|
||||||
|
}
|
||||||
|
case actDeselectAll:
|
||||||
|
if t.multi {
|
||||||
|
for i := 0; i < t.merger.Length(); i++ {
|
||||||
|
item := t.merger.Get(i)
|
||||||
|
delete(t.selected, item.index)
|
||||||
|
}
|
||||||
|
req(reqList, reqInfo)
|
||||||
|
}
|
||||||
|
case actToggle:
|
||||||
|
if t.multi && t.merger.Length() > 0 {
|
||||||
|
toggle()
|
||||||
req(reqList)
|
req(reqList)
|
||||||
}
|
}
|
||||||
} else if mx >= t.marginInt[3] && mx < C.MaxX()-t.marginInt[1] &&
|
case actToggleAll:
|
||||||
my >= t.marginInt[0] && my < C.MaxY()-t.marginInt[2] {
|
if t.multi {
|
||||||
mx -= t.marginInt[3]
|
for i := 0; i < t.merger.Length(); i++ {
|
||||||
my -= t.marginInt[0]
|
toggleY(i)
|
||||||
mx = util.Constrain(mx-len(t.prompt), 0, len(t.input))
|
|
||||||
if !t.reverse {
|
|
||||||
my = t.maxHeight() - my - 1
|
|
||||||
}
|
|
||||||
min := 2 + len(t.header)
|
|
||||||
if t.inlineInfo {
|
|
||||||
min--
|
|
||||||
}
|
|
||||||
if me.Double {
|
|
||||||
// Double-click
|
|
||||||
if my >= min {
|
|
||||||
if t.vset(t.offset+my-min) && t.cy < t.merger.Length() {
|
|
||||||
req(reqClose)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if me.Down {
|
req(reqList, reqInfo)
|
||||||
if my == 0 && mx >= 0 {
|
}
|
||||||
// Prompt
|
case actToggleDown:
|
||||||
t.cx = mx
|
if t.multi && t.merger.Length() > 0 {
|
||||||
} else if my >= min {
|
toggle()
|
||||||
// List
|
t.vmove(-1)
|
||||||
if t.vset(t.offset+my-min) && t.multi && me.Mod {
|
req(reqList)
|
||||||
|
}
|
||||||
|
case actToggleUp:
|
||||||
|
if t.multi && t.merger.Length() > 0 {
|
||||||
|
toggle()
|
||||||
|
t.vmove(1)
|
||||||
|
req(reqList)
|
||||||
|
}
|
||||||
|
case actDown:
|
||||||
|
t.vmove(-1)
|
||||||
|
req(reqList)
|
||||||
|
case actUp:
|
||||||
|
t.vmove(1)
|
||||||
|
req(reqList)
|
||||||
|
case actAccept:
|
||||||
|
req(reqClose)
|
||||||
|
case actClearScreen:
|
||||||
|
req(reqRedraw)
|
||||||
|
case actUnixLineDiscard:
|
||||||
|
if t.cx > 0 {
|
||||||
|
t.yanked = copySlice(t.input[:t.cx])
|
||||||
|
t.input = t.input[t.cx:]
|
||||||
|
t.cx = 0
|
||||||
|
}
|
||||||
|
case actUnixWordRubout:
|
||||||
|
if t.cx > 0 {
|
||||||
|
t.rubout("\\s\\S")
|
||||||
|
}
|
||||||
|
case actBackwardKillWord:
|
||||||
|
if t.cx > 0 {
|
||||||
|
t.rubout("[^[:alnum:]][[:alnum:]]")
|
||||||
|
}
|
||||||
|
case actYank:
|
||||||
|
suffix := copySlice(t.input[t.cx:])
|
||||||
|
t.input = append(append(t.input[:t.cx], t.yanked...), suffix...)
|
||||||
|
t.cx += len(t.yanked)
|
||||||
|
case actPageUp:
|
||||||
|
t.vmove(t.maxItems() - 1)
|
||||||
|
req(reqList)
|
||||||
|
case actPageDown:
|
||||||
|
t.vmove(-(t.maxItems() - 1))
|
||||||
|
req(reqList)
|
||||||
|
case actBackwardWord:
|
||||||
|
t.cx = findLastMatch("[^[:alnum:]][[:alnum:]]", string(t.input[:t.cx])) + 1
|
||||||
|
case actForwardWord:
|
||||||
|
t.cx += findFirstMatch("[[:alnum:]][^[:alnum:]]|(.$)", string(t.input[t.cx:])) + 1
|
||||||
|
case actKillWord:
|
||||||
|
ncx := t.cx +
|
||||||
|
findFirstMatch("[[:alnum:]][^[:alnum:]]|(.$)", string(t.input[t.cx:])) + 1
|
||||||
|
if ncx > t.cx {
|
||||||
|
t.yanked = copySlice(t.input[t.cx:ncx])
|
||||||
|
t.input = append(t.input[:t.cx], t.input[ncx:]...)
|
||||||
|
}
|
||||||
|
case actKillLine:
|
||||||
|
if t.cx < len(t.input) {
|
||||||
|
t.yanked = copySlice(t.input[t.cx:])
|
||||||
|
t.input = t.input[:t.cx]
|
||||||
|
}
|
||||||
|
case actRune:
|
||||||
|
prefix := copySlice(t.input[:t.cx])
|
||||||
|
t.input = append(append(prefix, event.Char), t.input[t.cx:]...)
|
||||||
|
t.cx++
|
||||||
|
case actPreviousHistory:
|
||||||
|
if t.history != nil {
|
||||||
|
t.history.override(string(t.input))
|
||||||
|
t.input = []rune(t.history.previous())
|
||||||
|
t.cx = len(t.input)
|
||||||
|
}
|
||||||
|
case actNextHistory:
|
||||||
|
if t.history != nil {
|
||||||
|
t.history.override(string(t.input))
|
||||||
|
t.input = []rune(t.history.next())
|
||||||
|
t.cx = len(t.input)
|
||||||
|
}
|
||||||
|
case actMouse:
|
||||||
|
me := event.MouseEvent
|
||||||
|
mx, my := me.X, me.Y
|
||||||
|
if me.S != 0 {
|
||||||
|
// Scroll
|
||||||
|
if t.merger.Length() > 0 {
|
||||||
|
if t.multi && me.Mod {
|
||||||
toggle()
|
toggle()
|
||||||
}
|
}
|
||||||
|
t.vmove(me.S)
|
||||||
req(reqList)
|
req(reqList)
|
||||||
}
|
}
|
||||||
|
} else if mx >= t.marginInt[3] && mx < C.MaxX()-t.marginInt[1] &&
|
||||||
|
my >= t.marginInt[0] && my < C.MaxY()-t.marginInt[2] {
|
||||||
|
mx -= t.marginInt[3]
|
||||||
|
my -= t.marginInt[0]
|
||||||
|
mx = util.Constrain(mx-len(t.prompt), 0, len(t.input))
|
||||||
|
if !t.reverse {
|
||||||
|
my = t.maxHeight() - my - 1
|
||||||
|
}
|
||||||
|
min := 2 + len(t.header)
|
||||||
|
if t.inlineInfo {
|
||||||
|
min--
|
||||||
|
}
|
||||||
|
if me.Double {
|
||||||
|
// Double-click
|
||||||
|
if my >= min {
|
||||||
|
if t.vset(t.offset+my-min) && t.cy < t.merger.Length() {
|
||||||
|
return doAction(t.keymap[C.DoubleClick])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if me.Down {
|
||||||
|
if my == 0 && mx >= 0 {
|
||||||
|
// Prompt
|
||||||
|
t.cx = mx
|
||||||
|
} else if my >= min {
|
||||||
|
// List
|
||||||
|
if t.vset(t.offset+my-min) && t.multi && me.Mod {
|
||||||
|
toggle()
|
||||||
|
}
|
||||||
|
req(reqList)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if !doAction(action) {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
changed := string(previousInput) != string(t.input)
|
changed := string(previousInput) != string(t.input)
|
||||||
t.mutex.Unlock() // Must be unlocked before touching reqBox
|
t.mutex.Unlock() // Must be unlocked before touching reqBox
|
||||||
|
Loading…
x
Reference in New Issue
Block a user