Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,11 @@ impl MappableCommand {
goto_last_diag, "Goto last diagnostic",
goto_next_diag, "Goto next diagnostic",
goto_prev_diag, "Goto previous diagnostic",
grow_buffer_width, "Grow focused container width",
shrink_buffer_width, "Shrink focused container width",
grow_buffer_height, "Grow focused container height",
shrink_buffer_height, "Shrink focused container height",
buffer_focus_mode, "Enable focus mode on buffer",
goto_line_start, "Goto line start",
goto_line_end, "Goto line end",
goto_next_buffer, "Goto next buffer",
Expand Down Expand Up @@ -645,6 +650,25 @@ fn goto_line_start(cx: &mut Context) {
)
}

fn grow_buffer_width(cx: &mut Context) {
cx.editor.grow_buffer_width();
}

fn shrink_buffer_width(cx: &mut Context) {
cx.editor.shrink_buffer_width();
}
fn grow_buffer_height(cx: &mut Context) {
cx.editor.grow_buffer_height();
}

fn shrink_buffer_height(cx: &mut Context) {
cx.editor.shrink_buffer_height();
}

fn buffer_focus_mode(cx: &mut Context) {
cx.editor.buffer_focus_mode();
}

fn goto_next_buffer(cx: &mut Context) {
goto_buffer(cx.editor, Direction::Forward);
}
Expand Down
8 changes: 8 additions & 0 deletions helix-term/src/keymap/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ pub fn default() -> HashMap<Mode, Keymap> {
"home" => goto_line_start,
"end" => goto_line_end,

"A-w" => { "Alter Window"
"A-w"|"A-left" => shrink_buffer_width,
"A-l"|"A-right" => grow_buffer_width,
"A-j"|"A-down" => shrink_buffer_height,
"A-k"|"A-up" => grow_buffer_height,
"A-f" => buffer_focus_mode,
},

"w" => move_next_word_start,
"b" => move_prev_word_start,
"e" => move_next_word_end,
Expand Down
20 changes: 20 additions & 0 deletions helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,26 @@ impl Editor {
self.tree.transpose();
}

pub fn grow_buffer_width(&mut self) {
self.tree.grow_buffer_width();
}

pub fn shrink_buffer_width(&mut self) {
self.tree.shrink_buffer_width();
}

pub fn grow_buffer_height(&mut self) {
self.tree.grow_buffer_height();
}

pub fn shrink_buffer_height(&mut self) {
self.tree.shrink_buffer_height();
}

pub fn buffer_focus_mode(&mut self) {
self.tree.buffer_focus_mode();
}

pub fn should_close(&self) -> bool {
self.tree.is_empty()
}
Expand Down
190 changes: 177 additions & 13 deletions helix-view/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ pub struct Container {
layout: Layout,
children: Vec<ViewId>,
area: Rect,
node_bounds: Vec<ContainerBounds>,
}

#[derive(Debug, Clone, Copy)]
pub struct ContainerBounds {
width: usize,
height: usize,
focus: bool,
}

impl Container {
Expand All @@ -73,8 +81,80 @@ impl Container {
layout,
children: Vec::new(),
area: Rect::default(),
node_bounds: Vec::new(),
}
}

fn get_child_by_view_id(&mut self, node: ViewId) -> Option<&mut ContainerBounds> {
if let Some(index) = self.children.iter().position(|child| child == &node) {
return self.node_bounds.get_mut(index);
};
None
Comment on lines +99 to +102
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if let Some(index) = self.children.iter().position(|child| child == &node) {
return self.node_bounds.get_mut(index);
};
None
self.children
.iter()
.position(|child| child == &node)
.and_then(|index| self.node_bounds.get_mut(index))

}

fn push_child(&mut self, node: ViewId) -> &mut Self {
self.children.push(node);
self.add_child_bounds();
self
}

fn insert_child(&mut self, index: usize, node: ViewId) -> &mut Self {
self.children.insert(index, node);
self.insert_child_bounds(index);
self
}

fn remove_child(&mut self, index: usize) -> &mut Self {
self.children.remove(index);
self.remove_child_bounds(index);
self
}

fn add_child_bounds(&mut self) -> &mut Self {
self.node_bounds.push(ContainerBounds {
width: 10,
height: 10,
focus: false,
});
self
}

fn insert_child_bounds(&mut self, index: usize) -> &mut Self {
self.node_bounds.insert(
index,
ContainerBounds {
width: 10,
height: 10,
focus: false,
},
);
self
}

fn remove_child_bounds(&mut self, index: usize) -> &mut Self {
self.node_bounds.remove(index);
self
}

fn calculate_slots_width(&self) -> usize {
self.node_bounds
.iter()
.map(|bounds| match bounds.focus {
true => 40,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

40 is hard-coded in a few places. Can we make it a pub const that gets shared between the modules that use it? It could make sense to have this be configurable in the future for those that like resizing to be more fine-grained (or not).

false => bounds.width,
})
.sum()
}

fn calculate_slots_height(&self) -> usize {
self.node_bounds
.iter()
.map(|bounds| match bounds.focus {
true => 40,
false => bounds.height,
})
.sum()
}
}

