diff options
| author | 2024-02-22 00:00:22 +0200 | |
|---|---|---|
| committer | 2024-02-22 00:00:22 +0200 | |
| commit | 93050dc047204cd12857199c3dea8fc4f38a2e5e (patch) | |
| tree | f1146a0a4dc22d5493cbb197cc1019bc6fba4828 /src | |
| parent | Add functionality for skipping words left and right (diff) | |
| download | es-93050dc047204cd12857199c3dea8fc4f38a2e5e.tar.gz es-93050dc047204cd12857199c3dea8fc4f38a2e5e.tar.xz es-93050dc047204cd12857199c3dea8fc4f38a2e5e.zip | |
Add functionality for deleting words
Diffstat (limited to 'src')
| -rw-r--r-- | src/Buffer.zig | 128 | ||||
| -rw-r--r-- | src/KeyMap.zig | 5 |
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 | ||
| 92 | pub fn backwardDeleteChar(self: *Buffer) !void { | 92 | pub 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 | ||
| 100 | pub 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 | |||
| 97 | pub fn backwardParagraph(self: *Buffer) void { | 112 | pub 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 | ||
| 113 | pub fn backwardWord(self: *Buffer) void { | 128 | pub 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 | ||
| 183 | pub 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 | |||
| 179 | pub fn deleteRow(self: *Buffer, at: usize) void { | 194 | pub 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 | ||
| 313 | pub 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 | |||
| 335 | pub 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 | |||
| 298 | pub fn forwardChar(self: *Buffer) void { | 357 | pub 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 | ||
| 327 | pub fn forwardWord(self: *Buffer) void { | 386 | pub 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 | ||
| 457 | pub fn lineNumberDigits(self: Buffer) usize { | 495 | pub 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); |