file explorer mnvp, malvim fixes

also terminal ctrl+p and ctrl+n, error logging for the ipc windows, other fixes
This commit is contained in:
stjet
2024-12-20 08:39:58 +00:00
parent 3ed612752b
commit 606d8bf67f
7 changed files with 151 additions and 27 deletions

View File

@@ -1,6 +1,7 @@
use std::vec::Vec; use std::vec::Vec;
use std::vec; use std::vec;
use std::fs::read_dir; use std::fs::read_dir;
use std::path::PathBuf;
use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType }; use ming_wm::window_manager::{ DrawInstructions, WindowLike, WindowLikeType };
use ming_wm::messages::{ WindowMessage, WindowMessageResponse }; use ming_wm::messages::{ WindowMessage, WindowMessageResponse };
@@ -8,19 +9,32 @@ use ming_wm::framebuffer::Dimensions;
use ming_wm::themes::ThemeInfo; use ming_wm::themes::ThemeInfo;
use ming_wm::ipc::listen; use ming_wm::ipc::listen;
struct DirectoryChild {
//if some, use instead of file/dir name
override_name: Option<String>,
path: PathBuf,
is_file: bool,
//can only be true if dir
//if true, means the contents of this dir should be visible too, even though it isn't the current path. like a tree
tree_open: bool,
}
#[derive(Default)] #[derive(Default)]
pub struct FileExplorer { pub struct FileExplorer {
dimensions: Dimensions, dimensions: Dimensions,
current_path: String, current_path: PathBuf,
//current_dir_contents: current_dir_contents: Vec<DirectoryChild>,
//for scrolling and selecting dirs
position: usize,
} }
impl WindowLike for FileExplorer { impl WindowLike for FileExplorer {
fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse { fn handle_message(&mut self, message: WindowMessage) -> WindowMessageResponse {
match message { match message {
WindowMessage::Init(dimensions) => { WindowMessage::Init(dimensions) => {
self.current_path = "/".to_string(); self.current_path = PathBuf::from("/");
self.dimensions = dimensions; self.dimensions = dimensions;
self.current_dir_contents = self.get_current_dir_contents();
WindowMessageResponse::JustRerender WindowMessageResponse::JustRerender
}, },
WindowMessage::ChangeDimensions(dimensions) => { WindowMessage::ChangeDimensions(dimensions) => {
@@ -28,16 +42,68 @@ impl WindowLike for FileExplorer {
WindowMessageResponse::JustRerender WindowMessageResponse::JustRerender
}, },
WindowMessage::KeyPress(key_press) => { WindowMessage::KeyPress(key_press) => {
// if key_press.key == '𐘂' { //the enter key
if self.current_dir_contents.len() > 0 {
let selected_entry = &self.current_dir_contents[self.position];
if !selected_entry.is_file {
self.current_path = selected_entry.path.clone();
self.current_dir_contents = self.get_current_dir_contents();
self.position = 0;
return WindowMessageResponse::JustRerender;
}
}
WindowMessageResponse::DoNothing WindowMessageResponse::DoNothing
} else if key_press.key == 'j' {
//down
if self.position == self.current_dir_contents.len() - 1 {
self.position = 0;
} 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;
} else {
self.position -= 1;
}
WindowMessageResponse::JustRerender
} else {
WindowMessageResponse::DoNothing
}
}, },
_ => WindowMessageResponse::DoNothing, _ => WindowMessageResponse::DoNothing,
} }
} }
fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> { fn draw(&self, theme_info: &ThemeInfo) -> Vec<DrawInstructions> {
let mut instructions = Vec::new();
//top bar with path name and editing //top bar with path name and editing
vec![] //
//the actual files and directories
let mut start_y = 0;
let mut i = 0;
for entry in &self.current_dir_contents {
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));
}
//unwrap_or not used because "Arguments passed to unwrap_or are eagerly evaluated", apparently
let name = entry.override_name.clone();
let name = if name.is_none() {
entry.path.file_name().unwrap().to_os_string().into_string().unwrap()
} else {
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;
i += 1;
}
instructions
} }
fn title(&self) -> String { fn title(&self) -> String {
@@ -63,8 +129,26 @@ impl FileExplorer {
} }
//should include .. if not / //should include .. if not /
fn read_current_dir_contents(&self) { fn get_current_dir_contents(&self) -> Vec<DirectoryChild> {
// let mut contents = Vec::new();
if self.current_path != PathBuf::from("/") {
contents.push(DirectoryChild {
override_name: Some("..".to_string()),
is_file: false,
tree_open: false,
path: self.current_path.parent().unwrap().to_owned(),
});
}
contents.extend(read_dir(&self.current_path).unwrap().map(|entry| {
let path = entry.unwrap().path();
DirectoryChild {
override_name: None,
is_file: path.is_file(),
tree_open: false,
path,
}
}));
contents
} }
} }

