v1.0.0: tab path autocomplete, malvim features, terminal history

various fixes, docs, some kanji and romaji font chars
This commit is contained in:
stjet
2025-03-16 05:56:00 +00:00
parent 22b21401f9
commit 668ce2ea6c
87 changed files with 171 additions and 73 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ming-wm" name = "ming-wm"
version = "1.0.0-beta.1" version = "1.0.0"
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"
@@ -20,7 +20,7 @@ ming-wm-lib = { path = "ming-wm-lib" }
blake2 = { version = "0.10.6", default-features = false } blake2 = { version = "0.10.6", default-features = false }
linux = { path = "linux" } linux = { path = "linux" }
termion = { version = "4.0.3", optional = true } termion = { version = "4.0.3", optional = true }
rodio = { version = "0.19.0", optional = true } rodio = { version = "0.19.0", default-features = false, features = [ "flac", "mp3", "symphonia-vorbis", "wav" ], optional = true }
rand = { version = "0.9.0", default-features = false, features = [ "small_rng" ], optional = true } rand = { version = "0.9.0", default-features = false, features = [ "small_rng" ], optional = true }
id3 = { version = "1.10.0", optional = true } id3 = { version = "1.10.0", optional = true }
mp4ameta = { version = "0.11.0", optional = true } mp4ameta = { version = "0.11.0", optional = true }

View File

