This repository has been archived by the owner on Oct 10, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
hints.go
137 lines (124 loc) · 3.31 KB
/
hints.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package states
import (
"errors"
"fmt"
"log"
"github.com/tkerber/golem/cmd"
)
// HintsCallback is an interface for golem.(*webView), implementing the
// methods needed by hints. (mostly web extension calls)
type HintsCallback interface {
LinkHintsMode() (int64, error)
FormVariableHintsMode() (int64, error)
ClickHintsMode() (int64, error)
EndHintsMode() error
FilterHintsMode(string) (bool, error)
}
// HintsMode is a mode which displays key strings on items of intrest in a
// web view, and allows the selection of said items by typing these key
// strings.
type HintsMode struct {
*cmd.StateIndependant
cmd.Substate
HintsCallback
CurrentKeys []cmd.Key
ExecuterFunction func(string) bool
}
// NewHintsMode creates a new hints mode.
//
// It returns a hints mode, and asynchronously either an error or nil in the
// given channel.
//
// The special error nil is returned if no error occured, but hints mode
// should stop.
//
// The channel is closed when initialization finishes.
func NewHintsMode(
s cmd.State,
st cmd.Substate,
cb HintsCallback,
e func(string) bool) (*HintsMode, <-chan error) {
hm := &HintsMode{
s.GetStateIndependant(),
st,
cb,
make([]cmd.Key, 0),
e,
}
c := make(chan error, 1)
go func() {
// Start hints mode
var err error
var nHints int64
switch hm.Substate {
case HintsSubstateFollow:
nHints, err = hm.HintsCallback.ClickHintsMode()
case HintsSubstateBackground,
HintsSubstateRapid,
HintsSubstateTab,
HintsSubstateWindow:
nHints, err = hm.HintsCallback.LinkHintsMode()
case HintsSubstateSearchEngine:
nHints, err = hm.HintsCallback.FormVariableHintsMode()
default:
err = fmt.Errorf("Unknown hints type: %d", hm.Substate)
}
if err != nil {
c <- err
} else if nHints == 0 {
c <- errors.New("No hints to follow")
} else if nHints == -1 {
c <- errors.New("Internal error displaying hints")
} else if nHints == 1 {
c <- nil
}
close(c)
}()
return hm, c
}
// ProcessKeyPress processes exactly one key press in hints mode.
//
// It returns the new state, and whether the key press was swallowed or not.
func (s *HintsMode) ProcessKeyPress(key cmd.RealKey) (cmd.State, bool) {
var newKeys []cmd.Key
switch key.Keyval {
// TODO maybe do something on enter. For now, just end hints mode.
// TODO maybe handle tab.
case cmd.KeyReturn, cmd.KeyKPEnter, cmd.KeyEscape:
return cmd.NewNormalMode(s), true
case cmd.KeyBackSpace:
if len(s.CurrentKeys) == 0 {
return cmd.NewNormalMode(s), true
}
newKeys = s.CurrentKeys[:len(s.CurrentKeys)-1]
default:
newKeys = cmd.ImmutableAppend(s.CurrentKeys, key)
}
ret := &HintsMode{
s.StateIndependant,
s.Substate,
s.HintsCallback,
newKeys,
s.ExecuterFunction,
}
go func() {
hitAndEnd, err := s.HintsCallback.FilterHintsMode(cmd.KeysString(newKeys))
if err != nil {
log.Printf("Failed to filter hints: %v", err)
} else if hitAndEnd {
sNew := s.GetState()
if sNew == s || sNew == ret {
s.StateIndependant.SetState(cmd.NewNormalMode(s))
}
}
}()
return ret, true
}
// GetStateIndependant gets the state independant associated with this state.
func (s *HintsMode) GetStateIndependant() *cmd.StateIndependant {
return s.StateIndependant
}
// GetSubstate gets the substate associated with this state.
func (s *HintsMode) GetSubstate() cmd.Substate {
return s.Substate
}