Skip to content

Commit 2f9ca38

Browse files
authored
Add preview for scratch buffers in buffer picker (#3454)
1 parent 420e33a commit 2f9ca38

File tree

5 files changed

+88
-55
lines changed

5 files changed

+88
-55
lines changed

helix-term/src/commands.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2005,7 +2005,7 @@ fn global_search(cx: &mut Context) {
20052005
align_view(doc, view, Align::Center);
20062006
},
20072007
|_editor, FileResult { path, line_num }| {
2008-
Some((path.clone(), Some((*line_num, *line_num))))
2008+
Some((path.clone().into(), Some((*line_num, *line_num))))
20092009
},
20102010
);
20112011
compositor.push(Box::new(overlayed(picker)));
@@ -2360,7 +2360,7 @@ fn buffer_picker(cx: &mut Context) {
23602360
.selection(view_id)
23612361
.primary()
23622362
.cursor_line(doc.text().slice(..));
2363-
Some((meta.path.clone()?, Some((line, line))))
2363+
Some((meta.id.into(), Some((line, line))))
23642364
},
23652365
);
23662366
cx.push_layer(Box::new(overlayed(picker)));
@@ -2441,7 +2441,7 @@ fn jumplist_picker(cx: &mut Context) {
24412441
|editor, meta| {
24422442
let doc = &editor.documents.get(&meta.id)?;
24432443
let line = meta.selection.primary().cursor_line(doc.text().slice(..));
2444-
Some((meta.path.clone()?, Some((line, line))))
2444+
Some((meta.path.clone()?.into(), Some((line, line))))
24452445
},
24462446
);
24472447
cx.push_layer(Box::new(overlayed(picker)));

helix-term/src/commands/dap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ fn thread_picker(
8585
frame.line.saturating_sub(1),
8686
frame.end_line.unwrap_or(frame.line).saturating_sub(1),
8787
));
88-
Some((path, pos))
88+
Some((path.into(), pos))
8989
},
9090
);
9191
compositor.push(Box::new(picker));
@@ -706,7 +706,7 @@ pub fn dap_switch_stack_frame(cx: &mut Context) {
706706
.and_then(|source| source.path.clone())
707707
.map(|path| {
708708
(
709-
path,
709+
path.into(),
710710
Some((
711711
frame.line.saturating_sub(1),
712712
frame.end_line.unwrap_or(frame.line).saturating_sub(1),

helix-term/src/commands/lsp.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ fn location_to_file_location(location: &lsp::Location) -> FileLocation {
156156
location.range.start.line as usize,
157157
location.range.end.line as usize,
158158
));
159-
(path, line)
159+
(path.into(), line)
160160
}
161161

162162
// TODO: share with symbol picker(symbol.location)

helix-term/src/ui/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi
230230
cx.editor.set_error(err);
231231
}
232232
},
233-
|_editor, path| Some((path.clone(), None)),
233+
|_editor, path| Some((path.clone().into(), None)),
234234
)
235235
}
236236

helix-term/src/ui/picker.rs

Lines changed: 81 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,14 @@ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
1212
use tui::widgets::Widget;
1313

1414
use std::{cmp::Ordering, time::Instant};
15-
use std::{
16-
collections::HashMap,
17-
io::Read,
18-
path::{Path, PathBuf},
19-
};
15+
use std::{collections::HashMap, io::Read, path::PathBuf};
2016

2117
use crate::ui::{Prompt, PromptEvent};
2218
use helix_core::{movement::Direction, Position};
2319
use helix_view::{
2420
editor::Action,
2521
graphics::{CursorKind, Margin, Modifier, Rect},
26-
Document, Editor,
22+
Document, DocumentId, Editor,
2723
};
2824

2925
use super::menu::Item;
@@ -32,8 +28,36 @@ pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72;
3228
/// Biggest file size to preview in bytes
3329
pub const MAX_FILE_SIZE_FOR_PREVIEW: u64 = 10 * 1024 * 1024;
3430

31+
#[derive(PartialEq, Eq, Hash)]
32+
pub enum PathOrId {
33+
Id(DocumentId),
34+
Path(PathBuf),
35+
}
36+
37+
impl PathOrId {
38+
fn get_canonicalized(self) -> std::io::Result<Self> {
39+
use PathOrId::*;
40+
Ok(match self {
41+
Path(path) => Path(helix_core::path::get_canonicalized_path(&path)?),
42+
Id(id) => Id(id),
43+
})
44+
}
45+
}
46+
47+
impl From<PathBuf> for PathOrId {
48+
fn from(v: PathBuf) -> Self {
49+
Self::Path(v)
50+
}
51+
}
52+
53+
impl From<DocumentId> for PathOrId {
54+
fn from(v: DocumentId) -> Self {
55+
Self::Id(v)
56+
}
57+
}
58+
3559
/// File path and range of lines (used to align and highlight lines)
36-
pub type FileLocation = (PathBuf, Option<(usize, usize)>);
60+
pub type FileLocation = (PathOrId, Option<(usize, usize)>);
3761

