From 62ef99d062c35f5a87c7e59048cd4ecbae71221e Mon Sep 17 00:00:00 2001 From: tauraamui Date: Wed, 7 Jan 2026 00:29:07 +0000 Subject: [PATCH 1/7] feat: render divider line twixt splits left side Need to disable this for the left most split --- editor.v | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/editor.v b/editor.v index 608c2ac5..c8c7b841 100644 --- a/editor.v +++ b/editor.v @@ -186,6 +186,13 @@ fn (m EditorModel) view(mut ctx tea.Context) { ctx.set_clip_area(tea.ClipArea{ 0, 0, m.width, m.height }) defer { ctx.clear_clip_area() } + + for y in 0..m.height { + ctx.draw_text(0, y, '│') + } + + ctx.push_offset(tea.Offset{ x: 1 }) + for y, l in m.lines { ctx.draw_text(0, y, l.replace('\t', ' ')) } From 0cb18a0b09163edce9dc867ae1580870ebf03694 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Thu, 8 Jan 2026 01:05:56 +0000 Subject: [PATCH 2/7] chore: start to move split migration into msgs This will help us tell the editors which are currently the active/in-focus ones directly in case they need to know. --- editor_workspace.v | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/editor_workspace.v b/editor_workspace.v index eac61127..3b24226c 100644 --- a/editor_workspace.v +++ b/editor_workspace.v @@ -173,6 +173,7 @@ fn get_branch(execute fn (cmd string) os.Result) string { return res.output } +// NOTE(tauraamui) [08/01/26]: do these actually need to be public, not sure, doubt it check when have time pub struct VerticalSplitMsg {} pub fn split_vertically() tea.Msg { @@ -185,6 +186,20 @@ pub fn close_active_split() tea.Msg { return CloseActiveSplitMsg{} } +enum SplitMoveDir { + left + right +} + +struct SwitchActiveSplitMsg { + dir SplitMoveDir +} + +fn switch_active_split(dir SplitMoveDir) tea.Cmd { + return fn [dir] () tea.Msg { + return SwitchActiveSplitMsg{dir} + } +} fn (mut m EditorWorkspaceModel) update_dialog(msg tea.Msg) (?tea.Model, ?tea.Cmd) { if msg is CloseDialogMsg { @@ -325,6 +340,7 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { cmds << switch_mode(.navigation) } "ctrl+w+h" { + cmds << switch_active_split(.left) // move to previous split (left) if m.split_tree.count() > 1 { old_id := m.split_tree.active_editor_id @@ -350,6 +366,7 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { } } "ctrl+w+l" { + cmds << switch_active_split(.right) // move to next split (right) if m.split_tree.count() > 1 { old_id := m.split_tree.active_editor_id From a2378df8759e070a294dbe4a3c6146901c1cf1f3 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Thu, 8 Jan 2026 14:16:16 +0000 Subject: [PATCH 3/7] feat: provide ability to infer "first" editor in splits arrangement --- split_tree.v | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/split_tree.v b/split_tree.v index 4eaff165..13fe7c08 100644 --- a/split_tree.v +++ b/split_tree.v @@ -279,6 +279,25 @@ pub: height int } +pub fn (t SplitTree) get_leftmost_id() int { + if root := t.root { + return t.find_leftmost_id(root) + } + return -1 +} + +fn (t SplitTree) find_leftmost_id(node SplitNode) int { + match node { + EditorLeaf { + return node.editor_id + } + SplitContainer { + // the leftmost editor is always in the first child + return t.find_leftmost_id(node.children[0]) + } + } +} + pub fn (t SplitTree) get_layout(total_width int, total_height int) []LayoutRect { mut rects := []LayoutRect{} if root := t.root { From 65d13c755b2ea575378a68b26593bb23e0e25a39 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Thu, 8 Jan 2026 14:16:51 +0000 Subject: [PATCH 4/7] chore: migrate switching between splits into msg emission --- editor_workspace.v | 173 +++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 93 deletions(-) diff --git a/editor_workspace.v b/editor_workspace.v index 3b24226c..010499fa 100644 --- a/editor_workspace.v +++ b/editor_workspace.v @@ -101,6 +101,19 @@ fn unfocus_editor(editor_id int) tea.Cmd { } } +struct ToggleEditorShowBorderMsg { + id int + show bool +} + +fn toggle_editor_show_border(editor_id int, show bool) tea.Cmd { + return fn [editor_id, show] () tea.Msg { + return ToggleEditorShowBorderMsg{ + id: editor_id + show: show + } + } +} fn raise_error(error string) tea.Cmd { return tea.sequence(display_error(error), error_log(error), hide_error_after(6 * time.second)) @@ -275,53 +288,10 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { .runes { match msg.string() { 'h' { - // move to previous split (left) - if m.split_tree.count() > 1 { - old_id := m.split_tree.active_editor_id - moved := m.split_tree.navigate_prev(m.tmux_wrapped) - - if moved == false { - os.execute('tmux select-pane -L') - } else { - new_id := m.split_tree.active_editor_id - m.active_editor_id = new_id - - cmds << tea.sequence( - unfocus_editor(old_id), - focus_editor(new_id), - query_editor_data(new_id), - query_pwd_git_branch - ) - } - } else { - if m.tmux_wrapped { - os.execute('tmux select-pane -L') - } - } + cmds << switch_active_split(.left) } 'l' { - // move to next split (right) - if m.split_tree.count() > 1 { - old_id := m.split_tree.active_editor_id - moved := m.split_tree.navigate_next(m.tmux_wrapped) - if moved == false { - os.execute('tmux select-pane -R') - } else { - new_id := m.split_tree.active_editor_id - m.active_editor_id = new_id - - cmds << tea.sequence( - unfocus_editor(old_id), - focus_editor(new_id), - query_editor_data(new_id), - query_pwd_git_branch - ) - } - } else { - if m.tmux_wrapped { - os.execute('tmux select-pane -R') - } - } + cmds << switch_active_split(.right) } else {} } @@ -341,54 +311,9 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { } "ctrl+w+h" { cmds << switch_active_split(.left) - // move to previous split (left) - if m.split_tree.count() > 1 { - old_id := m.split_tree.active_editor_id - moved := m.split_tree.navigate_prev(m.tmux_wrapped) - - if moved == false { - os.execute('tmux select-pane -L') - } else { - new_id := m.split_tree.active_editor_id - m.active_editor_id = new_id - - cmds << tea.sequence( - unfocus_editor(old_id), - focus_editor(new_id), - query_editor_data(new_id), - query_pwd_git_branch - ) - } - } else { - if m.tmux_wrapped { - os.execute('tmux select-pane -L') - } - } } "ctrl+w+l" { cmds << switch_active_split(.right) - // move to next split (right) - if m.split_tree.count() > 1 { - old_id := m.split_tree.active_editor_id - moved := m.split_tree.navigate_next(m.tmux_wrapped) - if moved == false { - os.execute('tmux select-pane -R') - } else { - new_id := m.split_tree.active_editor_id - m.active_editor_id = new_id - - cmds << tea.sequence( - unfocus_editor(old_id), - focus_editor(new_id), - query_editor_data(new_id), - query_pwd_git_branch - ) - } - } else { - if m.tmux_wrapped { - os.execute('tmux select-pane -R') - } - } } else {} } @@ -473,7 +398,12 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { cmds << u_cmd } - cmds << tea.sequence(focus_editor(editor_id), query_editor_data(editor_id), query_pwd_git_branch) + cmds << tea.sequence( + focus_editor(editor_id), + toggle_editor_show_border(editor_id, false), + query_editor_data(editor_id), + query_pwd_git_branch + ) cmds << debug_log("opened file ${msg.file_path} into model of id ${editor_id}") } VerticalSplitMsg { @@ -492,9 +422,11 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { m.active_editor_id = m.split_tree.active_editor_id cmds << tea.sequence( - unfocus_editor(old_id), // Unfocus the old editor + unfocus_editor(old_id), + toggle_editor_show_border(m.split_tree.get_leftmost_id(), false), focus_editor(new_id), query_editor_data(new_id), + query_pwd_git_branch, tea.emit_resize ) } @@ -511,12 +443,67 @@ fn (mut m EditorWorkspaceModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { // focus the new active editor cmds << tea.sequence( focus_editor(m.active_editor_id), + toggle_editor_show_border(m.split_tree.get_leftmost_id(), false), query_editor_data(m.active_editor_id), - query_pwd_git_branch + query_pwd_git_branch, + tea.emit_resize ) } } } + SwitchActiveSplitMsg { + match msg.dir { + .left { + // move to previous split (left) + if m.split_tree.count() > 1 { + old_id := m.split_tree.active_editor_id + moved := m.split_tree.navigate_prev(m.tmux_wrapped) + + if moved == false { + os.execute('tmux select-pane -L') + } else { + new_id := m.split_tree.active_editor_id + m.active_editor_id = new_id + + cmds << tea.sequence( + unfocus_editor(old_id), + focus_editor(new_id), + query_editor_data(new_id), + query_pwd_git_branch + ) + } + } else { + if m.tmux_wrapped { + os.execute('tmux select-pane -L') + } + } + } + .right { + // move to next split (right) + if m.split_tree.count() > 1 { + old_id := m.split_tree.active_editor_id + moved := m.split_tree.navigate_next(m.tmux_wrapped) + if moved == false { + os.execute('tmux select-pane -R') + } else { + new_id := m.split_tree.active_editor_id + m.active_editor_id = new_id + + cmds << tea.sequence( + unfocus_editor(old_id), + focus_editor(new_id), + query_editor_data(new_id), + query_pwd_git_branch + ) + } + } else { + if m.tmux_wrapped { + os.execute('tmux select-pane -R') + } + } + } + } + } EditorDataResultMsg { m.active_editor_data = msg.data } From daeab6fc42a43b6a8f359032f62049e599dc9633 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Thu, 8 Jan 2026 14:18:46 +0000 Subject: [PATCH 5/7] docs: add reminder --- colors.v | 3 +++ 1 file changed, 3 insertions(+) diff --git a/colors.v b/colors.v index 970006e0..6a37bf36 100644 --- a/colors.v +++ b/colors.v @@ -2,6 +2,9 @@ module palette import tauraamui.bobatea as tea +// TODO(tauraamui): consolidate all used colors into a core palette/swatch set +// and alias reference off of that only in the places/models they are used with +// alternative names, instead of here. This file is getting messy and out of hand. pub const theme_bg_color = matte_black_bg_color pub const matte_black_bg_color = tea.Color{ 20, 20, 20 } From c1bc1e55eafc4212edbab752d3c3a64a456c767e Mon Sep 17 00:00:00 2001 From: tauraamui Date: Thu, 8 Jan 2026 14:25:00 +0000 Subject: [PATCH 6/7] feat: emit toggle border flip for editors --- editor.v | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/editor.v b/editor.v index c8c7b841..6c398492 100644 --- a/editor.v +++ b/editor.v @@ -44,8 +44,9 @@ struct EditorModel { id int file_path string mut: - focused bool - cursor_pos ModelCursorPos + focused bool + show_border bool = true + cursor_pos ModelCursorPos width int height int @@ -167,6 +168,15 @@ fn (mut m EditorModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { else {} } } + ToggleEditorShowBorderMsg { + if msg.id == m.id { + m.show_border = msg.show + } else { + if msg.show == false { + m.show_border = true + } + } + } EditorCursorUpMsg { if m.focused { m.cursor_pos = m.cursor_pos.up() @@ -182,13 +192,20 @@ fn (mut m EditorModel) update(msg tea.Msg) (tea.Model, ?tea.Cmd) { return m.clone(), tea.batch_array(cmds) } +const active_editor_border_color = palette.petal_pink_color +const inactive_editor_border_color = palette.status_dark_lilac + fn (m EditorModel) view(mut ctx tea.Context) { ctx.set_clip_area(tea.ClipArea{ 0, 0, m.width, m.height }) defer { ctx.clear_clip_area() } - - for y in 0..m.height { - ctx.draw_text(0, y, '│') + if m.show_border { + border_color := if m.focused { active_editor_border_color } else { inactive_editor_border_color } + ctx.set_color(border_color) + for y in 0..m.height { + ctx.draw_text(0, y, '│') + } + ctx.reset_color() } ctx.push_offset(tea.Offset{ x: 1 }) From 4b0cc0f729e18780617f2a0153bfab1a5c8f2064 Mon Sep 17 00:00:00 2001 From: tauraamui Date: Thu, 8 Jan 2026 14:34:06 +0000 Subject: [PATCH 7/7] chore: start to tidy colors --- colors.v | 34 +++++++++++++++------------------- editor_workspace.v | 2 +- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/colors.v b/colors.v index 6a37bf36..f4bd249d 100644 --- a/colors.v +++ b/colors.v @@ -8,10 +8,24 @@ import tauraamui.bobatea as tea pub const theme_bg_color = matte_black_bg_color pub const matte_black_bg_color = tea.Color{ 20, 20, 20 } +pub const petal_pink_color = tea.Color{ 245, 191, 243 } +pub const petal_green_color = tea.Color{ 97, 242, 136 } +pub const petal_red_color = tea.Color{ 245, 42, 42 } + +pub const status_green = tea.Color{ 145, 237, 145 } +pub const status_orange = tea.Color{ 237, 207, 123 } +pub const status_lilac = tea.Color{ 194, 110, 230 } +pub const status_dark_lilac = tea.Color{ 154, 119, 209 } +pub const status_cyan = tea.Color{ 138, 222, 237 } +pub const status_purple = tea.Color{ 130, 144, 250 } + +pub const error_color = petal_red_color + + pub const matte_black_fg_color = tea.Color.ansi(232) pub const matte_white_fg_color = tea.Color{ 230, 230, 230 } pub const bright_off_white_fg_color = tea.Color{ 255, 255, 255 } -pub const bright_red_fg_color = tea.Color{ 245, 42, 42 } +// pub const bright_red_fg_color = tea.Color{ 245, 42, 42 } pub const subtle_text_fg_color = tea.Color.ansi(249) pub const help_fg_color = tea.Color.ansi(241) @@ -20,30 +34,12 @@ pub const selected_highlight_bg_color = tea.Color.ansi(239) pub const subtle_border_fg_color = petal_pink_color -pub const petal_pink_color = tea.Color{ - r: 245 - g: 191 - b: 243 -} - -pub const petal_green_color = tea.Color{ - r: 97 - g: 242 - b: 136 -} pub const status_bar_bg_color = tea.Color.ansi(234) pub const status_file_name_bg_color = tea.Color{ 86, 86, 86 } pub const status_branch_name_bg_color = tea.Color{ 154, 119, 209 } pub const status_cursor_pos_bg_color = tea.Color{ 245, 42, 42 } -pub const status_green = tea.Color{ 145, 237, 145 } -pub const status_orange = tea.Color{ 237, 207, 123 } -pub const status_lilac = tea.Color{ 194, 110, 230 } -pub const status_dark_lilac = tea.Color{ 154, 119, 209 } -pub const status_cyan = tea.Color{ 138, 222, 237 } -pub const status_purple = tea.Color{ 130, 144, 250 } - pub fn fg_color(background_color tea.Color) tea.Color { s_r := f32(background_color.r) / 255 s_g := f32(background_color.g) / 255 diff --git a/editor_workspace.v b/editor_workspace.v index 010499fa..a0b28f30 100644 --- a/editor_workspace.v +++ b/editor_workspace.v @@ -716,7 +716,7 @@ fn (m EditorWorkspaceModel) render_status_blocks(mut ctx tea.Context) { fn (m EditorWorkspaceModel) render_leader_or_command_user_input_text(mut ctx tea.Context) { if err_msg := m.error_msg { - ctx.set_color(palette.bright_red_fg_color) + ctx.set_color(palette.error_color) ctx.draw_text(1, ctx.window_height() - 1, err_msg) ctx.reset_color() return