@@ -1,4 +1,4 @@
Ming-wm is a keyboard-based, retro-themed window manager for Linux. It is single-threaded, and is neither for Wayland or the X Window System - it writes directly to the framebuffer. Inspirations include i3, Haiku, SerenityOS, and Windows98, and it is a conceptual successor to the previous [mingde](https://github.com/stjet/mingde) and [ming-os](https://github.com/stjet/ming-os). Ming-wm is a keyboard-based, retro-themed window manager for Linux. It is neither for Wayland or the X Window System - it writes directly to the framebuffer. Inspirations include i3, Haiku, SerenityOS, and Windows98, and it is a conceptual successor to the previous [mingde](https://github.com/stjet/mingde) and [ming-os](https://github.com/stjet/ming-os).
![example 1](/docs/images/ws1.png) ![example 1](/docs/images/ws1.png)
![example 2](/docs/images/ws3.png) ![example 2](/docs/images/ws3.png)
@@ -49,7 +49,7 @@ Usage for most of the included windows and window-likes are included in `docs/wi
## Running on Mobile Linux ## Running on Mobile Linux
Running with an onscreen keyboard. The framebuffer may not be redrawn to the screen without a (real) key press. The volume down button seems to work. Running with an onscreen keyboard. The framebuffer may not be redrawn to the screen without a (real) key press. The volume down button seems to work. If someone knows why this is the case, and/or how to fix this, please let me know.
`evtest` needs to be installed. Currently, the input device is assumed to be at `/dev/first-touchscreen`. `evtest` needs to be installed. Currently, the input device is assumed to be at `/dev/first-touchscreen`.
@@ -73,7 +73,7 @@ See [/docs/philosophy.md](/docs/philosophy.md) for some hopefully interesting ra
Windows (may be called apps in other window managers) can be developed in any language, though it is easiest to do so in Rust because the `ming-wm-lib` crate can be used. Windows (may be called apps in other window managers) can be developed in any language, though it is easiest to do so in Rust because the `ming-wm-lib` crate can be used.
See [koxinga](https://github.com/stjet/koxinga) or `src/bin` for examples. The `docs` directory includes a [brief introduction to writing windows](docs/system/writing_windows.md). [incomplete] documentation on the architecture of ming-wm. See [koxinga](https://github.com/stjet/koxinga) or `src/bin` for examples. The `docs` directory includes a [brief introduction to writing windows](docs/system/writing_windows.md), and (incomplete) documentation on the workings of ming-wm.
## Security ## Security

BIN
bmps/shippori-mincho/y0.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

View File

@@ -104,9 +104,9 @@ Further documentation on specific window-likes can be found in `docs/window-like
The window manager passes information about it's theme to all window-likes as a parameter to `draw`, so windows can have appropriate background colours, highlight colours, text colours, etc. The window manager passes information about it's theme to all window-likes as a parameter to `draw`, so windows can have appropriate background colours, highlight colours, text colours, etc.
//can't change themes yet. in fact, no other themes yet See the end of `docs/window-likes/desktop-background.md` for theme config information.
## Fonts / Text ## Fonts / Text
// See `docs/system/fonts.md`. There is no Japanese input system... yet.
//Japanese / Chinese characters can only be used for display, not input, as there is no CJK input system. yet. And these text inputs don't yet handle multi-byte input very gracefully

View File

@@ -12,6 +12,8 @@ Type to write commands, backspace to delete last character, and enter to run com
- `p <dir / playlist file>`: Play audio files in `<dir>` or play the songs listed in the `<playlist file>`. Unless paths are absolute, they will be relative to the directory specified by the `b <dir>` command - `p <dir / playlist file>`: Play audio files in `<dir>` or play the songs listed in the `<playlist file>`. Unless paths are absolute, they will be relative to the directory specified by the `b <dir>` command
- `a <dir / playlist file>`: Same as `p` but appends to the end of the queue instead of clearing the current song and the queue - `a <dir / playlist file>`: Same as `p` but appends to the end of the queue instead of clearing the current song and the queue
Tab completion is supported for the `<dir>` and `<dir / playlist file>` arguments.
## Playlists ## Playlists
Example playlist file: Example playlist file:

View File

@@ -1,4 +1,6 @@
A text editor. Specifically, a subset of a vim. A text/code editor. Specifically, a subset of vim.
Funnily enough, that subset doesn't include the **vi**sual (ie, multi-line) capabilities of vim that the "vi" stands for. Perhaps it should be called "maled"?
## Usage ## Usage
@@ -6,11 +8,13 @@ It is probably best to read a Vim tutorial for the basics. All supportd keystrok
### Supported in Command-line Mode ### Supported in Command-line Mode
- `e[dit]` - `e[dit] <file>`
- `t[abe]`, `[tab]n`, `[tab]p` - `t[abe] <file>`, `[tab]n`, `[tab]p`
- `q[uit]` - `q[uit]`
- `w[rite]` - `w[rite]`
Tab completion is supported for the `<file>` argument.
### Supported in Normal Mode ### Supported in Normal Mode
- `:` - `:`
@@ -26,8 +30,9 @@ It is probably best to read a Vim tutorial for the basics. All supportd keystrok
- `F<char>` - `F<char>`
- `x` - `x`
- `h`, `j`, `k`, `l` - `h`, `j`, `k`, `l`
- `<num>h`, `<num>j`, `<num>k`, `<num>l`
- `0`, `^`, `$` - `0`, `^`, `$`
### Malvim Specific ### Malvim Specific
In Command-line Mode, `autoindent` can be done to toggle auto-indenting (when making new line in Insert Mode [ie, by hitting Enter/Return], space indentation of the new line will be the same as the space indentation of the current line). In Command-line Mode, `autoindent` can be done to toggle auto-indenting (when making new line in Insert Mode [ie, by hitting Enter/Return], space indentation of the new line will be the same as the space indentation of the current line). **Toggling on `autoindent` is highly recommended when editing code.**

View File

@@ -8,13 +8,17 @@ The terminal starts off in INPUT mode, which allows entering commands to run. If
In INPUT mode, commands can be freely typed. There are a few special control sequences: In INPUT mode, commands can be freely typed. There are a few special control sequences:
- `ctrl+p`: Brings up the last run command to the command input - `ctrl+p`: Equivalent to the up arrow in most terminals. Brings up the previous command in the command history, and so on.
- `ctrl+n`: Clears the command input - `ctrl+n`: Equivalent to the down arrow in most terminals. Either clears the current input if not in a previous command, else brings up the next command in the command history.
Tab completion is also supported, though only for file/directory paths.
Once a command is entered, hit 'enter' to execute it. The terminal will change into "RUNNING" mode. In this mode, clicking any key except for 'i' will result in the terminal writing the current output of the running command to the window (`ctrl+c` will force the process to exit). It will also check if the command has exited, in which case the INPUT mode is returned to. Clicking the 'i' key will change the terminal to "STDIN" mode. Once a command is entered, hit 'enter' to execute it. The terminal will change into "RUNNING" mode. In this mode, clicking any key except for 'i' will result in the terminal writing the current output of the running command to the window (`ctrl+c` will force the process to exit). It will also check if the command has exited, in which case the INPUT mode is returned to. Clicking the 'i' key will change the terminal to "STDIN" mode.
In STDIN mode, any keys typed followed by the 'enter' key will send those keys to the command's STDIN, if it is still running. To escape STDIN mode, use the `esc` key. In STDIN mode, any keys typed followed by the 'enter' key will send those keys to the command's STDIN, if it is still running. To escape STDIN mode, use the `esc` key.
ANSI escape codes are currently not supported, and are stripped.
### Sudo ### Sudo
To get sudo to read from stdin, the `-S` option will need to be used (eg, `sudo -S ls`). Then switch to STDIN mode, type in the password and hit enter. To get sudo to read from stdin, the `-S` option will need to be used (eg, `sudo -S ls`). Then switch to STDIN mode, type in the password and hit enter.
@@ -23,3 +27,6 @@ To get sudo to read from stdin, the `-S` option will need to be used (eg, `sudo
This window-like supports the paste [shortcut](../system/shortcuts.md) (`Alt+P`) if in INPUT or STDIN mode. This window-like supports the paste [shortcut](../system/shortcuts.md) (`Alt+P`) if in INPUT or STDIN mode.
## Notes
Some commands like `git diff` don't quite work well yet. Also, some command outputs are very long, but the terminal doesn't really support scrolling. Instead, redirect the output of those commands to a file and read it in Malvim (eg `git diff > diff.txt`).

View File

@@ -1,8 +1,13 @@
#!/bin/sh #!/bin/sh
rm -rf /usr/local/bin/ming_bmps rm -rf /usr/local/bin/ming_bmps
cp -r ./bmps /usr/local/bin/ming_bmps cp -r ./bmps /usr/local/bin/ming_bmps
rm -rf /usr/local/bin/ming_bmps/nimbus-roman/*.bmp
rm -rf /usr/local/bin/ming_bmps/nimbus-romano/*.bmp
rm -rf /usr/local/bin/ming_bmps/shippori-mincho/*.bmp
rm /usr/local/bin/ming_bmps/*1440x842.bmp
rm -rf /usr/local/bin/ming_docs rm -rf /usr/local/bin/ming_docs
cp -r ./docs /usr/local/bin/ming_docs cp -r ./docs /usr/local/bin/ming_docs
rm -rf /usr/local/bin/ming_docs/images
cp ./target/release/ming /usr/local/bin/ming cp ./target/release/ming /usr/local/bin/ming
cp ./target/release/mingUtils_Terminal /usr/local/bin/mingUtils_Terminal cp ./target/release/mingUtils_Terminal /usr/local/bin/mingUtils_Terminal
cp ./target/release/mingGames_Reversi /usr/local/bin/mingGames_Reversi cp ./target/release/mingGames_Reversi /usr/local/bin/mingGames_Reversi

View File

@@ -1,8 +1,13 @@
#!/bin/sh #!/bin/sh
rm -rf ~/.local/bin/ming_bmps rm -rf ~/.local/bin/ming_bmps
cp -r ./bmps ~/.local/bin/ming_bmps cp -r ./bmps ~/.local/bin/ming_bmps
rm -rf ~/.local/bin/ming_bmps/nimbus-roman/*.bmp
rm -rf ~/.local/bin/ming_bmps/nimbus-romano/*.bmp
rm -rf ~/.local/bin/ming_bmps/shippori-mincho/*.bmp
rm ~/.local/bin/ming_bmps/*1440x842.bmp
rm -rf ~/.local/bin/ming_docs rm -rf ~/.local/bin/ming_docs
cp -r ./docs ~/.local/bin/ming_docs cp -r ./docs ~/.local/bin/ming_docs
rm -rf ~/.local/bin/ming_docs/images
cp ./target/release/ming ~/.local/bin/ming cp ./target/release/ming ~/.local/bin/ming
cp ./target/release/mingUtils_Terminal ~/.local/bin/mingUtils_Terminal cp ./target/release/mingUtils_Terminal ~/.local/bin/mingUtils_Terminal
cp ./target/release/mingGames_Reversi ~/.local/bin/mingGames_Reversi cp ./target/release/mingGames_Reversi ~/.local/bin/mingGames_Reversi

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "ming-wm-lib" name = "ming-wm-lib"
version = "0.1.3" version = "0.1.4"
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"
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"

View File

@@ -1,4 +1,5 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::fs::read_dir;
use crate::framebuffer_types::{ Dimensions, Point }; use crate::framebuffer_types::{ Dimensions, Point };
@@ -80,6 +81,10 @@ pub fn calc_new_cursor_pos(cursor_pos: usize, new_length: usize) -> usize {
pub fn concat_paths(current_path: &str, add_path: &str) -> Result<PathBuf, ()> { pub fn concat_paths(current_path: &str, add_path: &str) -> Result<PathBuf, ()> {
let mut new_path = PathBuf::from(current_path); let mut new_path = PathBuf::from(current_path);
//if current_path is a file, automatically uses it's parent (a directory)
if new_path.is_file() {
new_path = new_path.parent().unwrap().to_path_buf();
}
if add_path.starts_with("/") { if add_path.starts_with("/") {
//absolute path //absolute path
new_path = PathBuf::from(add_path); new_path = PathBuf::from(add_path);
@@ -156,3 +161,36 @@ pub fn get_rest_of_split(split: &mut dyn Iterator<Item = &str>, sep: Option<&str
rest rest
} }
pub fn path_autocomplete(current_path: &str, partial_path: &str) -> Option<String> {
if let Ok(new_path) = concat_paths(current_path, &partial_path) {
let partial_name;
let parent;
if partial_path.ends_with("/") {
partial_name = "".to_string();
parent = new_path.as_path();
} else {
//this is just silly
partial_name = new_path.clone().file_name().unwrap().to_os_string().to_string_lossy().to_string();
parent = new_path.parent().unwrap();
};
if let Ok(entries) = read_dir(parent) {
for entry in entries {
let entry_path = entry.unwrap().path();
let name = entry_path.file_name().unwrap().to_os_string().to_string_lossy().to_string();
if name.starts_with(&partial_name) {
let add = name[partial_name.len()..].to_string();
let add_len = add.len();
return Some(add + if entry_path.is_dir() && add_len > 0 {
"/"
} else {
""
});
}
}
}
None
} else {
None
}
}

View File

@@ -17,7 +17,7 @@ use ming_wm_lib::window_manager_types::{ DrawInstructions, WindowLike, WindowLik
use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse }; use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse };
use ming_wm_lib::framebuffer_types::Dimensions; use ming_wm_lib::framebuffer_types::Dimensions;
use ming_wm_lib::themes::ThemeInfo; use ming_wm_lib::themes::ThemeInfo;
use ming_wm_lib::utils::{ concat_paths, format_seconds, Substring }; use ming_wm_lib::utils::{ concat_paths, path_autocomplete, format_seconds, Substring };
use ming_wm_lib::dirs::home; use ming_wm_lib::dirs::home;
use ming_wm_lib::ipc::listen; use ming_wm_lib::ipc::listen;
use ming_wm::fs::get_all_files; use ming_wm::fs::get_all_files;
@@ -98,6 +98,18 @@ impl WindowLike for AudioPlayer {
if self.command.len() > 0 { if self.command.len() > 0 {
self.command = self.command.remove_last(); self.command = self.command.remove_last();
} }
} else if key_press.key == '\t' { //tab
let mut parts = self.command.split(" ");
let parts_len = parts.clone().count();
if parts_len == 2 {
if let Some(add) = path_autocomplete(&self.base_directory, parts.nth(1).unwrap()) {
self.command += &add;
} else {
return WindowMessageResponse::DoNothing;
}
} else {
return WindowMessageResponse::DoNothing;
}
} else { } else {
self.command += &key_press.key.to_string(); self.command += &key_press.key.to_string();
} }

View File

@@ -10,6 +10,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::ipc::listen; use ming_wm_lib::ipc::listen;
const MONO_WIDTH: u8 = 10; const MONO_WIDTH: u8 = 10;
@@ -175,11 +176,17 @@ 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' {
//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 { let line_len = line.chars().count();
if line_len > 0 && current_file.cursor_pos < line_len {
//offset until space or eol //offset until space or eol
let offset = line.chars().skip(current_file.cursor_pos).position(|c| c == ' ').unwrap_or(line.chars().count() - current_file.cursor_pos); 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 != ' '
} else {
c == ' '
}).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);
@@ -235,23 +242,23 @@ impl WindowLike for Malvim {
} }
} }
} else if key_press.key == 'h' { } else if key_press.key == 'h' {
current_file.cursor_pos = current_file.cursor_pos.checked_sub(1).unwrap_or(0); current_file.cursor_pos = current_file.cursor_pos.checked_sub(self.maybe_num.unwrap_or(1)).unwrap_or(0);
changed = false; changed = false;
} else if key_press.key == 'j' || key_press.key == 'k' { } else if key_press.key == 'j' || key_press.key == 'k' {
if key_press.key == 'j' { if key_press.key == 'j' {
current_file.line_pos += 1; current_file.line_pos += self.maybe_num.unwrap_or(1);
if current_file.line_pos == current_file.content.len() { if current_file.line_pos >= current_file.content.len() {
current_file.line_pos = current_file.content.len() - 1; current_file.line_pos = current_file.content.len() - 1;
} }
} else { } else {
current_file.line_pos = current_file.line_pos.checked_sub(1).unwrap_or(0); current_file.line_pos = current_file.line_pos.checked_sub(self.maybe_num.unwrap_or(1)).unwrap_or(0);
} }
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);
changed = false; changed = false;
} else if key_press.key == 'l' { } else if key_press.key == 'l' {
if current_length > 0 { if current_length > 0 {
current_file.cursor_pos += 1; current_file.cursor_pos += self.maybe_num.unwrap_or(1);
let line_len = current_file.content[current_file.line_pos].chars().count(); let line_len = current_file.content[current_file.line_pos].chars().count();
if current_file.cursor_pos > line_len { if current_file.cursor_pos > line_len {
current_file.cursor_pos = line_len; current_file.cursor_pos = line_len;
@@ -295,10 +302,10 @@ impl WindowLike for Malvim {
} else { } else {
changed = false; changed = false;
} }
//reset maybe_num if not num
if !numbered && self.state != State::Maybeg { if !numbered && self.state != State::Maybeg {
self.maybe_num = None; self.maybe_num = None;
} }
//
} else if self.mode == Mode::Command { } else if self.mode == Mode::Command {
self.bottom_message = None; self.bottom_message = None;
let command = self.command.clone().unwrap_or("".to_string()); let command = self.command.clone().unwrap_or("".to_string());
@@ -306,6 +313,23 @@ impl WindowLike for Malvim {
new = self.process_command(); new = self.process_command();
self.command = None; self.command = None;
self.mode = Mode::Normal; self.mode = Mode::Normal;
} else if key_press.key == '\t' { //tab
let mut parts = command.split(" ").skip(1);
let parts_len = parts.clone().count();
if parts_len == 1 { //caused one skipped
if let Some(second) = parts.next() {
let base_path = if self.files.len() > 0 {
//this is a file path, not a directory,
//but path_autocomplete's concat_path will sort it out for us
&self.files[self.current_file_index].path
} else {
&home().unwrap_or(PathBuf::from("/")).to_string_lossy().to_string()
};
if let Some(add) = path_autocomplete(&base_path, second) {
self.command = Some(command + &add);
}
}
}
} else if key_press.key == '𐘁' { //backspace } else if key_press.key == '𐘁' { //backspace
if command.len() > 0 { if command.len() > 0 {
self.command = Some(command[..command.len() - 1].to_string()); self.command = Some(command[..command.len() - 1].to_string());
@@ -388,7 +412,7 @@ impl WindowLike for Malvim {
theme_info.alt_secondary theme_info.alt_secondary
}; };
instructions.extend(vec![ instructions.extend(vec![
DrawInstructions::Rect([used_width, 2], [future_used_width, BAND_HEIGHT - 2], background), DrawInstructions::Rect([used_width, 2], [future_used_width - used_width, BAND_HEIGHT - 2], background),
DrawInstructions::Text([used_width + 2, 2], vec!["nimbus-romono".to_string()], if file_info.changed { "+ ".to_string() } else { String::new() } + &file_info.name, theme_info.alt_text, background, Some(0), Some(MONO_WIDTH)), DrawInstructions::Text([used_width + 2, 2], vec!["nimbus-romono".to_string()], if file_info.changed { "+ ".to_string() } else { String::new() } + &file_info.name, theme_info.alt_text, background, Some(0), Some(MONO_WIDTH)),
]); ]);
used_width = future_used_width; used_width = future_used_width;
@@ -550,12 +574,12 @@ impl Malvim {
} }
} else { } else {
//t(abe) //t(abe)
self.current_file_index += 1;
if self.current_file_index == self.files.len() - 1 { if self.current_file_index == self.files.len() - 1 {
self.files.push(file_info); self.files.push(file_info);
} else { } else {
self.files.insert(self.current_file_index, file_info); self.files.insert(self.current_file_index + 1, file_info);
} }
self.current_file_index += 1;
} }
return true; return true;
} else { } else {
@@ -577,15 +601,18 @@ impl Malvim {
current_file.cursor_pos = 0; current_file.cursor_pos = 0;
} }
} }
} else if first == "w" || first == "write" { } else if first == "x" || first == "w" || first == "write" || first == "q" || first == "quit" {
let current_file = &self.files[self.current_file_index]; if first == "x" || first == "w" || first == "write" {
let _ = write(&current_file.path, &current_file.content.join("\n")); let current_file = &self.files[self.current_file_index];
self.files[self.current_file_index].changed = false; let _ = write(&current_file.path, &current_file.content.join("\n"));
self.bottom_message = Some("Written".to_string()); self.files[self.current_file_index].changed = false;
} else if first == "q" || first == "quit" { self.bottom_message = Some("Written".to_string());
self.files.remove(self.current_file_index); }
self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(0); if first == "x" || first == "q" || first == "quit" {
return true; 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" { } else if first == "p" || first == "tabp" {
self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(self.files.len() - 1); self.current_file_index = self.current_file_index.checked_sub(1).unwrap_or(self.files.len() - 1);
return true; return true;

View File

@@ -7,7 +7,6 @@ use std::io::{ Read, Write };
use std::time::Duration; use std::time::Duration;
use std::path::PathBuf; use std::path::PathBuf;
use std::fmt; use std::fmt;
use std::fs::read_dir;
use pty_process::blocking; use pty_process::blocking;
@@ -15,12 +14,10 @@ use ming_wm_lib::window_manager_types::{ DrawInstructions, WindowLike, WindowLik
use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse, ShortcutType }; use ming_wm_lib::messages::{ WindowMessage, WindowMessageResponse, ShortcutType };
use ming_wm_lib::framebuffer_types::Dimensions; use ming_wm_lib::framebuffer_types::Dimensions;
use ming_wm_lib::themes::ThemeInfo; use ming_wm_lib::themes::ThemeInfo;
use ming_wm_lib::utils::{ concat_paths, Substring }; use ming_wm_lib::utils::{ concat_paths, path_autocomplete, Substring };
use ming_wm_lib::dirs::home; use ming_wm_lib::dirs::home;
use ming_wm_lib::ipc::listen; use ming_wm_lib::ipc::listen;
//todo: support copy and paste
const MONO_WIDTH: u8 = 10; const MONO_WIDTH: u8 = 10;
const LINE_HEIGHT: usize = 15; const LINE_HEIGHT: usize = 15;
const PADDING: usize = 4; const PADDING: usize = 4;
@@ -83,7 +80,8 @@ pub struct Terminal {
process_current_line: Vec<u8>, //bytes of line process_current_line: Vec<u8>, //bytes of line
pty_outerr_rx: Option<Receiver<u8>>, pty_outerr_rx: Option<Receiver<u8>>,
pty_in_tx: Option<Sender<String>>, pty_in_tx: Option<Sender<String>>,
last_command: Option<String>, history: Vec<String>,
history_index: Option<usize>,
} }
//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
@@ -114,39 +112,21 @@ 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.history.push(self.current_input.clone());
self.history_index = None;
self.mode = self.process_command(); self.mode = self.process_command();
self.current_input = String::new(); self.current_input = String::new();
} else if key_press.key == '\t' { //tab } else if key_press.key == '\t' { //tab
//autocomplete assuming it's a file system path //autocomplete assuming it's a file system path
//...mostly working //...mostly working
let mut useless_tab = true;
if self.current_input.len() > 0 { if self.current_input.len() > 0 {
let partial_path = self.current_input.split(" ").last().unwrap(); let partial_path = self.current_input.split(" ").last().unwrap();
if let Ok(new_path) = concat_paths(&self.current_path, partial_path) { if let Some(add) = path_autocomplete(&self.current_path, partial_path) {
let partial_name; self.current_input += &add;
let parent; } else {
if self.current_input.ends_with("/") { return WindowMessageResponse::DoNothing;
partial_name = "".to_string();
parent = new_path.as_path();
} else {
//this is just silly
partial_name = new_path.clone().file_name().unwrap().to_os_string().to_string_lossy().to_string();
parent = new_path.parent().unwrap();
};
for entry in read_dir(parent).unwrap() {
let name = entry.unwrap().path().file_name().unwrap().to_os_string().to_string_lossy().to_string();
if name.starts_with(&partial_name) {
self.current_input += &name[partial_name.len()..];
useless_tab = false;
break;
}
}
} }
} }
if useless_tab {
return WindowMessageResponse::DoNothing;
}
} else { } else {
self.current_input += &key_press.key.to_string(); self.current_input += &key_press.key.to_string();
} }
@@ -229,12 +209,25 @@ impl WindowLike for Terminal {
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
} else if self.mode == Mode::Input && (key_press.key == 'p' || key_press.key == 'n') { } else if self.mode == Mode::Input && (key_press.key == 'p' || key_press.key == 'n') {
//only the last command is saved unlike other terminals. good enough for me //only the last command is saved unlike other terminals. good enough for me
if key_press.key == 'p' && self.last_command.is_some() { if key_press.key == 'p' && self.history.len() > 0 {
self.current_input = self.last_command.clone().unwrap(); if let Some(history_index) = self.history_index {
if history_index > 0 {
self.history_index = Some(history_index - 1);
}
} else {
self.history_index = Some(self.history.len() - 1);
}
self.current_input = self.history[self.history_index.unwrap()].clone();
self.calc_actual_lines(); self.calc_actual_lines();
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
} else if key_press.key == 'n' { } else if key_press.key == 'n' {
self.current_input = String::new(); if self.history_index.is_none() || self.history_index.unwrap() == self.history.len() - 1 {
self.history_index = None;
self.current_input = String::new();
} else {
self.history_index = Some(self.history_index.unwrap() + 1);
self.current_input = self.history[self.history_index.unwrap()].clone();
}
self.calc_actual_lines(); self.calc_actual_lines();
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
} else { } else {

View File

@@ -23,7 +23,12 @@ impl WindowLike for Help {
match message { match message {
WindowMessage::Init(dimensions) => { WindowMessage::Init(dimensions) => {
self.dimensions = dimensions; self.dimensions = dimensions;
self.paragraph = Some(Box::new(Paragraph::new("help".to_string(), [2, 22], [self.dimensions[0] - 4, self.dimensions[1] - 24], "Press the 'h' and 'l' keys to read the different help pages".to_string(), ()))); let first_content = if self.files.len() > 0 {
read_to_string(self.files[0].clone()).unwrap()
} else {
String::new()
};
self.paragraph = Some(Box::new(Paragraph::new("help".to_string(), [2, 22], [self.dimensions[0] - 4, self.dimensions[1] - 24], "Press the 'h' and 'l' keys to read the different help pages".to_string() + &first_content, ())));
WindowMessageResponse::JustRedraw WindowMessageResponse::JustRedraw
}, },
WindowMessage::KeyPress(key_press) => { WindowMessage::KeyPress(key_press) => {
@@ -97,4 +102,3 @@ impl Help {
} }
} }
} }

View File

@@ -30,8 +30,8 @@ pub fn get_font_char_from_fonts(fonts: &[String], c: char) -> (char, Vec<Vec<u8>
} }
} }
let p = dirs::exe_dir(Some(&("ming_bmps/".to_string() + &fonts[0]))).to_string_lossy().to_string(); let p = dirs::exe_dir(Some(&("ming_bmps/".to_string() + &fonts[0]))).to_string_lossy().to_string();
//so a ? char must be in every font //so a ? char should be in every font. otherwise will just return blank
get_font_char(&p, '?').unwrap() get_font_char(&p, '?').unwrap_or(('?', vec![vec![0]], 0))
} }
pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> { pub fn get_all_files(dir: PathBuf) -> Vec<PathBuf> {