Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: ci

on:
push:
branches: [main, master, upgrade-path]
pull_request:

jobs:
shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { submodules: false }
- name: Run shellcheck
uses: ludeeus/action-shellcheck@master
with:
severity: error
scandir: "./"
ignore_paths: |
oh-my-zsh
zsh-autosuggestions
zsh-syntax-highlighting
k
vimrc
backup

syntax-zsh:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { submodules: false }
- name: Install zsh
run: sudo apt-get update && sudo apt-get install -y zsh
- name: Parse-check profile zshrc files
run: |
for f in profiles/classic/zshrc profiles/modern/zshrc zshrc.file; do
zsh -n "$f"
done

syntax-nvim:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { submodules: false }
- name: Install Neovim
run: sudo apt-get update && sudo apt-get install -y neovim
- name: Load-check init.lua
run: nvim --headless -u profiles/modern/nvim/init.lua +qa
37 changes: 37 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Changelog

## Unreleased — upgrade-path branch

### Added
- **`x doctor` offers profile upgrades.** When a user is on classic with a clean repo and an interactive tty, doctor prints the report and then offers to preview (`install.sh --dry-run --profile modern`) and, if accepted, apply the switch. Skippable with `--no-prompt`/`--report`. Intended as the friendly post-`git pull` entry point for existing classic users.
- **`x` command** (with `xydacshell` as a symlink alias for discoverability). PATH-installed dispatcher (`bin/x`) with subcommands: `install`, `update`, `switch`, `doctor`, `rollback`, `storage`, `uninstall`. Both profile zshrcs prepend `$XYDACSHELL_HOME/bin` to PATH so it "just works" after install. The installer warns if another `x` is already on PATH (or may be shadowed by a shell alias).
- **`xydacshell doctor`.** One-command diagnostic: current profile, managed symlinks, sacred custom file sizes, detected OS + package manager, modern-tool presence, most recent backup, git state.
- **`xydacshell rollback`.** Restore files from a timestamped backup dir (most recent by default; `--stamp` to pick one). Prompts before writing; `--dry-run` previews.
- **`xydacshell storage`.** Disk-usage report: local filesystems (via `duf`/`df`), top `$HOME` directories (via `dust`/`du`), package-manager caches (brew, npm, pnpm, cargo, pip, uv), docker, trash. `--caches` to focus, `--top N` to expand, `--clean` to prompt per-cache cleanup.
- **`xydacshell uninstall`.** Removes our symlinks, restores legacy `backup/.zshrc` / `backup/.vimrc` pre-install files when present. Does not delete the repo itself.
- **More modern tools in the installer.** `ncdu`, `dust`, `duf` added alongside starship/nvim/fzf/zoxide/lsd/bat. `dust` uses `cargo install du-dust` as fallback on apt/apk.
- **`LICENSE` file.** Formalizes the MIT license already declared in the README.
- **Modern-profile tool installer.** The installer now detects the OS (macOS / Linux) and an available package manager (brew / apt / dnf / pacman / apk), lists missing tools (starship, nvim, fzf, zoxide, lsd, bat) with their install commands, and prompts per tool. Uses the native package manager where possible; falls back to official curl installers (starship, zoxide) or `cargo install` (lsd on apt) where the pm doesn't ship the package. `--force` auto-accepts; `--dry-run` previews. Missing tools degrade gracefully — the profile still works without them.
- **Profiles.** Two installable profiles:
- `classic` — the original oh-my-zsh + materialshell-electro + amix/vimrc stack. Default for existing users.
- `modern` — starship prompt, Neovim with a small `init.lua`, graceful use of fzf/zoxide/lsd/bat when present, no oh-my-zsh dependency.
- **Profile dispatcher** in `zshrc.file` and `vimrc.file` — reads `~/.xydacshell/profile` and loads the active profile. Missing file → defaults to `classic`. Your `~/.zshrc` symlink keeps working; no action required for existing users.
- **Idempotent installer.** Re-running `install.sh` is safe. Creates a new `backup/<timestamp>/` directory per run; never touches existing backups.
- **Profile-switch flow.** `install.sh --profile modern` flips profile with confirmation.
- **Dry-run mode.** `install.sh --dry-run` prints everything it would do.
- **Safety preflight.** Installer refuses to run if there are uncommitted local edits to tracked files. Sacred files (`zshrc.custom`, `vimrc.custom`) are hash-verified before and after.
- **CI.** `shellcheck` on all shell scripts; `zsh -n` syntax-check on all zshrc files; `nvim --headless` load-check on the modern `init.lua`.

### Fixed
- **Broken git-status escape sequences** in `materialshell-electro.zsh-theme` (lines 68–73). Previously missing `%` before `%{$reset_color%}` would leak raw escape characters into the prompt. Classic users running a dirty repo would see garbled output.