3862
pub struct FilePicker<T: Item> {
3963
picker: Picker<T>,
@@ -112,62 +136,71 @@ impl<T: Item> FilePicker<T> {
112136
self.picker
113137
.selection()
114138
.and_then(|current| (self.file_fn)(editor, current))
115-
.and_then(|(path, line)| {
116-
helix_core::path::get_canonicalized_path(&path)
117-
.ok()
118-
.zip(Some(line))
119-
})
139+
.and_then(|(path_or_id, line)| path_or_id.get_canonicalized().ok().zip(Some(line)))
120140
}
121141

122142
/// Get (cached) preview for a given path. If a document corresponding
123143
/// to the path is already open in the editor, it is used instead.
124144
fn get_preview<'picker, 'editor>(
125145
&'picker mut self,
126-
path: &Path,
146+
path_or_id: PathOrId,
127147
editor: &'editor Editor,
128148
) -> Preview<'picker, 'editor> {
129-
if let Some(doc) = editor.document_by_path(path) {
130-
return Preview::EditorDocument(doc);
131-
}
149+
match path_or_id {
150+
PathOrId::Path(path) => {
151+
let path = &path;
152+
if let Some(doc) = editor.document_by_path(path) {
153+
return Preview::EditorDocument(doc);
154+
}
132155

133-
if self.preview_cache.contains_key(path) {
134-
return Preview::Cached(&self.preview_cache[path]);
135-
}
156+
if self.preview_cache.contains_key(path) {
157+
return Preview::Cached(&self.preview_cache[path]);
158+
}
136159

137-
let data = std::fs::File::open(path).and_then(|file| {
138-
let metadata = file.metadata()?;
139-
// Read up to 1kb to detect the content type
140-
let n = file.take(1024).read_to_end(&mut self.read_buffer)?;
141-
let content_type = content_inspector::inspect(&self.read_buffer[..n]);
142-
self.read_buffer.clear();
143-
Ok((metadata, content_type))
144-
});
145-
let preview = data
146-
.map(
147-
|(metadata, content_type)| match (metadata.len(), content_type) {
148-
(_, content_inspector::ContentType::BINARY) => CachedPreview::Binary,
149-
(size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => CachedPreview::LargeFile,
150-
_ => {
151-
// TODO: enable syntax highlighting; blocked by async rendering
152-
Document::open(path, None, None)
153-
.map(|doc| CachedPreview::Document(Box::new(doc)))
154-
.unwrap_or(CachedPreview::NotFound)
155-
}
156-
},
157-
)
158-
.unwrap_or(CachedPreview::NotFound);
159-
self.preview_cache.insert(path.to_owned(), preview);
160-
Preview::Cached(&self.preview_cache[path])
160+
let data = std::fs::File::open(path).and_then(|file| {
161+
let metadata = file.metadata()?;
162+
// Read up to 1kb to detect the content type
163+
let n = file.take(1024).read_to_end(&mut self.read_buffer)?;
164+
let content_type = content_inspector::inspect(&self.read_buffer[..n]);
165+
self.read_buffer.clear();
166+
Ok((metadata, content_type))
167+
});
168+
let preview = data
169+
.map(
170+
|(metadata, content_type)| match (metadata.len(), content_type) {
171+
(_, content_inspector::ContentType::BINARY) => CachedPreview::Binary,
172+
(size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => {
173+
CachedPreview::LargeFile
174+
}
175+
_ => {
176+
// TODO: enable syntax highlighting; blocked by async rendering
177+
Document::open(path, None, None)
178+
.map(|doc| CachedPreview::Document(Box::new(doc)))
179+
.unwrap_or(CachedPreview::NotFound)
180+
}
181+
},
182+
)
183+
.unwrap_or(CachedPreview::NotFound);
184+
self.preview_cache.insert(path.to_owned(), preview);
185+
Preview::Cached(&self.preview_cache[path])
186+
}
187+
PathOrId::Id(id) => {
188+
let doc = editor.documents.get(&id).unwrap();
189+
Preview::EditorDocument(doc)
190+
}
191+
}
161192
}
162193

163194
fn handle_idle_timeout(&mut self, cx: &mut Context) -> EventResult {
164195
// Try to find a document in the cache
165196
let doc = self
166197
.current_file(cx.editor)
167-
.and_then(|(path, _range)| self.preview_cache.get_mut(&path))
168-
.and_then(|cache| match cache {
169-
CachedPreview::Document(doc) => Some(doc),
170-
_ => None,
198+
.and_then(|(path, _range)| match path {
199+
PathOrId::Id(doc_id) => Some(doc_mut!(cx.editor, &doc_id)),
200+
PathOrId::Path(path) => match self.preview_cache.get_mut(&path) {
201+
Some(CachedPreview::Document(doc)) => Some(doc),
202+
_ => None,
203+
},
171204
});
172205

173206
// Then attempt to highlight it if it has no language set
@@ -224,7 +257,7 @@ impl<T: Item + 'static> Component for FilePicker<T> {
224257
block.render(preview_area, surface);
225258

226259
if let Some((path, range)) = self.current_file(cx.editor) {
227-
let preview = self.get_preview(&path, cx.editor);
260+
let preview = self.get_preview(path, cx.editor);
228261
let doc = match preview.document() {
229262
Some(doc) => doc,
230263
None => {

0 commit comments

Comments
 (0)