diff options
author | qkzk <qkzk@users.noreply.github.com> | 2024-09-24 21:18:46 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-24 21:18:46 +0200 |
commit | 272e8d862650a30c76699fec02b1e88ec2df38cd (patch) | |
tree | 06966e1375120d2f9225a2b82f8fe193f5ede75b | |
parent | de9173906fbbfc595bfd4fb6ef1866e8841bb292 (diff) | |
parent | c7e26b15c6ef1a4e3f492c83e8ae96a2973ea347 (diff) |
Merge pull request #97 from qkzk/v0.1.29-devv0.1.29
V0.1.29 dev
64 files changed, 1802 insertions, 2014 deletions
@@ -932,7 +932,7 @@ dependencies = [ [[package]] name = "fm-tui" -version = "0.1.28" +version = "0.1.29" dependencies = [ "anyhow", "chrono", @@ -1,6 +1,6 @@ [package] name = "fm-tui" -version = "0.1.28" +version = "0.1.29" authors = ["Quentin Konieczko <qu3nt1n@gmail.com>"] edition = "2021" license-file = "LICENSE.txt" @@ -20,25 +20,6 @@ fn main() { Ok(_) => (), Err(e) => eprintln!("{e:?}"), } - - update_breaking_config() -} - -/// Remove old binds from user config file. -/// -/// Remove all binds to `Jump` and `Mocp...` variants since they were removed from fm. -fn update_breaking_config() { - let config = tilde("~/.config/fm/config.yaml"); - let config: &str = config.borrow(); - let content = std::fs::read_to_string(config) - .expect("config file should be readable") - .lines() - .map(String::from) - .filter(|line| !line.contains("Jump")) - .filter(|line| !line.contains("Mocp")) - .collect::<Vec<String>>() - .join("\n"); - std::fs::write(config, content).expect("config should be writabe"); } fn home_dir() -> Option<std::path::PathBuf> { diff --git a/config_files/fm/config.yaml b/config_files/fm/config.yaml index ca0157f1..31d2b33f 100644 --- a/config_files/fm/config.yaml +++ b/config_files/fm/config.yaml @@ -7,53 +7,54 @@ terminal: st # configurable colors -# Define a palette for the "normal" files. -# File will be colored randomly from their extensions. -# Accepted values are "red", "green", "blue" or a rgb color +# Colors for "non normal" files. The list is below. +# you can define an ANSI color or an rgb color for any kind of file except "normal" files. +# colors for normal files are calculated on the fly from the "palette" values provided above. +# List of allowed ANSI colors: +# white, black, red, green, blue, yellow, cyan, magenta +# light_white, light_black, light_red, light_green, light_blue, light_yellow, light_cyan, light_magenta # Allowed Format for rgb color : # - `rgb(r, g, b)` where r, g and b are integers between 0 and 255 included. # - `#rrggbb` aka hex colors, where rr, gg and bb are hexadecimals -# Unfortunatelly, not all ansi color names are accepted. -# palette: -# start: "rgb(255, 110, 128)" -# stop: "rgb(123, 100, 255)" -palette: - start: green - stop: blue - -# Colors for "non normal" files. The list is below. colors: - # you can define an ANSI color or an rgb color for any kind of file except "normal" files. - # colors for normal files are calculated on the fly. - # List of allowed colors: - # white, black, red, green, blue, yellow, cyan, magenta - # light_white, light_black, light_red, light_green, light_blue, light_yellow, light_cyan, light_magenta - # Allowed Format for rgb color : - # - `rgb(r, g, b)` where r, g and b are integers between 0 and 255 included. - # - `#rrggbb` aka hex colors, where rr, gg and bb are hexadecimals - directory: red - block: yellow - char: green - fifo: blue - socket: cyan - symlink: magenta - broken: light_magenta + # Gradient from start to stop for normal files. + # the files are colored randomly according to their extension + # ANSI colors won't be linked to their configured values but to the default ANSI values. + normal_start: rgb(187, 102, 255) + normal_stop: rgb(255, 102, 187) + + # color for different filekinds + # here you can use ANSI values + # colors for folders / directory + directory: rgb(45, 250, 209) + # block device (hard drives...) + block: rgb(231, 100, 100) + # char devices (ttys, /dev/urandom etc.) + char: rgb(230, 189, 87) + # fifos + fifo: rgb(180, 255, 255) + # opened sockets + socket: rgb(231, 100, 100) + # valid symlinks + symlink: rgb(59, 204, 255) + # broken symlinks + broken: rgb(140, 140, 140) -# Colors for menus, headers, footers etc. -menu_colors: + # Colors for menus, headers, footers etc. + # The same values are accepted. # first color - first: rgb(45, 250, 209) + header_first: rgb(45, 250, 209) # second color - second: rgb(230, 189, 87) + header_second: rgb(230, 189, 87) # selected tab border - selected_border: rgb(45, 250, 209) + selected_border: rgb(45, 250, 209) # non selected tab border - inert_border: rgb(120, 120, 120) - # palette of 4 elements, used in menus (second window) and header - palette_1: rgb(45, 250, 209) - palette_2: rgb(230, 189, 87) - palette_3: rgb(230, 167, 255) - palette_4: rgb(59, 204, 255) + inert_border: rgb(120, 120, 120) + # palette of 4 elements, used in menus (second window) + palette_1: rgb(45, 250, 209) + palette_2: rgb(230, 189, 87) + palette_3: rgb(230, 167, 255) + palette_4: rgb(59, 204, 255) # keybindings # @@ -148,6 +149,7 @@ keys: custom: # open the selected file with chrome 'alt-u': "/usr/bin/google-chrome-stable %s" + # drag & drop the selected file to a GUI application 'shift-d': "/usr/bin/dragon-drop %s" # DO NOT EDIT UNLESS YOU WANT TO ADD AN UNKNOWN TERMINAL EMULATOR diff --git a/development.md b/development.md index 867c1667..4c73a137 100644 --- a/development.md +++ b/development.md @@ -1052,8 +1052,6 @@ New view: Tree ! Toggle with 't', fold with 'z'. Navigate normally. - [ ] FIX: alt + g, type, complete, back crash. Can't reproduce - [x] FIX: too much thing on menu and last line -## Current dev - ### Version 0.1.28 #### Summary @@ -1102,10 +1100,71 @@ New view: Tree ! Toggle with 't', fold with 'z'. Navigate normally. - [x] Fix: opening tree mode with selection on "." doesn't display "." as selected - [x] refactor draw tree line - [x] Fix: Crash when quiting. "sending on a closed channel". From quit -> refresher::quit +- [ ] - [ ] Badges to latest version +## Current dev + +### Version 0.1.29 + +#### Summary + +- Fixed the documentation and updated the badges +- Flagged files are now displayed in a menu instead of the main window. You can still jump to them, removed them individually +- Fix jump mode (Alt+g) to allow paths to file. It will jump there and select the file. +- Preview valid symlink as their target. Broken symlink aren't previewed at all +- Fixed a few bugs. See details below. +- **Breaking changes**: color configuration. + + Only one mapping is used in config.yml. All colors are now regrouped there. + Some names have changed : + + - "start" -> "normal_start" + - "stop" -> "normal_stop" + + Your old config will still be loaded, but their colors won't be recognized unless you update the config. + See the [source](config_file/fm/config.yml) for more infos. + +#### Changelog + +- [x] refactor path reducer +- [x] Fix: when ".." is selected, header path is wrong. This is a big one... +- [x] Fix: directory mode when path is root, header is wrong, should just be "/""run" not "/""/run" +- [x] Fix attempt of docs. Don't panic in build if no config file is found. That was dumb +- [x] Fix: Tree mode, when path is root, header is wrong +- [x] Alt+g should accept pathes to file from input and go there +- [x] Preview refactor + - [x] mod for ueberzug + - [x] builder for ueberzug + - [x] creator for thumbnail + - [x] video slideshow + - [x] Fix: ueberzug creation may crash the app (poison lock etc.) `Error: Error locking status: poisoned lock: another task failed inside` + - [x] preview builder + - [x] preview symlink to folder as the target + - [x] preview symlink to files as the target. Must change PreviewBuilder completely + - [x] merge all previews which hold text into a single variant + - [x] simplify the mess as much as possible +- [x] flagged should be a menu + - [x] use a menu to display flagged files + - [x] display binds +- [x] refactor context menu "more info" into a struct with explicit methods +- [x] simplify history a little +- [x] simplify color configuration + - [x] only one "colors" map in yaml file + - [x] migration of config file : detailed in release + ## TODO +- [ ] google drive should be a display ? +- [ ] status, tab, event exec refactor. What should go where ? status is too big and should be splitted +- [ ] menus refactor + - [ ] open 2 menus at once + - [ ] maybe use the same system as preview, create them on the fly + - [ ] attach menus to tab, where they belong + - [ ] leaving left menu shouldn't reset right menu +- [ ] replace tuikit by ratatui + crossterm +- [ ] Focus & mouseover. Mousemove require raw terminal mode.. Requires to rewrite every event (Mousepress, mouse release etc.) + Another motivation to switch to ratatui + crossterm. - [ ] ideas from broot : https://dystroy.org/broot/#apply-commands-on-several-files - [ ] floating windows ? - [ ] rclone diff --git a/src/app/application.rs b/src/app/application.rs index c67e7db1..fbfe7f19 100644 --- a/src/app/application.rs +++ b/src/app/application.rs @@ -2,31 +2,18 @@ use std::process::exit; use std::sync::Arc; use std::sync::Mutex; -use anyhow::anyhow; -use anyhow::Context; -use anyhow::Result; +use anyhow::{anyhow, Context, Result}; use clap::Parser; -use crate::app::Displayer; -use crate::app::Refresher; -use crate::app::Status; -use crate::common::CONFIG_PATH; -use crate::common::{clear_tmp_file, init_term}; -use crate::config::cloud_config; -use crate::config::load_config; -use crate::config::set_configurable_static; -use crate::config::Config; -use crate::config::START_FOLDER; -use crate::event::EventDispatcher; -use crate::event::EventReader; -use crate::event::FmEvents; -use crate::io::set_loggers; -use crate::io::Args; -use crate::io::Opener; +use crate::app::{Displayer, Refresher, Status}; +use crate::common::{clear_tmp_files, init_term, print_on_quit, CONFIG_PATH}; +use crate::config::{cloud_config, load_config, set_configurable_static, Config, START_FOLDER}; +use crate::event::{EventDispatcher, EventReader, FmEvents}; +use crate::io::{set_loggers, Args, Opener}; use crate::log_info; /// Holds everything about the application itself. -/// Most attributes holds an `Arc<tuikit::Term::term>`. +/// Most attributes holds an [`std::sync::Arc`] with [`tuikit::term::Term`]. /// Dropping the instance of FM allows to write again to stdout. pub struct FM { /// Poll the event sent to the terminal by the user or the OS @@ -127,7 +114,7 @@ impl FM { fn exit_wrong_config() -> ! { eprintln!("Couldn't load the config file at {CONFIG_PATH}. See https://raw.githubusercontent.com/qkzk/fm/master/config_files/fm/config.yaml for an example."); log_info!("Couldn't read the config file {CONFIG_PATH}"); - std::process::exit(1) + exit(1) } /// Return the last event received by the terminal @@ -160,15 +147,15 @@ impl FM { } } - /// Run the status loop. - pub fn run(&mut self) -> Result<()> { + /// Run the status loop and returns itself after completion. + pub fn run(mut self) -> Result<Self> { while let Ok(event) = self.poll_event() { self.update(event)?; if self.must_quit()? { break; } } - Ok(()) + Ok(self) } /// Display the cursor, @@ -179,19 +166,22 @@ impl FM { /// /// May fail if the terminal crashes /// May also fail if the thread running in [`crate::app::Refresher`] crashed - pub fn quit(self) -> Result<String> { - clear_tmp_file(); + pub fn quit(self) -> Result<()> { + let final_path = self + .status + .lock() + .map_err(|error| anyhow!("Error locking status: {error}"))? + .current_tab_path_str() + .to_owned(); + + clear_tmp_files(); drop(self.event_reader); drop(self.event_dispatcher); self.displayer.quit(); self.refresher.quit(); + drop(self.status); - let status = self - .status - .lock() - .map_err(|error| anyhow!("Error locking status: {error}"))?; - let final_path = status.current_tab_path_str().to_owned(); - drop(status); - Ok(final_path) + print_on_quit(final_path); + Ok(()) } } diff --git a/src/app/header_footer.rs b/src/app/header_footer.rs index 39697129..7af21ab3 100644 --- a/src/app/header_footer.rs +++ b/src/app/header_footer.rs @@ -3,17 +3,16 @@ mod inner { use crate::app::{Status, Tab}; use crate::common::{ - UtfWidth, HELP_FIRST_SENTENCE, HELP_SECOND_SENTENCE, LOG_FIRST_SENTENCE, + PathShortener, UtfWidth, HELP_FIRST_SENTENCE, HELP_SECOND_SENTENCE, LOG_FIRST_SENTENCE, LOG_SECOND_SENTENCE, }; use crate::event::ActionMap; use crate::modes::{ - shorten_path, ColoredText, Content, Display, FileInfo, FilterKind, Preview, Search, - Selectable, TextKind, + Content, Display, FileInfo, FilterKind, Preview, Search, Selectable, Text, TextKind, }; #[derive(Clone, Copy)] - pub enum HorizontalAlign { + pub enum Align { Left, Right, } @@ -36,11 +35,11 @@ mod inner { /// It calculates its position with `col` and `align`. /// If left aligned, the text size will be added to `col` and the text will span from col to col + width. /// otherwise, the text will spawn from col - width to col. - fn new(text: String, align: HorizontalAlign, action: ActionMap, col: usize) -> Self { + fn new(text: String, align: Align, action: ActionMap, col: usize) -> Self { let width = text.utf_width(); let (left, right) = match align { - HorizontalAlign::Left => (col, col + width), - HorizontalAlign::Right => (col - width - 3, col - 3), + Align::Left => (col, col + width), + Align::Right => (col - width - 3, col - 3), }; Self { text, @@ -146,8 +145,13 @@ mod inner { fn elem_shorten_path(tab: &Tab, left: usize) -> Result<ClickableString> { Ok(ClickableString::new( - format!(" {}", shorten_path(&tab.directory.path, None)?), - HorizontalAlign::Left, + format!( + " {}", + PathShortener::path(&tab.directory.path) + .context("Couldn't parse path")? + .shorten() + ), + Align::Left, ActionMap::Cd, left, )) @@ -155,43 +159,48 @@ mod inner { fn elem_filename(tab: &Tab, width: usize, left: usize) -> Result<ClickableString> { let text = match tab.display_mode { - Display::Tree => format!( - "/{rel}", - rel = - shorten_path(tab.tree.selected_path_relative_to_root()?, Some(width / 2))? - ), - _ => { - if let Some(fileinfo) = tab.directory.selected() { - fileinfo.filename_without_dot_dotdot() - } else { - "".to_owned() - } - } + Display::Tree => Self::elem_tree_filename(tab, width)?, + _ => Self::elem_directory_filename(tab), }; Ok(ClickableString::new( text, - HorizontalAlign::Left, + Align::Left, ActionMap::Rename, left, )) } + fn elem_tree_filename(tab: &Tab, width: usize) -> Result<String> { + Ok(format!( + "{sep}{rel}", + rel = PathShortener::path(tab.tree.selected_path_relative_to_root()?) + .context |