From c0407a706380fa68a9081892aea070cbcb845a20 Mon Sep 17 00:00:00 2001 From: "lincoln auster [they/them]" Date: Fri, 22 Oct 2021 23:12:13 -0600 Subject: [PATCH 1/6] extract `title` in current_buffer_status_line_data This will make following changes (adding a position indicator) moderately simpler. --- src/presenters/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/presenters/mod.rs b/src/presenters/mod.rs index f50949af..a8ef35aa 100644 --- a/src/presenters/mod.rs +++ b/src/presenters/mod.rs @@ -14,15 +14,12 @@ fn current_buffer_status_line_data(workspace: &mut Workspace) -> StatusLineData let modified = workspace.current_buffer().map(|b| b.modified()).unwrap_or(false); let (content, style) = workspace.current_buffer_path().map(|path| { - // Determine buffer title styles based on its modification status. + let mut title = path_as_title(path); if modified { - // Use an emboldened path with an asterisk. - let mut title = path_as_title(path); title.push('*'); - (title, Style::Bold) } else { - (path_as_title(path), Style::Default) + (title, Style::Default) } }).unwrap_or((String::new(), Style::Default)); From 3cba012cff857eeb537827aa0b267bd15309cdbd Mon Sep 17 00:00:00 2001 From: "lincoln auster [they/them]" Date: Fri, 22 Oct 2021 23:29:00 -0600 Subject: [PATCH 2/6] display the percentage through the file that the cursor is at A modeline may look like, for instance: NORMAL [17%] src/presenters/mod.rs as opposed to the previous: NORMAL src/presenters/mod.rs This is a small & slightly opinionated change. --- src/presenters/mod.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/presenters/mod.rs b/src/presenters/mod.rs index a8ef35aa..452aac34 100644 --- a/src/presenters/mod.rs +++ b/src/presenters/mod.rs @@ -11,16 +11,26 @@ fn path_as_title(path: &Path) -> String { } fn current_buffer_status_line_data(workspace: &mut Workspace) -> StatusLineData { - let modified = workspace.current_buffer().map(|b| b.modified()).unwrap_or(false); + let buffer = workspace.current_buffer(); + let modified = buffer.as_ref().map(|b| b.modified()).unwrap_or(false); + + let line_perc = buffer.map(|b| { + let line_total = b.line_count(); + let line_at = b.cursor.position.line + 1; + let line_perc = (line_at * 100) / line_total; + format!("[{:2}%]", line_perc) + }).unwrap_or(String::new()); let (content, style) = workspace.current_buffer_path().map(|path| { let mut title = path_as_title(path); + let mut style = Style::Default; + if modified { title.push('*'); - (title, Style::Bold) - } else { - (title, Style::Default) + style = Style::Bold; } + + (format!(" {}{}", line_perc, title), style) }).unwrap_or((String::new(), Style::Default)); StatusLineData { From 7607292238ecf77b81b059f1e3adbe31f3cc963b Mon Sep 17 00:00:00 2001 From: "lincoln auster [they/them]" Date: Sun, 23 Jan 2022 12:06:52 -0700 Subject: [PATCH 3/6] present statusline by left/right elements The previous logic to display the statusline did so by right aligning only the last element. This isn't sufficient if more than one element is to appear on the right (e.g., a cursor position indicator). So, this commit replaces the logic to first render the right elements as compactly as possible, then render the first left elements as compactly as possible, but expand out the last left element to fill the remaining space. Behavior is identical; this is purely an API change. --- src/presenters/error.rs | 15 ++++-- src/presenters/modes/confirm.rs | 17 +++--- src/presenters/modes/insert.rs | 19 ++++--- src/presenters/modes/jump.rs | 19 ++++--- src/presenters/modes/line_jump.rs | 17 +++--- src/presenters/modes/normal.rs | 22 ++++---- src/presenters/modes/path.rs | 27 +++++----- src/presenters/modes/search.rs | 38 ++++++++------ src/presenters/modes/search_select.rs | 19 ++++--- src/presenters/modes/select.rs | 19 ++++--- src/presenters/modes/select_line.rs | 19 ++++--- src/view/presenter.rs | 76 +++++++++++++-------------- 12 files changed, 172 insertions(+), 135 deletions(-) diff --git a/src/presenters/error.rs b/src/presenters/error.rs index 163c9031..c46a0052 100644 --- a/src/presenters/error.rs +++ b/src/presenters/error.rs @@ -11,11 +11,16 @@ pub fn display(workspace: &mut Workspace, view: &mut View, error: &Error) { let _ = presenter.print_buffer(buffer, &data, None, None); } - presenter.print_status_line(&[StatusLineData { - content: error.description().to_string(), - style: Style::Bold, - colors: Colors::Warning, - }]); + presenter.print_status_line( + &[ + StatusLineData { + content: error.description().to_string(), + style: Style::Bold, + colors: Colors::Warning, + } + ], + &[], + ); presenter.present(); } diff --git a/src/presenters/modes/confirm.rs b/src/presenters/modes/confirm.rs index 41eb1744..d1162b30 100644 --- a/src/presenters/modes/confirm.rs +++ b/src/presenters/modes/confirm.rs @@ -12,13 +12,16 @@ pub fn display(workspace: &mut Workspace, view: &mut View) -> Result<()> { // Draw the status line as a search prompt. let confirmation = "Are you sure? (y/n)".to_string(); - presenter.print_status_line(&[ - StatusLineData { - content: confirmation, - style: Style::Bold, - colors: Colors::Warning, - } - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: confirmation, + style: Style::Bold, + colors: Colors::Warning, + } + ], + &[], + ); // Render the changes to the screen. presenter.present(); diff --git a/src/presenters/modes/insert.rs b/src/presenters/modes/insert.rs index 4a8b32da..26e6a1c6 100644 --- a/src/presenters/modes/insert.rs +++ b/src/presenters/modes/insert.rs @@ -12,14 +12,17 @@ pub fn display(workspace: &mut Workspace, view: &mut View) -> Result<()> { // Draw the visible set of tokens to the terminal. presenter.print_buffer(buf, &data, None, None)?; - presenter.print_status_line(&[ - StatusLineData { - content: " INSERT ".to_string(), - style: Style::Default, - colors: Colors::Insert, - }, - buffer_status - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: " INSERT ".to_string(), + style: Style::Default, + colors: Colors::Insert, + }, + buffer_status + ], + &[], + ); // Render the changes to the screen. presenter.present(); diff --git a/src/presenters/modes/jump.rs b/src/presenters/modes/jump.rs index 6aef8cb6..4d6c1f3f 100644 --- a/src/presenters/modes/jump.rs +++ b/src/presenters/modes/jump.rs @@ -15,14 +15,17 @@ pub fn display(workspace: &mut Workspace, mode: &mut JumpMode, view: &mut View) // Draw the visible set of tokens to the terminal. presenter.print_buffer(buf, &data, None, Some(mode))?; - presenter.print_status_line(&[ - StatusLineData { - content: " JUMP ".to_string(), - style: Style::Default, - colors: Colors::Inverted, - }, - buffer_status - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: " JUMP ".to_string(), + style: Style::Default, + colors: Colors::Inverted, + }, + buffer_status + ], + &[], + ); // Don't display a cursor. presenter.set_cursor(None); diff --git a/src/presenters/modes/line_jump.rs b/src/presenters/modes/line_jump.rs index d715c2b3..1c189348 100644 --- a/src/presenters/modes/line_jump.rs +++ b/src/presenters/modes/line_jump.rs @@ -13,13 +13,16 @@ pub fn display(workspace: &mut Workspace, mode: &LineJumpMode, view: &mut View) // Draw the status line as an input prompt. let input_prompt = format!("Go to line: {}", mode.input); let input_prompt_len = input_prompt.len(); - presenter.print_status_line(&[ - StatusLineData { - content: input_prompt, - style: Style::Default, - colors: Colors::Default, - } - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: input_prompt, + style: Style::Default, + colors: Colors::Default, + } + ], + &[], + ); // Move the cursor to the end of the search query input. let cursor_line = presenter.height() - 1; diff --git a/src/presenters/modes/normal.rs b/src/presenters/modes/normal.rs index c8cd0b3a..46cc2fa6 100644 --- a/src/presenters/modes/normal.rs +++ b/src/presenters/modes/normal.rs @@ -22,15 +22,19 @@ pub fn display(workspace: &mut Workspace, view: &mut View, repo: &Option R mode_display.graphemes(true).count() + search_input.graphemes(true).count(); - presenter.print_status_line(&[ - StatusLineData { - content: mode_display, - style: Style::Default, - colors: Colors::PathMode, - }, - StatusLineData { - content: search_input, - style: Style::Default, - colors: Colors::Focused, - }, - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: mode_display, + style: Style::Default, + colors: Colors::PathMode, + }, + StatusLineData { + content: search_input, + style: Style::Default, + colors: Colors::Focused, + }, + ], + &[], + ); // Move the cursor to the end of the search query input. { diff --git a/src/presenters/modes/search.rs b/src/presenters/modes/search.rs index b1945f45..96586d2d 100644 --- a/src/presenters/modes/search.rs +++ b/src/presenters/modes/search.rs @@ -34,23 +34,27 @@ pub fn display(workspace: &mut Workspace, mode: &SearchMode, view: &mut View) -> mode_display.graphemes(true).count() + search_input.graphemes(true).count(); - presenter.print_status_line(&[ - StatusLineData { - content: mode_display, - style: Style::Default, - colors: Colors::SearchMode, - }, - StatusLineData { - content: search_input, - style: Style::Default, - colors: Colors::Focused, - }, - StatusLineData { - content: result_display, - style: Style::Default, - colors: Colors::Focused, - }, - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: mode_display, + style: Style::Default, + colors: Colors::SearchMode, + }, + StatusLineData { + content: search_input, + style: Style::Default, + colors: Colors::Focused, + }, + ], + &[ + StatusLineData { + content: result_display, + style: Style::Default, + colors: Colors::Focused, + }, + ], + ); // Move the cursor to the end of the search query input. if mode.insert { diff --git a/src/presenters/modes/search_select.rs b/src/presenters/modes/search_select.rs index ea3ae8d3..5f7b30f4 100644 --- a/src/presenters/modes/search_select.rs +++ b/src/presenters/modes/search_select.rs @@ -22,14 +22,17 @@ pub fn display(workspace: &mut Workspace, mode: &mut dyn SearchSelec data = buf.data(); presenter.print_buffer(buf, &data, None, None)?; - presenter.print_status_line(&[ - StatusLineData { - content: format!(" {} ", mode), - style: Style::Default, - colors: Colors::Inverted, - }, - buffer_status - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: format!(" {} ", mode), + style: Style::Default, + colors: Colors::Inverted, + }, + buffer_status + ], + &[], + ); } if let Some(message) = mode.message() { diff --git a/src/presenters/modes/select.rs b/src/presenters/modes/select.rs index ba9e1a2d..96c837c7 100644 --- a/src/presenters/modes/select.rs +++ b/src/presenters/modes/select.rs @@ -15,14 +15,17 @@ pub fn display(workspace: &mut Workspace, mode: &SelectMode, view: &mut View) -> // Draw the visible set of tokens to the terminal. presenter.print_buffer(buf, &data, Some(&[selected_range]), None)?; - presenter.print_status_line(&[ - StatusLineData { - content: " SELECT ".to_string(), - style: Style::Default, - colors: Colors::SelectMode, - }, - buffer_status - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: " SELECT ".to_string(), + style: Style::Default, + colors: Colors::SelectMode, + }, + buffer_status + ], + &[], + ); // Render the changes to the screen. presenter.present(); diff --git a/src/presenters/modes/select_line.rs b/src/presenters/modes/select_line.rs index 691955dd..057fc52c 100644 --- a/src/presenters/modes/select_line.rs +++ b/src/presenters/modes/select_line.rs @@ -14,14 +14,17 @@ pub fn display(workspace: &mut Workspace, mode: &SelectLineMode, view: &mut View // Draw the visible set of tokens to the terminal. presenter.print_buffer(buf, &data, Some(&[selected_range]), None)?; - presenter.print_status_line(&[ - StatusLineData { - content: " SELECT LINE ".to_string(), - style: Style::Default, - colors: Colors::SelectMode, - }, - buffer_status - ]); + presenter.print_status_line( + &[ + StatusLineData { + content: " SELECT LINE ".to_string(), + style: Style::Default, + colors: Colors::SelectMode, + }, + buffer_status + ], + &[], + ); // Render the changes to the screen. presenter.present(); diff --git a/src/view/presenter.rs b/src/view/presenter.rs index 8a726b86..30f161dc 100644 --- a/src/view/presenter.rs +++ b/src/view/presenter.rs @@ -86,49 +86,49 @@ impl<'p> Presenter<'p> { Ok(()) } - pub fn print_status_line(&mut self, entries: &[StatusLineData]) { + pub fn print_status_line( + &mut self, left: &[StatusLineData], right: &[StatusLineData] + ) { let line = self.view.terminal.height() - 1; - entries.iter().enumerate().fold(0, |offset, (index, element)| { - let content = match entries.len() { - // There's only one element; have it fill the line. - 1 => format!( - "{:width$}", - element.content, - width = self.view.terminal.width(), - ), - - // Expand the last element to fill the remaining width. - 2 if index == entries.len() - 1 => format!( - "{:width$}", - element.content, - width = self.view.terminal.width().saturating_sub(offset), - ), - 2 => element.content.clone(), - - _ if index == entries.len() - 2 => { - let space = offset + entries[index+1].content.len(); - format!( - "{:width$}", - element.content, - width = self.view.terminal.width().saturating_sub(space), - ) - }, - _ => element.content.clone(), - }; - - // Update the tracked offset. - let updated_offset = offset + content.len(); - + let mut left_end = self.view.terminal.width(); + for entry in right.iter().rev() { + left_end = left_end.saturating_sub(entry.content.len()); self.print( - &Position{ line, offset }, - element.style, - element.colors, - content + &Position { line, offset: left_end }, + entry.style, + entry.colors, + entry.content.clone(), ); + } - updated_offset - }); + let mut left_start = 0; + + for (i, entry) in left.iter().enumerate() { + if i == left.len() - 1 { + // The last element should fill the remaining the width. + let len = left_end.saturating_sub(left_start); + self.print( + &Position { line, offset: left_start }, + entry.style, + entry.colors, + format!( + "{:width$}", + entry.content.clone(), + width = len, + ), + ); + } else { + self.print( + &Position { line, offset: left_start }, + entry.style, + entry.colors, + entry.content.clone(), + ); + + left_start += entry.content.len(); + } + } } pub fn print(&mut self, position: &Position, style: Style, colors: Colors, content: C) From d6302d95ec20535d095a17430352256333a2e208 Mon Sep 17 00:00:00 2001 From: "lincoln auster [they/them]" Date: Sun, 23 Jan 2022 12:16:23 -0700 Subject: [PATCH 4/6] display precentage through file on the right This only applies to normal mode, and is a straightforward extension of ff0dc68's modifications. --- src/presenters/mod.rs | 25 +++++++++++++++++-------- src/presenters/modes/normal.rs | 7 ++++++- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/presenters/mod.rs b/src/presenters/mod.rs index 452aac34..eb1afd98 100644 --- a/src/presenters/mod.rs +++ b/src/presenters/mod.rs @@ -14,13 +14,6 @@ fn current_buffer_status_line_data(workspace: &mut Workspace) -> StatusLineData let buffer = workspace.current_buffer(); let modified = buffer.as_ref().map(|b| b.modified()).unwrap_or(false); - let line_perc = buffer.map(|b| { - let line_total = b.line_count(); - let line_at = b.cursor.position.line + 1; - let line_perc = (line_at * 100) / line_total; - format!("[{:2}%]", line_perc) - }).unwrap_or(String::new()); - let (content, style) = workspace.current_buffer_path().map(|path| { let mut title = path_as_title(path); let mut style = Style::Default; @@ -30,7 +23,7 @@ fn current_buffer_status_line_data(workspace: &mut Workspace) -> StatusLineData style = Style::Bold; } - (format!(" {}{}", line_perc, title), style) + (format!(" {}", title), style) }).unwrap_or((String::new(), Style::Default)); StatusLineData { @@ -40,6 +33,21 @@ fn current_buffer_status_line_data(workspace: &mut Workspace) -> StatusLineData } } +fn percentage_cursor_indicator_line_data(workspace: &mut Workspace) -> StatusLineData { + let content = workspace.current_buffer().map(|b| { + let line_total = b.line_count(); + let line_at = b.cursor.position.line + 1; + let line_perc = (line_at * 100) / line_total; + format!(" [{:2}%]", line_perc) + }).unwrap_or(String::new()); + + StatusLineData { + content, + style: Style::Default, + colors: Colors::Default, + } +} + fn git_status_line_data(repo: &Option, path: &Option) -> StatusLineData { // Build a display value for the current buffer's git status. let mut content = String::new(); @@ -61,6 +69,7 @@ fn git_status_line_data(repo: &Option, path: &Option) -> St colors: Colors::Focused, } } + fn presentable_status(status: &Status) -> &str { if status.contains(git2::Status::WT_NEW) { if status.contains(git2::Status::INDEX_NEW) { diff --git a/src/presenters/modes/normal.rs b/src/presenters/modes/normal.rs index 46cc2fa6..14927e7f 100644 --- a/src/presenters/modes/normal.rs +++ b/src/presenters/modes/normal.rs @@ -1,7 +1,11 @@ use crate::errors::*; use scribe::Workspace; use scribe::buffer::Position; -use crate::presenters::{current_buffer_status_line_data, git_status_line_data}; +use crate::presenters::{ + current_buffer_status_line_data, + git_status_line_data, + percentage_cursor_indicator_line_data +}; use git2::Repository; use crate::view::{Colors, StatusLineData, Style, View}; @@ -33,6 +37,7 @@ pub fn display(workspace: &mut Workspace, view: &mut View, repo: &Option Date: Sun, 23 Jan 2022 12:31:06 -0700 Subject: [PATCH 5/6] only show cursor percentage indicator when file is larger than height This modifies the display function in normal mode without changing the logic to gather the percentage, and should make the statusline a bit cleaner on small files. --- src/presenters/modes/normal.rs | 17 +++++++++++++---- src/view/mod.rs | 4 ++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/presenters/modes/normal.rs b/src/presenters/modes/normal.rs index 14927e7f..27448f0e 100644 --- a/src/presenters/modes/normal.rs +++ b/src/presenters/modes/normal.rs @@ -10,10 +10,13 @@ use git2::Repository; use crate::view::{Colors, StatusLineData, Style, View}; pub fn display(workspace: &mut Workspace, view: &mut View, repo: &Option) -> Result<()> { + let height = view.height(); let mut presenter = view.build_presenter()?; let buffer_status = current_buffer_status_line_data(workspace); if let Some(buf) = workspace.current_buffer() { + let line_count = buf.line_count(); + // Draw the visible set of tokens to the terminal. let data = buf.data(); presenter.print_buffer(buf, &data, None, None)?; @@ -25,6 +28,15 @@ pub fn display(workspace: &mut Workspace, view: &mut View, repo: &Option usize { + self.terminal.height() + } + /// /// Scrollable region delegation methods. /// From d34a2bd2e9a5d6b5f973221dd29c6699c2c80a09 Mon Sep 17 00:00:00 2001 From: "lincoln auster [they/them]" Date: Mon, 24 Jan 2022 21:32:56 -0700 Subject: [PATCH 6/6] use same colors throughout statusline The percentage indicator previously used the default colors, which was in contrast to the rest of the statusline, which used focused. --- src/presenters/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/presenters/mod.rs b/src/presenters/mod.rs index eb1afd98..bfa39034 100644 --- a/src/presenters/mod.rs +++ b/src/presenters/mod.rs @@ -44,7 +44,7 @@ fn percentage_cursor_indicator_line_data(workspace: &mut Workspace) -> StatusLin StatusLineData { content, style: Style::Default, - colors: Colors::Default, + colors: Colors::Focused, } }