mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2024-11-22 05:12:27 +00:00
Merge remote-tracking branch 'upstream/main' into flatpak
This commit is contained in:
commit
6e7fe51f91
34
Cargo.lock
generated
34
Cargo.lock
generated
|
@ -194,9 +194,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.17"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
|
||||
checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -204,9 +204,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.17"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
|
||||
checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -216,9 +216,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.13"
|
||||
version = "4.5.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
|
@ -491,7 +491,7 @@ checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
|||
|
||||
[[package]]
|
||||
name = "linutil_core"
|
||||
version = "24.9.23"
|
||||
version = "24.9.28"
|
||||
dependencies = [
|
||||
"ego-tree",
|
||||
"include_dir",
|
||||
|
@ -503,7 +503,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "linutil_tui"
|
||||
version = "24.9.23"
|
||||
version = "24.9.28"
|
||||
dependencies = [
|
||||
"ansi-to-tui",
|
||||
"anstyle",
|
||||
|
@ -519,7 +519,7 @@ dependencies = [
|
|||
"tree-sitter-bash",
|
||||
"tree-sitter-highlight",
|
||||
"tui-term",
|
||||
"unicode-width",
|
||||
"unicode-width 0.2.0",
|
||||
"zips",
|
||||
]
|
||||
|
||||
|
@ -792,7 +792,7 @@ dependencies = [
|
|||
"strum_macros",
|
||||
"unicode-segmentation",
|
||||
"unicode-truncate",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1205,14 +1205,20 @@ checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf"
|
|||
dependencies = [
|
||||
"itertools",
|
||||
"unicode-segmentation",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.13"
|
||||
version = "0.1.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
|
||||
checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
|
@ -1234,7 +1240,7 @@ checksum = "84cd863bf0db7e392ba3bd04994be3473491b31e66340672af5d11943c6274de"
|
|||
dependencies = [
|
||||
"itoa",
|
||||
"log",
|
||||
"unicode-width",
|
||||
"unicode-width 0.1.14",
|
||||
"vte",
|
||||
]
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[workspace.package]
|
||||
license = "MIT"
|
||||
version = "24.9.23"
|
||||
version = "24.9.28"
|
||||
|
||||
[workspace.dependencies]
|
||||
ego-tree = "0.6.2"
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
use crate::{Command, ListNode, Tab};
|
||||
use ego_tree::{NodeMut, Tree};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufRead, BufReader, Read},
|
||||
os::unix::fs::PermissionsExt,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use crate::{Command, ListNode, Tab};
|
||||
use ego_tree::{NodeMut, Tree};
|
||||
use include_dir::{include_dir, Dir};
|
||||
use serde::Deserialize;
|
||||
use tempdir::TempDir;
|
||||
|
||||
const TAB_DATA: Dir = include_dir!("$CARGO_MANIFEST_DIR/tabs");
|
||||
|
@ -35,12 +37,12 @@ pub fn get_tabs(validate: bool) -> Vec<Tab> {
|
|||
},
|
||||
directory,
|
||||
)| {
|
||||
let mut tree = Tree::new(ListNode {
|
||||
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 {
|
||||
|
@ -164,28 +166,28 @@ fn filter_entries(entries: &mut Vec<Entry>) {
|
|||
|
||||
fn create_directory(
|
||||
data: Vec<Entry>,
|
||||
node: &mut NodeMut<ListNode>,
|
||||
node: &mut NodeMut<Rc<ListNode>>,
|
||||
command_dir: &Path,
|
||||
validate: bool,
|
||||
) {
|
||||
for entry in data {
|
||||
match entry.entry_type {
|
||||
EntryType::Entries(entries) => {
|
||||
let mut node = node.append(ListNode {
|
||||
let mut node = node.append(Rc::new(ListNode {
|
||||
name: entry.name,
|
||||
description: entry.description,
|
||||
command: Command::None,
|
||||
task_list: String::new(),
|
||||
});
|
||||
}));
|
||||
create_directory(entries, &mut node, command_dir, validate);
|
||||
}
|
||||
EntryType::Command(command) => {
|
||||
node.append(ListNode {
|
||||
node.append(Rc::new(ListNode {
|
||||
name: entry.name,
|
||||
description: entry.description,
|
||||
command: Command::Raw(command),
|
||||
task_list: String::new(),
|
||||
});
|
||||
}));
|
||||
}
|
||||
EntryType::Script(script) => {
|
||||
let script = command_dir.join(script);
|
||||
|
@ -194,7 +196,7 @@ fn create_directory(
|
|||
}
|
||||
|
||||
if let Some((executable, args)) = get_shebang(&script, validate) {
|
||||
node.append(ListNode {
|
||||
node.append(Rc::new(ListNode {
|
||||
name: entry.name,
|
||||
description: entry.description,
|
||||
command: Command::LocalFile {
|
||||
|
@ -203,7 +205,7 @@ fn create_directory(
|
|||
file: script,
|
||||
},
|
||||
task_list: entry.task_list,
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
mod inner;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use ego_tree::Tree;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
@ -20,7 +22,7 @@ pub enum Command {
|
|||
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||
pub struct Tab {
|
||||
pub name: String,
|
||||
pub tree: Tree<ListNode>,
|
||||
pub tree: Tree<Rc<ListNode>>,
|
||||
pub multi_selectable: bool,
|
||||
}
|
||||
|
||||
|
|
|
@ -3,10 +3,25 @@
|
|||
. ../../common-script.sh
|
||||
|
||||
installMeld() {
|
||||
cd "$HOME" && git clone https://gitlab.gnome.org/GNOME/meld.git
|
||||
echo "PATH=\$PATH:$HOME/meld/bin" | "$ESCALATION_TOOL" tee -a /etc/environment
|
||||
if ! command_exists meld; then
|
||||
printf "%b\n" "${YELLOW}Installing Meld...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm meld
|
||||
;;
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -y install meld
|
||||
;;
|
||||
*)
|
||||
. ../setup-flatpak.sh
|
||||
flatpak install -y flathub org.gnome.meld
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Meld is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installMeld
|
||||
installMeld
|
|
@ -4,15 +4,6 @@
|
|||
|
||||
gitpath="$HOME/.local/share/neovim"
|
||||
|
||||
checkNeovimVer() {
|
||||
# lazy.nvim requires nvim >= 0.8.0
|
||||
nvim_version=$(nvim --version | head -n 1 | awk '{print $2}')
|
||||
if [ "$(printf "%s\n" "$nvim_version" "0.8.0" | sort -V | head -n 1)" != "0.8.0" ]; then
|
||||
printf "%b\n" "${RED}Neovim version $nvim_version not supported.${RC}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cloneNeovim() {
|
||||
# Check if the dir exists before attempting to clone into it.
|
||||
if [ -d "$gitpath" ]; then
|
||||
|
@ -30,7 +21,10 @@ installNeovim() {
|
|||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm neovim ripgrep fzf python-virtualenv luarocks go shellcheck git
|
||||
;;
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y neovim ripgrep fd-find python3-venv luarocks golang-go shellcheck git
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y ripgrep fd-find python3-venv luarocks golang-go shellcheck git
|
||||
curl -sSLo /tmp/nvim.appimage https://github.com/neovim/neovim/releases/latest/download/nvim.appimage
|
||||
chmod u+x /tmp/nvim.appimage
|
||||
"$ESCALATION_TOOL" mv /tmp/nvim.appimage /usr/local/bin/nvim
|
||||
;;
|
||||
dnf|zypper)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y neovim ripgrep fzf python3-virtualenv luarocks golang ShellCheck git
|
||||
|
@ -60,7 +54,6 @@ linkNeovimConfig() {
|
|||
checkEnv
|
||||
checkEscalationTool
|
||||
installNeovim
|
||||
checkNeovimVer
|
||||
cloneNeovim
|
||||
backupNeovimConfig
|
||||
linkNeovimConfig
|
||||
|
|
|
@ -17,7 +17,6 @@ installVsCodium() {
|
|||
printf "%b\n" "[gitlab.com_paulcarroty_vscodium_repo]\nname=gitlab.com_paulcarroty_vscodium_repo\nbaseurl=https://download.vscodium.com/rpms/\nenabled=1\ngpgcheck=1\nrepo_gpgcheck=1\ngpgkey=https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/-/raw/master/pub.gpg\nmetadata_expire=1h" | "$ESCALATION_TOOL" tee -a /etc/zypp/repos.d/vscodium.repo
|
||||
"$ESCALATION_TOOL" "$PACKAGER" refresh
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --non-interactive install codium
|
||||
|
||||
;;
|
||||
pacman)
|
||||
"$AUR_HELPER" -S --noconfirm vscodium-bin
|
||||
|
|
|
@ -15,9 +15,9 @@ installLinutil() {
|
|||
printf "%b" "Enter your choice: "
|
||||
read -r choice
|
||||
case $choice in
|
||||
1) "$AUR_HELPER" -S --noconfirm linutil ;;
|
||||
2) "$AUR_HELPER" -S --noconfirm linutil-bin ;;
|
||||
3) "$AUR_HELPER" -S --noconfirm linutil-git ;;
|
||||
1) "$AUR_HELPER" -S --needed --noconfirm linutil ;;
|
||||
2) "$AUR_HELPER" -S --needed --noconfirm linutil-bin ;;
|
||||
3) "$AUR_HELPER" -S --needed --noconfirm linutil-git ;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Invalid choice:${RC} $choice"
|
||||
exit 1
|
||||
|
|
38
core/tabs/applications-setup/office-suites/freeoffice.sh
Normal file
38
core/tabs/applications-setup/office-suites/freeoffice.sh
Normal file
|
@ -0,0 +1,38 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installFreeOffice() {
|
||||
if ! command_exists softmaker-freeoffice-2024 freeoffice softmaker; then
|
||||
printf "%b\n" "${YELLOW}Installing Free Office...${RC}"
|
||||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
curl -O https://www.softmaker.net/down/softmaker-freeoffice-2024_1218-01_amd64.deb
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y ./softmaker-freeoffice-2024_1218-01_amd64.deb
|
||||
;;
|
||||
zypper)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" addrepo -f https://shop.softmaker.com/repo/rpm SoftMaker
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --gpg-auto-import-keys refresh
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --non-interactive install softmaker-freeoffice-2024
|
||||
;;
|
||||
pacman)
|
||||
"$AUR_HELPER" -S --needed --noconfirm freeoffice
|
||||
;;
|
||||
dnf)
|
||||
"$ESCALATION_TOOL" curl -O -qO /etc/yum.repos.d/softmaker.repo https://shop.softmaker.com/repo/softmaker.repo
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y softmaker-freeoffice-2024
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: ""$PACKAGER""${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Free Office is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
checkAurHelper
|
||||
installFreeOffice
|
31
core/tabs/applications-setup/office-suites/libreoffice.sh
Normal file
31
core/tabs/applications-setup/office-suites/libreoffice.sh
Normal file
|
@ -0,0 +1,31 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installLibreOffice() {
|
||||
if ! command_exists libreoffice; then
|
||||
printf "%b\n" "${YELLOW}Installing Libre Office...${RC}"
|
||||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y libreoffice-core
|
||||
;;
|
||||
zypper|dnf)
|
||||
. ./setup-flatpak.sh
|
||||
flatpak install -y flathub org.libreoffice.LibreOffice
|
||||
;;
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm libreoffice-fresh
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: ""$PACKAGER""${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Libre Office is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installLibreOffice
|
33
core/tabs/applications-setup/office-suites/onlyoffice.sh
Normal file
33
core/tabs/applications-setup/office-suites/onlyoffice.sh
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installOnlyOffice() {
|
||||
if ! command_exists onlyoffice-desktopeditors; then
|
||||
printf "%b\n" "${YELLOW}Installing Only Office..${RC}."
|
||||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
curl -O https://download.onlyoffice.com/install/desktop/editors/linux/onlyoffice-desktopeditors_amd64.deb
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y ./onlyoffice-desktopeditors_amd64.deb
|
||||
;;
|
||||
zypper|dnf)
|
||||
. ./setup-flatpak.sh
|
||||
flatpak install -y flathub org.onlyoffice.desktopeditors
|
||||
;;
|
||||
pacman)
|
||||
"$AUR_HELPER" -S --needed --noconfirm onlyoffice
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: ""$PACKAGER""${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Only Office is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
checkAurHelper
|
||||
installOnlyOffice
|
25
core/tabs/applications-setup/office-suites/wpsoffice.sh
Normal file
25
core/tabs/applications-setup/office-suites/wpsoffice.sh
Normal file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installWpsOffice() {
|
||||
if ! command_exists com.wps.Office; then
|
||||
printf "%b\n" "${YELLOW}Installing WPS Office...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
"$AUR_HELPER" -S --needed --noconfirm wps-office
|
||||
;;
|
||||
*)
|
||||
. ./setup-flatpak.sh
|
||||
flatpak install flathub com.wps.Office
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}WPS Office is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
checkAurHelper
|
||||
installWpsOffice
|
23
core/tabs/applications-setup/pdf-suites/evince.sh
Normal file
23
core/tabs/applications-setup/pdf-suites/evince.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installEvince() {
|
||||
if ! command_exists evince; then
|
||||
printf "%b\n" "${YELLOW}Installing Evince...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm evince
|
||||
;;
|
||||
*)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y evince
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Evince is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installEvince
|
23
core/tabs/applications-setup/pdf-suites/okular.sh
Normal file
23
core/tabs/applications-setup/pdf-suites/okular.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installOkular() {
|
||||
if ! command_exists okular; then
|
||||
printf "%b\n" "${YELLOW}Installing Okular...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm okular
|
||||
;;
|
||||
*)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y okular
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Okular is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installOkular
|
23
core/tabs/applications-setup/pdf-suites/pdfstudio.sh
Normal file
23
core/tabs/applications-setup/pdf-suites/pdfstudio.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installPdfstudio() {
|
||||
if ! command_exists pdfstudio2024; then
|
||||
printf "%b\n" "${YELLOW}Installing PDF Studio...${RC}"
|
||||
curl -O https://download.qoppa.com/pdfstudio/PDFStudio_linux64.sh
|
||||
"$ESCALATION_TOOL" chmod +x PDFStudio_linux64.sh
|
||||
if sh PDFStudio_linux64.sh; then
|
||||
printf "%b\n" "${GREEN}PDF Studio installed successfully!${RC}"
|
||||
else
|
||||
printf "%b\n" "${RED}PDF Studio installation failed!${RC}"
|
||||
fi
|
||||
rm PDFStudio_linux64.sh
|
||||
else
|
||||
printf "%b\n" "${GREEN}PDF Studio is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installPdfstudio
|
23
core/tabs/applications-setup/pdf-suites/pdfstudioviewer.sh
Normal file
23
core/tabs/applications-setup/pdf-suites/pdfstudioviewer.sh
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
|
||||
installPdfstudioviewer() {
|
||||
if ! command_exists pdfstudioviewer2024; then
|
||||
printf "%b\n" "${YELLOW}Installing PDF Studio Viewer...${RC}"
|
||||
curl -O https://download.qoppa.com/pdfstudioviewer/PDFStudioViewer_linux64.sh
|
||||
"$ESCALATION_TOOL" chmod +x PDFStudioViewer_linux64.sh
|
||||
if sh PDFStudioViewer_linux64.sh; then
|
||||
printf "%b\n" "${GREEN}PDF Studio Viewer installed successfully!${RC}"
|
||||
else
|
||||
printf "%b\n" "${RED}Installation failed!${RC}"
|
||||
fi
|
||||
rm PDFStudioViewer_linux64.sh
|
||||
else
|
||||
printf "%b\n" "${GREEN}PDF Studio Viewer is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
installPdfstudioviewer
|
|
@ -37,7 +37,7 @@ task_list = "I"
|
|||
name = "Meld"
|
||||
description = "Meld is a visual diff and merge tool that helps compare files, directories, and version-controlled projects."
|
||||
script = "Developer-tools/meld-setup.sh"
|
||||
task_list = "I"
|
||||
task_list = "I FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Ngrok"
|
||||
|
@ -90,6 +90,51 @@ description = "Thunderbird is a free, open-source email client that offers power
|
|||
script = "communication-apps/thunderbird-setup.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data]]
|
||||
name = "Office Suites"
|
||||
|
||||
[[data.entries]]
|
||||
name = "LibreOffice"
|
||||
script = "office-suites/libreoffice.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "OnlyOffice"
|
||||
script = "office-suites/onlyoffice.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "FreeOffice"
|
||||
script = "office-suites/freeoffice.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "WPS Office"
|
||||
script = "office-suites/wpsoffice.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data]]
|
||||
name = "PDF Suites"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Evince"
|
||||
script = "pdf-suites/evince.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Okular"
|
||||
script = "pdf-suites/okular.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "PDF Studio"
|
||||
script = "pdf-suites/pdfstudio.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "PDF Studio Viewer"
|
||||
script = "pdf-suites/pdfstudioviewer.sh"
|
||||
|
||||
[[data]]
|
||||
name = "Web Browsers"
|
||||
|
||||
|
@ -223,12 +268,6 @@ matches = true
|
|||
data = "command_exists"
|
||||
values = [ "linutil" ]
|
||||
|
||||
[[data]]
|
||||
name = "Office Suite"
|
||||
description = "An office suite installer is a software package that installs productivity tools such as word processing, spreadsheets, presentations, and pdf viewers for business and personal use."
|
||||
script = "office-suite-setup.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data]]
|
||||
name = "Rofi"
|
||||
description = "Rofi is a window switcher, run dialog, ssh-launcher and dmenu replacement that started as a clone of simpleswitcher, written by Sean Pringle and later expanded by Dave Davenport.\nThis command installs and configures rofi with configuration from CTT's DWM repo.\nhttps://github.com/ChrisTitusTech/dwm-titus"
|
||||
|
|
|
@ -59,7 +59,7 @@ updateSystem() {
|
|||
printf "%b\n" "${GREEN}Updating system${RC}"
|
||||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update -y
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update
|
||||
"$ESCALATION_TOOL" "$PACKAGER" upgrade -y
|
||||
;;
|
||||
dnf)
|
||||
|
|
|
@ -43,11 +43,13 @@ task_list = "PFM"
|
|||
|
||||
[[data.entries]]
|
||||
name = "Multimedia Codecs"
|
||||
description = "This script is designed to install multimedia codecs, and to ensure RPM Fusion repositories are installed."
|
||||
script = "fedora/multimedia-codecs.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Nvidia Proprietary Drivers"
|
||||
description = "This script is designed to download the proprietary NVIDIA drivers in Fedora."
|
||||
script = "fedora/nvidia-proprietary-driver-setup.sh"
|
||||
task_list = "I"
|
||||
|
||||
|
@ -71,6 +73,7 @@ task_list = "I"
|
|||
|
||||
[[data]]
|
||||
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"
|
||||
|
||||
|
@ -97,3 +100,9 @@ name = "Remove Snaps"
|
|||
description = "This script is designed to remove snap"
|
||||
script = "remove-snaps.sh"
|
||||
task_list = "RP"
|
||||
|
||||
[[data]]
|
||||
name = "TTY Fonts"
|
||||
description = "This Script will set the default TTY font to Terminus size 32 Bold"
|
||||
script = "terminus-tty.sh"
|
||||
task_list = "I PFM"
|
||||
|
|
66
core/tabs/system-setup/terminus-tty.sh
Executable file
66
core/tabs/system-setup/terminus-tty.sh
Executable file
|
@ -0,0 +1,66 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../common-script.sh
|
||||
InstallTermiusFonts() {
|
||||
if [ ! -f "/usr/share/kbd/consolefonts/ter-c18b.psf.gz" ] &&
|
||||
[ ! -f "/usr/share/consolefonts/Uni3-TerminusBold18x10.psf.gz" ] &&
|
||||
[ ! -f "/usr/lib/kbd/consolefonts/ter-p32n.psf.gz" ]; then
|
||||
printf "%b\n" "${YELLOW}Installing Terminus Fonts...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm terminus-font
|
||||
;;
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y fonts-terminus
|
||||
;;
|
||||
dnf)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y terminus-fonts-console
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: ""$PACKAGER""${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Terminus Fonts is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
SetTermiusFonts() {
|
||||
case "$DTYPE" in
|
||||
arch)
|
||||
printf "%b\n" "${YELLOW}Updating FONT= line in /etc/vconsole.conf...${RC}"
|
||||
"$ESCALATION_TOOL" sed -i 's/^FONT=.*/FONT=ter-v32b/' /etc/vconsole.conf
|
||||
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
|
||||
"$ESCALATION_TOOL" setfont -C /dev/tty1 ter-v32b
|
||||
fi
|
||||
printf "%b\n" "${GREEN}Terminus font set for TTY.${RC}"
|
||||
;;
|
||||
debian)
|
||||
|
||||
printf "%b\n" "${YELLOW}Updating console-setup configuration...${RC}"
|
||||
"$ESCALATION_TOOL" sed -i 's/^CODESET=.*/CODESET="guess"/' /etc/default/console-setup
|
||||
"$ESCALATION_TOOL" sed -i 's/^FONTFACE=.*/FONTFACE="TerminusBold"/' /etc/default/console-setup
|
||||
"$ESCALATION_TOOL" sed -i 's/^FONTSIZE=.*/FONTSIZE="16x32"/' /etc/default/console-setup
|
||||
printf "%b\n" "${GREEN}Console-setup configuration updated for Terminus font.${RC}"
|
||||
# Editing console-setup requires initramfs to be regenerated
|
||||
"$ESCALATION_TOOL" update-initramfs -u
|
||||
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
|
||||
"$ESCALATION_TOOL" setfont -C /dev/tty1 /usr/share/consolefonts/Uni3-TerminusBold32x16.psf.gz
|
||||
fi
|
||||
printf "%b\n" "${GREEN}Terminus font has been set for TTY.${RC}"
|
||||
;;
|
||||
fedora)
|
||||
printf "%b\n" "${YELLOW}Updating FONT= line in /etc/vconsole.conf...${RC}"
|
||||
"$ESCALATION_TOOL" sed -i 's/^FONT=.*/FONT=ter-v32b/' /etc/vconsole.conf
|
||||
if [ -z "$DISPLAY" ] && [ -z "$WAYLAND_DISPLAY" ]; then
|
||||
"$ESCALATION_TOOL" setfont -C /dev/tty1 ter-v32b
|
||||
fi
|
||||
printf "%b\n" "${GREEN}Terminus font has been set for TTY.${RC}"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
checkEnv
|
||||
InstallTermiusFonts
|
||||
SetTermiusFonts
|
|
@ -21,7 +21,7 @@ select_drive() {
|
|||
|
||||
# Function to get UUID and FSTYPE of the selected drive
|
||||
get_uuid_fstype() {
|
||||
UUID=$(blkid -s UUID -o value "${partition}")
|
||||
UUID=$("$ESCALATION_TOOL" blkid -s UUID -o value "${partition}")
|
||||
FSTYPE=$(lsblk -no FSTYPE "${partition}")
|
||||
NAME=$(lsblk -no NAME "${partition}")
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
- **Gaming Setup**: Configures Steam, Lutris, etc.
|
||||
- **Global Theming**: Sets up and manages global themes.
|
||||
- **Remove Snaps**: Removes snap packages.
|
||||
- **TTY Fonts**: This Script will set the default TTY font to Terminus size 32 Bold
|
||||
|
||||
### Arch Setup
|
||||
|
||||
|
|
|
@ -15,16 +15,16 @@ default = ["tips"]
|
|||
tips = ["rand"]
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.16", features = ["derive"] }
|
||||
clap = { version = "4.5.18", features = ["derive"] }
|
||||
crossterm = "0.28.1"
|
||||
ego-tree = { workspace = true }
|
||||
oneshot = "0.1.8"
|
||||
portable-pty = "0.8.1"
|
||||
ratatui = "0.28.1"
|
||||
tui-term = "0.1.12"
|
||||
unicode-width = "0.1.13"
|
||||
unicode-width = "0.2.0"
|
||||
rand = { version = "0.8.5", optional = true }
|
||||
linutil_core = { path = "../core", version = "24.9.23" }
|
||||
linutil_core = { path = "../core", version = "24.9.28" }
|
||||
tree-sitter-highlight = "0.23.0"
|
||||
tree-sitter-bash = "0.23.1"
|
||||
anstyle = "1.0.8"
|
||||
|
|
126
tui/src/confirmation.rs
Normal file
126
tui/src/confirmation.rs
Normal file
|
@ -0,0 +1,126 @@
|
|||
use std::borrow::Cow;
|
||||
|
||||
use crate::{float::FloatContent, hint::Shortcut};
|
||||
|
||||
use crossterm::event::{KeyCode, KeyEvent};
|
||||
use ratatui::{
|
||||
layout::Alignment,
|
||||
prelude::*,
|
||||
widgets::{Block, Borders, Clear, List},
|
||||
};
|
||||
|
||||
pub enum ConfirmStatus {
|
||||
Confirm,
|
||||
Abort,
|
||||
None,
|
||||
}
|
||||
|
||||
pub struct ConfirmPrompt {
|
||||
pub names: Box<[String]>,
|
||||
pub status: ConfirmStatus,
|
||||
scroll: usize,
|
||||
}
|
||||
|
||||
impl ConfirmPrompt {
|
||||
pub fn new(names: &[&str]) -> Self {
|
||||
let max_count_str = format!("{}", names.len());
|
||||
let names = names
|
||||
.iter()
|
||||
.zip(1..)
|
||||
.map(|(name, n)| {
|
||||
let count_str = format!("{n}");
|
||||
let space_str = (0..(max_count_str.len() - count_str.len()))
|
||||
.map(|_| ' ')
|
||||
.collect::<String>();
|
||||
format!("{space_str}{n}. {name}")
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self {
|
||||
names,
|
||||
status: ConfirmStatus::None,
|
||||
scroll: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_down(&mut self) {
|
||||
if self.scroll < self.names.len() - 1 {
|
||||
self.scroll += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_up(&mut self) {
|
||||
if self.scroll > 0 {
|
||||
self.scroll -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FloatContent for ConfirmPrompt {
|
||||
fn draw(&mut self, frame: &mut Frame, area: Rect) {
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(" Confirm selections ")
|
||||
.title_bottom(" [y] to continue, [n] to abort ")
|
||||
.title_alignment(Alignment::Center)
|
||||
.title_style(Style::default().bold())
|
||||
.style(Style::default());
|
||||
|
||||
frame.render_widget(block.clone(), area);
|
||||
|
||||
let inner_area = block.inner(area);
|
||||
|
||||
let paths_text = self
|
||||
.names
|
||||
.iter()
|
||||
.skip(self.scroll)
|
||||
.map(|p| {
|
||||
let span = Span::from(Cow::<'_, str>::Borrowed(p));
|
||||
Line::from(span).style(Style::default())
|
||||
})
|
||||
.collect::<Text>();
|
||||
|
||||
frame.render_widget(Clear, inner_area);
|
||||
frame.render_widget(List::new(paths_text), inner_area);
|
||||
}
|
||||
|
||||
fn handle_key_event(&mut self, key: &KeyEvent) -> bool {
|
||||
use KeyCode::*;
|
||||
self.status = match key.code {
|
||||
Char('y') | Char('Y') => ConfirmStatus::Confirm,
|
||||
Char('n') | Char('N') | Esc => ConfirmStatus::Abort,
|
||||
Char('j') => {
|
||||
self.scroll_down();
|
||||
ConfirmStatus::None
|
||||
}
|
||||
Char('k') => {
|
||||
self.scroll_up();
|
||||
ConfirmStatus::None
|
||||
}
|
||||
_ => ConfirmStatus::None,
|
||||
};
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn is_finished(&self) -> bool {
|
||||
use ConfirmStatus::*;
|
||||
match self.status {
|
||||
Confirm | Abort => true,
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_shortcut_list(&self) -> (&str, Box<[Shortcut]>) {
|
||||
(
|
||||
"Confirmation prompt",
|
||||
Box::new([
|
||||
Shortcut::new("Continue", ["Y", "y"]),
|
||||
Shortcut::new("Abort", ["N", "n"]),
|
||||
Shortcut::new("Scroll up", ["j"]),
|
||||
Shortcut::new("Scroll down", ["k"]),
|
||||
Shortcut::new("Close linutil", ["CTRL-c", "q"]),
|
||||
]),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -13,14 +13,14 @@ pub trait FloatContent {
|
|||
fn get_shortcut_list(&self) -> (&str, Box<[Shortcut]>);
|
||||
}
|
||||
|
||||
pub struct Float {
|
||||
content: Box<dyn FloatContent>,
|
||||
pub struct Float<Content: FloatContent + ?Sized> {
|
||||
pub content: Box<Content>,
|
||||
width_percent: u16,
|
||||
height_percent: u16,
|
||||
}
|
||||
|
||||
impl Float {
|
||||
pub fn new(content: Box<dyn FloatContent>, width_percent: u16, height_percent: u16) -> Self {
|
||||
impl<Content: FloatContent + ?Sized> Float<Content> {
|
||||
pub fn new(content: Box<Content>, width_percent: u16, height_percent: u16) -> Self {
|
||||
Self {
|
||||
content,
|
||||
width_percent,
|
||||
|
@ -60,6 +60,7 @@ impl Float {
|
|||
| KeyCode::Char('p')
|
||||
| KeyCode::Char('d')
|
||||
| KeyCode::Char('g')
|
||||
| KeyCode::Char('q')
|
||||
| KeyCode::Esc
|
||||
if self.content.is_finished() =>
|
||||
{
|
||||
|
|
|
@ -298,7 +298,7 @@ impl FloatContent for FloatingText {
|
|||
Shortcut::new("Scroll up", ["k", "Up"]),
|
||||
Shortcut::new("Scroll left", ["h", "Left"]),
|
||||
Shortcut::new("Scroll right", ["l", "Right"]),
|
||||
Shortcut::new("Close window", ["Enter", "p", "d", "g"]),
|
||||
Shortcut::new("Close window", ["Enter", "p", "q", "d", "g"]),
|
||||
]),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod confirmation;
|
||||
mod filter;
|
||||
mod float;
|
||||
mod floating_text;
|
||||
|
|
|
@ -37,6 +37,7 @@ pub struct RunningCommand {
|
|||
writer: Box<dyn Write + Send>,
|
||||
/// Only set after the process has ended
|
||||
status: Option<ExitStatus>,
|
||||
scroll_offset: usize,
|
||||
}
|
||||
|
||||
impl FloatContent for RunningCommand {
|
||||
|
@ -102,6 +103,12 @@ impl FloatContent for RunningCommand {
|
|||
KeyCode::Enter if self.is_finished() => {
|
||||
return true;
|
||||
}
|
||||
KeyCode::PageUp => {
|
||||
self.scroll_offset = self.scroll_offset.saturating_add(10);
|
||||
}
|
||||
KeyCode::PageDown => {
|
||||
self.scroll_offset = self.scroll_offset.saturating_sub(10);
|
||||
}
|
||||
// Pass other key events to the terminal
|
||||
_ => self.handle_passthrough_key_event(key),
|
||||
}
|
||||
|
@ -121,12 +128,20 @@ impl FloatContent for RunningCommand {
|
|||
if self.is_finished() {
|
||||
(
|
||||
"Finished command",
|
||||
Box::new([Shortcut::new("Close window", ["Enter", "q"])]),
|
||||
Box::new([
|
||||
Shortcut::new("Close window", ["Enter", "q"]),
|
||||
Shortcut::new("Scroll up", ["Page up"]),
|
||||
Shortcut::new("Scroll down", ["Page down"]),
|
||||
]),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
"Running command",
|
||||
Box::new([Shortcut::new("Kill the command", ["CTRL-c"])]),
|
||||
Box::new([
|
||||
Shortcut::new("Kill the command", ["CTRL-c"]),
|
||||
Shortcut::new("Scroll up", ["Page up"]),
|
||||
Shortcut::new("Scroll down", ["Page down"]),
|
||||
]),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -220,6 +235,7 @@ impl RunningCommand {
|
|||
pty_master: pair.master,
|
||||
writer,
|
||||
status: None,
|
||||
scroll_offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,10 +253,12 @@ impl RunningCommand {
|
|||
// 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
|
||||
// way, and doesn't cost that much
|
||||
let mut parser = vt100::Parser::new(size.height, size.width, 0);
|
||||
let mut parser = vt100::Parser::new(size.height, size.width, 200);
|
||||
let mutex = self.buffer.lock();
|
||||
let buffer = mutex.as_ref().unwrap();
|
||||
parser.process(buffer);
|
||||
// Adjust the screen content based on the scroll offset
|
||||
parser.set_scrollback(self.scroll_offset);
|
||||
parser.screen().clone()
|
||||
}
|
||||
|
||||
|
@ -297,8 +315,6 @@ impl RunningCommand {
|
|||
KeyCode::Tab => vec![9],
|
||||
KeyCode::Home => vec![27, 91, 72],
|
||||
KeyCode::End => vec![27, 91, 70],
|
||||
KeyCode::PageUp => vec![27, 91, 53, 126],
|
||||
KeyCode::PageDown => vec![27, 91, 54, 126],
|
||||
KeyCode::BackTab => vec![27, 91, 90],
|
||||
KeyCode::Delete => vec![27, 91, 51, 126],
|
||||
KeyCode::Insert => vec![27, 91, 50, 126],
|
||||
|
|
101
tui/src/state.rs
101
tui/src/state.rs
|
@ -1,4 +1,7 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
confirmation::{ConfirmPrompt, ConfirmStatus},
|
||||
filter::{Filter, SearchAction},
|
||||
float::{Float, FloatContent},
|
||||
floating_text::{FloatingText, FloatingTextMode},
|
||||
|
@ -8,7 +11,7 @@ use crate::{
|
|||
};
|
||||
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
|
||||
use ego_tree::NodeId;
|
||||
use linutil_core::{Command, ListNode, Tab};
|
||||
use linutil_core::{ListNode, Tab};
|
||||
#[cfg(feature = "tips")]
|
||||
use rand::Rng;
|
||||
use ratatui::{
|
||||
|
@ -53,7 +56,7 @@ pub struct AppState {
|
|||
selection: ListState,
|
||||
filter: Filter,
|
||||
multi_select: bool,
|
||||
selected_commands: Vec<Command>,
|
||||
selected_commands: Vec<Rc<ListNode>>,
|
||||
drawable: bool,
|
||||
#[cfg(feature = "tips")]
|
||||
tip: &'static str,
|
||||
|
@ -63,11 +66,12 @@ pub enum Focus {
|
|||
Search,
|
||||
TabList,
|
||||
List,
|
||||
FloatingWindow(Float),
|
||||
FloatingWindow(Float<dyn FloatContent>),
|
||||
ConfirmationPrompt(Float<ConfirmPrompt>),
|
||||
}
|
||||
|
||||
pub struct ListEntry {
|
||||
pub node: ListNode,
|
||||
pub node: Rc<ListNode>,
|
||||
pub id: NodeId,
|
||||
pub has_children: bool,
|
||||
}
|
||||
|
@ -164,6 +168,7 @@ impl AppState {
|
|||
),
|
||||
|
||||
Focus::FloatingWindow(ref float) => float.get_shortcut_list(),
|
||||
Focus::ConfirmationPrompt(ref prompt) => prompt.get_shortcut_list(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +313,7 @@ impl AppState {
|
|||
|ListEntry {
|
||||
node, has_children, ..
|
||||
}| {
|
||||
let is_selected = self.selected_commands.contains(&node.command);
|
||||
let is_selected = self.selected_commands.contains(node);
|
||||
let (indicator, style) = if is_selected {
|
||||
(self.theme.multi_select_icon(), Style::default().bold())
|
||||
} else {
|
||||
|
@ -389,8 +394,10 @@ impl AppState {
|
|||
|
||||
frame.render_stateful_widget(disclaimer_list, list_chunks[1], &mut self.selection);
|
||||
|
||||
if let Focus::FloatingWindow(float) = &mut self.focus {
|
||||
float.draw(frame, chunks[1]);
|
||||
match &mut self.focus {
|
||||
Focus::FloatingWindow(float) => float.draw(frame, chunks[1]),
|
||||
Focus::ConfirmationPrompt(prompt) => prompt.draw(frame, chunks[1]),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
frame.render_widget(keybind_para, vertical[1]);
|
||||
|
@ -400,9 +407,11 @@ impl AppState {
|
|||
// This should be defined first to allow closing
|
||||
// the application even when not drawable ( If terminal is small )
|
||||
// Exit on 'q' or 'Ctrl-c' input
|
||||
if matches!(self.focus, Focus::TabList | Focus::List)
|
||||
&& (key.code == KeyCode::Char('q')
|
||||
|| key.modifiers.contains(KeyModifiers::CONTROL) && key.code == KeyCode::Char('c'))
|
||||
if matches!(
|
||||
self.focus,
|
||||
Focus::TabList | Focus::List | Focus::ConfirmationPrompt(_)
|
||||
) && (key.code == KeyCode::Char('q')
|
||||
|| key.modifiers.contains(KeyModifiers::CONTROL) && key.code == KeyCode::Char('c'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -444,6 +453,22 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
|
||||
Focus::ConfirmationPrompt(confirm) => {
|
||||
confirm.content.handle_key_event(key);
|
||||
match confirm.content.status {
|
||||
ConfirmStatus::Abort => {
|
||||
self.focus = Focus::List;
|
||||
// selected command was pushed to selection list if multi-select was
|
||||
// enabled, need to clear it to prevent state corruption
|
||||
if !self.multi_select {
|
||||
self.selected_commands.clear()
|
||||
}
|
||||
}
|
||||
ConfirmStatus::Confirm => self.handle_confirm_command(),
|
||||
ConfirmStatus::None => {}
|
||||
}
|
||||
}
|
||||
|
||||
Focus::Search => match self.filter.handle_key(key) {
|
||||
SearchAction::Exit => self.exit_search(),
|
||||
SearchAction::Update => self.update_items(),
|
||||
|
@ -503,7 +528,7 @@ impl AppState {
|
|||
}
|
||||
|
||||
fn toggle_selection(&mut self) {
|
||||
if let Some(command) = self.get_selected_command() {
|
||||
if let Some(command) = self.get_selected_node() {
|
||||
if self.selected_commands.contains(&command) {
|
||||
self.selected_commands.retain(|c| c != &command);
|
||||
} else {
|
||||
|
@ -552,7 +577,7 @@ impl AppState {
|
|||
self.update_items();
|
||||
}
|
||||
|
||||
fn get_selected_node(&self) -> Option<&ListNode> {
|
||||
fn get_selected_node(&self) -> Option<Rc<ListNode>> {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
if !self.at_root() && selected_index == 0 {
|
||||
|
@ -564,18 +589,17 @@ impl AppState {
|
|||
|
||||
if let Some(item) = self.filter.item_list().get(selected_index) {
|
||||
if !item.has_children {
|
||||
return Some(&item.node);
|
||||
return Some(item.node.clone());
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
pub fn get_selected_command(&self) -> Option<Command> {
|
||||
self.get_selected_node().map(|node| node.command.clone())
|
||||
}
|
||||
|
||||
fn get_selected_description(&self) -> Option<String> {
|
||||
self.get_selected_node()
|
||||
.map(|node| node.description.clone())
|
||||
}
|
||||
|
||||
pub fn go_to_selected_dir(&mut self) {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
|
@ -596,6 +620,7 @@ impl AppState {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn selected_item_is_dir(&self) -> bool {
|
||||
let mut selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
|
@ -615,20 +640,26 @@ impl AppState {
|
|||
|
||||
pub fn selected_item_is_cmd(&self) -> bool {
|
||||
// Any item that is not a directory or up directory (..) must be a command
|
||||
!(self.selected_item_is_up_dir() || self.selected_item_is_dir())
|
||||
self.selection.selected().is_some()
|
||||
&& !(self.selected_item_is_up_dir() || self.selected_item_is_dir())
|
||||
}
|
||||
|
||||
pub fn selected_item_is_up_dir(&self) -> bool {
|
||||
let selected_index = self.selection.selected().unwrap_or(0);
|
||||
|
||||
!self.at_root() && selected_index == 0
|
||||
}
|
||||
|
||||
fn enable_preview(&mut self) {
|
||||
if let Some(command) = self.get_selected_command() {
|
||||
if let Some(preview) = FloatingText::from_command(&command, FloatingTextMode::Preview) {
|
||||
if let Some(node) = self.get_selected_node() {
|
||||
if let Some(preview) =
|
||||
FloatingText::from_command(&node.command, FloatingTextMode::Preview)
|
||||
{
|
||||
self.spawn_float(preview, 80, 80);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_description(&mut self) {
|
||||
if let Some(command_description) = self.get_selected_description() {
|
||||
let description = FloatingText::new(command_description, FloatingTextMode::Description);
|
||||
|
@ -639,31 +670,53 @@ impl AppState {
|
|||
fn handle_enter(&mut self) {
|
||||
if self.selected_item_is_cmd() {
|
||||
if self.selected_commands.is_empty() {
|
||||
if let Some(cmd) = self.get_selected_command() {
|
||||
self.selected_commands.push(cmd);
|
||||
if let Some(node) = self.get_selected_node() {
|
||||
self.selected_commands.push(node);
|
||||
}
|
||||
}
|
||||
let command = RunningCommand::new(self.selected_commands.clone());
|
||||
self.spawn_float(command, 80, 80);
|
||||
self.selected_commands.clear();
|
||||
|
||||
let cmd_names = self
|
||||
.selected_commands
|
||||
.iter()
|
||||
.map(|node| node.name.as_str())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let prompt = ConfirmPrompt::new(&cmd_names[..]);
|
||||
self.focus = Focus::ConfirmationPrompt(Float::new(Box::new(prompt), 40, 40));
|
||||
} else {
|
||||
self.go_to_selected_dir();
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_confirm_command(&mut self) {
|
||||
let commands = self
|
||||
.selected_commands
|
||||
.iter()
|
||||
.map(|node| node.command.clone())
|
||||
.collect();
|
||||
|
||||
let command = RunningCommand::new(commands);
|
||||
self.spawn_float(command, 80, 80);
|
||||
self.selected_commands.clear();
|
||||
}
|
||||
|
||||
fn spawn_float<T: FloatContent + 'static>(&mut self, float: T, width: u16, height: u16) {
|
||||
self.focus = Focus::FloatingWindow(Float::new(Box::new(float), width, height));
|
||||
}
|
||||
|
||||
fn enter_search(&mut self) {
|
||||
self.focus = Focus::Search;
|
||||
self.filter.activate_search();
|
||||
self.selection.select(None);
|
||||
}
|
||||
|
||||
fn exit_search(&mut self) {
|
||||
self.selection.select(Some(0));
|
||||
self.focus = Focus::List;
|
||||
self.filter.deactivate_search();
|
||||
self.update_items();
|
||||
}
|
||||
|
||||
fn refresh_tab(&mut self) {
|
||||
self.visit_stack = vec![self.tabs[self.current_tab.selected().unwrap()]
|
||||
.tree
|
||||
|
|
Loading…
Reference in New Issue
Block a user