/
insert_api.go
145 lines (135 loc) · 4.78 KB
/
insert_api.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
138
139
140
141
142
143
144
145
package edit
import (
"github.com/elves/elvish/pkg/cli"
"github.com/elves/elvish/pkg/eval"
"github.com/elves/elvish/pkg/eval/vals"
"github.com/elves/elvish/pkg/eval/vars"
"github.com/xiaq/persistent/hashmap"
)
//elvdoc:var abbr
//
// A map from (simple) abbreviations to their expansions.
//
// An abbreviation is replaced by its expansion when it is typed in full
// and consecutively, without being interrupted by the use of other editing
// functionalities, such as cursor movements.
//
// If more than one abbreviations would match, the longest one is used.
//
// Examples:
//
// ```elvish
// edit:abbr['||'] = '| less'
// edit:abbr['>dn'] = '2>/dev/null'
// ```
//
// With the definitions above, typing `||` anywhere expands to `| less`, and
// typing `>dn` anywhere expands to `2>/dev/null`. However, typing a `|`, moving
// the cursor left, and typing another `|` does **not** expand to `| less`,
// since the abbreviation `||` was not typed consecutively.
//
// @cf edit:small-word-abbr
//elvdoc:var small-word-abbr
//
// A map from small-word abbreviations and their expansions.
//
// A small-word abbreviation is replaced by its expansion after it is typed in
// full and consecutively, and followed by another character (the *trigger*
// character). Furthermore, the expansion requires the following conditions to
// be satisfied:
//
// - The end of the abbreviation must be adjacent to a small-word boundary,
// i.e. the last character of the abbreviation and the trigger character
// must be from two different small-word categories.
//
// - The start of the abbreviation must also be adjacent to a small-word
// boundary, unless it appears at the beginning of the code buffer.
//
// - The cursor must be at the end of the buffer.
//
// If more than one abbreviations would match, the longest one is used.
//
// As an example, with the following configuration:
//
// ```elvish
// edit:small-word-abbr['gcm'] = 'git checkout master'
// ```
//
// In the following scenarios, the `gcm` abbreviation is expanded:
//
// - With an empty buffer, typing `gcm` and a space or semicolon;
//
// - When the buffer ends with a space, typing `gcm` and a space or semicolon.
//
// The space or semicolon after `gcm` is preserved in both cases.
//
// In the following scenarios, the `gcm` abbreviation is **not** expanded:
//
// - With an empty buffer, typing `Xgcm` and a space or semicolon (start of
// abbreviation is not adjacent to a small-word boundary);
//
// - When the buffer ends with `X`, typing `gcm` and a space or semicolon (end
// of abbreviation is not adjacent to a small-word boundary);
//
// - When the buffer is non-empty, move the cursor to the beginning, and typing
// `gcm` and a space (cursor not at the end of the buffer).
//
// This example shows the case where the abbreviation consists of a single small
// word of alphanumerical characters, but that doesn't have to be the case. For
// example, with the following configuration:
//
// ```elvish
// edit:small-word-abbr['>dn'] = ' 2>/dev/null'
// ```
//
// The abbreviation `>dn` starts with a punctuation character, and ends with an
// alphanumerical character. This means that it is expanded when it borders
// a whitespace or alphanumerical character to the left, and a whitespace or
// punctuation to the right; for example, typing `ls>dn;` will expand it.
//
// Some extra examples of small-word abbreviations:
//
// ```elvish
// edit:small-word-abbr['gcp'] = 'git cherry-pick -x'
// edit:small-word-abbr['ll'] = 'ls -ltr'
// ```
//
// If both a [simple abbreviation](#editabbr) and a small-word abbreviation can
// be expanded, the simple abbreviation has priority.
//
// @cf edit:abbr
func initInsertAPI(appSpec *cli.AppSpec, nt notifier, ev *eval.Evaler, nb eval.NsBuilder) {
abbr := vals.EmptyMap
abbrVar := vars.FromPtr(&abbr)
appSpec.Abbreviations = makeMapIterator(abbrVar)
SmallWordAbbr := vals.EmptyMap
SmallWordAbbrVar := vars.FromPtr(&SmallWordAbbr)
appSpec.SmallWordAbbreviations = makeMapIterator(SmallWordAbbrVar)
binding := newBindingVar(EmptyBindingMap)
appSpec.OverlayHandler = newMapBinding(nt, ev, binding)
quotePaste := newBoolVar(false)
appSpec.QuotePaste = func() bool { return quotePaste.GetRaw().(bool) }
toggleQuotePaste := func() {
quotePaste.Set(!quotePaste.Get().(bool))
}
nb.Add("abbr", abbrVar)
nb.Add("small-word-abbr", SmallWordAbbrVar)
nb.AddGoFn("<edit>", "toggle-quote-paste", toggleQuotePaste)
nb.AddNs("insert", eval.NsBuilder{
"binding": binding,
"quote-paste": quotePaste,
}.Ns())
}
func makeMapIterator(mv vars.PtrVar) func(func(a, b string)) {
return func(f func(a, b string)) {
for it := mv.GetRaw().(hashmap.Map).Iterator(); it.HasElem(); it.Next() {
k, v := it.Elem()
ks, kok := k.(string)
vs, vok := v.(string)
if !kok || !vok {
continue
}
f(ks, vs)
}
}
}