From ed21346a9412f52e828ce003700babc64db90fcd Mon Sep 17 00:00:00 2001 From: smolck <46855713+smolck@users.noreply.github.com> Date: Sun, 23 Jun 2019 11:24:37 -0500 Subject: [PATCH] Remove 'help-circle.svg' (question mark) icon from unknown autocompletions (#50) * remove 'help-circle' icon for unknown completion items in popupmenu * Remove unnecessary comments * Remove (more) unnecessary comments * This commit changes the behavior of unknown completions. Unknown completions in the pmenu now show icons if one or more completions' kinds in the pmenu are known (to gnvim). This is done by iterating throughout the items in the pmenu when necessary to check if their completion kind is known (to gnvim). * Refactor previous changes Some notable changes in this commit include the additoin of the 'CompletionItemKind' enum to nvim_bridge.rs per vhakulinen's suggestion, in addition to changing the 'CompletionItemWidgetWrap::create' function to take a reference to the other items in the popupmenu. That function then checks whether or not any other items in the pmenu have icons to determine if it should use an icon for the created 'CompletionItemWidgetWrap' object if it's kind is unknown. I have also refactored `get_icon_pixbuf` and `get_icon_name_for_kind` to take a reference to a 'CompletionItemKind' instead of a 'str'. * Refactor to use variable * Refactor to use `show_kind` variable * Refactor with changes requested by @vhakulinen * Add less padding when all completion items are unknown. * Avoid unnecessary clone * Add padding to `info` when kind is not shown --- src/nvim_bridge.rs | 80 +++++++++++++++++- src/ui/popupmenu/completion_item_widget.rs | 97 ++++++++++++---------- src/ui/popupmenu/lazy_loader.rs | 8 ++ src/ui/popupmenu/popupmenu.rs | 21 +++-- 4 files changed, 155 insertions(+), 51 deletions(-) diff --git a/src/nvim_bridge.rs b/src/nvim_bridge.rs index 72a97778..7b71c546 100644 --- a/src/nvim_bridge.rs +++ b/src/nvim_bridge.rs @@ -211,10 +211,83 @@ pub enum OptionSet { NotSupported(String), } +#[derive(Clone)] +pub enum CompletionItemKind { + Class, + Color, + Constant, + Constructor, + Enum, + EnumMember, + Event, + Function, + File, + Folder, + Field, + Interface, + Keyword, + Method, + Module, + Operator, + Property, + Reference, + Snippet, + Struct, + Text, + TypeParameter, + Unit, + Unknown, + Value, + Variable, +} + +impl From<&str> for CompletionItemKind { + fn from(from: &str) -> Self { + match from { + "class" => CompletionItemKind::Class, + "color" => CompletionItemKind::Color, + "constant" => CompletionItemKind::Constant, + "constructor" => CompletionItemKind::Constructor, + "enum" => CompletionItemKind::Enum, + "enum member" => CompletionItemKind::EnumMember, + "event" => CompletionItemKind::Event, + "function" => CompletionItemKind::Function, + "file" => CompletionItemKind::File, + "folder" => CompletionItemKind::Folder, + "field" => CompletionItemKind::Field, + "interface" => CompletionItemKind::Interface, + "keyword" => CompletionItemKind::Keyword, + "method" => CompletionItemKind::Method, + "module" => CompletionItemKind::Module, + "operator" => CompletionItemKind::Operator, + "property" => CompletionItemKind::Property, + "reference" => CompletionItemKind::Reference, + "snippet" => CompletionItemKind::Snippet, + "struct" => CompletionItemKind::Struct, + "text" => CompletionItemKind::Text, + "type parameter" => CompletionItemKind::TypeParameter, + "unit" => CompletionItemKind::Unit, + "value" => CompletionItemKind::Value, + "variable" => CompletionItemKind::Variable, + _ => CompletionItemKind::Unknown, + } + } +} + +impl CompletionItemKind { + pub fn is_unknown(&self) -> bool { + match self { + CompletionItemKind::Unknown => true, + _ => false, + } + } +} + #[derive(Clone)] pub struct CompletionItem { pub word: String, - pub kind: String, + pub kind: CompletionItemKind, + pub kind_raw: String, pub menu: String, pub info: String, } @@ -679,7 +752,9 @@ fn parse_redraw_event(args: Vec) -> Vec { for item in unwrap_array!(args[0]) { let item = unwrap_array!(item); let word = unwrap_str!(item[0]).to_owned(); - let kind = unwrap_str!(item[1]).to_owned(); + let kind = + CompletionItemKind::from(unwrap_str!(item[1])); + let kind_raw = unwrap_str!(item[1]).to_owned(); let menu = unwrap_str!(item[2]).to_owned(); let info = unwrap_str!(item[3]).to_owned(); @@ -688,6 +763,7 @@ fn parse_redraw_event(args: Vec) -> Vec { kind, menu, info, + kind_raw, }); } diff --git a/src/ui/popupmenu/completion_item_widget.rs b/src/ui/popupmenu/completion_item_widget.rs index 727be1c7..1fac004c 100644 --- a/src/ui/popupmenu/completion_item_widget.rs +++ b/src/ui/popupmenu/completion_item_widget.rs @@ -1,7 +1,7 @@ use gtk; use gtk::prelude::*; -use nvim_bridge::CompletionItem; +use nvim_bridge::{CompletionItem, CompletionItemKind}; use ui::color::Color; macro_rules! icon { @@ -20,7 +20,9 @@ pub struct CompletionItemWidgetWrap { /// Label displaying `menu` for this item in the list. pub menu: gtk::Label, /// Image of the item in the row. - pub kind: gtk::Image, + pub image: gtk::Image, + /// Kind of the item + pub kind: CompletionItemKind, /// Root container. pub row: gtk::ListBoxRow, } @@ -28,6 +30,7 @@ pub struct CompletionItemWidgetWrap { impl CompletionItemWidgetWrap { pub fn create( item: CompletionItem, + show_kind: bool, css_provider: >k::CssProvider, icon_fg: &Color, size: f64, @@ -37,11 +40,16 @@ impl CompletionItemWidgetWrap { let grid = gtk::Grid::new(); grid.set_column_spacing(10); - let buf = get_icon_pixbuf(&item.kind.as_str(), icon_fg, size); - let kind = gtk::Image::new_from_pixbuf(&buf); - kind.set_tooltip_text(format!("kind: '{}'", item.kind).as_str()); - kind.set_margin_start(margin); - grid.attach(&kind, 0, 0, 1, 1); + let image = gtk::Image::new(); + if show_kind { + let buf = get_icon_pixbuf(&item.kind, icon_fg, size); + image.set_from_pixbuf(&buf); + image.set_tooltip_text( + format!("kind: '{}'", item.kind_raw).as_str(), + ); + image.set_margin_start(margin); + grid.attach(&image, 0, 0, 1, 1); + } let menu = gtk::Label::new(item.menu.as_str()); menu.set_halign(gtk::Align::End); @@ -58,6 +66,11 @@ impl CompletionItemWidgetWrap { info.set_halign(gtk::Align::Start); info.set_ellipsize(pango::EllipsizeMode::End); + if !show_kind { + word.set_margin_start(5); + info.set_margin_start(5); + } + info.connect_realize(|info| { info.hide(); }); @@ -72,12 +85,14 @@ impl CompletionItemWidgetWrap { let row = gtk::ListBoxRow::new(); row.add(&grid); - add_css_provider!(css_provider, grid, kind, word, info, row, menu); + add_css_provider!(css_provider, grid, word, image, info, row, menu); + let kind = item.kind.clone(); CompletionItemWidgetWrap { item, info, row, + image, kind, menu, } @@ -92,7 +107,7 @@ fn shorten_info(info: &String) -> String { } pub fn get_icon_pixbuf( - kind: &str, + kind: &CompletionItemKind, color: &Color, size: f64, ) -> gdk_pixbuf::Pixbuf { @@ -105,44 +120,42 @@ pub fn get_icon_pixbuf( buf } -fn get_icon_name_for_kind(kind: &str, color: &Color, size: f64) -> String { +fn get_icon_name_for_kind( + kind: &CompletionItemKind, + color: &Color, + size: f64, +) -> String { let color = color.to_hex(); let size = size * 1.1; + use self::CompletionItemKind::*; match kind { - "method" | "function" | "constructor" => { - icon!("../../../assets/icons/box.svg", color, size) - } - "field" => { - icon!("../../../assets/icons/chevrons-right.svg", color, size) - } - "event" => icon!("../../../assets/icons/zap.svg", color, size), - "operator" => icon!("../../../assets/icons/sliders.svg", color, size), - "variable" => icon!("../../../assets/icons/disc.svg", color, size), - "class" => icon!("../../../assets/icons/share-2.svg", color, size), - "interface" => { - icon!("../../../assets/icons/book-open.svg", color, size) - } - "struct" => icon!("../../../assets/icons/align-left.svg", color, size), - "type parameter" => { - icon!("../../../assets/icons/type.svg", color, size) - } - "module" => icon!("../../../assets/icons/code.svg", color, size), - "property" => icon!("../../../assets/icons/key.svg", color, size), - "unit" => icon!("../../../assets/icons/compass.svg", color, size), - "constant" => icon!("../../../assets/icons/shield.svg", color, size), - "value" | "enum" => { - icon!("../../../assets/icons/database.svg", color, size) - } - "enum member" => icon!("../../../assets/icons/tag.svg", color, size), - "keyword" => icon!("../../../assets/icons/link-2.svg", color, size), - "text" => icon!("../../../assets/icons/at-sign.svg", color, size), - "color" => icon!("../../../assets/icons/aperture.svg", color, size), - "file" => icon!("../../../assets/icons/file.svg", color, size), - "reference" => icon!("../../../assets/icons/link.svg", color, size), - "snippet" => icon!("../../../assets/icons/file-text.svg", color, size), - "folder" => icon!("../../../assets/icons/folder.svg", color, size), + Constructor => icon!("../../../assets/icons/box.svg", color, size), + Method => icon!("../../../assets/icons/box.svg", color, size), + Function => icon!("../../../assets/icons/box.svg", color, size), + Field => icon!("../../../assets/icons/chevrons-right.svg", color, size), + Event => icon!("../../../assets/icons/zap.svg", color, size), + Operator => icon!("../../../assets/icons/sliders.svg", color, size), + Variable => icon!("../../../assets/icons/disc.svg", color, size), + Class => icon!("../../../assets/icons/share-2.svg", color, size), + Interface => icon!("../../../assets/icons/book-open.svg", color, size), + Struct => icon!("../../../assets/icons/align-left.svg", color, size), + TypeParameter => icon!("../../../assets/icons/type.svg", color, size), + Module => icon!("../../../assets/icons/code.svg", color, size), + Property => icon!("../../../assets/icons/key.svg", color, size), + Unit => icon!("../../../assets/icons/compass.svg", color, size), + Constant => icon!("../../../assets/icons/shield.svg", color, size), + Value => icon!("../../../assets/icons/database.svg", color, size), + Enum => icon!("../../../assets/icons/database.svg", color, size), + EnumMember => icon!("../../../assets/icons/tag.svg", color, size), + Keyword => icon!("../../../assets/icons/link-2.svg", color, size), + Text => icon!("../../../assets/icons/at-sign.svg", color, size), + Color => icon!("../../../assets/icons/aperture.svg", color, size), + File => icon!("../../../assets/icons/file.svg", color, size), + Reference => icon!("../../../assets/icons/link.svg", color, size), + Snippet => icon!("../../../assets/icons/file-text.svg", color, size), + Folder => icon!("../../../assets/icons/folder.svg", color, size), _ => icon!("../../../assets/icons/help-circle.svg", color, size), } diff --git a/src/ui/popupmenu/lazy_loader.rs b/src/ui/popupmenu/lazy_loader.rs index ef14ec83..c5bf0942 100644 --- a/src/ui/popupmenu/lazy_loader.rs +++ b/src/ui/popupmenu/lazy_loader.rs @@ -12,6 +12,7 @@ use ui::popupmenu::CompletionItemWidgetWrap; struct State { items: Vec, items_to_load: Vec, + show_kind: bool, source_id: Option, @@ -43,6 +44,7 @@ impl State { source_id: None, list, css_provider, + show_kind: false, } } } @@ -58,6 +60,10 @@ impl LazyLoader { } } + pub fn get_show_kind(&self) -> bool { + self.state.borrow().show_kind + } + pub fn set_items( &mut self, items: Vec, @@ -67,6 +73,7 @@ impl LazyLoader { let mut state = self.state.borrow_mut(); state.clear(); + state.show_kind = items.iter().any(|item| !item.kind.is_unknown()); state.items_to_load = items; let state_ref = self.state.clone(); @@ -89,6 +96,7 @@ impl LazyLoader { let item = state.items_to_load.remove(0); let widget = CompletionItemWidgetWrap::create( item, + state.show_kind, &state.css_provider, &icon_fg, size, diff --git a/src/ui/popupmenu/popupmenu.rs b/src/ui/popupmenu/popupmenu.rs index cc69cc5c..b2a6b6b8 100644 --- a/src/ui/popupmenu/popupmenu.rs +++ b/src/ui/popupmenu/popupmenu.rs @@ -380,6 +380,7 @@ impl Popupmenu { let list = self.list.clone(); let info_label = self.info_label.clone(); let info_shown = self.info_shown; + let show_kind = self.items.get_show_kind(); self.items.once_loaded(Some(item_num), move |items| { let mut state = state.borrow_mut(); @@ -388,9 +389,12 @@ impl Popupmenu { prev.info.set_visible(false); prev.menu.set_visible(false); - // Update the `kind` icon with default fg color. - let buf = get_icon_pixbuf(&prev.item.kind, &fg, font_height); - prev.kind.set_from_pixbuf(&buf); + if show_kind { + // Update the `kind` icon with default fg color. + let buf = + get_icon_pixbuf(&prev.item.kind, &fg, font_height); + prev.image.set_from_pixbuf(&buf); + } } state.selected = item_num; @@ -442,10 +446,13 @@ impl Popupmenu { *id.borrow_mut() = Some(sig_id); } - // Update the `kind` icon with "selected" fg color. - let buf = - get_icon_pixbuf(&item.item.kind, &fg_sel, font_height); - item.kind.set_from_pixbuf(&buf); + if show_kind { + // Update the `kind` icon with "selected" fg color. + let buf = + get_icon_pixbuf(&item.item.kind, &fg_sel, font_height); + item.image.set_from_pixbuf(&buf); + } + let newline = if item.item.menu.len() > 0 && item.item.info.len() > 0 { "\n"