From a35bbc7e96cc14304cccc4699622e92088035ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 11 Nov 2025 15:33:56 -0500 Subject: [PATCH 1/9] refactor: prepare match minimode --- src/keybind/builtin/helix.json | 7 +--- src/tui/mode/mini/match.zig | 65 ++++++++++++++++++++++++++++++++++ src/tui/tui.zig | 5 +++ 3 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 src/tui/mode/mini/match.zig diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 1e9e063..9fb088b 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -169,12 +169,7 @@ [";", "collapse_selections"], ["x", "extend_line_below"], - ["m m", "match_brackets"], - ["m s", "surround_add"], - ["m r", "surround_replace"], - ["m d", "surround_delete"], - ["m a", "select_textobject_around"], - ["m i", "select_textobject_inner"], + ["m", "match"], ["[ D", "goto_first_diag"], ["[ G", "goto_first_change"], diff --git a/src/tui/mode/mini/match.zig b/src/tui/mode/mini/match.zig new file mode 100644 index 0000000..de699c5 --- /dev/null +++ b/src/tui/mode/mini/match.zig @@ -0,0 +1,65 @@ +const std = @import("std"); +const cbor = @import("cbor"); +const command = @import("command"); +const tp = @import("thespian"); +const log = @import("log"); + +const tui = @import("../../tui.zig"); + +pub const Type = @import("get_char.zig").Create(@This()); +pub const create = Type.create; + +pub fn name(self: *Type) []const u8 { + var suffix: []const u8 = ""; + if ((self.ctx.args.match(.{tp.extract(&suffix)}) catch false)) { + return suffix; + } + return "󰅪 match"; +} + +pub fn process_egc(self: *Type, egc: []const u8) command.Result { + var prev: []const u8 = ""; + if ((self.ctx.args.match(.{tp.extract(&prev)}) catch false)) { + if (std.mem.eql(u8, prev, "mi")) { + command.executeName("select_textobject_inner", command.fmt(.{egc})) catch { + try command.executeName("exit_mini_mode", .{}); + }; + } else if (std.mem.eql(u8, prev, "ma")) { + command.executeName("select_textobject_around", command.fmt(.{egc})) catch { + try command.executeName("exit_mini_mode", .{}); + }; + } else if (std.mem.eql(u8, prev, "md")) { + command.executeName("surround_delete", command.fmt(.{egc})) catch { + try command.executeName("exit_mini_mode", .{}); + }; + } else if (std.mem.eql(u8, prev, "mr")) { + command.executeName("surround_replace", command.fmt(.{egc})) catch { + try command.executeName("exit_mini_mode", .{}); + }; + } else if (std.mem.eql(u8, prev, "ms")) { + command.executeName("surround_add", command.fmt(.{egc})) catch { + try command.executeName("exit_mini_mode", .{}); + }; + } + try command.executeName("exit_mini_mode", .{}); + } else { + if (std.mem.eql(u8, egc, "i")) { + try command.executeName("match", command.fmt(.{"mi"})); + } else if (std.mem.eql(u8, egc, "a")) { + try command.executeName("match", command.fmt(.{"ma"})); + } else if (std.mem.eql(u8, egc, "d")) { + try command.executeName("match", command.fmt(.{"md"})); + } else if (std.mem.eql(u8, egc, "r")) { + try command.executeName("match", command.fmt(.{"mr"})); + } else if (std.mem.eql(u8, egc, "s")) { + try command.executeName("match", command.fmt(.{"ms"})); + } else if (std.mem.eql(u8, egc, "m")) { + command.executeName("match_brackets", .{}) catch { + try command.executeName("exit_mini_mode", .{}); + }; + try command.executeName("exit_mini_mode", .{}); + } else { + try command.executeName("exit_mini_mode", .{}); + } + } +} diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 09a8462..581baa8 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -1279,6 +1279,11 @@ const cmds = struct { } pub const underline_meta: Meta = .{ .description = "Underline with character" }; + pub fn match(self: *Self, ctx: Ctx) Result { + return enter_mini_mode(self, @import("mode/mini/match.zig"), ctx); + } + pub const match_meta: Meta = .{ .description = "Match mode" }; + pub fn open_file(self: *Self, ctx: Ctx) Result { if (get_active_selection(self.allocator)) |text| { defer self.allocator.free(text); From 878aef9926a85078879a65814754c70b6242c864 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 11 Nov 2025 15:46:02 -0500 Subject: [PATCH 2/9] feat: [hx] miw and miW support --- src/tui/editor.zig | 6 +++--- src/tui/mode/helix.zig | 48 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 5dd92b8..57538df 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2259,7 +2259,7 @@ pub const Editor = struct { }; } - fn is_word_char(c: []const u8) bool { + pub fn is_word_char(c: []const u8) bool { return !is_not_word_char(c); } @@ -2271,7 +2271,7 @@ pub const Editor = struct { return cursor.test_at(root, is_not_word_char, metrics); } - fn is_word_boundary_left(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { + pub fn is_word_boundary_left(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { if (cursor.col == 0) return true; if (is_non_word_char_at_cursor(root, cursor, metrics)) @@ -2324,7 +2324,7 @@ pub const Editor = struct { return false; } - fn is_word_boundary_right(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { + pub fn is_word_boundary_right(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { const line_width = root.line_width(cursor.row, metrics) catch return true; if (cursor.col >= line_width) return true; diff --git a/src/tui/mode/helix.zig b/src/tui/mode/helix.zig index bd3322a..e08e724 100644 --- a/src/tui/mode/helix.zig +++ b/src/tui/mode/helix.zig @@ -411,6 +411,28 @@ const cmds_ = struct { } pub const extend_to_char_right_helix_meta: Meta = .{ .description = "Extend Selection to char right" }; + pub fn select_textobject_inner(_: *void, ctx: Ctx) Result { + var action: []const u8 = ""; + + if (!try ctx.args.match(.{tp.extract(&action)})) return error.Stop; + const logger = log.logger("helix-mode"); + defer logger.deinit(); + logger.print("the selection {s}", .{action}); + const mv = tui.mainview() orelse return; + const ed = mv.get_active_editor() orelse return; + const root = ed.buf_root() catch return; + + if (std.mem.eql(u8, action, "w")) { + try ed.with_cursels_const(root, select_inner_word, ed.metrics); + } else if (std.mem.eql(u8, action, "W")) { + try ed.with_cursels_const(root, select_inner_long_word, ed.metrics); + } else { + return; + } + ed.clamp(); + } + pub const select_textobject_inner_meta: Meta = .{ .description = "select inside object helix" }; + pub fn copy_helix(_: *void, _: Ctx) Result { const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; @@ -522,6 +544,32 @@ fn to_char_helix(ctx: command.Context, move: Editor.cursel_operator_mut_once_arg ed.clamp(); } +fn select_inner_word(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { + if (!cursel.cursor.test_at(root, Editor.is_word_char, metrics)) return; + var prev = cursel.cursor; + var next = cursel.cursor; + Editor.move_cursor_left_until(root, &prev, Editor.is_word_boundary_left, metrics); + Editor.move_cursor_right_until(root, &next, Editor.is_word_boundary_right, metrics); + try next.move_right(root, metrics); + const sel = try cursel.enable_selection(root, metrics); + sel.begin = prev; + sel.end = next; + cursel.*.cursor = next; +} + +fn select_inner_long_word(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { + if (cursel.cursor.test_at(root, Editor.is_whitespace, metrics)) return; + var prev = cursel.cursor; + var next = cursel.cursor; + Editor.move_cursor_left_until(root, &prev, is_long_word_boundary_left, metrics); + Editor.move_cursor_right_until(root, &next, is_long_word_boundary_right, metrics); + try next.move_right(root, metrics); + const sel = try cursel.enable_selection(root, metrics); + sel.begin = prev; + sel.end = next; + cursel.*.cursor = next; +} + fn select_cursel_to_char_left_helix(root: Buffer.Root, cursel: *CurSel, ctx: command.Context, metrics: Buffer.Metrics) error{Stop}!void { var moving_cursor: Cursor = cursel.*.cursor; var begin = cursel.*.cursor; From 4b3e71408ad449f31074ee2d5cbd9f2cd461d072 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 11 Nov 2025 17:18:14 -0500 Subject: [PATCH 3/9] feat: [hx] maw and maW support --- src/tui/mode/helix.zig | 83 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) diff --git a/src/tui/mode/helix.zig b/src/tui/mode/helix.zig index e08e724..2c49306 100644 --- a/src/tui/mode/helix.zig +++ b/src/tui/mode/helix.zig @@ -415,9 +415,6 @@ const cmds_ = struct { var action: []const u8 = ""; if (!try ctx.args.match(.{tp.extract(&action)})) return error.Stop; - const logger = log.logger("helix-mode"); - defer logger.deinit(); - logger.print("the selection {s}", .{action}); const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; const root = ed.buf_root() catch return; @@ -433,6 +430,25 @@ const cmds_ = struct { } pub const select_textobject_inner_meta: Meta = .{ .description = "select inside object helix" }; + pub fn select_textobject_around(_: *void, ctx: Ctx) Result { + var action: []const u8 = ""; + + if (!try ctx.args.match(.{tp.extract(&action)})) return error.Stop; + const mv = tui.mainview() orelse return; + const ed = mv.get_active_editor() orelse return; + const root = ed.buf_root() catch return; + + if (std.mem.eql(u8, action, "w")) { + try ed.with_cursels_const(root, select_around_word, ed.metrics); + } else if (std.mem.eql(u8, action, "W")) { + try ed.with_cursels_const(root, select_inner_long_word, ed.metrics); + } else { + return; + } + ed.clamp(); + } + pub const select_textobject_around_meta: Meta = .{ .description = "select around object helix" }; + pub fn copy_helix(_: *void, _: Ctx) Result { const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; @@ -570,6 +586,67 @@ fn select_inner_long_word(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Me cursel.*.cursor = next; } +fn is_tab_or_space(c: []const u8) bool { + return (c[0] == ' ') or (c[0] == '\t'); +} + +fn is_tab_or_espace_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { + return cursor.test_at(root, is_tab_or_space, metrics); +} +fn is_not_tab_or_espace_at_cursor(root: Buffer.Root, cursor: *const Cursor, metrics: Buffer.Metrics) bool { + return !cursor.test_at(root, is_tab_or_space, metrics); +} + +fn select_around_word(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { + if (!cursel.cursor.test_at(root, Editor.is_word_char, metrics)) return; + var expander = cursel.*; + try select_inner_word(root, &expander, metrics); + const sel_e = try expander.enable_selection(root, metrics); + var prev = sel_e.begin; + var next = sel_e.end; + if (next.test_at(root, is_tab_or_space, metrics)) { + Editor.move_cursor_right_until(root, &next, is_not_tab_or_espace_at_cursor, metrics); + } else { + next = sel_e.end; + prev.move_left(root, metrics) catch {}; + if (prev.test_at(root, is_tab_or_space, metrics)) { + Editor.move_cursor_left_until(root, &prev, is_not_tab_or_espace_at_cursor, metrics); + prev.move_right(root, metrics) catch {}; + } else { + prev = sel_e.begin; + } + } + const sel = try cursel.enable_selection(root, metrics); + sel.begin = prev; + sel.end = next; + cursel.*.cursor = next; +} + +fn select_around_long_word(root: Buffer.Root, cursel: *CurSel, metrics: Buffer.Metrics) !void { + if (!cursel.cursor.test_at(root, Editor.is_word_char, metrics)) return; + var expander = cursel.*; + try select_inner_long_word(root, &expander, metrics); + const sel_e = try expander.enable_selection(root, metrics); + var prev = sel_e.begin; + var next = sel_e.end; + if (next.test_at(root, is_tab_or_space, metrics)) { + Editor.move_cursor_right_until(root, &next, is_not_tab_or_espace_at_cursor, metrics); + } else { + next = sel_e.end; + prev.move_left(root, metrics) catch {}; + if (prev.test_at(root, is_tab_or_space, metrics)) { + Editor.move_cursor_left_until(root, &prev, is_not_tab_or_espace_at_cursor, metrics); + prev.move_right(root, metrics) catch {}; + } else { + prev = sel_e.begin; + } + } + const sel = try cursel.enable_selection(root, metrics); + sel.begin = prev; + sel.end = next; + cursel.*.cursor = next; +} + fn select_cursel_to_char_left_helix(root: Buffer.Root, cursel: *CurSel, ctx: command.Context, metrics: Buffer.Metrics) error{Stop}!void { var moving_cursor: Cursor = cursel.*.cursor; var begin = cursel.*.cursor; From 124cbcbe5fba646b0379831a57e431d3582cee5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 11 Nov 2025 17:19:14 -0500 Subject: [PATCH 4/9] fix: Add @ to non_word characters --- src/tui/editor.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 57538df..5c99f1d 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -2252,6 +2252,7 @@ pub const Editor = struct { '!' => true, '?' => true, '&' => true, + '@' => true, '-' => true, '<' => true, '>' => true, From 0b80ae50db7fc4382ad656fa846aa109ab676fa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 17 Nov 2025 14:25:25 -0500 Subject: [PATCH 5/9] refactor: simplify match mode --- src/keybind/builtin/helix.json | 17 +++++++----- src/tui/mode/mini/match.zig | 47 ++++------------------------------ 2 files changed, 16 insertions(+), 48 deletions(-) diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index 9fb088b..bceb127 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -169,7 +169,12 @@ [";", "collapse_selections"], ["x", "extend_line_below"], - ["m", "match"], + ["m m", "match_brackets"], + ["m a", "match", "select_textobject_around"], + ["m i", "match", "select_textobject_inner"], + ["m d", "match", "surround_delete"], + ["m r", "match", "surround_replace"], + ["m s", "match", "surround_add"], ["[ D", "goto_first_diag"], ["[ G", "goto_first_change"], @@ -459,11 +464,11 @@ ["x", "extend_line_below"], ["m m", "match_brackets", "helix_sel_mode"], - ["m s", "surround_add"], - ["m r", "surround_replace"], - ["m d", "surround_delete"], - ["m a", "select_textobject_around"], - ["m i", "select_textobject_inner"], + ["m a", "match", "select_textobject_around"], + ["m i", "match", "select_textobject_inner"], + ["m d", "match", "surround_delete"], + ["m r", "match", "surround_replace"], + ["m s", "match", "surround_add"], ["[ D", "goto_first_diag"], ["[ G", "goto_first_change"], diff --git a/src/tui/mode/mini/match.zig b/src/tui/mode/mini/match.zig index de699c5..957fe95 100644 --- a/src/tui/mode/mini/match.zig +++ b/src/tui/mode/mini/match.zig @@ -18,48 +18,11 @@ pub fn name(self: *Type) []const u8 { } pub fn process_egc(self: *Type, egc: []const u8) command.Result { - var prev: []const u8 = ""; - if ((self.ctx.args.match(.{tp.extract(&prev)}) catch false)) { - if (std.mem.eql(u8, prev, "mi")) { - command.executeName("select_textobject_inner", command.fmt(.{egc})) catch { - try command.executeName("exit_mini_mode", .{}); - }; - } else if (std.mem.eql(u8, prev, "ma")) { - command.executeName("select_textobject_around", command.fmt(.{egc})) catch { - try command.executeName("exit_mini_mode", .{}); - }; - } else if (std.mem.eql(u8, prev, "md")) { - command.executeName("surround_delete", command.fmt(.{egc})) catch { - try command.executeName("exit_mini_mode", .{}); - }; - } else if (std.mem.eql(u8, prev, "mr")) { - command.executeName("surround_replace", command.fmt(.{egc})) catch { - try command.executeName("exit_mini_mode", .{}); - }; - } else if (std.mem.eql(u8, prev, "ms")) { - command.executeName("surround_add", command.fmt(.{egc})) catch { - try command.executeName("exit_mini_mode", .{}); - }; - } - try command.executeName("exit_mini_mode", .{}); + var action: []const u8 = ""; + if ((self.ctx.args.match(.{tp.extract(&action)}) catch false)) { + try command.executeName(action, command.fmt(.{egc})); } else { - if (std.mem.eql(u8, egc, "i")) { - try command.executeName("match", command.fmt(.{"mi"})); - } else if (std.mem.eql(u8, egc, "a")) { - try command.executeName("match", command.fmt(.{"ma"})); - } else if (std.mem.eql(u8, egc, "d")) { - try command.executeName("match", command.fmt(.{"md"})); - } else if (std.mem.eql(u8, egc, "r")) { - try command.executeName("match", command.fmt(.{"mr"})); - } else if (std.mem.eql(u8, egc, "s")) { - try command.executeName("match", command.fmt(.{"ms"})); - } else if (std.mem.eql(u8, egc, "m")) { - command.executeName("match_brackets", .{}) catch { - try command.executeName("exit_mini_mode", .{}); - }; - try command.executeName("exit_mini_mode", .{}); - } else { - try command.executeName("exit_mini_mode", .{}); - } + try command.executeName("match_brackets", .{}); } + try command.executeName("exit_mini_mode", .{}); } From 3d0a0571c255936eab01bac634e0dfe26323d6c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 17 Nov 2025 17:44:01 -0500 Subject: [PATCH 6/9] fix: removed unused code --- src/tui/mode/mini/match.zig | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/tui/mode/mini/match.zig b/src/tui/mode/mini/match.zig index 957fe95..10b582b 100644 --- a/src/tui/mode/mini/match.zig +++ b/src/tui/mode/mini/match.zig @@ -21,8 +21,6 @@ pub fn process_egc(self: *Type, egc: []const u8) command.Result { var action: []const u8 = ""; if ((self.ctx.args.match(.{tp.extract(&action)}) catch false)) { try command.executeName(action, command.fmt(.{egc})); - } else { - try command.executeName("match_brackets", .{}); } try command.executeName("exit_mini_mode", .{}); } From fd3401748ec5f56233de466704a44255cae53d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 17 Nov 2025 17:44:40 -0500 Subject: [PATCH 7/9] refactor: identify mode inside hx on bracket matching --- src/keybind/builtin/helix.json | 2 +- src/tui/mode/helix.zig | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/keybind/builtin/helix.json b/src/keybind/builtin/helix.json index bceb127..a76828c 100644 --- a/src/keybind/builtin/helix.json +++ b/src/keybind/builtin/helix.json @@ -463,7 +463,7 @@ ["x", "extend_line_below"], - ["m m", "match_brackets", "helix_sel_mode"], + ["m m", "match_brackets"], ["m a", "match", "select_textobject_around"], ["m i", "match", "select_textobject_inner"], ["m d", "match", "surround_delete"], diff --git a/src/tui/mode/helix.zig b/src/tui/mode/helix.zig index 2c49306..ed631ad 100644 --- a/src/tui/mode/helix.zig +++ b/src/tui/mode/helix.zig @@ -209,11 +209,12 @@ const cmds_ = struct { } pub const split_selection_on_newline_meta: Meta = .{ .description = "Add cursor to each line in selection helix" }; - pub fn match_brackets(_: *void, ctx: Ctx) Result { + pub fn match_brackets(_: *void, _: Ctx) Result { const mv = tui.mainview() orelse return; const ed = mv.get_active_editor() orelse return; const root = ed.buf_root() catch return; - try ed.with_cursels_const_once_arg(root, &match_bracket, ctx); + const m = tui.input_mode().?.*.name; + try ed.with_cursels_const_once_arg(root, &match_bracket, command.fmt(.{m})); ed.clamp(); } pub const match_brackets_meta: Meta = .{ .description = "Goto matching bracket" }; @@ -493,7 +494,7 @@ const cmds_ = struct { fn match_bracket(root: Buffer.Root, cursel: *CurSel, ctx: command.Context, metrics: Buffer.Metrics) error{Stop}!void { var symbol: []const u8 = undefined; const mode: enum { helix_sel_mode, helix_nor_mode } = if ((ctx.args.match(.{tp.extract(&symbol)}) catch false) and - std.mem.eql(u8, @tagName(.helix_sel_mode), symbol)) .helix_sel_mode else .helix_nor_mode; + std.mem.eql(u8, "SEL", symbol)) .helix_sel_mode else .helix_nor_mode; if (mode == .helix_sel_mode) { const begin: Cursor = if (cursel.selection) |sel| sel.begin else cursel.*.cursor; From b4b44ec9062502df7af40e2f58a537fc7943091a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 17 Nov 2025 23:09:40 -0500 Subject: [PATCH 8/9] refactor: additional characters for smart_insert --- src/buffer/unicode.zig | 6 +++++- src/keybind/builtin/flow.json | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/buffer/unicode.zig b/src/buffer/unicode.zig index 2cd84fa..9009578 100644 --- a/src/buffer/unicode.zig +++ b/src/buffer/unicode.zig @@ -41,13 +41,15 @@ pub fn control_code_to_unicode(code: u8) [:0]const u8 { pub const char_pairs = [_]struct { []const u8, []const u8 }{ .{ "\"", "\"" }, .{ "'", "'" }, + .{ "`", "`" }, .{ "(", ")" }, .{ "[", "]" }, .{ "{", "}" }, .{ "‘", "’" }, .{ "“", "”" }, - .{ "‚", "‘" }, .{ "«", "»" }, + .{ "¿", "?" }, + .{ "¡", "!" }, }; pub const open_close_pairs = [_]struct { []const u8, []const u8 }{ @@ -57,6 +59,8 @@ pub const open_close_pairs = [_]struct { []const u8, []const u8 }{ .{ "‘", "’" }, .{ "“", "”" }, .{ "«", "»" }, + .{ "¿", "?" }, + .{ "¡", "!" }, }; fn raw_byte_to_utf8(cp: u8, buf: []u8) ![]const u8 { diff --git a/src/keybind/builtin/flow.json b/src/keybind/builtin/flow.json index 1df59b2..0a0c8a3 100644 --- a/src/keybind/builtin/flow.json +++ b/src/keybind/builtin/flow.json @@ -255,6 +255,7 @@ ["\"", "smart_insert_pair", "\"", "\""], ["'", "smart_insert_pair", "'", "'"], + ["`", "smart_insert_pair", "`", "`"], ["(", "smart_insert_pair", "(", ")"], [")", "smart_insert_pair_close", "(", ")"], ["[", "smart_insert_pair", "[", "]"], @@ -269,6 +270,8 @@ ["‘", "smart_insert_pair_close", "‚", "‘"], ["«", "smart_insert_pair", "«", "»"], ["»", "smart_insert_pair_close", "«", "»"], + ["¿", "smart_insert_pair", "¿", "?"], + ["¡", "smart_insert_pair", "¡", "!"], ["alt+0", "add_integer_argument_digit", 0], ["alt+1", "add_integer_argument_digit", 1], From 8b9cc87cabb45baa48864b8bb799f243a02f580c Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 18 Nov 2025 10:55:36 +0100 Subject: [PATCH 9/9] fix: add back german quotes to char_pairs --- src/buffer/unicode.zig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/buffer/unicode.zig b/src/buffer/unicode.zig index 9009578..0571e14 100644 --- a/src/buffer/unicode.zig +++ b/src/buffer/unicode.zig @@ -47,6 +47,7 @@ pub const char_pairs = [_]struct { []const u8, []const u8 }{ .{ "{", "}" }, .{ "‘", "’" }, .{ "“", "”" }, + .{ "‚", "‘" }, .{ "«", "»" }, .{ "¿", "?" }, .{ "¡", "!" },