Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d32b82a2bb |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ming-wm"
|
name = "ming-wm"
|
||||||
version = "1.0.2"
|
version = "1.0.3"
|
||||||
repository = "https://github.com/stjet/ming-wm"
|
repository = "https://github.com/stjet/ming-wm"
|
||||||
license = "GPL-3.0-or-later"
|
license = "GPL-3.0-or-later"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 470 B After Width: | Height: | Size: 374 B |
Binary file not shown.
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 374 B |
48
build.rs
48
build.rs
@@ -15,34 +15,32 @@ fn font_chars_to_alphas(dir: &str) {
|
|||||||
if file_name.len() < 2 {
|
if file_name.len() < 2 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if file_name[1] == "bmp" {
|
if file_name[1] == "bmp" && !path.is_dir() {
|
||||||
if !path.is_dir() {
|
let mut ch: Vec<Vec<String>> = Vec::new();
|
||||||
let mut ch: Vec<Vec<String>> = Vec::new();
|
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap();
|
||||||
let b = BMP::new_from_file(&path.clone().into_os_string().into_string().unwrap()).unwrap();
|
let dib_header = b.get_dib_header().unwrap();
|
||||||
let dib_header = b.get_dib_header().unwrap();
|
let width = dib_header.width as usize;
|
||||||
let width = dib_header.width as usize;
|
let height = dib_header.height as usize;
|
||||||
let height = dib_header.height as usize;
|
for y in 0..height {
|
||||||
for y in 0..height {
|
let mut row = Vec::new();
|
||||||
let mut row = Vec::new();
|
for x in 0..width {
|
||||||
for x in 0..width {
|
let pixel_color = b.get_color_of_px(x, y).unwrap();
|
||||||
let pixel_color = b.get_color_of_px(x, y).unwrap();
|
if pixel_color[3] == 0 {
|
||||||
if pixel_color[3] == 0 {
|
//zeroes are just empty. eg 255,0,255 becomes 255,,255
|
||||||
//zeroes are just empty. eg 255,0,255 becomes 255,,255
|
row.push(String::new());
|
||||||
row.push(String::new());
|
} else {
|
||||||
} else {
|
row.push(pixel_color[3].to_string()); //push alpha channel
|
||||||
row.push(pixel_color[3].to_string()); //push alpha channel
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ch.push(row);
|
|
||||||
}
|
}
|
||||||
let ch: Vec<String> = ch.into_iter().map(|row| {
|
ch.push(row);
|
||||||
row.join(",")
|
|
||||||
}).collect();
|
|
||||||
let chars: Vec<char> = 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();
|
|
||||||
}
|
}
|
||||||
|
let ch: Vec<String> = ch.into_iter().map(|row| {
|
||||||
|
row.join(",")
|
||||||
|
}).collect();
|
||||||
|
let chars: Vec<char> = 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,5 +16,9 @@
|
|||||||
- Alt+J: Move window to bottom edge
|
- Alt+J: Move window to bottom edge
|
||||||
- Alt+K: Move window to top edge
|
- Alt+K: Move window to top edge
|
||||||
- Alt+L: Move window to right 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+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]
|
- Alt+shift+1, Alt+shift+2, ..., Alt+shift+[n], ..., Alt+shift+9: Move window to workspace [n]
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ It is probably best to read a Vim tutorial for the basics. All supportd keystrok
|
|||||||
- `t[abe] <file>`, `[tab]n`, `[tab]p`
|
- `t[abe] <file>`, `[tab]n`, `[tab]p`
|
||||||
- `q[uit]`
|
- `q[uit]`
|
||||||
- `w[rite]`
|
- `w[rite]`
|
||||||
|
- `/<query>`
|
||||||
|
|
||||||
Tab completion is supported for the `<file>` argument.
|
Tab completion is supported for the `<file>` argument.
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ Tab completion is supported for the `<file>` argument.
|
|||||||
- `r`
|
- `r`
|
||||||
- `dd`
|
- `dd`
|
||||||
- `dw`
|
- `dw`
|
||||||
|
- `d$`
|
||||||
- `G`
|
- `G`
|
||||||
- `gg`
|
- `gg`
|
||||||
- `<number>gg`
|
- `<number>gg`
|
||||||
@@ -32,6 +34,7 @@ Tab completion is supported for the `<file>` argument.
|
|||||||
- `h` (or left arrow), `j` (or down arrow), `k` (or up arrow), `l` (or right arrow)
|
- `h` (or left arrow), `j` (or down arrow), `k` (or up arrow), `l` (or right arrow)
|
||||||
- `<num>h`, `<num>j` (or down arrow), `<num>k` (or up arrow), `<num>l`
|
- `<num>h`, `<num>j` (or down arrow), `<num>k` (or up arrow), `<num>l`
|
||||||
- `0`, `^`, `$`
|
- `0`, `^`, `$`
|
||||||
|
- `%`
|
||||||
|
|
||||||
### Malvim Specific
|
### Malvim Specific
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "ming-wm-lib"
|
name = "ming-wm-lib"
|
||||||
version = "0.1.5"
|
version = "0.1.6"
|
||||||
repository = "https://github.com/stjet/ming-wm"
|
repository = "https://github.com/stjet/ming-wm"
|
||||||
description = "library for building windows for ming-wm in rust"
|
description = "library for building windows for ming-wm in rust"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|||||||
@@ -58,22 +58,22 @@ pub fn listen(mut window_like: impl WindowLike) {
|
|||||||
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
let arg = &parts.collect::<Vec<&str>>().join(" ");
|
||||||
let output = match method {
|
let output = match method {
|
||||||
"handle_message" => {
|
"handle_message" => {
|
||||||
format!("{}", &window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize())
|
window_like.handle_message(WindowMessage::deserialize(arg).unwrap()).serialize().to_string()
|
||||||
},
|
},
|
||||||
"draw" => {
|
"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" => {
|
"title" => {
|
||||||
format!("{}", window_like.title())
|
window_like.title().to_string()
|
||||||
},
|
},
|
||||||
"resizable" => {
|
"resizable" => {
|
||||||
format!("{}", window_like.resizable())
|
window_like.resizable().to_string()
|
||||||
},
|
},
|
||||||
"subtype" => {
|
"subtype" => {
|
||||||
format!("{}", &window_like.subtype().serialize())
|
window_like.subtype().serialize().to_string()
|
||||||
},
|
},
|
||||||
"ideal_dimensions" => {
|
"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(),
|
_ => String::new(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ fn option_to_string<T: Display>(option: &Option<T>) -> String {
|
|||||||
fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
||||||
let rgb = serialized.split("\x1F");
|
let rgb = serialized.split("\x1F");
|
||||||
let mut color = [0; 3];
|
let mut color = [0; 3];
|
||||||
let mut c_i = 0;
|
|
||||||
//won't return error if rgb is 0, 1, or 2 elements.
|
//won't return error if rgb is 0, 1, or 2 elements.
|
||||||
//I guess that's okay, since it doesn't panic either
|
//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 {
|
if c_i == 3 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,6 @@ fn get_color(serialized: &str) -> Result<[u8; 3], ()> {
|
|||||||
} else {
|
} else {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
c_i += 1;
|
|
||||||
}
|
}
|
||||||
Ok(color)
|
Ok(color)
|
||||||
}
|
}
|
||||||
@@ -68,7 +67,7 @@ fn get_two_array(serialized: &str) -> Result<[usize; 2], ()> {
|
|||||||
}
|
}
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
return Ok(a);
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Serializable {
|
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 serialized = if serialized.ends_with("\n") { &serialized[..serialized.len() - 1] } else { serialized };
|
||||||
let mut theme_info: ThemeInfo = Default::default();
|
let mut theme_info: ThemeInfo = Default::default();
|
||||||
let arrays = serialized.split(":");
|
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
|
//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 {
|
if a_i == 9 {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
@@ -127,7 +125,6 @@ impl Serializable for ThemeInfo {
|
|||||||
if a_i == 8 {
|
if a_i == 8 {
|
||||||
return Ok(theme_info);
|
return Ok(theme_info);
|
||||||
}
|
}
|
||||||
a_i += 1;
|
|
||||||
}
|
}
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
@@ -220,7 +217,7 @@ impl Serializable for DrawInstructions {
|
|||||||
match self {
|
match self {
|
||||||
//use \x1E (record separator) because it won't be in strings. it better fucking not be at least
|
//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::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::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::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)),
|
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_tuple: (usize, String) = Default::default();
|
||||||
let mut w_vec = Vec::new();
|
let mut w_vec = Vec::new();
|
||||||
let mut i = 0;
|
for (i, a) in arg2.unwrap().split("\x1F").enumerate() {
|
||||||
for a in arg2.unwrap().split("\x1F") {
|
|
||||||
if i % 2 == 0 {
|
if i % 2 == 0 {
|
||||||
if let Ok(n) = a.parse() {
|
if let Ok(n) = a.parse() {
|
||||||
w_tuple.0 = n;
|
w_tuple.0 = n;
|
||||||
@@ -684,7 +680,6 @@ impl Serializable for WindowMessage {
|
|||||||
w_tuple.1 = a.to_string();
|
w_tuple.1 = a.to_string();
|
||||||
w_vec.push(w_tuple.clone());
|
w_vec.push(w_tuple.clone());
|
||||||
}
|
}
|
||||||
i += 1;
|
|
||||||
}
|
}
|
||||||
let arg2 = parts2.next();
|
let arg2 = parts2.next();
|
||||||
if arg2.is_none() {
|
if arg2.is_none() {
|
||||||
|
|||||||
@@ -104,6 +104,6 @@ pub fn get_theme_info(theme: &Themes) -> Option<ThemeInfo> {
|
|||||||
return Some(pair.1);
|
return Some(pair.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ pub trait Substring {
|
|||||||
fn substring(&self, start: usize, end: usize) -> &str;
|
fn substring(&self, start: usize, end: usize) -> &str;
|
||||||
fn remove(&self, index: usize, len: usize) -> String;
|
fn remove(&self, index: usize, len: usize) -> String;
|
||||||
fn remove_last(&self) -> String;
|
fn remove_last(&self) -> String;
|
||||||
|
fn find_substring(&self, substr: &str) -> Option<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Substring for String {
|
impl Substring for String {
|
||||||
@@ -29,6 +30,14 @@ impl Substring for String {
|
|||||||
byte_end += char_length;
|
byte_end += char_length;
|
||||||
}
|
}
|
||||||
&self[byte_start..byte_end]
|
&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 {
|
fn remove(&self, index: usize, len: usize) -> String {
|
||||||
@@ -38,13 +47,26 @@ impl Substring for String {
|
|||||||
fn remove_last(&self) -> String {
|
fn remove_last(&self) -> String {
|
||||||
self.substring(0, self.chars().count() - 1).to_string()
|
self.substring(0, self.chars().count() - 1).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_substring(&self, substr: &str) -> Option<usize> {
|
||||||
|
//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
|
//the tuple is first, line #, actual line
|
||||||
pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
|
pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_per_line: usize, one_extra: bool) -> Vec<(bool, usize, String)> {
|
||||||
let mut actual_lines = Vec::new();
|
let mut actual_lines = Vec::new();
|
||||||
let mut line_num = 0;
|
for (line_num, real_line) in lines.enumerate() {
|
||||||
for real_line in lines {
|
|
||||||
let mut line = real_line.to_string() + if one_extra { " " } else { "" };
|
let mut line = real_line.to_string() + if one_extra { " " } else { "" };
|
||||||
let mut first = true;
|
let mut first = true;
|
||||||
loop {
|
loop {
|
||||||
@@ -62,7 +84,6 @@ pub fn calc_actual_lines<'a>(lines: impl Iterator<Item = &'a String>, max_chars_
|
|||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
line_num += 1;
|
|
||||||
}
|
}
|
||||||
actual_lines
|
actual_lines
|
||||||
}
|
}
|
||||||
@@ -132,7 +153,7 @@ pub fn hex_to_u8(c1: char, c2: char) -> u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_hex(c: char) -> bool {
|
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 {
|
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<Strin
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ impl WindowLike for FileExplorer {
|
|||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
},
|
},
|
||||||
WindowMessage::KeyPress(key_press) => {
|
WindowMessage::KeyPress(key_press) => {
|
||||||
self.state = State::List;
|
if key_press.is_enter() && self.state == State::List {
|
||||||
if key_press.is_enter() {
|
|
||||||
if self.current_dir_contents.len() > 0 {
|
if self.current_dir_contents.len() > 0 {
|
||||||
let selected_entry = &self.current_dir_contents[self.position];
|
let selected_entry = &self.current_dir_contents[self.position];
|
||||||
if !selected_entry.is_file {
|
if !selected_entry.is_file {
|
||||||
@@ -75,6 +74,7 @@ impl WindowLike for FileExplorer {
|
|||||||
}
|
}
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
} else if key_press.key == 'j' || key_press.is_down_arrow() || key_press.key == 'k' || key_press.is_up_arrow() {
|
} 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() {
|
if key_press.key == 'j' || key_press.is_down_arrow() {
|
||||||
//down
|
//down
|
||||||
if self.position == self.current_dir_contents.len() - 1 {
|
if self.position == self.current_dir_contents.len() - 1 {
|
||||||
@@ -103,12 +103,21 @@ impl WindowLike for FileExplorer {
|
|||||||
};
|
};
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else if key_press.key == 'i' {
|
} else if key_press.key == 'i' {
|
||||||
self.state = State::Info;
|
if self.state == State::Info {
|
||||||
let selected_entry = &self.current_dir_contents[self.position];
|
self.state = State::List;
|
||||||
self.metadata = Some(metadata(&selected_entry.path).unwrap());
|
} else {
|
||||||
|
self.state = State::Info;
|
||||||
|
let selected_entry = &self.current_dir_contents[self.position];
|
||||||
|
self.metadata = Some(metadata(&selected_entry.path).unwrap());
|
||||||
|
}
|
||||||
WindowMessageResponse::JustRedraw
|
WindowMessageResponse::JustRedraw
|
||||||
} else {
|
} else {
|
||||||
WindowMessageResponse::DoNothing
|
if self.state == State::Info {
|
||||||
|
self.state = State::List;
|
||||||
|
WindowMessageResponse::JustRedraw
|
||||||
|
} else {
|
||||||
|
WindowMessageResponse::DoNothing
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => WindowMessageResponse::DoNothing,
|
_ => WindowMessageResponse::DoNothing,
|
||||||
|
|||||||
@@ -116,10 +116,10 @@ fn init(framebuffer: Framebuffer, framebuffer_info: FramebufferInfo) {
|
|||||||
let mut y: Option<usize> = None;
|
let mut y: Option<usize> = None;
|
||||||
for line in reader.lines() {
|
for line in reader.lines() {
|
||||||
let line = line.unwrap();
|
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: Vec<_> = line.split("), value ").collect();
|
||||||
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
let value = value[value.len() - 1].parse::<usize>().unwrap();
|
||||||
if line.contains(&"ABS_X") {
|
if line.contains("ABS_X") {
|
||||||
x = Some(value);
|
x = Some(value);
|
||||||
} else {
|
} else {
|
||||||
y = Some(value);
|
y = Some(value);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use std::vec::Vec;
|
|||||||
use std::vec;
|
use std::vec;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::{ read_to_string, write };
|
use std::fs::{ read_to_string, write };
|
||||||
|
|
||||||
use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse, WindowManagerRequest, ShortcutType };
|
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::window_manager_types::{ DrawInstructions, WindowLike, WindowLikeType };
|
||||||
use ming_wm_lib::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring };
|
use ming_wm_lib::utils::{ calc_actual_lines, calc_new_cursor_pos, Substring };
|
||||||
use ming_wm_lib::dirs::home;
|
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;
|
use ming_wm_lib::ipc::listen;
|
||||||
|
|
||||||
const MONO_WIDTH: u8 = 10;
|
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();
|
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);
|
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 = ¤t_file.content[current_file.line_pos];
|
||||||
let line_len = line.chars().count();
|
let line_len = line.chars().count();
|
||||||
if line_len > 0 && current_file.cursor_pos < line_len {
|
if line_len > 0 && current_file.cursor_pos < line_len {
|
||||||
//offset until space or eol
|
//offset until space or eol
|
||||||
let mut line_chars = line.chars().skip(current_file.cursor_pos).peekable();
|
let mut line_chars = line.chars().skip(current_file.cursor_pos).peekable();
|
||||||
let current_char = line_chars.peek().unwrap().clone();
|
//deref is Copy
|
||||||
let offset = line_chars.position(|c| if current_char == ' ' {
|
let current_char = *line_chars.peek().unwrap();
|
||||||
c != ' '
|
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 {
|
} else {
|
||||||
c == ' '
|
line_chars.count()
|
||||||
}).unwrap_or(line_len - current_file.cursor_pos);
|
};
|
||||||
current_file.content[current_file.line_pos] = line.remove(current_file.cursor_pos, offset);
|
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();
|
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);
|
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 {
|
if current_length == 1 {
|
||||||
current_file.cursor_pos = 0;
|
current_file.cursor_pos = 0;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
changed = false;
|
||||||
}
|
}
|
||||||
} else if key_press.key == 'h' || key_press.is_left_arrow() {
|
} 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);
|
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' {
|
} else if key_press.key == 'F' {
|
||||||
self.state = State::BackFind;
|
self.state = State::BackFind;
|
||||||
changed = false;
|
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::<String>()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if *forwards {
|
||||||
|
lines[i]
|
||||||
|
} else {
|
||||||
|
&lines[i].chars().rev().collect::<String>()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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);
|
self.maybe_num = Some(self.maybe_num.unwrap_or(0) * 10 + key_press.key.to_digit(10).unwrap() as usize);
|
||||||
numbered = true;
|
numbered = true;
|
||||||
changed = false;
|
changed = false;
|
||||||
@@ -401,7 +490,7 @@ impl WindowLike for Malvim {
|
|||||||
let mut used_width = 0;
|
let mut used_width = 0;
|
||||||
for file_index in 0..self.files.len() {
|
for file_index in 0..self.files.len() {
|
||||||
let file_info = &self.files[file_index];
|
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
|
//just cut off when too many file tabs open to fit
|
||||||
if future_used_width > self.dimensions[0] {
|
if future_used_width > self.dimensions[0] {
|
||||||
break;
|
break;
|
||||||
@@ -455,12 +544,11 @@ impl WindowLike for Malvim {
|
|||||||
//bottom blue band stuff
|
//bottom blue band stuff
|
||||||
//write mode
|
//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)));
|
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;
|
let file_status = if self.files.len() > 0 {
|
||||||
if self.files.len() > 0 {
|
self.files[self.current_file_index].name.clone()
|
||||||
file_status = self.files[self.current_file_index].name.clone();
|
|
||||||
} else {
|
} 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)));
|
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
|
//write command or bottom message
|
||||||
if self.mode == Mode::Command {
|
if self.mode == Mode::Command {
|
||||||
@@ -593,12 +681,40 @@ impl Malvim {
|
|||||||
} else if first.starts_with("/") {
|
} else if first.starts_with("/") {
|
||||||
let current_file = &mut self.files[self.current_file_index];
|
let current_file = &mut self.files[self.current_file_index];
|
||||||
if current_file.content.len() > 0 {
|
if current_file.content.len() > 0 {
|
||||||
let found_line_no = current_file.content.iter().skip(current_file.line_pos + 1).position(|line| {
|
let p1 = if arg == "" {
|
||||||
line.contains(&first[1..])
|
String::new()
|
||||||
});
|
} else {
|
||||||
if let Some(found_line_no) = found_line_no {
|
" ".to_string() + arg
|
||||||
current_file.line_pos = found_line_no + current_file.line_pos + 1;
|
};
|
||||||
current_file.cursor_pos = 0;
|
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" {
|
} else if first == "x" || first == "w" || first == "write" || first == "q" || first == "quit" {
|
||||||
|
|||||||
@@ -65,15 +65,15 @@ impl WindowLike for Minesweeper {
|
|||||||
self.first_char = '\0';
|
self.first_char = '\0';
|
||||||
WindowMessageResponse::DoNothing
|
WindowMessageResponse::DoNothing
|
||||||
} else if self.first_char == '\0' {
|
} 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;
|
self.first_char = key_press.key;
|
||||||
}
|
}
|
||||||
WindowMessageResponse::DoNothing
|
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 u = hex_to_u8(self.first_char, key_press.key) as usize;
|
||||||
let y = u / 16;
|
let y = u / 16;
|
||||||
let x = 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 {
|
if self.state == State::BeforePlaying {
|
||||||
loop {
|
loop {
|
||||||
self.new_tiles();
|
self.new_tiles();
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ impl WindowLike for Terminal {
|
|||||||
self.prev();
|
self.prev();
|
||||||
} else if key_press.is_down_arrow() {
|
} else if key_press.is_down_arrow() {
|
||||||
self.next();
|
self.next();
|
||||||
} else {
|
} else if key_press.is_regular() {
|
||||||
self.current_input += &key_press.key.to_string();
|
self.current_input += &key_press.key.to_string();
|
||||||
}
|
}
|
||||||
self.calc_actual_lines();
|
self.calc_actual_lines();
|
||||||
|
|||||||
@@ -115,13 +115,11 @@ impl WindowLike for StartMenu {
|
|||||||
];
|
];
|
||||||
let max_per_page = CATEGORIES.len();
|
let max_per_page = CATEGORIES.len();
|
||||||
let current_focus = self.get_focus_index().unwrap();
|
let current_focus = self.get_focus_index().unwrap();
|
||||||
let mut index = 0;
|
for (index, component) in self.components.iter().enumerate() {
|
||||||
for component in &self.components {
|
|
||||||
//supports multiple pages of window options per category
|
//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) {
|
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));
|
instructions.extend(component.draw(theme_info));
|
||||||
}
|
}
|
||||||
index += 1;
|
|
||||||
}
|
}
|
||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
@@ -194,8 +192,7 @@ impl StartMenu {
|
|||||||
pub fn add_category_components(&mut self) {
|
pub fn add_category_components(&mut self) {
|
||||||
self.current_focus = "About".to_string();
|
self.current_focus = "About".to_string();
|
||||||
self.components = Vec::new();
|
self.components = Vec::new();
|
||||||
for c in 0..CATEGORIES.len() {
|
for (c, name) in CATEGORIES.iter().enumerate() {
|
||||||
let name = CATEGORIES[c];
|
|
||||||
self.components.push(Box::new(HighlightButton::new(
|
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
|
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
|
||||||
)));
|
)));
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ impl FramebufferWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.rotate_buffer = Some(output_array);
|
self.rotate_buffer = Some(output_array);
|
||||||
&self.rotate_buffer.as_ref().unwrap()
|
self.rotate_buffer.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save_buffer(&mut self) {
|
pub fn save_buffer(&mut self) {
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ impl WindowManager {
|
|||||||
pub fn add_window_like(&mut self, mut window_like: Box<dyn WindowLike>, top_left: Point, dimensions: Option<Dimensions>) {
|
pub fn add_window_like(&mut self, mut window_like: Box<dyn WindowLike>, top_left: Point, dimensions: Option<Dimensions>) {
|
||||||
let subtype = window_like.subtype();
|
let subtype = window_like.subtype();
|
||||||
let dimensions = dimensions.unwrap_or(window_like.ideal_dimensions(self.dimensions));
|
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;
|
let id = self.id_count;
|
||||||
window_like.handle_message(WindowMessage::Init(dimensions));
|
window_like.handle_message(WindowMessage::Init(dimensions));
|
||||||
let dimensions = if subtype == WindowLikeType::Window { [dimensions[0], dimensions[1] + WINDOW_TOP_HEIGHT] } else { 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();
|
file.read_to_string(&mut contents).unwrap();
|
||||||
let lines: Vec<&str> = contents.split("\n").collect();
|
let lines: Vec<&str> = contents.split("\n").collect();
|
||||||
if lines.len() > self.current_workspace.into() {
|
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
|
//these are needed to decide when to snapshot
|
||||||
let max_index = if redraw_ids.len() > 0 { redraw_ids.len() } else { maybe_length } - 1;
|
let max_index = if redraw_ids.len() > 0 { redraw_ids.len() } else { maybe_length } - 1;
|
||||||
let mut w_index = 0;
|
for (w_index, window_info) in redraw_windows.enumerate() {
|
||||||
for window_info in redraw_windows {
|
|
||||||
let window_dimensions = if window_info.fullscreen {
|
let window_dimensions = if window_info.fullscreen {
|
||||||
[self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]
|
[self.dimensions[0], self.dimensions[1] - TASKBAR_HEIGHT - INDICATOR_HEIGHT]
|
||||||
} else {
|
} 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());
|
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?
|
//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();
|
let mut writer_borrow = self.writer.borrow_mut();
|
||||||
|
|||||||
Reference in New Issue
Block a user