|
diff --git a/editor.go b/editor.go
|
| ... |
| 1080 |
return indent |
1080 |
return indent |
| 1081 |
} |
1081 |
} |
| 1082 |
|
1082 |
|
|
|
1083 |
func (e *Editor) indentLine(y int) { |
|
|
1084 |
b := e.activeBuffer() |
|
|
1085 |
if b == nil || y < 0 || y >= len(b.buffer) { |
|
|
1086 |
return |
|
|
1087 |
} |
|
|
1088 |
|
|
|
1089 |
tabWidth := Config.DefaultTabWidth |
|
|
1090 |
if b.fileType != nil { |
|
|
1091 |
tabWidth = b.fileType.TabWidth |
|
|
1092 |
} |
|
|
1093 |
|
|
|
1094 |
var indentRunes []rune |
|
|
1095 |
if e.useTabs() { |
|
|
1096 |
indentRunes = []rune{'\t'} |
|
|
1097 |
} else { |
|
|
1098 |
indentRunes = []rune(strings.Repeat(" ", tabWidth)) |
|
|
1099 |
} |
|
|
1100 |
|
|
|
1101 |
line := b.buffer[y] |
|
|
1102 |
newLine := append(indentRunes, line...) |
|
|
1103 |
b.buffer[y] = newLine |
|
|
1104 |
|
|
|
1105 |
// Shift cursors on this line |
|
|
1106 |
for i := range b.cursors { |
|
|
1107 |
if b.cursors[i].Y == y { |
|
|
1108 |
b.cursors[i].X += len(indentRunes) |
|
|
1109 |
b.cursors[i].PreferredCol = b.cursors[i].X |
|
|
1110 |
} |
|
|
1111 |
} |
|
|
1112 |
|
|
|
1113 |
// Shift visual anchor if it's on this line |
|
|
1114 |
if (e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock) && e.visualStartY == y { |
|
|
1115 |
e.visualStartX += len(indentRunes) |
|
|
1116 |
} |
|
|
1117 |
} |
|
|
1118 |
|
|
|
1119 |
func (e *Editor) unindentLine(y int) { |
|
|
1120 |
b := e.activeBuffer() |
|
|
1121 |
if b == nil || y < 0 || y >= len(b.buffer) { |
|
|
1122 |
return |
|
|
1123 |
} |
|
|
1124 |
|
|
|
1125 |
line := b.buffer[y] |
|
|
1126 |
if len(line) == 0 { |
|
|
1127 |
return |
|
|
1128 |
} |
|
|
1129 |
|
|
|
1130 |
tabWidth := Config.DefaultTabWidth |
|
|
1131 |
if b.fileType != nil { |
|
|
1132 |
tabWidth = b.fileType.TabWidth |
|
|
1133 |
} |
|
|
1134 |
|
|
|
1135 |
removedCount := 0 |
|
|
1136 |
if line[0] == '\t' { |
|
|
1137 |
removedCount = 1 |
|
|
1138 |
} else if line[0] == ' ' { |
|
|
1139 |
removedCount = 0 |
|
|
1140 |
for removedCount < tabWidth && removedCount < len(line) && line[removedCount] == ' ' { |
|
|
1141 |
removedCount++ |
|
|
1142 |
} |
|
|
1143 |
} |
|
|
1144 |
|
|
|
1145 |
if removedCount > 0 { |
|
|
1146 |
b.buffer[y] = line[removedCount:] |
|
|
1147 |
// Shift cursors on this line |
|
|
1148 |
for i := range b.cursors { |
|
|
1149 |
if b.cursors[i].Y == y { |
|
|
1150 |
b.cursors[i].X -= removedCount |
|
|
1151 |
if b.cursors[i].X < 0 { |
|
|
1152 |
b.cursors[i].X = 0 |
|
|
1153 |
} |
|
|
1154 |
b.cursors[i].PreferredCol = b.cursors[i].X |
|
|
1155 |
} |
|
|
1156 |
} |
|
|
1157 |
|
|
|
1158 |
// Shift visual anchor if it's on this line |
|
|
1159 |
if (e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock) && e.visualStartY == y { |
|
|
1160 |
e.visualStartX -= removedCount |
|
|
1161 |
if e.visualStartX < 0 { |
|
|
1162 |
e.visualStartX = 0 |
|
|
1163 |
} |
|
|
1164 |
} |
|
|
1165 |
} |
|
|
1166 |
} |
|
|
1167 |
|
|
|
1168 |
func (e *Editor) Indent() { |
|
|
1169 |
e.IndentSelection(false) |
|
|
1170 |
} |
|
|
1171 |
|
|
|
1172 |
func (e *Editor) IndentSelection(stayInMode bool) { |
|
|
1173 |
b := e.activeBuffer() |
|
|
1174 |
if b == nil { |
|
|
1175 |
return |
|
|
1176 |
} |
|
|
1177 |
if b.readOnly { |
|
|
1178 |
e.message = "File is read-only" |
|
|
1179 |
return |
|
|
1180 |
} |
|
|
1181 |
|
|
|
1182 |
e.saveState() |
|
|
1183 |
|
|
|
1184 |
if e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock { |
|
|
1185 |
y1, _, y2, _ := e.getSelectionBounds() |
|
|
1186 |
for y := y1; y <= y2; y++ { |
|
|
1187 |
e.indentLine(y) |
|
|
1188 |
} |
|
|
1189 |
if !stayInMode { |
|
|
1190 |
e.mode = ModeNormal |
|
|
1191 |
} |
|
|
1192 |
} else { |
|
|
1193 |
// Indent lines with cursors |
|
|
1194 |
lines := make(map[int]bool) |
|
|
1195 |
for _, c := range b.cursors { |
|
|
1196 |
lines[c.Y] = true |
|
|
1197 |
} |
|
|
1198 |
for y := range lines { |
|
|
1199 |
e.indentLine(y) |
|
|
1200 |
} |
|
|
1201 |
} |
|
|
1202 |
|
|
|
1203 |
if b.syntax != nil { |
|
|
1204 |
b.syntax.Reparse([]byte(b.toString())) |
|
|
1205 |
} |
|
|
1206 |
e.markModified() |
|
|
1207 |
} |
|
|
1208 |
|
|
|
1209 |
func (e *Editor) Unindent() { |
|
|
1210 |
e.UnindentSelection(false) |
|
|
1211 |
} |
|
|
1212 |
|
|
|
1213 |
func (e *Editor) UnindentSelection(stayInMode bool) { |
|
|
1214 |
b := e.activeBuffer() |
|
|
1215 |
if b == nil { |
|
|
1216 |
return |
|
|
1217 |
} |
|
|
1218 |
if b.readOnly { |
|
|
1219 |
e.message = "File is read-only" |
|
|
1220 |
return |
|
|
1221 |
} |
|
|
1222 |
|
|
|
1223 |
e.saveState() |
|
|
1224 |
|
|
|
1225 |
if e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock { |
|
|
1226 |
y1, _, y2, _ := e.getSelectionBounds() |
|
|
1227 |
for y := y1; y <= y2; y++ { |
|
|
1228 |
e.unindentLine(y) |
|
|
1229 |
} |
|
|
1230 |
if !stayInMode { |
|
|
1231 |
e.mode = ModeNormal |
|
|
1232 |
} |
|
|
1233 |
} else { |
|
|
1234 |
// Unindent lines with cursors |
|
|
1235 |
lines := make(map[int]bool) |
|
|
1236 |
for _, c := range b.cursors { |
|
|
1237 |
lines[c.Y] = true |
|
|
1238 |
} |
|
|
1239 |
for y := range lines { |
|
|
1240 |
e.unindentLine(y) |
|
|
1241 |
} |
|
|
1242 |
} |
|
|
1243 |
|
|
|
1244 |
if b.syntax != nil { |
|
|
1245 |
b.syntax.Reparse([]byte(b.toString())) |
|
|
1246 |
} |
|
|
1247 |
e.markModified() |
|
|
1248 |
} |
|
|
1249 |
|
|
|
1250 |
func (e *Editor) MoveLinesUp() { |
|
|
1251 |
e.moveLines(-1) |
|
|
1252 |
} |
|
|
1253 |
|
|
|
1254 |
func (e *Editor) MoveLinesDown() { |
|
|
1255 |
e.moveLines(1) |
|
|
1256 |
} |
|
|
1257 |
|
|
|
1258 |
func (e *Editor) moveLines(dy int) { |
|
|
1259 |
b := e.activeBuffer() |
|
|
1260 |
if b == nil || b.readOnly || len(b.buffer) == 0 { |
|
|
1261 |
return |
|
|
1262 |
} |
|
|
1263 |
|
|
|
1264 |
e.saveState() |
|
|
1265 |
|
|
|
1266 |
var y1, y2 int |
|
|
1267 |
if e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock { |
|
|
1268 |
y1, _, y2, _ = e.getSelectionBounds() |
|
|
1269 |
} else { |
|
|
1270 |
y1 = b.PrimaryCursor().Y |
|
|
1271 |
y2 = b.PrimaryCursor().Y |
|
|
1272 |
for _, c := range b.cursors { |
|
|
1273 |
if c.Y < y1 { |
|
|
1274 |
y1 = c.Y |
|
|
1275 |
} |
|
|
1276 |
if c.Y > y2 { |
|
|
1277 |
y2 = c.Y |
|
|
1278 |
} |
|
|
1279 |
} |
|
|
1280 |
} |
|
|
1281 |
|
|
|
1282 |
if dy == -1 && y1 > 0 { |
|
|
1283 |
// Move block up: swap y1-1 with the block [y1, y2] |
|
|
1284 |
lineAbove := b.buffer[y1-1] |
|
|
1285 |
for y := y1; y <= y2; y++ { |
|
|
1286 |
b.buffer[y-1] = b.buffer[y] |
|
|
1287 |
} |
|
|
1288 |
b.buffer[y2] = lineAbove |
|
|
1289 |
|
|
|
1290 |
// Update cursors |
|
|
1291 |
for i := range b.cursors { |
|
|
1292 |
if b.cursors[i].Y >= y1 && b.cursors[i].Y <= y2 { |
|
|
1293 |
b.cursors[i].Y-- |
|
|
1294 |
} else if b.cursors[i].Y == y1-1 { |
|
|
1295 |
b.cursors[i].Y += (y2 - y1 + 1) |
|
|
1296 |
} |
|
|
1297 |
} |
|
|
1298 |
// Update visual anchor |
|
|
1299 |
if e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock { |
|
|
1300 |
if e.visualStartY >= y1 && e.visualStartY <= y2 { |
|
|
1301 |
e.visualStartY-- |
|
|
1302 |
} else if e.visualStartY == y1-1 { |
|
|
1303 |
e.visualStartY += (y2 - y1 + 1) |
|
|
1304 |
} |
|
|
1305 |
} |
|
|
1306 |
} else if dy == 1 && y2 < len(b.buffer)-1 { |
|
|
1307 |
// Move block down: swap y2+1 with the block [y1, y2] |
|
|
1308 |
lineBelow := b.buffer[y2+1] |
|
|
1309 |
for y := y2; y >= y1; y-- { |
|
|
1310 |
b.buffer[y+1] = b.buffer[y] |
|
|
1311 |
} |
|
|
1312 |
b.buffer[y1] = lineBelow |
|
|
1313 |
|
|
|
1314 |
// Update cursors |
|
|
1315 |
for i := range b.cursors { |
|
|
1316 |
if b.cursors[i].Y >= y1 && b.cursors[i].Y <= y2 { |
|
|
1317 |
b.cursors[i].Y++ |
|
|
1318 |
} else if b.cursors[i].Y == y2+1 { |
|
|
1319 |
b.cursors[i].Y -= (y2 - y1 + 1) |
|
|
1320 |
} |
|
|
1321 |
} |
|
|
1322 |
// Update visual anchor |
|
|
1323 |
if e.mode == ModeVisual || e.mode == ModeVisualLine || e.mode == ModeVisualBlock { |
|
|
1324 |
if e.visualStartY >= y1 && e.visualStartY <= y2 { |
|
|
1325 |
e.visualStartY++ |
|
|
1326 |
} else if e.visualStartY == y2+1 { |
|
|
1327 |
e.visualStartY -= (y2 - y1 + 1) |
|
|
1328 |
} |
|
|
1329 |
} |
|
|
1330 |
} |
|
|
1331 |
|
|
|
1332 |
if b.syntax != nil { |
|
|
1333 |
b.syntax.Reparse([]byte(b.toString())) |
|
|
1334 |
} |
|
|
1335 |
e.markModified() |
|
|
1336 |
} |
|
|
1337 |
|
| 1083 |
// insertNewline breaks the line at cursor and handles auto-indentation. |
1338 |
// insertNewline breaks the line at cursor and handles auto-indentation. |
| 1084 |
func (e *Editor) insertNewline() { |
1339 |
func (e *Editor) insertNewline() { |
| 1085 |
b := e.activeBuffer() |
1340 |
b := e.activeBuffer() |
| ... |
|
diff --git a/kevent.go b/kevent.go
|
| ... |
| 5 |
// etc.). |
5 |
// etc.). |
| 6 |
|
6 |
|
| 7 |
import ( |
7 |
import ( |
|
|
8 |
"time" |
|
|
9 |
|
| 8 |
"github.com/nsf/termbox-go" |
10 |
"github.com/nsf/termbox-go" |
| 9 |
) |
11 |
) |
| 10 |
|
12 |
|
|
|
13 |
const ( |
|
|
14 |
seqAltArrowUp = "[1;3A" |
|
|
15 |
seqAltArrowDown = "[1;3B" |
|
|
16 |
seqAltArrowRight = "[1;3C" |
|
|
17 |
seqAltArrowLeft = "[1;3D" |
|
|
18 |
) |
|
|
19 |
|
| 11 |
// HandleEvents is the central loop that waits for and processes all user input. |
20 |
// HandleEvents is the central loop that waits for and processes all user input. |
| 12 |
func (e *Editor) HandleEvents() { |
21 |
func (e *Editor) HandleEvents() { |
|
|
22 |
eventChan := make(chan termbox.Event) |
|
|
23 |
go func() { |
|
|
24 |
for { |
|
|
25 |
eventChan <- termbox.PollEvent() |
|
|
26 |
} |
|
|
27 |
}() |
|
|
28 |
|
| 13 |
for { |
29 |
for { |
| 14 |
// Redraw the screen before waiting for the next event. |
30 |
// Redraw the screen before waiting for the next event. |
| 15 |
e.draw() |
31 |
e.draw() |
| 16 |
ev := termbox.PollEvent() |
32 |
var ev termbox.Event |
|
|
33 |
select { |
|
|
34 |
case ev = <-eventChan: |
|
|
35 |
} |
| 17 |
|
36 |
|
| 18 |
// Handle interrupt events (triggered by diagnostic updates). |
37 |
// Handle interrupt events (triggered by diagnostic updates). |
| 19 |
// Fetch latest diagnostics from LSP client. |
38 |
// Fetch latest diagnostics from LSP client. |
| ... |
| 39 |
return |
58 |
return |
| 40 |
} |
59 |
} |
| 41 |
|
60 |
|
| 42 |
// Dispatch the key event to the handler for the current editor mode. |
61 |
// Special handling for ESC sequences (Alt+Arrows) in InputEsc mode. |
| 43 |
switch e.mode { |
62 |
if ev.Key == termbox.KeyEsc { |
| 44 |
case ModeNormal: |
63 |
seq := "" |
| 45 |
e.handleNormalMode(ev) |
64 |
timer := time.NewTimer(30 * time.Millisecond) |
| 46 |
case ModeInsert: |
65 |
matched := false |
| 47 |
e.handleInsertMode(ev) |
66 |
processed := false |
| 48 |
case ModeCommand: |
67 |
seqLoop: |
| 49 |
e.handleCommandMode(ev) |
68 |
for { |
| 50 |
case ModeFuzzy: |
69 |
select { |
| 51 |
e.handleFuzzyMode(ev) |
70 |
case nextEv := <-eventChan: |
| 52 |
case ModeFind: |
71 |
if nextEv.Type == termbox.EventKey { |
| 53 |
e.handleFindMode(ev) |
72 |
if nextEv.Key != 0 { |
| 54 |
case ModeVisual: |
73 |
// Some functional key followed ESC |
| 55 |
e.handleVisualMode(ev) |
74 |
if nextEv.Key == termbox.KeyArrowLeft { |
| 56 |
case ModeVisualLine: |
75 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowLeft, Mod: termbox.ModAlt} |
| 57 |
e.handleVisualLineMode(ev) |
76 |
matched = true |
| 58 |
case ModeVisualBlock: |
77 |
} else if nextEv.Key == termbox.KeyArrowRight { |
| 59 |
e.handleVisualBlockMode(ev) |
78 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowRight, Mod: termbox.ModAlt} |
| 60 |
case ModeReplace: |
79 |
matched = true |
| 61 |
e.handleReplaceMode(ev) |
80 |
} else if nextEv.Key == termbox.KeyArrowUp { |
| 62 |
case ModeConfirm: |
81 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowUp, Mod: termbox.ModAlt} |
| 63 |
e.handleConfirmMode(ev) |
82 |
matched = true |
|
|
83 |
} else if nextEv.Key == termbox.KeyArrowDown { |
|
|
84 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowDown, Mod: termbox.ModAlt} |
|
|
85 |
matched = true |
|
|
86 |
} else { |
|
|
87 |
// Not a known Alt+Arrow, process ESC then this key |
|
|
88 |
e.dispatchEvent(ev) |
|
|
89 |
ev = nextEv |
|
|
90 |
} |
|
|
91 |
break seqLoop |
|
|
92 |
} else { |
|
|
93 |
seq += string(nextEv.Ch) |
|
|
94 |
if seq == seqAltArrowLeft { |
|
|
95 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowLeft, Mod: termbox.ModAlt} |
|
|
96 |
matched = true |
|
|
97 |
break seqLoop |
|
|
98 |
} |
|
|
99 |
if seq == seqAltArrowRight { |
|
|
100 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowRight, Mod: termbox.ModAlt} |
|
|
101 |
matched = true |
|
|
102 |
break seqLoop |
|
|
103 |
} |
|
|
104 |
if seq == seqAltArrowUp { |
|
|
105 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowUp, Mod: termbox.ModAlt} |
|
|
106 |
matched = true |
|
|
107 |
break seqLoop |
|
|
108 |
} |
|
|
109 |
if seq == seqAltArrowDown { |
|
|
110 |
ev = termbox.Event{Type: termbox.EventKey, Key: termbox.KeyArrowDown, Mod: termbox.ModAlt} |
|
|
111 |
matched = true |
|
|
112 |
break seqLoop |
|
|
113 |
} |
|
|
114 |
if len(seq) > 5 { |
|
|
115 |
// Sequence too long, process as individual keys |
|
|
116 |
e.dispatchEvent(ev) |
|
|
117 |
for _, r := range seq { |
|
|
118 |
e.dispatchEvent(termbox.Event{Type: termbox.EventKey, Ch: r}) |
|
|
119 |
} |
|
|
120 |
processed = true |
|
|
121 |
break seqLoop |
|
|
122 |
} |
|
|
123 |
} |
|
|
124 |
} else { |
|
|
125 |
// Not a key event, process ESC then this event |
|
|
126 |
e.dispatchEvent(ev) |
|
|
127 |
ev = nextEv |
|
|
128 |
break seqLoop |
|
|
129 |
} |
|
|
130 |
case <-timer.C: |
|
|
131 |
break seqLoop |
|
|
132 |
} |
|
|
133 |
} |
|
|
134 |
if processed { |
|
|
135 |
continue |
|
|
136 |
} |
|
|
137 |
if !matched && seq != "" { |
|
|
138 |
e.dispatchEvent(ev) |
|
|
139 |
for _, r := range seq { |
|
|
140 |
e.dispatchEvent(termbox.Event{Type: termbox.EventKey, Ch: r}) |
|
|
141 |
} |
|
|
142 |
continue |
|
|
143 |
} |
| 64 |
} |
144 |
} |
|
|
145 |
|
|
|
146 |
e.dispatchEvent(ev) |
| 65 |
} else if ev.Type == termbox.EventMouse { |
147 |
} else if ev.Type == termbox.EventMouse { |
| 66 |
e.handleMouseEvent(ev) |
148 |
e.handleMouseEvent(ev) |
| 67 |
} |
149 |
} |
| 68 |
} |
150 |
} |
| 69 |
} |
151 |
} |
| 70 |
|
152 |
|
|
|
153 |
func (e *Editor) dispatchEvent(ev termbox.Event) { |
|
|
154 |
// Dispatch the key event to the handler for the current editor mode. |
|
|
155 |
switch e.mode { |
|
|
156 |
case ModeNormal: |
|
|
157 |
e.handleNormalMode(ev) |
|
|
158 |
case ModeInsert: |
|
|
159 |
e.handleInsertMode(ev) |
|
|
160 |
case ModeCommand: |
|
|
161 |
e.handleCommandMode(ev) |
|
|
162 |
case ModeFuzzy: |
|
|
163 |
e.handleFuzzyMode(ev) |
|
|
164 |
case ModeFind: |
|
|
165 |
e.handleFindMode(ev) |
|
|
166 |
case ModeVisual: |
|
|
167 |
e.handleVisualMode(ev) |
|
|
168 |
case ModeVisualLine: |
|
|
169 |
e.handleVisualLineMode(ev) |
|
|
170 |
case ModeVisualBlock: |
|
|
171 |
e.handleVisualBlockMode(ev) |
|
|
172 |
case ModeReplace: |
|
|
173 |
e.handleReplaceMode(ev) |
|
|
174 |
case ModeConfirm: |
|
|
175 |
e.handleConfirmMode(ev) |
|
|
176 |
} |
|
|
177 |
} |
|
|
178 |
|
| 71 |
// handleNormalMode processes keyboard input when the editor is in Normal mode. |
179 |
// handleNormalMode processes keyboard input when the editor is in Normal mode. |
| 72 |
func (e *Editor) handleNormalMode(ev termbox.Event) { |
180 |
func (e *Editor) handleNormalMode(ev termbox.Event) { |
| 73 |
// Escape clears any pending multi-key commands or secondary cursors. |
181 |
// Escape clears any pending multi-key commands or secondary cursors. |
| ... |
| 85 |
|
193 |
|
| 86 |
switch ev.Key { |
194 |
switch ev.Key { |
| 87 |
case termbox.KeyArrowLeft: |
195 |
case termbox.KeyArrowLeft: |
| 88 |
e.moveCursor(-1, 0) |
196 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
197 |
e.UnindentSelection(true) |
|
|
198 |
} else { |
|
|
199 |
e.moveCursor(-1, 0) |
|
|
200 |
} |
| 89 |
case termbox.KeyArrowRight: |
201 |
case termbox.KeyArrowRight: |
| 90 |
e.moveCursor(1, 0) |
202 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
203 |
e.IndentSelection(true) |
|
|
204 |
} else { |
|
|
205 |
e.moveCursor(1, 0) |
|
|
206 |
} |
| 91 |
case termbox.KeyArrowUp: |
207 |
case termbox.KeyArrowUp: |
| 92 |
if ev.Mod != 0 { |
208 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
209 |
e.MoveLinesUp() |
|
|
210 |
} else if ev.Mod != 0 { |
| 93 |
e.addCursorAbove() |
211 |
e.addCursorAbove() |
| 94 |
} else { |
212 |
} else { |
| 95 |
e.moveCursor(0, -1) |
213 |
e.moveCursor(0, -1) |
| 96 |
} |
214 |
} |
| 97 |
case termbox.KeyArrowDown: |
215 |
case termbox.KeyArrowDown: |
| 98 |
if ev.Mod != 0 { |
216 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
217 |
e.MoveLinesDown() |
|
|
218 |
} else if ev.Mod != 0 { |
| 99 |
e.addCursorBelow() |
219 |
e.addCursorBelow() |
| 100 |
} else { |
220 |
} else { |
| 101 |
e.moveCursor(0, 1) |
221 |
e.moveCursor(0, 1) |
| ... |
| 123 |
|
243 |
|
| 124 |
// Prevent key event fallthrough. |
244 |
// Prevent key event fallthrough. |
| 125 |
if ev.Key != 0 { |
245 |
if ev.Key != 0 { |
|
|
246 |
return |
|
|
247 |
} |
|
|
248 |
|
|
|
249 |
if ev.Mod&termbox.ModAlt != 0 { |
| 126 |
return |
250 |
return |
| 127 |
} |
251 |
} |
| 128 |
|
252 |
|
| ... |
| 249 |
} else { |
373 |
} else { |
| 250 |
e.pendingKey = 'd' |
374 |
e.pendingKey = 'd' |
| 251 |
} |
375 |
} |
|
|
376 |
case '>': |
|
|
377 |
if e.pendingKey == '>' { |
|
|
378 |
e.Indent() |
|
|
379 |
e.pendingKey = 0 |
|
|
380 |
} else { |
|
|
381 |
e.pendingKey = '>' |
|
|
382 |
} |
|
|
383 |
case '<': |
|
|
384 |
if e.pendingKey == '<' { |
|
|
385 |
e.Unindent() |
|
|
386 |
e.pendingKey = 0 |
|
|
387 |
} else { |
|
|
388 |
e.pendingKey = '<' |
|
|
389 |
} |
| 252 |
case 'y': |
390 |
case 'y': |
| 253 |
e.yankLine() |
391 |
e.yankLine() |
| 254 |
e.message = "Line yanked" |
392 |
e.message = "Line yanked" |
| ... |
| 493 |
e.triggerAutocomplete() |
631 |
e.triggerAutocomplete() |
| 494 |
default: |
632 |
default: |
| 495 |
// If a character key was pressed, insert the character. |
633 |
// If a character key was pressed, insert the character. |
| 496 |
if ev.Ch != 0 { |
634 |
if ev.Ch != 0 && ev.Mod&termbox.ModAlt == 0 { |
| 497 |
e.insertRune(ev.Ch) |
635 |
e.insertRune(ev.Ch) |
| 498 |
// Close autocomplete if user keeps typing. |
636 |
// Close autocomplete if user keeps typing. |
| 499 |
if e.showAutocomplete { |
637 |
if e.showAutocomplete { |
| ... |
| 553 |
// Navigate to next command in history |
691 |
// Navigate to next command in history |
| 554 |
e.commands.NavigateHistoryDown() |
692 |
e.commands.NavigateHistoryDown() |
| 555 |
default: |
693 |
default: |
| 556 |
if ev.Ch != 0 { |
694 |
if ev.Ch != 0 && ev.Mod&termbox.ModAlt == 0 { |
| 557 |
// Insert character at cursor position |
695 |
// Insert character at cursor position |
| 558 |
e.commandBuffer = append(e.commandBuffer[:e.commandCursorX], append([]rune{ev.Ch}, e.commandBuffer[e.commandCursorX:]...)...) |
696 |
e.commandBuffer = append(e.commandBuffer[:e.commandCursorX], append([]rune{ev.Ch}, e.commandBuffer[e.commandCursorX:]...)...) |
| 559 |
e.commandCursorX++ |
697 |
e.commandCursorX++ |
| ... |
| 584 |
e.updateFuzzyResults() |
722 |
e.updateFuzzyResults() |
| 585 |
default: |
723 |
default: |
| 586 |
// Update filter as user types. |
724 |
// Update filter as user types. |
| 587 |
if ev.Ch != 0 { |
725 |
if ev.Ch != 0 && ev.Mod&termbox.ModAlt == 0 { |
| 588 |
e.fuzzyBuffer = append(e.fuzzyBuffer, ev.Ch) |
726 |
e.fuzzyBuffer = append(e.fuzzyBuffer, ev.Ch) |
| 589 |
e.updateFuzzyResults() |
727 |
e.updateFuzzyResults() |
| 590 |
} |
728 |
} |
| ... |
| 619 |
e.lastSearch = string(e.findBuffer) |
757 |
e.lastSearch = string(e.findBuffer) |
| 620 |
default: |
758 |
default: |
| 621 |
// Incremental search: update e.lastSearch as the user types. |
759 |
// Incremental search: update e.lastSearch as the user types. |
| 622 |
if ev.Ch != 0 { |
760 |
if ev.Ch != 0 && ev.Mod&termbox.ModAlt == 0 { |
| 623 |
e.findBuffer = append(e.findBuffer, ev.Ch) |
761 |
e.findBuffer = append(e.findBuffer, ev.Ch) |
| 624 |
e.lastSearch = string(e.findBuffer) |
762 |
e.lastSearch = string(e.findBuffer) |
| 625 |
} |
763 |
} |
| ... |
| 636 |
|
774 |
|
| 637 |
switch ev.Key { |
775 |
switch ev.Key { |
| 638 |
case termbox.KeyArrowLeft: |
776 |
case termbox.KeyArrowLeft: |
| 639 |
e.moveCursor(-1, 0) |
777 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
778 |
e.UnindentSelection(true) |
|
|
779 |
} else { |
|
|
780 |
e.moveCursor(-1, 0) |
|
|
781 |
} |
| 640 |
case termbox.KeyArrowRight: |
782 |
case termbox.KeyArrowRight: |
| 641 |
e.moveCursor(1, 0) |
783 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
784 |
e.IndentSelection(true) |
|
|
785 |
} else { |
|
|
786 |
e.moveCursor(1, 0) |
|
|
787 |
} |
| 642 |
case termbox.KeyArrowUp: |
788 |
case termbox.KeyArrowUp: |
| 643 |
e.moveCursor(0, -1) |
789 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
790 |
e.MoveLinesUp() |
|
|
791 |
} else { |
|
|
792 |
e.moveCursor(0, -1) |
|
|
793 |
} |
| 644 |
case termbox.KeyArrowDown: |
794 |
case termbox.KeyArrowDown: |
| 645 |
e.moveCursor(0, 1) |
795 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
796 |
e.MoveLinesDown() |
|
|
797 |
} else { |
|
|
798 |
e.moveCursor(0, 1) |
|
|
799 |
} |
| 646 |
} |
800 |
} |
| 647 |
|
801 |
|
| 648 |
// Prevent key event fallthrough. |
802 |
// Prevent key event fallthrough. |
| ... |
| 650 |
return |
804 |
return |
| 651 |
} |
805 |
} |
| 652 |
|
806 |
|
|
|
807 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
808 |
return |
|
|
809 |
} |
|
|
810 |
|
| 653 |
switch ev.Ch { |
811 |
switch ev.Ch { |
| 654 |
case 'J': |
812 |
case 'J': |
| 655 |
e.saveState() |
813 |
e.saveState() |
| ... |
| 675 |
e.deleteVisualSelection() |
833 |
e.deleteVisualSelection() |
| 676 |
e.checkDiagnostics() |
834 |
e.checkDiagnostics() |
| 677 |
e.message = "Selection deleted" |
835 |
e.message = "Selection deleted" |
|
|
836 |
case '>': |
|
|
837 |
e.Indent() |
|
|
838 |
case '<': |
|
|
839 |
e.Unindent() |
| 678 |
case 'x': |
840 |
case 'x': |
| 679 |
if e.pendingKey == 'z' { |
841 |
if e.pendingKey == 'z' { |
| 680 |
e.saveState() |
842 |
e.saveState() |
| ... |
| 745 |
|
907 |
|
| 746 |
switch ev.Key { |
908 |
switch ev.Key { |
| 747 |
case termbox.KeyArrowLeft: |
909 |
case termbox.KeyArrowLeft: |
| 748 |
e.moveCursor(-1, 0) |
910 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
911 |
e.UnindentSelection(true) |
|
|
912 |
} else { |
|
|
913 |
e.moveCursor(-1, 0) |
|
|
914 |
} |
| 749 |
case termbox.KeyArrowRight: |
915 |
case termbox.KeyArrowRight: |
| 750 |
e.moveCursor(1, 0) |
916 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
917 |
e.IndentSelection(true) |
|
|
918 |
} else { |
|
|
919 |
e.moveCursor(1, 0) |
|
|
920 |
} |
| 751 |
case termbox.KeyArrowUp: |
921 |
case termbox.KeyArrowUp: |
| 752 |
e.moveCursor(0, -1) |
922 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
923 |
e.MoveLinesUp() |
|
|
924 |
} else { |
|
|
925 |
e.moveCursor(0, -1) |
|
|
926 |
} |
| 753 |
case termbox.KeyArrowDown: |
927 |
case termbox.KeyArrowDown: |
| 754 |
e.moveCursor(0, 1) |
928 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
929 |
e.MoveLinesDown() |
|
|
930 |
} else { |
|
|
931 |
e.moveCursor(0, 1) |
|
|
932 |
} |
| 755 |
} |
933 |
} |
| 756 |
|
934 |
|
| 757 |
// Prevent key event fallthrough. |
935 |
// Prevent key event fallthrough. |
| 758 |
if ev.Key != 0 { |
936 |
if ev.Key != 0 { |
|
|
937 |
return |
|
|
938 |
} |
|
|
939 |
|
|
|
940 |
if ev.Mod&termbox.ModAlt != 0 { |
| 759 |
return |
941 |
return |
| 760 |
} |
942 |
} |
| 761 |
|
943 |
|
| ... |
| 784 |
e.deleteVisualSelection() |
966 |
e.deleteVisualSelection() |
| 785 |
e.checkDiagnostics() |
967 |
e.checkDiagnostics() |
| 786 |
e.message = "Selection deleted" |
968 |
e.message = "Selection deleted" |
|
|
969 |
case '>': |
|
|
970 |
e.Indent() |
|
|
971 |
case '<': |
|
|
972 |
e.Unindent() |
| 787 |
case 'x': |
973 |
case 'x': |
| 788 |
if e.pendingKey == 'z' { |
974 |
if e.pendingKey == 'z' { |
| 789 |
e.saveState() |
975 |
e.saveState() |
| ... |
| 853 |
|
1039 |
|
| 854 |
switch ev.Key { |
1040 |
switch ev.Key { |
| 855 |
case termbox.KeyArrowLeft: |
1041 |
case termbox.KeyArrowLeft: |
| 856 |
e.moveCursor(-1, 0) |
1042 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
1043 |
e.UnindentSelection(true) |
|
|
1044 |
} else { |
|
|
1045 |
e.moveCursor(-1, 0) |
|
|
1046 |
} |
| 857 |
case termbox.KeyArrowRight: |
1047 |
case termbox.KeyArrowRight: |
| 858 |
e.moveCursor(1, 0) |
1048 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
1049 |
e.IndentSelection(true) |
|
|
1050 |
} else { |
|
|
1051 |
e.moveCursor(1, 0) |
|
|
1052 |
} |
| 859 |
case termbox.KeyArrowUp: |
1053 |
case termbox.KeyArrowUp: |
| 860 |
e.moveCursor(0, -1) |
1054 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
1055 |
e.MoveLinesUp() |
|
|
1056 |
} else { |
|
|
1057 |
e.moveCursor(0, -1) |
|
|
1058 |
} |
| 861 |
case termbox.KeyArrowDown: |
1059 |
case termbox.KeyArrowDown: |
| 862 |
e.moveCursor(0, 1) |
1060 |
if ev.Mod&termbox.ModAlt != 0 { |
|
|
1061 |
e.MoveLinesDown() |
|
|
1062 |
} else { |
|
|
1063 |
e.moveCursor(0, 1) |
|
|
1064 |
} |
| 863 |
} |
1065 |
} |
| 864 |
|
1066 |
|
| 865 |
// Prevent key event fallthrough. |
1067 |
// Prevent key event fallthrough. |
| 866 |
if ev.Key != 0 { |
1068 |
if ev.Key != 0 { |
|
|
1069 |
return |
|
|
1070 |
} |
|
|
1071 |
|
|
|
1072 |
if ev.Mod&termbox.ModAlt != 0 { |
| 867 |
return |
1073 |
return |
| 868 |
} |
1074 |
} |
| 869 |
|
1075 |
|
| ... |
| 892 |
e.deleteVisualSelection() |
1098 |
e.deleteVisualSelection() |
| 893 |
e.checkDiagnostics() |
1099 |
e.checkDiagnostics() |
| 894 |
e.message = "Selection deleted" |
1100 |
e.message = "Selection deleted" |
|
|
1101 |
case '>': |
|
|
1102 |
e.Indent() |
|
|
1103 |
case '<': |
|
|
1104 |
e.Unindent() |
| 895 |
case 'x': |
1105 |
case 'x': |
| 896 |
if e.pendingKey == 'z' { |
1106 |
if e.pendingKey == 'z' { |
| 897 |
e.saveState() |
1107 |
e.saveState() |
| ... |
| 981 |
|
1191 |
|
| 982 |
// Prevent key event fallthrough. |
1192 |
// Prevent key event fallthrough. |
| 983 |
if ev.Key != 0 { |
1193 |
if ev.Key != 0 { |
|
|
1194 |
return |
|
|
1195 |
} |
|
|
1196 |
|
|
|
1197 |
if ev.Mod&termbox.ModAlt != 0 { |
| 984 |
return |
1198 |
return |
| 985 |
} |
1199 |
} |
| 986 |
|
1200 |
|
| ... |