diff --git a/.github/workflows/bashisms.yml b/.github/workflows/bashisms.yml index 7ce39ef1..ffbe983b 100644 --- a/.github/workflows/bashisms.yml +++ b/.github/workflows/bashisms.yml @@ -3,7 +3,7 @@ name: Check for bashisms on: pull_request: paths: - - core/tabs/** + - 'core/tabs/**/*.sh' merge_group: workflow_dispatch: @@ -15,31 +15,33 @@ jobs: - uses: actions/checkout@v4 - run: git fetch origin ${{ github.base_ref }} - - name: Get a list of changed script files - id: get_sh_files - run: | - sh_files=$(git diff --name-only origin/${{ github.base_ref }} HEAD core/tabs | grep '\.sh$' || true) - if [ -n "$sh_files" ]; then - echo "$sh_files" > changed_files - echo "changed=1" >> $GITHUB_OUTPUT - else - echo "changed=0" >> $GITHUB_OUTPUT - fi - - name: Install devscripts - if: steps.get_sh_files.outputs.changed == 1 - run: sudo apt-get update && sudo apt-get install devscripts + run: sudo apt-get update && sudo apt-get install -y devscripts + + - name: Get changed .sh files (PR only) + id: changed-sh-files + if: github.event_name == 'pull_request' + uses: tj-actions/changed-files@v45 + with: + files: '**/*.sh' + + - name: Get all .sh files (if workflow dispatched) + id: sh-files + if: github.event_name != 'pull_request' + run: | + files=$(find . -type f -name "*.sh" | tr '\n' ' ') + echo "files=${files:-none}" >> $GITHUB_ENV + + - name: Set FILES for bashism check + id: set-files + run: | + if [[ "${{ steps.changed-sh-files.outputs.any_changed }}" == 'true' ]]; then + echo "FILES=${{ steps.changed-sh-files.outputs.all_changed_files }}" >> $GITHUB_ENV + else + echo "FILES=${{ env.files }}" >> $GITHUB_ENV + fi - name: Check for bashisms - if: steps.get_sh_files.outputs.changed == 1 run: | - echo "Running for:\n$(cat changed_files)\n" - for file in $(cat changed_files); do - if [[ -f "$file" ]]; then - checkbashisms "$file" - fi - done - - - name: Remove the created file - if: steps.get_sh_files.outputs.changed == 1 - run: rm changed_files + IFS=' ' read -r -a file_array <<< "$FILES" + checkbashisms "${file_array[@]}" diff --git a/.github/workflows/github-pages.yml b/.github/workflows/github-pages.yml index 30e992d4..94ca5e3c 100644 --- a/.github/workflows/github-pages.yml +++ b/.github/workflows/github-pages.yml @@ -13,6 +13,10 @@ on: jobs: build-and-deploy: runs-on: ubuntu-latest + environment: linutil_env + permissions: + contents: write + pull-requests: write steps: - name: Checkout Repository @@ -24,11 +28,17 @@ jobs: run: | echo -e "\n\n$(cat .github/CONTRIBUTING.md)" > 'docs/contributing.md' - - uses: stefanzweifel/git-auto-commit-action@v5 + - name: Create Pull Request + uses: peter-evans/create-pull-request@v6 with: - commit_message: Commit Contributing Guidelines - file_pattern: "docs/contributing.md" - add_options: '--force' + commit-message: Update Contributing Guidelines + title: 'docs: Update Contributing Guidelines' + body: 'Automated update of Contributing Guidelines from .github/CONTRIBUTING.md' + branch: update-contributing-guidelines + delete-branch: true + base: main + labels: documentation + token: ${{ secrets.PAT_TOKEN }} if: success() - name: Setup Python diff --git a/.github/workflows/linutil.yml b/.github/workflows/linutil.yml index 53c43d02..187f1e54 100644 --- a/.github/workflows/linutil.yml +++ b/.github/workflows/linutil.yml @@ -46,19 +46,9 @@ jobs: run: cargo build --target-dir=build --release --verbose --target=x86_64-unknown-linux-musl --all-features - name: Build aarch64 binary - run: cross build --target-dir=build --release --verbose --target=aarch64-unknown-linux-musl --all-features - - - name: Move binaries to build directory run: | - mv build/x86_64-unknown-linux-musl/release/linutil build/linutil - mv build/aarch64-unknown-linux-musl/release/linutil build/linutil-aarch64 - - - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Commit Linutil - file_pattern: "build/linutil build/linutil-aarch64" - add_options: '--force' - if: success() + cross build --target-dir=build --release --verbose --target=aarch64-unknown-linux-musl --all-features + mv ./build/aarch64-unknown-linux-musl/release/linutil ./build/aarch64-unknown-linux-musl/release/linutil-aarch64 - name: Extract Version id: extract_version @@ -80,32 +70,11 @@ jobs: append_body: true generate_release_notes: true files: | - ./build/linutil - ./build/linutil-aarch64 + ./build/x86_64-unknown-linux-musl/release/linutil + ./build/aarch64-unknown-linux-musl/release/linutil-aarch64 ./start.sh ./startdev.sh prerelease: true env: version: ${{ env.version }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Setup Preview - run: | - echo "$(pwd)/build" >> $GITHUB_PATH - - - name: Generate preview - uses: charmbracelet/vhs-action@v2.1.0 - with: - path: "docs/assets/preview.tape" - - - name: Move preview - run: | - mv preview.gif docs/assets/preview.gif - - - name: Upload preview - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Preview for ${{ env.version }} - file_pattern: "docs/assets/preview.gif" - add_options: "--force" - if: success() \ No newline at end of file diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 00000000..4967eeef --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,78 @@ +name: LinUtil Preview + +on: + workflow_dispatch: + inputs: + tag_name: + description: 'Tag name' + required: true + workflow_run: + workflows: ["LinUtil Release"] + types: + - completed + +jobs: + generate_preview: + runs-on: ubuntu-latest + environment: linutil_env + permissions: + contents: write + pull-requests: write + + steps: + - name: Checkout source + uses: actions/checkout@v4 + + - name: Get tag name ( Workflow Run ) + id: latest_tag + uses: actions/github-script@v7 + if: github.event_name == 'workflow_run' + with: + script: | + const releases = await github.rest.repos.listReleases({ + owner: context.repo.owner, + repo: context.repo.repo, + per_page: 1 + }); + core.setOutput('result', releases.data[0].tag_name); + result-encoding: string + + - name: Set tag name ( Workflow Run ) + if: github.event_name == 'workflow_run' + run: echo "tag_name=${{ steps.latest_tag.outputs.result }}" >> $GITHUB_ENV + + - name: Set tag name ( Workflow Dispatch ) + if: ${{ github.event_name }} == 'workflow_dispatch' + run: echo "tag_name=${{ github.event.inputs.tag_name }}" >> $GITHUB_ENV + + - name: Download binary + run: | + curl -LO "https://github.com/${{ github.repository }}/releases/download/${{ env.tag_name }}/linutil" + + - name: Set env + run: | + chmod +x linutil + mkdir -p build + mv linutil build/linutil + echo "${{ github.workspace }}/build" >> $GITHUB_PATH + + - name: Generate preview + uses: charmbracelet/vhs-action@v2.1.0 + with: + path: "docs/assets/preview.tape" + + - name: Move preview + run: mv preview.gif docs/assets/preview.gif + + - name: Create PR + uses: peter-evans/create-pull-request@v7.0.5 + with: + commit-message: Preview for ${{ env.tag_name }} + file-pattern: "docs/assets/preview.gif" + add-options: "--force" + token: ${{ secrets.PAT_TOKEN }} + branch: feature/preview-${{ env.tag_name }} + title: "Update preview for ${{ env.tag_name }}" + body: | + Automated PR to update preview gif for version ${{ env.tag_name }} + if: success() diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 854e9451..bfcc3bc8 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -17,6 +17,7 @@ jobs: - name: Run ShellCheck uses: reviewdog/action-shellcheck@v1 with: + shellcheck_flags: '--source-path=${{ github.workspace }}/.shellcheckrc' reviewdog_flags: '-fail-level=any' shfmt: diff --git a/.github/workflows/typos.yml b/.github/workflows/typos.yml index 901d5e71..864dfc3b 100644 --- a/.github/workflows/typos.yml +++ b/.github/workflows/typos.yml @@ -12,4 +12,4 @@ jobs: - run: git fetch origin ${{ github.base_ref }} - name: Run spellcheck - uses: crate-ci/typos@v1.25.0 + uses: crate-ci/typos@v1.26.0 diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 00000000..0b882066 --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,2 @@ +external-sources=true +source=core/tabs/common-script.sh \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 266ed837..fc49af4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -29,26 +29,11 @@ version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - [[package]] name = "ansi-to-tui" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c4af0bef1b514c9b6a32a773caf604c1390fa7913f4eaa23bfe76f251d6a42" +checksum = "67555e1f1ece39d737e28c8a017721287753af3f93225e4a445b29ccb0f5912c" dependencies = [ "nom", "ratatui", @@ -136,12 +121,6 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - [[package]] name = "byteorder" version = "1.5.0" @@ -178,25 +157,11 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "wasm-bindgen", - "windows-targets", -] - [[package]] name = "clap" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" dependencies = [ "clap_builder", "clap_derive", @@ -204,9 +169,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.19" +version = "4.5.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" dependencies = [ "anstream", "anstyle", @@ -252,12 +217,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - [[package]] name = "crossterm" version = "0.28.1" @@ -370,29 +329,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "iana-time-zone" -version = "0.1.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - [[package]] name = "include_dir" version = "0.7.4" @@ -422,6 +358,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + [[package]] name = "instability" version = "0.3.2" @@ -462,15 +404,6 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" -[[package]] -name = "js-sys" -version = "0.3.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" -dependencies = [ - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -501,7 +434,6 @@ version = "24.9.28" dependencies = [ "ansi-to-tui", "anstyle", - "chrono", "clap", "crossterm", "ego-tree", @@ -607,15 +539,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.19.0" @@ -743,23 +666,23 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" dependencies = [ "bitflags 2.6.0", "cassowary", "compact_str", "crossterm", + "indoc", "instability", "itertools", "lru", "paste", "strum", - "strum_macros", "unicode-segmentation", "unicode-truncate", - "unicode-width 0.1.14", + "unicode-width 0.2.0", ] [[package]] @@ -1088,9 +1011,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b84f60031bf8245b563a80c92c1034e557a914f7958f474bc0afa2eed78b98" +checksum = "f9871f16d6cf5c4757dcf30d5d2172a2df6987c510c017bbb7abfb7f9aa24d06" dependencies = [ "cc", "regex", @@ -1111,9 +1034,9 @@ dependencies = [ [[package]] name = "tree-sitter-highlight" -version = "0.24.2" +version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c727fb31f816c09fc54dc0e971d101318926866f7261b2acb820e84a61bf52d" +checksum = "48859aa39513716018d81904220960f415dbb72e071234a721304d20bf245e4c" dependencies = [ "lazy_static", "regex", @@ -1130,9 +1053,9 @@ checksum = "2545046bd1473dac6c626659cc2567c6c0ff302fc8b84a56c4243378276f7f57" [[package]] name = "tui-term" -version = "0.1.13" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07f0233f0d4795d2dc6663cfc3ce56b87bebcee66d6bcc088aa6aff5c072361" +checksum = "72af159125ce32b02ceaced6cffae6394b0e6b6dfd4dc164a6c59a2db9b3c0b0" dependencies = [ "ratatui", "vt100", @@ -1223,61 +1146,6 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" -[[package]] -name = "wasm-bindgen" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" - [[package]] name = "which" version = "6.0.3" @@ -1312,15 +1180,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-sys" version = "0.52.0" diff --git a/core/tabs/applications-setup/Developer-tools/jetbrains-toolbox.sh b/core/tabs/applications-setup/Developer-tools/jetbrains-toolbox.sh new file mode 100644 index 00000000..79ce360e --- /dev/null +++ b/core/tabs/applications-setup/Developer-tools/jetbrains-toolbox.sh @@ -0,0 +1,48 @@ +#!/bin/sh -e + +. ../../common-script.sh + +manualInstall() { + JETBRAINS_TOOLBOX_DIR="/opt/jetbrains-toolbox" + + case "$ARCH" in + x86_64) ARCHIVE_URL=$(curl -s "https://data.services.jetbrains.com/products/releases?code=TBA&latest=true&type=release" | jq -r ".TBA[0].downloads.linux.link") ;; + aarch64) ARCHIVE_URL=$(curl -s "https://data.services.jetbrains.com/products/releases?code=TBA&latest=true&type=release" | jq -r ".TBA[0].downloads.linuxARM64.link") ;; + esac + + curl -fSL "$ARCHIVE_URL" -o "jetbrains-toolbox.tar.gz" + + if [ -d "$JETBRAINS_TOOLBOX_DIR" ]; then + "$ESCALATION_TOOL" rm -rf "$JETBRAINS_TOOLBOX_DIR" + fi + + "$ESCALATION_TOOL" mkdir -p "$JETBRAINS_TOOLBOX_DIR" + "$ESCALATION_TOOL" tar -xzf "jetbrains-toolbox.tar.gz" -C "$JETBRAINS_TOOLBOX_DIR" --strip-components=1 + "$ESCALATION_TOOL" ln -sf "$JETBRAINS_TOOLBOX_DIR/jetbrains-toolbox" "/usr/bin/jetbrains-toolbox" +} + +installJetBrainsToolBox() { + if ! command_exists jetbrains-toolbox; then + printf "%b\n" "${YELLOW}Installing Jetbrains Toolbox...${RC}" + case "$PACKAGER" in + pacman) + "$AUR_HELPER" -S --needed --noconfirm jetbrains-toolbox + ;; + dnf) + manualInstall + ;; + *) + "$ESCALATION_TOOL" "$PACKAGER" install -y libfuse2 + manualInstall + ;; + esac + printf "%b\n" "${GREEN}Successfully installed Jetbrains Toolbox.${RC}" + else + printf "%b\n" "${GREEN}Jetbrains toolbox is already installed.${RC}" + fi +} + +checkEnv +checkEscalationTool +checkAURHelper +installJetBrainsToolBox diff --git a/core/tabs/applications-setup/Developer-tools/meld-setup.sh b/core/tabs/applications-setup/Developer-tools/meld-setup.sh index 86a909ec..36c1cfe4 100644 --- a/core/tabs/applications-setup/Developer-tools/meld-setup.sh +++ b/core/tabs/applications-setup/Developer-tools/meld-setup.sh @@ -3,7 +3,7 @@ . ../../common-script.sh installMeld() { - if ! command_exists meld; then + if ! command_exists org.gnome.meld && ! command_exists meld; then printf "%b\n" "${YELLOW}Installing Meld...${RC}" case "$PACKAGER" in pacman) @@ -16,7 +16,7 @@ installMeld() { "$ESCALATION_TOOL" "$PACKAGER" add meld ;; *) - . ../setup-flatpak.sh + checkFlatpak flatpak install -y flathub org.gnome.meld ;; esac diff --git a/core/tabs/applications-setup/bottles-setup.sh b/core/tabs/applications-setup/bottles-setup.sh index 02fef60b..0b29bedb 100755 --- a/core/tabs/applications-setup/bottles-setup.sh +++ b/core/tabs/applications-setup/bottles-setup.sh @@ -3,14 +3,9 @@ . ../common-script.sh installBottles() { - if ! command_exists flatpak; then - printf "%b\n" "${YELLOW}Installing Bottles...${RC}" - case "$PACKAGER" in - *) - . ./setup-flatpak.sh - flatpak install -y flathub com.usebottles.bottles - ;; - esac + if ! command_exists com.usebottles.bottles; then + printf "%b\n" "${YELLOW}Installing Bottles...${RC}" + flatpak install -y flathub com.usebottles.bottles else printf "%b\n" "${GREEN}Bottles is already installed.${RC}" fi @@ -18,4 +13,5 @@ installBottles() { checkEnv checkEscalationTool +checkFlatpak installBottles \ No newline at end of file diff --git a/core/tabs/applications-setup/browsers/vivaldi.sh b/core/tabs/applications-setup/browsers/vivaldi.sh index 002ff7e3..311816d0 100644 --- a/core/tabs/applications-setup/browsers/vivaldi.sh +++ b/core/tabs/applications-setup/browsers/vivaldi.sh @@ -2,22 +2,39 @@ . ../../common-script.sh -installLynx() { - if ! command_exists lynx; then - printf "%b\n" "${YELLOW}Installing Lynx...${RC}" +installVivaldi() { + if ! command_exists vivaldi; then + printf "%b\n" "${YELLOW}Installing Vivaldi...${RC}" case "$PACKAGER" in + apt-get|nala) + "$ESCALATION_TOOL" "$PACKAGER" install -y curl + "$ESCALATION_TOOL" curl -fsSL https://repo.vivaldi.com/archive/linux_signing_key.pub | gpg --dearmor | sudo dd of=/usr/share/keyrings/vivaldi-browser.gpg + "$ESCALATION_TOOL" echo "deb [signed-by=/usr/share/keyrings/vivaldi-browser.gpg arch=$(dpkg --print-architecture)] https://repo.vivaldi.com/archive/deb/ stable main" | sudo dd of=/etc/apt/sources.list.d/vivaldi-archive.list + "$ESCALATION_TOOL" "$PACKAGER" update + "$ESCALATION_TOOL" "$PACKAGER" install -y vivaldi-stable + ;; + dnf) + "$ESCALATION_TOOL" "$PACKAGER" install -y dnf-plugins-core + "$ESCALATION_TOOL" "$PACKAGER" config-manager --add-repo https://repo.vivaldi.com/stable/vivaldi-fedora.repo + "$ESCALATION_TOOL" "$PACKAGER" install -y vivaldi-stable + ;; + zypper) + "$ESCALATION_TOOL" zypper ar https://repo.vivaldi.com/archive/vivaldi-suse.repo + "$ESCALATION_TOOL" zypper --non-interactive --gpg-auto-import-keys in vivaldi-stable + ;; pacman) - "$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm lynx + "$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm vivaldi ;; *) - "$ESCALATION_TOOL" "$PACKAGER" install -y lynx + printf "%b\n" "${RED}Unsupported package manager: ""$PACKAGER""${RC}" + exit 1 ;; esac else - printf "%b\n" "${GREEN}Lynx TUI Browser is already installed.${RC}" + printf "%b\n" "${GREEN}Vivaldi Browser is already installed.${RC}" fi } checkEnv checkEscalationTool -installLynx \ No newline at end of file +installVivaldi diff --git a/core/tabs/applications-setup/communication-apps/signal-setup.sh b/core/tabs/applications-setup/communication-apps/signal-setup.sh index d7915152..18c462b1 100644 --- a/core/tabs/applications-setup/communication-apps/signal-setup.sh +++ b/core/tabs/applications-setup/communication-apps/signal-setup.sh @@ -20,8 +20,8 @@ installSignal() { "$ESCALATION_TOOL" "$PACKAGER" -S --noconfirm signal-desktop ;; dnf) - "$ESCALATION_TOOL" "$PACKAGER" copr enable luminoso/Signal-Desktop - "$ESCALATION_TOOL" "$PACKAGER" install -y signal-desktop + checkFlatpak + flatpak install -y flathub org.signal.Signal ;; apk) checkFlatpak diff --git a/core/tabs/applications-setup/communication-apps/slack-setup.sh b/core/tabs/applications-setup/communication-apps/slack-setup.sh index e4bf3719..24d6e532 100644 --- a/core/tabs/applications-setup/communication-apps/slack-setup.sh +++ b/core/tabs/applications-setup/communication-apps/slack-setup.sh @@ -3,14 +3,14 @@ . ../../common-script.sh installSlack() { - if ! command_exists slack; then + if ! command_exists com.slack.Slack && ! command_exists slack; then printf "%b\n" "${YELLOW}Installing Slack...${RC}" case "$PACKAGER" in pacman) "$AUR_HELPER" -S --needed --noconfirm slack-desktop ;; *) - . ../setup-flatpak.sh + checkFlatpak flatpak install -y flathub com.slack.Slack ;; esac diff --git a/core/tabs/applications-setup/communication-apps/zoom-setup.sh b/core/tabs/applications-setup/communication-apps/zoom-setup.sh index acd5b180..19d7e407 100644 --- a/core/tabs/applications-setup/communication-apps/zoom-setup.sh +++ b/core/tabs/applications-setup/communication-apps/zoom-setup.sh @@ -3,14 +3,14 @@ . ../../common-script.sh installZoom() { - if ! command_exists zoom; then + if ! command_exists us.zoom.Zoom && ! command_exists zoom; then printf "%b\n" "${YELLOW}Installing Zoom...${RC}" case "$PACKAGER" in pacman) "$AUR_HELPER" -S --needed --noconfirm zoom ;; *) - . ../setup-flatpak.sh + checkFlatpak flatpak install -y flathub us.zoom.Zoom ;; esac diff --git a/core/tabs/applications-setup/docker-setup.sh b/core/tabs/applications-setup/docker-setup.sh index 74aa4983..c4fc53ff 100755 --- a/core/tabs/applications-setup/docker-setup.sh +++ b/core/tabs/applications-setup/docker-setup.sh @@ -26,6 +26,12 @@ install_docker() { apt-get|nala) curl -fsSL https://get.docker.com | sh ;; + dnf) + "$ESCALATION_TOOL" "$PACKAGER" -y install dnf-plugins-core + "$ESCALATION_TOOL" "$PACKAGER" config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo + "$ESCALATION_TOOL" "$PACKAGER" -y install docker-ce docker-ce-cli containerd.io docker-buildx-plugin + "$ESCALATION_TOOL" systemctl enable --now docker + ;; zypper) "$ESCALATION_TOOL" "$PACKAGER" --non-interactive install docker ;; @@ -50,6 +56,11 @@ install_docker_compose() { apt-get|nala) "$ESCALATION_TOOL" "$PACKAGER" install -y docker-compose-plugin ;; + dnf) + "$ESCALATION_TOOL" "$PACKAGER" -y install dnf-plugins-core + "$ESCALATION_TOOL" "$PACKAGER" config-manager --add-repo https://download.docker.com/linux/fedora/docker-ce.repo + "$ESCALATION_TOOL" "$PACKAGER" install -y docker-compose-plugin + ;; zypper) "$ESCALATION_TOOL" "$PACKAGER" --non-interactive install docker-compose ;; diff --git a/core/tabs/applications-setup/office-suites/libreoffice.sh b/core/tabs/applications-setup/office-suites/libreoffice.sh index 3b5f9900..a55bd183 100644 --- a/core/tabs/applications-setup/office-suites/libreoffice.sh +++ b/core/tabs/applications-setup/office-suites/libreoffice.sh @@ -3,14 +3,14 @@ . ../../common-script.sh installLibreOffice() { - if ! command_exists libreoffice; then + if ! command_exists org.libreoffice.LibreOffice && ! 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 + checkFlatpak flatpak install -y flathub org.libreoffice.LibreOffice ;; pacman) diff --git a/core/tabs/applications-setup/office-suites/onlyoffice.sh b/core/tabs/applications-setup/office-suites/onlyoffice.sh index 9e80fd31..f6fb97f6 100644 --- a/core/tabs/applications-setup/office-suites/onlyoffice.sh +++ b/core/tabs/applications-setup/office-suites/onlyoffice.sh @@ -3,7 +3,7 @@ . ../../common-script.sh installOnlyOffice() { - if ! command_exists onlyoffice-desktopeditors; then + if ! command_exists org.onlyoffice.desktopeditors && ! command_exists onlyoffice-desktopeditors; then printf "%b\n" "${YELLOW}Installing Only Office..${RC}." case "$PACKAGER" in apt-get|nala) @@ -11,7 +11,7 @@ installOnlyOffice() { "$ESCALATION_TOOL" "$PACKAGER" install -y ./onlyoffice-desktopeditors_amd64.deb ;; zypper|dnf) - . ./setup-flatpak.sh + checkFlatpak flatpak install -y flathub org.onlyoffice.desktopeditors ;; pacman) diff --git a/core/tabs/applications-setup/office-suites/wpsoffice.sh b/core/tabs/applications-setup/office-suites/wpsoffice.sh index 5e75e800..4ce1f5c5 100644 --- a/core/tabs/applications-setup/office-suites/wpsoffice.sh +++ b/core/tabs/applications-setup/office-suites/wpsoffice.sh @@ -3,14 +3,14 @@ . ../../common-script.sh installWpsOffice() { - if ! command_exists com.wps.Office; then + if ! command_exists com.wps.Office && ! command_exists wps; then printf "%b\n" "${YELLOW}Installing WPS Office...${RC}" case "$PACKAGER" in pacman) "$AUR_HELPER" -S --needed --noconfirm wps-office ;; *) - . ./setup-flatpak.sh + checkFlatpak flatpak install flathub com.wps.Office ;; esac diff --git a/core/tabs/applications-setup/setup-flatpak.sh b/core/tabs/applications-setup/setup-flatpak.sh index 75da28af..379467a6 100755 --- a/core/tabs/applications-setup/setup-flatpak.sh +++ b/core/tabs/applications-setup/setup-flatpak.sh @@ -2,9 +2,7 @@ . ../common-script.sh -# Used to detect the desktop environment, Only used for the If statement in the setup_flatpak function. -# Perhaps this should be moved to common-script.sh later on? -detect_de() { +checkDE() { if [ -n "$XDG_CURRENT_DESKTOP" ]; then case "$XDG_CURRENT_DESKTOP" in *GNOME*) @@ -17,42 +15,11 @@ detect_de() { fi } -# Install Flatpak if not already installed. -setup_flatpak() { - if ! command_exists flatpak; then - printf "%b\n" "${YELLOW}Installing Flatpak...${RC}" - case "$PACKAGER" in - pacman) - "$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm flatpak - ;; - *) - "$ESCALATION_TOOL" "$PACKAGER" install -y flatpak - ;; - esac - printf "%b\n" "Adding Flathub remote..." - "$ESCALATION_TOOL" flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo - else - if command_exists flatpak; then - if ! flatpak remotes | grep -q "flathub"; then - printf "%b" "${YELLOW}Detected Flatpak package manager but Flathub remote is not added. Would you like to add it? (y/N): ${RC}" - read -r add_remote - case "$add_remote" in - [Yy]*) - printf "%b\n" "Adding Flathub remote..." - "$ESCALATION_TOOL" flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo - ;; - esac - else - # Needed mostly for systems without a polkit agent running (Error: updating: Unable to connect to system bus) - printf "%b\n" "${GREEN}Flathub already setup. You can quit.${RC}" - fi - fi - fi - +installExtra() { if [ "$PACKAGER" = "apt-get" ] || [ "$PACKAGER" = "nala" ]; then - detect_de + checkDE # Only used for Ubuntu GNOME. Ubuntu GNOME doesnt allow flathub to be added as a remote to their store. - # So in case the user wants to use a GUI siftware manager they can setup it here + # So in case the user wants to use a GUI software manager they can setup it here if [ "$DE" = "GNOME" ]; then printf "%b" "${YELLOW}Detected GNOME desktop environment. Would you like to install GNOME Software plugin for Flatpak? (y/N): ${RC}" read -r install_gnome @@ -72,4 +39,5 @@ setup_flatpak() { checkEnv checkEscalationTool -setup_flatpak +checkFlatpak +installExtra \ No newline at end of file diff --git a/core/tabs/applications-setup/tab_data.toml b/core/tabs/applications-setup/tab_data.toml index c102a5ce..44b74464 100644 --- a/core/tabs/applications-setup/tab_data.toml +++ b/core/tabs/applications-setup/tab_data.toml @@ -54,6 +54,12 @@ description = "GitHub Desktop is a user-friendly application that simplifies the script = "Developer-tools/githubdesktop-setup.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" +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." diff --git a/core/tabs/common-script.sh b/core/tabs/common-script.sh index 16ee4118..e915f692 100644 --- a/core/tabs/common-script.sh +++ b/core/tabs/common-script.sh @@ -9,10 +9,48 @@ CYAN='\033[36m' GREEN='\033[32m' command_exists() { - for cmd in "$@"; do - command -v "$cmd" >/dev/null 2>&1 || return 1 - done - return 0 +for cmd in "$@"; do + export PATH=/home/jeeva/.local/share/flatpak/exports/bin:/var/lib/flatpak/exports/bin:$PATH + command -v "$cmd" >/dev/null 2>&1 || return 1 +done +return 0 +} + +checkFlatpak() { + if ! command_exists flatpak; then + printf "%b\n" "${YELLOW}Installing Flatpak...${RC}" + case "$PACKAGER" in + pacman) + "$ESCALATION_TOOL" "$PACKAGER" -S --needed --noconfirm flatpak + ;; + apk) + "$ESCALATION_TOOL" "$PACKAGER" add flatpak + ;; + *) + "$ESCALATION_TOOL" "$PACKAGER" install -y flatpak + ;; + esac + printf "%b\n" "${YELLOW}Adding Flathub remote...${RC}" + "$ESCALATION_TOOL" flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + printf "%b\n" "${YELLOW}Applications installed by Flatpak may not appear on your desktop until the user session is restarted...${RC}" + else + if ! flatpak remotes | grep -q "flathub"; then + printf "%b\n" "${YELLOW}Adding Flathub remote...${RC}" + "$ESCALATION_TOOL" flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + else + printf "%b\n" "${CYAN}Flatpak is installed${RC}" + fi + fi +} + +checkArch() { + case "$(uname -m)" in + x86_64 | amd64) ARCH="x86_64" ;; + aarch64 | arm64) ARCH="aarch64" ;; + *) printf "%b\n" "${RED}Unsupported architecture: $(uname -m)${RC}" && exit 1 ;; + esac + + printf "%b\n" "${CYAN}System architecture: ${ARCH}${RC}" } checkAURHelper() { @@ -134,6 +172,7 @@ checkDistro() { } checkEnv() { + checkArch checkEscalationTool checkCommandRequirements "curl groups $ESCALATION_TOOL" checkPackageManager 'nala apt-get dnf pacman zypper apk' diff --git a/core/tabs/system-setup/arch/server-setup.sh b/core/tabs/system-setup/arch/server-setup.sh index 3a385df5..913d5f61 100755 --- a/core/tabs/system-setup/arch/server-setup.sh +++ b/core/tabs/system-setup/arch/server-setup.sh @@ -130,7 +130,7 @@ echo -ne " ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ██║ ██║ ╚██████╔╝███████║ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝ ------------------------------------------------------------------------ - Please select presetup settings for your system + Please select presetup settings for your system ------------------------------------------------------------------------ " } @@ -146,7 +146,7 @@ filesystem () { case $? in 0) export FS=btrfs;; 1) export FS=ext4;; - 2) + 2) set_password "LUKS_PASSWORD" export FS=luks ;; @@ -155,14 +155,14 @@ filesystem () { esac } -# @description Detects and sets timezone. +# @description Detects and sets timezone. timezone () { # Added this from arch wiki https://wiki.archlinux.org/title/System_time time_zone="$(curl --fail https://ipapi.co/timezone)" echo -ne " System detected your timezone to be '$time_zone' \n" echo -ne "Is this correct? - " + " options=("Yes" "No") select_option "${options[@]}" @@ -171,14 +171,14 @@ timezone () { echo "${time_zone} set as timezone" export TIMEZONE=$time_zone;; n|N|no|NO|No) - echo "Please enter your desired timezone e.g. Europe/London :" + echo "Please enter your desired timezone e.g. Europe/London :" read -r new_timezone echo "${new_timezone} set as timezone" export TIMEZONE=$new_timezone;; *) echo "Wrong option. Try again";timezone;; esac } -# @description Set user's keyboard mapping. +# @description Set user's keyboard mapping. keymap () { echo -ne " Please select key board layout from this list" @@ -236,18 +236,18 @@ echo -ne " drivessd } -# @description Gather username and password to be used for installation. +# @description Gather username and password to be used for installation. userinfo () { # Loop through user input until the user gives a valid username while true - do + do read -r -p "Please enter username: " username if [[ "${username,,}" =~ ^[a-z_]([a-z0-9_-]{0,31}|[a-z0-9_-]{0,30}\$)$ ]] - then + then break - fi + fi echo "Incorrect username." - done + done export USERNAME=$username while true @@ -264,22 +264,22 @@ userinfo () { done export PASSWORD=$PASSWORD1 - # Loop through user input until the user gives a valid hostname, but allow the user to force save + # Loop through user input until the user gives a valid hostname, but allow the user to force save while true - do + do read -r -p "Please name your machine: " name_of_machine # hostname regex (!!couldn't find spec for computer name!!) if [[ "${name_of_machine,,}" =~ ^[a-z][a-z0-9_.-]{0,62}[a-z0-9]$ ]] - then - break - fi + then + break + fi # if validation fails allow the user to force saving of the hostname - read -r -p "Hostname doesn't seem correct. Do you still want to save it? (y/n)" force + read -r -p "Hostname doesn't seem correct. Do you still want to save it? (y/n)" force if [[ "${force,,}" = "y" ]] - then - break - fi - done + then + break + fi + done export NAME_OF_MACHINE=$name_of_machine } @@ -351,7 +351,7 @@ echo -ne " Creating Filesystems ------------------------------------------------------------------------- " -# @description Creates the btrfs subvolumes. +# @description Creates the btrfs subvolumes. createsubvolumes () { btrfs subvolume create /mnt/@ btrfs subvolume create /mnt/@home @@ -362,11 +362,11 @@ mountallsubvol () { mount -o "${MOUNT_OPTIONS}",subvol=@home "${partition3}" /mnt/home } -# @description BTRFS subvolulme creation and mounting. +# @description BTRFS subvolulme creation and mounting. subvolumesetup () { # create nonroot subvolumes - createsubvolumes -# unmount root to remount with subvolume + createsubvolumes +# unmount root to remount with subvolume umount /mnt # mount @ subvolume mount -o "${MOUNT_OPTIONS}",subvol=@ "${partition3}" /mnt @@ -386,33 +386,36 @@ fi if [[ "${FS}" == "btrfs" ]]; then mkfs.vfat -F32 -n "EFIBOOT" "${partition2}" - mkfs.btrfs -L ROOT "${partition3}" -f + mkfs.btrfs -f "${partition3}" mount -t btrfs "${partition3}" /mnt subvolumesetup elif [[ "${FS}" == "ext4" ]]; then mkfs.vfat -F32 -n "EFIBOOT" "${partition2}" - mkfs.ext4 -L ROOT "${partition3}" + mkfs.ext4 "${partition3}" mount -t ext4 "${partition3}" /mnt elif [[ "${FS}" == "luks" ]]; then - mkfs.vfat -F32 -n "EFIBOOT" "${partition2}" + mkfs.vfat -F32 "${partition2}" # enter luks password to cryptsetup and format root partition echo -n "${LUKS_PASSWORD}" | cryptsetup -y -v luksFormat "${partition3}" - -# open luks container and ROOT will be place holder +# open luks container and ROOT will be place holder echo -n "${LUKS_PASSWORD}" | cryptsetup open "${partition3}" ROOT - # now format that container - mkfs.btrfs -L ROOT "${partition3}" + mkfs.btrfs "${partition3}" # create subvolumes for btrfs mount -t btrfs "${partition3}" /mnt subvolumesetup + ENCRYPTED_PARTITION_UUID=$(blkid -s UUID -o value "${partition3}") fi +BOOT_UUID=$(blkid -s UUID -o value "${partition2}") + sync if ! mountpoint -q /mnt; then echo "ERROR! Failed to mount ${partition3} to /mnt after multiple attempts." exit 1 fi mkdir -p /mnt/boot/efi -mount -t vfat -L EFIBOOT /mnt/boot/ +mount -t vfat -U "${BOOT_UUID}" /mnt/boot/ if ! grep -qs '/mnt' /proc/mounts; then echo "Drive is not mounted can not continue" @@ -435,8 +438,8 @@ fi echo "keyserver hkp://keyserver.ubuntu.com" >> /mnt/etc/pacman.d/gnupg/gpg.conf cp /etc/pacman.d/mirrorlist /mnt/etc/pacman.d/mirrorlist -genfstab -L /mnt >> /mnt/etc/fstab -echo " +genfstab -U /mnt >> /mnt/etc/fstab +echo " Generated /etc/fstab: " cat /mnt/etc/fstab @@ -475,14 +478,14 @@ arch-chroot /mnt /bin/bash -c "KEYMAP='${KEYMAP}' /bin/bash" <, + completion_preview: Option, } impl Filter { @@ -31,17 +32,23 @@ impl Filter { in_search_mode: false, input_position: 0, items: vec![], + completion_preview: None, } } + pub fn item_list(&self) -> &[ListEntry] { &self.items } + pub fn activate_search(&mut self) { self.in_search_mode = true; } + pub fn deactivate_search(&mut self) { self.in_search_mode = false; + self.completion_preview = None; } + pub fn update_items(&mut self, tabs: &[Tab], current_tab: usize, node: NodeId) { if self.search_input.is_empty() { let curr = tabs[current_tab].tree.get(node).unwrap(); @@ -78,13 +85,34 @@ impl Filter { } self.items.sort_by(|a, b| a.node.name.cmp(&b.node.name)); } + + self.update_completion_preview(); } + + fn update_completion_preview(&mut self) { + if self.search_input.is_empty() { + self.completion_preview = None; + return; + } + + let input = self.search_input.iter().collect::().to_lowercase(); + self.completion_preview = self.items.iter().find_map(|item| { + let item_name_lower = item.node.name.to_lowercase(); + if item_name_lower.starts_with(&input) { + Some(item_name_lower[input.len()..].to_string()) + } else { + None + } + }); + } + pub fn draw_searchbar(&self, frame: &mut Frame, area: Rect, theme: &Theme) { //Set the search bar text (If empty use the placeholder) let display_text = if !self.in_search_mode && self.search_input.is_empty() { Span::raw("Press / to search") } else { - Span::raw(self.search_input.iter().collect::()) + let input_text = self.search_input.iter().collect::(); + Span::styled(input_text, Style::default().fg(theme.focused_color())) }; let search_color = if self.in_search_mode { @@ -95,7 +123,7 @@ impl Filter { //Create the search bar widget let search_bar = Paragraph::new(display_text) - .block(Block::default().borders(Borders::ALL).title("Search")) + .block(Block::default().borders(Borders::ALL).title(" Search ")) .style(Style::default().fg(search_color)); //Render the search bar (First chunk of the screen) @@ -110,11 +138,22 @@ impl Filter { let x = area.x + cursor_position as u16 + 1; let y = area.y + 1; frame.set_cursor_position(Position::new(x, y)); + + if let Some(preview) = &self.completion_preview { + let preview_span = Span::styled(preview, Style::default().fg(Color::DarkGray)); + let preview_paragraph = Paragraph::new(preview_span).style(Style::default()); + let preview_area = Rect::new( + x, + y, + (preview.len() as u16).min(area.width - cursor_position as u16 - 1), + 1, + ); + frame.render_widget(preview_paragraph, preview_area); + } } } // Handles key events. Returns true if search must be exited pub fn handle_key(&mut self, event: &KeyEvent) -> SearchAction { - //Insert user input into the search bar match event.code { KeyCode::Char('c') if event.modifiers.contains(KeyModifiers::CONTROL) => { return self.exit_search() @@ -124,10 +163,17 @@ impl Filter { KeyCode::Delete => self.remove_next(), KeyCode::Left => return self.cursor_left(), KeyCode::Right => return self.cursor_right(), + KeyCode::Tab => return self.complete_search(), + KeyCode::Esc => { + self.input_position = 0; + self.search_input.clear(); + self.completion_preview = None; + return SearchAction::Exit; + } KeyCode::Enter => return SearchAction::Exit, - KeyCode::Esc => return self.exit_search(), _ => return SearchAction::None, }; + self.update_completion_preview(); SearchAction::Update } @@ -141,16 +187,19 @@ impl Filter { self.input_position = self.input_position.saturating_sub(1); SearchAction::None } + fn cursor_right(&mut self) -> SearchAction { if self.input_position < self.search_input.len() { self.input_position += 1; } SearchAction::None } + fn insert_char(&mut self, input: char) { self.search_input.insert(self.input_position, input); self.cursor_right(); } + fn remove_previous(&mut self) { let current = self.input_position; if current > 0 { @@ -158,12 +207,25 @@ impl Filter { self.cursor_left(); } } + fn remove_next(&mut self) { let current = self.input_position; if current < self.search_input.len() { self.search_input.remove(current); } } + + fn complete_search(&mut self) -> SearchAction { + if let Some(completion) = self.completion_preview.take() { + self.search_input.extend(completion.chars()); + self.input_position = self.search_input.len(); + self.update_completion_preview(); + SearchAction::Update + } else { + SearchAction::None + } + } + pub fn clear_search(&mut self) { self.search_input.clear(); self.input_position = 0; diff --git a/tui/src/running_command.rs b/tui/src/running_command.rs index 89daa755..f2471778 100644 --- a/tui/src/running_command.rs +++ b/tui/src/running_command.rs @@ -74,7 +74,7 @@ impl FloatContent for RunningCommand { title_line.push_span( Span::default() - .content(" press to close this window ") + .content(" Press to close this window ") .style(Style::default()), ); diff --git a/tui/src/state.rs b/tui/src/state.rs index fbd21ac8..a07bf178 100644 --- a/tui/src/state.rs +++ b/tui/src/state.rs @@ -24,7 +24,7 @@ use temp_dir::TempDir; const MIN_WIDTH: u16 = 100; const MIN_HEIGHT: u16 = 25; -const TITLE: &str = concat!("Linux Toolbox - ", env!("CARGO_PKG_VERSION")); +const TITLE: &str = concat!(" Linux Toolbox - ", env!("CARGO_PKG_VERSION"), " "); const ACTIONS_GUIDE: &str = "List of important tasks performed by commands' names: D - disk modifications (ex. partitioning) (privileged) @@ -61,7 +61,7 @@ pub struct AppState { selected_commands: Vec>, drawable: bool, #[cfg(feature = "tips")] - tip: &'static str, + tip: String, } pub enum Focus { @@ -375,17 +375,17 @@ impl AppState { }; let title = if self.multi_select { - &format!("{} [Multi-Select]", TITLE) + &format!("{}[Multi-Select] ", TITLE) } else { TITLE }; #[cfg(feature = "tips")] - let bottom_title = Line::from(self.tip.bold().blue()).right_aligned(); + let bottom_title = Line::from(self.tip.as_str().bold().blue()).right_aligned(); #[cfg(not(feature = "tips"))] let bottom_title = ""; - let task_list_title = Line::from("Important Actions ").right_aligned(); + let task_list_title = Line::from(" Important Actions ").right_aligned(); // Create the list widget with items let list = List::new(items) @@ -824,13 +824,13 @@ impl AppState { const TIPS: &str = include_str!("../cool_tips.txt"); #[cfg(feature = "tips")] -fn get_random_tip() -> &'static str { +fn get_random_tip() -> String { let tips: Vec<&str> = TIPS.lines().collect(); if tips.is_empty() { - return ""; + return "".to_string(); } let mut rng = rand::thread_rng(); let random_index = rng.gen_range(0..tips.len()); - tips[random_index] + format!(" {} ", tips[random_index]) }