Compare commits

...

10 Commits

Author SHA1 Message Date
JEEVITHA KANNAN K S
c4a661ab4e
Merge fa8bb74527 into e3688e9b3d 2024-10-25 16:01:23 +02:00
Adam Perkowski
e3688e9b3d
fix+refact(system-cleanup) (#856)
* fix(system-cleanup): some issues

* new packager quotes
2024-10-24 14:59:23 -05:00
Adam Perkowski
51631a16cb
feat: desktop entry & manpage installation through linutil-installer.sh (#802) 2024-10-24 14:55:56 -05:00
Adam Perkowski
d39ffad527
📖 fix(docs): newlines (#796) 2024-10-24 14:50:27 -05:00
Adam Perkowski
c0982a787f
📖 add auto docs generation instructions to the Contributing Guidelines (#788)
* 📖 add auto docs generation instructions to the Contributing Guidelines

* Commit Contributing Guidelines

---------

Co-authored-by: adamperkowski <adamperkowski@users.noreply.github.com>
2024-10-24 14:45:37 -05:00
Adam Perkowski
4f7de594a6
🔍️ exiting search with Ctrl-C + better shortcut tips (#768) 2024-10-24 14:43:16 -05:00
Adam Perkowski
fa2f838b63
📃 fix(monitor setup): a bug with utility-functions; newlines & colors in the scripts (#713)
* fixed newlines & changed colors to keep synergy

* fixed a bug
2024-10-24 14:39:04 -05:00
JEEVITHA KANNAN K S
fa8bb74527
Merge remote-tracking branch 'upstream/main' into multi-select-refact 2024-10-04 10:37:42 +05:30
JEEVITHA KANNAN K S
3796c7abdb
Add colors for nm cmds 2024-10-01 21:59:22 +05:30
JEEVITHA KANNAN K S
8edd12f0b4
Add per cmd multi-selection 2024-10-01 20:49:57 +05:30
18 changed files with 135 additions and 86 deletions

View File

@ -16,6 +16,7 @@ cd linutil
```
## 3. Make your changes
- **Edit the files you want to change**: Make your changes to the relevant files.
- **Test your changes**: Run `cargo run` to test your modifications in a local environment and ensure everything works as expected.
@ -60,6 +61,7 @@ cd linutil
## 11. Documentation
- **Update the documentation**: If your change affects the functionality, please update the relevant documentation files to reflect this.
- **Automatic generation**: If you decide to add functionality through a new shell script, make sure to fill out all fields in `tab_data.toml` and run `cargo xtask docgen`.
## 12. License

View File

@ -22,7 +22,7 @@ jobs:
- name: Copy Contributing Guidelines
run: |
echo "<!-- THIS FILE IS GENERATED AUTOMATICALLY. EDIT .github/CONTRIBUTING.md -->\n\n$(cat .github/CONTRIBUTING.md)" > 'docs/contributing.md'
echo -e "<!-- THIS FILE IS GENERATED AUTOMATICALLY. EDIT .github/CONTRIBUTING.md -->\n\n$(cat .github/CONTRIBUTING.md)" > 'docs/contributing.md'
- uses: stefanzweifel/git-auto-commit-action@v5
with:

View File

@ -33,30 +33,18 @@ pub fn get_tabs(validate: bool) -> (TempDir, Vec<Tab>) {
let tabs: Vec<Tab> = tabs
.into_iter()
.map(
|(
TabEntry {
name,
data,
multi_selectable,
},
directory,
)| {
let mut tree = Tree::new(Rc::new(ListNode {
name: "root".to_string(),
description: String::new(),
command: Command::None,
task_list: String::new(),
}));
let mut root = tree.root_mut();
create_directory(data, &mut root, &directory, validate);
Tab {
name,
tree,
multi_selectable,
}
},
)
.map(|(TabEntry { name, data }, directory)| {
let mut tree = Tree::new(Rc::new(ListNode {
name: "root".to_string(),
description: String::new(),
command: Command::None,
task_list: String::new(),
multi_select: false,
}));
let mut root = tree.root_mut();
create_directory(data, &mut root, &directory, validate, true);
Tab { name, tree }
})
.collect();
if tabs.is_empty() {
@ -74,12 +62,6 @@ struct TabList {
struct TabEntry {
name: String,
data: Vec<Entry>,
#[serde(default = "default_multi_selectable")]
multi_selectable: bool,
}
fn default_multi_selectable() -> bool {
true
}
#[derive(Deserialize)]
@ -94,6 +76,12 @@ struct Entry {
entry_type: EntryType,
#[serde(default)]
task_list: String,
#[serde(default = "default_true")]
multi_select: bool,
}
fn default_true() -> bool {
true
}
#[derive(Deserialize)]
@ -174,8 +162,11 @@ fn create_directory(
node: &mut NodeMut<Rc<ListNode>>,
command_dir: &Path,
validate: bool,
parent_multi_select: bool,
) {
for entry in data {
let multi_select = parent_multi_select && entry.multi_select;
match entry.entry_type {
EntryType::Entries(entries) => {
let mut node = node.append(Rc::new(ListNode {
@ -183,8 +174,9 @@ fn create_directory(
description: entry.description,
command: Command::None,
task_list: String::new(),
multi_select,
}));
create_directory(entries, &mut node, command_dir, validate);
create_directory(entries, &mut node, command_dir, validate, multi_select);
}
EntryType::Command(command) => {
node.append(Rc::new(ListNode {
@ -192,6 +184,7 @@ fn create_directory(
description: entry.description,
command: Command::Raw(command),
task_list: String::new(),
multi_select,
}));
}
EntryType::Script(script) => {
@ -210,6 +203,7 @@ fn create_directory(
file: script,
},
task_list: entry.task_list,
multi_select,
}));
}
}

View File

@ -23,7 +23,6 @@ pub enum Command {
pub struct Tab {
pub name: String,
pub tree: Tree<Rc<ListNode>>,
pub multi_selectable: bool,
}
#[derive(Clone, Hash, Eq, PartialEq)]
@ -32,4 +31,5 @@ pub struct ListNode {
pub description: String,
pub command: Command,
pub task_list: String,
pub multi_select: bool,
}

View File

@ -35,10 +35,10 @@ installLinutil() {
printf "%b\n" "${YELLOW}Installing rustup...${RC}"
case "$PACKAGER" in
pacman)
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm rustup
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm curl rustup man-db
;;
dnf)
"$ESCALATION_TOOL" "$PACKAGER" install -y rustup
"$ESCALATION_TOOL" "$PACKAGER" install -y curl rustup man-pages man-db man
;;
zypper)
"$ESCALATION_TOOL" "$PACKAGER" install -n curl gcc make
@ -54,12 +54,23 @@ installLinutil() {
rustup default stable
cargo install --force linutil_tui
printf "%b\n" "${GREEN}Installed successfully.${RC}"
installExtra
;;
*) printf "%b\n" "${RED}Linutil not installed.${RC}" ;;
esac
esac
}
installExtra() {
printf "%b\n" "${YELLOW}Installing the manpage...${RC}"
"$ESCALATION_TOOL" mkdir -p /usr/share/man/man1
curl 'https://raw.githubusercontent.com/ChrisTitusTech/linutil/refs/heads/main/man/linutil.1' | "$ESCALATION_TOOL" tee '/usr/share/man/man1/linutil.1' > /dev/null
printf "%b\n" "${YELLOW}Creating a Desktop Entry...${RC}"
"$ESCALATION_TOOL" mkdir -p /usr/share/applications
curl 'https://raw.githubusercontent.com/ChrisTitusTech/linutil/refs/heads/main/linutil.desktop' | "$ESCALATION_TOOL" tee /usr/share/applications/linutil.desktop > /dev/null
printf "%b\n" "${GREEN}Done.${RC}"
}
checkEnv
checkEscalationTool
checkAURHelper

23
core/tabs/system-setup/system-cleanup.sh Normal file → Executable file
View File

@ -26,16 +26,21 @@ cleanup_system() {
"$ESCALATION_TOOL" "$PACKAGER" -Rns $(pacman -Qtdq) --noconfirm > /dev/null 2>&1
;;
*)
printf "%b\n" "${RED}Unsupported package manager: ""$PACKAGER""${RC}"
return 1
printf "%b\n" "${RED}Unsupported package manager: ${PACKAGER}. Skipping.${RC}"
;;
esac
}
common_cleanup() {
"$ESCALATION_TOOL" find /var/tmp -type f -atime +5 -delete
"$ESCALATION_TOOL" find /tmp -type f -atime +5 -delete
"$ESCALATION_TOOL" find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
if [ -d /var/tmp ]; then
"$ESCALATION_TOOL" find /var/tmp -type f -atime +5 -delete
fi
if [ -d /tmp ]; then
"$ESCALATION_TOOL" find /tmp -type f -atime +5 -delete
fi
if [ -d /var/log ]; then
"$ESCALATION_TOOL" find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
fi
"$ESCALATION_TOOL" journalctl --vacuum-time=3d
}
@ -45,8 +50,12 @@ clean_data() {
case $clean_response in
y|Y)
printf "%b\n" "${YELLOW}Cleaning up old cache files and emptying trash...${RC}"
find "$HOME/.cache/" -type f -atime +5 -delete
find "$HOME/.local/share/Trash" -mindepth 1 -delete
if [ -d "$HOME/.cache" ]; then
find "$HOME/.cache/" -type f -atime +5 -delete
fi
if [ -d "$HOME/.local/share/Trash" ]; then
find "$HOME/.local/share/Trash" -mindepth 1 -delete
fi
printf "%b\n" "${GREEN}Cache and trash cleanup completed.${RC}"
;;
*)

View File

@ -1,5 +1,4 @@
name = "System Setup"
multi_selectable = false
[[data]]
name = "Arch Linux"
@ -14,6 +13,7 @@ name = "Arch Server Setup"
description = "This command installs a minimal arch server setup under 5 minutes."
script = "arch/server-setup.sh"
task_list = "SI D"
multi_select = false
[[data.entries]]
name = "Paru AUR Helper"
@ -76,12 +76,14 @@ name = "Full System Cleanup"
description = "This script is designed to remove unnecessary packages, clean old cache files, remove temporary files, and to empty the trash."
script = "system-cleanup.sh"
task_list = "RP PFM"
multi_select = false
[[data]]
name = "Full System Update"
description = "This command updates your system to the latest packages available for your distro"
script = "system-update.sh"
task_list = "PFM"
multi_select = false
[[data]]
name = "Gaming Dependencies"

View File

@ -13,7 +13,7 @@ change_orientation() {
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b\n" "${YELLOW} Change Monitor Orientation${RC}"
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b" "${YELLOW}Choose a monitor to configure: ${RC}"
printf "%b\n" "${YELLOW}Choose a monitor to configure: ${RC}"
i=1
for monitor in $monitor_array; do
printf "%b\n" "$i. ${GREEN}$monitor${RC}"

View File

@ -13,7 +13,7 @@ disable_monitor() {
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b\n" "${YELLOW} Disable Monitor${RC}"
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b" "Choose a monitor to disable: "
printf "%b\n" "Choose a monitor to disable: "
i=1
for monitor in $monitor_array; do
printf "%b\n" "$i. ${GREEN}$monitor${RC}"

View File

@ -13,7 +13,7 @@ enable_monitor() {
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b\n" "${YELLOW} Enable Monitor${RC}"
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b" "${YELLOW}Choose a monitor to enable: ${RC}"
printf "%b\n" "${YELLOW}Choose a monitor to enable: ${RC}"
i=1
for monitor in $monitor_array; do

View File

@ -1,6 +1,6 @@
#!/bin/sh -e
. ./utility_functions.sh
. ../utility_functions.sh
. ../../common-script.sh

View File

@ -13,10 +13,10 @@ manage_arrangement() {
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b\n" "${YELLOW} Manage Monitor Arrangement${RC}"
printf "%b\n" "${YELLOW}=========================================${RC}"
printf "%b" "${YELLOW}Choose the monitor to arrange: ${RC}"
printf "%b\n" "${YELLOW}Choose the monitor to arrange: ${RC}"
i=1
for monitor in $monitor_array; do
printf "%b\n" "$i. ${YELLOW}$monitor${RC}"
printf "%b\n" "$i. ${GREEN}$monitor${RC}"
i=$((i + 1))
done

View File

@ -16,7 +16,7 @@ set_primary_monitor() {
printf "%b\n" "${YELLOW}Choose a monitor to set as primary:${RC}"
i=1
for monitor in $monitor_array; do
printf "%b\n" "$i. ${YELLOW}$monitor${RC}"
printf "%b\n" "$i. ${GREEN}$monitor${RC}"
i=$((i + 1))
done

View File

@ -1,8 +1,8 @@
name = "Utilities"
multi_selectable = false
[[data]]
name = "Monitor Control"
multi_select = false
[[data.preconditions]]
matches = true
@ -78,6 +78,7 @@ script = "monitor-control/set_resolutions.sh"
[[data]]
name = "User Account Manager"
multi_select = false
[[data.entries]]
name = "Add User"
@ -104,6 +105,7 @@ name = "Auto Mount Drive"
description = "This utility is designed to help with automating the process of mounting a drive on to your system."
script = "auto-mount.sh"
task_list = "PFM"
multi_select = false
[[data]]
name = "Auto Login"
@ -120,6 +122,7 @@ name = "Bluetooth Manager"
description = "This utility is designed to manage bluetooth in your system"
script = "bluetooth-control.sh"
task_list = "I SS"
multi_select = false
[[data]]
name = "Bootable USB Creator"

View File

@ -1,4 +1,6 @@
<!-- THIS FILE IS GENERATED AUTOMATICALLY. EDIT .github/CONTRIBUTING.md -->\n\n# Contributing Guidelines for Linutil
<!-- THIS FILE IS GENERATED AUTOMATICALLY. EDIT .github/CONTRIBUTING.md -->
# Contributing Guidelines for Linutil
Thank you for considering contributing to Linutil! We appreciate your effort in helping improve this project. To ensure that your contributions align with the goals and quality standards of Linutil, please follow these guidelines:
@ -16,6 +18,7 @@ cd linutil
```
## 3. Make your changes
- **Edit the files you want to change**: Make your changes to the relevant files.
- **Test your changes**: Run `cargo run` to test your modifications in a local environment and ensure everything works as expected.
@ -60,6 +63,7 @@ cd linutil
## 11. Documentation
- **Update the documentation**: If your change affects the functionality, please update the relevant documentation files to reflect this.
- **Automatic generation**: If you decide to add functionality through a new shell script, make sure to fill out all fields in `tab_data.toml` and run `cargo xtask docgen`.
## 12. License

View File

@ -1,5 +1,5 @@
use crate::{state::ListEntry, theme::Theme};
use crossterm::event::{KeyCode, KeyEvent};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use ego_tree::NodeId;
use linutil_core::Tab;
use ratatui::{
@ -116,21 +116,27 @@ impl Filter {
pub fn handle_key(&mut self, event: &KeyEvent) -> SearchAction {
//Insert user input into the search bar
match event.code {
KeyCode::Char('c') if event.modifiers.contains(KeyModifiers::CONTROL) => {
return self.exit_search()
}
KeyCode::Char(c) => self.insert_char(c),
KeyCode::Backspace => self.remove_previous(),
KeyCode::Delete => self.remove_next(),
KeyCode::Left => return self.cursor_left(),
KeyCode::Right => return self.cursor_right(),
KeyCode::Esc => {
self.input_position = 0;
self.search_input.clear();
return SearchAction::Exit;
}
KeyCode::Enter => return SearchAction::Exit,
KeyCode::Esc => return self.exit_search(),
_ => return SearchAction::None,
};
SearchAction::Update
}
fn exit_search(&mut self) -> SearchAction {
self.input_position = 0;
self.search_input.clear();
SearchAction::Exit
}
fn cursor_left(&mut self) -> SearchAction {
self.input_position = self.input_position.saturating_sub(1);
SearchAction::None

View File

@ -119,7 +119,10 @@ impl AppState {
match self.focus {
Focus::Search => (
"Search bar",
Box::new([Shortcut::new("Finish search", ["Enter"])]),
Box::new([
Shortcut::new("Abort search", ["Esc", "CTRL-c"]),
Shortcut::new("Search", ["Enter"]),
]),
),
Focus::List => {
@ -143,12 +146,10 @@ impl AppState {
hints.push(Shortcut::new("Select item below", ["j", "Down"]));
hints.push(Shortcut::new("Next theme", ["t"]));
hints.push(Shortcut::new("Previous theme", ["T"]));
if self.is_current_tab_multi_selectable() {
hints.push(Shortcut::new("Toggle multi-selection mode", ["v"]));
hints.push(Shortcut::new("Multi-selection mode", ["v"]));
if self.multi_select {
hints.push(Shortcut::new("Select multiple commands", ["Space"]));
}
hints.push(Shortcut::new("Next tab", ["Tab"]));
hints.push(Shortcut::new("Previous tab", ["Shift-Tab"]));
hints.push(Shortcut::new("Important actions guide", ["g"]));
@ -320,7 +321,12 @@ impl AppState {
let (indicator, style) = if is_selected {
(self.theme.multi_select_icon(), Style::default().bold())
} else {
("", Style::new())
let ms_style = if self.multi_select && !node.multi_select {
Style::default().fg(self.theme.multi_select_disabled_color())
} else {
Style::new()
};
("", ms_style)
};
if *has_children {
Line::from(format!(
@ -330,6 +336,7 @@ impl AppState {
indicator
))
.style(self.theme.dir_color())
.patch_style(style)
} else {
Line::from(format!(
"{} {} {}",
@ -347,13 +354,21 @@ impl AppState {
|ListEntry {
node, has_children, ..
}| {
let ms_style = if self.multi_select && !node.multi_select {
Style::default().fg(self.theme.multi_select_disabled_color())
} else {
Style::new()
};
if *has_children {
Line::from(" ").style(self.theme.dir_color())
Line::from(" ")
.style(self.theme.dir_color())
.patch_style(ms_style)
} else {
Line::from(format!("{} ", node.task_list))
.alignment(Alignment::Right)
.style(self.theme.cmd_color())
.bold()
.patch_style(ms_style)
}
},
));
@ -465,6 +480,13 @@ impl AppState {
// enabled, need to clear it to prevent state corruption
if !self.multi_select {
self.selected_commands.clear()
} else {
// Prevents non multi_selectable cmd from being pushed into the selected list
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(),
@ -522,41 +544,30 @@ impl AppState {
}
fn toggle_multi_select(&mut self) {
if self.is_current_tab_multi_selectable() {
self.multi_select = !self.multi_select;
if !self.multi_select {
self.selected_commands.clear();
}
self.multi_select = !self.multi_select;
if !self.multi_select {
self.selected_commands.clear();
}
}
fn toggle_selection(&mut self) {
if let Some(command) = self.get_selected_node() {
if self.selected_commands.contains(&command) {
self.selected_commands.retain(|c| c != &command);
} else {
self.selected_commands.push(command);
if let Some(node) = self.get_selected_node() {
if node.multi_select {
if self.selected_commands.contains(&node) {
self.selected_commands.retain(|c| c != &node);
} else {
self.selected_commands.push(node);
}
}
}
}
pub fn is_current_tab_multi_selectable(&self) -> bool {
let index = self.current_tab.selected().unwrap_or(0);
self.tabs
.get(index)
.map_or(false, |tab| tab.multi_selectable)
}
fn update_items(&mut self) {
self.filter.update_items(
&self.tabs,
self.current_tab.selected().unwrap(),
*self.visit_stack.last().unwrap(),
);
if !self.is_current_tab_multi_selectable() {
self.multi_select = false;
self.selected_commands.clear();
}
}
/// Checks either the current tree node is the root node (can we go up the tree or no)

View File

@ -28,6 +28,13 @@ impl Theme {
}
}
pub fn multi_select_disabled_color(&self) -> Color {
match self {
Theme::Default => Color::DarkGray,
Theme::Compatible => Color::DarkGray,
}
}
pub fn tab_color(&self) -> Color {
match self {
Theme::Default => Color::Rgb(255, 255, 85),