impl Default for Container {
Expand Down Expand Up @@ -131,7 +211,7 @@ impl Tree {
pos + 1
};

container.children.insert(pos, node);
container.insert_child(pos, node);
// focus the new node
self.focus = node;

Expand Down Expand Up @@ -168,7 +248,7 @@ impl Tree {
.unwrap();
pos + 1
};
container.children.insert(pos, node);
container.insert_child(pos, node);
self.nodes[node].parent = parent;
} else {
let mut split = Node::container(layout);
Expand All @@ -182,8 +262,8 @@ impl Tree {
} => container,
_ => unreachable!(),
};
container.children.push(focus);
container.children.push(node);
container.push_child(focus);
container.push_child(node);
self.nodes[focus].parent = split;
self.nodes[node].parent = split;

Expand Down Expand Up @@ -232,7 +312,7 @@ impl Tree {
} = &mut self.nodes[parent_id]
{
if let Some(pos) = container.children.iter().position(|&child| child == index) {
container.children.remove(pos);
container.remove_child(pos);

// TODO: if container now only has one child, remove it and place child in parent
if container.children.is_empty() && parent_id != self.root {
Expand Down Expand Up @@ -340,12 +420,17 @@ impl Tree {
match container.layout {
Layout::Horizontal => {
let len = container.children.len();

let height = area.height / len as u16;

let slots = container.calculate_slots_height();
let slot_height = area.height as f32 / slots as f32;
let mut child_y = area.y;

for (i, child) in container.children.iter().enumerate() {
let bounds = container.node_bounds[i];
let height = match bounds.focus {
true => (40.0 * slot_height) as u16,
false => (slot_height * bounds.height as f32).floor() as u16,
};

let mut area = Rect::new(
container.area.x,
child_y,
Expand All @@ -354,7 +439,7 @@ impl Tree {
);
child_y += height;

// last child takes the remaining width because we can get uneven
// last child takes the remaining height because we can get uneven
// space from rounding
if i == len - 1 {
area.height = container.area.y + container.area.height - area.y;
Expand All @@ -365,15 +450,20 @@ impl Tree {
}
Layout::Vertical => {
let len = container.children.len();

let width = area.width / len as u16;
let slots = container.calculate_slots_width();
let slot_width: f32 = area.width as f32 / slots as f32;
let mut child_x = area.x;

let inner_gap = 1u16;
// let total_gap = inner_gap * (len as u16 - 1);

let mut child_x = area.x;

for (i, child) in container.children.iter().enumerate() {
let bounds = container.node_bounds[i];
let width = match bounds.focus {
true => (40.0 * slot_width) as u16,
false => (slot_width * bounds.width as f32).floor() as u16,
};

let mut area = Rect::new(
child_x,
container.area.y,
Expand Down Expand Up @@ -538,6 +628,80 @@ impl Tree {
}
}

fn get_active_node_bounds_mut(
&mut self,
expect_layout: Layout,
) -> Option<&mut ContainerBounds> {
let mut focus = self.focus;
let mut parent = self.nodes[focus].parent;

// Parent expected to be container
if let Some(focused_layout) = match &self.nodes[parent].content {
Content::View(_) => unreachable!(),
Content::Container(node) => Some(node.layout),
} {
// if we want to make a width change and we have a `Horizontal` layout focused,
// alter the parent `Vertical` layout instead and vice versa
if focused_layout != expect_layout {
focus = parent;
parent = self.nodes[parent].parent;
}

if let Content::Container(node) = &mut self.nodes[parent].content {
return node.as_mut().get_child_by_view_id(focus);
};
}
None
}

pub fn grow_buffer_width(&mut self) {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Vertical) {
if bounds.width < 20 {
bounds.width += 1;
self.recalculate();
}
}
}

pub fn shrink_buffer_width(&mut self) {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Vertical) {
if bounds.width > 1 {
bounds.width -= 1;
self.recalculate();
}
}
}

pub fn grow_buffer_height(&mut self) {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Horizontal) {
if bounds.height < 20 {
bounds.height += 1;
self.recalculate();
}
}
}

pub fn shrink_buffer_height(&mut self) {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Horizontal) {
if bounds.height > 1 {
bounds.height -= 1;
self.recalculate();
}
}
}

pub fn buffer_focus_mode(&mut self) {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Horizontal) {
bounds.focus = !bounds.focus;
}

if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Vertical) {
bounds.focus = !bounds.focus;
}

self.recalculate();
}

pub fn swap_split_in_direction(&mut self, direction: Direction) -> Option<()> {
let focus = self.focus;
let target = self.find_split_in_direction(focus, direction)?;
Expand Down