Compare commits
24 Commits
a7f7452b2b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8bfb3272c0 | ||
|
|
1a48280b14 | ||
|
|
9a272689eb | ||
|
|
6e4d052170 | ||
|
|
ceb3386c57 | ||
|
|
d22b24e54c | ||
|
|
28e4c112af | ||
|
|
9ec52aa49f | ||
|
|
1b28e90c62 | ||
|
|
1e31712b60 | ||
|
|
5faae67d11 | ||
|
|
ee72ede116 | ||
|
|
f5244ac062 | ||
|
|
9a089112c3 | ||
|
|
e64a857a43 | ||
|
|
ddd7d4193a | ||
|
|
83a1c8ce48 | ||
|
|
b29fa3b30c | ||
|
|
cd0bcfd214 | ||
|
|
a91c41871a | ||
|
|
9698f0e506 | ||
|
|
9e22f007b9 | ||
|
|
d472fb61aa | ||
|
|
9108ee8266 |
83
README.md
83
README.md
@@ -10,12 +10,28 @@ current shell is not bash.
|
|||||||
|
|
||||||
## 2. Getting started
|
## 2. Getting started
|
||||||
Download and extract (or use git clone) the profile archive into your home
|
Download and extract (or use git clone) the profile archive into your home
|
||||||
directory. You will have to modify your `~/.bashrc` and/or `~/.profile` file to
|
directory.
|
||||||
add at the end (preferably):
|
|
||||||
|
The profile is designed to be **sourced**, not executed directly.
|
||||||
|
|
||||||
|
Manual setup:
|
||||||
```bash
|
```bash
|
||||||
source <installpath>/profile/profile.sh
|
source <installpath>/profile/profile.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Automatic setup (recommended):
|
||||||
|
```bash
|
||||||
|
bash <installpath>/profile/profile.sh --install
|
||||||
|
```
|
||||||
|
|
||||||
|
`--install` appends the required `source` line to both `~/.bashrc` and
|
||||||
|
`~/.profile` by default. You can target one file only:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash <installpath>/profile/profile.sh --install --bashrc
|
||||||
|
bash <installpath>/profile/profile.sh --install --profile
|
||||||
|
```
|
||||||
|
|
||||||
You may also set the `PROFILE_PATH` environment variable before sourcing if you
|
You may also set the `PROFILE_PATH` environment variable before sourcing if you
|
||||||
want to override the automatic path detection:
|
want to override the automatic path detection:
|
||||||
```bash
|
```bash
|
||||||
@@ -26,7 +42,22 @@ source /opt/profile/profile.sh
|
|||||||
It's not recommended to load that profile in `/etc/profile` as users' `.bashrc`
|
It's not recommended to load that profile in `/etc/profile` as users' `.bashrc`
|
||||||
files might interfere with some aliases and functions defined in profile.
|
files might interfere with some aliases and functions defined in profile.
|
||||||
|
|
||||||
### 2.1. Initial configuration
|
### 2.1. Interactive vs non-interactive shells
|
||||||
|
|
||||||
|
`profile.sh` detects whether the current shell is interactive.
|
||||||
|
|
||||||
|
In interactive shells (typical terminal sessions), profile enables
|
||||||
|
interactive-only features such as:
|
||||||
|
- aliases from `[aliases]`
|
||||||
|
- bash completion scripts from `profile.d/bash-completion/`
|
||||||
|
- prompt initialization (`PROMPT_COMMAND` and timer hook)
|
||||||
|
- welcome display (`showinfo`) and startup update check (`check_updates -q`)
|
||||||
|
|
||||||
|
In non-interactive shells (typical script execution), those features are
|
||||||
|
intentionally skipped to avoid side effects and startup noise. Public functions
|
||||||
|
remain available after sourcing, so scripts can still call profile helpers.
|
||||||
|
|
||||||
|
### 2.2. Initial configuration
|
||||||
Copy the example configuration file and customise it to your needs:
|
Copy the example configuration file and customise it to your needs:
|
||||||
```bash
|
```bash
|
||||||
cp <installpath>/profile/doc/profile.conf.example <installpath>/profile/profile.conf
|
cp <installpath>/profile/doc/profile.conf.example <installpath>/profile/profile.conf
|
||||||
@@ -49,10 +80,10 @@ A bar-style prompt showing current time, execution time of the last command
|
|||||||
| Function | Module | Description |
|
| Function | Module | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `busy` | fun | Monitor /dev/urandom for a hex pattern — look busy |
|
| `busy` | fun | Monitor /dev/urandom for a hex pattern — look busy |
|
||||||
| `check_updates` | updates | Check whether a newer profile version is available online |
|
| `check_updates` | updates | Check whether a newer profile version is available online; when called with `-q` at startup a 3-second network timeout is applied so a slow or absent network never delays the prompt |
|
||||||
| `clean` | filefct | Erase backup files in given directories, optionally recursive |
|
| `clean` | filefct | Erase backup files in given directories, optionally recursive |
|
||||||
| `disp` | disp | Display formatted info / warning / error / debug messages |
|
| `disp` | disp | Display formatted info / warning / error / debug messages; long messages are word-wrapped and continuation lines are indented to align with the message text |
|
||||||
| `dwl` | net | Download a URL using curl, wget, or fetch transparently |
|
| `dwl` | net | Download a URL using curl, wget, or fetch transparently; supports `-t <seconds>` / `--timeout <seconds>` to cap the transfer time |
|
||||||
| `expandlist` | filefct | Expand glob expressions into a quoted, separated list |
|
| `expandlist` | filefct | Expand glob expressions into a quoted, separated list |
|
||||||
| `file_stats` | filefct | Display file size statistics for a path |
|
| `file_stats` | filefct | Display file size statistics for a path |
|
||||||
| `findbig` | filefct | Find the biggest files in the given or current directory |
|
| `findbig` | filefct | Find the biggest files in the given or current directory |
|
||||||
@@ -68,12 +99,13 @@ A bar-style prompt showing current time, execution time of the last command
|
|||||||
| `gsync` | git | Fetch and rebase the current branch onto its upstream |
|
| `gsync` | git | Fetch and rebase the current branch onto its upstream |
|
||||||
| `gst` | git | Display compact git status with branch tracking information |
|
| `gst` | git | Display compact git status with branch tracking information |
|
||||||
| `gwip` | git | Create a quick WIP checkpoint commit |
|
| `gwip` | git | Create a quick WIP checkpoint commit |
|
||||||
| `help` | help | Display the list of available functions and basic usage |
|
| `help` | help | Display the list of available functions and basic usage; `help <command>` delegates to `<command> --help` |
|
||||||
| `isipv4` | net | Tell if the given parameter is a valid IPv4 address |
|
| `isipv4` | net | Tell if the given parameter is a valid IPv4 address |
|
||||||
| `isipv6` | net | Tell if the given parameter is a valid IPv6 address |
|
| `isipv6` | net | Tell if the given parameter is a valid IPv6 address |
|
||||||
| `ku` | processes | Kill all processes owned by the given user name or ID |
|
| `ku` | processes | Kill all processes owned by the given user name or ID |
|
||||||
| `matrix` | rain | Console screensaver with Matrix-style digital rain (binary, kana, ascii charset) |
|
| `matrix` | rain | Console screensaver with Matrix-style digital rain (binary, kana, ascii charset) |
|
||||||
| `mcd` | filefct | Create a directory and immediately move into it |
|
| `mcd` | filefct | Create a directory and immediately move into it |
|
||||||
|
| `mdcat` | disp | Render Markdown files in terminal with colors, inline formatting, and framed code blocks |
|
||||||
| `meteo` | info | Display weather forecast for the configured or given city |
|
| `meteo` | info | Display weather forecast for the configured or given city |
|
||||||
| `myextip` | net | Get information about your public IP address |
|
| `myextip` | net | Get information about your public IP address |
|
||||||
| `get_pkgmgr` | packages | Detect the active package manager of the running distribution (`apt`, `dnf`, `yum`, `zypper`, `pacman`, `apk`, `portage`, `xbps`, `nix`) |
|
| `get_pkgmgr` | packages | Detect the active package manager of the running distribution (`apt`, `dnf`, `yum`, `zypper`, `pacman`, `apk`, `portage`, `xbps`, `nix`) |
|
||||||
@@ -99,6 +131,13 @@ A bar-style prompt showing current time, execution time of the last command
|
|||||||
Locale shortcut functions (`setfr`, `setus`, etc.) are dynamically generated at
|
Locale shortcut functions (`setfr`, `setus`, etc.) are dynamically generated at
|
||||||
startup from the `SET_LOCALE` configuration key (see section 4).
|
startup from the `SET_LOCALE` configuration key (see section 4).
|
||||||
|
|
||||||
|
### 3.3. Bash completion
|
||||||
|
|
||||||
|
profile loads all `*.sh` files found under `profile.d/bash-completion/`
|
||||||
|
automatically in interactive sessions. This directory is the right place to add
|
||||||
|
any custom completion definitions. profile already ships completions for its git
|
||||||
|
helper functions there (`git-completion.sh`).
|
||||||
|
|
||||||
## 4. Configuration
|
## 4. Configuration
|
||||||
profile uses an INI-style configuration file (`profile.conf`) located in the
|
profile uses an INI-style configuration file (`profile.conf`) located in the
|
||||||
same directory as `profile.sh`. Sections are declared with `[section_name]` and
|
same directory as `profile.sh`. Sections are declared with `[section_name]` and
|
||||||
@@ -109,7 +148,7 @@ apply when unset.
|
|||||||
|
|
||||||
`profile.conf` is listed in `.gitignore` so personal values (API keys, cities,
|
`profile.conf` is listed in `.gitignore` so personal values (API keys, cities,
|
||||||
compiler flags, …) are never accidentally staged. Start from the annotated
|
compiler flags, …) are never accidentally staged. Start from the annotated
|
||||||
template at `doc/profile.conf.example` (see [section 2.1](#21-initial-configuration)).
|
template at `doc/profile.conf.example` (see [section 2.2](#22-initial-configuration)).
|
||||||
|
|
||||||
### 4.1. Core sections
|
### 4.1. Core sections
|
||||||
|
|
||||||
@@ -129,7 +168,7 @@ change the default without having to pass flags every time.
|
|||||||
| Key | Default | Description |
|
| Key | Default | Description |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `TAZ_DEFAULT_FORMAT` | `tar.gz` | Archive format for `taz` (`tar.gz`, `tar.bz2`, `tar.xz`, `zip`, …) |
|
| `TAZ_DEFAULT_FORMAT` | `tar.gz` | Archive format for `taz` (`tar.gz`, `tar.bz2`, `tar.xz`, `zip`, …) |
|
||||||
| `TAZ_DEFAULT_THREADS` | `0` | Compression threads (0 = auto-detect) |
|
| `TAZ_DEFAULT_THREADS` | `auto` | Compression threads (`auto` = runtime CPU count, or explicit positive integer) |
|
||||||
| `TAZ_DEFAULT_LEVEL` | `6` | Compression level (1–9) |
|
| `TAZ_DEFAULT_LEVEL` | `6` | Compression level (1–9) |
|
||||||
| `UTAZ_DEFAULT_DELETE` | `0` | Set to `1` to delete the source archive after extraction |
|
| `UTAZ_DEFAULT_DELETE` | `0` | Set to `1` to delete the source archive after extraction |
|
||||||
| `UTAZ_DEFAULT_DIR_MODE` | `0` | Set to `1` to always extract into a subdirectory |
|
| `UTAZ_DEFAULT_DIR_MODE` | `0` | Set to `1` to always extract into a subdirectory |
|
||||||
@@ -149,8 +188,10 @@ change the default without having to pass flags every time.
|
|||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `RAIN_DEFAULT_SPEED` | `0.1` | Falling speed for `rain` |
|
| `RAIN_DEFAULT_SPEED` | `0.1` | Falling speed for `rain` |
|
||||||
| `RAIN_DEFAULT_COLOR` | `Green` | Colour for `rain` |
|
| `RAIN_DEFAULT_COLOR` | `Green` | Colour for `rain` |
|
||||||
|
| `RAIN_DEFAULT_DENSITY` | dynamic | Maximum number of simultaneous falling elements for `rain` |
|
||||||
| `MATRIX_DEFAULT_SPEED` | `0.05` | Falling speed for `matrix` |
|
| `MATRIX_DEFAULT_SPEED` | `0.05` | Falling speed for `matrix` |
|
||||||
| `MATRIX_DEFAULT_COLOR` | `Green` | Colour for `matrix` |
|
| `MATRIX_DEFAULT_COLOR` | `Green` | Colour for `matrix` |
|
||||||
|
| `MATRIX_DEFAULT_DENSITY` | dynamic | Maximum number of simultaneous falling elements for `matrix` |
|
||||||
| `MATRIX_DEFAULT_CHARSET` | `binary` | Character set for `matrix` (`binary`, `kana`, `ascii`) |
|
| `MATRIX_DEFAULT_CHARSET` | `binary` | Character set for `matrix` (`binary`, `kana`, `ascii`) |
|
||||||
|
|
||||||
**`[ssh]`**
|
**`[ssh]`**
|
||||||
@@ -269,7 +310,7 @@ PROMPT_COLOR_USER_FG = $ICyan
|
|||||||
PROMPT_COLOR_DIR_FG = $IYellow
|
PROMPT_COLOR_DIR_FG = $IYellow
|
||||||
```
|
```
|
||||||
|
|
||||||
The eleven available `PROMPT_COLOR_*` keys are:
|
The twelve available `PROMPT_COLOR_*` keys are:
|
||||||
|
|
||||||
| Key | Role |
|
| Key | Role |
|
||||||
|---|---|
|
|---|---|
|
||||||
@@ -280,6 +321,28 @@ The eleven available `PROMPT_COLOR_*` keys are:
|
|||||||
| `PROMPT_COLOR_ROOT_FG` | Username colour when running as root |
|
| `PROMPT_COLOR_ROOT_FG` | Username colour when running as root |
|
||||||
| `PROMPT_COLOR_USER_FG` | Username@host colour for normal users |
|
| `PROMPT_COLOR_USER_FG` | Username@host colour for normal users |
|
||||||
| `PROMPT_COLOR_DIR_FG` | Working directory colour |
|
| `PROMPT_COLOR_DIR_FG` | Working directory colour |
|
||||||
|
| `PROMPT_COLOR_CTX_FG` | Git/Conda context segment colour at end of top bar |
|
||||||
|
|
||||||
|
**Top-bar context segment (Git / Conda):**
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[prompt]
|
||||||
|
PROMPT_SHOW_GIT = 1
|
||||||
|
PROMPT_SHOW_GIT_STATUS = 1
|
||||||
|
PROMPT_SHOW_CONDA = 1
|
||||||
|
PROMPT_SHOW_VENV = 1
|
||||||
|
PROMPT_SHOW_SESSION = 1
|
||||||
|
```
|
||||||
|
|
||||||
|
When enabled, the top prompt bar appends:
|
||||||
|
|
||||||
|
- `git:<branch>` when inside a Git repository
|
||||||
|
- `git:<branch>*` when local changes are present
|
||||||
|
- `git:<branch> +N/-M` when ahead/behind upstream
|
||||||
|
- `conda:<env>` when a Conda environment is active
|
||||||
|
- `venv:<name>` when a Python virtualenv is active (and Conda is not)
|
||||||
|
- `ssh`, `tmux`, `screen` markers when the session runs in those contexts
|
||||||
|
- both, separated by `|`, when both are available
|
||||||
|
|
||||||
**Writing a custom theme file:**
|
**Writing a custom theme file:**
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,36 @@ Versions follow `MAJOR.MINOR.PATCH-REVISION_STAGE_N` (e.g. `3.99.1-4_rc_1`).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [4.1.0] — 2026-05-07
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- `profile.sh --install` command to automatically configure profile loading in
|
||||||
|
shell startup files.
|
||||||
|
- `--install --bashrc` and `--install --profile` target selectors for
|
||||||
|
single-file installation.
|
||||||
|
- **`git.sh`** — entirely new module providing git workflow helpers: `gst`,
|
||||||
|
`ggraph`, `gsync`, `gacp`, `greset`, `gwip`, `gprune`, `groot`.
|
||||||
|
- Dedicated git helper completions under `profile.d/bash-completion/`, loaded
|
||||||
|
automatically in interactive sessions from `profile.d/bash-completion/*.sh`.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- `disp` now wraps long messages on terminal width, avoids mid-word splits, and
|
||||||
|
aligns continuation lines with the message body after the prefix.
|
||||||
|
- `help` now supports `help <command>` and delegates to `<command> --help`.
|
||||||
|
- `taz` now supports `-p auto` / `--parallel=auto` to automatically use the
|
||||||
|
runtime CPU count. This mode is now the default via
|
||||||
|
`TAZ_DEFAULT_THREADS=auto`.
|
||||||
|
- `taz` keeps backward compatibility with legacy `TAZ_DEFAULT_THREADS=0`
|
||||||
|
values by interpreting `0` as `auto`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Startup responsiveness improved: `check_updates -q` now uses a short network
|
||||||
|
timeout so unavailable/slow networks no longer delay prompt readiness.
|
||||||
|
- `dwl` gained timeout support (`-t` / `--timeout`) and is now used by quiet
|
||||||
|
startup update checks to enforce fast failure.
|
||||||
|
- `profile.sh` now detects direct execution and warns that it is designed to be
|
||||||
|
sourced.
|
||||||
|
|
||||||
## [4.0.0] — 2026-04-23
|
## [4.0.0] — 2026-04-23
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
147
doc/FAQ.md
147
doc/FAQ.md
@@ -4,6 +4,33 @@
|
|||||||
|
|
||||||
## Installation & loading
|
## Installation & loading
|
||||||
|
|
||||||
|
**Q: How do I install profile automatically into my shell startup files?**
|
||||||
|
|
||||||
|
Run the installer directly (no need to source first):
|
||||||
|
```bash
|
||||||
|
bash <installpath>/profile/profile.sh --install
|
||||||
|
```
|
||||||
|
This appends the required `source` line to both `~/.bashrc` and `~/.profile`.
|
||||||
|
To target only one file:
|
||||||
|
```bash
|
||||||
|
bash <installpath>/profile/profile.sh --install --bashrc
|
||||||
|
bash <installpath>/profile/profile.sh --install --profile
|
||||||
|
```
|
||||||
|
The operation is idempotent — running it again will not add a duplicate line.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Q: I ran `profile.sh` directly and got a warning about sourcing.**
|
||||||
|
|
||||||
|
profile.sh is designed to be *sourced*, not executed:
|
||||||
|
```bash
|
||||||
|
source <installpath>/profile/profile.sh
|
||||||
|
```
|
||||||
|
The only exception is `--install`, which must be passed to a direct execution
|
||||||
|
(`bash profile.sh --install`) to set up the sourcing line automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**Q: profile refuses to load and prints "This profile requires Bash 4.3 or higher."**
|
**Q: profile refuses to load and prints "This profile requires Bash 4.3 or higher."**
|
||||||
|
|
||||||
Your system's default shell is an older Bash (common on macOS, which ships
|
Your system's default shell is an older Bash (common on macOS, which ships
|
||||||
@@ -25,6 +52,33 @@ scripts start with `#!/usr/bin/env bash`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
**Q: Can I use profile functions in scripts?**
|
||||||
|
|
||||||
|
Yes. The supported way is to source `profile.sh` from a Bash script:
|
||||||
|
```bash
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
source /path/to/profile/profile.sh
|
||||||
|
|
||||||
|
taz -p auto -f lz mydir
|
||||||
|
```
|
||||||
|
You can also source one module directly (for example
|
||||||
|
`profile.d/compress.sh`) if you only need a subset of functions.
|
||||||
|
|
||||||
|
When you source a module directly, profile configuration parsing/loading from
|
||||||
|
`profile.sh` is skipped, so defaults from `profile.conf` are not applied unless
|
||||||
|
your script loads them explicitly.
|
||||||
|
|
||||||
|
`profile.sh` also detects whether the current shell is interactive. In
|
||||||
|
non-interactive shells (typical script execution), interactive-only features
|
||||||
|
are intentionally disabled: prompt setup, aliases, welcome/info messages, and
|
||||||
|
startup update checks are not enabled.
|
||||||
|
|
||||||
|
In all cases, avoid aliases in scripts. Use real commands/functions instead,
|
||||||
|
because alias expansion is interactive-shell oriented and can be disabled or
|
||||||
|
behave differently in non-interactive execution.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**Q: I set `PROFILE_PATH` but profile still can't find its modules.**
|
**Q: I set `PROFILE_PATH` but profile still can't find its modules.**
|
||||||
|
|
||||||
`PROFILE_PATH` must be exported *before* you source `profile.sh`:
|
`PROFILE_PATH` must be exported *before* you source `profile.sh`:
|
||||||
@@ -84,7 +138,8 @@ Add to `profile.conf`:
|
|||||||
PROMPT_THEME = dark
|
PROMPT_THEME = dark
|
||||||
```
|
```
|
||||||
Built-in names: `default`, `dark`, `light`, `solarized`, `solarized-light`,
|
Built-in names: `default`, `dark`, `light`, `solarized`, `solarized-light`,
|
||||||
`monokai`, `monochrome`, `abyss`, `plasma`, `adwaita`.
|
`monokai`, `monochrome`, `abyss`, `plasma`, `adwaita`, but you can create your
|
||||||
|
own theme.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -119,6 +174,55 @@ theme file cannot execute code. Values must be a colour variable reference
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Git helpers
|
||||||
|
|
||||||
|
**Q: What git helper functions does profile provide?**
|
||||||
|
|
||||||
|
All git helpers are defined in `profile.d/git.sh` (new in 4.1.0):
|
||||||
|
|
||||||
|
| Command | Purpose |
|
||||||
|
|---|---|
|
||||||
|
| `gst` | Compact status with branch tracking info |
|
||||||
|
| `ggraph` | Decorated history graph |
|
||||||
|
| `gsync` | Fetch and rebase onto upstream |
|
||||||
|
| `gacp` | Add, commit and push in one command |
|
||||||
|
| `greset` | Reset to upstream, stashing local changes first |
|
||||||
|
| `gwip` | Quick WIP checkpoint commit |
|
||||||
|
| `gprune` | Delete merged local branches |
|
||||||
|
| `groot` | Print or cd to repository root |
|
||||||
|
|
||||||
|
All commands accept `-h` / `--help`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Q: Tab completion for `gacp` does not show modified files.**
|
||||||
|
|
||||||
|
Profile ships dedicated completions in `profile.d/bash-completion/git-completion.sh`,
|
||||||
|
loaded automatically in interactive sessions. If completions are missing,
|
||||||
|
check that the system git completion is installed:
|
||||||
|
```bash
|
||||||
|
# Debian / Ubuntu
|
||||||
|
apt-get install bash-completion
|
||||||
|
# Fedora / RHEL
|
||||||
|
dnf install bash-completion
|
||||||
|
```
|
||||||
|
When the native git completion helpers are available, `gacp` path completion
|
||||||
|
behaves exactly like `git add` (modified files, untracked files, directories).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Q: `gacp` says "No files specified" even though I passed `-a`.**
|
||||||
|
|
||||||
|
The `-a` / `--auto` flag adds all modified files (equivalent to `git add -A`).
|
||||||
|
The default depends on `GIT_GACP_AUTO_ADD` in `profile.conf`:
|
||||||
|
```ini
|
||||||
|
[git]
|
||||||
|
GIT_GACP_AUTO_ADD = 1
|
||||||
|
```
|
||||||
|
Set to `1` to make `-a` the default.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
|
|
||||||
**Q: `meteo` prints "No city specified" even though I set a default.**
|
**Q: `meteo` prints "No city specified" even though I set a default.**
|
||||||
@@ -147,11 +251,46 @@ Or set `DWL_PREFERRED_TOOL` in `[net]` to whichever tool you have.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
**Q: How do I limit how long `dwl` waits for a download?**
|
||||||
|
|
||||||
|
Use the `-t` / `--timeout` option:
|
||||||
|
```bash
|
||||||
|
dwl -t 5 https://example.com/file.txt /tmp/file.txt
|
||||||
|
```
|
||||||
|
This sets a 5-second cap on both the connection and the overall transfer.
|
||||||
|
The timeout is propagated to `curl` (`--max-time` + `--connect-timeout`),
|
||||||
|
`wget` (`--timeout`), or `fetch` (`-T`) transparently.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Q: The prompt takes a long time to appear when my network is unavailable.**
|
||||||
|
|
||||||
|
Fixed in 4.1.0. `check_updates -q` (called at startup) now enforces a
|
||||||
|
3-second network timeout. If the update server is unreachable the check
|
||||||
|
fails silently and the prompt appears immediately.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Q: `help` only shows a list of functions. Can I get usage for a specific one?**
|
||||||
|
|
||||||
|
Yes — pass the command name as an argument:
|
||||||
|
```bash
|
||||||
|
help gacp
|
||||||
|
help dwl
|
||||||
|
help taz
|
||||||
|
```
|
||||||
|
This calls `<command> --help` and prints the full usage for that function.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**Q: `pkgs` does not find packages I know are installed.**
|
**Q: `pkgs` does not find packages I know are installed.**
|
||||||
|
|
||||||
`pkgs` delegates to `dpkg -l` (Debian/Ubuntu) or `rpm -qa` (RHEL/Fedora).
|
`pkgs` uses `get_pkgmgr` to detect the active package manager and delegates
|
||||||
If your distribution uses a different package manager (pacman, apk, brew …)
|
to the appropriate tool. Supported families: `apt` (Debian/Ubuntu),
|
||||||
it is not yet supported. See `doc/todo.md` for the tracking issue.
|
`dnf` / `yum` (RHEL/Fedora), `zypper` (openSUSE), `pacman` (Arch),
|
||||||
|
`apk` (Alpine), `portage` (Gentoo), `xbps` (Void), `nix`, `brew` (macOS).
|
||||||
|
If your distribution is not detected, run `get_pkgmgr` to see what is
|
||||||
|
identified, and check that the package manager binary is in your `PATH`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
36
doc/known-bugs.md
Executable file
36
doc/known-bugs.md
Executable file
@@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
# Known bugs
|
||||||
|
|
||||||
|
This document tracks currently known issues and limitations.
|
||||||
|
|
||||||
|
## Open issues
|
||||||
|
|
||||||
|
- **Prompt execution time is inaccurate in Windows Terminal (WSL)**
|
||||||
|
- **Status:** open, likely not fully fixable with the current Bash prompt model.
|
||||||
|
- **Symptoms:** in Windows Terminal, the displayed duration includes idle time
|
||||||
|
and typing time, and is consistently higher than real command execution time.
|
||||||
|
Behavior differs across terminal environments:
|
||||||
|
- In a native Linux terminal (including Linux shells launched through WSL),
|
||||||
|
timing starts when Enter is pressed and stops when the prompt is shown again.
|
||||||
|
- In Windows Terminal, timing appears to start/stop on prompt display events.
|
||||||
|
- **Technical context:** execution time is measured from a `DEBUG` trap plus
|
||||||
|
`PROMPT_COMMAND`, using `date +%s%N` deltas. In WSL + Windows Terminal,
|
||||||
|
timer precision and scheduling behavior can introduce jitter that does not
|
||||||
|
match wall-clock perception.
|
||||||
|
- **Likely cause:** Windows Terminal does not handle Bash timing-related events
|
||||||
|
in the same way as native Linux terminals.
|
||||||
|
- **Impact:** cosmetic/observability issue only. Commands are executed normally.
|
||||||
|
- **Workarounds:**
|
||||||
|
- Use a native Linux terminal under WSL (for example QTerminal, Terminator,
|
||||||
|
Konsole, etc.) to recover the expected Enter→prompt timing behavior.
|
||||||
|
- Use `/usr/bin/time -p <command>` (or `time <command>`) when accurate timing is needed.
|
||||||
|
- Treat prompt timing as an approximate indicator in this environment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Rain/Matrix rendering is slow on Windows
|
||||||
|
|
||||||
|
- **Description:** The rain and matrix terminal effects are significantly slower on Windows, especially with high density settings.
|
||||||
|
- **Cause:** This is due to the way Windows handles terminal display updates, which is inherently less efficient than on Unix-like systems.
|
||||||
|
- **Status:** Not fixable in Bash; this is a limitation of Windows terminal design.
|
||||||
|
- **Workaround:** Lower the density parameter for better performance, or use a Unix-like environment for optimal speed.
|
||||||
@@ -30,8 +30,10 @@ TERM=xterm-256color
|
|||||||
# Supported: lz (default), xz, bz2, gz, lzo, tar, zip, zst
|
# Supported: lz (default), xz, bz2, gz, lzo, tar, zip, zst
|
||||||
#TAZ_DEFAULT_FORMAT=lz
|
#TAZ_DEFAULT_FORMAT=lz
|
||||||
|
|
||||||
# taz: Number of compression threads (0 = auto-detect CPU count).
|
# taz: Number of compression threads.
|
||||||
#TAZ_DEFAULT_THREADS=0
|
# auto — detect CPU count at runtime (default)
|
||||||
|
# N — explicit positive integer
|
||||||
|
#TAZ_DEFAULT_THREADS=auto
|
||||||
|
|
||||||
# taz: Compression level 1 (fast/large) … 9 (slow/small).
|
# taz: Compression level 1 (fast/large) … 9 (slow/small).
|
||||||
#TAZ_DEFAULT_LEVEL=6
|
#TAZ_DEFAULT_LEVEL=6
|
||||||
@@ -169,6 +171,24 @@ TERM=xterm-256color
|
|||||||
#
|
#
|
||||||
# Working directory
|
# Working directory
|
||||||
#PROMPT_COLOR_DIR_FG=$ICyan
|
#PROMPT_COLOR_DIR_FG=$ICyan
|
||||||
|
#
|
||||||
|
# Context segment (Git branch / Conda environment) on the top bar
|
||||||
|
#PROMPT_COLOR_CTX_FG=$BIYellow
|
||||||
|
#
|
||||||
|
# Show Git branch at the end of the top bar when inside a repository.
|
||||||
|
#PROMPT_SHOW_GIT=1
|
||||||
|
#
|
||||||
|
# Include Git dirty marker and upstream drift (+ahead/-behind) in the context.
|
||||||
|
#PROMPT_SHOW_GIT_STATUS=1
|
||||||
|
#
|
||||||
|
# Show Conda environment name at the end of the top bar when active.
|
||||||
|
#PROMPT_SHOW_CONDA=1
|
||||||
|
#
|
||||||
|
# Show Python venv name when active (ignored if Conda is active).
|
||||||
|
#PROMPT_SHOW_VENV=1
|
||||||
|
#
|
||||||
|
# Show session markers (ssh, tmux, screen) when applicable.
|
||||||
|
#PROMPT_SHOW_SESSION=1
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
[pwd]
|
[pwd]
|
||||||
@@ -205,12 +225,20 @@ TERM=xterm-256color
|
|||||||
# rain: Colour theme. Supported: white (default), green, blue, red, yellow, cyan
|
# rain: Colour theme. Supported: white (default), green, blue, red, yellow, cyan
|
||||||
#RAIN_DEFAULT_COLOR=white
|
#RAIN_DEFAULT_COLOR=white
|
||||||
|
|
||||||
|
# rain: Maximum number of simultaneous falling elements.
|
||||||
|
# Leave unset to keep the terminal-size-based dynamic default.
|
||||||
|
#RAIN_DEFAULT_DENSITY=80
|
||||||
|
|
||||||
# matrix: Falling speed.
|
# matrix: Falling speed.
|
||||||
#MATRIX_DEFAULT_SPEED=3.5
|
#MATRIX_DEFAULT_SPEED=3.5
|
||||||
|
|
||||||
# matrix: Colour theme. Supported: green (default), blue, red, yellow, cyan, white
|
# matrix: Colour theme. Supported: green (default), blue, red, yellow, cyan, white
|
||||||
#MATRIX_DEFAULT_COLOR=green
|
#MATRIX_DEFAULT_COLOR=green
|
||||||
|
|
||||||
|
# matrix: Maximum number of simultaneous falling elements.
|
||||||
|
# Leave unset to keep the terminal-size-based dynamic default.
|
||||||
|
#MATRIX_DEFAULT_DENSITY=120
|
||||||
|
|
||||||
# matrix: Character set. Supported: binary (default), kana, ascii
|
# matrix: Character set. Supported: binary (default), kana, ascii
|
||||||
#MATRIX_DEFAULT_CHARSET=binary
|
#MATRIX_DEFAULT_CHARSET=binary
|
||||||
|
|
||||||
|
|||||||
@@ -191,6 +191,10 @@ SET_LOCALE="fr:fr_FR.UTF-8,us:en_US.UTF-8"
|
|||||||
# Supported values: white (default), green, blue, red, yellow, cyan
|
# Supported values: white (default), green, blue, red, yellow, cyan
|
||||||
#RAIN_DEFAULT_COLOR=white
|
#RAIN_DEFAULT_COLOR=white
|
||||||
|
|
||||||
|
# rain: Maximum number of simultaneous falling elements.
|
||||||
|
# Leave unset to keep the terminal-size-based dynamic default.
|
||||||
|
#RAIN_DEFAULT_DENSITY=80
|
||||||
|
|
||||||
# matrix: Default speed value, using the /100 scale (3.5 => 0.035s).
|
# matrix: Default speed value, using the /100 scale (3.5 => 0.035s).
|
||||||
#MATRIX_DEFAULT_SPEED=3.5
|
#MATRIX_DEFAULT_SPEED=3.5
|
||||||
|
|
||||||
@@ -198,6 +202,10 @@ SET_LOCALE="fr:fr_FR.UTF-8,us:en_US.UTF-8"
|
|||||||
# Supported values: green (default), blue, red, yellow, cyan, white
|
# Supported values: green (default), blue, red, yellow, cyan, white
|
||||||
#MATRIX_DEFAULT_COLOR=green
|
#MATRIX_DEFAULT_COLOR=green
|
||||||
|
|
||||||
|
# matrix: Maximum number of simultaneous falling elements.
|
||||||
|
# Leave unset to keep the terminal-size-based dynamic default.
|
||||||
|
#MATRIX_DEFAULT_DENSITY=120
|
||||||
|
|
||||||
# matrix: Default character set.
|
# matrix: Default character set.
|
||||||
# Supported values: binary (default), kana, ascii
|
# Supported values: binary (default), kana, ascii
|
||||||
MATRIX_DEFAULT_CHARSET=kana
|
MATRIX_DEFAULT_CHARSET=kana
|
||||||
|
|||||||
15
doc/todo.md
15
doc/todo.md
@@ -12,7 +12,7 @@ version-bump.
|
|||||||
blockers are `local -A` (no associative arrays in ZSH without `typeset -A`)
|
blockers are `local -A` (no associative arrays in ZSH without `typeset -A`)
|
||||||
and `local -n` namerefs. A thin compatibility shim would open the project to
|
and `local -n` namerefs. A thin compatibility shim would open the project to
|
||||||
ZSH users. **[hard]**
|
ZSH users. **[hard]**
|
||||||
- [ ] **Bash completion** — add a `profile.d/completion/` directory and write
|
- [ ] **Bash completion** — add a more bash completion directory and write
|
||||||
`_profile_upgrade`, `_taz`, `_utaz`, `_meteo`, etc. completions so that
|
`_profile_upgrade`, `_taz`, `_utaz`, `_meteo`, etc. completions so that
|
||||||
`<Tab>` works on all public functions. **[medium]**
|
`<Tab>` works on all public functions. **[medium]**
|
||||||
|
|
||||||
@@ -20,11 +20,14 @@ version-bump.
|
|||||||
|
|
||||||
## Prompt & theming
|
## Prompt & theming
|
||||||
|
|
||||||
- [ ] **Git branch in prompt** — show the current branch name (and dirty
|
- [x] **Git branch in prompt** — show the current branch name (with dirty and
|
||||||
indicator) in the PS1 bar when inside a Git repository. Should be
|
upstream drift indicators) in the PS1 bar when inside a Git repository,
|
||||||
gated behind a `[prompt]` config key so it can be disabled. **[medium]**
|
gated by `[prompt]` config keys. **[medium]**
|
||||||
- [ ] **Virtual-env / conda indicator** — detect `$VIRTUAL_ENV` / `$CONDA_DEFAULT_ENV`
|
- [x] **Virtual-env / conda indicator** — detect `$VIRTUAL_ENV` / `$CONDA_DEFAULT_ENV`
|
||||||
and display the name in the prompt bar. **[easy]**
|
and display the active environment in the prompt bar. **[easy]**
|
||||||
|
- [x] **Session context markers** — display lightweight session markers
|
||||||
|
(`ssh`, `tmux`, `screen`) at the end of the prompt bar, gated by
|
||||||
|
`[prompt]` config keys. **[easy]**
|
||||||
- [ ] **True-colour terminal auto-detection** — query `$COLORTERM` and
|
- [ ] **True-colour terminal auto-detection** — query `$COLORTERM` and
|
||||||
`$TERM` at load time; automatically fall back from a 24-bit theme to its
|
`$TERM` at load time; automatically fall back from a 24-bit theme to its
|
||||||
16-colour equivalent when the terminal does not support true colour. **[medium]**
|
16-colour equivalent when the terminal does not support true colour. **[medium]**
|
||||||
|
|||||||
220
profile.d/bash-completion/git-completion.sh
Normal file
220
profile.d/bash-completion/git-completion.sh
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Git helper completions for profile.d/git.sh shortcuts.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Return 0 when current directory is inside a git work tree.
|
||||||
|
_profile_git_in_repo()
|
||||||
|
{
|
||||||
|
git rev-parse --is-inside-work-tree >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load git completion helpers on demand if they are available on the system.
|
||||||
|
_profile_git_load_completion_helpers()
|
||||||
|
{
|
||||||
|
declare -F __git_complete >/dev/null 2>&1 && return 0
|
||||||
|
|
||||||
|
local completion_file
|
||||||
|
for completion_file in \
|
||||||
|
/usr/share/bash-completion/completions/git \
|
||||||
|
/usr/share/git/completion/git-completion.bash \
|
||||||
|
/etc/bash_completion.d/git
|
||||||
|
do
|
||||||
|
if [[ -r "$completion_file" ]]; then
|
||||||
|
# shellcheck source=/dev/null
|
||||||
|
. "$completion_file"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
declare -F __git_complete >/dev/null 2>&1
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_git_complete_remotes()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
if ! _profile_git_in_repo; then
|
||||||
|
COMPREPLY=()
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMPREPLY=( $(compgen -W "$(git remote 2>/dev/null)" -- "$cur") )
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_git_complete_refs()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
if ! _profile_git_in_repo; then
|
||||||
|
COMPREPLY=()
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMPREPLY=( $(compgen -W "$(git for-each-ref --format='%(refname:short)' refs/heads refs/remotes refs/tags 2>/dev/null)" -- "$cur") )
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_git_complete_add_paths()
|
||||||
|
{
|
||||||
|
# shellcheck disable=SC2034 # Used indirectly by git-completion helpers via dynamic scope.
|
||||||
|
local cur words cword prev __git_cmd_idx=0
|
||||||
|
local complete_opt="--others --modified --directory --no-empty-directory"
|
||||||
|
|
||||||
|
if declare -F __git_complete_index_file >/dev/null 2>&1; then
|
||||||
|
if declare -F _get_comp_words_by_ref >/dev/null 2>&1; then
|
||||||
|
_get_comp_words_by_ref -n =: cur words cword prev
|
||||||
|
else
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
if (( COMP_CWORD > 0 )); then
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
else
|
||||||
|
prev=""
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC2034 # Used indirectly by git-completion helpers via dynamic scope.
|
||||||
|
cword="$COMP_CWORD"
|
||||||
|
# shellcheck disable=SC2034 # Used indirectly by git-completion helpers via dynamic scope.
|
||||||
|
words=("${COMP_WORDS[@]}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n $(__git_find_on_cmdline "-u --update") ]]; then
|
||||||
|
complete_opt="--modified"
|
||||||
|
fi
|
||||||
|
__git_complete_index_file "$complete_opt"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMPREPLY=( $(compgen -f -- "${COMP_WORDS[COMP_CWORD]}") )
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_gst()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
case "$cur" in
|
||||||
|
-*)
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help" -- "$cur") )
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
COMPREPLY=( $(compgen -d -- "$cur") )
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_ggraph()
|
||||||
|
{
|
||||||
|
local cur prev
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
|
||||||
|
case "$prev" in
|
||||||
|
-n|--limit)
|
||||||
|
COMPREPLY=()
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help -n --limit" -- "$cur") )
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_gsync()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help" -- "$cur") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_profile_git_complete_remotes
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_gacp()
|
||||||
|
{
|
||||||
|
local cur prev
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
|
||||||
|
case "$prev" in
|
||||||
|
-m|--message)
|
||||||
|
COMPREPLY=()
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help -a --auto -m --message" -- "$cur") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_profile_git_complete_add_paths
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_greset()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help -x --with-ignored" -- "$cur") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_profile_git_complete_refs
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_gwip()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help" -- "$cur") )
|
||||||
|
else
|
||||||
|
COMPREPLY=()
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_gprune()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
if [[ $cur == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help" -- "$cur") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_profile_git_complete_refs
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_groot()
|
||||||
|
{
|
||||||
|
local cur
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help -g --go" -- "$cur") )
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_git_register_completions()
|
||||||
|
{
|
||||||
|
complete -F _complete_gst gst
|
||||||
|
complete -F _complete_ggraph ggraph
|
||||||
|
complete -F _complete_gsync gsync
|
||||||
|
complete -F _complete_gacp gacp
|
||||||
|
complete -F _complete_greset greset
|
||||||
|
complete -F _complete_gwip gwip
|
||||||
|
complete -F _complete_gprune gprune
|
||||||
|
complete -F _complete_groot groot
|
||||||
|
}
|
||||||
|
|
||||||
|
# Register completions only in interactive bash sessions.
|
||||||
|
if [[ $- == *i* && -n ${BASH_VERSION:-} ]]; then
|
||||||
|
_profile_git_load_completion_helpers >/dev/null 2>&1 || true
|
||||||
|
_profile_git_register_completions
|
||||||
|
fi
|
||||||
|
|
||||||
|
# EOF
|
||||||
52
profile.d/bash-completion/prompt-completion.sh
Executable file
52
profile.d/bash-completion/prompt-completion.sh
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Prompt helper completions for profile.d/prompt.sh shortcuts.
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_profile_prompt_complete_theme_names()
|
||||||
|
{
|
||||||
|
local theme_dir="${PROMPT_THEME_DIR:-${MYPATH}/profile.d/themes}"
|
||||||
|
|
||||||
|
[[ -d "$theme_dir" ]] || return 0
|
||||||
|
|
||||||
|
local theme_file theme_names=""
|
||||||
|
for theme_file in "$theme_dir"/*.theme; do
|
||||||
|
[[ -f "$theme_file" ]] || continue
|
||||||
|
theme_names+=" ${theme_file##*/}"
|
||||||
|
theme_names="${theme_names%.theme}"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "%s\n" "$theme_names"
|
||||||
|
}
|
||||||
|
|
||||||
|
_complete_set_theme()
|
||||||
|
{
|
||||||
|
local cur prev
|
||||||
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||||
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||||
|
|
||||||
|
case "$prev" in
|
||||||
|
-h|--help|-l|--list)
|
||||||
|
COMPREPLY=()
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [[ "$cur" == -* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -W "-h --help -l --list" -- "$cur") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$cur" == */* || "$cur" == .* ]]; then
|
||||||
|
COMPREPLY=( $(compgen -f -X '!*.theme' -- "$cur") )
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
COMPREPLY=( $(compgen -W "$(_profile_prompt_complete_theme_names)" -- "$cur") )
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $- == *i* && -n ${BASH_VERSION:-} ]]; then
|
||||||
|
complete -F _complete_set_theme set_theme
|
||||||
|
fi
|
||||||
|
|
||||||
|
# EOF
|
||||||
@@ -395,18 +395,32 @@ export -f utaz
|
|||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Compress directories or files into one or more archive
|
# Compress directories or files into one or more archive
|
||||||
# Usage: taz [option] [--parallel=<n>] [--format=<format>] [directory1 ... directoryN]
|
# Usage: taz [option] [--parallel=<n|auto>] [--format=<format>] [directory1 ... directoryN]
|
||||||
# Options:
|
# Options:
|
||||||
# -h, --help Display that help screen
|
# -h, --help Display that help screen
|
||||||
# -d, --delete Delete source file or directory after success
|
# -d, --delete Delete source file or directory after success
|
||||||
# -f, --format Chose archive format in the given list. If several format are
|
# -f, --format Chose archive format in the given list. If several format are
|
||||||
# given, the smalest is kept
|
# given, the smalest is kept
|
||||||
# -p, --parallel Number of threads to use (if allowed by underlying utility)
|
# -p, --parallel Number of threads to use, or 'auto' to use detected CPU count
|
||||||
# -v, --verbose Display progress where possible
|
# -v, --verbose Display progress where possible
|
||||||
# -q, --quiet Display less messages (only errors and warnings)
|
# -q, --quiet Display less messages (only errors and warnings)
|
||||||
# -1, .., -9 Compression level to use [1=fast/biggest, 9=slow/smallest]
|
# -1, .., -9 Compression level to use [1=fast/biggest, 9=slow/smallest]
|
||||||
taz()
|
taz()
|
||||||
{
|
{
|
||||||
|
# Resolve runtime CPU count for --parallel=auto.
|
||||||
|
_taz_detect_cpus()
|
||||||
|
{
|
||||||
|
local cpus=1
|
||||||
|
if command -v nproc >/dev/null 2>&1; then
|
||||||
|
cpus=$(nproc 2>/dev/null)
|
||||||
|
elif command -v getconf >/dev/null 2>&1; then
|
||||||
|
cpus=$(getconf _NPROCESSORS_ONLN 2>/dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ $cpus =~ ^[1-9][0-9]*$ ]] || cpus=1
|
||||||
|
printf "%s\n" "$cpus"
|
||||||
|
}
|
||||||
|
|
||||||
# shellcheck disable=SC2329
|
# shellcheck disable=SC2329
|
||||||
_doxz()
|
_doxz()
|
||||||
{
|
{
|
||||||
@@ -476,7 +490,7 @@ taz()
|
|||||||
[[ $4 ]] && opt=('--verbose')
|
[[ $4 ]] && opt=('--verbose')
|
||||||
opt+=("$procopt")
|
opt+=("$procopt")
|
||||||
|
|
||||||
# Compresse au format bz2
|
# Compress with gzip
|
||||||
$command "${opt[@]}" --keep "-$3" "$1"
|
$command "${opt[@]}" --keep "-$3" "$1"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
@@ -520,7 +534,7 @@ taz()
|
|||||||
[[ $4 ]] && verb=('-v')
|
[[ $4 ]] && verb=('-v')
|
||||||
[[ $2 -gt 1 ]] && disp W "lzop doesn't support multithreading, falling back to 1 thread."
|
[[ $2 -gt 1 ]] && disp W "lzop doesn't support multithreading, falling back to 1 thread."
|
||||||
|
|
||||||
# Compresse au format lzo
|
# Compress with lzo
|
||||||
lzop "${verb[@]}" --keep "-$3" "$1"
|
lzop "${verb[@]}" --keep "-$3" "$1"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
@@ -537,13 +551,13 @@ taz()
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
-h|--help)
|
-h|--help)
|
||||||
printf "taz: archive all files of a directory.\n\n"
|
printf "taz: archive all files of a directory.\n\n"
|
||||||
printf "Usage: taz [option] [--parallel=<n>] [--format=<format>] [directory1 ... directoryN]\n\n"
|
printf "Usage: taz [option] [--parallel=<n|auto>] [--format=<format>] [directory1 ... directoryN]\n\n"
|
||||||
printf "Options:\n"
|
printf "Options:\n"
|
||||||
printf "\t-h, --help\tDisplay that help screen\n"
|
printf "\t-h, --help\tDisplay that help screen\n"
|
||||||
printf "\t-d, --delete\tDelete source file or directory after success\n"
|
printf "\t-d, --delete\tDelete source file or directory after success\n"
|
||||||
printf "\t-f, --format\tChose archive format in the given list. If several format are"
|
printf "\t-f, --format\tChose archive format in the given list. If several format are\n"
|
||||||
printf "\t\t\tgiven, the smalest is kept\n"
|
printf "\t\t\tgiven, the smalest is kept\n"
|
||||||
printf "\t-p, --parallel\tNumber of threads to use (if allowed by underlying utility)\n"
|
printf "\t-p, --parallel\tNumber of threads, or 'auto' for runtime CPU count\n"
|
||||||
printf "\t-v, --verbose\tDisplay progress where possible\n"
|
printf "\t-v, --verbose\tDisplay progress where possible\n"
|
||||||
printf "\t-q, --quiet\tDisplay less messages (only errors and warnings)\n"
|
printf "\t-q, --quiet\tDisplay less messages (only errors and warnings)\n"
|
||||||
printf "\t-1, .., -9\tCompression level to use [1=fast/biggest, 9=slow/smallest]\n\n"
|
printf "\t-1, .., -9\tCompression level to use [1=fast/biggest, 9=slow/smallest]\n\n"
|
||||||
@@ -606,11 +620,20 @@ taz()
|
|||||||
[[ ${#FILES[@]} -eq 0 ]] && FILES=(".")
|
[[ ${#FILES[@]} -eq 0 ]] && FILES=(".")
|
||||||
|
|
||||||
[[ ! $compform ]] && compform=${TAZ_DEFAULT_FORMAT:-lz}
|
[[ ! $compform ]] && compform=${TAZ_DEFAULT_FORMAT:-lz}
|
||||||
[[ ! $nproc ]] && nproc=${TAZ_DEFAULT_THREADS:-1}
|
[[ ! $nproc ]] && nproc=${TAZ_DEFAULT_THREADS:-auto}
|
||||||
[[ ! $complevel ]] && complevel=${TAZ_DEFAULT_LEVEL:-6}
|
[[ ! $complevel ]] && complevel=${TAZ_DEFAULT_LEVEL:-6}
|
||||||
[[ $verbose -gt 1 && $quiet -gt 1 ]] &&
|
[[ $verbose -gt 1 && $quiet -gt 1 ]] &&
|
||||||
disp E "The --verbose and --quiet options can't be used together."
|
disp E "The --verbose and --quiet options can't be used together."
|
||||||
|
|
||||||
|
# Backward compatibility: 0 previously meant auto-detect.
|
||||||
|
[[ $nproc == 0 ]] && nproc=auto
|
||||||
|
if [[ $nproc == auto ]]; then
|
||||||
|
nproc=$(_taz_detect_cpus)
|
||||||
|
elif [[ ! $nproc =~ ^[1-9][0-9]*$ ]]; then
|
||||||
|
disp E "Invalid value for --parallel: '$nproc' (expected auto or a positive integer)."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
for item in "${FILES[@]}"; do
|
for item in "${FILES[@]}"; do
|
||||||
local donetar=0
|
local donetar=0
|
||||||
disp I "Processing $item..."
|
disp I "Processing $item..."
|
||||||
|
|||||||
@@ -128,52 +128,107 @@ export -f set_colors
|
|||||||
# D : debug (cyan)
|
# D : debug (cyan)
|
||||||
disp()
|
disp()
|
||||||
{
|
{
|
||||||
|
_disp_print_wrapped()
|
||||||
|
{
|
||||||
|
local prefix="$1"
|
||||||
|
local prefix_len="$2"
|
||||||
|
local target_fd="$3"
|
||||||
|
shift 3
|
||||||
|
local message="$*"
|
||||||
|
|
||||||
|
local cols="${COLUMNS:-}"
|
||||||
|
if [[ -z "$cols" || ! "$cols" =~ ^[0-9]+$ || "$cols" -lt 20 ]]; then
|
||||||
|
cols=$(tput cols 2>/dev/null)
|
||||||
|
fi
|
||||||
|
[[ -z "$cols" || ! "$cols" =~ ^[0-9]+$ || "$cols" -lt 20 ]] && cols=80
|
||||||
|
|
||||||
|
local indent_len=0
|
||||||
|
[[ "$prefix_len" =~ ^[0-9]+$ && "$prefix_len" -gt 0 ]] && indent_len=$((prefix_len + 1))
|
||||||
|
|
||||||
|
local width=$((cols - indent_len))
|
||||||
|
(( width < 10 )) && width=10
|
||||||
|
|
||||||
|
local wrapped
|
||||||
|
wrapped=$(printf "%s" "$message" | fold -s -w "$width")
|
||||||
|
|
||||||
|
local first_line=1
|
||||||
|
local line
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
if (( first_line )); then
|
||||||
|
if [[ -n "$prefix" ]]; then
|
||||||
|
if [[ "$target_fd" -eq 2 ]]; then
|
||||||
|
printf "%b\n" "${prefix} ${line}${RESETCOL}" >&2
|
||||||
|
else
|
||||||
|
printf "%b\n" "${prefix} ${line}${RESETCOL}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$target_fd" -eq 2 ]]; then
|
||||||
|
printf "%b\n" "${line}${RESETCOL}" >&2
|
||||||
|
else
|
||||||
|
printf "%b\n" "${line}${RESETCOL}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
first_line=0
|
||||||
|
else
|
||||||
|
if [[ "$target_fd" -eq 2 ]]; then
|
||||||
|
printf "%*s%b\n" "$indent_len" "" "${line}${RESETCOL}" >&2
|
||||||
|
else
|
||||||
|
printf "%*s%b\n" "$indent_len" "" "${line}${RESETCOL}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<< "$wrapped"
|
||||||
|
}
|
||||||
|
|
||||||
# Handle NO_COLOR: disable colors if set
|
# Handle NO_COLOR: disable colors if set
|
||||||
local color_enabled=1
|
local color_enabled=1
|
||||||
[[ -n $NO_COLOR ]] && color_enabled=0
|
[[ -n $NO_COLOR ]] && color_enabled=0
|
||||||
|
|
||||||
case ${1^^} in
|
case ${1^^} in
|
||||||
"I")
|
"I")
|
||||||
|
local heads_plain="[ info ]"
|
||||||
if [[ $color_enabled -eq 1 ]]; then
|
if [[ $color_enabled -eq 1 ]]; then
|
||||||
local heads="[ ${IGreen}info${DEFAULTFG} ]"
|
local heads="[ ${IGreen}info${DEFAULTFG} ]"
|
||||||
else
|
else
|
||||||
local heads="[ info ]"
|
local heads="$heads_plain"
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
[[ -z $QUIET || $QUIET -ne 1 ]] && \
|
[[ -z $QUIET || $QUIET -ne 1 ]] && \
|
||||||
printf "%b\n" "${heads} $*${RESETCOL}"
|
_disp_print_wrapped "$heads" "${#heads_plain}" 1 "$*"
|
||||||
;;
|
;;
|
||||||
"W")
|
"W")
|
||||||
|
local heads_plain="[ Warning ]"
|
||||||
if [[ $color_enabled -eq 1 ]]; then
|
if [[ $color_enabled -eq 1 ]]; then
|
||||||
local heads="[ ${IYellow}Warning${DEFAULTFG} ]"
|
local heads="[ ${IYellow}Warning${DEFAULTFG} ]"
|
||||||
else
|
else
|
||||||
local heads="[ Warning ]"
|
local heads="$heads_plain"
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
printf "%b\n" "${heads} $*${RESETCOL}" >&2
|
_disp_print_wrapped "$heads" "${#heads_plain}" 2 "$*"
|
||||||
;;
|
;;
|
||||||
"E")
|
"E")
|
||||||
|
local heads_plain="[ ERROR ]"
|
||||||
if [[ $color_enabled -eq 1 ]]; then
|
if [[ $color_enabled -eq 1 ]]; then
|
||||||
local heads="[ ${IRed}ERROR${DEFAULTFG} ]"
|
local heads="[ ${IRed}ERROR${DEFAULTFG} ]"
|
||||||
else
|
else
|
||||||
local heads="[ ERROR ]"
|
local heads="$heads_plain"
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
printf "%b\n" "${heads} $*${RESETCOL}" >&2
|
_disp_print_wrapped "$heads" "${#heads_plain}" 2 "$*"
|
||||||
;;
|
;;
|
||||||
"D")
|
"D")
|
||||||
|
local heads_plain="[ debug ]"
|
||||||
if [[ $color_enabled -eq 1 ]]; then
|
if [[ $color_enabled -eq 1 ]]; then
|
||||||
local heads="[ ${ICyan}debug${DEFAULTFG} ]"
|
local heads="[ ${ICyan}debug${DEFAULTFG} ]"
|
||||||
else
|
else
|
||||||
local heads="[ debug ]"
|
local heads="$heads_plain"
|
||||||
fi
|
fi
|
||||||
shift
|
shift
|
||||||
[[ -n $DEBUG && $DEBUG -gt 1 ]] && \
|
[[ -n $DEBUG && $DEBUG -gt 1 ]] && \
|
||||||
printf "%b\n" "${heads} $*${RESETCOL}"
|
_disp_print_wrapped "$heads" "${#heads_plain}" 1 "$*"
|
||||||
;;
|
;;
|
||||||
* )
|
* )
|
||||||
[[ -z $QUIET || $QUIET -ne 1 ]] && \
|
[[ -z $QUIET || $QUIET -ne 1 ]] && \
|
||||||
printf "%b\n" "$*"
|
_disp_print_wrapped "" 0 1 "$*"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -181,6 +236,478 @@ export -f disp
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Render Markdown files with terminal formatting
|
||||||
|
# Usage: mdcat [file]
|
||||||
|
mdcat()
|
||||||
|
{
|
||||||
|
_mdcat_style_inline()
|
||||||
|
{
|
||||||
|
local text="$1"
|
||||||
|
local bold_on="" italic_on="" code_on="" style_off=""
|
||||||
|
local link_text_on="" link_url_on=""
|
||||||
|
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
bold_on=$'\e[1m'
|
||||||
|
italic_on=$'\e[3m'
|
||||||
|
code_on="${On_IBlack}${BIWhite}"
|
||||||
|
link_text_on=$'\e[4;96m'
|
||||||
|
link_url_on="$IBlack"
|
||||||
|
style_off="$RESETCOL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply inline transforms in a safe order: code, links, then emphasis.
|
||||||
|
# This prevents emphasis parsing inside code spans or link URLs.
|
||||||
|
while [[ "$text" =~ \[([^][]+)\]\(([^()]+)\) ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local label="${BASH_REMATCH[1]}"
|
||||||
|
local url="${BASH_REMATCH[2]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
if [[ "$label" == "$url" ]]; then
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
text="${before}${link_text_on}${label}${style_off}${after}"
|
||||||
|
else
|
||||||
|
text="${before}${label}${after}"
|
||||||
|
fi
|
||||||
|
elif [[ -z $NO_COLOR ]]; then
|
||||||
|
text="${before}${link_text_on}${label}${style_off} ${link_url_on}(${url})${style_off}${after}"
|
||||||
|
else
|
||||||
|
text="${before}${label} (${url})${after}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Style bare URLs without re-matching the same URL forever.
|
||||||
|
# The prefix capture keeps progress monotonic and prevents freeze loops.
|
||||||
|
# Skip this transformation in NO_COLOR mode.
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
while [[ "$text" =~ (^|[[:space:]\(])(https?://[^[:space:]\)]+) ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local pre="${BASH_REMATCH[1]}"
|
||||||
|
local url="${BASH_REMATCH[2]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${pre}${link_text_on}${url}${style_off}${after}"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
while [[ "$text" =~ \`([^\`]+)\` ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local val="${BASH_REMATCH[1]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${code_on}${val}${style_off}${after}"
|
||||||
|
done
|
||||||
|
|
||||||
|
while [[ "$text" =~ \*\*([^*]+)\*\* ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local val="${BASH_REMATCH[1]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${bold_on}${val}${style_off}${after}"
|
||||||
|
done
|
||||||
|
|
||||||
|
while [[ "$text" =~ __([^_]+)__ ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local val="${BASH_REMATCH[1]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${bold_on}${val}${style_off}${after}"
|
||||||
|
done
|
||||||
|
|
||||||
|
while [[ "$text" =~ \*([^*]+)\* ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local val="${BASH_REMATCH[1]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${italic_on}${val}${style_off}${after}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Match _italic_ only when underscores are outside word-like identifiers.
|
||||||
|
while [[ "$text" =~ (^|[[:space:][:punct:]])_([^[:space:]_][^_]*[^[:space:]_])_([[:space:][:punct:]]|$) ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local pre="${BASH_REMATCH[1]}"
|
||||||
|
local val="${BASH_REMATCH[2]}"
|
||||||
|
local post="${BASH_REMATCH[3]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${pre}${italic_on}${val}${style_off}${post}${after}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Unescape Markdown punctuation escapes, such as \<, \>, \_, and \*.
|
||||||
|
while [[ "$text" =~ \\([[:punct:]]) ]]; do
|
||||||
|
local match="${BASH_REMATCH[0]}"
|
||||||
|
local val="${BASH_REMATCH[1]}"
|
||||||
|
local before="${text%%"$match"*}"
|
||||||
|
local after="${text#*"$match"}"
|
||||||
|
text="${before}${val}${after}"
|
||||||
|
done
|
||||||
|
|
||||||
|
printf "%s\n" "$text"
|
||||||
|
}
|
||||||
|
|
||||||
|
_mdcat_print_hr()
|
||||||
|
{
|
||||||
|
local cols="${COLUMNS:-}"
|
||||||
|
if [[ -z "$cols" || ! "$cols" =~ ^[0-9]+$ || "$cols" -lt 20 ]]; then
|
||||||
|
cols=$(tput cols 2>/dev/null)
|
||||||
|
fi
|
||||||
|
[[ -z "$cols" || ! "$cols" =~ ^[0-9]+$ || "$cols" -lt 20 ]] && cols=80
|
||||||
|
|
||||||
|
local hr
|
||||||
|
printf -v hr "%*s" "$cols" ""
|
||||||
|
hr="${hr// /-}"
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
printf "%b%s%b\n" "$IBlack" "$hr" "$RESETCOL"
|
||||||
|
else
|
||||||
|
printf "%s\n" "$hr"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
_mdcat_print_code_block()
|
||||||
|
{
|
||||||
|
local lang="$1"
|
||||||
|
shift
|
||||||
|
local -a lines=("$@")
|
||||||
|
|
||||||
|
local cols="${COLUMNS:-}"
|
||||||
|
if [[ -z "$cols" || ! "$cols" =~ ^[0-9]+$ || "$cols" -lt 20 ]]; then
|
||||||
|
cols=$(tput cols 2>/dev/null)
|
||||||
|
fi
|
||||||
|
[[ -z "$cols" || ! "$cols" =~ ^[0-9]+$ || "$cols" -lt 20 ]] && cols=80
|
||||||
|
|
||||||
|
local max_inner=$((cols - 4))
|
||||||
|
(( max_inner < 16 )) && max_inner=16
|
||||||
|
|
||||||
|
local width=16 line
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
local line_len=${#line}
|
||||||
|
(( line_len > width )) && width=$line_len
|
||||||
|
done
|
||||||
|
(( width > max_inner )) && width=$max_inner
|
||||||
|
|
||||||
|
local border
|
||||||
|
printf -v border "+-%*s-+" "$width" ""
|
||||||
|
border="${border// /-}"
|
||||||
|
|
||||||
|
local frame_on="" code_on="" off=""
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
frame_on="$IBlack"
|
||||||
|
code_on="$BIWhite"
|
||||||
|
off="$RESETCOL"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%b%s%b\n" "$frame_on" "$border" "$off"
|
||||||
|
if [[ -n "$lang" ]]; then
|
||||||
|
local tag="language: $lang"
|
||||||
|
local wrapped_tag
|
||||||
|
wrapped_tag=$(printf "%s" "$tag" | fold -s -w "$width")
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
printf "%b| %b%-*s%b |%b\n" "$frame_on" "$code_on" "$width" "$line" "$frame_on" "$off"
|
||||||
|
done <<< "$wrapped_tag"
|
||||||
|
printf "%b%s%b\n" "$frame_on" "$border" "$off"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ${#lines[@]} -eq 0 ]]; then
|
||||||
|
printf "%b| %b%-*s%b |%b\n" "$frame_on" "$code_on" "$width" "" "$frame_on" "$off"
|
||||||
|
else
|
||||||
|
for line in "${lines[@]}"; do
|
||||||
|
local wrapped
|
||||||
|
wrapped=$(printf "%s" "$line" | fold -s -w "$width")
|
||||||
|
while IFS= read -r wline || [[ -n "$wline" ]]; do
|
||||||
|
printf "%b| %b%-*s%b |%b\n" "$frame_on" "$code_on" "$width" "$wline" "$frame_on" "$off"
|
||||||
|
done <<< "$wrapped"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
printf "%b%s%b\n" "$frame_on" "$border" "$off"
|
||||||
|
}
|
||||||
|
|
||||||
|
_mdcat_print_table()
|
||||||
|
{
|
||||||
|
local -a lines=("$@")
|
||||||
|
local -a table_rows=()
|
||||||
|
local -a col_widths=()
|
||||||
|
local i j ncols=0
|
||||||
|
local sep=$'\x1f'
|
||||||
|
|
||||||
|
_mdcat_parse_table_row()
|
||||||
|
{
|
||||||
|
local input="$1"
|
||||||
|
local line
|
||||||
|
line=$(printf '%s' "$input" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')
|
||||||
|
line="${line#|}"
|
||||||
|
line="${line%|}"
|
||||||
|
|
||||||
|
# Parse Markdown cells using only '|' separators and preserve spaces inside cells.
|
||||||
|
local -a cells=()
|
||||||
|
local cell rest="$line"
|
||||||
|
while :; do
|
||||||
|
if [[ "$rest" == *'|'* ]]; then
|
||||||
|
cell="${rest%%|*}"
|
||||||
|
rest="${rest#*|}"
|
||||||
|
else
|
||||||
|
cell="$rest"
|
||||||
|
rest=""
|
||||||
|
fi
|
||||||
|
cell=$(printf '%s' "$cell" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//')
|
||||||
|
cells+=("$cell")
|
||||||
|
[[ -z "$rest" ]] && break
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#cells[@]} -eq 0 ]]; then
|
||||||
|
printf '%s' ""
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local joined="${cells[0]}"
|
||||||
|
for ((j=1; j<${#cells[@]}; ++j)); do
|
||||||
|
joined+="$sep${cells[j]}"
|
||||||
|
done
|
||||||
|
printf '%s' "$joined"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse header and data rows, skipping the Markdown separator row.
|
||||||
|
# Width is computed from visible text length with ANSI escapes stripped.
|
||||||
|
for ((i=0; i<${#lines[@]}; ++i)); do
|
||||||
|
(( i == 1 )) && continue
|
||||||
|
local parsed
|
||||||
|
parsed=$(_mdcat_parse_table_row "${lines[i]}")
|
||||||
|
table_rows+=("$parsed")
|
||||||
|
|
||||||
|
local -a row=()
|
||||||
|
IFS="$sep" read -r -a row <<< "$parsed"
|
||||||
|
(( ncols < ${#row[@]} )) && ncols=${#row[@]}
|
||||||
|
for ((j=0; j<${#row[@]}; ++j)); do
|
||||||
|
local vis
|
||||||
|
vis=$(_mdcat_style_inline "${row[j]}")
|
||||||
|
vis=$(printf '%b' "$vis" | sed -E 's/\x1B\[[0-9;]*[mK]//g')
|
||||||
|
local cell_len=${#vis}
|
||||||
|
[[ -z "${col_widths[j]}" ]] && col_widths[j]=0
|
||||||
|
(( col_widths[j] < cell_len )) && col_widths[j]=$cell_len
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ensure all width slots are initialized before drawing borders.
|
||||||
|
for ((j=0; j<ncols; ++j)); do
|
||||||
|
[[ -z "${col_widths[j]}" ]] && col_widths[j]=0
|
||||||
|
done
|
||||||
|
|
||||||
|
# Draw top border
|
||||||
|
local border="+"
|
||||||
|
for ((j=0; j<ncols; ++j)); do
|
||||||
|
local w=$((col_widths[j]+2))
|
||||||
|
border+="$(printf '%*s' "$w" "" | tr ' ' '-')+"
|
||||||
|
done
|
||||||
|
printf "%b\n" "$IBlack$border$RESETCOL"
|
||||||
|
|
||||||
|
# Print header row
|
||||||
|
local -a header=()
|
||||||
|
IFS="$sep" read -r -a header <<< "${table_rows[0]}"
|
||||||
|
printf "%b|" "$IBlack"
|
||||||
|
for ((j=0; j<ncols; ++j)); do
|
||||||
|
local raw_cell="${header[j]:-}"
|
||||||
|
local styled_cell
|
||||||
|
styled_cell=$(_mdcat_style_inline "$raw_cell")
|
||||||
|
local visible
|
||||||
|
visible=$(printf '%b' "$styled_cell" | sed -E 's/\x1B\[[0-9;]*[mK]//g')
|
||||||
|
local pad=$((col_widths[j] - ${#visible}))
|
||||||
|
(( pad < 0 )) && pad=0
|
||||||
|
printf " %b%b%*s%b |" "$BBlue" "$styled_cell" "$pad" "" "$IBlack"
|
||||||
|
done
|
||||||
|
printf "%b\n" "$RESETCOL"
|
||||||
|
|
||||||
|
# Header separator
|
||||||
|
printf "%b|" "$IBlack"
|
||||||
|
for ((j=0; j<ncols; ++j)); do
|
||||||
|
printf " %s |" "$(printf '%*s' "${col_widths[j]}" "" | tr ' ' '-')"
|
||||||
|
done
|
||||||
|
printf "%b\n" "$RESETCOL"
|
||||||
|
|
||||||
|
# Print data rows
|
||||||
|
for ((i=1; i<${#table_rows[@]}; ++i)); do
|
||||||
|
local -a row=()
|
||||||
|
IFS="$sep" read -r -a row <<< "${table_rows[i]}"
|
||||||
|
printf "%b|" "$IBlack"
|
||||||
|
for ((j=0; j<ncols; ++j)); do
|
||||||
|
local raw_cell="${row[j]:-}"
|
||||||
|
local styled_cell
|
||||||
|
styled_cell=$(_mdcat_style_inline "$raw_cell")
|
||||||
|
local visible
|
||||||
|
visible=$(printf '%b' "$styled_cell" | sed -E 's/\x1B\[[0-9;]*[mK]//g')
|
||||||
|
local pad=$((col_widths[j] - ${#visible}))
|
||||||
|
(( pad < 0 )) && pad=0
|
||||||
|
printf " %b%b%*s%b |" "$RESETCOL" "$styled_cell" "$pad" "" "$IBlack"
|
||||||
|
done
|
||||||
|
printf "%b\n" "$RESETCOL"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Draw bottom border
|
||||||
|
printf "%b\n" "$IBlack$border$RESETCOL"
|
||||||
|
}
|
||||||
|
|
||||||
|
local PARSED
|
||||||
|
PARSED=$(getopt -o h --long help -n 'mdcat' -- "$@")
|
||||||
|
# shellcheck disable=SC2181 # getopt return code is checked immediately after
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
disp E "Invalid options, use \"mdcat --help\" to display usage."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
eval set -- "$PARSED"
|
||||||
|
while true; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help)
|
||||||
|
printf "mdcat: Render a Markdown file with terminal formatting.\n"
|
||||||
|
printf "Usage: mdcat [file]\n"
|
||||||
|
printf "If no file is provided, mdcat reads from standard input.\n"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
disp E "Invalid option, use \"mdcat --help\" to display options list"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ $# -gt 1 ]]; then
|
||||||
|
disp E "Too many arguments. Usage: mdcat [file]"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local input_file=""
|
||||||
|
if [[ $# -eq 1 ]]; then
|
||||||
|
input_file="$1"
|
||||||
|
if [[ ! -f "$input_file" ]]; then
|
||||||
|
disp E "File not found: $input_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [[ ! -r "$input_file" ]]; then
|
||||||
|
disp E "File is not readable: $input_file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
elif [[ -t 0 ]]; then
|
||||||
|
disp E "No input provided. Usage: mdcat [file] or: cat file.md | mdcat"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
local in_code=0 code_lang="" raw line
|
||||||
|
local -a code_lines=()
|
||||||
|
local in_table=0
|
||||||
|
local -a table_lines=()
|
||||||
|
while IFS= read -r raw || [[ -n "$raw" ]]; do
|
||||||
|
line="${raw%$'\r'}"
|
||||||
|
|
||||||
|
# Table detection: line with |, next line with | and ---
|
||||||
|
if [[ $in_table -eq 0 && "$line" =~ ^[[:space:]]*\|.*\|[[:space:]]*$ ]]; then
|
||||||
|
local next
|
||||||
|
IFS= read -r next || true
|
||||||
|
# Accept: | --- | --- | or |:---|---:| etc.
|
||||||
|
if [[ "$next" =~ ^[[:space:]]*\|[[:space:]]*:?[-]+:?([[:space:]]*\|[[:space:]]*:?[ -]+:?)*\|[[:space:]]*$ ]]; then
|
||||||
|
in_table=1
|
||||||
|
table_lines=("$line" "$next")
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ $in_table -eq 1 ]]; then
|
||||||
|
# Accept table row if it starts and ends with |
|
||||||
|
if [[ "$line" =~ ^[[:space:]]*\|.*\|[[:space:]]*$ && ! "$line" =~ ^[[:space:]]*\|[[:space:]]*:?[-]+:?([[:space:]]*\|[[:space:]]*:?[ -]+:?)*\|[[:space:]]*$ ]]; then
|
||||||
|
table_lines+=("$line")
|
||||||
|
continue
|
||||||
|
else
|
||||||
|
_mdcat_print_table "${table_lines[@]}"
|
||||||
|
in_table=0
|
||||||
|
table_lines=()
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $in_code -eq 1 ]]; then
|
||||||
|
if [[ "$line" =~ ^\`\`\` ]]; then
|
||||||
|
_mdcat_print_code_block "$code_lang" "${code_lines[@]}"
|
||||||
|
in_code=0
|
||||||
|
code_lang=""
|
||||||
|
code_lines=()
|
||||||
|
else
|
||||||
|
code_lines+=("$line")
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$line" =~ ^\`\`\`[[:space:]]*([^[:space:]]*) ]]; then
|
||||||
|
in_code=1
|
||||||
|
code_lang="${BASH_REMATCH[1]}"
|
||||||
|
code_lines=()
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$line" =~ ^(#{1,6})[[:space:]]+(.*)$ ]]; then
|
||||||
|
local lvl=${#BASH_REMATCH[1]}
|
||||||
|
local title="${BASH_REMATCH[2]}"
|
||||||
|
local h_on=""
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
case "$lvl" in
|
||||||
|
1) h_on="$BBlue" ;;
|
||||||
|
2) h_on="$BCyan" ;;
|
||||||
|
3) h_on="$BGreen" ;;
|
||||||
|
*) h_on="$BIWhite" ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
printf "%b%s%b\n" "$h_on" "$title" "$RESETCOL"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$line" =~ ^[[:space:]]*([\-*_])[[:space:]]*\1[[:space:]]*\1[\-*_[:space:]]*$ ]]; then
|
||||||
|
_mdcat_print_hr
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$line" =~ ^([[:space:]]*)\>[[:space:]]?(.*)$ ]]; then
|
||||||
|
local quote="${BASH_REMATCH[2]}"
|
||||||
|
quote=$(_mdcat_style_inline "$quote")
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
printf "%s%b|%b %b\n" "${BASH_REMATCH[1]}" "$ICyan" "$RESETCOL" "$quote"
|
||||||
|
else
|
||||||
|
printf "%s| %b\n" "${BASH_REMATCH[1]}" "$quote"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$line" =~ ^([[:space:]]*)[-+*][[:space:]]+(.*)$ ]]; then
|
||||||
|
local item="${BASH_REMATCH[2]}"
|
||||||
|
item=$(_mdcat_style_inline "$item")
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
printf "%s%b*%b %b\n" "${BASH_REMATCH[1]}" "$IGreen" "$RESETCOL" "$item"
|
||||||
|
else
|
||||||
|
printf "%s* %b\n" "${BASH_REMATCH[1]}" "$item"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$line" =~ ^([[:space:]]*)([0-9]+)\.[[:space:]]+(.*)$ ]]; then
|
||||||
|
local nitem="${BASH_REMATCH[3]}"
|
||||||
|
nitem=$(_mdcat_style_inline "$nitem")
|
||||||
|
if [[ -z $NO_COLOR ]]; then
|
||||||
|
printf "%s%b%s.%b %b\n" "${BASH_REMATCH[1]}" "$IGreen" "${BASH_REMATCH[2]}" "$RESETCOL" "$nitem"
|
||||||
|
else
|
||||||
|
printf "%s%s. %b\n" "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "$nitem"
|
||||||
|
fi
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%b\n" "$(_mdcat_style_inline "$line")"
|
||||||
|
done < "${input_file:-/dev/stdin}"
|
||||||
|
|
||||||
|
if [[ $in_code -eq 1 ]]; then
|
||||||
|
_mdcat_print_code_block "$code_lang" "${code_lines[@]}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
export -f mdcat
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
# Load disp section variables
|
# Load disp section variables
|
||||||
load_conf disp
|
load_conf disp
|
||||||
set_colors
|
set_colors
|
||||||
|
|||||||
2
profile.d/git.sh
Executable file → Normal file
2
profile.d/git.sh
Executable file → Normal file
@@ -71,7 +71,7 @@ _git_default_branch()
|
|||||||
|
|
||||||
head=$(git symbolic-ref --quiet --short "refs/remotes/${remote}/HEAD" 2>/dev/null) || true
|
head=$(git symbolic-ref --quiet --short "refs/remotes/${remote}/HEAD" 2>/dev/null) || true
|
||||||
if [[ -n $head ]]; then
|
if [[ -n $head ]]; then
|
||||||
printf "%s\n" "${head#${remote}/}"
|
printf "%s\n" "${head#"${remote}"/}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -36,9 +36,21 @@
|
|||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Display list of commands and general informations
|
# Display list of commands and general informations
|
||||||
# Usage: help
|
# Usage: help [command]
|
||||||
help()
|
help()
|
||||||
{
|
{
|
||||||
|
# If a command name is given, delegate to its --help output.
|
||||||
|
if [[ $# -gt 0 && "$1" != "--help" && "$1" != "-h" ]]; then
|
||||||
|
local cmd="$1"
|
||||||
|
if declare -F "$cmd" >/dev/null 2>&1 || command -v "$cmd" >/dev/null 2>&1; then
|
||||||
|
"$cmd" --help
|
||||||
|
else
|
||||||
|
disp E "Unknown command: $cmd"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
# shellcheck disable=SC2154 # color code in disp.sh
|
# shellcheck disable=SC2154 # color code in disp.sh
|
||||||
# shellcheck disable=SC2059 # printf format is a color variable
|
# shellcheck disable=SC2059 # printf format is a color variable
|
||||||
printf "${BIWhite}Welcome to your profile! Here is a list of available commands:${DEFAULTCOL}\n\n"
|
printf "${BIWhite}Welcome to your profile! Here is a list of available commands:${DEFAULTCOL}\n\n"
|
||||||
@@ -67,6 +79,7 @@ help()
|
|||||||
printf "ku\t\tKill all processes owned by the given user name or ID\n"
|
printf "ku\t\tKill all processes owned by the given user name or ID\n"
|
||||||
printf "matrix\t\tConsole screensaver with Matrix-style digital rain (binary, kana, ascii charset)\n"
|
printf "matrix\t\tConsole screensaver with Matrix-style digital rain (binary, kana, ascii charset)\n"
|
||||||
printf "mcd\t\tCreate a directory and immediately move into it\n"
|
printf "mcd\t\tCreate a directory and immediately move into it\n"
|
||||||
|
printf "mdcat\t\tRender Markdown files in terminal with colors and code frames\n"
|
||||||
printf "meteo\t\tDisplay weather forecast for the configured or given city\n"
|
printf "meteo\t\tDisplay weather forecast for the configured or given city\n"
|
||||||
printf "myextip\t\tGet information about your public IP address\n"
|
printf "myextip\t\tGet information about your public IP address\n"
|
||||||
printf "pkgs\t\tSearch for a pattern in installed package names (dpkg/rpm, supports -i)\n"
|
printf "pkgs\t\tSearch for a pattern in installed package names (dpkg/rpm, supports -i)\n"
|
||||||
@@ -90,7 +103,7 @@ help()
|
|||||||
printf "utaz\t\tSmartly uncompress archives (zip, tar.gz/bz2/xz/lz, rar, arj, lha, ace, 7z, zst, cpio, cab, deb, rpm)\n"
|
printf "utaz\t\tSmartly uncompress archives (zip, tar.gz/bz2/xz/lz, rar, arj, lha, ace, 7z, zst, cpio, cab, deb, rpm)\n"
|
||||||
printf "ver\t\tDisplay the installed profile version\n\n"
|
printf "ver\t\tDisplay the installed profile version\n\n"
|
||||||
|
|
||||||
printf "\nPlease use <command> --help to obtain usage details.\n"
|
printf "\nPlease use <command> --help or help <command> to obtain usage details.\n"
|
||||||
}
|
}
|
||||||
export -f help
|
export -f help
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -36,27 +36,52 @@
|
|||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Download a resource using curl, wget, or fetch.
|
# Download a resource using curl, wget, or fetch.
|
||||||
# Usage: dwl <url> [output_file]
|
# Usage: dwl [-t <seconds>] <url> [output_file]
|
||||||
dwl()
|
dwl()
|
||||||
{
|
{
|
||||||
|
local timeout=""
|
||||||
|
|
||||||
|
# Parse leading options before the URL.
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--help|-h)
|
--help|-h)
|
||||||
echo "Usage: dwl <url> [output_file]"
|
echo "Usage: dwl [-t <seconds>|--timeout <seconds>] <url> [output_file]"
|
||||||
echo "Downloads a resource using curl, wget, or fetch."
|
echo "Downloads a resource using curl, wget, or fetch."
|
||||||
echo ""
|
echo ""
|
||||||
echo "Arguments:"
|
echo "Arguments:"
|
||||||
|
echo " -t, --timeout Maximum time in seconds to wait for the transfer."
|
||||||
echo " url The full URL to download (http/https/ftp)."
|
echo " url The full URL to download (http/https/ftp)."
|
||||||
echo " output_file (Optional) Path to save the file. If omitted, prints to stdout."
|
echo " output_file (Optional) Path to save the file. If omitted, prints to stdout."
|
||||||
return 0
|
return 0
|
||||||
;;
|
;;
|
||||||
"")
|
-t|--timeout)
|
||||||
echo "Error: URL argument is missing." >&2
|
[[ -z "${2:-}" || ! "${2:-}" =~ ^[0-9]+$ ]] && {
|
||||||
echo "Try 'get_resource --help' for usage." >&2
|
echo "Error: --timeout requires a positive integer argument." >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
timeout="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
shift
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo "Error: Unknown option '$1'. Try 'dwl --help'." >&2
|
||||||
return 1
|
return 1
|
||||||
;;
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
case "$1" in
|
case "${1:-}" in
|
||||||
|
"")
|
||||||
|
echo "Error: URL argument is missing." >&2
|
||||||
|
echo "Try 'dwl --help' for usage." >&2
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
http://*|https://*|ftp://*) ;;
|
http://*|https://*|ftp://*) ;;
|
||||||
*)
|
*)
|
||||||
echo "Error: '$1' does not look like a valid URL. Must start with http://, https://, or ftp://" >&2
|
echo "Error: '$1' does not look like a valid URL. Must start with http://, https://, or ftp://" >&2
|
||||||
@@ -65,35 +90,41 @@ dwl()
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
local url="$1"
|
local url="$1"
|
||||||
local output="$2"
|
local output="${2:-}"
|
||||||
|
|
||||||
# Honour preferred tool from configuration; fall back to auto-detection.
|
# Honour preferred tool from configuration; fall back to auto-detection.
|
||||||
local preferred="${DWL_PREFERRED_TOOL:-}"
|
local preferred="${DWL_PREFERRED_TOOL:-}"
|
||||||
|
|
||||||
_try_curl()
|
_try_curl()
|
||||||
{
|
{
|
||||||
|
local args=(-sL)
|
||||||
|
[[ -n "$timeout" ]] && args+=(--max-time "$timeout" --connect-timeout "$timeout")
|
||||||
if [[ -z "$output" ]]; then
|
if [[ -z "$output" ]]; then
|
||||||
curl -sL "$url"
|
curl "${args[@]}" "$url"
|
||||||
else
|
else
|
||||||
curl -sL -o "$output" "$url"
|
curl "${args[@]}" -o "$output" "$url"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_try_wget()
|
_try_wget()
|
||||||
{
|
{
|
||||||
|
local args=(-q)
|
||||||
|
[[ -n "$timeout" ]] && args+=(--timeout="$timeout")
|
||||||
if [[ -z "$output" ]]; then
|
if [[ -z "$output" ]]; then
|
||||||
wget -qO- "$url"
|
wget "${args[@]}" -O- "$url"
|
||||||
else
|
else
|
||||||
wget -q -O "$output" "$url"
|
wget "${args[@]}" -O "$output" "$url"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
_try_fetch()
|
_try_fetch()
|
||||||
{
|
{
|
||||||
|
local args=()
|
||||||
|
[[ -n "$timeout" ]] && args+=(-T "$timeout")
|
||||||
if [[ -z "$output" ]]; then
|
if [[ -z "$output" ]]; then
|
||||||
fetch -o - "$url"
|
fetch "${args[@]}" -o - "$url"
|
||||||
else
|
else
|
||||||
fetch -o "$output" "$url"
|
fetch "${args[@]}" -o "$output" "$url"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
# checking available binaries in a fixed priority order.
|
# checking available binaries in a fixed priority order.
|
||||||
# Echoes one of: apt dnf yum zypper pacman apk portage xbps nix
|
# Echoes one of: apt dnf yum zypper pacman apk portage xbps nix
|
||||||
# Returns 1 if no known package manager could be identified.
|
# Returns 1 if no known package manager could be identified.
|
||||||
_get_pkgmgr()
|
get_pkgmgr()
|
||||||
{
|
{
|
||||||
local distro_id="" distro_like=""
|
local distro_id="" distro_like=""
|
||||||
if [[ -r /etc/os-release ]]; then
|
if [[ -r /etc/os-release ]]; then
|
||||||
@@ -56,30 +56,48 @@ _get_pkgmgr()
|
|||||||
for id in $distro_id $distro_like; do
|
for id in $distro_id $distro_like; do
|
||||||
case "${id,,}" in
|
case "${id,,}" in
|
||||||
debian|ubuntu|linuxmint|raspbian|pop|kali|elementary|zorin|neon|parrot)
|
debian|ubuntu|linuxmint|raspbian|pop|kali|elementary|zorin|neon|parrot)
|
||||||
echo "apt"; return 0 ;;
|
echo "apt"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
fedora)
|
fedora)
|
||||||
echo "dnf"; return 0 ;;
|
echo "dnf"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
rhel|centos|rocky|almalinux|ol|scientific|amzn)
|
rhel|centos|rocky|almalinux|ol|scientific|amzn)
|
||||||
command -v dnf >/dev/null 2>&1 && { echo "dnf"; return 0; }
|
command -v dnf >/dev/null 2>&1 && { echo "dnf"; return 0; }
|
||||||
echo "yum"; return 0 ;;
|
echo "yum"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
opensuse*|sles|sled)
|
opensuse*|sles|sled)
|
||||||
echo "zypper"; return 0 ;;
|
echo "zypper"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
arch|manjaro|endeavouros|garuda|artix|cachyos)
|
arch|manjaro|endeavouros|garuda|artix|cachyos)
|
||||||
echo "pacman"; return 0 ;;
|
echo "pacman"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
alpine)
|
alpine)
|
||||||
echo "apk"; return 0 ;;
|
echo "apk"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
gentoo)
|
gentoo)
|
||||||
echo "portage"; return 0 ;;
|
echo "portage"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
void)
|
void)
|
||||||
echo "xbps"; return 0 ;;
|
echo "xbps"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
nixos)
|
nixos)
|
||||||
echo "nix"; return 0 ;;
|
echo "nix"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
# Fallback: check for binaries in priority order.
|
# Fallback: check for binaries in priority order.
|
||||||
local bin
|
local bin
|
||||||
for bin in apt-get dnf yum zypper pacman apk emerge xbps-install nix-env; do
|
for bin in apt apt-get dnf yum zypper pacman apk emerge xbps-install nix-env; do
|
||||||
command -v "$bin" >/dev/null 2>&1 && {
|
command -v "$bin" >/dev/null 2>&1 && {
|
||||||
case "$bin" in
|
case "$bin" in
|
||||||
apt-get) echo "apt" ;;
|
apt-get) echo "apt" ;;
|
||||||
@@ -94,7 +112,7 @@ _get_pkgmgr()
|
|||||||
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
export -f _get_pkgmgr
|
export -f get_pkgmgr
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@@ -150,7 +168,7 @@ pkgs()
|
|||||||
(( ignore_case )) && grep_opt="-i"
|
(( ignore_case )) && grep_opt="-i"
|
||||||
|
|
||||||
local pkgmgr
|
local pkgmgr
|
||||||
pkgmgr=$(_get_pkgmgr) || {
|
pkgmgr=$(get_pkgmgr) || {
|
||||||
disp E "No usable package manager could be detected on this system."
|
disp E "No usable package manager could be detected on this system."
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ load_theme()
|
|||||||
[PROMPT_COLOR_ERR_BG]=1 [PROMPT_COLOR_ERR_FG]=1 [PROMPT_COLOR_ERR_MARK]=1
|
[PROMPT_COLOR_ERR_BG]=1 [PROMPT_COLOR_ERR_FG]=1 [PROMPT_COLOR_ERR_MARK]=1
|
||||||
[PROMPT_COLOR_ROOT_FG]=1 [PROMPT_COLOR_USER_FG]=1
|
[PROMPT_COLOR_ROOT_FG]=1 [PROMPT_COLOR_USER_FG]=1
|
||||||
[PROMPT_COLOR_DIR_FG]=1
|
[PROMPT_COLOR_DIR_FG]=1
|
||||||
|
[PROMPT_COLOR_CTX_FG]=1
|
||||||
)
|
)
|
||||||
|
|
||||||
# ---- Colour variable names exported by disp.sh --------------------------
|
# ---- Colour variable names exported by disp.sh --------------------------
|
||||||
@@ -184,16 +185,16 @@ set_theme()
|
|||||||
printf "set_theme: Switch the prompt colour theme for the current shell session.\n\n"
|
printf "set_theme: Switch the prompt colour theme for the current shell session.\n\n"
|
||||||
printf "Usage: set_theme [options] [theme]\n\n"
|
printf "Usage: set_theme [options] [theme]\n\n"
|
||||||
printf "Options:\n"
|
printf "Options:\n"
|
||||||
printf " -h, --help Display this help screen\n"
|
printf "\t-h, --help\tDisplay this help screen\n"
|
||||||
printf " -l, --list List available themes (default when no argument is given)\n\n"
|
printf "\t-l, --list\tList available themes (default when no argument is given)\n\n"
|
||||||
printf "Arguments:\n"
|
printf "Arguments:\n"
|
||||||
printf " theme Bare theme name (e.g. 'dark') or an explicit path to a .theme file.\n"
|
printf "\ttheme \tBare theme name (e.g. 'dark') or an explicit path to a .theme file.\n"
|
||||||
printf " Themes are searched in: %s\n" "$theme_dir"
|
printf "\t \tThemes are searched in: %s\n" "$theme_dir"
|
||||||
printf " Override with PROMPT_THEME_DIR in profile.conf [prompt].\n\n"
|
printf "\t \tOverride with PROMPT_THEME_DIR in profile.conf [prompt].\n\n"
|
||||||
printf "Examples:\n"
|
printf "Examples:\n"
|
||||||
printf " set_theme — list available themes\n"
|
printf "\tset_theme \t— list available themes\n"
|
||||||
printf " set_theme dark — apply the dark theme\n"
|
printf "\tset_theme dark \t— apply the dark theme\n"
|
||||||
printf " set_theme ~/my.theme — apply a theme by path\n"
|
printf "\tset_theme ~/my.theme\t— apply a theme by path\n"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -285,6 +286,68 @@ function timer_stop
|
|||||||
# command, the elapsed time of the last command, and the current user and host.
|
# command, the elapsed time of the last command, and the current user and host.
|
||||||
set_prompt()
|
set_prompt()
|
||||||
{
|
{
|
||||||
|
_prompt_git_segment()
|
||||||
|
{
|
||||||
|
# Fast path: skip git lookup when feature is disabled.
|
||||||
|
[[ "${PROMPT_SHOW_GIT:-1}" == "0" ]] && return 0
|
||||||
|
|
||||||
|
local branch
|
||||||
|
branch=$(git symbolic-ref --quiet --short HEAD 2>/dev/null) || \
|
||||||
|
branch=$(git rev-parse --short HEAD 2>/dev/null) || return 0
|
||||||
|
|
||||||
|
local dirty="" sync=""
|
||||||
|
if [[ "${PROMPT_SHOW_GIT_STATUS:-1}" != "0" ]]; then
|
||||||
|
if ! git diff --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null || \
|
||||||
|
! git diff --cached --no-ext-diff --quiet --ignore-submodules -- 2>/dev/null; then
|
||||||
|
dirty="*"
|
||||||
|
fi
|
||||||
|
|
||||||
|
local counts ahead behind
|
||||||
|
counts=$(git rev-list --left-right --count "@{upstream}...HEAD" 2>/dev/null) || counts=""
|
||||||
|
if [[ "$counts" =~ ^([0-9]+)[[:space:]]+([0-9]+)$ ]]; then
|
||||||
|
behind="${BASH_REMATCH[1]}"
|
||||||
|
ahead="${BASH_REMATCH[2]}"
|
||||||
|
if [[ "$ahead" -gt 0 || "$behind" -gt 0 ]]; then
|
||||||
|
sync=" +${ahead}/-${behind}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s" "git:${branch}${dirty}${sync}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_prompt_conda_env()
|
||||||
|
{
|
||||||
|
[[ "${PROMPT_SHOW_CONDA:-1}" == "0" ]] && return 0
|
||||||
|
[[ -z "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
||||||
|
printf "%s" "conda:${CONDA_DEFAULT_ENV}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_prompt_venv_env()
|
||||||
|
{
|
||||||
|
[[ "${PROMPT_SHOW_VENV:-1}" == "0" ]] && return 0
|
||||||
|
[[ -n "${CONDA_DEFAULT_ENV:-}" ]] && return 0
|
||||||
|
[[ -z "${VIRTUAL_ENV:-}" ]] && return 0
|
||||||
|
printf "%s" "venv:${VIRTUAL_ENV##*/}"
|
||||||
|
}
|
||||||
|
|
||||||
|
_prompt_session_markers()
|
||||||
|
{
|
||||||
|
[[ "${PROMPT_SHOW_SESSION:-1}" == "0" ]] && return 0
|
||||||
|
|
||||||
|
local -a tags=()
|
||||||
|
[[ -n "${SSH_CONNECTION:-}" ]] && tags+=("ssh")
|
||||||
|
[[ -n "${TMUX:-}" ]] && tags+=("tmux")
|
||||||
|
[[ -n "${STY:-}" ]] && tags+=("screen")
|
||||||
|
[[ ${#tags[@]} -eq 0 ]] && return 0
|
||||||
|
|
||||||
|
local out="${tags[0]}" i
|
||||||
|
for ((i=1; i<${#tags[@]}; ++i)); do
|
||||||
|
out+="+${tags[i]}"
|
||||||
|
done
|
||||||
|
printf "%s" "$out"
|
||||||
|
}
|
||||||
|
|
||||||
local Last_Command=$? # Must come first!
|
local Last_Command=$? # Must come first!
|
||||||
local FancyX='\342\234\227'
|
local FancyX='\342\234\227'
|
||||||
local Checkmark='\342\234\223'
|
local Checkmark='\342\234\223'
|
||||||
@@ -301,6 +364,7 @@ set_prompt()
|
|||||||
local _root_fg="${PROMPT_COLOR_ROOT_FG:-$Red}"
|
local _root_fg="${PROMPT_COLOR_ROOT_FG:-$Red}"
|
||||||
local _user_fg="${PROMPT_COLOR_USER_FG:-$BGreen}"
|
local _user_fg="${PROMPT_COLOR_USER_FG:-$BGreen}"
|
||||||
local _dir_fg="${PROMPT_COLOR_DIR_FG:-$ICyan}"
|
local _dir_fg="${PROMPT_COLOR_DIR_FG:-$ICyan}"
|
||||||
|
local _ctx_fg="${PROMPT_COLOR_CTX_FG:-$BIYellow}"
|
||||||
|
|
||||||
# Begin with time (cursor-save is non-printing; all ANSI sequences wrapped
|
# Begin with time (cursor-save is non-printing; all ANSI sequences wrapped
|
||||||
# in \[...\] so bash does not count them toward the visible line width).
|
# in \[...\] so bash does not count them toward the visible line width).
|
||||||
@@ -330,6 +394,42 @@ set_prompt()
|
|||||||
else
|
else
|
||||||
PS1+="\[${_user_fg}${_bar_bg}\] \\u@\\h"
|
PS1+="\[${_user_fg}${_bar_bg}\] \\u@\\h"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Optional context segment appended at the end of the top bar.
|
||||||
|
local _git_seg _conda_env _venv_env _session_tags _ctx=""
|
||||||
|
_git_seg="$(_prompt_git_segment)"
|
||||||
|
_conda_env="$(_prompt_conda_env)"
|
||||||
|
_venv_env="$(_prompt_venv_env)"
|
||||||
|
_session_tags="$(_prompt_session_markers)"
|
||||||
|
|
||||||
|
if [[ -n "$_git_seg" ]]; then
|
||||||
|
_ctx="$_git_seg"
|
||||||
|
fi
|
||||||
|
if [[ -n "$_conda_env" ]]; then
|
||||||
|
if [[ -n "$_ctx" ]]; then
|
||||||
|
_ctx+=" | ${_conda_env}"
|
||||||
|
else
|
||||||
|
_ctx="${_conda_env}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -n "$_venv_env" ]]; then
|
||||||
|
if [[ -n "$_ctx" ]]; then
|
||||||
|
_ctx+=" | ${_venv_env}"
|
||||||
|
else
|
||||||
|
_ctx="${_venv_env}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -n "$_session_tags" ]]; then
|
||||||
|
if [[ -n "$_ctx" ]]; then
|
||||||
|
_ctx+=" | ${_session_tags}"
|
||||||
|
else
|
||||||
|
_ctx="${_session_tags}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [[ -n "$_ctx" ]]; then
|
||||||
|
PS1+="\[${_ctx_fg}${_bar_bg}\] [ ${_ctx} ]"
|
||||||
|
fi
|
||||||
|
|
||||||
PS1+="\[\e[K\e[u\]\[$RESETCOL\]\n"
|
PS1+="\[\e[K\e[u\]\[$RESETCOL\]\n"
|
||||||
# Print the working directory and prompt marker, then reset colour.
|
# Print the working directory and prompt marker, then reset colour.
|
||||||
PS1+="\[${_dir_fg}\]\\w \\\$\[$RESETCOL\] "
|
PS1+="\[${_dir_fg}\]\\w \\\$\[$RESETCOL\] "
|
||||||
|
|||||||
@@ -110,12 +110,24 @@ _rain_normalize_speed()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_rain_normalize_density()
|
||||||
|
{
|
||||||
|
local raw_density="$1"
|
||||||
|
|
||||||
|
if [[ ! "$raw_density" =~ ^[0-9]+$ || "$raw_density" -lt 1 ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "%s" "$raw_density"
|
||||||
|
}
|
||||||
|
|
||||||
_rain_engine()
|
_rain_engine()
|
||||||
{
|
{
|
||||||
local step_duration="$1"
|
local step_duration="$1"
|
||||||
local base_color="$2"
|
local base_color="$2"
|
||||||
local mode="$3"
|
local mode="$3"
|
||||||
local charset="$4"
|
local charset="$4"
|
||||||
|
local density_override="$5"
|
||||||
|
|
||||||
command -v tput >/dev/null 2>&1 || {
|
command -v tput >/dev/null 2>&1 || {
|
||||||
disp E "The program 'tput' is required but not installed."
|
disp E "The program 'tput' is required but not installed."
|
||||||
@@ -175,6 +187,10 @@ _rain_engine()
|
|||||||
frame_sleep="$step_duration"
|
frame_sleep="$step_duration"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if [[ -n "$density_override" ]]; then
|
||||||
|
max_rain_width="$density_override"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
do_exit()
|
do_exit()
|
||||||
@@ -251,7 +267,11 @@ _rain_engine()
|
|||||||
if ((num_rains < max_rain_width)) && ((100 * RANDOM / 32768 < new_rain_odd)); then
|
if ((num_rains < max_rain_width)) && ((100 * RANDOM / 32768 < new_rain_odd)); then
|
||||||
rain_drop="${rain_chars[rain_tab * RANDOM / 32768]}"
|
rain_drop="${rain_chars[rain_tab * RANDOM / 32768]}"
|
||||||
drop_color="${rain_colors[rain_color_tab * RANDOM / 32768]}"
|
drop_color="${rain_colors[rain_color_tab * RANDOM / 32768]}"
|
||||||
|
if [[ "$mode" == "matrix" ]]; then
|
||||||
|
drop_length=$((max_rain_height * RANDOM / 32768 + 2))
|
||||||
|
else
|
||||||
drop_length=$((max_rain_height * RANDOM / 32768 + 1))
|
drop_length=$((max_rain_height * RANDOM / 32768 + 1))
|
||||||
|
fi
|
||||||
X=$((term_width * RANDOM / 32768 + 1))
|
X=$((term_width * RANDOM / 32768 + 1))
|
||||||
Y=$((1 - drop_length))
|
Y=$((1 - drop_length))
|
||||||
rains=("${rains[@]}" "$X" "$Y" "$rain_drop" "$drop_color" "$drop_length")
|
rains=("${rains[@]}" "$X" "$Y" "$rain_drop" "$drop_color" "$drop_length")
|
||||||
@@ -277,11 +297,12 @@ rain()
|
|||||||
{
|
{
|
||||||
printf "Usage: rain [OPTIONS]\n"
|
printf "Usage: rain [OPTIONS]\n"
|
||||||
printf "Options:\n"
|
printf "Options:\n"
|
||||||
printf "\t-s, --speed NUM Set speed value (default: 5 => 0.050s).\n"
|
printf "\t-s, --speed NUM\tSet speed value (default: 5 => 0.050s).\n"
|
||||||
printf "\t Values >=1 use a /100 scale (5 => 0.05s).\n"
|
printf "\t\t\t\tValues >=1 use a /100 scale (5 => 0.05s).\n"
|
||||||
printf "\t Values <1 are interpreted as raw seconds.\n"
|
printf "\t\t\t\tValues <1 are interpreted as raw seconds.\n"
|
||||||
printf "\t-c, --color COLOR Set the color theme (default: white).\n"
|
printf "\t-d, --density NUM\tMaximum number of simultaneous falling elements.\n"
|
||||||
printf "\t-h, --help Display this help message and exit.\n\n"
|
printf "\t-c, --color COLOR\tSet the color theme (default: white).\n"
|
||||||
|
printf "\t-h, --help\t\tDisplay this help message and exit.\n\n"
|
||||||
printf "Available Colors:\n"
|
printf "Available Colors:\n"
|
||||||
printf "\t\e[32mgreen\e[0m\t: Matrix-like green shades\n"
|
printf "\t\e[32mgreen\e[0m\t: Matrix-like green shades\n"
|
||||||
printf "\t\e[34mblue\e[0m\t: Deep ocean blue gradients\n"
|
printf "\t\e[34mblue\e[0m\t: Deep ocean blue gradients\n"
|
||||||
@@ -296,6 +317,11 @@ rain()
|
|||||||
local step_duration
|
local step_duration
|
||||||
step_duration=$(_rain_normalize_speed "$_raw_speed") || step_duration=0.050
|
step_duration=$(_rain_normalize_speed "$_raw_speed") || step_duration=0.050
|
||||||
local base_color="${RAIN_DEFAULT_COLOR:-white}"
|
local base_color="${RAIN_DEFAULT_COLOR:-white}"
|
||||||
|
local density_override="${RAIN_DEFAULT_DENSITY:-}"
|
||||||
|
|
||||||
|
if [[ -n "$density_override" ]]; then
|
||||||
|
density_override=$(_rain_normalize_density "$density_override") || density_override=""
|
||||||
|
fi
|
||||||
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
while [[ "$#" -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -323,6 +349,20 @@ rain()
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
-d|--density)
|
||||||
|
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||||
|
density_override=$(_rain_normalize_density "$2") || {
|
||||||
|
disp E "--density requires a positive integer value."
|
||||||
|
_rain_show_usage
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
disp E "--density requires a positive integer value."
|
||||||
|
_rain_show_usage
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
_rain_show_usage
|
_rain_show_usage
|
||||||
return 0
|
return 0
|
||||||
@@ -340,7 +380,7 @@ rain()
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
_rain_engine "$step_duration" "$base_color" "rain" ""
|
_rain_engine "$step_duration" "$base_color" "rain" "" "$density_override"
|
||||||
}
|
}
|
||||||
export -f rain
|
export -f rain
|
||||||
|
|
||||||
@@ -353,12 +393,13 @@ matrix()
|
|||||||
{
|
{
|
||||||
printf "Usage: matrix [OPTIONS]\n"
|
printf "Usage: matrix [OPTIONS]\n"
|
||||||
printf "Options:\n"
|
printf "Options:\n"
|
||||||
printf "\t-s, --speed NUM Set speed value (default: 3.5 => 0.035s).\n"
|
printf "\t-s, --speed NUM\tSet speed value (default: 3.5 => 0.035s).\n"
|
||||||
printf "\t Values >=1 use a /100 scale (3.5 => 0.035s).\n"
|
printf "\t\t\t\tValues >=1 use a /100 scale (3.5 => 0.035s).\n"
|
||||||
printf "\t Values <1 are interpreted as raw seconds.\n"
|
printf "\t\t\t\tValues <1 are interpreted as raw seconds.\n"
|
||||||
printf "\t-c, --color COLOR Set color theme (default: green).\n"
|
printf "\t-d, --density NUM\tMaximum number of simultaneous falling elements.\n"
|
||||||
printf "\t-C, --charset SET Character set: binary, kana, ascii (default: binary).\n"
|
printf "\t-c, --color COLOR\tSet color theme (default: green).\n"
|
||||||
printf "\t-h, --help Display this help message and exit.\n\n"
|
printf "\t-C, --charset SET\tCharacter set: binary, kana, ascii (default: binary).\n"
|
||||||
|
printf "\t-h, --help\t\tDisplay this help message and exit.\n\n"
|
||||||
printf "Example: matrix -C kana -c green --speed 2\n"
|
printf "Example: matrix -C kana -c green --speed 2\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,6 +408,11 @@ matrix()
|
|||||||
step_duration=$(_rain_normalize_speed "$_raw_speed") || step_duration=0.035
|
step_duration=$(_rain_normalize_speed "$_raw_speed") || step_duration=0.035
|
||||||
local base_color="${MATRIX_DEFAULT_COLOR:-green}"
|
local base_color="${MATRIX_DEFAULT_COLOR:-green}"
|
||||||
local charset="${MATRIX_DEFAULT_CHARSET:-binary}"
|
local charset="${MATRIX_DEFAULT_CHARSET:-binary}"
|
||||||
|
local density_override="${MATRIX_DEFAULT_DENSITY:-}"
|
||||||
|
|
||||||
|
if [[ -n "$density_override" ]]; then
|
||||||
|
density_override=$(_rain_normalize_density "$density_override") || density_override=""
|
||||||
|
fi
|
||||||
|
|
||||||
while [[ "$#" -gt 0 ]]; do
|
while [[ "$#" -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -412,6 +458,20 @@ matrix()
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
-d|--density)
|
||||||
|
if [[ -n "$2" && ! "$2" =~ ^- ]]; then
|
||||||
|
density_override=$(_rain_normalize_density "$2") || {
|
||||||
|
disp E "--density requires a positive integer value."
|
||||||
|
_matrix_show_usage
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
disp E "--density requires a positive integer value."
|
||||||
|
_matrix_show_usage
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
_matrix_show_usage
|
_matrix_show_usage
|
||||||
return 0
|
return 0
|
||||||
@@ -429,10 +489,9 @@ matrix()
|
|||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
_rain_engine "$step_duration" "$base_color" "matrix" "$charset"
|
_rain_engine "$step_duration" "$base_color" "matrix" "$charset" "$density_override"
|
||||||
}
|
}
|
||||||
export -f matrix
|
export -f matrix
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
load_conf "rain"
|
load_conf "rain"
|
||||||
|
|||||||
@@ -40,3 +40,4 @@ PROMPT_COLOR_ERR_MARK="$IYellow" # golden X
|
|||||||
PROMPT_COLOR_ROOT_FG="$IRed" # red for root
|
PROMPT_COLOR_ROOT_FG="$IRed" # red for root
|
||||||
PROMPT_COLOR_USER_FG="$IBlue" # electric blue for user
|
PROMPT_COLOR_USER_FG="$IBlue" # electric blue for user
|
||||||
PROMPT_COLOR_DIR_FG="$ICyan" # teal path
|
PROMPT_COLOR_DIR_FG="$ICyan" # teal path
|
||||||
|
PROMPT_COLOR_CTX_FG="$IYellow" # context segment (git/conda)
|
||||||
|
|||||||
@@ -40,3 +40,4 @@ PROMPT_COLOR_ERR_MARK="$Yellow" # yellow X (warning intent)
|
|||||||
PROMPT_COLOR_ROOT_FG="$Red" # Adwaita red for root
|
PROMPT_COLOR_ROOT_FG="$Red" # Adwaita red for root
|
||||||
PROMPT_COLOR_USER_FG="$BBlue" # darker bold blue — readable on blue bar
|
PROMPT_COLOR_USER_FG="$BBlue" # darker bold blue — readable on blue bar
|
||||||
PROMPT_COLOR_DIR_FG="$IGreen" # Adwaita green for path
|
PROMPT_COLOR_DIR_FG="$IGreen" # Adwaita green for path
|
||||||
|
PROMPT_COLOR_CTX_FG="$BIWhite" # context segment (git/conda)
|
||||||
|
|||||||
@@ -30,3 +30,4 @@ PROMPT_COLOR_ERR_MARK="$BIYellow" # X mark colour on failure
|
|||||||
PROMPT_COLOR_ROOT_FG="$BIRed" # Username colour when root
|
PROMPT_COLOR_ROOT_FG="$BIRed" # Username colour when root
|
||||||
PROMPT_COLOR_USER_FG="$ICyan" # Username@host colour for normal users
|
PROMPT_COLOR_USER_FG="$ICyan" # Username@host colour for normal users
|
||||||
PROMPT_COLOR_DIR_FG="$IPurple" # Working directory colour
|
PROMPT_COLOR_DIR_FG="$IPurple" # Working directory colour
|
||||||
|
PROMPT_COLOR_CTX_FG="$BIYellow" # Context segment (git/conda)
|
||||||
|
|||||||
@@ -30,3 +30,4 @@ PROMPT_COLOR_ERR_MARK="$BYellow" # X mark colour on failure
|
|||||||
PROMPT_COLOR_ROOT_FG="$Red" # Username colour when root
|
PROMPT_COLOR_ROOT_FG="$Red" # Username colour when root
|
||||||
PROMPT_COLOR_USER_FG="$Green" # Username@host colour for normal users
|
PROMPT_COLOR_USER_FG="$Green" # Username@host colour for normal users
|
||||||
PROMPT_COLOR_DIR_FG="$ICyan" # Working directory colour
|
PROMPT_COLOR_DIR_FG="$ICyan" # Working directory colour
|
||||||
|
PROMPT_COLOR_CTX_FG="$BIYellow" # Context segment (git/conda)
|
||||||
|
|||||||
@@ -33,3 +33,4 @@ PROMPT_COLOR_ERR_MARK="$BYellow" # X mark on failure (BIYellow → BYellow, l
|
|||||||
PROMPT_COLOR_ROOT_FG="$Red" # Username when root (BIRed → Red)
|
PROMPT_COLOR_ROOT_FG="$Red" # Username when root (BIRed → Red)
|
||||||
PROMPT_COLOR_USER_FG="$Blue" # Username@host normal user (ICyan → Blue)
|
PROMPT_COLOR_USER_FG="$Blue" # Username@host normal user (ICyan → Blue)
|
||||||
PROMPT_COLOR_DIR_FG="$Purple" # Working directory (IPurple → Purple)
|
PROMPT_COLOR_DIR_FG="$Purple" # Working directory (IPurple → Purple)
|
||||||
|
PROMPT_COLOR_CTX_FG="$BBlack" # Context segment (git/conda)
|
||||||
|
|||||||
@@ -62,3 +62,4 @@ PROMPT_COLOR_ERR_MARK="$BBlack" # bold black X
|
|||||||
PROMPT_COLOR_ROOT_FG="$BIWhite" # bold bright white for root warning
|
PROMPT_COLOR_ROOT_FG="$BIWhite" # bold bright white for root warning
|
||||||
PROMPT_COLOR_USER_FG="$IWhite" # bright white for normal user
|
PROMPT_COLOR_USER_FG="$IWhite" # bright white for normal user
|
||||||
PROMPT_COLOR_DIR_FG="$White" # standard white for path
|
PROMPT_COLOR_DIR_FG="$White" # standard white for path
|
||||||
|
PROMPT_COLOR_CTX_FG="$BIWhite" # context segment (git/conda)
|
||||||
|
|||||||
@@ -43,3 +43,4 @@ PROMPT_COLOR_ERR_MARK="$IRed" # hot pink X
|
|||||||
PROMPT_COLOR_ROOT_FG="$IRed" # hot pink for root
|
PROMPT_COLOR_ROOT_FG="$IRed" # hot pink for root
|
||||||
PROMPT_COLOR_USER_FG="$IYellow" # orange-yellow for user
|
PROMPT_COLOR_USER_FG="$IYellow" # orange-yellow for user
|
||||||
PROMPT_COLOR_DIR_FG="$ICyan" # electric cyan for path
|
PROMPT_COLOR_DIR_FG="$ICyan" # electric cyan for path
|
||||||
|
PROMPT_COLOR_CTX_FG="$IYellow" # context segment (git/conda)
|
||||||
|
|||||||
@@ -40,3 +40,4 @@ PROMPT_COLOR_ERR_MARK="$IYellow" # yellow X
|
|||||||
PROMPT_COLOR_ROOT_FG="$IRed" # red for root
|
PROMPT_COLOR_ROOT_FG="$IRed" # red for root
|
||||||
PROMPT_COLOR_USER_FG="$BIPurple" # bold vivid purple for user
|
PROMPT_COLOR_USER_FG="$BIPurple" # bold vivid purple for user
|
||||||
PROMPT_COLOR_DIR_FG="$ICyan" # electric cyan path
|
PROMPT_COLOR_DIR_FG="$ICyan" # electric cyan path
|
||||||
|
PROMPT_COLOR_CTX_FG="$IYellow" # context segment (git/conda)
|
||||||
|
|||||||
@@ -125,3 +125,4 @@ PROMPT_COLOR_ERR_MARK="\e[38;2;253;246;227m" # Base3 — X mark (bright on red
|
|||||||
PROMPT_COLOR_ROOT_FG="\e[38;2;220;50;47m" # Red — root warning
|
PROMPT_COLOR_ROOT_FG="\e[38;2;220;50;47m" # Red — root warning
|
||||||
PROMPT_COLOR_USER_FG="\e[38;2;42;161;152m" # Cyan — normal user
|
PROMPT_COLOR_USER_FG="\e[38;2;42;161;152m" # Cyan — normal user
|
||||||
PROMPT_COLOR_DIR_FG="\e[38;2;38;139;210m" # Blue — working directory
|
PROMPT_COLOR_DIR_FG="\e[38;2;38;139;210m" # Blue — working directory
|
||||||
|
PROMPT_COLOR_CTX_FG="\e[38;2;181;137;0m" # Yellow — context segment (git/conda)
|
||||||
|
|||||||
@@ -120,3 +120,4 @@ PROMPT_COLOR_ERR_MARK="\e[1;38;2;253;246;227m" # Base3 bold — bright warm mark
|
|||||||
PROMPT_COLOR_ROOT_FG="\e[38;2;220;50;47m" # Red — root warning
|
PROMPT_COLOR_ROOT_FG="\e[38;2;220;50;47m" # Red — root warning
|
||||||
PROMPT_COLOR_USER_FG="\e[38;2;42;161;152m" # Cyan — normal user
|
PROMPT_COLOR_USER_FG="\e[38;2;42;161;152m" # Cyan — normal user
|
||||||
PROMPT_COLOR_DIR_FG="\e[38;2;38;139;210m" # Blue — working directory
|
PROMPT_COLOR_DIR_FG="\e[38;2;38;139;210m" # Blue — working directory
|
||||||
|
PROMPT_COLOR_CTX_FG="\e[38;2;181;137;0m" # Yellow — context segment (git/conda)
|
||||||
|
|||||||
@@ -90,9 +90,14 @@ check_updates()
|
|||||||
return 4
|
return 4
|
||||||
}
|
}
|
||||||
|
|
||||||
dwl "$UPDT_URL/version" "$vfile" >/dev/null 2>&1 || {
|
# In quiet mode (startup), use a short timeout so a missing or slow network
|
||||||
|
# never blocks the interactive prompt.
|
||||||
|
local dwl_opts=()
|
||||||
|
(( quiet == 1 )) && dwl_opts+=(-t 3)
|
||||||
|
|
||||||
|
dwl "${dwl_opts[@]}" "$UPDT_URL/version" "$vfile" >/dev/null 2>&1 || {
|
||||||
rm -f "$vfile"
|
rm -f "$vfile"
|
||||||
disp E "Cannot download version file; unable to continue."
|
(( quiet != 1 )) && disp E "Cannot download version file; unable to continue."
|
||||||
return 5
|
return 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
135
profile.sh
135
profile.sh
@@ -35,10 +35,123 @@
|
|||||||
# * OF SUCH DAMAGE.
|
# * OF SUCH DAMAGE.
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_profile_is_sourced()
|
||||||
|
{
|
||||||
|
[[ "${BASH_SOURCE[0]}" != "$0" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_finish()
|
||||||
|
{
|
||||||
|
local rc="${1:-0}"
|
||||||
|
if _profile_is_sourced; then
|
||||||
|
return "$rc"
|
||||||
|
fi
|
||||||
|
exit "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_install_in_file()
|
||||||
|
{
|
||||||
|
local rc_file="$1"
|
||||||
|
local source_line="$2"
|
||||||
|
|
||||||
|
[[ -f "$rc_file" ]] || touch "$rc_file" || {
|
||||||
|
printf "[ Error ] Cannot create %s\n" "$rc_file" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if grep -Fqx "$source_line" "$rc_file"; then
|
||||||
|
printf "[ Info ] Already configured in %s\n" "$rc_file"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\n%s\n" "$source_line" >> "$rc_file" || {
|
||||||
|
printf "[ Error ] Cannot write to %s\n" "$rc_file" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
printf "[ Info ] Added profile source line to %s\n" "$rc_file"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_profile_install()
|
||||||
|
{
|
||||||
|
local install_bashrc=0
|
||||||
|
local install_profile=0
|
||||||
|
local target_selected=0
|
||||||
|
local script_dir source_line rc=0
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--bashrc)
|
||||||
|
install_bashrc=1
|
||||||
|
target_selected=1
|
||||||
|
;;
|
||||||
|
--profile)
|
||||||
|
install_profile=1
|
||||||
|
target_selected=1
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
printf "Usage: %s --install [--bashrc] [--profile]\n" "${BASH_SOURCE[0]}"
|
||||||
|
printf "If no target is specified, both ~/.bashrc and ~/.profile are configured.\n"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "[ Error ] Unknown install option: %s\n" "$1" >&2
|
||||||
|
return 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
if (( target_selected == 0 )); then
|
||||||
|
install_bashrc=1
|
||||||
|
install_profile=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
script_dir=$(dirname "$(realpath -s "${BASH_SOURCE[0]}")")
|
||||||
|
source_line="source \"$script_dir/profile.sh\""
|
||||||
|
|
||||||
|
if (( install_bashrc == 1 )); then
|
||||||
|
_profile_install_in_file "$HOME/.bashrc" "$source_line" || rc=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (( install_profile == 1 )); then
|
||||||
|
_profile_install_in_file "$HOME/.profile" "$source_line" || rc=$?
|
||||||
|
fi
|
||||||
|
|
||||||
|
return "$rc"
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ $# -gt 0 ]]; then
|
||||||
|
case "$1" in
|
||||||
|
--install)
|
||||||
|
shift
|
||||||
|
_profile_install "$@"
|
||||||
|
_profile_finish $?
|
||||||
|
;;
|
||||||
|
-h|--help)
|
||||||
|
printf "Usage: source %s\n" "${BASH_SOURCE[0]}"
|
||||||
|
printf " %s --install [--bashrc] [--profile]\n" "${BASH_SOURCE[0]}"
|
||||||
|
_profile_finish 0
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
printf "[ Error ] Unknown option: %s\n" "$1" >&2
|
||||||
|
_profile_finish 2
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _profile_is_sourced; then
|
||||||
|
printf "[ Warning ] profile.sh is designed to be sourced, not executed directly.\n" >&2
|
||||||
|
printf "Use: source \"%s\"\n" "$(realpath -s "${BASH_SOURCE[0]}")" >&2
|
||||||
|
printf "Or run: %s --install [--bashrc] [--profile]\n" "${BASH_SOURCE[0]}" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ ! $SHELL =~ bash ]]; then
|
if [[ ! $SHELL =~ bash ]]; then
|
||||||
echo "That environment script is designed to be used with bash being the shell."
|
echo "That environment script is designed to be used with bash being the shell."
|
||||||
echo "Please consider using bash to enjoy our features!"
|
echo "Please consider using bash to enjoy our features!"
|
||||||
return 1
|
_profile_finish 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Required for associative arrays (4.0+) and namerefs (4.3+)
|
# Required for associative arrays (4.0+) and namerefs (4.3+)
|
||||||
@@ -236,6 +349,10 @@ fi
|
|||||||
# Parse and load general configuration
|
# Parse and load general configuration
|
||||||
export PROFILE_CONF="$MYPATH/profile.conf"
|
export PROFILE_CONF="$MYPATH/profile.conf"
|
||||||
parse_conf "$PROFILE_CONF"
|
parse_conf "$PROFILE_CONF"
|
||||||
|
# Overload with user configuration if it exists
|
||||||
|
if [[ -f "$HOME/.profile.conf" ]]; then
|
||||||
|
parse_conf "$HOME/.profile.conf"
|
||||||
|
fi
|
||||||
load_conf system # Load Bash system behavior configuration (history, pager, etc.)
|
load_conf system # Load Bash system behavior configuration (history, pager, etc.)
|
||||||
load_conf general # General purpose configuration (compilation flags, etc.)
|
load_conf general # General purpose configuration (compilation flags, etc.)
|
||||||
|
|
||||||
@@ -255,8 +372,16 @@ shopt -u nullglob
|
|||||||
[[ $- == *i* ]] && export INTERACTIVE=1
|
[[ $- == *i* ]] && export INTERACTIVE=1
|
||||||
|
|
||||||
if [[ $INTERACTIVE ]]; then
|
if [[ $INTERACTIVE ]]; then
|
||||||
# For compiling (as we often compile with LFS/0linux...)
|
# Load custom bash completions
|
||||||
#Aliases
|
shopt -s nullglob
|
||||||
|
for _compl in "$MYPATH/profile.d/bash-completion/"*.sh; do
|
||||||
|
# shellcheck disable=SC1090 # Dynamic sourcing of completion scripts
|
||||||
|
[[ -f "$_compl" && -r "$_compl" ]] && . "$_compl"
|
||||||
|
done
|
||||||
|
unset _compl
|
||||||
|
shopt -u nullglob
|
||||||
|
|
||||||
|
# Aliases
|
||||||
load_alias aliases
|
load_alias aliases
|
||||||
|
|
||||||
# Define PS1
|
# Define PS1
|
||||||
@@ -281,7 +406,9 @@ if [[ $INTERACTIVE ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
unset pathremove pathprepend pathappend
|
unset -f _profile_is_sourced _profile_finish _profile_install_in_file _profile_install
|
||||||
|
unset -f parse_conf load_alias load_conf
|
||||||
|
unset -f pathremove pathprepend pathappend
|
||||||
|
|
||||||
#return 0
|
#return 0
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user