From acdb59d668ff4c2ad26548a95b3cafb2afb4fa6c Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Fri, 27 Dec 2024 23:58:45 +0000 Subject: [PATCH] copy paste shortcuts, file explorer scrolling malvim find in file with / --- src/bin/file_explorer.rs | 46 ++++++++++++++++++++++++++-------------- src/bin/malvim.rs | 44 +++++++++++++++++++++++++++++++++++--- src/bin/terminal.rs | 6 +++++- src/messages.rs | 3 +++ src/window_manager.rs | 26 ++++++++++++++++++++++- 5 files changed, 104 insertions(+), 21 deletions(-) diff --git a/src/bin/file_explorer.rs b/src/bin/file_explorer.rs index 5cc620b..82d3605 100644 --- a/src/bin/file_explorer.rs +++ b/src/bin/file_explorer.rs @@ -9,6 +9,8 @@ use ming_wm::framebuffer::Dimensions; use ming_wm::themes::ThemeInfo; use ming_wm::ipc::listen; +const HEIGHT: usize = 20; + struct DirectoryChild { //if some, use instead of file/dir name override_name: Option, @@ -26,6 +28,7 @@ pub struct FileExplorer { current_dir_contents: Vec, //for scrolling and selecting dirs position: usize, + top_position: usize, } impl WindowLike for FileExplorer { @@ -49,25 +52,36 @@ impl WindowLike for FileExplorer { self.current_path = selected_entry.path.clone(); self.current_dir_contents = self.get_current_dir_contents(); self.position = 0; + self.top_position = 0; return WindowMessageResponse::JustRerender; } } WindowMessageResponse::DoNothing - } else if key_press.key == 'j' { - //down - if self.position == self.current_dir_contents.len() - 1 { - self.position = 0; + } else if key_press.key == 'j' || key_press.key == 'k' { + if key_press.key == 'j' { + //down + if self.position == self.current_dir_contents.len() - 1 { + self.position = 0; + } else { + self.position += 1; + } } else { - self.position += 1; + //up + if self.position == 0 { + self.position = self.current_dir_contents.len() - 1; + } else { + self.position -= 1; + } } - WindowMessageResponse::JustRerender - } else if key_press.key == 'k' { - //up - if self.position == 0 { - self.position = self.current_dir_contents.len() - 1; + //calculate position + if self.position > self.top_position { + let current_height = (self.position - self.top_position) * HEIGHT; + if current_height > self.dimensions[1] { + self.top_position += (current_height - self.dimensions[1]) / HEIGHT + 1; + } } else { - self.position -= 1; - } + self.top_position = self.position; + }; WindowMessageResponse::JustRerender } else { WindowMessageResponse::DoNothing @@ -83,14 +97,14 @@ impl WindowLike for FileExplorer { // //the actual files and directories let mut start_y = 0; - let mut i = 0; - for entry in &self.current_dir_contents { + let mut i = self.top_position; + for entry in self.current_dir_contents.iter().skip(self.top_position) { if start_y > self.dimensions[1] { break; } let is_selected = i == self.position; if is_selected { - instructions.push(DrawInstructions::Rect([0, start_y], [self.dimensions[0], 20], theme_info.top)); + instructions.push(DrawInstructions::Rect([0, start_y], [self.dimensions[0], HEIGHT], theme_info.top)); } //unwrap_or not used because "Arguments passed to unwrap_or are eagerly evaluated", apparently let name = entry.override_name.clone(); @@ -100,7 +114,7 @@ impl WindowLike for FileExplorer { name.unwrap() }; instructions.push(DrawInstructions::Text([5, start_y], vec!["times-new-roman".to_string(), "shippori-mincho".to_string()], name, if is_selected { theme_info.top_text } else { theme_info.text }, if is_selected { theme_info.top } else { theme_info.background }, None, None)); - start_y += 20; + start_y += HEIGHT; i += 1; } instructions diff --git a/src/bin/malvim.rs b/src/bin/malvim.rs index f4f37f1..b29f999 100644 --- a/src/bin/malvim.rs +++ b/src/bin/malvim.rs @@ -4,7 +4,7 @@ use std::fmt; use std::path::PathBuf; use std::fs::{ read_to_string, write }; -use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; +use ming_wm::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest, ShortcutType }; use ming_wm::themes::ThemeInfo; use ming_wm::framebuffer::Dimensions; use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; @@ -310,6 +310,33 @@ impl WindowLike for Malvim { self.dimensions = dimensions; WindowMessageResponse::JustRerender }, + WindowMessage::Shortcut(shortcut) => { + match shortcut { + ShortcutType::ClipboardCopy => { + if self.files.len() > 0 { + let current_file = &mut self.files[self.current_file_index]; + WindowMessageResponse::Request(WindowManagerRequest::ClipboardCopy(current_file.content[current_file.line_pos].clone())) + } else { + WindowMessageResponse::DoNothing + } + }, + ShortcutType::ClipboardPaste(copy_string) => { + if self.mode == Mode::Insert { + let current_file = &mut self.files[self.current_file_index]; + let line = ¤t_file.content[current_file.line_pos]; + current_file.content[current_file.line_pos] = line.substring(0, current_file.cursor_pos).to_string() + ©_string + line.substring(current_file.cursor_pos, line.len()); + current_file.cursor_pos += copy_string.len(); + self.calc_top_line_pos(); + self.calc_current(); //too over zealous but whatever + self.files[self.current_file_index].changed = true; + WindowMessageResponse::JustRerender + } else { + WindowMessageResponse::DoNothing + } + }, + _ => WindowMessageResponse::DoNothing, + } + }, _ => WindowMessageResponse::DoNothing, } } @@ -429,7 +456,7 @@ impl Malvim { //if not, move top_line_pos down until it is let current_file = &self.files[self.current_file_index]; let actual_line_pos = self.current.actual_lines.iter().position(|l| l.1 == current_file.line_pos).unwrap(); - if current_file.top_line_pos + self.current.max_lines < actual_line_pos { + if current_file.top_line_pos + self.current.max_lines <= actual_line_pos { self.files[self.current_file_index].top_line_pos = actual_line_pos.checked_sub(self.current.max_lines - 1).unwrap_or(0); } else if actual_line_pos < current_file.top_line_pos { self.files[self.current_file_index].top_line_pos = actual_line_pos; @@ -516,6 +543,17 @@ impl Malvim { } } else if self.files.len() == 0 { self.bottom_message = Some("No files are open, so can only do :e(dit)".to_string()); + } else if first.starts_with("/") { + let current_file = &mut self.files[self.current_file_index]; + if current_file.content.len() > 0 { + let found_line_no = current_file.content.iter().skip(current_file.line_pos + 1).position(|line| { + line.contains(&first[1..]) + }); + if let Some(found_line_no) = found_line_no { + current_file.line_pos = found_line_no + current_file.line_pos + 1; + current_file.cursor_pos = 0; + } + } } else if first == "w" || first == "write" { let current_file = &self.files[self.current_file_index]; let _ = write(¤t_file.path, ¤t_file.content.join("\n")); @@ -524,6 +562,7 @@ impl Malvim { } else if first == "q" || first == "quit" { self.files.remove(self.current_file_index); self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(0); + return true; } else if first == "p" || first == "tabp" { self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(self.files.len() - 1); return true; @@ -543,4 +582,3 @@ impl Malvim { pub fn main() { listen(Malvim::new()); } - diff --git a/src/bin/terminal.rs b/src/bin/terminal.rs index 33f2a24..eb68c0d 100644 --- a/src/bin/terminal.rs +++ b/src/bin/terminal.rs @@ -69,7 +69,7 @@ impl WindowLike for Terminal { self.calc_actual_lines(); self.actual_line_num = self.actual_lines.len().checked_sub(self.get_max_lines()).unwrap_or(0); WindowMessageResponse::JustRerender - } else { + } else if key_press.key.len_utf8() == 1 { //update let running_process = self.running_process.as_mut().unwrap(); if let Some(status) = running_process.try_wait().unwrap() { @@ -90,6 +90,10 @@ impl WindowLike for Terminal { //still running WindowMessageResponse::DoNothing } + } else { + //esc key (crash happens if esc key is entered and deleted, so prevent it from being entered) + //but if we want to support eg Chinese we need to properly handle multi-byte chars (todo) + WindowMessageResponse::DoNothing } }, WindowMessage::CtrlKeyPress(key_press) => { diff --git a/src/messages.rs b/src/messages.rs index 784d970..c604fcc 100644 --- a/src/messages.rs +++ b/src/messages.rs @@ -27,6 +27,7 @@ impl PartialEq for WindowBox { #[derive(PartialEq, Serialize, Deserialize)] pub enum WindowManagerRequest { OpenWindow(String), + ClipboardCopy(String), CloseStartMenu, Unlock, Lock, @@ -73,6 +74,8 @@ pub enum ShortcutType { CenterWindow, FullscreenWindow, HalfWidthWindow, //half width, full height + ClipboardCopy, + ClipboardPaste(String), // } diff --git a/src/window_manager.rs b/src/window_manager.rs index af57e26..fd3356d 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -23,6 +23,7 @@ use crate::essential::taskbar::Taskbar; use crate::essential::lock_screen::LockScreen; use crate::essential::workspace_indicator::WorkspaceIndicator; use crate::essential::start_menu::StartMenu; +use crate::logging::log; pub const TASKBAR_HEIGHT: usize = 38; pub const INDICATOR_HEIGHT: usize = 20; @@ -137,6 +138,7 @@ pub struct WindowManager { pub locked: bool, current_workspace: u8, framebuffer: Framebuffer, + clipboard: Option, } //1 is up, 2 is down @@ -152,6 +154,7 @@ impl WindowManager { locked: false, current_workspace: 0, framebuffer, + clipboard: None, }; wm.lock(); wm @@ -259,6 +262,8 @@ impl WindowManager { ('c', ShortcutType::CenterWindow), ('f', ShortcutType::FullscreenWindow), ('w', ShortcutType::HalfWidthWindow), + ('C', ShortcutType::ClipboardCopy), + ('P', ShortcutType::ClipboardPaste(String::new())), //move window a small amount ('h', ShortcutType::MoveWindow(Direction::Left)), ('j', ShortcutType::MoveWindow(Direction::Down)), @@ -464,6 +469,22 @@ impl WindowManager { } } }, + &ShortcutType::ClipboardCopy => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window { + press_response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardCopy)); + } + } + }, + &ShortcutType::ClipboardPaste(_) => { + if let Some(focused_index) = self.get_focused_index() { + let window_like = &self.window_infos[focused_index].window_like; + if window_like.subtype() == WindowLikeType::Window && self.clipboard.is_some() { + press_response = self.window_infos[focused_index].window_like.handle_message(WindowMessage::Shortcut(ShortcutType::ClipboardPaste(self.clipboard.clone().unwrap()))); + } + } + }, }; } } @@ -558,6 +579,10 @@ impl WindowManager { } self.lock(); }, + WindowManagerRequest::ClipboardCopy(content) => { + self.clipboard = Some(content); + log(&format!("{:?}", self.clipboard)); + }, }; } @@ -671,4 +696,3 @@ impl WindowManager { self.framebuffer.write_frame(WRITER.lock().unwrap().get_buffer()); } } -