Merge branch 'ChrisTitusTech:main' into testing-5

This commit is contained in:
Nyx 2024-09-12 16:20:48 -04:00 committed by GitHub
commit 5e64657108
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 1047 additions and 452 deletions

View File

@ -2,7 +2,7 @@
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
labels: 'bug'
assignees: ''
---

View File

@ -2,7 +2,7 @@
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
labels: 'enhancement'
assignees: ''
---

View File

@ -1,5 +1,6 @@
name-template: '$RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'
tag-prefix: ""
categories:
- title: '🚀 Features'
labels:
@ -10,8 +11,10 @@ categories:
- 'fix'
- 'bugfix'
- 'bug'
- title: '🧰 Maintenance'
label: 'chore'
- title: '📚 Documentation'
label: 'documentation'
- title: '🔒 Security'
label: 'security'
change-template: '- $TITLE @$AUTHOR (#$NUMBER)'
template: |
## Changes
@ -21,3 +24,37 @@ template: |
## Contributors
$CONTRIBUTORS
change-title-escapes: '\<*_&"'''
autolabeler:
- label: 'documentation'
files:
- '*.md'
branch:
- '/docs{0,1}\/.+/'
- label: 'bug'
branch:
- '/fix\/.+/'
title:
- '/fix/i'
- label: 'enhancement'
branch:
- '/feature\/.+/'
body:
- '/[A-Z]+-[0-9]+/'
- label: 'documentation'
files:
- '**/*.md'
- 'docs/**/*'
- label: 'security'
branch:
- '/security\/.+/'
replacers:
- search: /"/g
replace: ''
- search: /'/g
replace: ''
- search: /`/g
replace: ''
exclude-labels:
- 'skip-changelog'

25
.github/workflows/cargo-lock.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Remove Cargo.lock changes
on:
pull_request:
types: [opened, synchronize]
paths:
- 'Cargo.lock'
jobs:
remove-cargo-lock:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Remove Cargo.lock changes
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git checkout ${{ github.head_ref }}
git reset origin/${{ github.base_ref }} -- Cargo.lock
git commit -m "Remove changes to Cargo.lock" || echo "No changes to commit"
git push origin ${{ github.head_ref }} --force

View File

@ -1,22 +1,32 @@
name: GitHub Pages Deploy
on:
release:
types: [published, prereleased]
push:
paths:
- 'mkdocs.yml'
- 'docs/**'
- 'overrides/**'
- 'CONTRIBUTING.md'
workflow_dispatch:
permissions:
contents: write
jobs:
deploy:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v4
- name: Checkout Repository
uses: actions/checkout@v4
with:
python-version: 3.x
- uses: actions/cache@v4
fetch-depth: '0' # Fetch all commit history for all branches as well as tags.
- name: Setup Python
uses: actions/setup-python@v5
with:
key: ${{ github.ref }}
path: .cache
- run: pip install mkdocs-material
- run: pip install pillow cairosvg
- run: mkdocs gh-deploy --force
python-version: 3.x # Install latest Stable release of Python 3
cache: 'pip' # Caching pip dependencies
- name: Install Necessary Dependencies
run: pip install -r .github/requirements.txt
- name: Build & Deploy using mkdocs
run: mkdocs gh-deploy --force -f .github/mkdocs.yml

View File

@ -27,21 +27,12 @@ jobs:
- name: Generate Release Notes
id: generate_notes
uses: release-drafter/release-drafter@v5
uses: release-drafter/release-drafter@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
config-name: release-drafter.yml
version: ${{ env.version }}
version-template: '$YEAR.$MONTH.$DAY'
- name: Prepare Release Body
id: prepare_body
run: |
new_changes="${{ steps.generate_notes.outputs.body }}"
echo "body<<EOF" >> $GITHUB_OUTPUT
echo "$new_changes" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create and Upload Release
id: create_release
@ -50,7 +41,7 @@ jobs:
tag_name: ${{ env.version }}
name: Pre-Release ${{ env.version }}
body: |
${{ steps.prepare_body.outputs.body }}
${{ steps.generate_notes.outputs.body }}
![GitHub Downloads (specific asset, specific tag)](https://img.shields.io/github/downloads/ChrisTitusTech/linutil/${{ env.version }}/linutil)
append_body: false

550
Cargo.lock generated
View File

@ -21,10 +21,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
[[package]]
name = "anstream"
version = "0.6.14"
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
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 = "anstream"
version = "0.6.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
dependencies = [
"anstyle",
"anstyle-parse",
@ -43,43 +58,43 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
[[package]]
name = "anstyle-parse"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "3.0.3"
version = "3.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [
"anstyle",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
name = "anyhow"
version = "1.0.86"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
checksum = "4e1496f8fb1fbf272686b8d37f523dab3e4a7443300055e74cdaa449f3114356"
[[package]]
name = "arrayvec"
version = "0.7.4"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "autocfg"
@ -95,9 +110,15 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
[[package]]
name = "cassowary"
@ -107,13 +128,22 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
[[package]]
name = "castaway"
version = "0.2.2"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.1.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -121,10 +151,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.5.16"
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"android-tzdata",
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-targets",
]
[[package]]
name = "clap"
version = "4.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e5a21b8495e732f1b3c364c9949b201ca7bae518c502c80256c96ad79eaf6ac"
dependencies = [
"clap_builder",
"clap_derive",
@ -132,9 +176,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.15"
version = "4.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6"
checksum = "8cf2dd12af7a047ad9d6da2b6b249759a22a7abc0f474c1dae1777afa4b21a73"
dependencies = [
"anstream",
"anstyle",
@ -156,40 +200,47 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.7.1"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70"
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
[[package]]
name = "colorchoice"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "compact_str"
version = "0.7.1"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"rustversion",
"ryu",
"static_assertions",
]
[[package]]
name = "crossterm"
version = "0.27.0"
name = "core-foundation-sys"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
[[package]]
name = "crossterm"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"rustix",
"signal-hook",
"signal-hook-mio",
"winapi",
@ -212,15 +263,15 @@ checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "ego-tree"
version = "0.6.2"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68a4904193147e0a8dec3314640e6db742afd5f6e634f428a6af230d9b3591"
checksum = "12a0bb14ac04a9fcf170d0bbbef949b44cc492f4452bd20c095636956f653642"
[[package]]
name = "either"
version = "1.12.0"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "equivalent"
@ -235,7 +286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [
"libc",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
@ -271,13 +322,42 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "home"
version = "0.5.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
dependencies = [
"windows-sys 0.52.0",
"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]]
@ -301,14 +381,24 @@ dependencies = [
[[package]]
name = "indexmap"
version = "2.4.0"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c"
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "instability"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "ioctl-rs"
version = "0.1.6"
@ -320,9 +410,9 @@ dependencies = [
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
@ -340,16 +430,53 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "lazy_static"
version = "1.4.0"
name = "js-sys"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
dependencies = [
"wasm-bindgen",
]
[[package]]
name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]]
name = "libc"
version = "0.2.155"
version = "0.2.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
[[package]]
name = "linutil_core"
version = "0.1.0"
dependencies = [
"ego-tree",
"include_dir",
"serde",
"tempdir",
"toml",
"which",
]
[[package]]
name = "linutil_tui"
version = "0.1.0"
dependencies = [
"chrono",
"clap",
"crossterm",
"ego-tree",
"linutil_core",
"oneshot",
"portable-pty",
"ratatui",
"tui-term",
"unicode-width",
]
[[package]]
name = "linux-raw-sys"
@ -369,15 +496,15 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.21"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
[[package]]
name = "lru"
version = "0.12.3"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904"
dependencies = [
"hashbrown",
]
@ -399,14 +526,15 @@ dependencies = [
[[package]]
name = "mio"
version = "0.8.11"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
dependencies = [
"hermit-abi",
"libc",
"log",
"wasi",
"windows-sys 0.48.0",
"windows-sys",
]
[[package]]
@ -423,6 +551,15 @@ dependencies = [
"pin-utils",
]
[[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"
@ -437,9 +574,9 @@ checksum = "e296cf87e61c9cfc1a61c3c63a0f7f286ed4554e0e22be84e8a38e1d264a2a29"
[[package]]
name = "parking_lot"
version = "0.12.2"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
dependencies = [
"lock_api",
"parking_lot_core",
@ -455,7 +592,7 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
"windows-targets 0.52.5",
"windows-targets",
]
[[package]]
@ -493,18 +630,18 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.83"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
@ -539,18 +676,18 @@ checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "ratatui"
version = "0.27.0"
version = "0.28.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3"
checksum = "fdef7f9be5c0122f890d58bdf4d964349ba6a6161f705907526d891efabba57d"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"cassowary",
"compact_str",
"crossterm",
"instability",
"itertools",
"lru",
"paste",
"stability",
"strum",
"strum_macros",
"unicode-segmentation",
@ -569,11 +706,11 @@ dependencies = [
[[package]]
name = "redox_syscall"
version = "0.5.1"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
]
[[package]]
@ -587,15 +724,15 @@ dependencies = [
[[package]]
name = "rustix"
version = "0.38.34"
version = "0.38.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
dependencies = [
"bitflags 2.5.0",
"bitflags 2.6.0",
"errno",
"libc",
"linux-raw-sys",
"windows-sys 0.52.0",
"windows-sys",
]
[[package]]
@ -618,18 +755,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.205"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33aedb1a7135da52b7c21791455563facbbcc43d0f0f66165b42c21b3dfb150"
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.205"
version = "1.0.210"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "692d6f5ac90220161d6774db30c662202721e64aed9058d2c394f451261420c1"
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
dependencies = [
"proc-macro2",
"quote",
@ -703,6 +840,12 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "signal-hook"
version = "0.3.17"
@ -715,9 +858,9 @@ dependencies = [
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
dependencies = [
"libc",
"mio",
@ -739,16 +882,6 @@ version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "stability"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
@ -763,9 +896,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "strum"
version = "0.26.2"
version = "0.26.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29"
checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
dependencies = [
"strum_macros",
]
@ -785,9 +918,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.65"
version = "2.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2863d96a84c6439701d7a38f9de935ec562c8832cc55d1dde0f513b52fad106"
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
dependencies = [
"proc-macro2",
"quote",
@ -815,18 +948,18 @@ dependencies = [
[[package]]
name = "thiserror"
version = "1.0.61"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.61"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
@ -867,30 +1000,11 @@ dependencies = [
"winnow",
]
[[package]]
name = "tui"
version = "0.1.0"
dependencies = [
"clap",
"crossterm",
"ego-tree",
"include_dir",
"oneshot",
"portable-pty",
"ratatui",
"serde",
"tempdir",
"toml",
"tui-term",
"unicode-width",
"which",
]
[[package]]
name = "tui-term"
version = "0.1.12"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fac7538a3b9d5e92739253323e169ed25f005669c0e7f9d98f50f697fcada4e8"
checksum = "d07f0233f0d4795d2dc6663cfc3ce56b87bebcee66d6bcc088aa6aff5c072361"
dependencies = [
"ratatui",
"vt100",
@ -898,9 +1012,9 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.12"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
[[package]]
name = "unicode-segmentation"
@ -927,15 +1041,15 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d"
[[package]]
name = "utf8parse"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "version_check"
version = "0.9.4"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "vt100"
@ -962,9 +1076,9 @@ dependencies = [
[[package]]
name = "vte_generate_state_changes"
version = "0.1.1"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff"
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
dependencies = [
"proc-macro2",
"quote",
@ -976,6 +1090,61 @@ 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"
@ -1011,12 +1180,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.48.0"
name = "windows-core"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
"windows-targets 0.48.5",
"windows-targets",
]
[[package]]
@ -1025,129 +1194,72 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
"windows-targets 0.52.5",
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
]
[[package]]
name = "windows-targets"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
dependencies = [
"windows_aarch64_gnullvm 0.52.5",
"windows_aarch64_msvc 0.52.5",
"windows_i686_gnu 0.52.5",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc 0.52.5",
"windows_x86_64_gnu 0.52.5",
"windows_x86_64_gnullvm 0.52.5",
"windows_x86_64_msvc 0.52.5",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]]
name = "windows_i686_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]]
name = "windows_i686_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
name = "winnow"
@ -1175,18 +1287,18 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
[[package]]
name = "zerocopy"
version = "0.7.34"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.7.34"
version = "0.7.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
dependencies = [
"proc-macro2",
"quote",

View File

@ -1,34 +1,16 @@
[package]
name = "tui"
[workspace.package]
license = "MIT"
version = "0.1.0"
edition = "2021"
[dependencies]
clap = { version = "4.5.16", features = ["derive"] }
crossterm = "0.27.0"
[workspace.dependencies]
ego-tree = "0.6.2"
oneshot = "0.1.8"
portable-pty = "0.8.1"
ratatui = "0.27.0"
tui-term = "0.1.12"
include_dir = "0.7.4"
tempdir = "0.3.7"
serde = { version = "1.0.205", features = ["derive"] }
toml = "0.8.19"
which = "6.0.3"
unicode-width = "0.1.13"
[build-dependencies]
chrono = "0.4.33"
[[bin]]
name = "linutil"
path = "src/main.rs"
[workspace]
members = ["tui", "core"]
resolver = "2"
[profile.release]
opt-level = 3
opt-level = "z"
debug = false
lto = true
codegen-units = 1

View File

@ -2,6 +2,7 @@
[![Version](https://img.shields.io/github/v/release/ChrisTitusTech/linutil?color=%230567ff&label=Latest%20Release&style=for-the-badge)](https://github.com/ChrisTitusTech/linutil/releases/latest)
![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/ChrisTitusTech/linutil/linutil?label=Total%20Downloads&style=for-the-badge)
[![](https://dcbadge.limes.pink/api/server/https://discord.gg/bujFYKAHSp)](https://discord.gg/bujFYKAHSp)
![Preview](docs/assets/preview.png)

View File

@ -1,12 +0,0 @@
fn main() {
// Rebuild program if any file in commands directory changes.
println!("cargo:rerun-if-changed=src/commands");
// Rerun build script if any code is modified
println!("cargo:rerun-if-changed=src");
// Add current date as a variable to be displayed in the 'Linux Toolbox' text.
println!(
"cargo:rustc-env=BUILD_DATE={}",
chrono::Local::now().format("%Y-%m-%d")
);
}

Binary file not shown.

5
cargo-lock-merge.txt Normal file
View File

@ -0,0 +1,5 @@
What to do when you have a Cargo.lock merge conflict?
1. `git checkout origin/main -- Cargo.lock` to get the original Cargo.lock
2. `cargo build` to update Cargo.lock
3. `git add Cargo.lock`
4. continue the merge as normal

13
core/Cargo.toml Normal file
View File

@ -0,0 +1,13 @@
[package]
name = "linutil_core"
edition = "2021"
version.workspace = true
license.workspace = true
[dependencies]
include_dir = "0.7.4"
tempdir = "0.3.7"
serde = { version = "1.0.205", features = ["derive"] }
toml = "0.8.19"
which = "6.0.3"
ego-tree = { workspace = true }

View File

@ -1,7 +1,42 @@
use crate::running_command::Command;
use crate::{Command, ListNode, Tab};
use ego_tree::{NodeMut, Tree};
use include_dir::{include_dir, Dir};
use serde::Deserialize;
use std::path::{Path, PathBuf};
use tempdir::TempDir;
const TAB_DATA: Dir = include_dir!("$CARGO_MANIFEST_DIR/../tabs");
pub fn get_tabs(validate: bool) -> Vec<Tab> {
let tab_files = TabList::get_tabs();
let tabs = tab_files.into_iter().map(|path| {
let directory = path.parent().unwrap().to_owned();
let data = std::fs::read_to_string(path).expect("Failed to read tab data");
let mut tab_data: TabEntry = toml::from_str(&data).expect("Failed to parse tab data");
if validate {
filter_entries(&mut tab_data.data);
}
(tab_data, directory)
});
let tabs: Vec<Tab> = tabs
.map(|(TabEntry { name, data }, directory)| {
let mut tree = Tree::new(ListNode {
name: "root".to_string(),
command: Command::None,
});
let mut root = tree.root_mut();
create_directory(data, &mut root, &directory);
Tab { name, tree }
})
.collect();
if tabs.is_empty() {
panic!("No tabs found");
}
tabs
}
#[derive(Deserialize)]
struct TabList {
@ -79,49 +114,6 @@ enum SystemDataType {
CommandExists,
}
#[derive(Hash, Eq, PartialEq)]
pub struct Tab {
pub name: String,
pub tree: Tree<ListNode>,
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct ListNode {
pub name: String,
pub command: Command,
}
pub fn get_tabs(command_dir: &Path, validate: bool) -> Vec<Tab> {
let tab_files = TabList::get_tabs(command_dir);
let tabs = tab_files.into_iter().map(|path| {
let directory = path.parent().unwrap().to_owned();
let data = std::fs::read_to_string(path).expect("Failed to read tab data");
let mut tab_data: TabEntry = toml::from_str(&data).expect("Failed to parse tab data");
if validate {
filter_entries(&mut tab_data.data);
}
(tab_data, directory)
});
let tabs: Vec<Tab> = tabs
.map(|(TabEntry { name, data }, directory)| {
let mut tree = Tree::new(ListNode {
name: "root".to_string(),
command: Command::None,
});
let mut root = tree.root_mut();
create_directory(data, &mut root, &directory);
Tab { name, tree }
})
.collect();
if tabs.is_empty() {
panic!("No tabs found");
}
tabs
}
fn filter_entries(entries: &mut Vec<Entry>) {
entries.retain_mut(|entry| {
if !entry.is_supported() {
@ -176,15 +168,21 @@ fn create_directory(data: Vec<Entry>, node: &mut NodeMut<ListNode>, command_dir:
}
}
}
impl TabList {
fn get_tabs(command_dir: &Path) -> Vec<PathBuf> {
let tab_files = std::fs::read_to_string(command_dir.join("tabs.toml"))
.expect("Failed to read tabs.toml");
fn get_tabs() -> Vec<PathBuf> {
let temp_dir = TempDir::new("linutil_scripts").unwrap().into_path();
TAB_DATA
.extract(&temp_dir)
.expect("Failed to extract the saved directory");
let tab_files =
std::fs::read_to_string(temp_dir.join("tabs.toml")).expect("Failed to read tabs.toml");
let data: Self = toml::from_str(&tab_files).expect("Failed to parse tabs.toml");
data.directories
.into_iter()
.map(|path| command_dir.join(path).join("tab_data.toml"))
.iter()
.map(|path| temp_dir.join(path).join("tab_data.toml"))
.collect()
}
}

25
core/src/lib.rs Normal file
View File

@ -0,0 +1,25 @@
mod inner;
use ego_tree::Tree;
use std::path::PathBuf;
pub use inner::get_tabs;
#[derive(Clone, Hash, Eq, PartialEq)]
pub enum Command {
Raw(String),
LocalFile(PathBuf),
None, // Directory
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct Tab {
pub name: String,
pub tree: Tree<ListNode>,
}
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct ListNode {
pub name: String,
pub command: Command,
}

View File

@ -1 +1,4 @@
# Known Issues
---
- [Known Issues](https://github.com/ChrisTitusTech/linutil/issues)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,2 +1,62 @@
# How to Contribute?
Thank you for considering contributing to Linutil! We appreciate your effort in helping improve this project. To ensure that your contributions align with the goals and quality standards of Linutil, please follow these guidelines:
## 1. **Install Rust**:
Make sure you have Rust installed on your machine. You can install it by following the instructions at [rust-lang.org](https://www.rust-lang.org/tools/install).
## 2. **Fork and Clone the repo**
1. Make a fork of the repo in GitHub
2. Clone the fork
```bash
git clone https://github.com/YOUR_USERNAME_HERE/linutil.git
cd linutil
```
## 3. Make your changes
- **Edit the files you want to change**: Make your changes to the relevant files.
- **Test your changes**: Run `cargo run` to test your modifications in a local environment and ensure everything works as expected.
## 4. Understand the existing code
- **Have a clear reason**: Dont change the way things are done without a valid reason. If you propose an alteration, be prepared to explain why its necessary and how it improves the project.
- **Respect existing conventions**: Changes should align with the existing code style, design patterns, and overall project philosophy. If you want to introduce a new way of doing things, justify it clearly.
## 5. Learn from Past Pull Requests (PRs)
- **Check merged PRs**: Reviewing merged pull requests can give you an idea of what kind of contributions are accepted and how they are implemented.
- **Study rejected PRs**: This is especially important as it helps you avoid making similar mistakes or proposing changes that have already been considered and declined.
## 6. Write Clean, Descriptive Commit Messages
- **Be descriptive**: Your commit messages should clearly describe what the change does and why it was made.
- **Use the imperative mood**: For example, "Add feature X" or "Fix bug in Y", rather than "Added feature X" or "Fixed bug in Y".
- **Keep commits clean**: Avoid committing a change and then immediately following it with a fix for that change. Instead, amend your commit or squash it if needed.
## 7. Keep Your Pull Requests (PRs) Small and Focused
- **Make small, targeted PRs**: Focus on one feature or fix per pull request. This makes it easier to review and increases the likelihood of acceptance.
- **Avoid combining unrelated changes**: PRs that tackle multiple unrelated issues are harder to review and might be rejected because of a single problem.
## 8. Code Review and Feedback
- **Expect feedback**: PRs will undergo code review. Be open to feedback and willing to make adjustments as needed.
- **Participate in reviews**: If you feel comfortable, review other contributors' PRs as well. Peer review is a great way to learn and ensure high-quality contributions.
## 9. Contributing Is More Than Just Code
- **Test the tool**: Running tests and providing feedback on how the tool works in different environments is a valuable contribution.
- **Write well-formed issues**: Clearly describe bugs or problems you encounter, providing as much detail as possible, including steps to reproduce the issue.
- **Propose reasonable feature requests**: When suggesting new features, ensure they fit within the scope, style, and design of the project. Provide clear reasoning and use cases.
## 10. Documentation
- **Update the documentation**: If your change affects the functionality, please update the relevant documentation files to reflect this.
## 11. License
- **Agree to the license**: By contributing to Linutil, you agree that your contributions will be licensed under the project's MIT license.
We appreciate your contributions and look forward to collaborating with you to make Linutil better!

View File

@ -2,14 +2,22 @@
[![Version](https://img.shields.io/github/v/release/ChrisTitusTech/linutil?color=%230567ff&label=Latest%20Release&style=for-the-badge)](https://github.com/ChrisTitusTech/linutil/releases/latest)
![GitHub Downloads (specific asset, all releases)](https://img.shields.io/github/downloads/ChrisTitusTech/linutil/start.sh?label=Total%20Downloads&style=for-the-badge)
[![Discord Community Server](https://dcbadge.limes.pink/api/server/https://discord.gg/bujFYKAHSp)](https://discord.gg/bujFYKAHSp)
## Running latest release of LinUtil
## Running the latest release of LinUtil
To get started, run the following command in your terminal:
### Stable branch
* You will first need to start a Terminal on your linux machine.
* Now you will need to run following command:
```
curl -fsSL https://christitus.com/linux | sh
```
---
After you've ran the command, you should see a GUI on your screen; It will look something like this:
![preview](assets/preview.png)
!!! info

View File

@ -1,9 +1,32 @@
# Walkthrough
---
## How to run LinUtil?
Run the following command in a terminal on your Linux System:
```
curl -fsSL https://christitus.com/linux | sh
```
Once you have run that command you will see the following GUI show on your screen:
![Main Page](assets/mainpage.png)
## System Setup
- **System Update**: Starts a system-wide update.
- **Compile Setup**: Installs tools and dependencies for compiling software.
- **Gaming Setup**: Configures Steam, Lutris, etc.
- **Global Theming**: Sets up and manages global themes.
- **Remove Snaps**: Removes snap packages.
## Arch Setup
- **Paru Setup**: Installs the Paru AUR helper.
- **Yay Setup**: Installs the Yay AUR helper.
- **Server Setup**: Installs Arch Linux.
## Fedora Setup
- **RPM Fusion Setup**: Adds RPM Fusion repositories.
## Applications Setup
- **Alacritty Setup**: Installs and configures Alacritty for you.
- **DwmTitus Setup**: Sets up the Dwm window manager.
- **Kitty Setup**: Installs and configures Kitty for you.
- **Rofi Setup**: Installs the Rofi application/script launcher.
- **Zsh Setup**: Installs and configures Zsh for you.
## Security Features
- **Firewall Baselines**: Sets up firewall rules.

23
roadmap.md Normal file
View File

@ -0,0 +1,23 @@
# Roadmap
## Vision
- To simplify linux tasks for all users for all distributions; Easily, efficiently, and effortlessly.
## Goals
- [ ] Focus on tasks that take time in Linux and automate them. (Example: Removing a user, adding a user, etc. - but mostly BASH scripts with POSIX compliance.)
- [ ] Remove Binary linutil from being tracked in git and make it a github action.
- [ ] Document every function and feature of linutil. (Preview panel description addition)
- [x] Create a discord server for linutil and invite the community.
- [ ] Power Optimizations for Laptops
## Milestones
### Q3 2024
- [ ] Finish the foundation of the project in CLI mode.
- [ ] DENY ALL GUI Pull Requests while CLI and foundation is being established.
### Q4 2024
- [ ] GUI Brainstorming and Planning
- [ ] GUI Implementation towards the end of Q4
## Community Feedback
- Encourage community input and suggestions for future development.

View File

@ -15,11 +15,11 @@ setupDWM() {
$ESCALATION_TOOL "$PACKAGER" -S --needed --noconfirm base-devel libx11 libxinerama libxft imlib2 libxcb
;;
apt)
$ESCALATION_TOOL "$PACKAGER" install -y build-essential libx11-dev libxinerama-dev libxft-dev libimlib2-dev libxcb1-dev
$ESCALATION_TOOL "$PACKAGER" install -y build-essential libx11-dev libxinerama-dev libxft-dev libimlib2-dev libxcb1-dev libx11-xcb1
;;
dnf)
$ESCALATION_TOOL "$PACKAGER" groupinstall -y "Development Tools"
$ESCALATION_TOOL "$PACKAGER" install -y libx11-devel libxinerama-devel libxft-devel imlib2-devel libxcb-devel
$ESCALATION_TOOL "$PACKAGER" install -y libX11-devel libXinerama-devel libXft-devel imlib2-devel libxcb-devel
;;
*)
echo "Unsupported package manager: $PACKAGER"

View File

@ -11,6 +11,36 @@ command_exists() {
which "$1" >/dev/null 2>&1
}
checkAURHelper() {
## Check & Install AUR helper
if [ "$PACKAGER" = "pacman" ]; then
if [ -z "$AUR_HELPER_CHECKED" ]; then
AUR_HELPERS="yay paru"
for helper in ${AUR_HELPERS}; do
if command_exists "${helper}"; then
AUR_HELPER=${helper}
echo "Using ${helper} as AUR helper"
AUR_HELPER_CHECKED=true
return 0
fi
done
echo "Installing yay as AUR helper..."
$ESCALATION_TOOL "$PACKAGER" -S --needed --noconfirm base-devel
cd /opt && $ESCALATION_TOOL git clone https://aur.archlinux.org/yay-git.git && $ESCALATION_TOOL chown -R "$USER":"$USER" ./yay-git
cd yay-git && makepkg --noconfirm -si
if command_exists yay; then
AUR_HELPER="yay"
AUR_HELPER_CHECKED=true
else
echo -e "${RED}Failed to install AUR helper.${RC}"
exit 1
fi
fi
fi
}
checkEscalationTool() {
## Check for escalation tools.
if [ -z "$ESCALATION_TOOL_CHECKED" ]; then
@ -100,4 +130,5 @@ checkEnv() {
checkSuperUser
checkDistro
checkEscalationTool
checkAURHelper
}

View File

@ -15,22 +15,6 @@ installDepend() {
else
echo "Multilib is already enabled."
fi
if ! command_exists yay && ! command_exists paru; then
echo "Installing yay as AUR helper..."
$ESCALATION_TOOL "$PACKAGER" -S --needed --noconfirm base-devel
cd /opt && $ESCALATION_TOOL git clone https://aur.archlinux.org/yay-git.git && $ESCALATION_TOOL chown -R "$USER":"$USER" ./yay-git
cd yay-git && makepkg --noconfirm -si
else
echo "Aur helper already installed"
fi
if command_exists yay; then
AUR_HELPER="yay"
elif command_exists paru; then
AUR_HELPER="paru"
else
echo "No AUR helper found. Please install yay or paru."
exit 1
fi
$AUR_HELPER -S --needed --noconfirm "$DEPENDENCIES"
;;
apt-get|nala)
@ -80,6 +64,7 @@ install_additional_dependencies() {
}
checkEnv
checkAURHelper
checkEscalationTool
installDepend
install_additional_dependencies

View File

@ -13,22 +13,6 @@ installDepend() {
else
echo "Multilib is already enabled."
fi
if ! command_exists yay && ! command_exists paru; then
echo "Installing yay as AUR helper..."
$ESCALATION_TOOL ${PACKAGER} -S --needed --noconfirm base-devel
cd /opt && $ESCALATION_TOOL git clone https://aur.archlinux.org/yay-git.git && $ESCALATION_TOOL chown -R ${USER}:${USER} ./yay-git
cd yay-git && makepkg --noconfirm -si
else
echo "Aur helper already installed"
fi
if command_exists yay; then
AUR_HELPER="yay"
elif command_exists paru; then
AUR_HELPER="paru"
else
echo "No AUR helper found. Please install yay or paru."
exit 1
fi
$AUR_HELPER -S --needed --noconfirm wine giflib lib32-giflib libpng lib32-libpng libldap lib32-libldap gnutls lib32-gnutls \
mpg123 lib32-mpg123 openal lib32-openal v4l-utils lib32-v4l-utils libpulse lib32-libpulse libgpg-error \
lib32-libgpg-error alsa-plugins lib32-alsa-plugins alsa-lib lib32-alsa-lib libjpeg-turbo lib32-libjpeg-turbo \
@ -109,6 +93,7 @@ install_additional_dependencies() {
}
checkEnv
checkAURHelper
checkEscalationTool
installDepend
install_additional_dependencies

View File

@ -5,25 +5,8 @@
fastUpdate() {
case ${PACKAGER} in
pacman)
if ! command_exists yay && ! command_exists paru; then
echo "Installing yay as AUR helper..."
$ESCALATION_TOOL ${PACKAGER} -S --needed --noconfirm base-devel || { echo -e "${RED}Failed to install base-devel${RC}"; exit 1; }
cd /opt && $ESCALATION_TOOL git clone https://aur.archlinux.org/yay-git.git && $ESCALATION_TOOL chown -R ${USER}:${USER} ./yay-git
cd yay-git && makepkg --noconfirm -si || { echo -e "${RED}Failed to install yay${RC}"; exit 1; }
else
echo "AUR helper already installed"
fi
if command_exists yay; then
AUR_HELPER="yay"
elif command_exists paru; then
AUR_HELPER="paru"
else
echo "No AUR helper found. Please install yay or paru."
exit 1
fi
${AUR_HELPER} -S --needed --noconfirm rate-mirrors-bin
$AUR_HELPER -S --needed --noconfirm rate-mirrors-bin
if [ -s /etc/pacman.d/mirrorlist ]; then
$ESCALATION_TOOL cp /etc/pacman.d/mirrorlist /etc/pacman.d/mirrorlist.bak
@ -113,6 +96,7 @@ updateFlatpaks() {
}
checkEnv
checkAURHelper
checkEscalationTool
fastUpdate
updateSystem

23
tui/Cargo.toml Normal file
View File

@ -0,0 +1,23 @@
[package]
name = "linutil_tui"
edition = "2021"
version.workspace = true
license.workspace = true
[dependencies]
clap = { version = "4.5.16", features = ["derive"] }
crossterm = "0.28.1"
ego-tree = { workspace = true }
oneshot = "0.1.8"
portable-pty = "0.8.1"
ratatui = "0.28.1"
tui-term = "0.1.12"
unicode-width = "0.1.13"
linutil_core = { path = "../core" }
[build-dependencies]
chrono = "0.4.33"
[[bin]]
name = "linutil"
path = "src/main.rs"

7
tui/build.rs Normal file
View File

@ -0,0 +1,7 @@
fn main() {
// Add current date as a variable to be displayed in the 'Linux Toolbox' text.
println!(
"cargo:rustc-env=BUILD_DATE={}",
chrono::Local::now().format("%Y-%m-%d")
);
}

View File

@ -1,8 +1,9 @@
use crate::{state::ListEntry, tabs::Tab, theme::Theme};
use crate::{state::ListEntry, theme::Theme};
use crossterm::event::{KeyCode, KeyEvent};
use ego_tree::NodeId;
use linutil_core::Tab;
use ratatui::{
layout::Rect,
layout::{Position, Rect},
style::Style,
text::Span,
widgets::{Block, Borders, Paragraph},
@ -108,7 +109,7 @@ impl Filter {
.sum();
let x = area.x + cursor_position as u16 + 1;
let y = area.y + 1;
frame.set_cursor(x, y);
frame.set_cursor_position(Position::new(x, y));
}
}
// Handles key events. Returns true if search must be exited

View File

@ -4,10 +4,13 @@ use ratatui::{
Frame,
};
use crate::hint::ShortcutList;
pub trait FloatContent {
fn draw(&mut self, frame: &mut Frame, area: Rect);
fn handle_key_event(&mut self, key: &KeyEvent) -> bool;
fn is_finished(&self) -> bool;
fn get_shortcut_list(&self) -> ShortcutList;
}
pub struct Float {
@ -69,4 +72,8 @@ impl Float {
_ => self.content.handle_key_event(key),
}
}
pub fn get_shortcut_list(&self) -> ShortcutList {
self.content.get_shortcut_list()
}
}

View File

@ -1,5 +1,9 @@
use crate::{float::FloatContent, running_command::Command};
use crate::{
float::FloatContent,
hint::{Shortcut, ShortcutList},
};
use crossterm::event::{KeyCode, KeyEvent};
use linutil_core::Command;
use ratatui::{
layout::Rect,
style::{Style, Stylize},
@ -103,4 +107,15 @@ impl FloatContent for FloatingText {
fn is_finished(&self) -> bool {
true
}
fn get_shortcut_list(&self) -> ShortcutList {
ShortcutList {
scope_name: "Floating text",
hints: vec![
Shortcut::new(vec!["j", "Down"], "Scroll down"),
Shortcut::new(vec!["k", "Up"], "Scroll up"),
Shortcut::new(vec!["Enter", "q"], "Close window"),
],
}
}
}

161
tui/src/hint.rs Normal file
View File

@ -0,0 +1,161 @@
use ratatui::{
layout::{Margin, Rect},
style::{Style, Stylize},
text::{Line, Span},
widgets::{Block, Borders, Paragraph},
Frame,
};
use crate::state::{AppState, Focus};
pub const SHORTCUT_LINES: usize = 2;
pub struct ShortcutList {
pub scope_name: &'static str,
pub hints: Vec<Shortcut>,
}
pub struct Shortcut {
pub key_sequenses: Vec<Span<'static>>,
pub desc: &'static str,
}
pub fn span_vec_len(span_vec: &[Span]) -> usize {
span_vec.iter().rfold(0, |init, s| init + s.width())
}
impl ShortcutList {
pub fn draw(&self, frame: &mut Frame, area: Rect) {
let block = Block::default()
.title(self.scope_name)
.borders(Borders::all());
let inner_area = area.inner(Margin::new(1, 1));
let mut shortcut_list: Vec<Vec<Span>> = self.hints.iter().map(|h| h.to_spans()).collect();
let mut lines = vec![Line::default(); SHORTCUT_LINES];
let mut idx = 0;
while idx < SHORTCUT_LINES - 1 {
let split_idx = shortcut_list
.iter()
.scan(0usize, |total_len, s| {
*total_len += span_vec_len(s);
if *total_len > inner_area.width as usize {
None
} else {
*total_len += 4;
Some(1)
}
})
.count();
let new_shortcut_list = shortcut_list.split_off(split_idx);
let line: Vec<_> = shortcut_list
.into_iter()
.flat_map(|mut s| {
s.push(Span::default().content(" "));
s
})
.collect();
shortcut_list = new_shortcut_list;
lines[idx] = line.into();
idx += 1;
}
lines[idx] = shortcut_list
.into_iter()
.flat_map(|mut s| {
s.push(Span::default().content(" "));
s
})
.collect();
let p = Paragraph::new(lines).block(block);
frame.render_widget(p, area);
}
}
impl Shortcut {
pub fn new(key_sequences: Vec<&'static str>, desc: &'static str) -> Self {
Self {
key_sequenses: key_sequences
.iter()
.map(|s| Span::styled(*s, Style::default().bold()))
.collect(),
desc,
}
}
fn to_spans(&self) -> Vec<Span> {
let mut ret: Vec<_> = self
.key_sequenses
.iter()
.flat_map(|seq| {
[
Span::default().content("["),
seq.clone(),
Span::default().content("] "),
]
})
.collect();
ret.push(Span::styled(self.desc, Style::default().italic()));
ret
}
}
fn get_list_item_shortcut(state: &AppState) -> Shortcut {
if state.selected_item_is_dir() {
Shortcut::new(vec!["l", "Right", "Enter"], "Go to selected dir")
} else {
Shortcut::new(vec!["l", "Right", "Enter"], "Run selected command")
}
}
pub fn draw_shortcuts(state: &AppState, frame: &mut Frame, area: Rect) {
match state.focus {
Focus::Search => ShortcutList {
scope_name: "Search bar",
hints: vec![Shortcut::new(vec!["Enter"], "Finish search")],
},
Focus::List => {
let mut hints = Vec::new();
hints.push(Shortcut::new(vec!["q", "CTRL-c"], "Exit linutil"));
if state.at_root() {
hints.push(Shortcut::new(vec!["h", "Left", "Tab"], "Focus tab list"));
hints.push(get_list_item_shortcut(state));
} else {
if state.selected_item_is_up_dir() {
hints.push(Shortcut::new(
vec!["l", "Right", "Enter", "h", "Left"],
"Go to parrent directory",
));
} else {
hints.push(Shortcut::new(vec!["h", "Left"], "Go to parrent directory"));
hints.push(get_list_item_shortcut(state));
if state.selected_item_is_cmd() {
hints.push(Shortcut::new(vec!["p"], "Enable preview"));
}
}
hints.push(Shortcut::new(vec!["Tab"], "Focus tab list"));
};
hints.push(Shortcut::new(vec!["k", "Up"], "Select item above"));
hints.push(Shortcut::new(vec!["j", "Down"], "Select item below"));
hints.push(Shortcut::new(vec!["t"], "Next theme"));
hints.push(Shortcut::new(vec!["T"], "Previous theme"));
ShortcutList {
scope_name: "Item list",
hints,
}
}
Focus::TabList => ShortcutList {
scope_name: "Tab list",
hints: vec![
Shortcut::new(vec!["q", "CTRL-c"], "Exit linutil"),
Shortcut::new(vec!["l", "Right", "Tab", "Enter"], "Focus action list"),
Shortcut::new(vec!["k", "Up"], "Select item above"),
Shortcut::new(vec!["j", "Down"], "Select item below"),
Shortcut::new(vec!["t"], "Next theme"),
Shortcut::new(vec!["T"], "Previous theme"),
],
},
Focus::FloatingWindow(ref float) => float.get_shortcut_list(),
}
.draw(frame, area);
}

View File

@ -1,9 +1,9 @@
mod filter;
mod float;
mod floating_text;
mod hint;
mod running_command;
pub mod state;
mod tabs;
mod theme;
use std::{
@ -20,13 +20,11 @@ use crossterm::{
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand,
};
use include_dir::include_dir;
use ratatui::{
backend::{Backend, CrosstermBackend},
Terminal,
};
use state::AppState;
use tempdir::TempDir;
// Linux utility toolbox
#[derive(Debug, Parser)]
@ -43,13 +41,7 @@ struct Args {
fn main() -> std::io::Result<()> {
let args = Args::parse();
let commands_dir = include_dir!("src/commands");
let temp_dir: TempDir = TempDir::new("linutil_scripts").unwrap();
commands_dir
.extract(temp_dir.path())
.expect("Failed to extract the saved directory");
let mut state = AppState::new(args.theme, temp_dir.path(), args.override_validation);
let mut state = AppState::new(args.theme, args.override_validation);
stdout().execute(EnterAlternateScreen)?;
enable_raw_mode()?;
@ -71,7 +63,6 @@ fn main() -> std::io::Result<()> {
fn run<B: Backend>(terminal: &mut Terminal<B>, state: &mut AppState) -> io::Result<()> {
loop {
terminal.draw(|frame| state.draw(frame)).unwrap();
// Wait for an event
if !event::poll(Duration::from_millis(10))? {
continue;

View File

@ -1,5 +1,9 @@
use crate::float::FloatContent;
use crate::{
float::FloatContent,
hint::{Shortcut, ShortcutList},
};
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use linutil_core::Command;
use oneshot::{channel, Receiver};
use portable_pty::{
ChildKiller, CommandBuilder, ExitStatus, MasterPty, NativePtySystem, PtySize, PtySystem,
@ -13,7 +17,6 @@ use ratatui::{
};
use std::{
io::Write,
path::PathBuf,
sync::{Arc, Mutex},
thread::JoinHandle,
};
@ -22,13 +25,6 @@ use tui_term::{
widget::PseudoTerminal,
};
#[derive(Clone, Hash, Eq, PartialEq)]
pub enum Command {
Raw(String),
LocalFile(PathBuf),
None, // Directory
}
pub struct RunningCommand {
/// A buffer to save all the command output (accumulates, until the command exits)
buffer: Arc<Mutex<Vec<u8>>>,
@ -123,6 +119,20 @@ impl FloatContent for RunningCommand {
true
}
}
fn get_shortcut_list(&self) -> ShortcutList {
if self.is_finished() {
ShortcutList {
scope_name: "Finished command",
hints: vec![Shortcut::new(vec!["Enter", "q"], "Close window")],
}
} else {
ShortcutList {
scope_name: "Running command",
hints: vec![Shortcut::new(vec!["CTRL-c"], "Kill the command")],
}
}
}
}
impl RunningCommand {

View File

@ -2,26 +2,26 @@ use crate::{
filter::{Filter, SearchAction},
float::{Float, FloatContent},
floating_text::FloatingText,
running_command::{Command, RunningCommand},
tabs::{ListNode, Tab},
hint::{draw_shortcuts, SHORTCUT_LINES},
running_command::RunningCommand,
theme::Theme,
};
use crossterm::event::{KeyCode, KeyEvent, KeyEventKind};
use ego_tree::NodeId;
use linutil_core::{Command, ListNode, Tab};
use ratatui::{
layout::{Constraint, Direction, Layout},
layout::{Alignment, Constraint, Direction, Layout},
style::{Style, Stylize},
text::Line,
widgets::{Block, Borders, List, ListState},
text::{Line, Span},
widgets::{Block, Borders, List, ListState, Paragraph},
Frame,
};
use std::path::Path;
pub struct AppState {
/// Selected theme
theme: Theme,
/// Currently focused area
focus: Focus,
pub focus: Focus,
/// List of tabs
tabs: Vec<Tab>,
/// Current tab
@ -49,8 +49,8 @@ pub struct ListEntry {
}
impl AppState {
pub fn new(theme: Theme, temp_path: &Path, override_validation: bool) -> Self {
let tabs = crate::tabs::get_tabs(temp_path, !override_validation);
pub fn new(theme: Theme, override_validation: bool) -> Self {
let tabs = linutil_core::get_tabs(!override_validation);
let root_id = tabs[0].tree.root().id();
let mut state = Self {
theme,
@ -65,12 +65,44 @@ impl AppState {
state
}
pub fn draw(&mut self, frame: &mut Frame) {
let label_block =
Block::default()
.borders(Borders::all())
.border_set(ratatui::symbols::border::Set {
top_left: " ",
top_right: " ",
bottom_left: " ",
bottom_right: " ",
vertical_left: " ",
vertical_right: " ",
horizontal_top: "*",
horizontal_bottom: "*",
});
let str1 = "Linutil ";
let str2 = "by Chris Titus";
let label = Paragraph::new(Line::from(vec![
Span::styled(str1, Style::default().bold()),
Span::styled(str2, Style::default().italic()),
]))
.block(label_block)
.alignment(Alignment::Center);
let longest_tab_display_len = self
.tabs
.iter()
.map(|tab| tab.name.len() + self.theme.tab_icon().len())
.max()
.unwrap_or(0);
.unwrap_or(0)
.max(str1.len() + str2.len());
let vertical = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Percentage(100),
Constraint::Min(2 + SHORTCUT_LINES as u16),
])
.margin(0)
.split(frame.area());
let horizontal = Layout::default()
.direction(Direction::Horizontal)
@ -78,11 +110,13 @@ impl AppState {
Constraint::Min(longest_tab_display_len as u16 + 5),
Constraint::Percentage(100),
])
.split(frame.size());
.split(vertical[0]);
let left_chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Length(3), Constraint::Min(1)])
.split(horizontal[0]);
frame.render_widget(label, left_chunks[0]);
let tabs = self
.tabs
@ -148,6 +182,8 @@ impl AppState {
if let Focus::FloatingWindow(float) = &mut self.focus {
float.draw(frame, chunks[1]);
}
draw_shortcuts(self, frame, vertical[1]);
}
pub fn handle_key(&mut self, key: &KeyEvent) -> bool {
match &mut self.focus {
@ -213,7 +249,7 @@ impl AppState {
/// Checks ehther the current tree node is the root node (can we go up the tree or no)
/// Returns `true` if we can't go up the tree (we are at the tree root)
/// else returns `false`
fn at_root(&self) -> bool {
pub fn at_root(&self) -> bool {
self.visit_stack.len() == 1
}
fn enter_parent_directory(&mut self) {
@ -221,13 +257,10 @@ impl AppState {
self.selection.select(Some(0));
self.update_items();
}
fn get_selected_command(&mut self, change_directory: bool) -> Option<Command> {
pub fn get_selected_command(&self) -> Option<Command> {
let mut selected_index = self.selection.selected().unwrap_or(0);
if !self.at_root() && selected_index == 0 {
if change_directory {
self.enter_parent_directory();
}
return None;
}
if !self.at_root() {
@ -237,25 +270,83 @@ impl AppState {
if let Some(item) = self.filter.item_list().get(selected_index) {
if !item.has_children {
return Some(item.node.command.clone());
} else if change_directory {
}
}
None
}
pub fn go_to_selected_dir(&mut self) {
let mut selected_index = self.selection.selected().unwrap_or(0);
if !self.at_root() && selected_index == 0 {
self.enter_parent_directory();
return;
}
if !self.at_root() {
selected_index = selected_index.saturating_sub(1);
}
if let Some(item) = self.filter.item_list().get(selected_index) {
if item.has_children {
self.visit_stack.push(item.id);
self.selection.select(Some(0));
self.update_items();
}
}
None
}
pub fn selected_item_is_dir(&self) -> bool {
let mut selected_index = self.selection.selected().unwrap_or(0);
if !self.at_root() && selected_index == 0 {
return false;
}
if !self.at_root() {
selected_index = selected_index.saturating_sub(1);
}
if let Some(item) = self.filter.item_list().get(selected_index) {
item.has_children
} else {
false
}
}
pub fn selected_item_is_cmd(&self) -> bool {
let mut selected_index = self.selection.selected().unwrap_or(0);
if !self.at_root() && selected_index == 0 {
return false;
}
if !self.at_root() {
selected_index = selected_index.saturating_sub(1);
}
if let Some(item) = self.filter.item_list().get(selected_index) {
!item.has_children
} else {
false
}
}
pub fn selected_item_is_up_dir(&self) -> bool {
let selected_index = self.selection.selected().unwrap_or(0);
!self.at_root() && selected_index == 0
}
fn enable_preview(&mut self) {
if let Some(command) = self.get_selected_command(false) {
if let Some(command) = self.get_selected_command() {
if let Some(preview) = FloatingText::from_command(&command) {
self.spawn_float(preview, 80, 80);
}
}
}
fn handle_enter(&mut self) {
if let Some(cmd) = self.get_selected_command(true) {
if let Some(cmd) = self.get_selected_command() {
let command = RunningCommand::new(cmd);
self.spawn_float(command, 80, 80);
} else {
self.go_to_selected_dir();
}
}
fn spawn_float<T: FloatContent + 'static>(&mut self, float: T, width: u16, height: u16) {