From 908b1eee1d1df8c9992143304309eb3a753dd79d Mon Sep 17 00:00:00 2001 From: Jakub Panek Date: Tue, 18 Jul 2023 11:05:25 +0200 Subject: [PATCH] fix: handle binary data properly, implement different buffer types --- lapce-app/src/completion.rs | 4 +- lapce-app/src/doc.rs | 4 +- lapce-app/src/palette.rs | 9 +- lapce-app/src/window_tab.rs | 33 +++-- lapce-proxy/src/buffer.rs | 69 +++++++--- lapce-proxy/src/dispatch.rs | 244 +++++++++++++++++++++--------------- 6 files changed, 232 insertions(+), 131 deletions(-) diff --git a/lapce-app/src/completion.rs b/lapce-app/src/completion.rs index 96859b7989..140c192314 100644 --- a/lapce-app/src/completion.rs +++ b/lapce-app/src/completion.rs @@ -356,7 +356,9 @@ fn completion_lens_text( .unwrap_or(InsertTextFormat::PLAIN_TEXT); // We don't display insert and replace - let CompletionTextEdit::Edit(edit) = edit else { return None }; + let CompletionTextEdit::Edit(edit) = edit else { + return None; + }; // The completion offset can be different from the current cursor offset. let completion_offset = completion.offset; diff --git a/lapce-app/src/doc.rs b/lapce-app/src/doc.rs index 6d07df1f35..e911c4302f 100644 --- a/lapce-app/src/doc.rs +++ b/lapce-app/src/doc.rs @@ -923,7 +923,9 @@ impl Document { /// Update the completion lens position after an edit so that it appears in the correct place. pub fn update_completion_lens(&mut self, delta: &RopeDelta) { - let Some(completion) = self.completion_lens.as_ref() else { return }; + let Some(completion) = self.completion_lens.as_ref() else { + return; + }; let (line, col) = self.completion_pos; let offset = self.buffer().offset_of_line_col(line, col); diff --git a/lapce-app/src/palette.rs b/lapce-app/src/palette.rs index ef2343a168..9d56b1c0fe 100644 --- a/lapce-app/src/palette.rs +++ b/lapce-app/src/palette.rs @@ -829,7 +829,14 @@ impl PaletteData { } fn preselect_matching(&self, matching: &str) { - let Some((idx, _)) = self.items.get_untracked().iter().find_position(|item| item.filter_text == matching) else { return }; + let Some((idx, _)) = self + .items + .get_untracked() + .iter() + .find_position(|item| item.filter_text == matching) + else { + return; + }; self.index.set(idx); } diff --git a/lapce-app/src/window_tab.rs b/lapce-app/src/window_tab.rs index 7095151b61..f79ec2ba89 100644 --- a/lapce-app/src/window_tab.rs +++ b/lapce-app/src/window_tab.rs @@ -540,17 +540,20 @@ impl WindowTabData { let mut paths = HashSet::new(); for (_, editor_data) in editors.iter() { editor_data.with_untracked(|editor_data| { - let should_save = editor_data.view.doc.with_untracked(|doc| { - let DocContent::File(path) = &doc.content else { return false }; + let should_save = + editor_data.view.doc.with_untracked(|doc| { + let DocContent::File(path) = &doc.content else { + return false; + }; - if paths.contains(path) { - return false; - } + if paths.contains(path) { + return false; + } - paths.insert(path.clone()); + paths.insert(path.clone()); - true - }); + true + }); if should_save { editor_data.save(true, || {}); @@ -681,12 +684,17 @@ impl WindowTabData { self.main_split.active_editor_tab.get_untracked() { self.main_split.editor_tabs.with_untracked(|editor_tabs| { - let Some(editor_tab) = editor_tabs.get(&editor_tab_id) else { return }; + let Some(editor_tab) = editor_tabs.get(&editor_tab_id) + else { + return; + }; let new_index = editor_tab.with_untracked(|editor_tab| { if editor_tab.children.is_empty() { None - } else if editor_tab.active == editor_tab.children.len() - 1 { + } else if editor_tab.active + == editor_tab.children.len() - 1 + { Some(0) } else { Some(editor_tab.active + 1) @@ -706,7 +714,10 @@ impl WindowTabData { self.main_split.active_editor_tab.get_untracked() { self.main_split.editor_tabs.with_untracked(|editor_tabs| { - let Some(editor_tab) = editor_tabs.get(&editor_tab_id) else { return }; + let Some(editor_tab) = editor_tabs.get(&editor_tab_id) + else { + return; + }; let new_index = editor_tab.with_untracked(|editor_tab| { if editor_tab.children.is_empty() { diff --git a/lapce-proxy/src/buffer.rs b/lapce-proxy/src/buffer.rs index a777d2b52c..4a13d598c6 100644 --- a/lapce-proxy/src/buffer.rs +++ b/lapce-proxy/src/buffer.rs @@ -16,6 +16,35 @@ use lapce_rpc::buffer::BufferId; use lapce_xi_rope::{interval::IntervalBounds, rope::Rope, RopeDelta}; use lsp_types::*; +#[derive(Clone)] +pub enum BufferType { + Text(Buffer), + File, + Error(String), +} + +impl BufferType { + pub fn new(id: BufferId, path: PathBuf) -> BufferType { + return match load_file(&path) { + Ok(content) => { + let rope = Rope::from(content); + let rev = u64::from(!rope.is_empty()); + let language_id = language_id_from_path(&path).unwrap_or(""); + let mod_time = get_mod_time(&path); + BufferType::Text(Buffer { + id, + rope, + path, + language_id, + rev, + mod_time, + }) + } + Err(e) => BufferType::Error(e.to_string()), + }; + } +} + #[derive(Clone)] pub struct Buffer { pub language_id: &'static str, @@ -27,20 +56,25 @@ pub struct Buffer { } impl Buffer { - pub fn new(id: BufferId, path: PathBuf) -> Buffer { - let rope = Rope::from(load_file(&path).unwrap_or_default()); - let rev = u64::from(!rope.is_empty()); - let language_id = language_id_from_path(&path).unwrap_or(""); - let mod_time = get_mod_time(&path); - Buffer { - id, - rope, - path, - language_id, - rev, - mod_time, - } - } + // pub fn new(id: BufferId, path: PathBuf) -> BufferType { + // return match load_file(&path) { + // Ok(content) => { + // let rope = Rope::from(content); + // let rev = u64::from(!rope.is_empty()); + // let language_id = language_id_from_path(&path).unwrap_or(""); + // let mod_time = get_mod_time(&path); + // BufferType::Text(Buffer { + // id, + // rope, + // path, + // language_id, + // rev, + // mod_time, + // }) + // } + // Err(e) => BufferType::Error(e.to_string()), + // }; + // } pub fn save(&mut self, rev: u64) -> Result<()> { if self.rev != rev { @@ -165,6 +199,13 @@ pub fn read_path_to_string_lossy>( let mut buffer = Vec::new(); file.read_to_end(&mut buffer)?; + if buffer[..8] == [137, 80, 78, 71, 13, 10, 26, 10] { + return Err(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Not a text file", + )); + } + // Parse the file contents as utf8, replacing non-utf8 data with the // replacement character let contents = String::from_utf8_lossy(&buffer); diff --git a/lapce-proxy/src/dispatch.rs b/lapce-proxy/src/dispatch.rs index 7ef9704b46..71842d1b6d 100644 --- a/lapce-proxy/src/dispatch.rs +++ b/lapce-proxy/src/dispatch.rs @@ -35,7 +35,7 @@ use lsp_types::{Position, Range, TextDocumentItem, Url}; use parking_lot::Mutex; use crate::{ - buffer::{get_mod_time, load_file, Buffer}, + buffer::{get_mod_time, load_file, Buffer, BufferType}, plugin::{catalog::PluginCatalog, remove_volt, PluginCatalogRpcHandler}, terminal::Terminal, watcher::{FileWatcher, Notify, WatchToken}, @@ -49,7 +49,7 @@ pub struct Dispatcher { pub proxy_rpc: ProxyRpcHandler, core_rpc: CoreRpcHandler, catalog_rpc: PluginCatalogRpcHandler, - buffers: HashMap, + buffers: HashMap, #[allow(deprecated)] terminals: HashMap>, file_watcher: FileWatcher, @@ -106,7 +106,7 @@ impl ProxyHandler for Dispatcher { .notification(CoreNotification::OpenPaths { paths }); } OpenFileChanged { path } => { - if let Some(buffer) = self.buffers.get(&path) { + if let Some(BufferType::Text(buffer)) = self.buffers.get(&path) { if get_mod_time(&buffer.path) == buffer.mod_time { return; } @@ -141,15 +141,17 @@ impl ProxyHandler for Dispatcher { } Update { path, delta, rev } => { let buffer = self.buffers.get_mut(&path).unwrap(); - let old_text = buffer.rope.clone(); - buffer.update(&delta, rev); - self.catalog_rpc.did_change_text_document( - &path, - rev, - delta, - old_text, - buffer.rope.clone(), - ); + if let BufferType::Text(buffer) = buffer { + let old_text = buffer.rope.clone(); + buffer.update(&delta, rev); + self.catalog_rpc.did_change_text_document( + &path, + rev, + delta, + old_text, + buffer.rope.clone(), + ); + } } UpdatePluginConfigs { configs } => { let _ = self.catalog_rpc.update_plugin_configs(configs); @@ -321,16 +323,23 @@ impl ProxyHandler for Dispatcher { use ProxyRequest::*; match rpc { NewBuffer { buffer_id, path } => { - let buffer = Buffer::new(buffer_id, path.clone()); - let content = buffer.rope.to_string(); - self.catalog_rpc.did_open_document( - &path, - buffer.language_id.to_string(), - buffer.rev as i32, - content.clone(), - ); + let buffer_type = BufferType::new(buffer_id, path.clone()); self.file_watcher.watch(&path, false, OPEN_FILE_EVENT_TOKEN); - self.buffers.insert(path, buffer); + self.buffers.insert(path.clone(), buffer_type.clone()); + let content = match buffer_type { + BufferType::Text(buffer) => { + let content = buffer.rope.to_string(); + self.catalog_rpc.did_open_document( + &path, + buffer.language_id.to_string(), + buffer.rev as i32, + content.clone(), + ); + content + } + BufferType::Error(e) => e, + _ => String::new(), + }; self.respond_rpc( id, Ok(ProxyResponse::NewBufferResponse { content }), @@ -500,63 +509,71 @@ impl ProxyHandler for Dispatcher { GetInlayHints { path } => { let proxy_rpc = self.proxy_rpc.clone(); let buffer = self.buffers.get(&path).unwrap(); - let range = Range { - start: Position::new(0, 0), - end: buffer.offset_to_position(buffer.len()), - }; - self.catalog_rpc - .get_inlay_hints(&path, range, move |_, result| { - let result = result - .map(|hints| ProxyResponse::GetInlayHints { hints }); - proxy_rpc.handle_response(id, result); - }); + if let BufferType::Text(buffer) = buffer { + let range = Range { + start: Position::new(0, 0), + end: buffer.offset_to_position(buffer.len()), + }; + self.catalog_rpc.get_inlay_hints( + &path, + range, + move |_, result| { + let result = result + .map(|hints| ProxyResponse::GetInlayHints { hints }); + proxy_rpc.handle_response(id, result); + }, + ); + } } GetSemanticTokens { path } => { let buffer = self.buffers.get(&path).unwrap(); - let text = buffer.rope.clone(); - let rev = buffer.rev; - let len = buffer.len(); - let local_path = path.clone(); - let proxy_rpc = self.proxy_rpc.clone(); - let catalog_rpc = self.catalog_rpc.clone(); - - let handle_tokens = - move |result: Result, RpcError>| match result { - Ok(styles) => { - proxy_rpc.handle_response( - id, - Ok(ProxyResponse::GetSemanticTokens { - styles: SemanticStyles { - rev, - path: local_path, - styles, - len, - }, - }), - ); - } - Err(e) => { - proxy_rpc.handle_response(id, Err(e)); - } - }; + if let BufferType::Text(buffer) = buffer { + let text = buffer.rope.clone(); + let rev = buffer.rev; + let len = buffer.len(); + let local_path = path.clone(); + let proxy_rpc = self.proxy_rpc.clone(); + let catalog_rpc = self.catalog_rpc.clone(); + + let handle_tokens = + move |result: Result, RpcError>| match result + { + Ok(styles) => { + proxy_rpc.handle_response( + id, + Ok(ProxyResponse::GetSemanticTokens { + styles: SemanticStyles { + rev, + path: local_path, + styles, + len, + }, + }), + ); + } + Err(e) => { + proxy_rpc.handle_response(id, Err(e)); + } + }; - let proxy_rpc = self.proxy_rpc.clone(); - self.catalog_rpc.get_semantic_tokens( - &path, - move |plugin_id, result| match result { - Ok(result) => { - catalog_rpc.format_semantic_tokens( - plugin_id, - result, - text, - Box::new(handle_tokens), - ); - } - Err(e) => { - proxy_rpc.handle_response(id, Err(e)); - } - }, - ); + let proxy_rpc = self.proxy_rpc.clone(); + self.catalog_rpc.get_semantic_tokens( + &path, + move |plugin_id, result| match result { + Ok(result) => { + catalog_rpc.format_semantic_tokens( + plugin_id, + result, + text, + Box::new(handle_tokens), + ); + } + Err(e) => { + proxy_rpc.handle_response(id, Err(e)); + } + }, + ); + } } GetCodeActions { path, @@ -678,11 +695,22 @@ impl ProxyHandler for Dispatcher { let items = self .buffers .iter() - .map(|(path, buffer)| TextDocumentItem { - uri: Url::from_file_path(path).unwrap(), - language_id: buffer.language_id.to_string(), - version: buffer.rev as i32, - text: buffer.get_document(), + .map(|(path, buffer_type)| { + if let BufferType::Text(buffer) = buffer_type { + TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: buffer.language_id.to_string(), + version: buffer.rev as i32, + text: buffer.get_document(), + } + } else { + TextDocumentItem { + uri: Url::from_file_path(path).unwrap(), + language_id: String::new(), + version: 0, + text: String::from("Not a text file"), + } + } }) .collect(); let resp = ProxyResponse::GetOpenFilesContentResponse { items }; @@ -722,18 +750,20 @@ impl ProxyHandler for Dispatcher { } Save { rev, path } => { let buffer = self.buffers.get_mut(&path).unwrap(); - let result = buffer - .save(rev) - .map(|_r| { - self.catalog_rpc - .did_save_text_document(&path, buffer.rope.clone()); - ProxyResponse::SaveResponse {} - }) - .map_err(|e| RpcError { - code: 0, - message: e.to_string(), - }); - self.respond_rpc(id, result); + if let BufferType::Text(buffer) = buffer { + let result = buffer + .save(rev) + .map(|_r| { + self.catalog_rpc + .did_save_text_document(&path, buffer.rope.clone()); + ProxyResponse::SaveResponse {} + }) + .map_err(|e| RpcError { + code: 0, + message: e.to_string(), + }); + self.respond_rpc(id, result); + } } SaveBufferAs { buffer_id, @@ -741,18 +771,26 @@ impl ProxyHandler for Dispatcher { rev, content, } => { - let mut buffer = Buffer::new(buffer_id, path.clone()); - buffer.rope = Rope::from(content); - buffer.rev = rev; - let result = buffer - .save(rev) - .map(|_| ProxyResponse::Success {}) - .map_err(|e| RpcError { - code: 0, - message: e.to_string(), - }); - self.buffers.insert(path, buffer); - self.respond_rpc(id, result); + let buffer_type = BufferType::new(buffer_id, path.clone()); + if let BufferType::Text(buffer) = buffer_type { + let mut new_buffer = Buffer { + rope: Rope::from(content), + rev, + language_id: buffer.language_id, + id: buffer.id, + path: buffer.path, + mod_time: buffer.mod_time, + }; + let result = new_buffer + .save(rev) + .map(|_| ProxyResponse::Success {}) + .map_err(|e| RpcError { + code: 0, + message: e.to_string(), + }); + self.buffers.insert(path, BufferType::Text(new_buffer)); + self.respond_rpc(id, result); + } } CreateFile { path } => { let result = path