### Preserved (intentionally unchanged)
- Existing users' `~/.xydacshell/backup/.zshrc` and `backup/.vimrc` (their pre-install configs) remain untouched.
- `zshrc.custom` and `vimrc.custom` are never rewritten by the installer.
- Every submodule. Classic still needs them.
- The `~/.zshrc` / `~/.vimrc` symlink targets stay the same paths (`zshrc.file` / `vimrc.file`) — existing symlinks continue to work without modification.

### Planned for a future major
- Retire the `classic` profile; drop `oh-my-zsh`, `amix/vimrc`, and `k` submodules.
- Make the modern profile fully submodule-free (source zsh plugins from `brew`/`apt`).
- Publish as a Homebrew tap for brew-managed upgrades.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2010-2026 Deepak Seth <xydac>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
160 changes: 121 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,139 @@
# xydacshell

# Xydac Shell
Opinionated Awesome Shell with cherry picked awesomeness.
An opinionated terminal setup. Two profiles, one managed toolchain, safe to re-run.

## Includes
* [oh-my-zsh](https://github.com/robbyrussell/oh-my-zsh)
* [vim rc](https://github.com/amix/vimrc)
* [zsh-syntax-highlighting](https://github.com/zsh-users/zsh-syntax-highlighting)
* [zsh-autosuggestions](https://github.com/zsh-users/zsh-autosuggestions)
* [k](https://github.com/supercrabtree/k)
![demo](vhs/demo.gif)

## Features
A lovely and Customized terminal System that declutters your shell customzations
- **classic** — oh-my-zsh with the `materialshell-electro` theme, amix/vimrc, and a handful of zsh plugins. The original xydacshell stack.
- **modern** — starship prompt, Neovim with a small `init.lua`, and graceful use of fzf / zoxide / lsd / bat / ncdu / dust / duf when they're installed.

Existing users: your setup still works. You stay on `classic` until you opt into `modern`.

## Screenshots
Prompt Preview
![Prompt Theme](https://raw.githubusercontent.com/xydac/xydacshell/master/screenshots/screenshot-prompt.png)
VIM Preview
![VI](https://raw.githubusercontent.com/xydac/xydacshell/master/screenshots/screenshot-vi.png)
## Install

## Installation, Updates, Uninstallation
### Installation :
```
git clone https://github.com/xydac/xydacshell.git ~/.xydacshell && cd ~/.xydacshell && bash install.sh
```bash
git clone --recurse-submodules https://github.com/xydac/xydacshell.git ~/.xydacshell
cd ~/.xydacshell
bash install.sh # fresh: defaults to classic
bash install.sh --profile modern # opt into modern
```
### Update:

### Upgrading from a pre-2026 install

Existing classic-profile installs keep working after a `git pull`. The updated
dispatcher defaults to classic when no profile file is present, so your shell
stays byte-for-byte the same. The only visible change is that the `x` command
appears on your `PATH` in new shells.

One-liner:

```bash
cd ~/.xydacshell && git pull --rebase --autostash && git submodule update --init --recursive && exec zsh
```
cd ~/.xydacshell && git pull --rebase

Then:

```bash
x doctor
```
### Uninstall
Restores Backup

`--autostash` stashes local hand-edits before the rebase and pops them after, so this works whether or not you have uncommitted changes. `x doctor` detects that you're on classic, checks that the repo is clean, and offers to dry-run and then apply a switch to the modern profile. Say no and nothing changes.

From then on, `x update` handles future pulls (git pull + submodules + reinstall) in one step.

The installer is idempotent — running it twice is safe. After it finishes, open a new shell. The `x` command (and its `xydacshell` alias) is on your `PATH`.

> **Heads-up on the name `x`:** the installer warns you if another `x` command already exists on your PATH (or via shell alias). Our `x` will take precedence in new shells. If you'd rather keep your existing `x`, use the `xydacshell` symlink instead — it's the same command.

## Usage

Once installed, everything runs through the `x` command (`xydacshell` is an alias):

```bash
x # help
x install [--profile X] # run the installer (same as bash install.sh)
x update # git pull + submodule sync + reinstall
x switch modern # flip profile
x doctor # diagnose current install state
x rollback # restore from the most recent backup
x storage # disk-usage report, per-cache cleanup prompts
x uninstall # remove cleanly, restore legacy backups
```
rm ~/.zshrc ~/.vimrc && mv ~/.xydacshell/backup/.zshrc ~/.zshrc && ~/.xydacshell/backup/.vimrc ~/.vimrc

Every command supports `--dry-run` and `--force`.

## Storage analytics

```bash
x storage # filesystems + $HOME top dirs + pkg caches
x storage --caches # only package-manager caches
x storage --top 20 # more $HOME entries
x storage --clean # after the report, prompt per-cache to prune
```
## Tweaks
* Alias : ```c``` --> Clears Screen
* Alias : ```gitlog``` --> One Liner Git Logs

### VI Tweaks
* Leader Key : ``` ` ```
* Shortcut : ``` ` + <Arrow Keys>``` --> Move Panes
* Shortcut : ``` ` + <TAB>``` --> Recent Files
The report covers:
- local filesystems (via `duf` if installed, else `df -h`)
- top directories in `$HOME` (via `dust` if installed, else `du | sort`)
- package-manager caches: brew · npm · pnpm · cargo · pip · uv
- docker (`docker system df`)
- trash

Clean-up runs the documented cleanup command for each cache (e.g. `brew cleanup -s`, `pnpm store prune`, `docker system prune -f`), guarded by per-cache y/n prompts. `--dry-run` previews.

## Customize

Edit these files — they outlive any profile switch or upgrade and are never touched by the installer.

- zsh: `~/.xydacshell/zshrc.custom`
- vim (classic): `~/.xydacshell/vimrc.custom`
- nvim (modern): `~/.xydacshell/nvim.custom.lua`

## Modern profile — optional tool install

The installer detects your OS + package manager and offers to install each missing tool, one at a time. Missing tools degrade gracefully — the modern profile still works without them.

```bash
# What the installer offers on macOS:
brew install starship neovim fzf zoxide lsd bat ncdu dust duf

# On Debian/Ubuntu the installer falls back to official scripts for
# tools apt doesn't ship (starship, zoxide, dust).
```

## Uninstall

```bash
x uninstall # removes our symlinks, restores legacy backups
rm -rf ~/.xydacshell # removes the repo itself
```

## Repository layout

```
xydacshell/
├── bin/x # dispatcher on your PATH
├── bin/xydacshell # symlink → x
├── install.sh # idempotent, profile-aware
├── lib/
│ ├── util.sh # shared shell helpers
│ ├── modern-tools.sh # OS + PM detection, tool installer
│ └── cmds/ # one file per `xydacshell <verb>`
├── profiles/
│ ├── classic/ { zshrc, vimrc } # the original setup
│ └── modern/ { zshrc, starship.toml, nvim/init.lua }
├── zshrc.file, vimrc.file # dispatchers (read the profile, load config)
├── materialshell-electro.zsh-theme # classic prompt theme
├── backup/ # timestamped backups per install run
└── .github/workflows/ci.yml # shellcheck + zsh/nvim syntax checks
```

## Further Customization
* Vim Customization : update your custom tweaks in ```~/.xydacshell/vimrc.custom```
* ZSH Customization : update your custom tweaks in ```~/.xydacshell/zshrc.custom```
## Compatibility

## Minimum Requirement
* zsh
* git
- `zsh` required.
- `git` required.
- `classic` profile: submodules are used (oh-my-zsh, amix/vimrc, etc.).
- `modern` profile: Neovim recommended; starship, fzf, zoxide, lsd, bat are optional with fallbacks.

## License
MIT

- Pull Request Welcome
MIT. Pull requests welcome.
68 changes: 68 additions & 0 deletions bin/x
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
# xydacshell subcommand dispatcher.
# Installed as `x` (primary) with an `xydacshell` symlink for discoverability.
# Add $XYDACSHELL_HOME/bin to PATH (the profile zshrcs do this for you).

set -euo pipefail

: ${XYDACSHELL_HOME:=$HOME/.xydacshell}
export XYDACSHELL_HOME

if [ ! -f "$XYDACSHELL_HOME/lib/util.sh" ]; then
echo "x: cannot find $XYDACSHELL_HOME/lib/util.sh — is XYDACSHELL_HOME correct?" >&2
exit 1
fi

# shellcheck source=../lib/util.sh
. "$XYDACSHELL_HOME/lib/util.sh"

usage() {
cat <<'EOF'
x — your terminal setup, managed.

usage: x <command> [args]

commands
install [flags] run the installer (same as bash install.sh)
update git pull + submodule sync + reinstall
switch <classic|modern> switch profile
doctor diagnose current install state
rollback [--stamp YYYYMMDDTHHMMSSZ]
restore from a timestamped backup
storage [--caches] [--top N] [--clean]
disk usage report; --clean prompts to prune
uninstall remove installation, restore legacy backups

global flags
--dry-run preview (supported by install/update/switch/rollback/storage/uninstall)
--force auto-accept prompts
--help, -h show this message or per-command help

run 'x <command> --help' for per-command help.
(also available as `xydacshell`.)
EOF
}

cmd="${1:-help}"
shift || true

case "$cmd" in
install|update|switch|doctor|rollback|storage|uninstall)
src="$XYDACSHELL_HOME/lib/cmds/$cmd.sh"
if [ ! -f "$src" ]; then
xs_err "command file missing: $src"
exit 1
fi
# shellcheck source=/dev/null
. "$src"
"xs_cmd_$cmd" "$@"
;;
help|--help|-h|"")
usage
;;
*)
xs_err "unknown command: $cmd"
usage >&2
exit 2
;;
esac
1 change: 1 addition & 0 deletions bin/xydacshell
Loading
Loading