Skip to content

Commit 75d0989

Browse files
committed
helix-view: completion-item-kind support for path completion
1 parent 4303494 commit 75d0989

File tree

2 files changed

+62
-104
lines changed

2 files changed

+62
-104
lines changed

helix-term/src/ui/completion.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use crate::ui::{menu, Markdown, Menu, Popup, PromptEvent};
2424
use helix_lsp::{lsp, util, OffsetEncoding};
2525

2626
pub struct CompletionData {
27-
completion_item_kinds: Arc<HashMap<lsp::CompletionItemKind, CompletionItemKindStyle>>,
27+
completion_item_kinds: Arc<HashMap<&'static str, CompletionItemKindStyle>>,
2828
default_style: Style,
2929
}
3030

@@ -108,30 +108,34 @@ impl menu::Item for CompletionItem {
108108
CompletionItem::Lsp(LspCompletionItem { item, .. }) => {
109109
// If the user specified a custom kind text, use that. It will cause an allocation
110110
// though it should not have much impact since its pretty short strings
111-
if let Some(kind_style) = item
112-
.kind
113-
// NOTE: This table gets populated with default text as well.
114-
.and_then(|kind| data.completion_item_kinds.get(&kind))
115-
{
111+
let kind_name = completion_item_kind_name(item.kind).unwrap_or_else(|| {
112+
log::error!("Got invalid LSP completion item kind: {:?}", item.kind);
113+
""
114+
});
115+
116+
if let Some(kind_style) = data.completion_item_kinds.get(kind_name) {
116117
let style = kind_style.style.unwrap_or(data.default_style);
117-
if let Some(text) = kind_style.text.clone() {
118-
menu::Cell::from(Span::styled(text, style))
118+
if let Some(text) = kind_style.text.as_ref() {
119+
menu::Cell::from(Span::styled(text.clone(), style))
119120
} else {
120-
let text = completion_item_kind_name(item.kind).unwrap_or_else(|| {
121-
log::error!("Got invalid LSP completion item kind: {:?}", item.kind);
122-
""
123-
});
124-
menu::Cell::from(Span::styled(text, style))
121+
menu::Cell::from(Span::styled(kind_name, style))
125122
}
126123
} else {
127-
let text = completion_item_kind_name(item.kind).unwrap_or_else(|| {
128-
log::error!("Got invalid LSP completion item kind: {:?}", item.kind);
129-
""
130-
});
131-
menu::Cell::from(Span::styled(text, data.default_style))
124+
menu::Cell::from(Span::styled(kind_name, data.default_style))
125+
}
126+
}
127+
CompletionItem::Other(core::CompletionItem { kind, .. }) => {
128+
if let Some(kind_style) = data.completion_item_kinds.get(kind.as_ref()) {
129+
let style = kind_style.style.unwrap_or(data.default_style);
130+
if let Some(text) = kind_style.text.as_ref() {
131+
menu::Cell::from(Span::styled(text.clone(), style))
132+
} else {
133+
menu::Cell::from(Span::styled(kind.as_ref(), style))
134+
}
135+
} else {
136+
menu::Cell::from(Span::styled(kind.as_ref(), data.default_style))
132137
}
133138
}
134-
CompletionItem::Other(core::CompletionItem { kind, .. }) => menu::Cell::from(&**kind),
135139
};
136140

137141
menu::Row::new([label_cell, kind_cell])

helix-view/src/editor.rs

Lines changed: 39 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,7 @@ pub struct Config {
306306
pub completion_replace: bool,
307307
/// The completion item kind text to display in the completion menu. Leave kind empty to use
308308
/// the kind's name.
309-
#[serde(deserialize_with = "deserialize_completion_item_kinds")]
310-
pub completion_item_kinds: HashMap<lsp::CompletionItemKind, String>,
309+
pub completion_item_kinds: HashMap<String, String>,
311310
/// Whether to display infoboxes. Defaults to true.
312311
pub auto_info: bool,
313312
pub file_picker: FilePickerConfig,
@@ -852,58 +851,6 @@ where
852851
}
853852
}
854853

855-
fn deserialize_completion_item_kinds<'de, D>(
856-
deserializer: D,
857-
) -> Result<HashMap<lsp::CompletionItemKind, String>, D::Error>
858-
where
859-
D: serde::Deserializer<'de>,
860-
{
861-
let raw = HashMap::<String, String>::deserialize(deserializer)?;
862-
let mut ret = HashMap::with_capacity(raw.len());
863-
864-
for (kind, text) in raw {
865-
// NOTE: Doing manual string check since CompletionItemKind::from_str uses
866-
// PascalCase while the configuration is in kebab-case
867-
let kind = match kind.as_str() {
868-
"text" => lsp::CompletionItemKind::TEXT,
869-
"method" => lsp::CompletionItemKind::METHOD,
870-
"function" => lsp::CompletionItemKind::FUNCTION,
871-
"constructor" => lsp::CompletionItemKind::CONSTRUCTOR,
872-
"field" => lsp::CompletionItemKind::FIELD,
873-
"variable" => lsp::CompletionItemKind::VARIABLE,
874-
"class" => lsp::CompletionItemKind::CLASS,
875-
"interface" => lsp::CompletionItemKind::INTERFACE,
876-
"module" => lsp::CompletionItemKind::MODULE,
877-
"property" => lsp::CompletionItemKind::PROPERTY,
878-
"unit" => lsp::CompletionItemKind::UNIT,
879-
"value" => lsp::CompletionItemKind::VALUE,
880-
"enum" => lsp::CompletionItemKind::ENUM,
881-
"keyword" => lsp::CompletionItemKind::KEYWORD,
882-
"snippet" => lsp::CompletionItemKind::SNIPPET,
883-
"color" => lsp::CompletionItemKind::COLOR,
884-
"file" => lsp::CompletionItemKind::FILE,
885-
"reference" => lsp::CompletionItemKind::REFERENCE,
886-
"folder" => lsp::CompletionItemKind::FOLDER,
887-
"enum-member" => lsp::CompletionItemKind::ENUM_MEMBER,
888-
"constant" => lsp::CompletionItemKind::CONSTANT,
889-
"struct" => lsp::CompletionItemKind::STRUCT,
890-
"event" => lsp::CompletionItemKind::EVENT,
891-
"operator" => lsp::CompletionItemKind::OPERATOR,
892-
"type-parameter" => lsp::CompletionItemKind::TYPE_PARAMETER,
893-
_ => {
894-
return Err(<D::Error as serde::de::Error>::invalid_value(
895-
serde::de::Unexpected::Str(kind.as_str()),
896-
&"CompletionItemKind",
897-
));
898-
}
899-
};
900-
901-
ret.insert(kind, text);
902-
}
903-
904-
Ok(ret)
905-
}
906-
907854
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
908855
#[serde(default)]
909856
pub struct WhitespaceCharacters {
@@ -1131,7 +1078,7 @@ pub struct Editor {
11311078

11321079
pub config: Arc<dyn DynAccess<Config>>,
11331080
pub auto_pairs: Option<AutoPairs>,
1134-
pub completion_item_kind_styles: Arc<HashMap<lsp::CompletionItemKind, CompletionItemKindStyle>>,
1081+
pub completion_item_kind_styles: Arc<HashMap<&'static str, CompletionItemKindStyle>>,
11351082

11361083
pub idle_timer: Pin<Box<Sleep>>,
11371084
redraw_timer: Pin<Box<Sleep>>,
@@ -1322,6 +1269,10 @@ impl Editor {
13221269
pub fn refresh_config(&mut self) {
13231270
let config = self.config();
13241271
self.auto_pairs = (&config.auto_pairs).into();
1272+
self.completion_item_kind_styles = Arc::new(compute_completion_item_kind_styles(
1273+
&self.theme,
1274+
&self.config(),
1275+
));
13251276
self.reset_idle_timer();
13261277
self._refresh();
13271278
}
@@ -2292,39 +2243,42 @@ fn try_restore_indent(doc: &mut Document, view: &mut View) {
22922243
fn compute_completion_item_kind_styles(
22932244
theme: &Theme,
22942245
config: &DynGuard<Config>,
2295-
) -> HashMap<lsp::CompletionItemKind, CompletionItemKindStyle> {
2246+
) -> HashMap<&'static str, CompletionItemKindStyle> {
22962247
let mut ret = HashMap::new();
2297-
for (scope_name, kind) in [
2298-
("text", lsp::CompletionItemKind::TEXT),
2299-
("method", lsp::CompletionItemKind::METHOD),
2300-
("function", lsp::CompletionItemKind::FUNCTION),
2301-
("constructor", lsp::CompletionItemKind::CONSTRUCTOR),
2302-
("field", lsp::CompletionItemKind::FIELD),
2303-
("variable", lsp::CompletionItemKind::VARIABLE),
2304-
("class", lsp::CompletionItemKind::CLASS),
2305-
("interface", lsp::CompletionItemKind::INTERFACE),
2306-
("module", lsp::CompletionItemKind::MODULE),
2307-
("property", lsp::CompletionItemKind::PROPERTY),
2308-
("unit", lsp::CompletionItemKind::UNIT),
2309-
("value", lsp::CompletionItemKind::VALUE),
2310-
("enum", lsp::CompletionItemKind::ENUM),
2311-
("keyword", lsp::CompletionItemKind::KEYWORD),
2312-
("snippet", lsp::CompletionItemKind::SNIPPET),
2313-
("color", lsp::CompletionItemKind::COLOR),
2314-
("file", lsp::CompletionItemKind::FILE),
2315-
("reference", lsp::CompletionItemKind::REFERENCE),
2316-
("folder", lsp::CompletionItemKind::FOLDER),
2317-
("enum-member", lsp::CompletionItemKind::ENUM_MEMBER),
2318-
("constant", lsp::CompletionItemKind::CONSTANT),
2319-
("struct", lsp::CompletionItemKind::STRUCT),
2320-
("event", lsp::CompletionItemKind::EVENT),
2321-
("operator", lsp::CompletionItemKind::OPERATOR),
2322-
("type-parameter", lsp::CompletionItemKind::TYPE_PARAMETER),
2248+
// We populate with LSP kinds and additionally file+folder for path completion
2249+
for name in [
2250+
"text",
2251+
"method",
2252+
"function",
2253+
"constructor",
2254+
"field",
2255+
"variable",
2256+
"class",
2257+
"interface",
2258+
"module",
2259+
"property",
2260+
"unit",
2261+
"value",
2262+
"enum",
2263+
"keyword",
2264+
"snippet",
2265+
"color",
2266+
"file",
2267+
"reference",
2268+
"folder",
2269+
"enum-member",
2270+
"constant",
2271+
"struct",
2272+
"event",
2273+
"operator",
2274+
"type-parameter",
2275+
"file",
2276+
"folder",
23232277
] {
2324-
let style = theme.try_get(&dbg!(format!("ui.completion.kind.{scope_name}")));
2325-
let text = config.completion_item_kinds.get(&kind).cloned();
2278+
let style = theme.try_get(&format!("ui.completion.kind.{name}"));
2279+
let text = config.completion_item_kinds.get(name).cloned();
23262280
if style.is_some() || text.is_some() {
2327-
ret.insert(kind, CompletionItemKindStyle { text, style });
2281+
ret.insert(name, CompletionItemKindStyle { text, style });
23282282
}
23292283
}
23302284

0 commit comments

Comments
 (0)