├── .envrc ├── .github ├── CODE_OF_CONDUCT.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ └── bug_report.md ├── config.yml └── workflows │ └── nix.yml ├── .gitignore ├── .ignore ├── LICENSE ├── README.md ├── build.sh ├── demo.tape ├── docs ├── assets │ └── images │ │ └── isd.png ├── customization.md ├── faq.md ├── index.md ├── javascripts │ └── asciinema-player.min.js ├── loggen.py ├── media.md ├── roadmap.md ├── security.md └── stylesheets │ ├── asciinema-player.css │ ├── custom-asciinema-player.css │ └── extra_fonts.css ├── docs_glossary └── abbreviations.md ├── flake.lock ├── flake.nix ├── macros.py ├── mkdocs.yml ├── pyproject.toml ├── share ├── applications │ └── isd.desktop └── icons │ └── hicolor │ └── 512x512 │ └── apps │ └── isd.png ├── src └── isd_tui │ ├── __init__.py │ ├── architecture.md │ ├── dom.tcss │ ├── isd.py │ └── keybinding_notes.md ├── tests ├── __snapshots__ │ └── test_visual │ │ ├── test_snap_donation_screen.svg │ │ ├── test_snap_height.svg │ │ ├── test_snap_preview[#--content-tab-cat].svg │ │ ├── test_snap_preview[#--content-tab-dependencies].svg │ │ ├── test_snap_preview[#--content-tab-help].svg │ │ ├── test_snap_preview[#--content-tab-journal].svg │ │ ├── test_snap_preview[#--content-tab-show].svg │ │ ├── test_snap_preview[#--content-tab-status].svg │ │ ├── test_snap_systemctl_action.svg │ │ └── test_snap_toggled_mode.svg ├── data_generator.nu ├── fake_list_unit_files.json ├── fake_list_units.json ├── fake_runner.sh ├── integration-test │ ├── 0-isd-example-unit-01.service.cat.txt │ ├── 0-isd-example-unit-01.service.help.txt │ ├── 0-isd-example-unit-01.service.journalctl.txt │ ├── 0-isd-example-unit-01.service.list-dependencies.txt │ ├── 0-isd-example-unit-01.service.show.txt │ ├── 0-isd-example-unit-01.service.status.txt │ ├── 0-isd-example-unit-02.service.cat.txt │ ├── 0-isd-example-unit-02.service.help.txt │ ├── 0-isd-example-unit-02.service.journalctl.txt │ ├── 0-isd-example-unit-02.service.list-dependencies.txt │ ├── 0-isd-example-unit-02.service.show.txt │ ├── 0-isd-example-unit-02.service.status.txt │ ├── 0-isd-example-unit-03.service.cat.txt │ ├── 0-isd-example-unit-03.service.help.txt │ ├── 0-isd-example-unit-03.service.journalctl.txt │ ├── 0-isd-example-unit-03.service.list-dependencies.txt │ ├── 0-isd-example-unit-03.service.show.txt │ ├── 0-isd-example-unit-03.service.status.txt │ ├── 0-isd-example-unit-04.service.cat.txt │ ├── 0-isd-example-unit-04.service.help.txt │ ├── 0-isd-example-unit-04.service.journalctl.txt │ ├── 0-isd-example-unit-04.service.list-dependencies.txt │ ├── 0-isd-example-unit-04.service.show.txt │ ├── 0-isd-example-unit-04.service.status.txt │ ├── list-unit-files.txt │ └── list-units.txt ├── journalctl ├── quickemu │ ├── README.md │ ├── ubuntu-server-16.04.conf │ ├── ubuntu-server-18.04.conf │ ├── ubuntu-server-20.04.conf │ └── ubuntu-server-22.04.conf ├── systemctl ├── test-systemd-229 │ ├── list-unit-files.txt │ ├── list-units.txt │ ├── systemd-timesyncd.service.cat.txt │ ├── systemd-timesyncd.service.help.txt │ ├── systemd-timesyncd.service.journalctl.txt │ ├── systemd-timesyncd.service.list-dependencies.txt │ ├── systemd-timesyncd.service.show.txt │ └── systemd-timesyncd.service.status.txt ├── test-systemd-237 │ ├── list-unit-files.txt │ ├── list-units.txt │ ├── systemd-timesyncd.service.cat.txt │ ├── systemd-timesyncd.service.help.txt │ ├── systemd-timesyncd.service.journalctl.txt │ ├── systemd-timesyncd.service.list-dependencies.txt │ ├── systemd-timesyncd.service.show.txt │ └── systemd-timesyncd.service.status.txt ├── test-systemd-245 │ ├── list-unit-files.txt │ ├── list-units.txt │ ├── systemd-timesyncd.service.cat.txt │ ├── systemd-timesyncd.service.help.txt │ ├── systemd-timesyncd.service.journalctl.txt │ ├── systemd-timesyncd.service.list-dependencies.txt │ ├── systemd-timesyncd.service.show.txt │ └── systemd-timesyncd.service.status.txt ├── test-systemd-249 │ ├── list-unit-files.txt │ ├── list-units.txt │ ├── systemd-timesyncd.service.cat.txt │ ├── systemd-timesyncd.service.help.txt │ ├── systemd-timesyncd.service.journalctl.txt │ ├── systemd-timesyncd.service.list-dependencies.txt │ ├── systemd-timesyncd.service.show.txt │ └── systemd-timesyncd.service.status.txt ├── test_data_generator.sh ├── test_docs.py ├── test_parsing.py └── test_visual.py └── uv.lock /.envrc: -------------------------------------------------------------------------------- 1 | use flake .# --impure 2 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [safe.boat9582@fastmail.com](mailto:safe.boat9582@fastmail.com). 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: isdproject # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[Bug]" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Screenshots/Recording** 21 | If applicable, add screenshots or recordings to help explain your problem. 22 | This is especially helpful if your issue is related to some "dynamic" component. 23 | 24 | **Environment:** 25 | 26 | 1. Distribution: Use the output from `cat /etc/os-release`: 27 | ``` 28 | 29 | ``` 30 | 31 | 2. `isd` version: Open `isd`, open the command palette and run `Show the version` 32 | 33 | ``` 34 | 35 | ``` 36 | 37 | 3. Provide the `systemd` version via `systemctl --version` 38 | 39 | ``` 40 | 4 | isd logo 5 | 6 | 7 | 8 | > `isd` – a better way to work with `systemd` units 9 | 10 | Simplify `systemd` management with `isd`! 11 | `isd` is a TUI offering fuzzy search for units, auto-refreshing previews, 12 | smart `sudo` handling, and a fully customizable interface 13 | for power-users and newcomers alike. 14 | 15 | 16 | 17 | `isd` is a keyboard-focused, highly customizable TUI with the following features: 18 | 19 | - Quickly switch between `system` and `user` units 20 | - Fuzzy search units 21 | - Auto refresh previews 22 | - Quickly open outputs in a pager or editor 23 | - Auto `sudo` prefixing if required 24 | - Auto rescale depending on terminal window size (fluid design) 25 | - Extensive command palette with many keyboard shortcuts 26 | - Fully configurable keybindings 27 | - Optional input state caching for common inputs 28 | - Theme support 29 | - YAML configuration file _with auto-complete_ 30 | 31 | 32 | ## Demo 33 | 34 | https://github.com/user-attachments/assets/a22868c0-fc01-4973-86ea-410b80b188a8 35 | 36 | [Click here for a higher quality recording](https://isd-project.github.io/isd/#working-with-isd). 37 | 38 | ## Documentation 39 | 40 | The documentation is live at: 41 | 42 | - 43 | 44 | ## Installation 45 | 46 | The tool can be installed via `uv`, `nix`, and as an `AppImage`. 47 | Refer to the [official installation documentation](https://isd-project.github.io/isd/#installation) for more details. 48 | 49 | ## Road map 50 | 51 | 52 | A collection of some _unordered_ ideas that could improve `isd`: 53 | 54 | - [x] Add icon for project and application menu 55 | - [x] Support old `systemd` version 56 | - [ ] Option to view the security rating of units 57 | - [ ] Improve highlighting of `systemd` units (tree-sitter grammar) 58 | - [ ] Write a custom, more secure `$EDITOR` integration (more secure `sytemctl edit`) 59 | - [ ] Allow customization of preview windows 60 | - [ ] Improve `journal_pager` integration 61 | - [ ] Add custom sort options 62 | - [ ] Faster fuzzy search 63 | - [ ] Improve default themes 64 | 65 | 66 | 67 | ## Acknowledgments 68 | 69 | 70 | Big thanks to the developers of: 71 | 72 | - [systemd](https://systemd.io/) for creating the most widely used service manager for Linux 73 | - [NixOS](https://nixos.org/) for piquing my interest in `systemd` and service managers 74 | - [`sysz`](https://github.com/joehillen/sysz) for providing a starting point and a desire to build a more complex `systemctl` TUI 75 | - [textual](https://textual.textualize.io/) for making it a breeze to create TUIs in Python 76 | - [mkdocs-material](https://squidfunk.github.io/mkdocs-material/) for building a solid and simple to use static site generator for the documentation 77 | - [asciinema](https://docs.asciinema.org/) for developing an easy to use _and self-hostable_ terminal recorder and player 78 | - [vhs](https://github.com/charmbracelet/vhs) for creating a scriptable terminal program 79 | - [posting](https://github.com/darrenburns/posting) for showing me how to use `textual` 80 | 81 | 82 | 83 | 84 | ## Star history ⭐ 85 | [![Star History Chart](https://api.star-history.com/svg?repos=isd-project/isd&type=Date)](https://star-history.com/#isd-project/isd&Date) 86 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | set -euo pipefail 2 | 3 | grep "current_version =" "$REPO_ROOT/pyproject.toml" 4 | 5 | while true; do 6 | read -rp "Is the current version flag correctly set? [y/N] " yn 7 | case $yn in 8 | [yY]* ) break;; 9 | [Nn]* ) exit;; 10 | * ) exit ;; 11 | esac 12 | done 13 | 14 | # update the caches 15 | uv sync 16 | touch "$REPO_ROOT/flake.nix" 17 | 18 | # ensure that everything works as expected 19 | mkdocs build --clean 20 | pytest 21 | 22 | rm -rf "$REPO_ROOT/dist" 23 | rm -f "$REPO_ROOT/isd.x86_64-linux.AppImage" 24 | rm -f "$REPO_ROOT/isd.aarch64-linux.AppImage" 25 | 26 | # start building everything 27 | uv build 28 | 29 | echo "Building x86-64 isd-AppImage" 30 | nix build .#isd-AppImage 31 | cp "$(readlink -f ./result)" isd.x86_64-linux.AppImage 32 | 33 | echo "Building aarch64 isd-AppImage" 34 | nix build .#packages.aarch64-linux.isd-AppImage 35 | cp "$(readlink -f ./result)" isd.aarch64-linux.AppImage 36 | 37 | # publish latest docs 38 | echo "Publishing docs" 39 | mkdocs gh-deploy --no-history 40 | 41 | echo "Remember to update PyPI!" 42 | 43 | -------------------------------------------------------------------------------- /demo.tape: -------------------------------------------------------------------------------- 1 | # VHS documentation 2 | # 3 | # Output: 4 | # Output .gif Create a GIF output at the given 5 | # Output .mp4 Create an MP4 output at the given 6 | # Output .webm Create a WebM output at the given 7 | # 8 | # Require: 9 | # Require Ensure a program is on the $PATH to proceed 10 | # 11 | # Settings: 12 | # Set FontSize Set the font size of the terminal 13 | # Set FontFamily Set the font family of the terminal 14 | # Set Height Set the height of the terminal 15 | # Set Width Set the width of the terminal 16 | # Set LetterSpacing Set the font letter spacing (tracking) 17 | # Set LineHeight Set the font line height 18 | # Set LoopOffset % Set the starting frame offset for the GIF loop 19 | # Set Theme Set the theme of the terminal 20 | # Set Padding Set the padding of the terminal 21 | # Set Framerate Set the framerate of the recording 22 | # Set PlaybackSpeed Set the playback speed of the recording 23 | # Set MarginFill Set the file or color the margin will be filled with. 24 | # Set Margin Set the size of the margin. Has no effect if MarginFill isn't set. 25 | # Set BorderRadius Set terminal border radius, in pixels. 26 | # Set WindowBar Set window bar type. (one of: Rings, RingsRight, Colorful, ColorfulRight) 27 | # Set WindowBarSize Set window bar size, in pixels. Default is 40. 28 | # Set TypingSpeed