mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-11-21 12:59:41 +00:00
Compare commits
14 Commits
e583fc7864
...
eeb501401a
Author | SHA1 | Date | |
---|---|---|---|
|
eeb501401a | ||
|
a8343155e5 | ||
|
692bff1627 | ||
|
d1baa44833 | ||
|
93eb1196e8 | ||
|
6dae016104 | ||
|
684346272d | ||
|
6e84cb301b | ||
|
fbfcd5002c | ||
|
961511fb72 | ||
|
55fed66f0b | ||
|
fa69885b6c | ||
|
2dabb934f7 | ||
|
6d7d8dbc61 |
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)
|
||||||
|
|
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -381,7 +381,21 @@ checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linutil_core"
|
name = "linutil_core"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
|
dependencies = [
|
||||||
|
"ego-tree",
|
||||||
|
"include_dir",
|
||||||
|
"serde",
|
||||||
|
"temp-dir",
|
||||||
|
"toml",
|
||||||
|
"which",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linutil_core"
|
||||||
|
version = "24.10.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2990ea580e635f6700ae19bd0f5fa60c7037799908da476b0c233b9e514c1481"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ego-tree",
|
"ego-tree",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
|
@ -393,12 +407,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linutil_tui"
|
name = "linutil_tui"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi-to-tui",
|
"ansi-to-tui",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"clap",
|
"clap",
|
||||||
"linutil_core",
|
"linutil_core 24.10.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.29.0",
|
"nix 0.29.0",
|
||||||
"oneshot",
|
"oneshot",
|
||||||
"portable-pty",
|
"portable-pty",
|
||||||
|
@ -411,6 +425,7 @@ dependencies = [
|
||||||
"tree-sitter-highlight",
|
"tree-sitter-highlight",
|
||||||
"tui-term",
|
"tui-term",
|
||||||
"unicode-width 0.2.0",
|
"unicode-width 0.2.0",
|
||||||
|
"vt100-ctt",
|
||||||
"zips",
|
"zips",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1082,7 +1097,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72af159125ce32b02ceaced6cffae6394b0e6b6dfd4dc164a6c59a2db9b3c0b0"
|
checksum = "72af159125ce32b02ceaced6cffae6394b0e6b6dfd4dc164a6c59a2db9b3c0b0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"vt100",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1133,9 +1147,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vt100"
|
name = "vt100-ctt"
|
||||||
version = "0.15.2"
|
version = "0.15.3"
|
||||||
source = "git+https://github.com/ChrisTitusTech/vt100-rust#e41fb3d8fb5fd01dd2d076c9a25823a31656012f"
|
source = "git+https://github.com/ChrisTitusTech/vt100-rust#39136a6232d043d8447afa7d47805b6f6baa09ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1303,9 +1317,9 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xtask"
|
name = "xtask"
|
||||||
version = "24.9.28"
|
version = "24.10.31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"linutil_core",
|
"linutil_core 24.10.31",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -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]
|
||||||
|
@ -8,9 +8,6 @@ members = ["tui", "core", "xtask"]
|
||||||
default-members = ["tui", "core"]
|
default-members = ["tui", "core"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[patch.crates-io]
|
|
||||||
vt100 = { git = "https://github.com/ChrisTitusTech/vt100-rust" }
|
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "z"
|
opt-level = "z"
|
||||||
debug = false
|
debug = false
|
||||||
|
|
|
@ -18,12 +18,12 @@ clap = { version = "4.5.20", features = ["derive", "std"], default-features = fa
|
||||||
oneshot = { version = "0.1.8", features = ["std"], default-features = false }
|
oneshot = { version = "0.1.8", features = ["std"], default-features = false }
|
||||||
portable-pty = "0.8.1"
|
portable-pty = "0.8.1"
|
||||||
ratatui = { version = "0.29.0", features = ["crossterm"], default-features = false }
|
ratatui = { version = "0.29.0", features = ["crossterm"], default-features = false }
|
||||||
tui-term = "0.2.0"
|
tui-term = { version = "0.2.0", default-features = false }
|
||||||
temp-dir = "0.1.14"
|
temp-dir = "0.1.14"
|
||||||
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" }
|
||||||
tree-sitter-highlight = "0.24.3"
|
tree-sitter-highlight = "0.24.3"
|
||||||
tree-sitter-bash = "0.23.1"
|
tree-sitter-bash = "0.23.1"
|
||||||
textwrap = { version = "0.16.1", default-features = false }
|
textwrap = { version = "0.16.1", default-features = false }
|
||||||
|
@ -31,6 +31,7 @@ anstyle = { version = "1.0.8", default-features = false }
|
||||||
ansi-to-tui = { version = "7.0.0", default-features = false }
|
ansi-to-tui = { version = "7.0.0", default-features = false }
|
||||||
zips = "0.1.7"
|
zips = "0.1.7"
|
||||||
nix = { version = "0.29.0", features = [ "user" ] }
|
nix = { version = "0.29.0", features = [ "user" ] }
|
||||||
|
vt100-ctt = { git = "https://github.com/ChrisTitusTech/vt100-rust" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "linutil"
|
name = "linutil"
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::borrow::Cow;
|
||||||
use crate::{float::FloatContent, hint::Shortcut};
|
use crate::{float::FloatContent, hint::Shortcut};
|
||||||
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm::event::{KeyCode, KeyEvent, MouseEvent, MouseEventKind},
|
crossterm::event::{KeyCode, KeyEvent, MouseButton, MouseEvent, MouseEventKind},
|
||||||
layout::Alignment,
|
layout::Alignment,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
widgets::{Block, Borders, Clear, List},
|
widgets::{Block, Borders, Clear, List},
|
||||||
|
@ -87,15 +87,24 @@ impl FloatContent for ConfirmPrompt {
|
||||||
|
|
||||||
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
|
MouseEventKind::Down(MouseButton::Left) => {
|
||||||
|
self.status = ConfirmStatus::Confirm;
|
||||||
|
true
|
||||||
|
}
|
||||||
|
MouseEventKind::Down(MouseButton::Right) => {
|
||||||
|
self.status = ConfirmStatus::Abort;
|
||||||
|
false
|
||||||
|
}
|
||||||
MouseEventKind::ScrollDown => {
|
MouseEventKind::ScrollDown => {
|
||||||
self.scroll_down();
|
self.scroll_down();
|
||||||
|
false
|
||||||
}
|
}
|
||||||
MouseEventKind::ScrollUp => {
|
MouseEventKind::ScrollUp => {
|
||||||
self.scroll_up();
|
self.scroll_up();
|
||||||
|
false
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => false,
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use ratatui::{
|
||||||
Frame,
|
Frame,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::hint::Shortcut;
|
use crate::{event::MouseButton, event::MouseEventKind, hint::Shortcut};
|
||||||
|
|
||||||
pub trait FloatContent {
|
pub trait FloatContent {
|
||||||
fn draw(&mut self, frame: &mut Frame, area: Rect);
|
fn draw(&mut self, frame: &mut Frame, area: Rect);
|
||||||
|
@ -54,8 +54,14 @@ impl<Content: FloatContent + ?Sized> Float<Content> {
|
||||||
self.content.draw(frame, popup_area);
|
self.content.draw(frame, popup_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_mouse_event(&mut self, event: &MouseEvent) {
|
pub fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
||||||
self.content.handle_mouse_event(event);
|
match event.kind {
|
||||||
|
MouseEventKind::Down(MouseButton::Right) => {
|
||||||
|
self.content.handle_mouse_event(event);
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => self.content.handle_mouse_event(event),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the floating window is finished.
|
// Returns true if the floating window is finished.
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{float::FloatContent, hint::Shortcut};
|
||||||
use linutil_core::Command;
|
use linutil_core::Command;
|
||||||
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm::event::{KeyCode, KeyEvent, MouseEvent, MouseEventKind},
|
crossterm::event::{KeyCode, KeyEvent, MouseButton, MouseEvent, MouseEventKind},
|
||||||
layout::Rect,
|
layout::Rect,
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
text::Line,
|
text::Line,
|
||||||
|
@ -33,6 +33,8 @@ pub struct FloatingText {
|
||||||
mode_title: String,
|
mode_title: String,
|
||||||
wrap_words: bool,
|
wrap_words: bool,
|
||||||
frame_height: usize,
|
frame_height: usize,
|
||||||
|
drag_start_y: Option<u16>,
|
||||||
|
drag_start_scroll: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! style {
|
macro_rules! style {
|
||||||
|
@ -141,6 +143,8 @@ impl FloatingText {
|
||||||
h_scroll: 0,
|
h_scroll: 0,
|
||||||
wrap_words,
|
wrap_words,
|
||||||
frame_height: 0,
|
frame_height: 0,
|
||||||
|
drag_start_y: None,
|
||||||
|
drag_start_scroll: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +169,8 @@ impl FloatingText {
|
||||||
v_scroll: 0,
|
v_scroll: 0,
|
||||||
wrap_words: false,
|
wrap_words: false,
|
||||||
frame_height: 0,
|
frame_height: 0,
|
||||||
|
drag_start_y: None,
|
||||||
|
drag_start_scroll: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +212,19 @@ impl FloatingText {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_drag(&mut self, current_y: u16) {
|
||||||
|
if let (Some(start_y), Some(start_scroll)) = (self.drag_start_y, self.drag_start_scroll) {
|
||||||
|
let delta = start_y as i32 - current_y as i32;
|
||||||
|
let new_scroll = start_scroll as i32 + delta;
|
||||||
|
|
||||||
|
let max_scroll = self
|
||||||
|
.wrapped_lines
|
||||||
|
.len()
|
||||||
|
.saturating_sub(self.frame_height.saturating_sub(2));
|
||||||
|
self.v_scroll = new_scroll.clamp(0, max_scroll as i32) as usize;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatContent for FloatingText {
|
impl FloatContent for FloatingText {
|
||||||
|
@ -285,6 +304,17 @@ impl FloatContent for FloatingText {
|
||||||
|
|
||||||
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
fn handle_mouse_event(&mut self, event: &MouseEvent) -> bool {
|
||||||
match event.kind {
|
match event.kind {
|
||||||
|
MouseEventKind::Down(MouseButton::Left) => {
|
||||||
|
self.drag_start_y = Some(event.row);
|
||||||
|
self.drag_start_scroll = Some(self.v_scroll);
|
||||||
|
}
|
||||||
|
MouseEventKind::Up(MouseButton::Left) => {
|
||||||
|
self.drag_start_y = None;
|
||||||
|
self.drag_start_scroll = None;
|
||||||
|
}
|
||||||
|
MouseEventKind::Drag(MouseButton::Left) => {
|
||||||
|
self.handle_drag(event.row);
|
||||||
|
}
|
||||||
MouseEventKind::ScrollDown => self.scroll_down(),
|
MouseEventKind::ScrollDown => self.scroll_down(),
|
||||||
MouseEventKind::ScrollUp => self.scroll_up(),
|
MouseEventKind::ScrollUp => self.scroll_up(),
|
||||||
MouseEventKind::ScrollLeft => self.scroll_left(),
|
MouseEventKind::ScrollLeft => self.scroll_left(),
|
||||||
|
|
|
@ -18,10 +18,9 @@ use std::{
|
||||||
thread::JoinHandle,
|
thread::JoinHandle,
|
||||||
};
|
};
|
||||||
use time::{macros::format_description, OffsetDateTime};
|
use time::{macros::format_description, OffsetDateTime};
|
||||||
use tui_term::{
|
use tui_term::widget::PseudoTerminal;
|
||||||
vt100::{self, Screen},
|
use vt100_ctt::{Parser, Screen};
|
||||||
widget::PseudoTerminal,
|
|
||||||
};
|
|
||||||
pub struct RunningCommand {
|
pub struct RunningCommand {
|
||||||
/// A buffer to save all the command output (accumulates, until the command exits)
|
/// A buffer to save all the command output (accumulates, until the command exits)
|
||||||
buffer: Arc<Mutex<Vec<u8>>>,
|
buffer: Arc<Mutex<Vec<u8>>>,
|
||||||
|
@ -114,7 +113,7 @@ impl FloatContent for RunningCommand {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
true
|
false
|
||||||
}
|
}
|
||||||
/// Handle key events of the running command "window". Returns true when the "window" should be
|
/// Handle key events of the running command "window". Returns true when the "window" should be
|
||||||
/// closed
|
/// closed
|
||||||
|
@ -285,7 +284,7 @@ impl RunningCommand {
|
||||||
// Process the buffer with a parser with the current screen size
|
// Process the buffer with a parser with the current screen size
|
||||||
// We don't actually need to create a new parser every time, but it is so much easier this
|
// We don't actually need to create a new parser every time, but it is so much easier this
|
||||||
// way, and doesn't cost that much
|
// way, and doesn't cost that much
|
||||||
let mut parser = vt100::Parser::new(size.height, size.width, 1000);
|
let mut parser = Parser::new(size.height, size.width, 1000);
|
||||||
let mutex = self.buffer.lock();
|
let mutex = self.buffer.lock();
|
||||||
let buffer = mutex.as_ref().unwrap();
|
let buffer = mutex.as_ref().unwrap();
|
||||||
parser.process(buffer);
|
parser.process(buffer);
|
||||||
|
|
141
tui/src/state.rs
141
tui/src/state.rs
|
@ -13,7 +13,9 @@ use linutil_core::{ego_tree::NodeId, Config, ListNode, TabList};
|
||||||
#[cfg(feature = "tips")]
|
#[cfg(feature = "tips")]
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseEvent, MouseEventKind},
|
crossterm::event::{
|
||||||
|
KeyCode, KeyEvent, KeyEventKind, KeyModifiers, MouseButton, MouseEvent, MouseEventKind,
|
||||||
|
},
|
||||||
layout::{Alignment, Constraint, Direction, Flex, Layout, Position, Rect},
|
layout::{Alignment, Constraint, Direction, Flex, Layout, Position, Rect},
|
||||||
style::{Style, Stylize},
|
style::{Style, Stylize},
|
||||||
text::{Line, Span, Text},
|
text::{Line, Span, Text},
|
||||||
|
@ -481,7 +483,7 @@ impl AppState {
|
||||||
|
|
||||||
match &mut self.focus {
|
match &mut self.focus {
|
||||||
Focus::FloatingWindow(float) => float.draw(frame, chunks[1]),
|
Focus::FloatingWindow(float) => float.draw(frame, chunks[1]),
|
||||||
Focus::ConfirmationPrompt(prompt) => prompt.draw(frame, chunks[1]),
|
Focus::ConfirmationPrompt(confirm) => confirm.draw(frame, chunks[1]),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,51 +495,138 @@ impl AppState {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches!(self.focus, Focus::TabList | Focus::List) {
|
match &mut self.focus {
|
||||||
|
Focus::FloatingWindow(float) => {
|
||||||
|
if float.handle_mouse_event(event) {
|
||||||
|
self.focus = Focus::List;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Focus::ConfirmationPrompt(confirm) => {
|
||||||
|
if confirm.handle_mouse_event(event) {
|
||||||
|
match confirm.content.status {
|
||||||
|
ConfirmStatus::Abort => {
|
||||||
|
self.focus = Focus::List;
|
||||||
|
if !self.multi_select {
|
||||||
|
self.selected_commands.clear()
|
||||||
|
} else if let Some(node) = self.get_selected_node() {
|
||||||
|
if !node.multi_select {
|
||||||
|
self.selected_commands.retain(|cmd| cmd.name != node.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ConfirmStatus::Confirm => self.handle_confirm_command(),
|
||||||
|
ConfirmStatus::None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if matches!(self.focus, Focus::TabList | Focus::List | Focus::Search) {
|
||||||
let position = Position::new(event.column, event.row);
|
let position = Position::new(event.column, event.row);
|
||||||
let mouse_in_tab_list = self.areas.as_ref().unwrap().tab_list.contains(position);
|
let mouse_in_tab_list = self.areas.as_ref().unwrap().tab_list.contains(position);
|
||||||
let mouse_in_list = self.areas.as_ref().unwrap().list.contains(position);
|
let mouse_in_list = self.areas.as_ref().unwrap().list.contains(position);
|
||||||
|
|
||||||
|
let mouse_in_search = if let Some(areas) = &self.areas {
|
||||||
|
position.y >= areas.list.y
|
||||||
|
&& position.y < areas.list.y + 3
|
||||||
|
&& position.x >= areas.list.x
|
||||||
|
&& position.x < areas.list.x + areas.list.width
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
match event.kind {
|
match event.kind {
|
||||||
MouseEventKind::Moved => {
|
MouseEventKind::Moved => {
|
||||||
if mouse_in_list {
|
if mouse_in_search {
|
||||||
self.focus = Focus::List
|
if !matches!(self.focus, Focus::Search) {
|
||||||
|
self.focus = Focus::Search;
|
||||||
|
self.filter.activate_search();
|
||||||
|
}
|
||||||
|
} else if mouse_in_list {
|
||||||
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
|
self.focus = Focus::List;
|
||||||
|
if let Some(areas) = &self.areas {
|
||||||
|
let list_start = areas.list.y + 4;
|
||||||
|
let relative_y = position.y.saturating_sub(list_start);
|
||||||
|
let list_len = self.filter.item_list().len();
|
||||||
|
let adjusted_len = if self.at_root() {
|
||||||
|
list_len
|
||||||
|
} else {
|
||||||
|
list_len + 1
|
||||||
|
};
|
||||||
|
if relative_y < adjusted_len as u16 {
|
||||||
|
self.selection.select(Some(relative_y as usize));
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if mouse_in_tab_list {
|
} else if mouse_in_tab_list {
|
||||||
self.focus = Focus::TabList
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
|
self.focus = Focus::TabList;
|
||||||
|
if let Some(areas) = &self.areas {
|
||||||
|
let relative_y = position.y.saturating_sub(areas.tab_list.y + 1);
|
||||||
|
if relative_y < self.tabs.len() as u16 {
|
||||||
|
self.current_tab.select(Some(relative_y as usize));
|
||||||
|
self.refresh_tab();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MouseEventKind::ScrollDown => {
|
MouseEventKind::Down(button) => match button {
|
||||||
|
MouseButton::Left => {
|
||||||
|
if mouse_in_search {
|
||||||
|
self.enter_search();
|
||||||
|
} else if mouse_in_list {
|
||||||
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
|
self.handle_enter();
|
||||||
|
} else if mouse_in_tab_list {
|
||||||
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
|
self.focus = Focus::TabList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MouseButton::Right if mouse_in_list => {
|
||||||
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
|
self.enable_preview();
|
||||||
|
}
|
||||||
|
MouseButton::Middle if mouse_in_list => {
|
||||||
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
|
self.enable_description();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
MouseEventKind::ScrollDown | MouseEventKind::ScrollUp => {
|
||||||
|
if matches!(self.focus, Focus::Search) {
|
||||||
|
self.exit_search();
|
||||||
|
}
|
||||||
if mouse_in_tab_list {
|
if mouse_in_tab_list {
|
||||||
if self.current_tab.selected().unwrap() != self.tabs.len() - 1 {
|
if self.current_tab.selected().unwrap() != self.tabs.len() - 1 {
|
||||||
self.current_tab.select_next();
|
self.current_tab.select_next();
|
||||||
}
|
}
|
||||||
self.refresh_tab();
|
self.refresh_tab();
|
||||||
} else if mouse_in_list {
|
} else if mouse_in_list {
|
||||||
self.selection.select_next()
|
if event.kind == MouseEventKind::ScrollDown {
|
||||||
}
|
self.scroll_down();
|
||||||
}
|
} else {
|
||||||
MouseEventKind::ScrollUp => {
|
self.scroll_up();
|
||||||
if mouse_in_tab_list {
|
|
||||||
if self.current_tab.selected().unwrap() != 0 {
|
|
||||||
self.current_tab.select_previous();
|
|
||||||
}
|
}
|
||||||
self.refresh_tab();
|
|
||||||
} else if mouse_in_list {
|
|
||||||
self.selection.select_previous()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match &mut self.focus {
|
|
||||||
Focus::FloatingWindow(float) => {
|
|
||||||
float.content.handle_mouse_event(event);
|
|
||||||
}
|
|
||||||
Focus::ConfirmationPrompt(confirm) => {
|
|
||||||
confirm.content.handle_mouse_event(event);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user