@@ -12,18 +12,14 @@ use fuzzy_matcher::skim::SkimMatcherV2 as Matcher;
12use tui::widgets::Widget;
12use tui::widgets::Widget;
14use std::{cmp::Ordering, time::Instant};
14use std::{cmp::Ordering, time::Instant};
16− collections::HashMap,
15+use std::{collections::HashMap, io::Read, path::PathBuf};
18− path::{Path, PathBuf},
21use crate::ui::{Prompt, PromptEvent};
17use crate::ui::{Prompt, PromptEvent};
22use helix_core::{movement::Direction, Position};
18use helix_core::{movement::Direction, Position};
23use helix_view::{
19use helix_view::{
24 editor::Action,
20 editor::Action,
25 graphics::{CursorKind, Margin, Modifier, Rect},
21 graphics::{CursorKind, Margin, Modifier, Rect},
26− Document, Editor,
22+ Document, DocumentId, Editor,
29use super::menu::Item;
25use super::menu::Item;
@@ -32,8 +28,36 @@ pub const MIN_AREA_WIDTH_FOR_PREVIEW: u16 = 72;
32/// Biggest file size to preview in bytes
28/// Biggest file size to preview in bytes
33pub const MAX_FILE_SIZE_FOR_PREVIEW: u64 = 10 * 1024 * 1024;
29pub const MAX_FILE_SIZE_FOR_PREVIEW: u64 = 10 * 1024 * 1024;
31+#[derive(PartialEq, Eq, Hash)]
38+ fn get_canonicalized(self) -> std::io::Result<Self> {
41+ Path(path) => Path(helix_core::path::get_canonicalized_path(&path)?),
47+impl From<PathBuf> for PathOrId {
48+ fn from(v: PathBuf) -> Self {
53+impl From<DocumentId> for PathOrId {
54+ fn from(v: DocumentId) -> Self {
35/// File path and range of lines (used to align and highlight lines)
59/// 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)>);
38pub struct FilePicker<T: Item> {
62pub struct FilePicker<T: Item> {
39 picker: Picker<T>,
63 picker: Picker<T>,
@@ -112,62 +136,71 @@ impl<T: Item> FilePicker<T> {
112 self.picker
136 self.picker
113 .selection()
137 .selection()
114 .and_then(|current| (self.file_fn)(editor, current))
138 .and_then(|current| (self.file_fn)(editor, current))
115− .and_then(|(path, line)| {
139+ .and_then(|(path_or_id, line)| path_or_id.get_canonicalized().ok().zip(Some(line)))
116− helix_core::path::get_canonicalized_path(&path)
122 /// Get (cached) preview for a given path. If a document corresponding
142 /// Get (cached) preview for a given path. If a document corresponding
123 /// to the path is already open in the editor, it is used instead.
143 /// to the path is already open in the editor, it is used instead.
124 fn get_preview<'picker, 'editor>(
144 fn get_preview<'picker, 'editor>(
125 &'picker mut self,
145 &'picker mut self,
126− path: &Path,
146+ path_or_id: PathOrId,
127 editor: &'editor Editor,
147 editor: &'editor Editor,
128 ) -> Preview<'picker, 'editor> {
148 ) -> Preview<'picker, 'editor> {
150+ PathOrId::Path(path) => {
129− if let Some(doc) = editor.document_by_path(path) {
152+ if let Some(doc) = editor.document_by_path(path) {
130− return Preview::EditorDocument(doc);
153+ return Preview::EditorDocument(doc);
133− if self.preview_cache.contains_key(path) {
156+ if self.preview_cache.contains_key(path) {
134− return Preview::Cached(&self.preview_cache[path]);
157+ return Preview::Cached(&self.preview_cache[path]);
137− let data = std::fs::File::open(path).and_then(|file| {
160+ let data = std::fs::File::open(path).and_then(|file| {
138− let metadata = file.metadata()?;
161+ let metadata = file.metadata()?;
139− // Read up to 1kb to detect the content type
162+ // Read up to 1kb to detect the content type
140− let n = file.take(1024).read_to_end(&mut self.read_buffer)?;
163+ let n = file.take(1024).read_to_end(&mut self.read_buffer)?;
141− let content_type = content_inspector::inspect(&self.read_buffer[..n]);
164+ let content_type = content_inspector::inspect(&self.read_buffer[..n]);
142− self.read_buffer.clear();
165+ self.read_buffer.clear();
143− Ok((metadata, content_type))
166+ Ok((metadata, content_type))
145− let preview = data
168+ let preview = data
147− |(metadata, content_type)| match (metadata.len(), content_type) {
170+ |(metadata, content_type)| match (metadata.len(), content_type) {
148− (_, content_inspector::ContentType::BINARY) => CachedPreview::Binary,
171+ (_, content_inspector::ContentType::BINARY) => CachedPreview::Binary,
149− (size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => CachedPreview::LargeFile,
172+ (size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => {
173+ CachedPreview::LargeFile
151− // TODO: enable syntax highlighting; blocked by async rendering
176+ // TODO: enable syntax highlighting; blocked by async rendering
152− Document::open(path, None, None)
177+ Document::open(path, None, None)
153− .map(|doc| CachedPreview::Document(Box::new(doc)))
178+ .map(|doc| CachedPreview::Document(Box::new(doc)))
154− .unwrap_or(CachedPreview::NotFound)
179+ .unwrap_or(CachedPreview::NotFound)
158− .unwrap_or(CachedPreview::NotFound);
183+ .unwrap_or(CachedPreview::NotFound);
159− self.preview_cache.insert(path.to_owned(), preview);
184+ self.preview_cache.insert(path.to_owned(), preview);
160− Preview::Cached(&self.preview_cache[path])
185+ Preview::Cached(&self.preview_cache[path])
187+ PathOrId::Id(id) => {
188+ let doc = editor.documents.get(&id).unwrap();
189+ Preview::EditorDocument(doc)
163 fn handle_idle_timeout(&mut self, cx: &mut Context) -> EventResult {
194 fn handle_idle_timeout(&mut self, cx: &mut Context) -> EventResult {
164 // Try to find a document in the cache
195 // Try to find a document in the cache
165 let doc = self
196 let doc = self
166 .current_file(cx.editor)
197 .current_file(cx.editor)
198+ .and_then(|(path, _range)| match path {
199+ PathOrId::Id(doc_id) => Some(doc_mut!(cx.editor, &doc_id)),
167− .and_then(|(path, _range)| self.preview_cache.get_mut(&path))
200+ PathOrId::Path(path) => match self.preview_cache.get_mut(&path) {
168− .and_then(|cache| match cache {
169− CachedPreview::Document(doc) => Some(doc),
201+ Some(CachedPreview::Document(doc)) => Some(doc),
170− _ => None,
202+ _ => None,
173 // Then attempt to highlight it if it has no language set
206 // Then attempt to highlight it if it has no language set
@@ -224,7 +257,7 @@ impl<T: Item + 'static> Component for FilePicker<T> {
224 block.render(preview_area, surface);
257 block.render(preview_area, surface);
226 if let Some((path, range)) = self.current_file(cx.editor) {
259 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);
228 let doc = match preview.document() {
261 let doc = match preview.document() {
229 Some(doc) => doc,
262 Some(doc) => doc,
230 None => {
263 None => {