From 19f581693eceebb689ef233ce9eeabf62e6c90e2 Mon Sep 17 00:00:00 2001 From: Raphael Amorim Date: Mon, 7 Oct 2024 20:53:01 +0200 Subject: [PATCH] split right (basic poc functionality) --- frontends/rioterm/src/application.rs | 4 +- frontends/rioterm/src/context/grid.rs | 148 +++++++++++++++--- frontends/rioterm/src/context/mod.rs | 132 ++++++++++------ frontends/rioterm/src/renderer/mod.rs | 132 ++++++++-------- frontends/rioterm/src/screen/mod.rs | 13 ++ rio-backend/src/config/colors/defaults.rs | 14 ++ rio-backend/src/config/colors/mod.rs | 10 +- rio-backend/src/config/split.rs | 9 +- rio-window/src/event.rs | 2 +- .../src/platform_impl/macos/app_delegate.rs | 4 +- rio-window/src/platform_impl/macos/menu.rs | 10 +- 11 files changed, 331 insertions(+), 147 deletions(-) diff --git a/frontends/rioterm/src/application.rs b/frontends/rioterm/src/application.rs index c85a3e70..c3357947 100644 --- a/frontends/rioterm/src/application.rs +++ b/frontends/rioterm/src/application.rs @@ -1118,8 +1118,8 @@ impl ApplicationHandler for Application<'_> { route.window.screen.create_tab(); } } - Hook::CloseTab => { - route.window.screen.close_tab(); + Hook::Close => { + route.window.screen.close_split_or_tab(); } Hook::SplitDown => { // route.window.screen.close_tab(); diff --git a/frontends/rioterm/src/context/grid.rs b/frontends/rioterm/src/context/grid.rs index 12bff3b4..778e0bac 100644 --- a/frontends/rioterm/src/context/grid.rs +++ b/frontends/rioterm/src/context/grid.rs @@ -1,7 +1,9 @@ use crate::context::Context; use rio_backend::crosswords::grid::Dimensions; use rio_backend::event::EventListener; -use rio_backend::sugarloaf::{layout::SugarDimensions, Object, RichText, Quad, ComposedQuad}; +use rio_backend::sugarloaf::{ + layout::SugarDimensions, ComposedQuad, Object, Quad, RichText, +}; const MIN_COLS: usize = 2; const MIN_LINES: usize = 1; @@ -44,6 +46,8 @@ pub struct ContextGrid { pub height: f32, pub current: usize, pub margin: Delta, + border_color: [f32; 4], + active_border_color: [f32; 4], inner: Vec>, } @@ -67,8 +71,26 @@ impl ContextGridItem { } } +impl ContextGridItem { + #[inline] + pub fn context(&self) -> &Context { + &self.val + } + + #[inline] + pub fn context_mut(&mut self) -> &mut Context { + &mut self.val + } +} + impl ContextGrid { - pub fn new(context: Context, margin: Delta) -> Self { + pub fn new( + context: Context, + margin: Delta, + split_colors: ([f32; 4], [f32; 4]), + ) -> Self { + let border_color = split_colors.0; + let active_border_color = split_colors.1; let width = context.dimension.width; let height = context.dimension.height; let inner = vec![ContextGridItem::new(context)]; @@ -78,6 +100,8 @@ impl ContextGrid { margin, width, height, + border_color, + active_border_color, } } @@ -86,6 +110,16 @@ impl ContextGrid { &self.inner[index] } + #[inline] + pub fn contexts(&self) -> &Vec> { + &self.inner + } + + #[inline] + pub fn contexts_mut(&mut self) -> &mut Vec> { + &mut self.inner + } + #[inline] pub fn current(&self) -> &Context { &self.inner[self.current].val @@ -119,8 +153,21 @@ impl ContextGrid { objects } - pub fn plot_objects(&self, objects: &mut Vec, index: usize, margin: Delta) { + pub fn plot_objects( + &self, + objects: &mut Vec, + index: usize, + margin: Delta, + ) { if let Some(item) = self.inner.get(index) { + let border_color = if index == self.current { + self.active_border_color + } else { + self.border_color + }; + + let border_width = 1.0; + objects.push(Object::Quad(ComposedQuad { color: [0.0, 0.0, 0.0, 0.0], quad: Quad { @@ -128,23 +175,28 @@ impl ContextGrid { shadow_blur_radius: 0.0, shadow_offset: [0.0, 0.0], shadow_color: [0.0, 0.0, 0.0, 0.5], - border_color: [1.0, 0.0, 1.0, 1.0], - border_width: 2.0, + border_color, + border_width: 1.0, border_radius: [0.0, 0.0, 0.0, 0.0], - size: [item.width, item.height], + size: [ + item.width / item.val.dimension.dimension.scale, + item.height / item.val.dimension.dimension.scale, + ], }, })); objects.push(Object::RichText(RichText { id: item.val.rich_text_id, - position: [margin.x + PADDING, margin.top_y + PADDING], + position: [margin.x + border_width, margin.top_y - border_width], })); if let Some(right_item) = item.right { let new_margin = Delta { - x: margin.x + item.val.dimension.width, - top_y: 20., - bottom_y: 20., + x: margin.x + + PADDING + + (item.width / item.val.dimension.dimension.scale), + top_y: margin.top_y, + bottom_y: margin.bottom_y, }; self.plot_objects(objects, right_item, new_margin); } @@ -163,20 +215,56 @@ impl ContextGrid { }; } + pub fn remove_current_grid(&mut self) {} + pub fn split_right(&mut self, context: Context) { - let old_grid_item_width = self.inner[self.current].val.dimension.width; - let new_grid_item_width = old_grid_item_width / 2.0; + // If we are moving from first to second context, needs to change height + let should_change_height = self.inner.len() == 1; + + if should_change_height { + self.inner[self.current].height -= self.margin.top_y + * self.inner[self.current].val.dimension.dimension.scale; + // self.inner[self.current].val.dimension.height -= PADDING * 2.0; + } + + let old_grid_item_width = self.inner[self.current].width; + let new_grid_item_width = (old_grid_item_width / 2.0) - PADDING; // Change grid item by half self.inner[self.current].width = new_grid_item_width; // Move content to middle - self.inner[self.current].val.dimension.width = new_grid_item_width - (PADDING * 2.0); + self.inner[self.current] + .val + .dimension + .update_width(new_grid_item_width - (PADDING * 2.0)); + + let mut terminal = self.inner[self.current].val.terminal.lock(); + terminal.resize::(self.inner[self.current].val.dimension); + drop(terminal); + let winsize = crate::renderer::utils::terminal_dimensions( + &self.inner[self.current].val.dimension, + ); + let _ = self.inner[self.current].val.messenger.send_resize(winsize); let mut new_context = ContextGridItem::new(context); new_context.width = new_grid_item_width; - new_context.val.dimension.width = new_grid_item_width - (PADDING * 2.0); + new_context.height = self.inner[self.current].height; + + new_context + .val + .dimension + .update_width(new_grid_item_width - (PADDING * 2.0)); self.inner.push(new_context); let new_current = self.inner.len() - 1; + + let mut terminal = self.inner[new_current].val.terminal.lock(); + terminal.resize::(self.inner[new_current].val.dimension); + drop(terminal); + let winsize = crate::renderer::utils::terminal_dimensions( + &self.inner[new_current].val.dimension, + ); + let _ = self.inner[new_current].val.messenger.send_resize(winsize); + self.inner[self.current].right = Some(new_current); self.current = new_current; } @@ -213,6 +301,14 @@ impl ContextDimension { } } + pub fn update_width(&mut self, width: f32) { + self.width = width; + let (columns, lines) = + compute(self.width, self.height, self.dimension, 1.0, self.margin); + self.columns = columns; + self.lines = lines; + } + #[inline] pub fn update(&mut self) { let (columns, lines) = compute( @@ -254,10 +350,6 @@ impl Dimensions for ContextDimension { } } -// TODO: ContextGridItem should contain quad? -// - Qual a regra do quad? -// TODO: Split right - #[cfg(test)] pub mod test { use super::*; @@ -282,7 +374,7 @@ pub mod test { height: 9., }, 1.0, - Delta::::default() + Delta::::default(), ); assert_eq!(context_dimension.columns, 66); @@ -299,7 +391,11 @@ pub mod test { let context_width = context.dimension.width; let context_height = context.dimension.height; let context_margin = context.dimension.margin; - let grid = ContextGrid::::new(context, margin); + let grid = ContextGrid::::new( + context, + margin, + ([0., 0., 0., 0.], [0., 0., 0., 0.]), + ); // The first context should fill completely w/h grid assert_eq!(grid.width, context_width); assert_eq!(grid.height, context_height); @@ -338,7 +434,7 @@ pub mod test { height: 8., }, 1.0, - Delta::::default() + Delta::::default(), ); assert_eq!(context_dimension.columns, 85); @@ -355,7 +451,7 @@ pub mod test { rich_text_id, context_dimension, ), - rich_text_id + rich_text_id, ) }; @@ -370,11 +466,15 @@ pub mod test { rich_text_id, context_dimension, ), - rich_text_id + rich_text_id, ) }; - let mut grid = ContextGrid::::new(first_context, margin); + let mut grid = ContextGrid::::new( + first_context, + margin, + ([0., 0., 0., 0.], [0., 0., 0., 0.]), + ); assert_eq!( grid.objects(), diff --git a/frontends/rioterm/src/context/mod.rs b/frontends/rioterm/src/context/mod.rs index 06696f78..ed4d49ea 100644 --- a/frontends/rioterm/src/context/mod.rs +++ b/frontends/rioterm/src/context/mod.rs @@ -50,6 +50,22 @@ impl Drop for Context { } } +impl Context { + #[inline] + pub fn renderable_content(&mut self) -> &RenderableContent { + let terminal = self.terminal.lock(); + self.renderable_content.update( + terminal.visible_rows(), + terminal.display_offset(), + terminal.cursor(), + terminal.blinking_cursor, + ); + drop(terminal); + + &self.renderable_content + } +} + #[derive(Clone, Default)] pub struct ContextManagerConfig { pub shell: Shell, @@ -60,6 +76,7 @@ pub struct ContextManagerConfig { pub use_current_path: bool, pub is_native: bool, pub should_update_titles: bool, + pub split_colors: ([f32; 4], [f32; 4]), } pub struct ContextManagerTitles { @@ -324,7 +341,11 @@ impl ContextManager { current_index: 0, current_route: 0, acc_current_route: 0, - contexts: vec![ContextGrid::new(initial_context, margin)], + contexts: vec![ContextGrid::new( + initial_context, + margin, + ctx_config.split_colors, + )], capacity: DEFAULT_CONTEXT_CAPACITY, event_proxy, window_id, @@ -351,6 +372,7 @@ impl ContextManager { is_native: false, should_update_titles: false, use_current_path: false, + split_colors: ([0., 0., 0., 0.], [0., 0., 0., 0.]), }; let initial_context = ContextManager::create_context( (&CursorState::new('_'), false), @@ -369,7 +391,11 @@ impl ContextManager { current_index: 0, current_route: 0, acc_current_route: 0, - contexts: vec![ContextGrid::new(initial_context, Delta::::default())], + contexts: vec![ContextGrid::new( + initial_context, + Delta::::default(), + config.split_colors, + )], capacity, event_proxy, window_id, @@ -615,11 +641,26 @@ impl ContextManager { &self.contexts } + #[inline] + pub fn current_grid_len(&self) -> usize { + self.contexts.len() + } + + #[inline] + pub fn remove_current_grid(&self) { + self.contexts.remove_current_grid(); + } + #[inline] pub fn current_grid_mut(&mut self) -> &mut ContextGrid { &mut self.contexts[self.current_index] } + #[inline] + pub fn current_grid(&mut self) -> &ContextGrid { + &self.contexts[self.current_index] + } + #[cfg(test)] pub fn increase_capacity(&mut self, inc_val: usize) { self.capacity += inc_val; @@ -633,21 +674,6 @@ impl ContextManager { } } - #[inline] - pub fn renderable_content(&mut self) -> &RenderableContent { - let current = self.current_mut(); - let terminal = current.terminal.lock(); - current.renderable_content.update( - terminal.visible_rows(), - terminal.display_offset(), - terminal.cursor(), - terminal.blinking_cursor, - ); - drop(terminal); - - ¤t.renderable_content - } - #[inline] pub fn close_current_context(&mut self) { if self.contexts.len() == 1 { @@ -731,7 +757,11 @@ impl ContextManager { self.current_route = self.current().route_id; } - pub fn split_right(&mut self, cursor_state: (&CursorState, bool)) { + pub fn split_right( + &mut self, + rich_text_id: usize, + cursor_state: (&CursorState, bool), + ) { let mut working_dir = None; if self.config.use_current_path && self.config.working_dir.is_none() { #[cfg(not(target_os = "windows"))] @@ -764,8 +794,8 @@ impl ContextManager { cursor_state, self.event_proxy.clone(), self.window_id, - 0, self.acc_current_route, + rich_text_id, self.current().dimension, &cloned_config, ) { @@ -779,7 +809,12 @@ impl ContextManager { } #[inline] - pub fn add_context(&mut self, redirect: bool, cursor_state: (&CursorState, bool)) { + pub fn add_context( + &mut self, + redirect: bool, + rich_text_id: usize, + cursor_state: (&CursorState, bool), + ) { let mut working_dir = None; if self.config.use_current_path && self.config.working_dir.is_none() { #[cfg(not(target_os = "windows"))] @@ -823,15 +858,18 @@ impl ContextManager { cursor_state, self.event_proxy.clone(), self.window_id, - 0, self.acc_current_route, + rich_text_id, self.current().dimension, &cloned_config, ) { Ok(new_context) => { let previous_margin = self.contexts[self.current_index].margin; - self.contexts - .push(ContextGrid::new(new_context, previous_margin)); + self.contexts.push(ContextGrid::new( + new_context, + previous_margin, + self.config.split_colors, + )); if redirect { self.current_index = last_index; self.current_route = self.current().route_id; @@ -904,12 +942,12 @@ pub mod test { assert_eq!(context_manager.current_index, 0); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.capacity, 5); assert_eq!(context_manager.current_index, 0); let should_redirect = true; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.capacity, 5); assert_eq!(context_manager.current_index, 2); } @@ -923,13 +961,17 @@ pub mod test { assert_eq!(context_manager.capacity, 3); assert_eq!(context_manager.current_index, 0); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.len(), 2); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.len(), 3); for _ in 0..20 { - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context( + should_redirect, + 0, + (&CursorState::new('_'), false), + ); } assert_eq!(context_manager.len(), 3); @@ -944,7 +986,7 @@ pub mod test { ContextManager::start_with_capacity(8, VoidListener {}, window_id).unwrap(); let should_redirect = true; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.current_index, 1); context_manager.set_current(0); assert_eq!(context_manager.current_index, 0); @@ -952,8 +994,8 @@ pub mod test { assert_eq!(context_manager.capacity, 8); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); context_manager.set_current(3); assert_eq!(context_manager.current_index, 3); @@ -969,8 +1011,8 @@ pub mod test { ContextManager::start_with_capacity(3, VoidListener {}, window_id).unwrap(); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.len(), 3); assert_eq!(context_manager.current_index, 0); @@ -992,10 +1034,10 @@ pub mod test { ContextManager::start_with_capacity(5, VoidListener {}, window_id).unwrap(); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); context_manager.close_current_context(); context_manager.close_current_context(); @@ -1005,7 +1047,7 @@ pub mod test { assert_eq!(context_manager.len(), 1); assert_eq!(context_manager.current_index, 0); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.len(), 2); context_manager.set_current(1); @@ -1023,8 +1065,8 @@ pub mod test { ContextManager::start_with_capacity(2, VoidListener {}, window_id).unwrap(); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.len(), 2); assert_eq!(context_manager.current_index, 0); @@ -1044,11 +1086,11 @@ pub mod test { ContextManager::start_with_capacity(5, VoidListener {}, window_id).unwrap(); let should_redirect = false; - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); - context_manager.add_context(should_redirect, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); + context_manager.add_context(should_redirect, 0, (&CursorState::new('_'), false)); assert_eq!(context_manager.len(), 5); assert_eq!(context_manager.current_index, 0); diff --git a/frontends/rioterm/src/renderer/mod.rs b/frontends/rioterm/src/renderer/mod.rs index eea7f742..696e3637 100644 --- a/frontends/rioterm/src/renderer/mod.rs +++ b/frontends/rioterm/src/renderer/mod.rs @@ -724,80 +724,82 @@ impl Renderer { hints: &mut Option, focused_match: &Option>, ) { - let window_size = sugarloaf.window_size(); - let scale_factor = sugarloaf.scale_factor(); - let renderable_content = context_manager.renderable_content(); - self.cursor.state = renderable_content.cursor.clone(); - let mut is_cursor_visible = self.cursor.state.is_visible(); - - self.term_has_blinking_enabled = renderable_content.has_blinking_enabled; - - // Only blink cursor if does not contain selection - let has_selection = self.selection_range.is_some(); - if !has_selection && self.has_blinking_enabled() { - let mut should_blink = true; - if let Some(last_typing_time) = self.last_typing { - if last_typing_time.elapsed() < Duration::from_secs(1) { - should_blink = false; + let content = sugarloaf.content(); + + for grid_context in context_manager.current_grid_mut().contexts_mut() { + let context = grid_context.context_mut(); + let rich_text_id = context.rich_text_id; + let renderable_content = context.renderable_content(); + self.cursor.state = renderable_content.cursor.clone(); + let mut is_cursor_visible = self.cursor.state.is_visible(); + + self.term_has_blinking_enabled = renderable_content.has_blinking_enabled; + + // Only blink cursor if does not contain selection + let has_selection = self.selection_range.is_some(); + if !has_selection && self.has_blinking_enabled() { + let mut should_blink = true; + if let Some(last_typing_time) = self.last_typing { + if last_typing_time.elapsed() < Duration::from_secs(1) { + should_blink = false; + } } - } - if should_blink { - self.is_blinking = !self.is_blinking; - is_cursor_visible = self.is_blinking; + if should_blink { + self.is_blinking = !self.is_blinking; + is_cursor_visible = self.is_blinking; + } } - } + let display_offset = renderable_content.display_offset; - let content = sugarloaf.content(); - let display_offset = renderable_content.display_offset; - - // let mut render_strategy = &renderable_content.strategy; - // if has_selection { - // render_strategy = &RenderableContentStrategy::Full; - // } - - // let start = std::time::Instant::now(); - match &renderable_content.strategy { - RenderableContentStrategy::Full => { - content.sel(0); - content.clear(); - for (i, row) in renderable_content.inner.iter().enumerate() { - let has_cursor = is_cursor_visible && self.cursor.state.pos.row == i; - self.create_line( - content, - row, - has_cursor, - None, - Line((i as i32) - display_offset), - hints, - focused_match, - ); + // let mut render_strategy = &renderable_content.strategy; + // if has_selection { + // render_strategy = &RenderableContentStrategy::Full; + // } + + match &renderable_content.strategy { + RenderableContentStrategy::Full => { + content.sel(rich_text_id); + content.clear(); + for (i, row) in renderable_content.inner.iter().enumerate() { + let has_cursor = + is_cursor_visible && self.cursor.state.pos.row == i; + self.create_line( + content, + row, + has_cursor, + None, + Line((i as i32) - display_offset), + hints, + focused_match, + ); + } + content.build(); } - content.build(); - } - RenderableContentStrategy::Lines(lines) => { - content.sel(0); - for line in lines { - let line = *line; - let has_cursor = - is_cursor_visible && self.cursor.state.pos.row == line; - content.clear_line(line); - self.create_line( - content, - &renderable_content.inner[line], - has_cursor, - Some(line), - Line((line as i32) - display_offset), - hints, - focused_match, - ); + RenderableContentStrategy::Lines(lines) => { + content.sel(rich_text_id); + for line in lines { + let line = *line; + let has_cursor = + is_cursor_visible && self.cursor.state.pos.row == line; + content.clear_line(line); + self.create_line( + content, + &renderable_content.inner[line], + has_cursor, + Some(line), + Line((line as i32) - display_offset), + hints, + focused_match, + ); + } } + RenderableContentStrategy::Noop => {} } - RenderableContentStrategy::Noop => {} } - // let duration = start.elapsed(); - // println!("Total loop rows: {:?}", duration); + let window_size = sugarloaf.window_size(); + let scale_factor = sugarloaf.scale_factor(); let mut objects = Vec::with_capacity(30); self.navigation.build_objects( (window_size.width, window_size.height, scale_factor), diff --git a/frontends/rioterm/src/screen/mod.rs b/frontends/rioterm/src/screen/mod.rs index b7e942c6..5dbd2e7f 100644 --- a/frontends/rioterm/src/screen/mod.rs +++ b/frontends/rioterm/src/screen/mod.rs @@ -203,6 +203,7 @@ impl Screen<'_> { // does not make sense fetch for foreground process names should_update_titles: !(is_collapsed && config.navigation.color_automation.is_empty()), + split_colors: (config.colors.split, config.colors.split_active), }; let rich_text_id = sugarloaf.create_rich_text(); @@ -963,7 +964,9 @@ impl Screen<'_> { } pub fn split_right(&mut self) { + let rich_text_id = self.sugarloaf.create_rich_text(); self.context_manager.split_right( + rich_text_id, ( &self.renderer.get_cursor_state_from_ref(), self.renderer.config_has_blinking_enabled, @@ -976,8 +979,10 @@ impl Screen<'_> { pub fn create_tab(&mut self) { let redirect = true; + let rich_text_id = self.sugarloaf.create_rich_text(); self.context_manager.add_context( redirect, + rich_text_id, ( &self.renderer.get_cursor_state_from_ref(), self.renderer.config_has_blinking_enabled, @@ -990,6 +995,14 @@ impl Screen<'_> { self.render(); } + pub fn close_split_or_tab(&mut self) { + self.clear_selection(); + + if self.context_manager.current_grid_len() > 1 { + self.context_manager.remove_current_grid(); + } + } + pub fn close_tab(&mut self) { self.clear_selection(); self.context_manager.close_current_context(); diff --git a/rio-backend/src/config/colors/defaults.rs b/rio-backend/src/config/colors/defaults.rs index 384ae60c..18a89796 100644 --- a/rio-backend/src/config/colors/defaults.rs +++ b/rio-backend/src/config/colors/defaults.rs @@ -140,6 +140,20 @@ pub fn dim_black() -> ColorArray { .to_arr() } +#[inline] +pub fn split() -> ColorArray { + ColorBuilder::from_hex(String::from("#292527"), Format::SRGB0_1) + .unwrap() + .to_arr() +} + +#[inline] +pub fn split_active() -> ColorArray { + ColorBuilder::from_hex(String::from("#12d0ff"), Format::SRGB0_1) + .unwrap() + .to_arr() +} + #[inline] pub fn dim_blue() -> ColorArray { ColorBuilder::from_hex(String::from("#0E91B7"), Format::SRGB0_1) diff --git a/rio-backend/src/config/colors/mod.rs b/rio-backend/src/config/colors/mod.rs index 35ff4a2b..0270cc44 100644 --- a/rio-backend/src/config/colors/mod.rs +++ b/rio-backend/src/config/colors/mod.rs @@ -240,8 +240,13 @@ pub struct Colors { rename = "selection-foreground" )] pub selection_foreground: ColorArray, - #[serde(default = "defaults::cursor", deserialize_with = "deserialize_to_arr")] + #[serde(default = "defaults::split", deserialize_with = "deserialize_to_arr")] pub split: ColorArray, + #[serde( + default = "defaults::split_active", + deserialize_with = "deserialize_to_arr" + )] + pub split_active: ColorArray, #[serde( default = "defaults::search_match_background", deserialize_with = "deserialize_to_arr", @@ -284,7 +289,8 @@ impl Default for Colors { tabs_active_foreground: defaults::tabs_active_foreground(), tabs_foreground: defaults::tabs_foreground(), cursor: defaults::cursor(), - split: defaults::cursor(), + split: defaults::split(), + split_active: defaults::split_active(), vi_cursor: defaults::vi_cursor(), black: defaults::black(), cyan: defaults::cyan(), diff --git a/rio-backend/src/config/split.rs b/rio-backend/src/config/split.rs index 6cb8c890..8c26941c 100644 --- a/rio-backend/src/config/split.rs +++ b/rio-backend/src/config/split.rs @@ -1,8 +1,15 @@ use crate::config::default_bool_true; use serde::{Deserialize, Serialize}; -#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone, Copy)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone, Copy)] pub struct Split { #[serde(default = "default_bool_true")] pub enable: bool, } + +#[allow(clippy::derivable_impls)] +impl Default for Split { + fn default() -> Split { + Split { enable: true } + } +} diff --git a/rio-window/src/event.rs b/rio-window/src/event.rs index 776648f9..3bac43bd 100644 --- a/rio-window/src/event.rs +++ b/rio-window/src/event.rs @@ -140,7 +140,7 @@ impl Event { #[derive(Debug, Clone, PartialEq)] pub enum Hook { CreateTab, - CloseTab, + Close, Copy, Paste, SplitDown, diff --git a/rio-window/src/platform_impl/macos/app_delegate.rs b/rio-window/src/platform_impl/macos/app_delegate.rs index cf4df07b..ea59eebb 100644 --- a/rio-window/src/platform_impl/macos/app_delegate.rs +++ b/rio-window/src/platform_impl/macos/app_delegate.rs @@ -195,10 +195,10 @@ declare_class!( } } - #[method(rioCloseTab:)] + #[method(rioClose:)] fn close_tab(&self, _sender: Option<&AnyObject>) { if self.is_launched() { - self.dispatch_hook(Hook::CloseTab); + self.dispatch_hook(Hook::Close); } } diff --git a/rio-window/src/platform_impl/macos/menu.rs b/rio-window/src/platform_impl/macos/menu.rs index cc68b848..c399c05a 100644 --- a/rio-window/src/platform_impl/macos/menu.rs +++ b/rio-window/src/platform_impl/macos/menu.rs @@ -132,11 +132,11 @@ pub fn initialize(app: &NSApplication) { }), ); - let close_tab_item_title = ns_string!("Close Tab"); - let close_tab_item = menu_item( + let close_item_title = ns_string!("Close"); + let close_item = menu_item( mtm, - close_tab_item_title, - Some(sel!(rioCloseTab:)), + close_item_title, + Some(sel!(rioClose:)), Some(KeyEquivalent { key: ns_string!("w"), masks: Some(NSEventModifierFlags::NSEventModifierFlagCommand), @@ -207,7 +207,7 @@ pub fn initialize(app: &NSApplication) { app_menu_item.setSubmenu(Some(&app_menu)); shell_menu.addItem(&create_window_item); shell_menu.addItem(&create_tab_item); - shell_menu.addItem(&close_tab_item); + shell_menu.addItem(&close_item); shell_menu.addItem(&create_split_horizontally_item); shell_menu.addItem(&create_split_vertical_item); shell_menu_item.setSubmenu(Some(&shell_menu)); -- 2.51.2