Skip to content

Commit

Permalink
Add windows resize feature
Browse files Browse the repository at this point in the history
Co-authored-by: Termina94
  • Loading branch information
sander777 committed Oct 21, 2023
1 parent 7c98b1c commit 3b59425
Show file tree
Hide file tree
Showing 4 changed files with 238 additions and 11 deletions.
26 changes: 25 additions & 1 deletion helix-term/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use helix_view::{
info::Info,
input::KeyEvent,
keyboard::KeyCode,
tree,
tree::{self, Dimension, Resize},
view::View,
Document, DocumentId, Editor, ViewId,
};
Expand Down Expand Up @@ -347,6 +347,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",
toggle_focus_window, "Toggle focus mode on buffer",
goto_next_change, "Goto next change",
goto_prev_change, "Goto previous change",
goto_first_change, "Goto first change",
Expand Down Expand Up @@ -3360,6 +3365,25 @@ fn goto_first_change_impl(cx: &mut Context, reverse: bool) {
}
}

fn grow_buffer_width(cx: &mut Context) {
cx.editor.resize_buffer(Resize::Grow, Dimension::Width);
}

fn shrink_buffer_width(cx: &mut Context) {
cx.editor.resize_buffer(Resize::Shrink, Dimension::Width);
}
fn grow_buffer_height(cx: &mut Context) {
cx.editor.resize_buffer(Resize::Grow, Dimension::Height);
}

fn shrink_buffer_height(cx: &mut Context) {
cx.editor.resize_buffer(Resize::Shrink, Dimension::Height);
}

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

fn goto_next_change(cx: &mut Context) {
goto_next_change_impl(cx, Direction::Forward)
}
Expand Down
17 changes: 17 additions & 0 deletions helix-term/src/keymap/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,23 @@ pub fn default() -> HashMap<Mode, KeyTrie> {
},
},

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


"A-W" => { "Alter Window" sticky=true
"h" | "left" => shrink_buffer_width,
"l" | "right" => grow_buffer_width,
"j" | "down" => shrink_buffer_height,
"k" | "up" => grow_buffer_height,
"f" => toggle_focus_window,
},

// move under <space>c
"C-c" => toggle_comments,

Expand Down
10 changes: 9 additions & 1 deletion helix-view/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
input::KeyEvent,
register::Registers,
theme::{self, Theme},
tree::{self, Tree},
tree::{self, Dimension, Resize, Tree},
view::ViewPosition,
Align, Document, DocumentId, View, ViewId,
};
Expand Down Expand Up @@ -1645,6 +1645,14 @@ impl Editor {
self.tree.transpose();
}

pub fn resize_buffer(&mut self, resize_type: Resize, dimension: Dimension) {
self.tree.resize_buffer(resize_type, dimension);
}

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

pub fn should_close(&self) -> bool {
self.tree.is_empty()
}
Expand Down
196 changes: 187 additions & 9 deletions helix-view/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ pub enum Content {
Container(Box<Container>),
}

pub enum Resize {
Shrink,
Grow,
}

pub enum Dimension {
Width,
Height,
}

impl Node {
pub fn container(layout: Layout) -> Self {
Self {
Expand Down Expand Up @@ -65,6 +75,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,
expand: bool,
}

impl Container {
Expand All @@ -73,8 +91,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> {
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,
expand: false,
});
self
}

fn insert_child_bounds(&mut self, index: usize) -> &mut Self {
self.node_bounds.insert(
index,
ContainerBounds {
width: 10,
height: 10,
expand: 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.expand {
true => 40,
false => bounds.width,
})
.sum()
}

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

impl Default for Container {
Expand Down Expand Up @@ -131,7 +221,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 +258,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 +272,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 +322,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 {
// if container now empty, remove it
Expand Down Expand Up @@ -360,11 +450,17 @@ impl Tree {
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.expand {
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 @@ -373,7 +469,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 @@ -385,14 +481,19 @@ 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 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.expand {
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 @@ -571,6 +672,83 @@ 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 resize_buffer(&mut self, resize_type: Resize, dimension: Dimension) {
match dimension {
Dimension::Width => {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Vertical) {
match resize_type {
Resize::Shrink => {
if bounds.width > 1 {
bounds.width -= 1;
}
}
Resize::Grow => {
if bounds.width < 20 {
bounds.width += 1;
}
}
};
self.recalculate();
}
}
Dimension::Height => {
if let Some(bounds) = self.get_active_node_bounds_mut(Layout::Horizontal) {
match resize_type {
Resize::Shrink => {
if bounds.height > 1 {
bounds.height -= 1;
}
}
Resize::Grow => {
if bounds.height < 20 {
bounds.height += 1;
}
}
};
self.recalculate();
}
}
}
}

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

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

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

0 comments on commit 3b59425

Please sign in to comment.