mirror of
https://github.com/ChrisTitusTech/linutil.git
synced 2025-03-03 21:37:12 +00:00
Merge remote-tracking branch 'linutil'
This commit is contained in:
commit
fc3bfc6df3
51
.github/requirements.txt
vendored
51
.github/requirements.txt
vendored
|
@ -1,51 +0,0 @@
|
|||
Babel==2.15.0
|
||||
bracex==2.5
|
||||
cairocffi==1.7.1
|
||||
CairoSVG==2.7.1
|
||||
certifi==2024.7.4
|
||||
cffi==1.17.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
colorama==0.4.6
|
||||
csscompressor==0.9.5
|
||||
cssselect2==0.7.0
|
||||
defusedxml==0.7.1
|
||||
ghp-import==2.1.0
|
||||
gitdb==4.0.11
|
||||
GitPython==3.1.43
|
||||
htmlmin2==0.1.13
|
||||
idna==3.7
|
||||
Jinja2==3.1.4
|
||||
jsmin==3.0.1
|
||||
Markdown==3.6
|
||||
MarkupSafe==2.1.5
|
||||
mergedeep==1.3.4
|
||||
mkdocs==1.6.0
|
||||
mkdocs-awesome-pages-plugin==2.9.3
|
||||
mkdocs-get-deps==0.2.0
|
||||
mkdocs-git-revision-date-localized-plugin==1.2.6
|
||||
mkdocs-material==9.5.31
|
||||
mkdocs-material-extensions==1.3.1
|
||||
mkdocs-minify-plugin==0.8.0
|
||||
natsort==8.4.0
|
||||
packaging==24.1
|
||||
paginate==0.5.6
|
||||
pathspec==0.12.1
|
||||
pillow==10.4.0
|
||||
platformdirs==4.2.2
|
||||
pycparser==2.22
|
||||
Pygments==2.18.0
|
||||
pymdown-extensions==10.9
|
||||
python-dateutil==2.9.0.post0
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.2
|
||||
pyyaml_env_tag==0.1
|
||||
regex==2024.7.24
|
||||
requests==2.32.3
|
||||
six==1.16.0
|
||||
smmap==5.0.1
|
||||
tinycss2==1.3.0
|
||||
urllib3==2.2.2
|
||||
watchdog==4.0.1
|
||||
wcmatch==9.0
|
||||
webencodings==0.5.1
|
6
.github/workflows/shellcheck.yml
vendored
6
.github/workflows/shellcheck.yml
vendored
|
@ -31,9 +31,3 @@ jobs:
|
|||
steps:
|
||||
- name: Checkout sources
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run shfmt
|
||||
uses: reviewdog/action-shfmt@v1
|
||||
with:
|
||||
shfmt_flags: '-i 4 -ci'
|
||||
reviewdog_flags: '-fail-level=any'
|
||||
|
|
23
README.md
23
README.md
|
@ -27,25 +27,18 @@ curl -fsSL https://christitus.com/linuxdev | sh
|
|||
|
||||
### CLI arguments
|
||||
|
||||
Linutil supports various command-line arguments to customize its behavior. Here are some common arguments you can use:
|
||||
|
||||
- `-c, --config <CONFIG>` : Path to the configuration file.
|
||||
- `--override-validation` : Show all available options, disregarding compatibility checks (UNSAFE).
|
||||
- `--size-bypass` : Bypass the terminal size limit.
|
||||
- `-y, --skip-confirmation` : Skip confirmation prompt before executing commands.
|
||||
- `-t, --theme <THEME>` : Set the theme to use in the application [default: `default`] [possible values: `default`, `compatible`].
|
||||
- `-h, --help` : Print help.
|
||||
|
||||
For more detailed usage, run:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://christitus.com/linux | sh -s -- --help
|
||||
```
|
||||
View available options by running:
|
||||
|
||||
```bash
|
||||
linutil --help
|
||||
```
|
||||
|
||||
For installer options:
|
||||
|
||||
```bash
|
||||
curl -fsSL https://christitus.com/linux | sh -s -- --help
|
||||
```
|
||||
|
||||
## ⬇️ Installation
|
||||
|
||||
Linutil is also available as a package in various repositories:
|
||||
|
@ -142,7 +135,7 @@ Docs are now [here](https://github.com/Chris-Titus-Docs/linutil-docs)
|
|||
|
||||
## 🏅 Thanks to All Contributors
|
||||
|
||||
Thank you to everyone who has contributed to the development of Linutil. Your efforts are greatly appreciated, and you’re helping make this tool better for everyone!
|
||||
Thank you to everyone who has contributed to the development of Linutil. Your efforts are greatly appreciated, and you're helping make this tool better for everyone!
|
||||
|
||||
[](https://github.com/ChrisTitusTech/linutil/graphs/contributors)
|
||||
|
||||
|
|
|
@ -111,18 +111,16 @@ fn default_true() -> bool {
|
|||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum EntryType {
|
||||
#[serde(rename = "entries")]
|
||||
Entries(Vec<Entry>),
|
||||
#[serde(rename = "command")]
|
||||
Command(String),
|
||||
#[serde(rename = "script")]
|
||||
Script(PathBuf),
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
fn is_supported(&self) -> bool {
|
||||
self.preconditions.as_deref().map_or(true, |preconditions| {
|
||||
self.preconditions.as_deref().is_none_or(|preconditions| {
|
||||
preconditions.iter().all(
|
||||
|Precondition {
|
||||
matches,
|
||||
|
@ -132,14 +130,16 @@ impl Entry {
|
|||
match data {
|
||||
SystemDataType::Environment(var_name) => std::env::var(var_name)
|
||||
.is_ok_and(|var| values.contains(&var) == *matches),
|
||||
SystemDataType::File(path) => {
|
||||
std::fs::read_to_string(path).is_ok_and(|data| {
|
||||
values.iter().all(|matching| data.contains(matching)) == *matches
|
||||
})
|
||||
}
|
||||
SystemDataType::ContainingFile(file) => std::fs::read_to_string(file)
|
||||
.is_ok_and(|data| {
|
||||
values
|
||||
.iter()
|
||||
.all(|matching| data.contains(matching) == *matches)
|
||||
}),
|
||||
SystemDataType::CommandExists => values
|
||||
.iter()
|
||||
.all(|command| which::which(command).is_ok() == *matches),
|
||||
SystemDataType::FileExists => values.iter().all(|p| Path::new(p).is_file()),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -157,12 +157,11 @@ struct Precondition {
|
|||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
enum SystemDataType {
|
||||
#[serde(rename = "environment")]
|
||||
Environment(String),
|
||||
#[serde(rename = "file")]
|
||||
File(PathBuf),
|
||||
#[serde(rename = "command_exists")]
|
||||
ContainingFile(PathBuf),
|
||||
FileExists,
|
||||
CommandExists,
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ install_adb() {
|
|||
"$ESCALATION_TOOL" "$PACKAGER" add android-tools
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: "$PACKAGER"${RC}"
|
||||
printf "%b\n" "${RED}Unsupported package manager: $PACKAGER${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -8,7 +8,7 @@ installLibreWolf() {
|
|||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y gnupg lsb-release apt-transport-https ca-certificates
|
||||
distro=`if echo " una bookworm vanessa focal jammy bullseye vera uma " | grep -q " $(lsb_release -sc) "; then lsb_release -sc; else echo focal; fi`
|
||||
distro=$(if echo " una bookworm vanessa focal jammy bullseye vera uma " | grep -q "$(lsb_release -sc)"; then "$(lsb_release -sc)"; else echo 'focal'; fi)
|
||||
curl -fsSL https://deb.librewolf.net/keyring.gpg | "$ESCALATION_TOOL" gpg --dearmor -o /usr/share/keyrings/librewolf.gpg
|
||||
echo "Types: deb
|
||||
URIs: https://deb.librewolf.net
|
||||
|
|
29
core/tabs/applications-setup/browsers/zen-browser.sh
Executable file
29
core/tabs/applications-setup/browsers/zen-browser.sh
Executable file
|
@ -0,0 +1,29 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
installZenBrowser() {
|
||||
if ! command_exists io.github.zen_browser.zen && ! command_exists zen-browser; then
|
||||
printf "%b\n" "${YELLOW}Installing Zen Browser...${RC}"
|
||||
case "$PACKAGER" in
|
||||
pacman)
|
||||
if grep -q avx2 /proc/cpuinfo; then
|
||||
"$AUR_HELPER" -S --needed --noconfirm zen-browser-avx2-bin
|
||||
else
|
||||
"$AUR_HELPER" -S --needed --noconfirm zen-browser-bin
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
checkFlatpak
|
||||
flatpak install -y flathub io.github.zen_browser.zen
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Zen Browser is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
checkEscalationTool
|
||||
checkAURHelper
|
||||
installZenBrowser
|
|
@ -17,7 +17,7 @@ installDiscord() {
|
|||
"$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm discord
|
||||
;;
|
||||
dnf)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y "https://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm"
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y discord
|
||||
;;
|
||||
apk)
|
||||
|
|
|
@ -8,7 +8,7 @@ installSignal() {
|
|||
case "$PACKAGER" in
|
||||
apt-get|nala)
|
||||
curl -fsSL https://updates.signal.org/desktop/apt/keys.asc | gpg --dearmor > signal-desktop-keyring.gpg
|
||||
cat signal-desktop-keyring.gpg | "$ESCALATION_TOOL" tee /usr/share/keyrings/signal-desktop-keyring.gpg > /dev/null
|
||||
"$ESCALATION_TOOL" tee /usr/share/keyrings/signal-desktop-keyring.gpg < signal-desktop-keyring.gpg > /dev/null
|
||||
printf "%b\n" 'deb [arch=amd64 signed-by=/usr/share/keyrings/signal-desktop-keyring.gpg] https://updates.signal.org/desktop/apt xenial main' | "$ESCALATION_TOOL" tee /etc/apt/sources.list.d/signal-xenial.list
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -y install signal-desktop
|
||||
|
|
52
core/tabs/applications-setup/developer-tools/zed.sh
Normal file
52
core/tabs/applications-setup/developer-tools/zed.sh
Normal file
|
@ -0,0 +1,52 @@
|
|||
#!/bin/sh -e
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
installZed() {
|
||||
if ! command_exists dev.zed.Zed && ! command_exists zed && ! command_exists zeditor; then
|
||||
printf "%b\n" "${CYAN}Installing Zed.${RC}"
|
||||
case "$PACKAGER" in
|
||||
apk)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" add zed
|
||||
;;
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -S zed
|
||||
;;
|
||||
zypper)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" addrepo -f https://download.opensuse.org/repositories/editors/openSUSE_Tumbleweed/editors.repo
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y zed
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${YELLOW}No official package found for package manager $PACKAGER. Do you want to install flathub package or from source?${RC}"
|
||||
printf "%b\n" "1) Flathub package"
|
||||
printf "%b\n" "2) Source"
|
||||
printf "%b\n" "3) Exit"
|
||||
printf "%b" "Choose an option: "
|
||||
read -r choice
|
||||
case "$choice" in
|
||||
1)
|
||||
checkFlatpak
|
||||
flatpak install -y flathub dev.zed.Zed
|
||||
;;
|
||||
2)
|
||||
curl -f https://zed.dev/install.sh | sh
|
||||
;;
|
||||
3)
|
||||
printf "%b\n" "${GREEN}Exiting.${RC}"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Invalid option.${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "%b\n" "${GREEN}Zed is already installed.${RC}"
|
||||
fi
|
||||
}
|
||||
|
||||
checkEnv
|
||||
clear
|
||||
installZed
|
|
@ -192,7 +192,7 @@ setupDisplayManager() {
|
|||
"$ESCALATION_TOOL" "$PACKAGER" install -y xorg-x11-xinit xorg-x11-server-Xorg
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: "$PACKAGER"${RC}"
|
||||
printf "%b\n" "${RED}Unsupported package manager: $PACKAGER${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
@ -244,7 +244,7 @@ setupDisplayManager() {
|
|||
"$ESCALATION_TOOL" "$PACKAGER" install -y "$DM"
|
||||
;;
|
||||
*)
|
||||
printf "%b\n" "${RED}Unsupported package manager: "$PACKAGER"${RC}"
|
||||
printf "%b\n" "${RED}Unsupported package manager: $PACKAGER${RC}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
|
|
@ -53,7 +53,7 @@ installLinutil() {
|
|||
;;
|
||||
*)
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
. $HOME/.cargo/env
|
||||
. "$HOME/.cargo/env"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
|
|
@ -17,7 +17,7 @@ updateLinutil() {
|
|||
zypper)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -n curl gcc make
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
|
||||
. $HOME/.cargo/env
|
||||
. "$HOME/.cargo/env"
|
||||
;;
|
||||
apk)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" add build-base
|
||||
|
|
|
@ -57,49 +57,55 @@ name = "Developer Tools"
|
|||
[[data.entries]]
|
||||
name = "Github Desktop"
|
||||
description = "GitHub Desktop is a user-friendly application that simplifies the process of managing Git repositories and interacting with GitHub, providing a graphical interface for tasks like committing, branching, and syncing changes."
|
||||
script = "Developer-tools/githubdesktop-setup.sh"
|
||||
script = "developer-tools/githubdesktop.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "JetBrains Toolbox"
|
||||
description = "JetBrains Toolbox is a collection of tools and an app that help developers work with JetBrains products."
|
||||
script = "Developer-tools/jetbrains-toolbox.sh"
|
||||
script = "developer-tools/jetbrains-toolbox.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
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"
|
||||
script = "developer-tools/meld.sh"
|
||||
task_list = "I FI"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Neovim"
|
||||
description = "Neovim is a refactor, and sometimes redactor, in the tradition of Vim.\nIt is not a rewrite but a continuation and extension of Vim.\nThis command configures neovim from CTT's neovim configuration.\nhttps://github.com/ChrisTitusTech/neovim"
|
||||
script = "Developer-tools/neovim-setup.sh"
|
||||
script = "developer-tools/neovim.sh"
|
||||
task_list = "I FM"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Ngrok"
|
||||
description = "Ngrok is a tool that creates secure, temporary tunnels to expose local servers to the internet for testing and development."
|
||||
script = "Developer-tools/ngrok-setup.sh"
|
||||
script = "developer-tools/ngrok.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Sublime Text"
|
||||
description = "Sublime Text is a fast, lightweight, and customizable text editor known for its simplicity, powerful features, and wide range of plugins for various programming languages."
|
||||
script = "Developer-tools/sublime-setup.sh"
|
||||
script = "developer-tools/sublime.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "VS Code"
|
||||
description = "Visual Studio Code (VS Code) is a lightweight, open-source code editor with built-in support for debugging, version control, and extensions for various programming languages and frameworks."
|
||||
script = "Developer-tools/vscode-setup.sh"
|
||||
script = "developer-tools/vscode.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "VS Codium"
|
||||
description = "VSCodium is a free, open-source version of Visual Studio Code (VS Code) that removes Microsoft-specific telemetry and branding."
|
||||
script = "Developer-tools/vscodium-setup.sh"
|
||||
script = "developer-tools/vscodium.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Zed"
|
||||
description = "Zed is a next-generation code editor written in rust, designed for high-performance collaboration with humans and AI."
|
||||
script = "developer-tools/zed.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data]]
|
||||
|
@ -186,6 +192,12 @@ description = "Mozilla Firefox is a free and open-source web browser developed b
|
|||
script = "browsers/firefox.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Zen Browser"
|
||||
description = "Zen Browser is a privacy-focused web browser designed for enhanced security and a seamless browsing experience."
|
||||
script = "browsers/zen-browser.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Thorium"
|
||||
description = "Thorium is a Chromium-based browser focused on privacy and performance."
|
||||
|
|
15
core/tabs/system-setup/arch/hyprland-kool.sh
Normal file
15
core/tabs/system-setup/arch/hyprland-kool.sh
Normal file
|
@ -0,0 +1,15 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
printf "%b\n" "${YELLOW}Starting Hyprland JaKooLit installation${RC}"
|
||||
|
||||
if ! pacman -Q base-devel >/dev/null 2>&1; then
|
||||
printf "%b\n" "${YELLOW}Installing base-devel...${RC}"
|
||||
"$ESCALATION_TOOL" pacman -S --noconfirm base-devel
|
||||
fi
|
||||
|
||||
git clone --depth=1 https://github.com/JaKooLit/Arch-Hyprland.git "$HOME/Arch-Hyprland" || { printf "%b\n" "${RED}Failed to clone Jakoolits Arch-Hyprland repo${RC}"; exit 1; }
|
||||
cd "$HOME/Arch-Hyprland" || { printf "%b\n" "${RED}Failed to navigate to Arch-Hyprland directory${RC}"; exit 1; }
|
||||
chmod +x install.sh
|
||||
./install.sh
|
|
@ -15,33 +15,33 @@ installDepend() {
|
|||
else
|
||||
printf "%b\n" "${GREEN}Multilib is already enabled.${RC}"
|
||||
fi
|
||||
"$AUR_HELPER" -S --needed --noconfirm $DEPENDENCIES
|
||||
"$AUR_HELPER" -S --needed --noconfirm "$DEPENDENCIES"
|
||||
;;
|
||||
apt-get|nala)
|
||||
COMPILEDEPS='build-essential'
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update
|
||||
"$ESCALATION_TOOL" dpkg --add-architecture i386
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y $DEPENDENCIES $COMPILEDEPS
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y "$DEPENDENCIES" "$COMPILEDEPS"
|
||||
;;
|
||||
dnf)
|
||||
COMPILEDEPS='@development-tools'
|
||||
"$ESCALATION_TOOL" "$PACKAGER" update
|
||||
"$ESCALATION_TOOL" "$PACKAGER" config-manager --set-enabled powertools
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y $DEPENDENCIES $COMPILEDEPS
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y "$DEPENDENCIES" "$COMPILEDEPS"
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y glibc-devel.i686 libgcc.i686
|
||||
;;
|
||||
zypper)
|
||||
COMPILEDEPS='patterns-devel-base-devel_basis'
|
||||
"$ESCALATION_TOOL" "$PACKAGER" refresh
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --non-interactive install $DEPENDENCIES $COMPILEDEPS
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --non-interactive install "$DEPENDENCIES" "$COMPILEDEPS"
|
||||
"$ESCALATION_TOOL" "$PACKAGER" --non-interactive install libgcc_s1-gcc7-32bit glibc-devel-32bit
|
||||
;;
|
||||
apk)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" add build-base multitail tar tree trash-cli unzip cmake jq
|
||||
;;
|
||||
*)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y $DEPENDENCIES
|
||||
"$ESCALATION_TOOL" "$PACKAGER" install -y "$DEPENDENCIES"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
9
core/tabs/system-setup/debian/hyprland-kool-deb.sh
Normal file
9
core/tabs/system-setup/debian/hyprland-kool-deb.sh
Normal file
|
@ -0,0 +1,9 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
printf "%b\n" "${YELLOW}Starting Hyprland JaKooLit installation${RC}"
|
||||
git clone --depth=1 https://github.com/JaKooLit/Debian-Hyprland.git "$HOME/Debian-Hyprland" || { printf "%b\n" "${RED}Failed to clone Jakoolits Debian-Hyprland repo${RC}"; exit 1; }
|
||||
cd "$HOME/Debian-Hyprland" || { printf "%b\n" "${RED}Failed to navigate to Debian-Hyprland directory${RC}"; exit 1; }
|
||||
chmod +x install.sh
|
||||
./install.sh
|
10
core/tabs/system-setup/fedora/hyprland-kool-fed.sh
Normal file
10
core/tabs/system-setup/fedora/hyprland-kool-fed.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
printf "%b\n" "${YELLOW}Starting Hyprland JaKooLit installation${RC}"
|
||||
|
||||
git clone --depth=1 https://github.com/JaKooLit/Fedora-Hyprland.git "$HOME/Fedora-Hyprland" || { printf "%b\n" "${RED}Failed to clone Jakoolits Fedora-Hyprland repo${RC}"; exit 1; }
|
||||
cd "$HOME/Fedora-Hyprland" || { printf "%b\n" "${RED}Failed to navigate to Fedora-Hyprland directory${RC}"; exit 1; }
|
||||
chmod +x install.sh
|
||||
./install.sh
|
|
@ -22,7 +22,7 @@ cleanup_system() {
|
|||
;;
|
||||
pacman)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -Sc --noconfirm
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -Rns $(pacman -Qtdq) --noconfirm > /dev/null || true
|
||||
"$ESCALATION_TOOL" "$PACKAGER" -Rns "$(pacman -Qtdq)" --noconfirm > /dev/null || true
|
||||
;;
|
||||
apk)
|
||||
"$ESCALATION_TOOL" "$PACKAGER" cache clean
|
||||
|
|
|
@ -16,15 +16,22 @@ task_list = "SI D"
|
|||
multi_select = false
|
||||
|
||||
[[data.entries]]
|
||||
name ="Linux Neptune for SteamDeck"
|
||||
name = "Hyprland JaKooLit"
|
||||
description = "Install JaKooLit's Hyprland configuration"
|
||||
script = "arch/hyprland-kool.sh"
|
||||
task_list = "I MP"
|
||||
multi_select = false
|
||||
|
||||
[[data.entries]]
|
||||
name = "Linux Neptune for SteamDeck"
|
||||
description = "Valve's fork of Linux Kernel for the SteamDeck"
|
||||
script = "arch/linux-neptune.sh"
|
||||
task_list = "I PFM K"
|
||||
|
||||
[[data.entries.preconditions]]
|
||||
matches = true
|
||||
data = { file = "/sys/devices/virtual/dmi/id/board_vendor" }
|
||||
values = [ "Valve" ]
|
||||
data = { containing_file = "/sys/devices/virtual/dmi/id/board_vendor" }
|
||||
values = ["Valve"]
|
||||
|
||||
[[data.entries]]
|
||||
name = "Nvidia Drivers && Hardware Acceleration"
|
||||
|
@ -50,6 +57,20 @@ description = "Yet Another Yogurt - An AUR Helper Written in Go. To know more ab
|
|||
script = "arch/yay-setup.sh"
|
||||
task_list = "I"
|
||||
|
||||
[[data]]
|
||||
name = "Debian"
|
||||
|
||||
[[data.preconditions]]
|
||||
matches = true
|
||||
data = { containing_file = "/etc/os-release" }
|
||||
values = ["ID=debian"]
|
||||
|
||||
[[data.entries]]
|
||||
name = "Hyprland JaKooLit"
|
||||
description = "Install JaKooLit's Hyprland configuration"
|
||||
script = "debian/hyprland-kool-deb.sh"
|
||||
task_list = "I MP"
|
||||
|
||||
[[data]]
|
||||
name = "Fedora"
|
||||
|
||||
|
@ -64,6 +85,12 @@ description = "Optimizes DNF for parallel downloads"
|
|||
script = "fedora/configure-dnf.sh"
|
||||
task_list = "PFM"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Hyprland JaKooLit"
|
||||
description = "Install JaKooLit's Hyprland configuration"
|
||||
script = "fedora/hyprland-kool-fed.sh"
|
||||
task_list = "I MP"
|
||||
|
||||
[[data.entries]]
|
||||
name = "Multimedia Codecs"
|
||||
description = "This script is designed to install multimedia codecs, and to ensure RPM Fusion repositories are installed."
|
||||
|
@ -103,7 +130,26 @@ task_list = "I PFM SS"
|
|||
[[data.preconditions]]
|
||||
matches = true
|
||||
data = "command_exists"
|
||||
values = [ "btrfs" ]
|
||||
values = ["btrfs"]
|
||||
|
||||
[[data]]
|
||||
name = "Ubuntu"
|
||||
|
||||
[[data.preconditions]]
|
||||
matches = true
|
||||
data = { containing_file = "/etc/os-release" }
|
||||
values = ["ID=ubuntu"]
|
||||
|
||||
[[data.entries]]
|
||||
name = "Hyprland JaKooLit"
|
||||
description = "Install JaKooLit's Hyprland configuration"
|
||||
script = "ubuntu/hyprland-kool-ubuntu24.sh"
|
||||
task_list = "I MP"
|
||||
|
||||
[[data.preconditions]]
|
||||
matches = true
|
||||
data = { containing_file = "/etc/os-release" }
|
||||
values = ['VERSION_ID="24.04"']
|
||||
|
||||
[[data]]
|
||||
name = "Build Prerequisites"
|
||||
|
|
10
core/tabs/system-setup/ubuntu/hyprland-kool-ubuntu24.sh
Normal file
10
core/tabs/system-setup/ubuntu/hyprland-kool-ubuntu24.sh
Normal file
|
@ -0,0 +1,10 @@
|
|||
#!/bin/sh
|
||||
|
||||
. ../../common-script.sh
|
||||
|
||||
printf "%b\n" "${YELLOW}Starting Hyprland JaKooLit installation${RC}"
|
||||
|
||||
git clone -b 24.04 --depth=1 https://github.com/JaKooLit/Ubuntu-Hyprland.git "$HOME/Ubuntu-Hyprland-24.04" || { printf "%b\n" "${RED}Failed to clone Jakoolits Ubuntu-Hyprland repo${RC}"; exit 1; }
|
||||
cd "$HOME/Ubuntu-Hyprland-24.04" || { printf "%b\n" "${RED}Failed to navigate to Ubuntu-Hyprland-24.04 directory${RC}"; exit 1; }
|
||||
chmod +x install.sh
|
||||
./install.sh
|
|
@ -65,12 +65,11 @@ scan_devices() {
|
|||
printf "%b\n" "$devices"
|
||||
fi
|
||||
printf "%b" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
}
|
||||
|
||||
# Function to prompt for MAC address using numbers
|
||||
prompt_for_mac() {
|
||||
action=$1
|
||||
command=$2
|
||||
prompt_msg=$3
|
||||
success_msg=$4
|
||||
|
@ -82,14 +81,14 @@ prompt_for_mac() {
|
|||
if [ -z "$devices" ]; then
|
||||
printf "%b\n" "${RED}No devices available. Please scan for devices first.${RC}"
|
||||
printf "%b" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
return
|
||||
fi
|
||||
|
||||
# Display devices with numbers
|
||||
device_list=$(echo "$devices" | tr '\n' '\n')
|
||||
i=1
|
||||
echo "$device_list" | while IFS= read -r device; do
|
||||
for device in $device_list; do
|
||||
printf "%d. %s\n" "$i" "$device"
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
@ -102,12 +101,12 @@ prompt_for_mac() {
|
|||
device=$(echo "$device_list" | sed -n "${choice}p")
|
||||
mac=$(echo "$device" | awk '{print $2}')
|
||||
if bluetoothctl info "$mac" > /dev/null 2>&1; then
|
||||
bluetoothctl "$command" "$mac" && {
|
||||
if bluetoothctl "$command" "$mac"; then
|
||||
printf "%b\n" "${GREEN}$success_msg${RC}"
|
||||
break
|
||||
} || {
|
||||
else
|
||||
printf "%b\n" "${RED}$failure_msg${RC}"
|
||||
}
|
||||
fi
|
||||
else
|
||||
printf "%b\n" "${RED}Invalid MAC address. Please try again.${RC}"
|
||||
fi
|
||||
|
@ -118,7 +117,7 @@ prompt_for_mac() {
|
|||
fi
|
||||
done
|
||||
printf "%b" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
}
|
||||
|
||||
# Function to pair with a device
|
||||
|
|
|
@ -62,11 +62,11 @@ encrypt_file() {
|
|||
if [ -d "$INPUT_PATH" ]; then
|
||||
# Encrypt each file in the directory
|
||||
find "$INPUT_PATH" -type f | while read -r FILE; do
|
||||
REL_PATH="${FILE#$INPUT_PATH/}"
|
||||
REL_PATH="${FILE#"$INPUT_PATH"/}"
|
||||
OUTPUT_FILE="$OUTPUT_PATH/$REL_PATH.enc"
|
||||
mkdir -p "$(dirname "$OUTPUT_FILE")"
|
||||
openssl enc -aes-256-cbc -salt -pbkdf2 -in "$FILE" -out "$OUTPUT_FILE" -k "$PASSWORD"
|
||||
if [ $? -eq 0 ]; then
|
||||
|
||||
if [ "$(openssl enc -aes-256-cbc -salt -pbkdf2 -in "$FILE" -out "$OUTPUT_FILE" -k "$PASSWORD")" -eq 0 ]; then
|
||||
printf "%b\n" "Encrypted: $OUTPUT_FILE"
|
||||
else
|
||||
printf "%b\n" "Failed to encrypt: $FILE"
|
||||
|
@ -79,8 +79,8 @@ encrypt_file() {
|
|||
return
|
||||
fi
|
||||
mkdir -p "$(dirname "$OUTPUT_PATH")"
|
||||
openssl enc -aes-256-cbc -salt -pbkdf2 -in "$INPUT_PATH" -out "$OUTPUT_PATH" -k "$PASSWORD"
|
||||
if [ $? -eq 0 ]; then
|
||||
|
||||
if [ "$(openssl enc -aes-256-cbc -salt -pbkdf2 -in "$INPUT_PATH" -out "$OUTPUT_PATH" -k "$PASSWORD")" -eq 0 ]; then
|
||||
printf "%b\n" "Encrypted: $OUTPUT_PATH"
|
||||
else
|
||||
printf "%b\n" "Failed to encrypt: $INPUT_PATH"
|
||||
|
@ -107,11 +107,11 @@ decrypt_file() {
|
|||
if [ -d "$INPUT_PATH" ]; then
|
||||
# Decrypt each file in the directory
|
||||
find "$INPUT_PATH" -type f -name '*.enc' | while read -r FILE; do
|
||||
REL_PATH="${FILE#$INPUT_PATH/}"
|
||||
REL_PATH="${FILE#"$INPUT_PATH"/}"
|
||||
OUTPUT_FILE="$OUTPUT_PATH/${REL_PATH%.enc}"
|
||||
mkdir -p "$(dirname "$OUTPUT_FILE")"
|
||||
openssl enc -aes-256-cbc -d -pbkdf2 -in "$FILE" -out "$OUTPUT_FILE" -k "$PASSWORD"
|
||||
if [ $? -eq 0 ]; then
|
||||
|
||||
if [ "$(openssl enc -aes-256-cbc -d -pbkdf2 -in "$FILE" -out "$OUTPUT_FILE" -k "$PASSWORD")" -eq 0 ]; then
|
||||
printf "%b\n" "Decrypted: $OUTPUT_FILE"
|
||||
else
|
||||
printf "%b\n" "Failed to decrypt: $FILE"
|
||||
|
@ -124,8 +124,8 @@ decrypt_file() {
|
|||
return
|
||||
fi
|
||||
mkdir -p "$(dirname "$OUTPUT_PATH")"
|
||||
openssl enc -aes-256-cbc -d -pbkdf2 -in "$INPUT_PATH" -out "$OUTPUT_PATH" -k "$PASSWORD"
|
||||
if [ $? -eq 0 ]; then
|
||||
|
||||
if [ "$(openssl enc -aes-256-cbc -d -pbkdf2 -in "$INPUT_PATH" -out "$OUTPUT_PATH" -k "$PASSWORD")" -eq 0 ]; then
|
||||
printf "%b\n" "Decrypted: $OUTPUT_PATH"
|
||||
else
|
||||
printf "%b\n" "Failed to decrypt: $INPUT_PATH"
|
||||
|
@ -148,7 +148,7 @@ main(){
|
|||
esac
|
||||
|
||||
printf "%b\n" "Press [Enter] to continue..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ adjust_monitor_brightness() {
|
|||
if ! echo "$monitor_choice" | grep -qE '^[0-9]+$'; then
|
||||
printf "%b\n" "${RED}Invalid selection. Please try again.${RC}"
|
||||
printf "Press [Enter] to continue..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
continue
|
||||
fi
|
||||
|
||||
|
@ -37,7 +37,7 @@ adjust_monitor_brightness() {
|
|||
if [ "$monitor_choice" -lt 1 ] || [ "$monitor_choice" -gt "$monitor_count" ]; then
|
||||
printf "%b\n" "${RED}Invalid selection. Please try again.${RC}"
|
||||
printf "Press [Enter] to continue..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
continue
|
||||
fi
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ set_resolutions() {
|
|||
if ! echo "$monitor_choice" | grep -qE '^[0-9]+$' || [ "$monitor_choice" -lt 1 ] || [ "$monitor_choice" -gt "$((i - 1))" ]; then
|
||||
printf "%b\n" "${RED}Invalid selection. Please try again.${RC}"
|
||||
printf "%b\n" "Press [Enter] to continue..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
continue
|
||||
fi
|
||||
|
||||
|
|
|
@ -86,6 +86,7 @@ run_model() {
|
|||
|
||||
printf "%b\n" "${YELLOW}Custom Models${RC}"
|
||||
custom_models=$(ollama list | grep 'custom-model-prefix')
|
||||
printf "%b\n" "${custom_models}"
|
||||
|
||||
printf "%b" "Select a model to run: "
|
||||
printf "%b" "Enter the number corresponding to the model or enter the name of a custom model: "
|
||||
|
@ -195,7 +196,7 @@ menu() {
|
|||
esac
|
||||
|
||||
printf "%b\n" "${YELLOW}Press Enter to continue...${RC}"
|
||||
read -r dummy
|
||||
read -r _
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -173,7 +173,7 @@ setup_ssh_samba(){
|
|||
printf "%b\n" "5. Exit"
|
||||
|
||||
printf "%b" "Enter your choice (1-5): "
|
||||
read CHOICE
|
||||
read -r CHOICE
|
||||
|
||||
case "$CHOICE" in
|
||||
1)
|
||||
|
|
|
@ -267,7 +267,7 @@ main() {
|
|||
esac
|
||||
|
||||
printf "%b\n" "Press [Enter] to continue..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ create_snapshot() {
|
|||
"$ESCALATION_TOOL" timeshift --create --comments "$COMMENT" --tags "$TAG"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "%b\n" "${GREEN}Snapshot created successfully.${RC}"
|
||||
else
|
||||
|
@ -93,6 +94,7 @@ restore_snapshot() {
|
|||
"$ESCALATION_TOOL" timeshift --restore --snapshot "$SNAPSHOT" --target-device "$TARGET_DEVICE" --grub-device "$GRUB_DEVICE" --yes
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "%b\n" "${GREEN}Snapshot restored successfully.${RC}"
|
||||
else
|
||||
|
@ -110,6 +112,7 @@ delete_snapshot() {
|
|||
printf "%b\n" "${YELLOW}Deleting snapshot $SNAPSHOT...${RC}"
|
||||
"$ESCALATION_TOOL" timeshift --delete --snapshot "$SNAPSHOT" --yes
|
||||
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "%b\n" "${GREEN}Snapshot deleted successfully.${RC}"
|
||||
else
|
||||
|
@ -126,6 +129,7 @@ delete_all_snapshots() {
|
|||
if [ "$CONFIRMATION" = "y" ] || [ "$CONFIRMATION" = "Y" ]; then
|
||||
printf "%b\n" "${CYAN}Deleting all snapshots...${RC}"
|
||||
"$ESCALATION_TOOL" timeshift --delete-all --yes
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? -eq 0 ]; then
|
||||
printf "%b\n" "${GREEN}All snapshots deleted successfully.${RC}"
|
||||
else
|
||||
|
@ -153,7 +157,7 @@ main_menu() {
|
|||
*) printf "%b\n" "${RED}Invalid option. Please try again.${RC}" ;;
|
||||
esac
|
||||
printf "%b\n" "${CYAN}Press Enter to continue...${RC}"
|
||||
read -r dummy
|
||||
read -r _
|
||||
done
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ addToGroup() {
|
|||
groups_to_add=$(echo "$groups" | tr ' ' ',')
|
||||
|
||||
printf "%b" "${YELLOW}Are you sure you want to add user $username to $groups_to_add? [Y/n]: ${RC}"
|
||||
read -r confirm
|
||||
read -r _
|
||||
confirmAction || exit 1
|
||||
|
||||
"$ESCALATION_TOOL" usermod -aG "$groups_to_add" "$username"
|
||||
|
|
|
@ -17,7 +17,7 @@ changePassword() {
|
|||
read -r password
|
||||
|
||||
printf "%b" "${YELLOW}Are you sure you want to change password for ""$username""? [Y/n]: ${RC}"
|
||||
read -r confirm
|
||||
read -r _
|
||||
confirmAction || exit 1
|
||||
|
||||
echo "$username:$password" | "$ESCALATION_TOOL" chpasswd
|
||||
|
|
|
@ -14,7 +14,7 @@ deleteUser() {
|
|||
|
||||
if id "$username" > /dev/null 2>&1; then
|
||||
printf "%b" "${YELLOW}Are you sure you want to delete user ""$username""? [Y/n]: ${RC}"
|
||||
read -r confirm
|
||||
read -r _
|
||||
confirmAction || exit 1
|
||||
|
||||
$ESCALATION_TOOL userdel --remove "$username" 2>/dev/null
|
||||
|
|
|
@ -34,10 +34,10 @@ removeFromGroup() {
|
|||
groups_to_remove=$(echo "$groups" | tr ' ' ',')
|
||||
|
||||
printf "%b" "${YELLOW}Are you sure you want to remove user $username from $groups_to_remove? [Y/n]: ${RC}"
|
||||
read -r confirm
|
||||
read -r _
|
||||
confirmAction || exit 1
|
||||
|
||||
$ESCALATION_TOOL usermod -rG $groups_to_remove "$username"
|
||||
$ESCALATION_TOOL usermod -rG "$groups_to_remove" "$username"
|
||||
|
||||
printf "%b\n" "${GREEN}User successfully removed from $groups_to_remove${RC}"
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ execute_command() {
|
|||
command="$1"
|
||||
printf "Executing: %s\n" "$command"
|
||||
eval "$command" 2>&1 | tee /tmp/xrandr.log | tail -n 20
|
||||
# shellcheck disable=SC2181
|
||||
if [ $? -ne 0 ]; then
|
||||
printf "%b\n" "${RED}An error occurred while executing the command. Check /tmp/xrandr.log for details.${RC}"
|
||||
fi
|
||||
|
|
|
@ -75,33 +75,33 @@ scan_networks() {
|
|||
echo "$networks" | awk -F: '{printf("%d. SSID: %-25s \n", NR, $1)}'
|
||||
fi
|
||||
printf "%b\n" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
}
|
||||
|
||||
# Function to turn WiFi on
|
||||
wifi_on() {
|
||||
clear
|
||||
printf "%b\n" "${YELLOW}Turning WiFi on...${RC}"
|
||||
nmcli radio wifi on && {
|
||||
if "$(nmcli radio wifi on)"; then
|
||||
printf "%b\n" "${GREEN}WiFi is now turned on.${RC}"
|
||||
} || {
|
||||
else
|
||||
printf "%b\n" "${RED}Failed to turn on WiFi.${RC}"
|
||||
}
|
||||
fi
|
||||
printf "%b\n" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
}
|
||||
|
||||
# Function to turn WiFi off
|
||||
wifi_off() {
|
||||
clear
|
||||
printf "%b\n" "${YELLOW}Turning WiFi off...${RC}"
|
||||
nmcli radio wifi off && {
|
||||
if "$(nmcli radio wifi off)"; then
|
||||
printf "%b\n" "${GREEN}WiFi is now turned off.${RC}"
|
||||
} || {
|
||||
else
|
||||
printf "%b\n" "${RED}Failed to turn off WiFi.${RC}"
|
||||
}
|
||||
fi
|
||||
printf "%b\n" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
}
|
||||
|
||||
# Function to prompt for WiFi network selection
|
||||
|
@ -118,7 +118,7 @@ prompt_for_network() {
|
|||
if [ -z "$networks" ]; then
|
||||
printf "%b\n" "${RED}No networks available. Please scan for networks first.${RC}"
|
||||
printf "%b\n" "Press any key to return to the main menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
rm -f "$temp_file"
|
||||
return
|
||||
fi
|
||||
|
@ -142,18 +142,18 @@ prompt_for_network() {
|
|||
printf "%b" "Enter password for SSID: " "$ssid"
|
||||
read -r password
|
||||
printf "\n"
|
||||
nmcli dev wifi connect "$ssid" password "$password" && {
|
||||
if "$(nmcli dev wifi connect "$ssid" password "$password")"; then
|
||||
printf "%b\n" "${GREEN}$success_msg${RC}"
|
||||
} || {
|
||||
else
|
||||
printf "%b\n" "${RED}$failure_msg${RC}"
|
||||
}
|
||||
fi
|
||||
fi
|
||||
else
|
||||
printf "%b\n" "${RED}Invalid choice. Please try again.${RC}"
|
||||
fi
|
||||
|
||||
printf "%b\n" "Press any key to return to the selection menu..."
|
||||
read -r dummy
|
||||
read -r _
|
||||
done
|
||||
|
||||
rm -f "$temp_file"
|
||||
|
|
1
rustfmt.toml
Normal file
1
rustfmt.toml
Normal file
|
@ -0,0 +1 @@
|
|||
imports_granularity = "Crate"
|
|
@ -8,8 +8,9 @@ RED='\033[0;31m'
|
|||
# Function to fetch the latest release tag from the GitHub API
|
||||
get_latest_release() {
|
||||
latest_release=$(curl -s https://api.github.com/repos/ChrisTitusTech/linutil/releases |
|
||||
grep -oP '"tag_name": "\K[^"]*' |
|
||||
head -n 1)
|
||||
grep "tag_name" |
|
||||
head -n 1 |
|
||||
sed -E 's/.*"tag_name": "([^"]+)".*/\1/')
|
||||
if [ -z "$latest_release" ]; then
|
||||
printf "%b\n" "Error fetching release data" >&2
|
||||
return 1
|
||||
|
|
35
tui/src/cli.rs
Normal file
35
tui/src/cli.rs
Normal file
|
@ -0,0 +1,35 @@
|
|||
use crate::theme::Theme;
|
||||
use clap::Parser;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Parser, Clone)]
|
||||
pub struct Args {
|
||||
/// Path to the configuration file
|
||||
#[arg(short, long)]
|
||||
pub config: Option<PathBuf>,
|
||||
|
||||
/// Set the theme to use in the application
|
||||
#[arg(short, long, value_enum)]
|
||||
#[arg(default_value_t = Theme::Default)]
|
||||
pub theme: Theme,
|
||||
|
||||
/// Skip confirmation prompt before executing commands
|
||||
#[arg(short = 'y', long)]
|
||||
pub skip_confirmation: bool,
|
||||
|
||||
/// Show all available options, disregarding compatibility checks (UNSAFE)
|
||||
#[arg(short = 'u', long)]
|
||||
pub override_validation: bool,
|
||||
|
||||
/// Bypass the terminal size limit
|
||||
#[arg(short = 's', long)]
|
||||
pub size_bypass: bool,
|
||||
|
||||
/// Enable mouse interaction
|
||||
#[arg(short = 'm', long)]
|
||||
pub mouse: bool,
|
||||
|
||||
/// Bypass root user check
|
||||
#[arg(short = 'r', long)]
|
||||
pub bypass_root: bool,
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{float::FloatContent, hint::Shortcut, theme};
|
||||
use crate::{float::FloatContent, hint::Shortcut, shortcuts, theme};
|
||||
use ratatui::{
|
||||
crossterm::event::{KeyCode, KeyEvent, MouseEvent, MouseEventKind},
|
||||
layout::Alignment,
|
||||
|
@ -135,13 +135,13 @@ impl FloatContent for ConfirmPrompt {
|
|||
fn get_shortcut_list(&self) -> (&str, Box<[Shortcut]>) {
|
||||
(
|
||||
"Confirmation prompt",
|
||||
Box::new([
|
||||
Shortcut::new("Continue", ["Y", "y"]),
|
||||
Shortcut::new("Abort", ["N", "n", "q", "Esc"]),
|
||||
Shortcut::new("Scroll up", ["k", "Up"]),
|
||||
Shortcut::new("Scroll down", ["j", "Down"]),
|
||||
Shortcut::new("Close linutil", ["CTRL-c"]),
|
||||
]),
|
||||
shortcuts!(
|
||||
("Continue", ["Y", "y"]),
|
||||
("Abort", ["N", "n", "q", "Esc"]),
|
||||
("Scroll up", ["k", "Up"]),
|
||||
("Scroll down", ["j", "Down"]),
|
||||
("Close linutil", ["CTRL-c"]),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{float::FloatContent, hint::Shortcut, theme::Theme};
|
||||
use crate::{float::FloatContent, hint::Shortcut, shortcuts, theme::Theme};
|
||||
use linutil_core::Command;
|
||||
use ratatui::{
|
||||
crossterm::event::{KeyCode, KeyEvent, MouseEvent, MouseEventKind},
|
||||
|
@ -228,13 +228,13 @@ impl FloatContent for FloatingText<'_> {
|
|||
fn get_shortcut_list(&self) -> (&str, Box<[Shortcut]>) {
|
||||
(
|
||||
&self.mode_title,
|
||||
Box::new([
|
||||
Shortcut::new("Scroll down", ["j", "Down"]),
|
||||
Shortcut::new("Scroll up", ["k", "Up"]),
|
||||
Shortcut::new("Scroll left", ["h", "Left"]),
|
||||
Shortcut::new("Scroll right", ["l", "Right"]),
|
||||
Shortcut::new("Close window", ["Enter", "p", "q", "d", "g"]),
|
||||
]),
|
||||
shortcuts!(
|
||||
("Scroll down", ["j", "Down"]),
|
||||
("Scroll up", ["k", "Up"]),
|
||||
("Scroll left", ["h", "Left"]),
|
||||
("Scroll right", ["l", "Right"]),
|
||||
("Close window", ["Enter", "p", "q", "d", "g"])
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,3 +78,14 @@ impl Shortcut {
|
|||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! shortcuts {
|
||||
($(($name:literal,[$($key:literal),+ $(,)?])),* $(,)?) => {
|
||||
vec![
|
||||
$(
|
||||
Shortcut::new($name, [$($key),*])
|
||||
),*
|
||||
].into_boxed_slice()
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod cli;
|
||||
mod confirmation;
|
||||
mod filter;
|
||||
mod float;
|
||||
|
@ -11,7 +12,7 @@ mod theme;
|
|||
#[cfg(feature = "tips")]
|
||||
mod tips;
|
||||
|
||||
use crate::theme::Theme;
|
||||
use crate::cli::Args;
|
||||
use clap::Parser;
|
||||
use ratatui::{
|
||||
backend::CrosstermBackend,
|
||||
|
@ -26,40 +27,17 @@ use ratatui::{
|
|||
use state::AppState;
|
||||
use std::{
|
||||
io::{stdout, Result, Stdout},
|
||||
path::PathBuf,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
// Linux utility toolbox
|
||||
#[derive(Debug, Parser)]
|
||||
pub struct Args {
|
||||
#[arg(short, long, help = "Path to the configuration file")]
|
||||
config: Option<PathBuf>,
|
||||
#[arg(short, long, value_enum)]
|
||||
#[arg(default_value_t = Theme::Default)]
|
||||
#[arg(help = "Set the theme to use in the application")]
|
||||
theme: Theme,
|
||||
#[arg(
|
||||
short = 'y',
|
||||
long,
|
||||
help = "Skip confirmation prompt before executing commands"
|
||||
)]
|
||||
skip_confirmation: bool,
|
||||
#[arg(long, default_value_t = false)]
|
||||
#[clap(help = "Show all available options, disregarding compatibility checks (UNSAFE)")]
|
||||
override_validation: bool,
|
||||
#[arg(long, default_value_t = false)]
|
||||
#[clap(help = "Bypass the terminal size limit")]
|
||||
size_bypass: bool,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
|
||||
let mut state = AppState::new(args);
|
||||
let mut state = AppState::new(args.clone());
|
||||
|
||||
stdout().execute(EnterAlternateScreen)?;
|
||||
if args.mouse {
|
||||
stdout().execute(EnableMouseCapture)?;
|
||||
}
|
||||
|
||||
enable_raw_mode()?;
|
||||
let mut terminal = Terminal::new(CrosstermBackend::new(stdout()))?;
|
||||
|
@ -70,7 +48,9 @@ fn main() -> Result<()> {
|
|||
// restore terminal
|
||||
disable_raw_mode()?;
|
||||
terminal.backend_mut().execute(LeaveAlternateScreen)?;
|
||||
if args.mouse {
|
||||
terminal.backend_mut().execute(DisableMouseCapture)?;
|
||||
}
|
||||
terminal.backend_mut().execute(ResetColor)?;
|
||||
terminal.show_cursor()?;
|
||||
|
||||
|
|
|
@ -8,8 +8,12 @@ This means you have full system access and commands can potentially damage your
|
|||
Please proceed with caution and make sure you understand what each script does before executing it.";
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn check_root_status<'a>() -> Option<FloatingText<'a>> {
|
||||
(Uid::effective().is_root()).then_some(FloatingText::new(
|
||||
pub fn check_root_status(bypass_root: bool) -> Option<FloatingText<'static>> {
|
||||
if bypass_root {
|
||||
return None;
|
||||
}
|
||||
|
||||
Uid::effective().is_root().then_some(FloatingText::new(
|
||||
ROOT_WARNING.into(),
|
||||
"Root User Warning",
|
||||
true,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{float::FloatContent, hint::Shortcut, theme::Theme};
|
||||
use crate::{float::FloatContent, hint::Shortcut, shortcuts, theme::Theme};
|
||||
use linutil_core::Command;
|
||||
use oneshot::{channel, Receiver};
|
||||
use portable_pty::{
|
||||
|
@ -139,21 +139,21 @@ impl FloatContent for RunningCommand {
|
|||
if self.is_finished() {
|
||||
(
|
||||
"Finished command",
|
||||
Box::new([
|
||||
Shortcut::new("Close window", ["Enter", "q"]),
|
||||
Shortcut::new("Scroll up", ["Page up"]),
|
||||
Shortcut::new("Scroll down", ["Page down"]),
|
||||
Shortcut::new("Save log", ["l"]),
|
||||
]),
|
||||
shortcuts!(
|
||||
("Close window", ["Enter", "q"]),
|
||||
("Scroll up", ["Page up"]),
|
||||
("Scroll down", ["Page down"]),
|
||||
("Save log", ["l"]),
|
||||
),
|
||||
)
|
||||
} else {
|
||||
(
|
||||
"Running command",
|
||||
Box::new([
|
||||
Shortcut::new("Kill the command", ["CTRL-c"]),
|
||||
Shortcut::new("Scroll up", ["Page up"]),
|
||||
Shortcut::new("Scroll down", ["Page down"]),
|
||||
]),
|
||||
shortcuts!(
|
||||
("Kill the command", ["CTRL-c"]),
|
||||
("Scroll up", ["Page up"]),
|
||||
("Scroll down", ["Page down"]),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
117
tui/src/state.rs
117
tui/src/state.rs
|
@ -6,6 +6,7 @@ use crate::{
|
|||
hint::{create_shortcut_list, Shortcut},
|
||||
root::check_root_status,
|
||||
running_command::RunningCommand,
|
||||
shortcuts,
|
||||
theme::Theme,
|
||||
Args,
|
||||
};
|
||||
|
@ -65,6 +66,7 @@ pub struct AppState {
|
|||
tip: &'static str,
|
||||
size_bypass: bool,
|
||||
skip_confirmation: bool,
|
||||
mouse_enabled: bool,
|
||||
}
|
||||
|
||||
pub enum Focus {
|
||||
|
@ -93,8 +95,18 @@ enum SelectedItem {
|
|||
None,
|
||||
}
|
||||
|
||||
enum ScrollDir {
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(args: Args) -> Self {
|
||||
#[cfg(unix)]
|
||||
let root_warning = check_root_status(args.bypass_root);
|
||||
#[cfg(not(unix))]
|
||||
let root_warning = None;
|
||||
|
||||
let tabs = linutil_core::get_tabs(!args.override_validation);
|
||||
let root_id = tabs[0].tree.root().id();
|
||||
|
||||
|
@ -121,10 +133,11 @@ impl AppState {
|
|||
tip: crate::tips::get_random_tip(),
|
||||
size_bypass: args.size_bypass,
|
||||
skip_confirmation: args.skip_confirmation,
|
||||
mouse_enabled: args.mouse,
|
||||
};
|
||||
|
||||
#[cfg(unix)]
|
||||
if let Some(root_warning) = check_root_status() {
|
||||
if let Some(root_warning) = root_warning {
|
||||
state.spawn_float(root_warning, FLOAT_SIZE, FLOAT_SIZE);
|
||||
}
|
||||
|
||||
|
@ -171,13 +184,13 @@ impl AppState {
|
|||
|
||||
fn get_list_item_shortcut(&self) -> Box<[Shortcut]> {
|
||||
if self.selected_item_is_dir() {
|
||||
Box::new([Shortcut::new("Go to selected dir", ["l", "Right", "Enter"])])
|
||||
shortcuts!(("Go to selected dir", ["l", "Right", "Enter"]))
|
||||
} else {
|
||||
Box::new([
|
||||
Shortcut::new("Run selected command", ["l", "Right", "Enter"]),
|
||||
Shortcut::new("Enable preview", ["p"]),
|
||||
Shortcut::new("Command Description", ["d"]),
|
||||
])
|
||||
shortcuts!(
|
||||
("Run selected command", ["l", "Right", "Enter"]),
|
||||
("Enable preview", ["p"]),
|
||||
("Command Description", ["d"])
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -185,10 +198,7 @@ impl AppState {
|
|||
match self.focus {
|
||||
Focus::Search => (
|
||||
"Search bar",
|
||||
Box::new([
|
||||
Shortcut::new("Abort search", ["Esc", "CTRL-c"]),
|
||||
Shortcut::new("Search", ["Enter"]),
|
||||
]),
|
||||
shortcuts!(("Abort search", ["Esc", "CTRL-c"]), ("Search", ["Enter"])),
|
||||
),
|
||||
|
||||
Focus::List => {
|
||||
|
@ -208,35 +218,39 @@ impl AppState {
|
|||
hints.extend(self.get_list_item_shortcut());
|
||||
}
|
||||
|
||||
hints.push(Shortcut::new("Select item above", ["k", "Up"]));
|
||||
hints.push(Shortcut::new("Select item below", ["j", "Down"]));
|
||||
hints.push(Shortcut::new("Next theme", ["t"]));
|
||||
hints.push(Shortcut::new("Previous theme", ["T"]));
|
||||
hints.push(Shortcut::new("Multi-selection mode", ["v"]));
|
||||
hints.extend(shortcuts!(
|
||||
("Select item above", ["k", "Up"]),
|
||||
("Select item below", ["j", "Down"]),
|
||||
("Next theme", ["t"]),
|
||||
("Previous theme", ["T"]),
|
||||
("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"]));
|
||||
hints.extend(shortcuts!(
|
||||
("Next tab", ["Tab"]),
|
||||
("Previous tab", ["Shift-Tab"]),
|
||||
("Important actions guide", ["g"])
|
||||
));
|
||||
|
||||
("Command list", hints.into_boxed_slice())
|
||||
}
|
||||
|
||||
Focus::TabList => (
|
||||
"Tab list",
|
||||
Box::new([
|
||||
Shortcut::new("Exit linutil", ["q", "CTRL-c"]),
|
||||
Shortcut::new("Focus action list", ["l", "Right", "Enter"]),
|
||||
Shortcut::new("Select item above", ["k", "Up"]),
|
||||
Shortcut::new("Select item below", ["j", "Down"]),
|
||||
Shortcut::new("Next theme", ["t"]),
|
||||
Shortcut::new("Previous theme", ["T"]),
|
||||
Shortcut::new("Next tab", ["Tab"]),
|
||||
Shortcut::new("Previous tab", ["Shift-Tab"]),
|
||||
Shortcut::new("Important actions guide", ["g"]),
|
||||
Shortcut::new("Multi-selection mode", ["v"]),
|
||||
]),
|
||||
shortcuts!(
|
||||
("Exit linutil", ["q", "CTRL-c"]),
|
||||
("Focus action list", ["l", "Right", "Enter"]),
|
||||
("Select item above", ["k", "Up"]),
|
||||
("Select item below", ["j", "Down"]),
|
||||
("Next theme", ["t"]),
|
||||
("Previous theme", ["T"]),
|
||||
("Next tab", ["Tab"]),
|
||||
("Previous tab", ["Shift-Tab"]),
|
||||
("Important actions guide", ["g"]),
|
||||
("Multi-selection mode", ["v"]),
|
||||
),
|
||||
),
|
||||
|
||||
Focus::FloatingWindow(ref float) => float.get_shortcut_list(),
|
||||
|
@ -438,6 +452,10 @@ impl AppState {
|
|||
}
|
||||
|
||||
pub fn handle_mouse(&mut self, event: &MouseEvent) -> bool {
|
||||
if !self.mouse_enabled {
|
||||
return true;
|
||||
}
|
||||
|
||||
if !self.drawable {
|
||||
return true;
|
||||
}
|
||||
|
@ -595,24 +613,35 @@ impl AppState {
|
|||
true
|
||||
}
|
||||
|
||||
fn scroll_down(&mut self) {
|
||||
if let Some(selected) = self.selection.selected() {
|
||||
if selected == self.filter.item_list().len() - 1 {
|
||||
self.selection.select_first();
|
||||
fn scroll(&mut self, direction: ScrollDir) {
|
||||
let Some(selected) = self.selection.selected() else {
|
||||
return;
|
||||
};
|
||||
let list_len = if !self.at_root() {
|
||||
self.filter.item_list().len() + 1
|
||||
} else {
|
||||
self.selection.select_next();
|
||||
}
|
||||
}
|
||||
self.filter.item_list().len()
|
||||
};
|
||||
|
||||
if list_len == 0 {
|
||||
return;
|
||||
};
|
||||
|
||||
let next_selection = match direction {
|
||||
ScrollDir::Up if selected == 0 => list_len - 1,
|
||||
ScrollDir::Down if selected >= list_len - 1 => 0,
|
||||
ScrollDir::Up => selected - 1,
|
||||
ScrollDir::Down => selected + 1,
|
||||
};
|
||||
self.selection.select(Some(next_selection));
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self) {
|
||||
if let Some(selected) = self.selection.selected() {
|
||||
if selected == 0 {
|
||||
self.selection.select_last();
|
||||
} else {
|
||||
self.selection.select_previous();
|
||||
}
|
||||
self.scroll(ScrollDir::Up)
|
||||
}
|
||||
|
||||
fn scroll_down(&mut self) {
|
||||
self.scroll(ScrollDir::Down)
|
||||
}
|
||||
|
||||
fn toggle_multi_select(&mut self) {
|
||||
|
|
|
@ -2,8 +2,7 @@ use std::fs;
|
|||
|
||||
use linutil_core::Command;
|
||||
|
||||
use crate::path;
|
||||
use crate::DynError;
|
||||
use crate::{path, DynError};
|
||||
|
||||
pub const USER_GUIDE: &str = "userguide.md";
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ use std::{env, error::Error};
|
|||
type DynError = Box<dyn Error>;
|
||||
|
||||
pub mod tasks {
|
||||
use crate::docgen::USER_GUIDE;
|
||||
use crate::docgen::{userguide, write};
|
||||
use crate::DynError;
|
||||
use crate::{
|
||||
docgen::{userguide, write, USER_GUIDE},
|
||||
DynError,
|
||||
};
|
||||
|
||||
pub fn docgen() -> Result<(), DynError> {
|
||||
write(USER_GUIDE, &userguide()?);
|
||||
|
|
Loading…
Reference in New Issue
Block a user