diff --git a/src/buffer/unicode.zig b/src/buffer/unicode.zig index 60bf389..a9a3848 100644 --- a/src/buffer/unicode.zig +++ b/src/buffer/unicode.zig @@ -38,6 +38,25 @@ pub fn control_code_to_unicode(code: u8) [:0]const u8 { }; } +pub const char_pairs = [_]struct { []const u8, []const u8 }{ + .{ "\"", "\"" }, + .{ "'", "'" }, + .{ "(", ")" }, + .{ "(", ")" }, + .{ "[", "]" }, + .{ "[", "]" }, + .{ "{", "}" }, + .{ "{", "}" }, + .{ "‘", "’" }, + .{ "‘", "’" }, + .{ "“", "”" }, + .{ "“", "”" }, + .{ "‚", "‘" }, + .{ "‚", "‘" }, + .{ "«", "»" }, + .{ "«", "»" }, +}; + fn raw_byte_to_utf8(cp: u8, buf: []u8) ![]const u8 { var utf16le: [1]u16 = undefined; const utf16le_as_bytes = std.mem.sliceAsBytes(utf16le[0..]); diff --git a/src/keybind/builtin/flow.json b/src/keybind/builtin/flow.json index 62db5bd..35cdc55 100644 --- a/src/keybind/builtin/flow.json +++ b/src/keybind/builtin/flow.json @@ -149,7 +149,7 @@ ["escape", "cancel"], ["enter", "smart_insert_line"], ["delete", "delete_forward"], - ["backspace", "delete_backward"], + ["backspace", "smart_delete_backward"], ["left", "move_left"], ["right", "move_right"], ["up", "move_up"], diff --git a/src/tui/editor.zig b/src/tui/editor.zig index a9a7947..1c2b589 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2773,6 +2773,49 @@ pub const Editor = struct { } pub const delete_backward_meta = .{ .description = "Delete previous character" }; + pub fn smart_delete_backward(self: *Self, _: Context) Result { + const b = try self.buf_for_update(); + var all_stop = true; + var root = b.root; + + for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| { + if (cursel.selection) |_| { + root = self.delete_selection(root, cursel, b.allocator) catch continue; + all_stop = false; + continue; + } + with_selection_const(root, move_cursor_left, cursel, self.metrics) catch continue; + + if (cursel.selection) |*sel| { + const egc_left, _, _ = sel.end.egc_at(root, self.metrics) catch { + root = self.delete_selection(root, cursel, b.allocator) catch continue; + all_stop = false; + continue; + }; + const egc_right, _, _ = sel.begin.egc_at(root, self.metrics) catch { + root = self.delete_selection(root, cursel, b.allocator) catch continue; + all_stop = false; + continue; + }; + + for (Buffer.unicode.char_pairs) |pair| if (std.mem.eql(u8, egc_left, pair[0]) and std.mem.eql(u8, egc_right, pair[1])) { + sel.begin.move_right(root, self.metrics) catch {}; + break; + }; + } + + root = self.delete_selection(root, cursel, b.allocator) catch continue; + all_stop = false; + }; + + if (all_stop) + return error.Stop; + + try self.update_buf(root); + self.clamp(); + } + pub const smart_delete_backward_meta = .{ .description = "Delete previous character (smart)" }; + pub fn delete_word_left(self: *Self, _: Context) Result { const b = try self.buf_for_update(); const root = try self.delete_to(move_cursor_word_left_space, b.root, b.allocator);