Compare commits

..

No commits in common. "0df97f5ad5a35fc9894a613da786d11bd7b4a2fb" and "86856f663158e50d9c68d71df37ab9ca8dbad1ae" have entirely different histories.

4 changed files with 36 additions and 88 deletions

View file

@ -2,7 +2,7 @@ const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const cbor = @import("cbor"); const cbor = @import("cbor");
const TypedInt = @import("TypedInt"); const TypedInt = @import("TypedInt");
pub const VcsBlame = @import("VcsBlame"); const VcsBlame = @import("VcsBlame");
const file_type_config = @import("file_type_config"); const file_type_config = @import("file_type_config");
const Allocator = std.mem.Allocator; const Allocator = std.mem.Allocator;
const ArrayList = std.ArrayList; const ArrayList = std.ArrayList;

View file

@ -1538,16 +1538,13 @@ pub const Editor = struct {
return if (head_line < 0) null else @intCast(head_line); return if (head_line < 0) null else @intCast(head_line);
} }
pub fn get_vcs_blame(self: *const Self, row: usize) ?*const Buffer.VcsBlame.Commit {
const buffer = self.buffer orelse return null;
const blame_row = self.get_delta_lines_until_row(row) orelse return null;
return buffer.get_vcs_blame(blame_row) orelse return null;
}
fn render_blame(self: *Self, theme: *const Widget.Theme, hl_row: ?usize, cell_map: CellMap) !void { fn render_blame(self: *Self, theme: *const Widget.Theme, hl_row: ?usize, cell_map: CellMap) !void {
const cursor = self.get_primary().cursor; const cursor = self.get_primary().cursor;
const pos = self.screen_cursor(&cursor) orelse return; const pos = self.screen_cursor(&cursor) orelse return;
const commit = self.get_vcs_blame(cursor.row) orelse return; const buffer = self.buffer orelse return;
const blame_row = self.get_delta_lines_until_row(cursor.row) orelse return;
const commit = buffer.get_vcs_blame(blame_row) orelse return;
const screen_width = self.view.cols; const screen_width = self.view.cols;
var space_begin = screen_width; var space_begin = screen_width;

View file

@ -9,7 +9,6 @@
/// {{selections*}} - All current selections expanded to multiple quoted arguments /// {{selections*}} - All current selections expanded to multiple quoted arguments
/// {{indent_mode}} - The current indent mode ("tabs" or "spaces") /// {{indent_mode}} - The current indent mode ("tabs" or "spaces")
/// {{indent_size}} - The current indent size (in columns) /// {{indent_size}} - The current indent size (in columns)
/// {{blame_commit}} - The blame commit ID at the line number of the primary cursor
pub fn expand(allocator: Allocator, arg: []const u8) Error![]const u8 { pub fn expand(allocator: Allocator, arg: []const u8) Error![]const u8 {
var result: std.Io.Writer.Allocating = .init(allocator); var result: std.Io.Writer.Allocating = .init(allocator);
defer result.deinit(); defer result.deinit();
@ -161,18 +160,6 @@ const functions = struct {
try stream.writer.print("{d}", .{ed.indent_size}); try stream.writer.print("{d}", .{ed.indent_size});
return stream.toOwnedSlice(); return stream.toOwnedSlice();
} }
/// {{blame_commit}} - The blame commit ID at the line number of the primary cursor
pub fn blame_commit(allocator: Allocator) Error![]const u8 {
const mv = tui.mainview() orelse return &.{};
const ed = mv.get_active_editor() orelse return &.{};
const row = ed.get_primary().cursor.row;
const commit = ed.get_vcs_blame(row);
const id = if (commit) |c| c.id else "";
var stream: std.Io.Writer.Allocating = .init(allocator);
try stream.writer.print("{s}", .{id});
return stream.toOwnedSlice();
}
}; };
fn get_functions() []struct { []const u8, Function } { fn get_functions() []struct { []const u8, Function } {

View file

@ -30,7 +30,6 @@ const @"style.config" = struct {
close_icon_fg: colors = .Error, close_icon_fg: colors = .Error,
save_icon: []const u8 = "󰆓", save_icon: []const u8 = "󰆓",
save_icon_fg: ?colors = null, save_icon_fg: ?colors = null,
clipping_indicator: []const u8 = "»",
spacer: []const u8 = "|", spacer: []const u8 = "|",
spacer_fg: colors = .active_bg, spacer_fg: colors = .active_bg,
@ -101,8 +100,8 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
pub const TabBar = struct { pub const TabBar = struct {
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
plane: Plane, plane: Plane,
splits_list: *WidgetList, widget_list: *WidgetList,
splits_list_widget: Widget, widget_list_widget: Widget,
event_handler: ?EventHandler, event_handler: ?EventHandler,
tabs: []TabBarTab = &[_]TabBarTab{}, tabs: []TabBarTab = &[_]TabBarTab{},
active_focused_buffer_ref: ?Buffer.Ref = null, active_focused_buffer_ref: ?Buffer.Ref = null,
@ -134,8 +133,8 @@ pub const TabBar = struct {
return .{ return .{
.allocator = allocator, .allocator = allocator,
.plane = w.plane, .plane = w.plane,
.splits_list = w, .widget_list = w,
.splits_list_widget = w.widget(), .widget_list_widget = w.widget(),
.event_handler = event_handler, .event_handler = event_handler,
.tab_style = tab_style, .tab_style = tab_style,
.tab_style_bufs = tab_style_bufs, .tab_style_bufs = tab_style_bufs,
@ -146,13 +145,13 @@ pub const TabBar = struct {
pub fn deinit(self: *Self, allocator: std.mem.Allocator) void { pub fn deinit(self: *Self, allocator: std.mem.Allocator) void {
root.free_config(self.allocator, self.tab_style_bufs); root.free_config(self.allocator, self.tab_style_bufs);
self.allocator.free(self.tabs); self.allocator.free(self.tabs);
self.splits_list_widget.deinit(allocator); self.widget_list_widget.deinit(allocator);
allocator.destroy(self); allocator.destroy(self);
} }
pub fn layout(self: *Self) Widget.Layout { pub fn layout(self: *Self) Widget.Layout {
return if (self.tabs.len >= self.minimum_tabs_shown) return if (self.tabs.len >= self.minimum_tabs_shown)
self.splits_list_widget.layout() self.widget_list_widget.layout()
else else
.{ .static = 0 }; .{ .static = 0 };
} }
@ -160,9 +159,9 @@ pub const TabBar = struct {
pub fn update(self: *Self) void { pub fn update(self: *Self) void {
const drag_source, const drag_btn = tui.get_drag_source(); const drag_source, const drag_btn = tui.get_drag_source();
self.update_tabs(drag_source) catch {}; self.update_tabs(drag_source) catch {};
self.splits_list_widget.resize(Widget.Box.from(self.plane)); self.widget_list_widget.resize(Widget.Box.from(self.plane));
self.splits_list_widget.update(); self.widget_list_widget.update();
for (self.splits_list.widgets.items) |*split_widgetstate| if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split| for (self.widget_list.widgets.items) |*split_widgetstate| if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split|
for (split.widgets.items) |*widgetstate| if (widgetstate.widget.dynamic_cast(Tab.ButtonType)) |btn| if (btn.drag_pos) |_| for (split.widgets.items) |*widgetstate| if (widgetstate.widget.dynamic_cast(Tab.ButtonType)) |btn| if (btn.drag_pos) |_|
tui.update_drag_source(&widgetstate.widget, drag_btn); tui.update_drag_source(&widgetstate.widget, drag_btn);
tui.refresh_hover(@src()); tui.refresh_hover(@src());
@ -178,40 +177,10 @@ pub const TabBar = struct {
}); });
self.plane.fill(" "); self.plane.fill(" ");
self.plane.home(); self.plane.home();
for (self.tabs) |*tab| { for (self.tabs) |*tab| _ = tab.widget.render(theme);
const clipped, const clip_box = self.is_tab_clipped(tab);
if (clipped) {
if (clip_box) |box| self.render_clipping_indicator(box, theme);
continue;
}
_ = tab.widget.render(theme);
}
return false; return false;
} }
fn is_tab_clipped(self: *const Self, tab: *const TabBarTab) struct { bool, ?Widget.Box } {
const view = tab.view orelse return .{ true, null };
const split_idx = if (view < self.splits_list.widgets.items.len) view else return .{ true, null };
const split = self.splits_list.widgets.items[split_idx];
const split_box = Widget.Box.from(split.widget.plane.*);
const widget_box = tab.widget.box();
const dragging = if (tab.widget.dynamic_cast(Tab.ButtonType)) |btn| if (btn.drag_pos) |_| true else false else false;
if (dragging) return .{ false, split_box };
if (split_box.y + split_box.h < widget_box.y + widget_box.h or
split_box.x + split_box.w < widget_box.x + widget_box.w)
return .{ true, split_box };
return .{ false, split_box };
}
fn render_clipping_indicator(self: *@This(), box: Widget.Box, theme: *const Widget.Theme) void {
self.plane.set_style(.{
.fg = self.tab_style.bar_fg.from_theme(theme),
.bg = self.tab_style.bar_bg.from_theme(theme),
});
self.plane.cursor_move_yx(0, @intCast(box.x + box.w -| 1));
self.plane.putchar(self.tab_style.clipping_indicator);
}
pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool { pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
var buffer_ref: Buffer.Ref = undefined; var buffer_ref: Buffer.Ref = undefined;
if (try m.match(.{"next_tab"})) { if (try m.match(.{"next_tab"})) {
@ -267,7 +236,7 @@ pub const TabBar = struct {
fn handle_event_drop_target(self: *Self, dragging: usize) tp.result { fn handle_event_drop_target(self: *Self, dragging: usize) tp.result {
var hover_view: ?usize = null; var hover_view: ?usize = null;
for (self.splits_list.widgets.items, 0..) |*split_widgetstate, idx| for (self.widget_list.widgets.items, 0..) |*split_widgetstate, idx|
if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split| { if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split| {
for (split.widgets.items) |*widgetstate| for (split.widgets.items) |*widgetstate|
if (widgetstate.widget.dynamic_cast(drop_target.ButtonType)) |btn| { if (widgetstate.widget.dynamic_cast(drop_target.ButtonType)) |btn| {
@ -282,25 +251,20 @@ pub const TabBar = struct {
} }
pub fn handle_resize(self: *Self, pos: Widget.Box) void { pub fn handle_resize(self: *Self, pos: Widget.Box) void {
self.splits_list_widget.resize(pos); self.widget_list_widget.resize(pos);
self.plane = self.splits_list.plane; self.plane = self.widget_list.plane;
} }
pub fn get(self: *const Self, name: []const u8) ?*const Widget { pub fn get(self: *const Self, name: []const u8) ?*const Widget {
return self.splits_list_widget.get(name); return self.widget_list_widget.get(name);
} }
pub fn walk(self: *Self, ctx: *anyopaque, f: Widget.WalkFn, self_w: *Widget) bool { pub fn walk(self: *Self, ctx: *anyopaque, f: Widget.WalkFn, _: *Widget) bool {
for (self.tabs) |*tab| { return self.widget_list_widget.walk(ctx, f);
const clipped, _ = self.is_tab_clipped(tab);
if (!clipped)
if (tab.widget.walk(ctx, f)) return true;
}
return f(ctx, self_w);
} }
pub fn hover(self: *Self) bool { pub fn hover(self: *Self) bool {
return self.splits_list_widget.hover(); return self.widget_list_widget.hover();
} }
fn update_tabs(self: *Self, drag_source: ?*Widget) !void { fn update_tabs(self: *Self, drag_source: ?*Widget) !void {
@ -309,7 +273,7 @@ pub const TabBar = struct {
if (tab.widget.dynamic_cast(Tab.ButtonType)) |btn| if (tab.widget.dynamic_cast(Tab.ButtonType)) |btn|
if (btn.drag_pos) |_| break true; if (btn.drag_pos) |_| break true;
} else false; } else false;
if (!dragging and !buffers_changed and self.splits_list.widgets.items.len > 0) return; if (!dragging and !buffers_changed and self.widget_list.widgets.items.len > 0) return;
try self.update_tab_widgets(drag_source); try self.update_tab_widgets(drag_source);
} }
@ -318,19 +282,19 @@ pub const TabBar = struct {
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
var prev_widget_count: usize = 0; var prev_widget_count: usize = 0;
for (self.splits_list.widgets.items) |*split_widgetstate| if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split| { for (self.widget_list.widgets.items) |*split_widgetstate| if (split_widgetstate.widget.dynamic_cast(WidgetList)) |split| {
prev_widget_count += 1; prev_widget_count += 1;
for (split.widgets.items) |_| prev_widget_count += 1; for (split.widgets.items) |_| prev_widget_count += 1;
}; };
for (self.splits_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| { for (self.widget_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| {
for (split.widgets.items) |*widget| for (split.widgets.items) |*widget|
if (&widget.widget == drag_source) tui.reset_drag_context(); if (&widget.widget == drag_source) tui.reset_drag_context();
}; };
while (self.splits_list.pop()) |split_widget| if (split_widget.dynamic_cast(WidgetList)) |split| { while (self.widget_list.pop()) |split_widget| if (split_widget.dynamic_cast(WidgetList)) |split| {
while (split.pop()) |widget| if (widget.dynamic_cast(Tab.ButtonType) == null) while (split.pop()) |widget| if (widget.dynamic_cast(Tab.ButtonType) == null)
widget.deinit(self.splits_list.allocator); widget.deinit(self.widget_list.allocator);
split.deinit(self.splits_list.allocator); split.deinit(self.widget_list.allocator);
}; };
for (self.tabs) |*tab| if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer| { for (self.tabs) |*tab| if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer| {
@ -342,8 +306,8 @@ pub const TabBar = struct {
var widget_count: usize = 0; var widget_count: usize = 0;
for (0..views) |view| { for (0..views) |view| {
var first = true; var first = true;
var view_widget_list = try WidgetList.createH(self.allocator, self.splits_list.plane, "split", .dynamic); var view_widget_list = try WidgetList.createH(self.allocator, self.widget_list.plane, "split", .dynamic);
try self.splits_list.add(view_widget_list.widget()); try self.widget_list.add(view_widget_list.widget());
widget_count += 1; widget_count += 1;
for (self.tabs) |tab| { for (self.tabs) |tab| {
const tab_view = tab.view orelse 0; const tab_view = tab.view orelse 0;
@ -449,7 +413,7 @@ pub const TabBar = struct {
} }
fn find_first_tab_buffer(self: *Self) ?Buffer.Ref { fn find_first_tab_buffer(self: *Self) ?Buffer.Ref {
for (self.splits_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| for (self.widget_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split|
for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn|
return btn.opts.ctx.buffer_ref; return btn.opts.ctx.buffer_ref;
return null; return null;
@ -457,7 +421,7 @@ pub const TabBar = struct {
fn find_last_tab_buffer(self: *Self) ?Buffer.Ref { fn find_last_tab_buffer(self: *Self) ?Buffer.Ref {
var last: ?Buffer.Ref = null; var last: ?Buffer.Ref = null;
for (self.splits_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| for (self.widget_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split|
for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| { for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| {
last = btn.opts.ctx.buffer_ref; last = btn.opts.ctx.buffer_ref;
}; };
@ -466,7 +430,7 @@ pub const TabBar = struct {
fn find_next_tab_buffer(self: *Self) struct { ?Buffer.Ref, usize } { fn find_next_tab_buffer(self: *Self) struct { ?Buffer.Ref, usize } {
var found_active: bool = false; var found_active: bool = false;
for (self.splits_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| for (self.widget_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split|
for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| { for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| {
if (found_active) if (found_active)
return .{ btn.opts.ctx.buffer_ref, btn.opts.ctx.view }; return .{ btn.opts.ctx.buffer_ref, btn.opts.ctx.view };
@ -479,7 +443,7 @@ pub const TabBar = struct {
fn find_previous_tab_buffer(self: *Self) struct { ?Buffer.Ref, usize } { fn find_previous_tab_buffer(self: *Self) struct { ?Buffer.Ref, usize } {
var previous: ?Buffer.Ref = null; var previous: ?Buffer.Ref = null;
var previous_view: usize = 0; var previous_view: usize = 0;
for (self.splits_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split| for (self.widget_list.widgets.items) |*split_widget| if (split_widget.widget.dynamic_cast(WidgetList)) |split|
for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| { for (split.widgets.items) |*widget_state| if (widget_state.widget.dynamic_cast(Tab.ButtonType)) |btn| {
if (btn.opts.ctx.buffer_ref == self.active_focused_buffer_ref) if (btn.opts.ctx.buffer_ref == self.active_focused_buffer_ref)
return .{ previous, previous_view }; return .{ previous, previous_view };
@ -699,7 +663,7 @@ const Tab = struct {
) !Widget { ) !Widget {
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager"); const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
const buffer = buffer_manager.buffer_from_ref(buffer_ref); const buffer = buffer_manager.buffer_from_ref(buffer_ref);
return Button.create_widget(Tab, tabbar.allocator, tabbar.splits_list.plane, .{ return Button.create_widget(Tab, tabbar.allocator, tabbar.widget_list.plane, .{
.ctx = .{ .tabbar = tabbar, .buffer_ref = buffer_ref, .view = if (buffer) |buf| buf.get_last_view() orelse 0 else 0, .tab_style = tab_style }, .ctx = .{ .tabbar = tabbar, .buffer_ref = buffer_ref, .view = if (buffer) |buf| buf.get_last_view() orelse 0 else 0, .tab_style = tab_style },
.label = if (buffer) |buf| name_from_buffer(buf) else "???", .label = if (buffer) |buf| name_from_buffer(buf) else "???",
.on_click = Tab.on_click, .on_click = Tab.on_click,
@ -1062,7 +1026,7 @@ const drop_target = struct {
tabbar: *TabBar, tabbar: *TabBar,
view: usize, view: usize,
) !Widget { ) !Widget {
return Button.create_widget(@This(), tabbar.allocator, tabbar.splits_list.plane, .{ return Button.create_widget(@This(), tabbar.allocator, tabbar.widget_list.plane, .{
.ctx = .{ .tabbar = tabbar, .view = view }, .ctx = .{ .tabbar = tabbar, .view = view },
.label = &.{}, .label = &.{},
.on_layout = @This().layout, .on_layout = @This().layout,