summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Buffer.zig128
-rw-r--r--src/KeyMap.zig5
2 files changed, 88 insertions, 45 deletions
diff --git a/src/Buffer.zig b/src/Buffer.zig
index 26f9a93..8cf7dc0 100644
--- a/src/Buffer.zig
+++ b/src/Buffer.zig
@@ -90,10 +90,25 @@ pub fn backwardChar(self: *Buffer) void {
90} 90}
91 91
92pub fn backwardDeleteChar(self: *Buffer) !void { 92pub fn backwardDeleteChar(self: *Buffer) !void {
93 if (self.cx == 0 and self.cy == 0) {
94 return;
95 }
93 self.backwardChar(); 96 self.backwardChar();
94 return self.deleteChar(); 97 return self.deleteChar();
95} 98}
96 99
100pub fn backwardDeleteWord(self: *Buffer) !void {
101 const start = self.findBackwardWordStart();
102 if (start == self.cx) {
103 return self.backwardDeleteChar();
104 } else {
105 var row = &self.rows.items[self.cy];
106 row.data.replaceRangeAssumeCapacity(start, self.cx - start, &.{});
107 self.cx = start;
108 return row.update(self);
109 }
110}
111
97pub fn backwardParagraph(self: *Buffer) void { 112pub fn backwardParagraph(self: *Buffer) void {
98 if (self.cy == 0) { 113 if (self.cy == 0) {
99 return; 114 return;
@@ -111,22 +126,11 @@ pub fn backwardParagraph(self: *Buffer) void {
111} 126}
112 127
113pub fn backwardWord(self: *Buffer) void { 128pub fn backwardWord(self: *Buffer) void {
114 if (self.cx == 0) { 129 const target = self.findBackwardWordStart();
115 return self.backwardChar(); 130 if (target == self.cx) {
116 } 131 self.backwardChar();
117 132 } else {
118 const chars = self.rows.items[self.cy].data.items; 133 self.cx = target;
119 // First we skip non-word
120 while (self.cx > 0) : (self.cx -= 1) {
121 if (std.ascii.isAlphanumeric(chars[self.cx - 1])) {
122 break;
123 }
124 }
125 // Then we skip word
126 while (self.cx > 0) : (self.cx -= 1) {
127 if (!std.ascii.isAlphanumeric(chars[self.cx - 1])) {
128 break;
129 }
130 } 134 }
131} 135}
132 136
@@ -176,6 +180,17 @@ pub fn deleteAllRows(self: *Buffer) void {
176 } 180 }
177} 181}
178 182
183pub fn deleteWord(self: *Buffer) !void {
184 const end = self.findForwardWordEnd();
185 if (end == self.cx) {
186 return self.deleteChar();
187 } else {
188 var row = &self.rows.items[self.cy];
189 row.data.replaceRangeAssumeCapacity(self.cx, end - self.cx, &.{});
190 return row.update(self);
191 }
192}
193
179pub fn deleteRow(self: *Buffer, at: usize) void { 194pub fn deleteRow(self: *Buffer, at: usize) void {
180 if (at == self.rows.items.len) { 195 if (at == self.rows.items.len) {
181 return; 196 return;
@@ -295,6 +310,50 @@ pub fn drawStatusBar(self: Buffer, writer: anytype, screencols: usize) !void {
295 try writer.writeAll("\x1b[m\r\n"); 310 try writer.writeAll("\x1b[m\r\n");
296} 311}
297 312
313pub fn findBackwardWordStart(self: Buffer) usize {
314 if (self.cy == self.rows.items.len) {
315 return 0;
316 }
317
318 const chars = self.rows.items[self.cy].data.items;
319 var start = self.cx;
320 // First we skip non-word
321 while (start > 0) : (start -= 1) {
322 if (std.ascii.isAlphanumeric(chars[start - 1])) {
323 break;
324 }
325 }
326 // Then we skip word
327 while (start > 0) : (start -= 1) {
328 if (!std.ascii.isAlphanumeric(chars[start - 1])) {
329 break;
330 }
331 }
332 return start;
333}
334
335pub fn findForwardWordEnd(self: Buffer) usize {
336 if (self.cy == self.rows.items.len) {
337 return 0;
338 }
339
340 const chars = self.rows.items[self.cy].data.items;
341 var end = self.cx;
342 // First we skip non-word
343 while (end < chars.len) : (end += 1) {
344 if (std.ascii.isAlphanumeric(chars[end])) {
345 break;
346 }
347 }
348 // Then we skip word
349 while (end < chars.len) : (end += 1) {
350 if (!std.ascii.isAlphanumeric(chars[end])) {
351 break;
352 }
353 }
354 return end;
355}
356
298pub fn forwardChar(self: *Buffer) void { 357pub fn forwardChar(self: *Buffer) void {
299 if (self.rows.items.len == self.cy) { 358 if (self.rows.items.len == self.cy) {
300 return; 359 return;
@@ -325,26 +384,11 @@ pub fn forwardParagraph(self: *Buffer) void {
325} 384}
326 385
327pub fn forwardWord(self: *Buffer) void { 386pub fn forwardWord(self: *Buffer) void {
328 if (self.cy == self.rows.items.len) { 387 const end = self.findForwardWordEnd();
329 return; 388 if (end == self.cx) {
330 } 389 self.forwardChar();
331 390 } else {
332 const chars = self.rows.items[self.cy].data.items; 391 self.cx = end;
333 if (self.cx == chars.len) {
334 return self.forwardChar();
335 }
336
337 // First we skip non-word
338 while (self.cx < chars.len) : (self.cx += 1) {
339 if (std.ascii.isAlphanumeric(chars[self.cx])) {
340 break;
341 }
342 }
343 // Then we skip word
344 while (self.cx < chars.len) : (self.cx += 1) {
345 if (!std.ascii.isAlphanumeric(chars[self.cx])) {
346 break;
347 }
348 } 392 }
349} 393}
350 394
@@ -440,18 +484,12 @@ pub fn killLine(self: *Buffer) !void {
440 484
441 var row = &self.rows.items[self.cy]; 485 var row = &self.rows.items[self.cy];
442 if (self.cx == row.data.items.len) { 486 if (self.cx == row.data.items.len) {
443 if (self.cy == self.rows.items.len - 1) { 487 return self.deleteChar();
444 return;
445 }
446
447 try row.appendString(self, self.rows.items[self.cy+1].data.items);
448 self.deleteRow(self.cy + 1);
449 } else { 488 } else {
489 self.dirty = true;
450 try row.data.resize(self.cx); 490 try row.data.resize(self.cx);
491 return row.update(self);
451 } 492 }
452
453 self.dirty = true;
454 return row.update(self);
455} 493}
456 494
457pub fn lineNumberDigits(self: Buffer) usize { 495pub fn lineNumberDigits(self: Buffer) usize {
diff --git a/src/KeyMap.zig b/src/KeyMap.zig
index 8dca48d..15f5711 100644
--- a/src/KeyMap.zig
+++ b/src/KeyMap.zig
@@ -112,11 +112,14 @@ pub fn defaultMap(allocator: Allocator) !KeyMap {
112 try map.bind(&.{Key.meta(Key.ctrl('d'))}, Buffer.backwardDeleteChar); 112 try map.bind(&.{Key.meta(Key.ctrl('d'))}, Buffer.backwardDeleteChar);
113 113
114 // M-<*> 114 // M-<*>
115 try map.bind(&.{Key.meta(Key.backspace)}, Buffer.backwardDeleteWord);
116 try map.bind(&.{Key.meta(Key.delete)}, Buffer.deleteWord);
115 try map.bind(&.{Key.meta(Key.down)}, Buffer.forwardParagraph); 117 try map.bind(&.{Key.meta(Key.down)}, Buffer.forwardParagraph);
116 try map.bind(&.{Key.meta(Key.left)}, Buffer.backwardWord); 118 try map.bind(&.{Key.meta(Key.left)}, Buffer.backwardWord);
117 try map.bind(&.{Key.meta(Key.right)}, Buffer.forwardWord); 119 try map.bind(&.{Key.meta(Key.right)}, Buffer.forwardWord);
118 try map.bind(&.{Key.meta(Key.up)}, Buffer.backwardParagraph); 120 try map.bind(&.{Key.meta(Key.up)}, Buffer.backwardParagraph);
119 try map.bind(&.{Key.meta('b')}, Buffer.backwardWord); 121 try map.bind(&.{Key.meta('b')}, Buffer.backwardWord);
122 try map.bind(&.{Key.meta('d')}, Buffer.deleteWord);
120 try map.bind(&.{Key.meta('f')}, Buffer.forwardWord); 123 try map.bind(&.{Key.meta('f')}, Buffer.forwardWord);
121 // M-g is taken 124 // M-g is taken
122 try map.bind(&.{Key.meta('n')}, Buffer.forwardParagraph); 125 try map.bind(&.{Key.meta('n')}, Buffer.forwardParagraph);
@@ -125,6 +128,8 @@ pub fn defaultMap(allocator: Allocator) !KeyMap {
125 try map.bind(&.{Key.meta('v')}, Buffer.pageUp); 128 try map.bind(&.{Key.meta('v')}, Buffer.pageUp);
126 129
127 // C-<*> 130 // C-<*>
131 try map.bind(&.{Key.ctrl(Key.backspace)}, Buffer.backwardDeleteWord);
132 try map.bind(&.{Key.ctrl(Key.delete)}, Buffer.deleteWord);
128 try map.bind(&.{Key.ctrl(Key.down)}, Buffer.forwardParagraph); 133 try map.bind(&.{Key.ctrl(Key.down)}, Buffer.forwardParagraph);
129 try map.bind(&.{Key.ctrl(Key.left)}, Buffer.backwardWord); 134 try map.bind(&.{Key.ctrl(Key.left)}, Buffer.backwardWord);
130 try map.bind(&.{Key.ctrl(Key.right)}, Buffer.forwardWord); 135 try map.bind(&.{Key.ctrl(Key.right)}, Buffer.forwardWord);