mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-11-23 21:51:56 +00:00
Compare commits
11 Commits
da38626119
...
6d04cdabe2
Author | SHA1 | Date | |
---|---|---|---|
|
6d04cdabe2 | ||
|
a0752ae35f | ||
|
78b7c3faa1 | ||
|
42a7836b11 | ||
|
ed01e1302f | ||
|
2dabb934f7 | ||
|
6d7d8dbc61 | ||
|
1044517d8e | ||
|
f8c6ba1e59 | ||
|
4a9d726fdb | ||
|
1ff69c7846 |
93
.github/preview.tape
vendored
Normal file
93
.github/preview.tape
vendored
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
# VHS documentation
|
||||||
|
#
|
||||||
|
# Output:
|
||||||
|
# Output <path>.gif Create a GIF output at the given <path>
|
||||||
|
# Output <path>.mp4 Create an MP4 output at the given <path>
|
||||||
|
# Output <path>.webm Create a WebM output at the given <path>
|
||||||
|
#
|
||||||
|
# Require:
|
||||||
|
# Require <string> Ensure a program is on the $PATH to proceed
|
||||||
|
#
|
||||||
|
# Settings:
|
||||||
|
# Set FontSize <number> Set the font size of the terminal
|
||||||
|
# Set FontFamily <string> Set the font family of the terminal
|
||||||
|
# Set Height <number> Set the height of the terminal
|
||||||
|
# Set Width <number> Set the width of the terminal
|
||||||
|
# Set LetterSpacing <float> Set the font letter spacing (tracking)
|
||||||
|
# Set LineHeight <float> Set the font line height
|
||||||
|
# Set LoopOffset <float>% Set the starting frame offset for the GIF loop
|
||||||
|
# Set Theme <json|string> Set the theme of the terminal
|
||||||
|
# Set Padding <number> Set the padding of the terminal
|
||||||
|
# Set Framerate <number> Set the framerate of the recording
|
||||||
|
# Set PlaybackSpeed <float> Set the playback speed of the recording
|
||||||
|
# Set MarginFill <file|#000000> Set the file or color the margin will be filled with.
|
||||||
|
# Set Margin <number> Set the size of the margin. Has no effect if MarginFill isn't set.
|
||||||
|
# Set BorderRadius <number> Set terminal border radius, in pixels.
|
||||||
|
# Set WindowBar <string> Set window bar type. (one of: Rings, RingsRight, Colorful, ColorfulRight)
|
||||||
|
# Set WindowBarSize <number> Set window bar size, in pixels. Default is 40.
|
||||||
|
# Set TypingSpeed <time> Set the typing speed of the terminal. Default is 50ms.
|
||||||
|
#
|
||||||
|
# Sleep:
|
||||||
|
# Sleep <time> Sleep for a set amount of <time> in seconds
|
||||||
|
#
|
||||||
|
# Type:
|
||||||
|
# Type[@<time>] "<characters>" Type <characters> into the terminal with a
|
||||||
|
# <time> delay between each character
|
||||||
|
#
|
||||||
|
# Keys:
|
||||||
|
# Escape[@<time>] [number] Press the Escape key
|
||||||
|
# Backspace[@<time>] [number] Press the Backspace key
|
||||||
|
# Delete[@<time>] [number] Press the Delete key
|
||||||
|
# Insert[@<time>] [number] Press the Insert key
|
||||||
|
# Down[@<time>] [number] Press the Down key
|
||||||
|
# Enter[@<time>] [number] Press the Enter key
|
||||||
|
# Space[@<time>] [number] Press the Space key
|
||||||
|
# Tab[@<time>] [number] Press the Tab key
|
||||||
|
# Left[@<time>] [number] Press the Left Arrow key
|
||||||
|
# Right[@<time>] [number] Press the Right Arrow key
|
||||||
|
# Up[@<time>] [number] Press the Up Arrow key
|
||||||
|
# Down[@<time>] [number] Press the Down Arrow key
|
||||||
|
# PageUp[@<time>] [number] Press the Page Up key
|
||||||
|
# PageDown[@<time>] [number] Press the Page Down key
|
||||||
|
# Ctrl+<key> Press the Control key + <key> (e.g. Ctrl+C)
|
||||||
|
#
|
||||||
|
# Display:
|
||||||
|
# Hide Hide the subsequent commands from the output
|
||||||
|
# Show Show the subsequent commands in the output
|
||||||
|
|
||||||
|
Output preview.gif
|
||||||
|
|
||||||
|
Require linutil
|
||||||
|
Require sh
|
||||||
|
|
||||||
|
Set Shell "bash"
|
||||||
|
Set FontFamily "JetBrainsMono Nerd Font"
|
||||||
|
Set FontSize 24
|
||||||
|
Set Width 1920
|
||||||
|
Set Height 1080
|
||||||
|
|
||||||
|
Sleep 1s
|
||||||
|
|
||||||
|
Type "linutil" Sleep 1s Enter
|
||||||
|
|
||||||
|
Sleep 2s
|
||||||
|
|
||||||
|
Left Sleep 1s
|
||||||
|
Down Sleep 1s
|
||||||
|
Down Sleep 1s
|
||||||
|
Down Sleep 1s
|
||||||
|
Down Sleep 1s
|
||||||
|
Right Sleep 1s
|
||||||
|
|
||||||
|
Type "/" Sleep 1s
|
||||||
|
Type@200ms "Full System Cleanup" Sleep 1s Enter
|
||||||
|
|
||||||
|
Sleep 1s
|
||||||
|
Enter Sleep 2s
|
||||||
|
Type "y" # CONFIRMATION PROMPT
|
||||||
|
Sleep 15s
|
||||||
|
Type "y" # SYSTEM CLEANUP PROMPT
|
||||||
|
Enter
|
||||||
|
Sleep 4s
|
||||||
|
Enter
|
||||||
|
Sleep 2s
|
3
.github/workflows/preview.yml
vendored
3
.github/workflows/preview.yml
vendored
|
@ -67,9 +67,10 @@ jobs:
|
||||||
uses: peter-evans/create-pull-request@v7.0.5
|
uses: peter-evans/create-pull-request@v7.0.5
|
||||||
with:
|
with:
|
||||||
commit-message: Preview for ${{ env.tag_name }}
|
commit-message: Preview for ${{ env.tag_name }}
|
||||||
token: ${{ secrets.PAT_TOKEN }}
|
|
||||||
branch: feature/preview-${{ env.tag_name }}
|
branch: feature/preview-${{ env.tag_name }}
|
||||||
title: "Update preview for ${{ env.tag_name }}"
|
title: "Update preview for ${{ env.tag_name }}"
|
||||||
|
labels: |
|
||||||
|
documentation
|
||||||
body: |
|
body: |
|
||||||
Automated PR to update preview gif for version ${{ env.tag_name }}
|
Automated PR to update preview gif for version ${{ env.tag_name }}
|
||||||
![preview](https://raw.githubusercontent.com/${{ github.repository }}/feature/preview-${{ env.tag_name }}/.github/preview.gif)
|
![preview](https://raw.githubusercontent.com/${{ github.repository }}/feature/preview-${{ env.tag_name }}/.github/preview.gif)
|
||||||
|
|
6
Cargo.lock
generated
6
Cargo.lock
generated
|
@ -369,7 +369,7 @@ checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linutil_core"
|
name = "linutil_core"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ego-tree",
|
"ego-tree",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
|
@ -381,7 +381,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linutil_tui"
|
name = "linutil_tui"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"linutil_core",
|
"linutil_core",
|
||||||
|
@ -1264,7 +1264,7 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xtask"
|
name = "xtask"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linutil_core",
|
"linutil_core",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
|
|
|
@ -1,14 +1,29 @@
|
||||||
|
use crate::{ListNode, TabList};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{path::Path, process};
|
use std::{fs, path::Path, process, rc::Rc};
|
||||||
|
|
||||||
|
// Struct that defines what values can be used in the toml file
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub auto_execute: Vec<String>,
|
#[serde(default)]
|
||||||
|
auto_execute: Option<Vec<String>>,
|
||||||
|
#[serde(default)]
|
||||||
|
skip_confirmation: Option<bool>,
|
||||||
|
#[serde(default)]
|
||||||
|
size_bypass: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Struct that holds the parsed values from the toml so that it can be applied in the AppState
|
||||||
|
pub struct ConfigValues {
|
||||||
|
pub auto_execute_commands: Vec<Rc<ListNode>>,
|
||||||
|
pub skip_confirmation: bool,
|
||||||
|
pub size_bypass: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn from_file(path: &Path) -> Self {
|
pub fn read_config(path: &Path, tabs: &TabList) -> ConfigValues {
|
||||||
let content = match std::fs::read_to_string(path) {
|
let content = match fs::read_to_string(path) {
|
||||||
Ok(content) => content,
|
Ok(content) => content,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to read config file {}: {}", path.display(), e);
|
eprintln!("Failed to read config file {}: {}", path.display(), e);
|
||||||
|
@ -16,12 +31,29 @@ impl Config {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match toml::from_str(&content) {
|
let config: Config = match toml::from_str(&content) {
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("Failed to parse config file: {}", e);
|
eprintln!("Failed to parse config file: {}", e);
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigValues {
|
||||||
|
auto_execute_commands: config.auto_execute_commands(tabs),
|
||||||
|
skip_confirmation: config.skip_confirmation.unwrap_or(false),
|
||||||
|
size_bypass: config.size_bypass.unwrap_or(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn auto_execute_commands(&self, tabs: &TabList) -> Vec<Rc<ListNode>> {
|
||||||
|
self.auto_execute
|
||||||
|
.as_ref()
|
||||||
|
.map_or_else(Vec::new, |commands| {
|
||||||
|
commands
|
||||||
|
.iter()
|
||||||
|
.filter_map(|name| tabs.iter().find_map(|tab| tab.find_command_by_name(name)))
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ pub use ego_tree;
|
||||||
use ego_tree::Tree;
|
use ego_tree::Tree;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub use config::Config;
|
pub use config::{Config, ConfigValues};
|
||||||
pub use inner::{get_tabs, TabList};
|
pub use inner::{get_tabs, TabList};
|
||||||
|
|
||||||
#[derive(Clone, Hash, Eq, PartialEq)]
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
|
@ -36,3 +36,12 @@ pub struct ListNode {
|
||||||
pub task_list: String,
|
pub task_list: String,
|
||||||
pub multi_select: bool,
|
pub multi_select: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Tab {
|
||||||
|
fn find_command_by_name(&self, name: &str) -> Option<Rc<ListNode>> {
|
||||||
|
self.tree.root().descendants().find_map(|node| {
|
||||||
|
let node_value = node.value();
|
||||||
|
(node_value.name == name && !node.has_children()).then_some(node_value.clone())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ tui-term = "0.2.0"
|
||||||
time = { version = "0.3.36", features = ["formatting", "local-offset", "macros"], default-features = false }
|
time = { version = "0.3.36", features = ["formatting", "local-offset", "macros"], default-features = false }
|
||||||
unicode-width = { version = "0.2.0", default-features = false }
|
unicode-width = { version = "0.2.0", default-features = false }
|
||||||
rand = { version = "0.8.5", optional = true }
|
rand = { version = "0.8.5", optional = true }
|
||||||
linutil_core = { version = "24.9.28", path = "../core" }
|
linutil_core = { version = "24.10.31", path = "../core" }
|
||||||
tree-sitter-highlight = "0.24.4"
|
tree-sitter-highlight = "0.24.4"
|
||||||
tree-sitter-bash = "0.23.3"
|
tree-sitter-bash = "0.23.3"
|
||||||
nix = { version = "0.29.0", features = [ "user" ] }
|
nix = { version = "0.29.0", features = [ "user" ] }
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
theme::Theme,
|
theme::Theme,
|
||||||
Args,
|
Args,
|
||||||
};
|
};
|
||||||
use linutil_core::{ego_tree::NodeId, Command, Config, ListNode, TabList};
|
use linutil_core::{ego_tree::NodeId, Command, Config, ConfigValues, ListNode, TabList};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind},
|
crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind},
|
||||||
layout::Flex,
|
layout::Flex,
|
||||||
|
@ -98,10 +98,6 @@ impl AppState {
|
||||||
let tabs = linutil_core::get_tabs(!args.override_validation);
|
let tabs = linutil_core::get_tabs(!args.override_validation);
|
||||||
let root_id = tabs[0].tree.root().id();
|
let root_id = tabs[0].tree.root().id();
|
||||||
|
|
||||||
let auto_execute_commands = args
|
|
||||||
.config
|
|
||||||
.map(|path| Config::from_file(&path).auto_execute);
|
|
||||||
|
|
||||||
let longest_tab_display_len = tabs
|
let longest_tab_display_len = tabs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|tab| tab.name.len() + args.theme.tab_icon().len())
|
.map(|tab| tab.name.len() + args.theme.tab_icon().len())
|
||||||
|
@ -133,28 +129,26 @@ impl AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
state.update_items();
|
state.update_items();
|
||||||
if let Some(auto_execute_commands) = auto_execute_commands {
|
|
||||||
state.handle_initial_auto_execute(&auto_execute_commands);
|
if let Some(config_path) = args.config {
|
||||||
|
let config = Config::read_config(&config_path, &state.tabs);
|
||||||
|
state.apply_config(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
state
|
state
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_command_by_name(&self, name: &str) -> Option<Rc<ListNode>> {
|
fn apply_config(&mut self, config_values: ConfigValues) {
|
||||||
self.tabs.iter().find_map(|tab| {
|
self.skip_confirmation = self.skip_confirmation || config_values.skip_confirmation;
|
||||||
tab.tree.root().descendants().find_map(|node| {
|
self.size_bypass = self.size_bypass || config_values.size_bypass;
|
||||||
let node_value = node.value();
|
|
||||||
(node_value.name == name && !node.has_children()).then_some(node_value.clone())
|
if !config_values.auto_execute_commands.is_empty() {
|
||||||
})
|
self.selected_commands = config_values.auto_execute_commands;
|
||||||
})
|
self.handle_initial_auto_execute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_initial_auto_execute(&mut self, auto_execute_commands: &[String]) {
|
fn handle_initial_auto_execute(&mut self) {
|
||||||
self.selected_commands = auto_execute_commands
|
|
||||||
.iter()
|
|
||||||
.filter_map(|name| self.find_command_by_name(name))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if !self.selected_commands.is_empty() {
|
if !self.selected_commands.is_empty() {
|
||||||
self.spawn_confirmprompt();
|
self.spawn_confirmprompt();
|
||||||
}
|
}
|
||||||
|
@ -251,7 +245,8 @@ impl AppState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_terminal_drawable(&mut self, terminal_size: Rect) -> bool {
|
fn is_terminal_drawable(&mut self, terminal_size: Rect) -> bool {
|
||||||
!self.size_bypass && (terminal_size.height < MIN_HEIGHT || terminal_size.width < MIN_WIDTH)
|
!(self.size_bypass || matches!(self.focus, Focus::FloatingWindow(_)))
|
||||||
|
&& (terminal_size.height < MIN_HEIGHT || terminal_size.width < MIN_WIDTH)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&mut self, frame: &mut Frame) {
|
pub fn draw(&mut self, frame: &mut Frame) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user