From d32b82a2bbf0e502075f5ae5943dbbe72b3b34de Mon Sep 17 00:00:00 2001 From: stjet <49297268+stjet@users.noreply.github.com> Date: Thu, 17 Apr 2025 00:53:31 +0000 Subject: [PATCH] v1.0.3: mostly malvim improvements malvim: search, d$, %. fix w and m in mono font. apply some clippy lint suggestions --- Cargo.toml | 2 +- bmps/nimbus-romono/m4.bmp | Bin 470 -> 374 bytes bmps/nimbus-romono/w4.bmp | Bin 438 -> 374 bytes build.rs | 48 ++++++----- docs/system/shortcuts.md | 4 + docs/window-likes/malvim.md | 3 + ming-wm-lib/Cargo.toml | 2 +- ming-wm-lib/src/ipc.rs | 12 +-- ming-wm-lib/src/serialize.rs | 17 ++-- ming-wm-lib/src/themes.rs | 2 +- ming-wm-lib/src/utils.rs | 30 +++++-- src/bin/file_explorer.rs | 21 +++-- src/bin/main.rs | 4 +- src/bin/malvim.rs | 156 ++++++++++++++++++++++++++++++----- src/bin/minesweeper.rs | 6 +- src/bin/terminal.rs | 2 +- src/essential/start_menu.rs | 7 +- src/framebuffer.rs | 2 +- src/window_manager.rs | 8 +- 19 files changed, 233 insertions(+), 93 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1d51c57..fcb18be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ming-wm" -version = "1.0.2" +version = "1.0.3" repository = "https://github.com/stjet/ming-wm" license = "GPL-3.0-or-later" edition = "2021" diff --git a/bmps/nimbus-romono/m4.bmp b/bmps/nimbus-romono/m4.bmp index 10f3483a5818a04a61f570303a459e0bd2f45f81..b5147a5f10e6a06ac1dd005b9ca8286eb2b0c7d3 100644 GIT binary patch literal 374 zcmZ?rEn{Q=12Z700mNKD%mKuV3<^M!fx!VP59T0Vksz_J y5dQ_@C?IA6;uAo;1BgLxG6&)pP`9Q7+2?`S0En*v@eLpr1>)&I{1%7{LFxb&Nkw%4 literal 470 zcmci8!3se^6vpwnJBqAjrp!1e)ax cCFF6&+|>*@Z!tw5DIOT349)uv%{Elc8|*2IWB>pF diff --git a/bmps/nimbus-romono/w4.bmp b/bmps/nimbus-romono/w4.bmp index 8025c363ff9a5e65c88fddd2a2461b43aa076ea3..60574f8a8a380bdca0bc00d5c5bf5d47a6688003 100644 GIT binary patch literal 374 zcmYk%u?s;_6vy%NNJ;qzOhS^949qWOFfcLr11xXVGuRlVO#TiAGn)(+8BOAUu(`hX zb#C2TpL@^mymMdgbqDi6lGS0aA%`piDYA=%`aB7`8Dqp^6%cuONN%|7PI@t3Nb9{l z_0~OiC%qd^=p&CWj!1bkCGrnt>@dLtBZS`Ef_$}^wZa8U*xy@wb9ZvAb1iCnp{aR8 gok3mu741*SZ|@yrvi;_R&hci~s-t literal 438 zcmYk&KMR3T6vy%VlzI$eF)3w2%3zT)D7(QVC2xRLndB`fQ8JjsATk(O&C1&#gH55w z_v+j_w?6lt-?@K=Tdf^D^B+a#EFuWQGbv_chO++;G6g|k99li(RF07+F6))Pj~iC5 zPu;~E3D+1ZN we1|XlWor9&N3#94rPNXCCr0XipZq~w^`_)B7O-!vVgIj!2VQ8ZH@D>d53xpyDF6Tf diff --git a/build.rs b/build.rs index 829ffd1..9f598a4 100644 --- a/build.rs +++ b/build.rs @@ -15,34 +15,32 @@ fn font_chars_to_alphas(dir: &str) { if file_name.len() < 2 { continue; } - if file_name[1] == "bmp" { - if !path.is_dir() { - let mut ch: Vec> = Vec::new(); - let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap(); - let dib_header = b.get_dib_header().unwrap(); - let width = dib_header.width as usize; - let height = dib_header.height as usize; - for y in 0..height { - let mut row = Vec::new(); - for x in 0..width { - let pixel_color = b.get_color_of_px(x, y).unwrap(); - if pixel_color[3] == 0 { - //zeroes are just empty. eg 255,0,255 becomes 255,,255 - row.push(String::new()); - } else { - row.push(pixel_color[3].to_string()); //push alpha channel - } + if file_name[1] == "bmp" && !path.is_dir() { + let mut ch: Vec> = Vec::new(); + let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap(); + let dib_header = b.get_dib_header().unwrap(); + let width = dib_header.width as usize; + let height = dib_header.height as usize; + for y in 0..height { + let mut row = Vec::new(); + for x in 0..width { + let pixel_color = b.get_color_of_px(x, y).unwrap(); + if pixel_color[3] == 0 { + //zeroes are just empty. eg 255,0,255 becomes 255,,255 + row.push(String::new()); + } else { + row.push(pixel_color[3].to_string()); //push alpha channel } - ch.push(row); } - let ch: Vec = ch.into_iter().map(|row| { - row.join(",") - }).collect(); - let chars: Vec = file_name[0].chars().collect(); - File::create(dir.to_string() + "/" + &chars[0].to_string() + ".alpha").unwrap().write_all( - (chars[1].to_string() + "\n" + &ch.join("\n")).as_bytes() - ).unwrap(); + ch.push(row); } + let ch: Vec = ch.into_iter().map(|row| { + row.join(",") + }).collect(); + let chars: Vec = file_name[0].chars().collect(); + File::create(dir.to_string() + "/" + &chars[0].to_string() + ".alpha").unwrap().write_all( + (chars[1].to_string() + "\n" + &ch.join("\n")).as_bytes() + ).unwrap(); } } } diff --git a/docs/system/shortcuts.md b/docs/system/shortcuts.md index e194fcd..c63a4d5 100644 --- a/docs/system/shortcuts.md +++ b/docs/system/shortcuts.md @@ -16,5 +16,9 @@ - Alt+J: Move window to bottom edge - Alt+K: Move window to top edge - Alt+L: Move window to right edge +- Alt+n: Expand window width +- Alt+m: Expand window height +- Alt+N: Shrink window width +- Alt+M: Shrink window height - Alt+1, Alt+2, ..., Alt+[n], ..., Alt+9: Switch to workspace [n] - Alt+shift+1, Alt+shift+2, ..., Alt+shift+[n], ..., Alt+shift+9: Move window to workspace [n] diff --git a/docs/window-likes/malvim.md b/docs/window-likes/malvim.md index e52cee0..659bf8c 100644 --- a/docs/window-likes/malvim.md +++ b/docs/window-likes/malvim.md @@ -12,6 +12,7 @@ It is probably best to read a Vim tutorial for the basics. All supportd keystrok - `t[abe] `, `[tab]n`, `[tab]p` - `q[uit]` - `w[rite]` +- `/` Tab completion is supported for the `` argument. @@ -23,6 +24,7 @@ Tab completion is supported for the `` argument. - `r` - `dd` - `dw` +- `d$` - `G` - `gg` - `gg` @@ -32,6 +34,7 @@ Tab completion is supported for the `` argument. - `h` (or left arrow), `j` (or down arrow), `k` (or up arrow), `l` (or right arrow) - `h`, `j` (or down arrow), `k` (or up arrow), `l` - `0`, `^`, `$` +- `%` ### Malvim Specific diff --git a/ming-wm-lib/Cargo.toml b/ming-wm-lib/Cargo.toml index ba016f7..99c25f9 100644 --- a/ming-wm-lib/Cargo.toml +++ b/ming-wm-lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ming-wm-lib" -version = "0.1.5" +version = "0.1.6" repository = "https://github.com/stjet/ming-wm" description = "library for building windows for ming-wm in rust" readme = "README.md" diff --git a/ming-wm-lib/src/ipc.rs b/ming-wm-lib/src/ipc.rs index d4b1484..7b7772e 100644 --- a/ming-wm-lib/src/ipc.rs +++ b/ming-wm-lib/src/ipc.rs @@ -58,22 +58,22 @@ pub fn listen(mut window_like: impl WindowLike) { let arg = &parts.collect::>().join(" "); let output = match method { "handle_message" => { - format!("{}", &window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize()) + window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize().to_string() }, "draw" => { - format!("{}", &window_like.draw(&ThemeInfo::deserialize(arg).unwrap()).serialize().replace("\n", "")) + window_like.draw(&ThemeInfo::deserialize(arg).unwrap()).serialize().replace("\n", "").to_string() }, "title" => { - format!("{}", window_like.title()) + window_like.title().to_string() }, "resizable" => { - format!("{}", window_like.resizable()) + window_like.resizable().to_string() }, "subtype" => { - format!("{}", &window_like.subtype().serialize()) + window_like.subtype().serialize().to_string() }, "ideal_dimensions" => { - format!("{}", &window_like.ideal_dimensions(Dimensions::deserialize(arg).unwrap()).serialize()) + window_like.ideal_dimensions(Dimensions::deserialize(arg).unwrap()).serialize().to_string() }, _ => String::new(), }; diff --git a/ming-wm-lib/src/serialize.rs b/ming-wm-lib/src/serialize.rs index d953d2b..b2aaf4d 100644 --- a/ming-wm-lib/src/serialize.rs +++ b/ming-wm-lib/src/serialize.rs @@ -39,10 +39,10 @@ fn option_to_string(option: &Option) -> String { fn get_color(serialized: &str) -> Result<[u8; 3], ()> { let rgb = serialized.split("\x1F"); let mut color = [0; 3]; - let mut c_i = 0; //won't return error if rgb is 0, 1, or 2 elements. //I guess that's okay, since it doesn't panic either - for c in rgb { + //c_i is the loop counter. enumerate(), you are awesome + for (c_i, c) in rgb.enumerate() { if c_i == 3 { return Err(()); } @@ -51,7 +51,6 @@ fn get_color(serialized: &str) -> Result<[u8; 3], ()> { } else { return Err(()); } - c_i += 1; } Ok(color) } @@ -68,7 +67,7 @@ fn get_two_array(serialized: &str) -> Result<[usize; 2], ()> { } return Err(()); } - return Ok(a); + Ok(a) } pub trait Serializable { @@ -87,9 +86,8 @@ impl Serializable for ThemeInfo { let serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized }; let mut theme_info: ThemeInfo = Default::default(); let arrays = serialized.split(":"); - let mut a_i = 0; //won't error or panic if less than 9... rest will just be black by default I guess - for a in arrays { + for (a_i, a) in arrays.enumerate() { if a_i == 9 { return Err(()); } @@ -127,7 +125,6 @@ impl Serializable for ThemeInfo { if a_i == 8 { return Ok(theme_info); } - a_i += 1; } Err(()) } @@ -220,7 +217,7 @@ impl Serializable for DrawInstructions { match self { //use \x1E (record separator) because it won't be in strings. it better fucking not be at least DrawInstructions::Rect(p, d, c) => format!("Rect/{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c)), - DrawInstructions::Text(p, vs, s, c1, c2, ou1, ou2) => format!("Text/{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(&vs), s, array_to_string(c1), array_to_string(c2), option_to_string(ou1), option_to_string(ou2)), + DrawInstructions::Text(p, vs, s, c1, c2, ou1, ou2) => format!("Text/{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(vs), s, array_to_string(c1), array_to_string(c2), option_to_string(ou1), option_to_string(ou2)), DrawInstructions::Gradient(p, d, c1, c2, u) => format!("Gradient/{}\x1E{}\x1E{}\x1E{}\x1E{}", array_to_string(p), array_to_string(d), array_to_string(c1), array_to_string(c2), u), DrawInstructions::Bmp(p, s, b) => format!("Bmp/{}\x1E{}\x1E{}", array_to_string(p), s, b), DrawInstructions::Circle(p, u, c) => format!("Circle/{}\x1E{}\x1E{}", array_to_string(p), u, array_to_string(c)), @@ -674,8 +671,7 @@ impl Serializable for WindowMessage { } let mut w_tuple: (usize, String) = Default::default(); let mut w_vec = Vec::new(); - let mut i = 0; - for a in arg2.unwrap().split("\x1F") { + for (i, a) in arg2.unwrap().split("\x1F").enumerate() { if i % 2 == 0 { if let Ok(n) = a.parse() { w_tuple.0 = n; @@ -684,7 +680,6 @@ impl Serializable for WindowMessage { w_tuple.1 = a.to_string(); w_vec.push(w_tuple.clone()); } - i += 1; } let arg2 = parts2.next(); if arg2.is_none() { diff --git a/ming-wm-lib/src/themes.rs b/ming-wm-lib/src/themes.rs index 28b9976..32fd8b7 100644 --- a/ming-wm-lib/src/themes.rs +++ b/ming-wm-lib/src/themes.rs @@ -104,6 +104,6 @@ pub fn get_theme_info(theme: &Themes) -> Option { return Some(pair.1); } } - return None; + None } diff --git a/ming-wm-lib/src/utils.rs b/ming-wm-lib/src/utils.rs index 1e2aa20..e32a4d8 100644 --- a/ming-wm-lib/src/utils.rs +++ b/ming-wm-lib/src/utils.rs @@ -11,6 +11,7 @@ pub trait Substring { fn substring(&self, start: usize, end: usize) -> &str; fn remove(&self, index: usize, len: usize) -> String; fn remove_last(&self) -> String; + fn find_substring(&self, substr: &str) -> Option; } impl Substring for String { @@ -29,6 +30,14 @@ impl Substring for String { byte_end += char_length; } &self[byte_start..byte_end] + /* + let mut result = String::new(); + let mut chars = self.chars().skip(start); + for _i in 0..(end - start) { + result += &chars.next().unwrap().to_string(); + } + result + */ } fn remove(&self, index: usize, len: usize) -> String { @@ -38,13 +47,26 @@ impl Substring for String { fn remove_last(&self) -> String { self.substring(0, self.chars().count() - 1).to_string() } + + fn find_substring(&self, substr: &str) -> Option { + //slightly inefficient + let substr_len = substr.chars().count(); + let self_len = self.chars().count(); + if substr_len <= self_len { + for start in 0..=(self_len - substr_len) { + if self.substring(start, start + substr_len) == substr { + return Some(start); + } + } + } + None + } } //the tuple is first, line #, actual line pub fn calc_actual_lines<'a>(lines: impl Iterator, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> { let mut actual_lines = Vec::new(); - let mut line_num = 0; - for real_line in lines { + for (line_num, real_line) in lines.enumerate() { let mut line = real_line.to_string() + if one_extra { " " } else { "" }; let mut first = true; loop { @@ -62,7 +84,6 @@ pub fn calc_actual_lines<'a>(lines: impl Iterator, max_chars_ } first = false; } - line_num += 1; } actual_lines } @@ -132,7 +153,7 @@ pub fn hex_to_u8(c1: char, c2: char) -> u8 { } pub fn is_hex(c: char) -> bool { - HEX_CHARS.iter().position(|hc| hc == &c).is_some() + HEX_CHARS.iter().any(|hc| hc == &c) } pub fn point_inside(point: Point, top_left: Point, size: Dimensions) -> bool { @@ -193,4 +214,3 @@ pub fn path_autocomplete(current_path: &str, partial_path: &str) -> Option { - self.state = State::List; - if key_press.is_enter() { + if key_press.is_enter() && self.state == State::List { if self.current_dir_contents.len() > 0 { let selected_entry = &self.current_dir_contents[self.position]; if !selected_entry.is_file { @@ -75,6 +74,7 @@ impl WindowLike for FileExplorer { } WindowMessageResponse::DoNothing } else if key_press.key == 'j' || key_press.is_down_arrow() || key_press.key == 'k' || key_press.is_up_arrow() { + self.state = State::List; if key_press.key == 'j' || key_press.is_down_arrow() { //down if self.position == self.current_dir_contents.len() - 1 { @@ -103,12 +103,21 @@ impl WindowLike for FileExplorer { }; WindowMessageResponse::JustRedraw } else if key_press.key == 'i' { - self.state = State::Info; - let selected_entry = &self.current_dir_contents[self.position]; - self.metadata = Some(metadata(&selected_entry.path).unwrap()); + if self.state == State::Info { + self.state = State::List; + } else { + self.state = State::Info; + let selected_entry = &self.current_dir_contents[self.position]; + self.metadata = Some(metadata(&selected_entry.path).unwrap()); + } WindowMessageResponse::JustRedraw } else { - WindowMessageResponse::DoNothing + if self.state == State::Info { + self.state = State::List; + WindowMessageResponse::JustRedraw + } else { + WindowMessageResponse::DoNothing + } } }, _ => WindowMessageResponse::DoNothing, diff --git a/src/bin/main.rs b/src/bin/main.rs index 74ff82f..4c09208 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -116,10 +116,10 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) { let mut y: Option = None; for line in reader.lines() { let line = line.unwrap(); - if line.contains(&"ABS_X), value ") || line.contains(&"ABS_Y), value ") { + if line.contains("ABS_X), value ") || line.contains("ABS_Y), value ") { let value: Vec<_> = line.split("), value ").collect(); let value = value[value.len() - 1].parse::().unwrap(); - if line.contains(&"ABS_X") { + if line.contains("ABS_X") { x = Some(value); } else { y = Some(value); diff --git a/src/bin/malvim.rs b/src/bin/malvim.rs index fff1d77..96bbca6 100644 --- a/src/bin/malvim.rs +++ b/src/bin/malvim.rs @@ -2,6 +2,7 @@ use std::vec::Vec; use std::vec; use std::fmt; use std::path::PathBuf; +use std::collections::HashMap; use std::fs::{ read_to_string, write }; use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest, ShortcutType }; @@ -10,7 +11,7 @@ use ming_wm_lib::framebuffer_types::Dimensions; use ming_wm_lib::window_manager_types::{ DrawInstructions, WindowLike, WindowLikeType }; use ming_wm_lib::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring }; use ming_wm_lib::dirs::home; -use ming_wm_lib::utils::path_autocomplete; +use ming_wm_lib::utils::{ get_rest_of_split, path_autocomplete }; use ming_wm_lib::ipc::listen; const MONO_WIDTH: u8 = 10; @@ -175,18 +176,23 @@ impl WindowLike for Malvim { } let new_length = current_file.content[current_file.line_pos].chars().count(); 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' || key_press.key == '$' { let line = ¤t_file.content[current_file.line_pos]; let line_len = line.chars().count(); if line_len > 0 && current_file.cursor_pos < line_len { //offset until space or eol let mut line_chars = line.chars().skip(current_file.cursor_pos).peekable(); - let current_char = line_chars.peek().unwrap().clone(); - let offset = line_chars.position(|c| if current_char == ' ' { - c != ' ' + //deref is Copy + let current_char = *line_chars.peek().unwrap(); + let offset = if key_press.key == 'w' { + line_chars.position(|c| if current_char == ' ' { + c != ' ' + } else { + c == ' ' + }).unwrap_or(line_len - current_file.cursor_pos) } else { - c == ' ' - }).unwrap_or(line_len - current_file.cursor_pos); + line_chars.count() + }; current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos, offset); let new_length = current_file.content[current_file.line_pos].chars().count(); current_file.cursor_pos = calc_new_cursor_pos(current_file.cursor_pos, new_length); @@ -240,6 +246,8 @@ impl WindowLike for Malvim { if current_length == 1 { current_file.cursor_pos = 0; } + } else { + changed = false; } } else if key_press.key == 'h' || key_press.is_left_arrow() { current_file.cursor_pos = current_file.cursor_pos.checked_sub(self.maybe_num.unwrap_or(1)).unwrap_or(0); @@ -295,7 +303,88 @@ impl WindowLike for Malvim { } else if key_press.key == 'F' { self.state = State::BackFind; changed = false; - } else if key_press.key.is_digit(10) { + } else if key_press.key == '%' { + let current_l = ¤t_file.content[current_file.line_pos]; + if current_file.cursor_pos < current_l.len() { + let current_c = current_l.chars().nth(current_file.cursor_pos).unwrap(); + let pairs = HashMap::from([ + ('(', (')', true)), + (')', ('(', false)), + ('[', (']', true)), + (']', ('[', false)), + ('"', ('"', true)), //could be either, really + ('{', ('}', true)), + ('}', ('{', false)), + ('<', ('>', true)), + ('>', ('<', false)), + // + ]); + if let Some((corres, forwards)) = pairs.get(¤t_c) { + let mut count = 0; + let content_len = current_file.content.len(); + let lines: Vec<&String> = if *forwards { + current_file.content.iter().skip(current_file.line_pos).collect() + } else { + current_file.content.iter().rev().skip(content_len - current_file.line_pos - 1).collect() + }; + let end = if *forwards { + content_len - current_file.line_pos + } else { + current_file.line_pos + 1 + }; + 'outer: for i in 0..end { + let line = if i == 0 { + let l = lines[i]; + let l_len = l.len(); + if *forwards { + if current_file.cursor_pos + 1 < l_len { + l.substring(current_file.cursor_pos + 1, l_len) + } else { + "" + } + } else { + &l.substring(0, current_file.cursor_pos).chars().rev().collect::() + } + } else { + if *forwards { + lines[i] + } else { + &lines[i].chars().rev().collect::() + } + }; + for (c_i, c) in line.chars().enumerate() { + if c == current_c { + count += 1; + } else if &c == corres { + if count == 0 { + if *forwards { + current_file.line_pos += i; + } else { + current_file.line_pos -= i; + }; + current_file.cursor_pos = if i == 0 { + if *forwards { + current_file.cursor_pos + c_i + 1 + } else { + current_file.cursor_pos - c_i - 1 + } + } else { + if *forwards { + c_i + } else { + line.chars().count() - c_i - 1 + } + }; + break 'outer; + } + count -= 1; + } + } + } + } + } + changed = false; + } else if key_press.key.is_ascii_digit() { self.maybe_num = Some(self.maybe_num.unwrap_or(0) * 10 + key_press.key.to_digit(10).unwrap() as usize); numbered = true; changed = false; @@ -401,7 +490,7 @@ impl WindowLike for Malvim { let mut used_width = 0; for file_index in 0..self.files.len() { let file_info = &self.files[file_index]; - let future_used_width = used_width + 4 + (file_info.name.len() + if file_info.changed { 2 } else { 0 }) * MONO_WIDTH as usize; + let future_used_width = used_width + 4 + (file_info.name.len() + if file_info.changed { 2 } else { 0 }) * MONO_WIDTH as usize + 15; //just cut off when too many file tabs open to fit if future_used_width > self.dimensions[0] { break; @@ -455,12 +544,11 @@ impl WindowLike for Malvim { //bottom blue band stuff //write mode instructions.push(DrawInstructions::Text([0, self.dimensions[1] - BAND_HEIGHT * 2 + 2], vec!["nimbus-romono".to_string()], self.mode.to_string(), theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); - let file_status; - if self.files.len() > 0 { - file_status = self.files[self.current_file_index].name.clone(); + let file_status = if self.files.len() > 0 { + self.files[self.current_file_index].name.clone() } else { - file_status = "No file open".to_string(); - } + "No file open".to_string() + }; instructions.push(DrawInstructions::Text([self.dimensions[0] - file_status.len() * (MONO_WIDTH as usize), self.dimensions[1] - BAND_HEIGHT * 2 + 2], vec!["nimbus-romono".to_string()], file_status, theme_info.top_text, theme_info.top, Some(0), Some(MONO_WIDTH))); //write command or bottom message if self.mode == Mode::Command { @@ -593,12 +681,40 @@ impl Malvim { } 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; + let p1 = if arg == "" { + String::new() + } else { + " ".to_string() + arg + }; + let rest = get_rest_of_split(&mut parts, Some(" ")); + let rest = if rest == "" { + String::new() + } else { + " ".to_string() + &rest + }; + let query = first[1..].to_string() + &p1 + &rest; + let mut lines = current_file.content.iter().skip(current_file.line_pos); + for i in 0..(current_file.content.len() - current_file.line_pos) { + let line = if i == 0 { + let l = lines.next().unwrap(); + let l_len = l.len(); + if (current_file.cursor_pos + 1) < l_len { + l.substring(current_file.cursor_pos + 1, l_len) + } else { + "" + } + } else { + lines.next().unwrap() + }; + if let Some(found_index) = line.to_string().find_substring(&query) { + current_file.line_pos += i; + current_file.cursor_pos = if i == 0 { + current_file.cursor_pos + found_index + 1 + } else { + found_index + }; + break; + } } } } else if first == "x" || first == "w" || first == "write" || first == "q" || first == "quit" { diff --git a/src/bin/minesweeper.rs b/src/bin/minesweeper.rs index 541869f..7994f48 100644 --- a/src/bin/minesweeper.rs +++ b/src/bin/minesweeper.rs @@ -65,15 +65,15 @@ impl WindowLike for Minesweeper { self.first_char = '\0'; WindowMessageResponse::DoNothing } else if self.first_char == '\0' { - if HEX_CHARS.iter().find(|c| c == &&key_press.key).is_some() { + if HEX_CHARS.iter().any(|c| c == &key_press.key) { self.first_char = key_press.key; } WindowMessageResponse::DoNothing - } else if HEX_CHARS.iter().find(|c| c == &&key_press.key).is_some() { + } else if HEX_CHARS.iter().any(|c| c == &key_press.key) { let u = hex_to_u8(self.first_char, key_press.key) as usize; let y = u / 16; let x = u % 16; - if HEX_CHARS.iter().find(|c| c == &&key_press.key).is_some() { + if HEX_CHARS.iter().any(|c| c == &key_press.key) { if self.state == State::BeforePlaying { loop { self.new_tiles(); diff --git a/src/bin/terminal.rs b/src/bin/terminal.rs index 97b43cc..c87f249 100644 --- a/src/bin/terminal.rs +++ b/src/bin/terminal.rs @@ -131,7 +131,7 @@ impl WindowLike for Terminal { self.prev(); } else if key_press.is_down_arrow() { self.next(); - } else { + } else if key_press.is_regular() { self.current_input += &key_press.key.to_string(); } self.calc_actual_lines(); diff --git a/src/essential/start_menu.rs b/src/essential/start_menu.rs index 092c0ef..30e517b 100644 --- a/src/essential/start_menu.rs +++ b/src/essential/start_menu.rs @@ -115,13 +115,11 @@ impl WindowLike for StartMenu { ]; let max_per_page = CATEGORIES.len(); let current_focus = self.get_focus_index().unwrap(); - let mut index = 0; - for component in &self.components { + for (index, component) in self.components.iter().enumerate() { //supports multiple pages of window options per category if (index >= max_per_page && current_focus >= max_per_page) || (index < max_per_page && current_focus < max_per_page) { instructions.extend(component.draw(theme_info)); } - index += 1; } instructions } @@ -194,8 +192,7 @@ impl StartMenu { pub fn add_category_components(&mut self) { self.current_focus = "About".to_string(); self.components = Vec::new(); - for c in 0..CATEGORIES.len() { - let name = CATEGORIES[c]; + for (c, name) in CATEGORIES.iter().enumerate() { self.components.push(Box::new(HighlightButton::new( name.to_string(), [42, self.y_each * c + 1], [self.dimensions[0] - 42 - 1, self.y_each], name.to_string(), StartMenuMessage::CategoryClick(name), StartMenuMessage::ChangeAcknowledge, c == 0 ))); diff --git a/src/framebuffer.rs b/src/framebuffer.rs index 9a662e8..85de2cd 100644 --- a/src/framebuffer.rs +++ b/src/framebuffer.rs @@ -89,7 +89,7 @@ impl FramebufferWriter { } } self.rotate_buffer = Some(output_array); - &self.rotate_buffer.as_ref().unwrap() + self.rotate_buffer.as_ref().unwrap() } pub fn save_buffer(&mut self) { diff --git a/src/window_manager.rs b/src/window_manager.rs index c50c5b1..0b5d09c 100644 --- a/src/window_manager.rs +++ b/src/window_manager.rs @@ -95,7 +95,7 @@ impl WindowManager { pub fn add_window_like(&mut self, mut window_like: Box, top_left: Point, dimensions: Option) { let subtype = window_like.subtype(); let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions)); - self.id_count = self.id_count + 1; + self.id_count += 1; let id = self.id_count; window_like.handle_message(WindowMessage::Init(dimensions)); let dimensions = if subtype == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { dimensions }; @@ -154,7 +154,7 @@ impl WindowManager { file.read_to_string(&mut contents).unwrap(); let lines: Vec<&str> = contents.split("\n").collect(); if lines.len() > self.current_workspace.into() { - self.theme = Themes::from_str(lines[self.current_workspace as usize]).unwrap_or(Default::default()); + self.theme = Themes::from_str(lines[self.current_workspace as usize]).unwrap_or_default(); } } } @@ -667,8 +667,7 @@ impl WindowManager { }); //these are needed to decide when to snapshot let max_index = if redraw_ids.len() > 0 { redraw_ids.len() } else { maybe_length } - 1; - let mut w_index = 0; - for window_info in redraw_windows { + for (w_index, window_info) in redraw_windows.enumerate() { let window_dimensions = if window_info.fullscreen { [self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT] } else { @@ -746,7 +745,6 @@ impl WindowManager { } } self.writer.borrow_mut().draw_buffer(window_info.top_left, window_dimensions[1], window_dimensions[0] * bytes_per_pixel, &window_writer.get_buffer()); - w_index += 1; } //could probably figure out a way to do borrow() when self.rotate is false but does it matter? let mut writer_borrow = self.writer.borrow_mut();