View File

@@ -130,7 +130,7 @@ impl WindowLike for Malvim {
current_file.cursor_pos = spaces; current_file.cursor_pos = spaces;
} else if key_press.key == '𐘁' { //backspace } else if key_press.key == '𐘁' { //backspace
if current_length > 0 && current_file.cursor_pos > 0 { if current_length > 0 && current_file.cursor_pos > 0 {
current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos, 1); current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos - 1, 1);
current_file.cursor_pos -= 1; current_file.cursor_pos -= 1;
} else { } else {
if current_file.line_pos > 0 { if current_file.line_pos > 0 {
@@ -168,6 +168,7 @@ impl WindowLike for Malvim {
let new_length = current_file.content[current_file.line_pos].len(); let new_length = current_file.content[current_file.line_pos].len();
current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length); current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length);
} else if key_press.key == 'w' { } else if key_press.key == 'w' {
//todo: currently doesn't work on a single space?
let line = &current_file.content[current_file.line_pos]; let line = &current_file.content[current_file.line_pos];
if line.len() > 0 { if line.len() > 0 {
//offset until space or eol //offset until space or eol
@@ -192,11 +193,21 @@ impl WindowLike for Malvim {
} else if self.state == State::Find || self.state == State::BackFind { } else if self.state == State::Find || self.state == State::BackFind {
let old_pos = current_file.cursor_pos; let old_pos = current_file.cursor_pos;
let find_pos = if self.state == State::Find { let find_pos = if self.state == State::Find {
if old_pos < current_file.content[current_file.line_pos].len() {
old_pos + current_file.content[current_file.line_pos].chars().skip(old_pos + 1).position(|c| c == key_press.key).unwrap_or(0) + 1 old_pos + current_file.content[current_file.line_pos].chars().skip(old_pos + 1).position(|c| c == key_press.key).unwrap_or(0) + 1
} else { } else {
old_pos
}
} else {
//how does this work again? no idea
if old_pos != 0 {
old_pos - current_file.content[current_file.line_pos].chars().rev().skip(current_length - old_pos + 1).position(|c| c == key_press.key).unwrap_or(0) - 2 old_pos - current_file.content[current_file.line_pos].chars().rev().skip(current_length - old_pos + 1).position(|c| c == key_press.key).unwrap_or(0) - 2
} else {
old_pos //0
}
}; };
current_file.cursor_pos = find_pos; current_file.cursor_pos = find_pos;
changed = false;
self.state = State::None; self.state = State::None;
} else if key_press.key == 'x' { } else if key_press.key == 'x' {
if current_length > 0 && current_file.cursor_pos < current_length { if current_length > 0 && current_file.cursor_pos < current_length {
@@ -237,7 +248,7 @@ impl WindowLike for Malvim {
current_file.cursor_pos = current_file.content[current_file.line_pos].len(); current_file.cursor_pos = current_file.content[current_file.line_pos].len();
changed = false; changed = false;
} else if key_press.key == '^' { } else if key_press.key == '^' {
current_file.line_pos = current_file.content[current_file.line_pos].chars().position(|c| c != ' ').unwrap_or(0); current_file.cursor_pos = current_file.content[current_file.line_pos].chars().position(|c| c != ' ').unwrap_or(0);
changed = false; changed = false;
} else if key_press.key == 'r' { } else if key_press.key == 'r' {
self.state = State::Replace; self.state = State::Replace;
@@ -452,7 +463,7 @@ impl Malvim {
} else if first == "e" || first == "edit" || ((first == "t" || first == "tabe") && self.files.len() > 0) { } else if first == "e" || first == "edit" || ((first == "t" || first == "tabe") && self.files.len() > 0) {
//find the file and open it //find the file and open it
let mut failed = false; let mut failed = false;
let mut new_path = if self.files.len() > 0 { let mut new_path = if self.files.len() > 0 && !arg.starts_with("/") {
PathBuf::from(self.files[self.current_file_index].path.clone()).parent().unwrap().to_path_buf() PathBuf::from(self.files[self.current_file_index].path.clone()).parent().unwrap().to_path_buf()
} else { } else {
PathBuf::from("/") PathBuf::from("/")
@@ -509,6 +520,7 @@ impl Malvim {
let current_file = &self.files[self.current_file_index]; let current_file = &self.files[self.current_file_index];
let _ = write(&current_file.path, &current_file.content.join("\n")); let _ = write(&current_file.path, &current_file.content.join("\n"));
self.files[self.current_file_index].changed = false; self.files[self.current_file_index].changed = false;
self.bottom_message = Some("Written".to_string());
} else if first == "q" || first == "quit" { } else if first == "q" || first == "quit" {
self.files.remove(self.current_file_index); self.files.remove(self.current_file_index);
self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(0); self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(0);

View File

@@ -31,6 +31,7 @@ pub struct Terminal {
current_input: String, current_input: String,
current_path: String, current_path: String,
running_process: Option<Child>, running_process: Option<Child>,
last_command: Option<String>,
} }
//for some reason key presses, then moving the window leaves the old window still there, behind it. weird //for some reason key presses, then moving the window leaves the old window still there, behind it. weird
@@ -59,6 +60,7 @@ impl WindowLike for Terminal {
} }
} else if key_press.key == '𐘂' { //the enter key } else if key_press.key == '𐘂' { //the enter key
self.lines.push("$ ".to_string() + &self.current_input); self.lines.push("$ ".to_string() + &self.current_input);
self.last_command = Some(self.current_input.clone());
self.state = self.process_command(); self.state = self.process_command();
self.current_input = String::new(); self.current_input = String::new();
} else { } else {
@@ -96,6 +98,17 @@ impl WindowLike for Terminal {
let _ = self.running_process.take().unwrap().kill(); let _ = self.running_process.take().unwrap().kill();
self.state = State::Input; self.state = State::Input;
WindowMessageResponse::JustRerender WindowMessageResponse::JustRerender
} else if self.state == State::Input && (key_press.key == 'p' || key_press.key == 'n') {
//only the last command is saved unlike other terminals. good enough for me
if key_press.key == 'p' && self.last_command.is_some() {
self.current_input = self.last_command.clone().unwrap();
WindowMessageResponse::JustRerender
} else if key_press.key == 'n' {
self.current_input = String::new();
WindowMessageResponse::JustRerender
} else {
WindowMessageResponse::DoNothing
}
} else { } else {
WindowMessageResponse::DoNothing WindowMessageResponse::DoNothing
} }

View File

@@ -3,13 +3,9 @@ use std::io::{ Read, Write };
use ron; use ron;
use ming_wm::messages::WindowMessage;
fn main() { fn main() {
println!("{}", 'だ'); println!("{}", ron::to_string(&WindowMessage::Init([100,100])).unwrap());
println!("a");
let mut a = Command::new("cargo").arg("run").arg("-q").arg("--bin").arg("start_menu").stdout(Stdio::piped()).stdin(Stdio::piped()).stderr(Stdio::null()).spawn().unwrap();
a.stdin.unwrap().write_all("subtype\n".to_string().as_bytes());
let mut output = String::new();
let _ = a.stdout.as_mut().unwrap().read_to_string(&mut output);
println!("{}", output);
//println!("{}", &ron::to_string(&[122, 400]).unwrap()); //println!("{}", &ron::to_string(&[122, 400]).unwrap());
} }

View File

@@ -48,9 +48,9 @@ pub struct FramebufferWriter {
} }
impl FramebufferWriter { impl FramebufferWriter {
pub fn init(&mut self, info: FramebufferInfo, buffer_length: usize) { pub fn init(&mut self, info: FramebufferInfo) {
self.info = info; self.info = info;
self.buffer = vec![0; buffer_length]; self.buffer = vec![0; self.info.byte_len];
} }
pub fn get_info(&self) -> FramebufferInfo { pub fn get_info(&self) -> FramebufferInfo {
@@ -102,8 +102,10 @@ impl FramebufferWriter {
start_pos = ((top_left[1] + row + char_info.2 as usize) * self.info.stride + top_left[0]) * self.info.bytes_per_pixel; start_pos = ((top_left[1] + row + char_info.2 as usize) * self.info.stride + top_left[0]) * self.info.bytes_per_pixel;
for col in &char_info.1[row] { for col in &char_info.1[row] {
if col > &0 { if col > &0 {
if start_pos < self.info.byte_len {
self._draw_pixel(start_pos, color_with_alpha(color, bg_color, *col)); self._draw_pixel(start_pos, color_with_alpha(color, bg_color, *col));
} }
}
start_pos += self.info.bytes_per_pixel; start_pos += self.info.bytes_per_pixel;
} }
} }

View File

@@ -1,4 +1,5 @@
use std::io::{ stdin, BufRead }; use std::io::{ stdin, BufRead };
use std::panic;
//use serde::{ Deserialize, Serialize }; //use serde::{ Deserialize, Serialize };
use ron; use ron;
@@ -30,6 +31,20 @@ pub trait WindowLike {
const LOG: bool = false; const LOG: bool = false;
pub fn listen(mut window_like: impl WindowLike) { pub fn listen(mut window_like: impl WindowLike) {
panic::set_hook(Box::new(|panic_info| {
let (filename, line) = panic_info.location().map(|l| (l.file(), l.line())).unwrap_or(("<unknown>", 0));
let cause = if let Some(s) = panic_info.payload().downcast_ref::<&str>() {
format!("{:?}", s)
} else if let Some(s) = panic_info.payload().downcast_ref::<String>() {
format!("{:?}", s)
} else {
"panic occurred".to_string()
};
log(&format!("A panic occurred at {}:{}: {}", filename, line, cause));
}));
let stdin = stdin(); let stdin = stdin();
for line in stdin.lock().lines() { for line in stdin.lock().lines() {
let line = line.unwrap().clone(); let line = line.unwrap().clone();

View File

@@ -35,7 +35,7 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT); println!("bg: {}x{}", dimensions[0], dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT);
WRITER.lock().unwrap().init(framebuffer_info.clone(), framebuffer_info.height * framebuffer_info.stride * framebuffer_info.bytes_per_pixel); WRITER.lock().unwrap().init(framebuffer_info.clone());
let mut wm: WindowManager = WindowManager::new(framebuffer, dimensions); let mut wm: WindowManager = WindowManager::new(framebuffer, dimensions);
@@ -51,8 +51,8 @@ pub fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
for c in stdin.keys() { for c in stdin.keys() {
if let Some(kc) = key_to_char(c.unwrap()) { if let Some(kc) = key_to_char(c.unwrap()) {
//do not allow exit when locked unless debugging //do not allow exit when locked unless debugging
if kc == KeyChar::Alt('e') { //if kc == KeyChar::Alt('e') {
//if kc == KeyChar::Alt('e') && !wm.locked { if kc == KeyChar::Alt('e') && !wm.locked {
write!(stdout, "{}", cursor::Show).unwrap(); write!(stdout, "{}", cursor::Show).unwrap();
stdout.suspend_raw_mode().unwrap(); stdout.suspend_raw_mode().unwrap();
exit(0); exit(0);
@@ -454,6 +454,7 @@ impl WindowManager {
if let Some(focused_index) = self.get_focused_index() { if let Some(focused_index) = self.get_focused_index() {
let window_like = &self.window_infos[focused_index].window_like; let window_like = &self.window_infos[focused_index].window_like;
if window_like.subtype() == WindowLikeType::Window && window_like.resizable() { if window_like.subtype() == WindowLikeType::Window && window_like.resizable() {
self.window_infos[focused_index].fullscreen = false;
//full height, half width //full height, half width
self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT]; self.window_infos[focused_index].top_left = [0, INDICATOR_HEIGHT];
let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT]; let new_dimensions = [self.dimensions[0] / 2, self.dimensions[1] - INDICATOR_HEIGHT - TASKBAR_HEIGHT];
@@ -635,9 +636,10 @@ impl WindowManager {
framebuffer_info.width = window_width; framebuffer_info.width = window_width;
framebuffer_info.height = window_height; framebuffer_info.height = window_height;
framebuffer_info.stride = window_width; framebuffer_info.stride = window_width;
framebuffer_info.byte_len = window_width * window_height * bytes_per_pixel;
//make a writer just for the window //make a writer just for the window
let mut window_writer: FramebufferWriter = Default::default(); let mut window_writer: FramebufferWriter = Default::default();
window_writer.init(framebuffer_info, window_width * window_height * bytes_per_pixel); window_writer.init(framebuffer_info);
for instruction in instructions { for instruction in instructions {
//unsafe { SERIAL1.lock().write_text(&format!("{:?}\n", instruction)); } //unsafe { SERIAL1.lock().write_text(&format!("{:?}\n", instruction)); }
match instruction { match instruction {