From 5c7db7aed54f52b3af6102517f81c9d70bb6d1fb Mon Sep 17 00:00:00 2001
From: Gokul Soumya <gokulps15@gmail.com>
Date: Sun, 25 Dec 2022 11:24:09 +0530
Subject: [PATCH] Replace menu::Item::{row, label} with format()

---
 helix-term/src/commands.rs      | 10 +++++-----
 helix-term/src/commands/dap.rs  |  8 ++++----
 helix-term/src/commands/lsp.rs  | 16 ++++++++++------
 helix-term/src/ui/completion.rs |  7 +------
 helix-term/src/ui/menu.rs       | 22 ++++++++++------------
 helix-term/src/ui/picker.rs     |  6 +++---
 helix-tui/src/widgets/table.rs  |  6 ++++++
 7 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs
index 15e4b47b..5b3ce68e 100644
--- a/helix-term/src/commands.rs
+++ b/helix-term/src/commands.rs
@@ -5,7 +5,7 @@ pub(crate) mod typed;
 pub use dap::*;
 use helix_vcs::Hunk;
 pub use lsp::*;
-use tui::text::Spans;
+use tui::widgets::Row;
 pub use typed::*;
 
 use helix_core::{
@@ -1864,7 +1864,7 @@ fn global_search(cx: &mut Context) {
     impl ui::menu::Item for FileResult {
         type Data = Option<PathBuf>;
 
-        fn label(&self, current_path: &Self::Data) -> Spans {
+        fn format(&self, current_path: &Self::Data) -> Row {
             let relative_path = helix_core::path::get_relative_path(&self.path)
                 .to_string_lossy()
                 .into_owned();
@@ -2312,7 +2312,7 @@ fn buffer_picker(cx: &mut Context) {
     impl ui::menu::Item for BufferMeta {
         type Data = ();
 
-        fn label(&self, _data: &Self::Data) -> Spans {
+        fn format(&self, _data: &Self::Data) -> Row {
             let path = self
                 .path
                 .as_deref()
@@ -2381,7 +2381,7 @@ fn jumplist_picker(cx: &mut Context) {
     impl ui::menu::Item for JumpMeta {
         type Data = ();
 
-        fn label(&self, _data: &Self::Data) -> Spans {
+        fn format(&self, _data: &Self::Data) -> Row {
             let path = self
                 .path
                 .as_deref()
@@ -2454,7 +2454,7 @@ fn jumplist_picker(cx: &mut Context) {
 impl ui::menu::Item for MappableCommand {
     type Data = ReverseKeymap;
 
-    fn label(&self, keymap: &Self::Data) -> Spans {
+    fn format(&self, keymap: &Self::Data) -> Row {
         let fmt_binding = |bindings: &Vec<Vec<KeyEvent>>| -> String {
             bindings.iter().fold(String::new(), |mut acc, bind| {
                 if !acc.is_empty() {
diff --git a/helix-term/src/commands/dap.rs b/helix-term/src/commands/dap.rs
index b182f28c..b3166e39 100644
--- a/helix-term/src/commands/dap.rs
+++ b/helix-term/src/commands/dap.rs
@@ -12,7 +12,7 @@ use helix_view::editor::Breakpoint;
 
 use serde_json::{to_value, Value};
 use tokio_stream::wrappers::UnboundedReceiverStream;
-use tui::text::Spans;
+use tui::{text::Spans, widgets::Row};
 
 use std::collections::HashMap;
 use std::future::Future;
@@ -25,7 +25,7 @@ use helix_view::handlers::dap::{breakpoints_changed, jump_to_stack_frame, select
 impl ui::menu::Item for StackFrame {
     type Data = ();
 
-    fn label(&self, _data: &Self::Data) -> Spans {
+    fn format(&self, _data: &Self::Data) -> Row {
         self.name.as_str().into() // TODO: include thread_states in the label
     }
 }
@@ -33,7 +33,7 @@ impl ui::menu::Item for StackFrame {
 impl ui::menu::Item for DebugTemplate {
     type Data = ();
 
-    fn label(&self, _data: &Self::Data) -> Spans {
+    fn format(&self, _data: &Self::Data) -> Row {
         self.name.as_str().into()
     }
 }
@@ -41,7 +41,7 @@ impl ui::menu::Item for DebugTemplate {
 impl ui::menu::Item for Thread {
     type Data = ThreadStates;
 
-    fn label(&self, thread_states: &Self::Data) -> Spans {
+    fn format(&self, thread_states: &Self::Data) -> Row {
         format!(
             "{} ({})",
             self.name,
diff --git a/helix-term/src/commands/lsp.rs b/helix-term/src/commands/lsp.rs
index 86b0c5fa..90b6d76c 100644
--- a/helix-term/src/commands/lsp.rs
+++ b/helix-term/src/commands/lsp.rs
@@ -5,7 +5,10 @@ use helix_lsp::{
     util::{diagnostic_to_lsp_diagnostic, lsp_pos_to_pos, lsp_range_to_range, range_to_lsp_range},
     OffsetEncoding,
 };
-use tui::text::{Span, Spans};
+use tui::{
+    text::{Span, Spans},
+    widgets::Row,
+};
 
 use super::{align_view, push_jump, Align, Context, Editor, Open};
 
@@ -46,7 +49,7 @@ impl ui::menu::Item for lsp::Location {
     /// Current working directory.
     type Data = PathBuf;
 
-    fn label(&self, cwdir: &Self::Data) -> Spans {
+    fn format(&self, cwdir: &Self::Data) -> Row {
         // The preallocation here will overallocate a few characters since it will account for the
         // URL's scheme, which is not used most of the time since that scheme will be "file://".
         // Those extra chars will be used to avoid allocating when writing the line number (in the
@@ -80,7 +83,7 @@ impl ui::menu::Item for lsp::SymbolInformation {
     /// Path to currently focussed document
     type Data = Option<lsp::Url>;
 
-    fn label(&self, current_doc_path: &Self::Data) -> Spans {
+    fn format(&self, current_doc_path: &Self::Data) -> Row {
         if current_doc_path.as_ref() == Some(&self.location.uri) {
             self.name.as_str().into()
         } else {
@@ -110,7 +113,7 @@ struct PickerDiagnostic {
 impl ui::menu::Item for PickerDiagnostic {
     type Data = (DiagnosticStyles, DiagnosticsFormat);
 
-    fn label(&self, (styles, format): &Self::Data) -> Spans {
+    fn format(&self, (styles, format): &Self::Data) -> Row {
         let mut style = self
             .diag
             .severity
@@ -149,6 +152,7 @@ impl ui::menu::Item for PickerDiagnostic {
             Span::styled(&self.diag.message, style),
             Span::styled(code, style),
         ])
+        .into()
     }
 }
 
@@ -467,7 +471,7 @@ pub fn workspace_diagnostics_picker(cx: &mut Context) {
 
 impl ui::menu::Item for lsp::CodeActionOrCommand {
     type Data = ();
-    fn label(&self, _data: &Self::Data) -> Spans {
+    fn format(&self, _data: &Self::Data) -> Row {
         match self {
             lsp::CodeActionOrCommand::CodeAction(action) => action.title.as_str().into(),
             lsp::CodeActionOrCommand::Command(command) => command.title.as_str().into(),
@@ -662,7 +666,7 @@ pub fn code_action(cx: &mut Context) {
 
 impl ui::menu::Item for lsp::Command {
     type Data = ();
-    fn label(&self, _data: &Self::Data) -> Spans {
+    fn format(&self, _data: &Self::Data) -> Row {
         self.title.as_str().into()
     }
 }
diff --git a/helix-term/src/ui/completion.rs b/helix-term/src/ui/completion.rs
index 11d7886a..824bafd8 100644
--- a/helix-term/src/ui/completion.rs
+++ b/helix-term/src/ui/completion.rs
@@ -1,7 +1,6 @@
 use crate::compositor::{Component, Context, Event, EventResult};
 use helix_view::{apply_transaction, editor::CompleteAction, ViewId};
 use tui::buffer::Buffer as Surface;
-use tui::text::Spans;
 
 use std::borrow::Cow;
 
@@ -33,11 +32,7 @@ impl menu::Item for CompletionItem {
             .into()
     }
 
-    fn label(&self, _data: &Self::Data) -> Spans {
-        self.label.as_str().into()
-    }
-
-    fn row(&self, _data: &Self::Data) -> menu::Row {
+    fn format(&self, _data: &Self::Data) -> menu::Row {
         menu::Row::new(vec![
             menu::Cell::from(self.label.as_str()),
             menu::Cell::from(match self.kind {
diff --git a/helix-term/src/ui/menu.rs b/helix-term/src/ui/menu.rs
index b9c1f9de..e92578c5 100644
--- a/helix-term/src/ui/menu.rs
+++ b/helix-term/src/ui/menu.rs
@@ -4,7 +4,7 @@ use crate::{
     compositor::{Callback, Component, Compositor, Context, Event, EventResult},
     ctrl, key, shift,
 };
-use tui::{buffer::Buffer as Surface, text::Spans, widgets::Table};
+use tui::{buffer::Buffer as Surface, widgets::Table};
 
 pub use tui::widgets::{Cell, Row};
 
@@ -18,28 +18,24 @@ pub trait Item {
     /// Additional editor state that is used for label calculation.
     type Data;
 
-    fn label(&self, data: &Self::Data) -> Spans;
+    fn format(&self, data: &Self::Data) -> Row;
 
     fn sort_text(&self, data: &Self::Data) -> Cow<str> {
-        let label: String = self.label(data).into();
+        let label: String = self.format(data).cell_text().collect();
         label.into()
     }
 
     fn filter_text(&self, data: &Self::Data) -> Cow<str> {
-        let label: String = self.label(data).into();
+        let label: String = self.format(data).cell_text().collect();
         label.into()
     }
-
-    fn row(&self, data: &Self::Data) -> Row {
-        Row::new(vec![Cell::from(self.label(data))])
-    }
 }
 
 impl Item for PathBuf {
     /// Root prefix to strip.
     type Data = PathBuf;
 
-    fn label(&self, root_path: &Self::Data) -> Spans {
+    fn format(&self, root_path: &Self::Data) -> Row {
         self.strip_prefix(root_path)
             .unwrap_or(self)
             .to_string_lossy()
@@ -144,10 +140,10 @@ impl<T: Item> Menu<T> {
         let n = self
             .options
             .first()
-            .map(|option| option.row(&self.editor_data).cells.len())
+            .map(|option| option.format(&self.editor_data).cells.len())
             .unwrap_or_default();
         let max_lens = self.options.iter().fold(vec![0; n], |mut acc, option| {
-            let row = option.row(&self.editor_data);
+            let row = option.format(&self.editor_data);
             // maintain max for each column
             for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) {
                 let width = cell.content.width();
@@ -331,7 +327,9 @@ impl<T: Item + 'static> Component for Menu<T> {
             (a + b - 1) / b
         }
 
-        let rows = options.iter().map(|option| option.row(&self.editor_data));
+        let rows = options
+            .iter()
+            .map(|option| option.format(&self.editor_data));
         let table = Table::new(rows)
             .style(style)
             .highlight_style(selected)
diff --git a/helix-term/src/ui/picker.rs b/helix-term/src/ui/picker.rs
index 05738ccf..ccf37eb2 100644
--- a/helix-term/src/ui/picker.rs
+++ b/helix-term/src/ui/picker.rs
@@ -410,10 +410,10 @@ impl<T: Item> Picker<T> {
 
         let n = options
             .first()
-            .map(|option| option.row(&editor_data).cells.len())
+            .map(|option| option.format(&editor_data).cells.len())
             .unwrap_or_default();
         let max_lens = options.iter().fold(vec![0; n], |mut acc, option| {
-            let row = option.row(&editor_data);
+            let row = option.format(&editor_data);
             // maintain max for each column
             for (acc, cell) in acc.iter_mut().zip(row.cells.iter()) {
                 let width = cell.content.width();
@@ -729,7 +729,7 @@ impl<T: Item + 'static> Component for Picker<T> {
             .skip(offset)
             .take(rows as usize)
             .map(|pmatch| &self.options[pmatch.index])
-            .map(|option| option.row(&self.editor_data))
+            .map(|option| option.format(&self.editor_data))
             .map(|mut row| {
                 const TEMP_CELL_SEP: &str = " ";
 
diff --git a/helix-tui/src/widgets/table.rs b/helix-tui/src/widgets/table.rs
index 2983072d..400f65e0 100644
--- a/helix-tui/src/widgets/table.rs
+++ b/helix-tui/src/widgets/table.rs
@@ -127,6 +127,12 @@ impl<'a> Row<'a> {
     }
 }
 
+impl<'a, T: Into<Cell<'a>>> From<T> for Row<'a> {
+    fn from(cell: T) -> Self {
+        Row::new(vec![cell.into()])
+    }
+}
+
 /// A widget to display data in formatted columns.
 ///
 /// It is a collection of [`Row`]s, themselves composed of [`Cell`]s: