@@ -18,7 +18,9 @@ use crate::{
1818 },
1919};
2020
21−use std::{borrow::Cow, cmp::Ordering, collections::BTreeMap, path::PathBuf, sync::Arc};
21+use std::{
22+ borrow::Cow, cmp::Ordering, collections::BTreeMap, fmt::Write, path::PathBuf, sync::Arc,
23+};
2224
2325/// Gets the language server that is attached to a document, and
2426/// if it's not active displays a status message. Using this macro
@@ -43,23 +45,32 @@ impl ui::menu::Item for lsp::Location {
4345 type Data = PathBuf;
4446
4547 fn label(&self, cwdir: &Self::Data) -> Spans {
46− let file: Cow<'_, str> = (self.uri.scheme() == "file")
47− .then(|| {
48− self.uri
49− .to_file_path()
50− .map(|path| {
51− // strip root prefix
52− path.strip_prefix(&cwdir)
53− .map(|path| path.to_path_buf())
54− .unwrap_or(path)
55− })
56− .map(|path| Cow::from(path.to_string_lossy().into_owned()))
57− .ok()
58− })
59− .flatten()
60− .unwrap_or_else(|| self.uri.as_str().into());
61− let line = self.range.start.line;
62− format!("{}:{}", file, line).into()
48+ // The preallocation here will overallocate a few characters since it will account for the
49+ // URL's scheme, which is not used most of the time since that scheme will be "file://".
50+ // Those extra chars will be used to avoid allocating when writing the line number (in the
51+ // common case where it has 5 digits or less, which should be enough for a cast majority
52+ // of usages).
53+ let mut res = String::with_capacity(self.uri.as_str().len());
54+
55+ if self.uri.scheme() == "file" {
56+ // With the preallocation above and UTF-8 paths already, this closure will do one (1)
57+ // allocation, for `to_file_path`, else there will be two (2), with `to_string_lossy`.
58+ let mut write_path_to_res = || -> Option<()> {
59+ let path = self.uri.to_file_path().ok()?;
60+ res.push_str(&path.strip_prefix(&cwdir).unwrap_or(&path).to_string_lossy());
61+ Some(())
62+ };
63+ write_path_to_res();
64+ } else {
65+ // Never allocates since we declared the string with this capacity already.
66+ res.push_str(self.uri.as_str());
67+ }
68+
69+ // Most commonly, this will not allocate, especially on Unix systems where the root prefix
70+ // is a simple `/` and not `C:\` (with whatever drive letter)
71+ write!(&mut res, ":{}", self.range.start.line)
72+ .expect("Will only failed if allocating fail");
73+ res.into()
6374 }
6475}
6576
@@ -73,10 +84,8 @@ impl ui::menu::Item for lsp::SymbolInformation {
7384 } else {
7485 match self.location.uri.to_file_path() {
7586 Ok(path) => {
76− let relative_path = helix_core::path::get_relative_path(path.as_path())
77− .to_string_lossy()
78− .into_owned();
79− format!("{} ({})", &self.name, relative_path).into()
87+ let get_relative_path = path::get_relative_path(path.as_path());
88+ format!("{} ({})", &self.name, get_relative_path.to_string_lossy()).into()
8089 }
8190 Err(_) => format!("{} ({})", &self.name, &self.location.uri).into(),
8291 }
@@ -115,24 +124,21 @@ impl ui::menu::Item for PickerDiagnostic {
115124 // remove background as it is distracting in the picker list
116125 style.bg = None;
117126
118− let code = self
127+ let code: Cow<'_, str> = self
119128 .diag
120129 .code
121130 .as_ref()
122131 .map(|c| match c {
123− NumberOrString::Number(n) => n.to_string(),
124− NumberOrString::String(s) => s.to_string(),
132+ NumberOrString::Number(n) => n.to_string().into(),
133+ NumberOrString::String(s) => s.as_str().into(),
125134 })
126− .map(|code| format!(" ({})", code))
127135 .unwrap_or_default();
128136
129137 let path = match format {
130138 DiagnosticsFormat::HideSourcePath => String::new(),
131139 DiagnosticsFormat::ShowSourcePath => {
132− let path = path::get_truncated_path(self.url.path())
133− .to_string_lossy()
134− .into_owned();
135− format!("{}: ", path)
140+ let path = path::get_truncated_path(self.url.path());
141+ format!("{}: ", path.to_string_lossy())
136142 }
137143 };
138144