├── .all-contributorsrc ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ └── stale.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── async ├── async.zsh ├── docs ├── .nojekyll ├── CNAME ├── README.md ├── _media │ ├── adaptive_home_relative_path.png │ ├── arrow_symbols │ │ ├── default.png │ │ └── glyph_arrow.png │ ├── bg.png │ ├── configuration_examples │ │ ├── bash.png │ │ ├── dracula.png │ │ ├── half_pure.png │ │ └── pure.png │ ├── cursors │ │ ├── beam.png │ │ ├── block.png │ │ └── underscore.png │ ├── favicon.ico │ ├── git_relative_path │ │ ├── git_no_relative_path.png │ │ └── git_relative_path.png │ ├── home_relative_path.png │ ├── layouts │ │ ├── half_pure.png │ │ ├── multiline.png │ │ ├── pure.png │ │ ├── pure_verbose.png │ │ ├── singleline.png │ │ └── singleline_verbose.png │ ├── left_prompt_prefix │ │ ├── custom_command.png │ │ ├── date.png │ │ └── date_with_options.png │ ├── logo.svg │ ├── relative_path_off.png │ ├── return_code.png │ ├── right_prompt_prefix.png │ ├── symbols │ │ ├── arrow.png │ │ ├── default.png │ │ └── dollar_sign.png │ └── typewritten.gif ├── _sidebar.md ├── credits.md ├── git_status_indicators.md ├── index.html ├── installation.md ├── prompt_color_customization.md ├── prompt_customization.md ├── return_code.md ├── robots.txt └── sitemap.xml ├── lib ├── colors.zsh └── git.zsh ├── package.json ├── prompt_typewritten_setup ├── scripts ├── install.sh └── uninstall.sh ├── typewritten.plugin.zsh ├── typewritten.zsh └── typewritten.zsh-theme /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "badgeTemplate": " -orange.svg?style=flat-square\" alt=\"All contributors\" />", 8 | "contributors": [ 9 | { 10 | "login": "reobin", 11 | "name": "Robin Gagnon", 12 | "avatar_url": "https://avatars1.githubusercontent.com/u/5920450?v=4", 13 | "profile": "https://github.com/reobin", 14 | "contributions": [ 15 | "code", 16 | "maintenance", 17 | "doc" 18 | ] 19 | }, 20 | { 21 | "login": "thbe", 22 | "name": "thbe", 23 | "avatar_url": "https://avatars3.githubusercontent.com/u/495530?v=4", 24 | "profile": "https://www.thbe.org/", 25 | "contributions": [ 26 | "code" 27 | ] 28 | }, 29 | { 30 | "login": "erikr", 31 | "name": "Erik Reinertsen", 32 | "avatar_url": "https://avatars2.githubusercontent.com/u/1253422?v=4", 33 | "profile": "http://erikreinertsen.com", 34 | "contributions": [ 35 | "code", 36 | "doc" 37 | ] 38 | }, 39 | { 40 | "login": "artem-zinnatullin", 41 | "name": "Artem Zinnatullin :slowpoke:", 42 | "avatar_url": "https://avatars0.githubusercontent.com/u/967132?v=4", 43 | "profile": "https://twitter.com/artem_zin", 44 | "contributions": [ 45 | "code", 46 | "doc" 47 | ] 48 | }, 49 | { 50 | "login": "nizarmah", 51 | "name": "Nizar", 52 | "avatar_url": "https://avatars1.githubusercontent.com/u/5631091?v=4", 53 | "profile": "https://nizarmah.me/", 54 | "contributions": [ 55 | "code" 56 | ] 57 | }, 58 | { 59 | "login": "johnletey", 60 | "name": "John Letey", 61 | "avatar_url": "https://avatars1.githubusercontent.com/u/62398724?v=4", 62 | "profile": "https://github.com/johnletey", 63 | "contributions": [ 64 | "doc" 65 | ] 66 | }, 67 | { 68 | "login": "ninja18", 69 | "name": "Niranjan", 70 | "avatar_url": "https://avatars2.githubusercontent.com/u/19199814?v=4", 71 | "profile": "http://www.linkedin.com/in/ninja18", 72 | "contributions": [ 73 | "code" 74 | ] 75 | }, 76 | { 77 | "login": "mrillusi0n", 78 | "name": "Nikhil", 79 | "avatar_url": "https://avatars1.githubusercontent.com/u/37063502?v=4", 80 | "profile": "https://github.com/mrillusi0n", 81 | "contributions": [ 82 | "ideas" 83 | ] 84 | }, 85 | { 86 | "login": "tdeekens", 87 | "name": "Tobias Deekens", 88 | "avatar_url": "https://avatars3.githubusercontent.com/u/1877073?v=4", 89 | "profile": "http://tdeekens.name", 90 | "contributions": [ 91 | "ideas" 92 | ] 93 | }, 94 | { 95 | "login": "xenoterracide", 96 | "name": "Caleb Cushing", 97 | "avatar_url": "https://avatars3.githubusercontent.com/u/5517?v=4", 98 | "profile": "https://xenoterracide.com", 99 | "contributions": [ 100 | "ideas" 101 | ] 102 | }, 103 | { 104 | "login": "eleven4y", 105 | "name": "Konstantin Petrov", 106 | "avatar_url": "https://avatars2.githubusercontent.com/u/51177852?v=4", 107 | "profile": "http://k.petrov4y@outlook.com", 108 | "contributions": [ 109 | "code", 110 | "doc" 111 | ] 112 | }, 113 | { 114 | "login": "zembrowski", 115 | "name": "Krzysztof Tomasz Zembrowski", 116 | "avatar_url": "https://avatars0.githubusercontent.com/u/2451083?v=4", 117 | "profile": "https://rechtlogisch.de", 118 | "contributions": [ 119 | "doc" 120 | ] 121 | }, 122 | { 123 | "login": "Ivan-Velickovic", 124 | "name": "Ivan Velickovic", 125 | "avatar_url": "https://avatars0.githubusercontent.com/u/10481259?v=4", 126 | "profile": "https://github.com/Ivan-Velickovic", 127 | "contributions": [ 128 | "doc" 129 | ] 130 | }, 131 | { 132 | "login": "barischrooneyj", 133 | "name": "Jeremy Barisch-Rooney", 134 | "avatar_url": "https://avatars0.githubusercontent.com/u/6631452?v=4", 135 | "profile": "https://github.com/barischrooneyj", 136 | "contributions": [ 137 | "ideas" 138 | ] 139 | }, 140 | { 141 | "login": "oniGino", 142 | "name": "Gino", 143 | "avatar_url": "https://avatars3.githubusercontent.com/u/33404137?v=4", 144 | "profile": "https://github.com/oniGino", 145 | "contributions": [ 146 | "bug" 147 | ] 148 | }, 149 | { 150 | "login": "frdrk", 151 | "name": "frdrk", 152 | "avatar_url": "https://avatars3.githubusercontent.com/u/3447600?v=4", 153 | "profile": "https://github.com/frdrk", 154 | "contributions": [ 155 | "bug", 156 | "userTesting" 157 | ] 158 | }, 159 | { 160 | "login": "huy-ha", 161 | "name": "Huy Ha", 162 | "avatar_url": "https://avatars0.githubusercontent.com/u/33562579?v=4", 163 | "profile": "https://github.com/huy-ha", 164 | "contributions": [ 165 | "bug", 166 | "userTesting" 167 | ] 168 | }, 169 | { 170 | "login": "foruniverse", 171 | "name": "yanyan", 172 | "avatar_url": "https://avatars3.githubusercontent.com/u/32241199?v=4", 173 | "profile": "https://github.com/foruniverse", 174 | "contributions": [ 175 | "code" 176 | ] 177 | }, 178 | { 179 | "login": "louisdecharson", 180 | "name": "Louis de Charsonville", 181 | "avatar_url": "https://avatars1.githubusercontent.com/u/3234544?v=4", 182 | "profile": "http://louisdecharson.github.io", 183 | "contributions": [ 184 | "bug", 185 | "code" 186 | ] 187 | }, 188 | { 189 | "login": "crepppy", 190 | "name": "Jack Chapman", 191 | "avatar_url": "https://avatars1.githubusercontent.com/u/38158363?v=4", 192 | "profile": "https://jack-chapman.com", 193 | "contributions": [ 194 | "code", 195 | "bug" 196 | ] 197 | }, 198 | { 199 | "login": "GPSBach", 200 | "name": "GPSBach", 201 | "avatar_url": "https://avatars1.githubusercontent.com/u/35227624?v=4", 202 | "profile": "https://github.com/GPSBach", 203 | "contributions": [ 204 | "code", 205 | "ideas" 206 | ] 207 | }, 208 | { 209 | "login": "wwlorey", 210 | "name": "Will Lorey", 211 | "avatar_url": "https://avatars3.githubusercontent.com/u/22795803?v=4", 212 | "profile": "http://williamlorey.com", 213 | "contributions": [ 214 | "doc" 215 | ] 216 | }, 217 | { 218 | "login": "gartunius", 219 | "name": "Gabriel Ataide", 220 | "avatar_url": "https://avatars0.githubusercontent.com/u/27605237?v=4", 221 | "profile": "https://gartunius.github.io", 222 | "contributions": [ 223 | "bug", 224 | "code" 225 | ] 226 | }, 227 | { 228 | "login": "Scupake", 229 | "name": "Scupake", 230 | "avatar_url": "https://avatars0.githubusercontent.com/u/61241021?v=4", 231 | "profile": "https://github.com/Scupake", 232 | "contributions": [ 233 | "ideas", 234 | "test" 235 | ] 236 | }, 237 | { 238 | "login": "CrystalJewell", 239 | "name": "Crystal Adkins", 240 | "avatar_url": "https://avatars.githubusercontent.com/u/21298255?v=4", 241 | "profile": "https://github.com/CrystalJewell", 242 | "contributions": [ 243 | "code", 244 | "ideas" 245 | ] 246 | }, 247 | { 248 | "login": "juanCortelezzi", 249 | "name": "J.B.C", 250 | "avatar_url": "https://avatars.githubusercontent.com/u/57237705?v=4", 251 | "profile": "https://github.com/juanCortelezzi", 252 | "contributions": [ 253 | "bug", 254 | "code" 255 | ] 256 | }, 257 | { 258 | "login": "jeevatattva", 259 | "name": "Jeeva K", 260 | "avatar_url": "https://avatars.githubusercontent.com/u/26855245?v=4", 261 | "profile": "https://github.com/jeevatattva", 262 | "contributions": [ 263 | "bug", 264 | "ideas" 265 | ] 266 | }, 267 | { 268 | "login": "subhajit-halder", 269 | "name": "awakened", 270 | "avatar_url": "https://avatars.githubusercontent.com/u/54535412?v=4", 271 | "profile": "https://github.com/subhajit-halder", 272 | "contributions": [ 273 | "ideas" 274 | ] 275 | }, 276 | { 277 | "login": "spamwax", 278 | "name": "spamwax", 279 | "avatar_url": "https://avatars.githubusercontent.com/u/1251233?v=4", 280 | "profile": "https://github.com/spamwax", 281 | "contributions": [ 282 | "ideas" 283 | ] 284 | }, 285 | { 286 | "login": "Austin-Ray", 287 | "name": "Austin Ray", 288 | "avatar_url": "https://avatars.githubusercontent.com/u/1640737?v=4", 289 | "profile": "https://austinray.io", 290 | "contributions": [ 291 | "code", 292 | "bug" 293 | ] 294 | }, 295 | { 296 | "login": "Pound-Hash", 297 | "name": "Alan", 298 | "avatar_url": "https://avatars.githubusercontent.com/u/51193876?v=4", 299 | "profile": "https://github.com/Pound-Hash", 300 | "contributions": [ 301 | "bug" 302 | ] 303 | }, 304 | { 305 | "login": "vedantnn71", 306 | "name": "Vedant Nandwana", 307 | "avatar_url": "https://avatars.githubusercontent.com/u/70624701?v=4", 308 | "profile": "http://vedantnandwana.me", 309 | "contributions": [ 310 | "doc" 311 | ] 312 | }, 313 | { 314 | "login": "KEDLogic", 315 | "name": "Kyle Dozier", 316 | "avatar_url": "https://avatars.githubusercontent.com/u/9738036?v=4", 317 | "profile": "https://github.com/KEDLogic", 318 | "contributions": [ 319 | "doc", 320 | "ideas" 321 | ] 322 | }, 323 | { 324 | "login": "danielbayley", 325 | "name": "Daniel Bayley", 326 | "avatar_url": "https://avatars.githubusercontent.com/u/7797479?v=4", 327 | "profile": "http://vimeo.com/danielbayley", 328 | "contributions": [ 329 | "code", 330 | "doc" 331 | ] 332 | } 333 | ], 334 | "contributorsPerLine": 7, 335 | "projectName": "typewritten", 336 | "projectOwner": "reobin", 337 | "repoType": "github", 338 | "repoHost": "https://github.com", 339 | "skipCi": true, 340 | "commitConvention": "angular" 341 | } 342 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: reobin 2 | custom: "https://paypal.me/reobin" 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 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 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Close stale issues" 2 | on: 3 | schedule: 4 | - cron: "0 0 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v3 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | stale-issue-message: 'Stale issue message' 14 | stale-pr-message: 'Stale pull request message' 15 | stale-issue-label: 'no-issue-activity' 16 | exempt-issue-labels: 'awaiting-approval,work-in-progress' 17 | stale-pr-label: 'no-pr-activity' 18 | exempt-pr-labels: 'awaiting-approval,work-in-progress' 19 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at contact@reobin.dev. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## How to Contribute 2 | 3 | Pull requests are welcome in this repository. 4 | 5 | ## Local installation 6 | 7 | The easiest way to use a local copy to test out changes is to use npm. 8 | 9 | 1. fork the repository and clone it on your machine 10 | 2. `cd` into it 11 | 3. `npm install -g .` 12 | 4. reload zsh: `zsh` 13 | 14 | Any change you make to the prompt will be active after reloading zsh. 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robin Gagnon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | typewritten 3 |

4 | 5 |

typewritten

6 | 7 |

A minimal zsh prompt

8 | 9 |
10 | 11 |

12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |

22 |

23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | All contributors 32 | 33 | 34 |

35 | 36 |

37 | typewritten zsh prompt demo 38 |

39 | 40 | > Terminal is [iTerm2](https://iterm2.com/) — Font is [JetBrains Mono](https://www.jetbrains.com/lp/mono/) — Terminal theme is [Seoul256](https://github.com/junegunn/seoul256.vim) 41 | > 42 | > See how to make your terminal look exactly like the demo [here](https://github.com/reobin/typewritten/discussions/128) 43 | 44 | ## Features 45 | 46 | - Asynchronous git info 47 | - Fully customizable 48 | - [Colors for any of the prompt sections](https://typewritten.dev/#/prompt_color_customization) 49 | - [Prompt layout](https://typewritten.dev/#/prompt_customization?id=typewritten_prompt_layout) 50 | - [Prompt symbol](https://typewritten.dev/#/prompt_customization?id=typewritten_symbol) 51 | - [Constant display of git home directory](https://typewritten.dev/#/prompt_customization?id=typewritten_git_relative_path) 52 | - [Cursor](https://typewritten.dev/#/prompt_customization?id=typewritten_cursor) 53 | - [Prefix on right prompt](https://typewritten.dev/#/prompt_customization?id=typewritten_right_prompt_prefix) 54 | 55 | ## Quick start 56 | 57 | ### [npm](https://npmjs.com/get-npm) 58 | 59 | ```shell 60 | npm install -g typewritten 61 | ``` 62 | 63 | That's it. The script will make the necessary symlinks to `fpath` and set the prompt in your `.zshrc`. 64 | 65 | ### [Homebrew](https://brew.sh) 66 | 67 | ```shell 68 | brew install typewritten 69 | ``` 70 | 71 | Then load typewritten in your `.zshrc` by using zsh prompinit: 72 | 73 | ```shell 74 | autoload -U promptinit; promptinit 75 | prompt typewritten 76 | ``` 77 | 78 | ### Manual 79 | 80 | Clone the typewritten repository somewhere you can easily link. I recommend creating a `.zsh` directory at root. 81 | 82 | ```shell 83 | mkdir -p "$HOME/.zsh" 84 | git clone https://github.com/reobin/typewritten.git "$HOME/.zsh/typewritten" 85 | ``` 86 | 87 | Load typewritten in your `.zshrc` by using zsh prompinit: 88 | 89 | ```shell 90 | fpath+=$HOME/.zsh/typewritten 91 | autoload -U promptinit; promptinit 92 | prompt typewritten 93 | ``` 94 | 95 | Note: if using `oh-my-zsh`, set `ZSH_THEME=""` in your `.zshrc` to disable oh-my-zsh themes. 96 | 97 | ### Other ways to install 98 | 99 | Many other ways to install typewritten are available in the [docs](https://typewritten.dev/#/installation) 100 | 101 | ## Customization 102 | 103 | typewritten is customizable in many ways. To keep the readme file as lean as possible, the documentation was moved to [https://typewritten.dev](https://typewritten.dev). 104 | 105 | The documentation is separated into two parts: 106 | 107 | - [Prompt customization](https://typewritten.dev/#/prompt_customization), everything to do with how and where the info is displayed 108 | - [Prompt color customization](https://typewritten.dev/#/prompt_color_customization), set a custom color for any of the prompt sections 109 | 110 | **Example of 3 customized typewritten prompts** 111 | 112 |

113 | 114 |

115 |

116 | 117 | 118 |

119 | 120 | ## Contributors ✨ 121 | 122 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
Robin Gagnon
Robin Gagnon

💻 🚧 📖
thbe
thbe

💻
Erik Reinertsen
Erik Reinertsen

💻 📖
Artem Zinnatullin :slowpoke:
Artem Zinnatullin :slowpoke:

💻 📖
Nizar
Nizar

💻
John Letey
John Letey

📖
Niranjan
Niranjan

💻
Nikhil
Nikhil

🤔
Tobias Deekens
Tobias Deekens

🤔
Caleb Cushing
Caleb Cushing

🤔
Konstantin Petrov
Konstantin Petrov

💻 📖
Krzysztof Tomasz Zembrowski
Krzysztof Tomasz Zembrowski

📖
Ivan Velickovic
Ivan Velickovic

📖
Jeremy Barisch-Rooney
Jeremy Barisch-Rooney

🤔
Gino
Gino

🐛
frdrk
frdrk

🐛 📓
Huy Ha
Huy Ha

🐛 📓
yanyan
yanyan

💻
Louis de Charsonville
Louis de Charsonville

🐛 💻
Jack Chapman
Jack Chapman

💻 🐛
GPSBach
GPSBach

💻 🤔
Will Lorey
Will Lorey

📖
Gabriel Ataide
Gabriel Ataide

🐛 💻
Scupake
Scupake

🤔 ⚠️
Crystal Adkins
Crystal Adkins

💻 🤔
J.B.C
J.B.C

🐛 💻
Jeeva K
Jeeva K

🐛 🤔
awakened
awakened

🤔
spamwax
spamwax

🤔
Austin Ray
Austin Ray

💻 🐛
Alan
Alan

🐛
Vedant Nandwana
Vedant Nandwana

📖
Kyle Dozier
Kyle Dozier

📖 🤔
Daniel Bayley
Daniel Bayley

💻 📖
175 | 176 | 177 | 178 | 179 | 180 | 181 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 182 | 183 | ## Supporters 🌞 184 | 185 | [![Stargazers repo roster for @reobin/typewritten](https://reporoster.com/stars/reobin/typewritten)](https://github.com/reobin/typewritten/stargazers) 186 | 187 | [![Forkers repo roster for @reobin/typewritten](https://reporoster.com/forks/reobin/typewritten)](https://github.com/reobin/typewritten/network/members) 188 | 189 | ## Credits 190 | 191 | - `pure` layout is inspired by [Pure](https://github.com/sindresorhus/pure) 192 | - `npm` install and uninstall scripts are from [Spaceship prompt](https://github.com/spaceship-prompt/spaceship-prompt) 193 | -------------------------------------------------------------------------------- /async: -------------------------------------------------------------------------------- 1 | async.zsh -------------------------------------------------------------------------------- /async.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # 4 | # zsh-async 5 | # 6 | # version: v1.8.6 7 | # author: Mathias Fredriksson 8 | # url: https://github.com/mafredri/zsh-async 9 | # 10 | 11 | typeset -g ASYNC_VERSION=1.8.6 12 | # Produce debug output from zsh-async when set to 1. 13 | typeset -g ASYNC_DEBUG=${ASYNC_DEBUG:-0} 14 | 15 | # Execute commands that can manipulate the environment inside the async worker. Return output via callback. 16 | _async_eval() { 17 | local ASYNC_JOB_NAME 18 | # Rename job to _async_eval and redirect all eval output to cat running 19 | # in _async_job. Here, stdout and stderr are not separated for 20 | # simplicity, this could be improved in the future. 21 | { 22 | eval "$@" 23 | } &> >(ASYNC_JOB_NAME=[async/eval] _async_job 'command -p cat') 24 | } 25 | 26 | # Wrapper for jobs executed by the async worker, gives output in parseable format with execution time 27 | _async_job() { 28 | # Disable xtrace as it would mangle the output. 29 | setopt localoptions noxtrace 30 | 31 | # Store start time for job. 32 | float -F duration=$EPOCHREALTIME 33 | 34 | # Run the command and capture both stdout (`eval`) and stderr (`cat`) in 35 | # separate subshells. When the command is complete, we grab write lock 36 | # (mutex token) and output everything except stderr inside the command 37 | # block, after the command block has completed, the stdin for `cat` is 38 | # closed, causing stderr to be appended with a $'\0' at the end to mark the 39 | # end of output from this job. 40 | local jobname=${ASYNC_JOB_NAME:-$1} out 41 | out="$( 42 | local stdout stderr ret tok 43 | { 44 | stdout=$(eval "$@") 45 | ret=$? 46 | duration=$(( EPOCHREALTIME - duration )) # Calculate duration. 47 | 48 | print -r -n - $'\0'${(q)jobname} $ret ${(q)stdout} $duration 49 | } 2> >(stderr=$(command -p cat) && print -r -n - " "${(q)stderr}$'\0') 50 | )" 51 | if [[ $out != $'\0'*$'\0' ]]; then 52 | # Corrupted output (aborted job?), skipping. 53 | return 54 | fi 55 | 56 | # Grab mutex lock, stalls until token is available. 57 | read -r -k 1 -p tok || return 1 58 | 59 | # Return output ( ). 60 | print -r -n - "$out" 61 | 62 | # Unlock mutex by inserting a token. 63 | print -n -p $tok 64 | } 65 | 66 | # The background worker manages all tasks and runs them without interfering with other processes 67 | _async_worker() { 68 | # Reset all options to defaults inside async worker. 69 | emulate -R zsh 70 | 71 | # Make sure monitor is unset to avoid printing the 72 | # pids of child processes. 73 | unsetopt monitor 74 | 75 | # Redirect stderr to `/dev/null` in case unforseen errors produced by the 76 | # worker. For example: `fork failed: resource temporarily unavailable`. 77 | # Some older versions of zsh might also print malloc errors (know to happen 78 | # on at least zsh 5.0.2 and 5.0.8) likely due to kill signals. 79 | exec 2>/dev/null 80 | 81 | # When a zpty is deleted (using -d) all the zpty instances created before 82 | # the one being deleted receive a SIGHUP, unless we catch it, the async 83 | # worker would simply exit (stop working) even though visible in the list 84 | # of zpty's (zpty -L). This has been fixed around the time of Zsh 5.4 85 | # (not released). 86 | if ! is-at-least 5.4.1; then 87 | TRAPHUP() { 88 | return 0 # Return 0, indicating signal was handled. 89 | } 90 | fi 91 | 92 | local -A storage 93 | local unique=0 94 | local notify_parent=0 95 | local parent_pid=0 96 | local coproc_pid=0 97 | local processing=0 98 | 99 | local -a zsh_hooks zsh_hook_functions 100 | zsh_hooks=(chpwd periodic precmd preexec zshexit zshaddhistory) 101 | zsh_hook_functions=(${^zsh_hooks}_functions) 102 | unfunction $zsh_hooks &>/dev/null # Deactivate all zsh hooks inside the worker. 103 | unset $zsh_hook_functions # And hooks with registered functions. 104 | unset zsh_hooks zsh_hook_functions # Cleanup. 105 | 106 | close_idle_coproc() { 107 | local -a pids 108 | pids=(${${(v)jobstates##*:*:}%\=*}) 109 | 110 | # If coproc (cat) is the only child running, we close it to avoid 111 | # leaving it running indefinitely and cluttering the process tree. 112 | if (( ! processing )) && [[ $#pids = 1 ]] && [[ $coproc_pid = $pids[1] ]]; then 113 | coproc : 114 | coproc_pid=0 115 | fi 116 | } 117 | 118 | child_exit() { 119 | close_idle_coproc 120 | 121 | # On older version of zsh (pre 5.2) we notify the parent through a 122 | # SIGWINCH signal because `zpty` did not return a file descriptor (fd) 123 | # prior to that. 124 | if (( notify_parent )); then 125 | # We use SIGWINCH for compatibility with older versions of zsh 126 | # (pre 5.1.1) where other signals (INFO, ALRM, USR1, etc.) could 127 | # cause a deadlock in the shell under certain circumstances. 128 | kill -WINCH $parent_pid 129 | fi 130 | } 131 | 132 | # Register a SIGCHLD trap to handle the completion of child processes. 133 | trap child_exit CHLD 134 | 135 | # Process option parameters passed to worker. 136 | while getopts "np:uz" opt; do 137 | case $opt in 138 | n) notify_parent=1;; 139 | p) parent_pid=$OPTARG;; 140 | u) unique=1;; 141 | z) notify_parent=0;; # Uses ZLE watcher instead. 142 | esac 143 | done 144 | 145 | # Terminate all running jobs, note that this function does not 146 | # reinstall the child trap. 147 | terminate_jobs() { 148 | trap - CHLD # Ignore child exits during kill. 149 | coproc : # Quit coproc. 150 | coproc_pid=0 # Reset pid. 151 | 152 | if is-at-least 5.4.1; then 153 | trap '' HUP # Catch the HUP sent to this process. 154 | kill -HUP -$$ # Send to entire process group. 155 | trap - HUP # Disable HUP trap. 156 | else 157 | # We already handle HUP for Zsh < 5.4.1. 158 | kill -HUP -$$ # Send to entire process group. 159 | fi 160 | } 161 | 162 | killjobs() { 163 | local tok 164 | local -a pids 165 | pids=(${${(v)jobstates##*:*:}%\=*}) 166 | 167 | # No need to send SIGHUP if no jobs are running. 168 | (( $#pids == 0 )) && continue 169 | (( $#pids == 1 )) && [[ $coproc_pid = $pids[1] ]] && continue 170 | 171 | # Grab lock to prevent half-written output in case a child 172 | # process is in the middle of writing to stdin during kill. 173 | (( coproc_pid )) && read -r -k 1 -p tok 174 | 175 | terminate_jobs 176 | trap child_exit CHLD # Reinstall child trap. 177 | } 178 | 179 | local request do_eval=0 180 | local -a cmd 181 | while :; do 182 | # Wait for jobs sent by async_job. 183 | read -r -d $'\0' request || { 184 | # Unknown error occurred while reading from stdin, the zpty 185 | # worker is likely in a broken state, so we shut down. 186 | terminate_jobs 187 | 188 | # Stdin is broken and in case this was an unintended 189 | # crash, we try to report it as a last hurrah. 190 | print -r -n $'\0'"'[async]'" $(( 127 + 3 )) "''" 0 "'$0:$LINENO: zpty fd died, exiting'"$'\0' 191 | 192 | # We use `return` to abort here because using `exit` may 193 | # result in an infinite loop that never exits and, as a 194 | # result, high CPU utilization. 195 | return $(( 127 + 1 )) 196 | } 197 | 198 | # We need to clean the input here because sometimes when a zpty 199 | # has died and been respawned, messages will be prefixed with a 200 | # carraige return (\r, or \C-M). 201 | request=${request#$'\C-M'} 202 | 203 | # Check for non-job commands sent to worker 204 | case $request in 205 | _killjobs) killjobs; continue;; 206 | _async_eval*) do_eval=1;; 207 | esac 208 | 209 | # Parse the request using shell parsing (z) to allow commands 210 | # to be parsed from single strings and multi-args alike. 211 | cmd=("${(z)request}") 212 | 213 | # Name of the job (first argument). 214 | local job=$cmd[1] 215 | 216 | # Check if a worker should perform unique jobs, unless 217 | # this is an eval since they run synchronously. 218 | if (( !do_eval )) && (( unique )); then 219 | # Check if a previous job is still running, if yes, 220 | # skip this job and let the previous one finish. 221 | for pid in ${${(v)jobstates##*:*:}%\=*}; do 222 | if [[ ${storage[$job]} == $pid ]]; then 223 | continue 2 224 | fi 225 | done 226 | fi 227 | 228 | # Guard against closing coproc from trap before command has started. 229 | processing=1 230 | 231 | # Because we close the coproc after the last job has completed, we must 232 | # recreate it when there are no other jobs running. 233 | if (( ! coproc_pid )); then 234 | # Use coproc as a mutex for synchronized output between children. 235 | coproc command -p cat 236 | coproc_pid="$!" 237 | # Insert token into coproc 238 | print -n -p "t" 239 | fi 240 | 241 | if (( do_eval )); then 242 | shift cmd # Strip _async_eval from cmd. 243 | _async_eval $cmd 244 | else 245 | # Run job in background, completed jobs are printed to stdout. 246 | _async_job $cmd & 247 | # Store pid because zsh job manager is extremely unflexible (show jobname as non-unique '$job')... 248 | storage[$job]="$!" 249 | fi 250 | 251 | processing=0 # Disable guard. 252 | 253 | if (( do_eval )); then 254 | do_eval=0 255 | 256 | # When there are no active jobs we can't rely on the CHLD trap to 257 | # manage the coproc lifetime. 258 | close_idle_coproc 259 | fi 260 | done 261 | } 262 | 263 | # 264 | # Get results from finished jobs and pass it to the to callback function. This is the only way to reliably return the 265 | # job name, return code, output and execution time and with minimal effort. 266 | # 267 | # If the async process buffer becomes corrupt, the callback will be invoked with the first argument being `[async]` (job 268 | # name), non-zero return code and fifth argument describing the error (stderr). 269 | # 270 | # usage: 271 | # async_process_results 272 | # 273 | # callback_function is called with the following parameters: 274 | # $1 = job name, e.g. the function passed to async_job 275 | # $2 = return code 276 | # $3 = resulting stdout from execution 277 | # $4 = execution time, floating point e.g. 2.05 seconds 278 | # $5 = resulting stderr from execution 279 | # $6 = has next result in buffer (0 = buffer empty, 1 = yes) 280 | # 281 | async_process_results() { 282 | setopt localoptions unset noshwordsplit noksharrays noposixidentifiers noposixstrings 283 | 284 | local worker=$1 285 | local callback=$2 286 | local caller=$3 287 | local -a items 288 | local null=$'\0' data 289 | integer -l len pos num_processed has_next 290 | 291 | typeset -gA ASYNC_PROCESS_BUFFER 292 | 293 | # Read output from zpty and parse it if available. 294 | while zpty -r -t $worker data 2>/dev/null; do 295 | ASYNC_PROCESS_BUFFER[$worker]+=$data 296 | len=${#ASYNC_PROCESS_BUFFER[$worker]} 297 | pos=${ASYNC_PROCESS_BUFFER[$worker][(i)$null]} # Get index of NULL-character (delimiter). 298 | 299 | # Keep going until we find a NULL-character. 300 | if (( ! len )) || (( pos > len )); then 301 | continue 302 | fi 303 | 304 | while (( pos <= len )); do 305 | # Take the content from the beginning, until the NULL-character and 306 | # perform shell parsing (z) and unquoting (Q) as an array (@). 307 | items=("${(@Q)${(z)ASYNC_PROCESS_BUFFER[$worker][1,$pos-1]}}") 308 | 309 | # Remove the extracted items from the buffer. 310 | ASYNC_PROCESS_BUFFER[$worker]=${ASYNC_PROCESS_BUFFER[$worker][$pos+1,$len]} 311 | 312 | len=${#ASYNC_PROCESS_BUFFER[$worker]} 313 | if (( len > 1 )); then 314 | pos=${ASYNC_PROCESS_BUFFER[$worker][(i)$null]} # Get index of NULL-character (delimiter). 315 | fi 316 | 317 | has_next=$(( len != 0 )) 318 | if (( $#items == 5 )); then 319 | items+=($has_next) 320 | $callback "${(@)items}" # Send all parsed items to the callback. 321 | (( num_processed++ )) 322 | elif [[ -z $items ]]; then 323 | # Empty items occur between results due to double-null ($'\0\0') 324 | # caused by commands being both pre and suffixed with null. 325 | else 326 | # In case of corrupt data, invoke callback with *async* as job 327 | # name, non-zero exit status and an error message on stderr. 328 | $callback "[async]" 1 "" 0 "$0:$LINENO: error: bad format, got ${#items} items (${(q)items})" $has_next 329 | fi 330 | done 331 | done 332 | 333 | (( num_processed )) && return 0 334 | 335 | # Avoid printing exit value when `setopt printexitvalue` is active.` 336 | [[ $caller = trap || $caller = watcher ]] && return 0 337 | 338 | # No results were processed 339 | return 1 340 | } 341 | 342 | # Watch worker for output 343 | _async_zle_watcher() { 344 | setopt localoptions noshwordsplit 345 | typeset -gA ASYNC_PTYS ASYNC_CALLBACKS 346 | local worker=$ASYNC_PTYS[$1] 347 | local callback=$ASYNC_CALLBACKS[$worker] 348 | 349 | if [[ -n $2 ]]; then 350 | # from man zshzle(1): 351 | # `hup' for a disconnect, `nval' for a closed or otherwise 352 | # invalid descriptor, or `err' for any other condition. 353 | # Systems that support only the `select' system call always use 354 | # `err'. 355 | 356 | # this has the side effect to unregister the broken file descriptor 357 | async_stop_worker $worker 358 | 359 | if [[ -n $callback ]]; then 360 | $callback '[async]' 2 "" 0 "$0:$LINENO: error: fd for $worker failed: zle -F $1 returned error $2" 0 361 | fi 362 | return 363 | fi; 364 | 365 | if [[ -n $callback ]]; then 366 | async_process_results $worker $callback watcher 367 | fi 368 | } 369 | 370 | _async_send_job() { 371 | setopt localoptions noshwordsplit noksharrays noposixidentifiers noposixstrings 372 | 373 | local caller=$1 374 | local worker=$2 375 | shift 2 376 | 377 | zpty -t $worker &>/dev/null || { 378 | typeset -gA ASYNC_CALLBACKS 379 | local callback=$ASYNC_CALLBACKS[$worker] 380 | 381 | if [[ -n $callback ]]; then 382 | $callback '[async]' 3 "" 0 "$0:$LINENO: error: no such worker: $worker" 0 383 | else 384 | print -u2 "$caller: no such async worker: $worker" 385 | fi 386 | return 1 387 | } 388 | 389 | zpty -w $worker "$@"$'\0' 390 | } 391 | 392 | # 393 | # Start a new asynchronous job on specified worker, assumes the worker is running. 394 | # 395 | # Note if you are using a function for the job, it must have been defined before the worker was 396 | # started or you will get a `command not found` error. 397 | # 398 | # usage: 399 | # async_job [] 400 | # 401 | async_job() { 402 | setopt localoptions noshwordsplit noksharrays noposixidentifiers noposixstrings 403 | 404 | local worker=$1; shift 405 | 406 | local -a cmd 407 | cmd=("$@") 408 | if (( $#cmd > 1 )); then 409 | cmd=(${(q)cmd}) # Quote special characters in multi argument commands. 410 | fi 411 | 412 | _async_send_job $0 $worker "$cmd" 413 | } 414 | 415 | # 416 | # Evaluate a command (like async_job) inside the async worker, then worker environment can be manipulated. For example, 417 | # issuing a cd command will change the PWD of the worker which will then be inherited by all future async jobs. 418 | # 419 | # Output will be returned via callback, job name will be [async/eval]. 420 | # 421 | # usage: 422 | # async_worker_eval [] 423 | # 424 | async_worker_eval() { 425 | setopt localoptions noshwordsplit noksharrays noposixidentifiers noposixstrings 426 | 427 | local worker=$1; shift 428 | 429 | local -a cmd 430 | cmd=("$@") 431 | if (( $#cmd > 1 )); then 432 | cmd=(${(q)cmd}) # Quote special characters in multi argument commands. 433 | fi 434 | 435 | # Quote the cmd in case RC_EXPAND_PARAM is set. 436 | _async_send_job $0 $worker "_async_eval $cmd" 437 | } 438 | 439 | # This function traps notification signals and calls all registered callbacks 440 | _async_notify_trap() { 441 | setopt localoptions noshwordsplit 442 | 443 | local k 444 | for k in ${(k)ASYNC_CALLBACKS}; do 445 | async_process_results $k ${ASYNC_CALLBACKS[$k]} trap 446 | done 447 | } 448 | 449 | # 450 | # Register a callback for completed jobs. As soon as a job is finnished, async_process_results will be called with the 451 | # specified callback function. This requires that a worker is initialized with the -n (notify) option. 452 | # 453 | # usage: 454 | # async_register_callback 455 | # 456 | async_register_callback() { 457 | setopt localoptions noshwordsplit nolocaltraps 458 | 459 | typeset -gA ASYNC_PTYS ASYNC_CALLBACKS 460 | local worker=$1; shift 461 | 462 | ASYNC_CALLBACKS[$worker]="$*" 463 | 464 | # Enable trap when the ZLE watcher is unavailable, allows 465 | # workers to notify (via -n) when a job is done. 466 | if [[ ! -o interactive ]] || [[ ! -o zle ]]; then 467 | trap '_async_notify_trap' WINCH 468 | elif [[ -o interactive ]] && [[ -o zle ]]; then 469 | local fd w 470 | for fd w in ${(@kv)ASYNC_PTYS}; do 471 | if [[ $w == $worker ]]; then 472 | zle -F $fd _async_zle_watcher # Register the ZLE handler. 473 | break 474 | fi 475 | done 476 | fi 477 | } 478 | 479 | # 480 | # Unregister the callback for a specific worker. 481 | # 482 | # usage: 483 | # async_unregister_callback 484 | # 485 | async_unregister_callback() { 486 | typeset -gA ASYNC_CALLBACKS 487 | 488 | unset "ASYNC_CALLBACKS[$1]" 489 | } 490 | 491 | # 492 | # Flush all current jobs running on a worker. This will terminate any and all running processes under the worker, use 493 | # with caution. 494 | # 495 | # usage: 496 | # async_flush_jobs 497 | # 498 | async_flush_jobs() { 499 | setopt localoptions noshwordsplit 500 | 501 | local worker=$1; shift 502 | 503 | # Check if the worker exists 504 | zpty -t $worker &>/dev/null || return 1 505 | 506 | # Send kill command to worker 507 | async_job $worker "_killjobs" 508 | 509 | # Clear the zpty buffer. 510 | local junk 511 | if zpty -r -t $worker junk '*'; then 512 | (( ASYNC_DEBUG )) && print -n "async_flush_jobs $worker: ${(V)junk}" 513 | while zpty -r -t $worker junk '*'; do 514 | (( ASYNC_DEBUG )) && print -n "${(V)junk}" 515 | done 516 | (( ASYNC_DEBUG )) && print 517 | fi 518 | 519 | # Finally, clear the process buffer in case of partially parsed responses. 520 | typeset -gA ASYNC_PROCESS_BUFFER 521 | unset "ASYNC_PROCESS_BUFFER[$worker]" 522 | } 523 | 524 | # 525 | # Start a new async worker with optional parameters, a worker can be told to only run unique tasks and to notify a 526 | # process when tasks are complete. 527 | # 528 | # usage: 529 | # async_start_worker [-u] [-n] [-p ] 530 | # 531 | # opts: 532 | # -u unique (only unique job names can run) 533 | # -n notify through SIGWINCH signal 534 | # -p pid to notify (defaults to current pid) 535 | # 536 | async_start_worker() { 537 | setopt localoptions noshwordsplit noclobber 538 | 539 | local worker=$1; shift 540 | local -a args 541 | args=("$@") 542 | zpty -t $worker &>/dev/null && return 543 | 544 | typeset -gA ASYNC_PTYS 545 | typeset -h REPLY 546 | typeset has_xtrace=0 547 | 548 | if [[ -o interactive ]] && [[ -o zle ]]; then 549 | # Inform the worker to ignore the notify flag and that we're 550 | # using a ZLE watcher instead. 551 | args+=(-z) 552 | 553 | if (( ! ASYNC_ZPTY_RETURNS_FD )); then 554 | # When zpty doesn't return a file descriptor (on older versions of zsh) 555 | # we try to guess it anyway. 556 | integer -l zptyfd 557 | exec {zptyfd}>&1 # Open a new file descriptor (above 10). 558 | exec {zptyfd}>&- # Close it so it's free to be used by zpty. 559 | fi 560 | fi 561 | 562 | # Workaround for stderr in the main shell sometimes (incorrectly) being 563 | # reassigned to /dev/null by the reassignment done inside the async 564 | # worker. 565 | # See https://github.com/mafredri/zsh-async/issues/35. 566 | integer errfd=-1 567 | 568 | # Redirect of errfd is broken on zsh 5.0.2. 569 | if is-at-least 5.0.8; then 570 | exec {errfd}>&2 571 | fi 572 | 573 | # Make sure async worker is started without xtrace 574 | # (the trace output interferes with the worker). 575 | [[ -o xtrace ]] && { 576 | has_xtrace=1 577 | unsetopt xtrace 578 | } 579 | 580 | if (( errfd != -1 )); then 581 | zpty -b $worker _async_worker -p $$ $args 2>&$errfd 582 | else 583 | zpty -b $worker _async_worker -p $$ $args 584 | fi 585 | local ret=$? 586 | 587 | # Re-enable it if it was enabled, for debugging. 588 | (( has_xtrace )) && setopt xtrace 589 | (( errfd != -1 )) && exec {errfd}>& - 590 | 591 | if (( ret )); then 592 | async_stop_worker $worker 593 | return 1 594 | fi 595 | 596 | if ! is-at-least 5.0.8; then 597 | # For ZSH versions older than 5.0.8 we delay a bit to give 598 | # time for the worker to start before issuing commands, 599 | # otherwise it will not be ready to receive them. 600 | sleep 0.001 601 | fi 602 | 603 | if [[ -o interactive ]] && [[ -o zle ]]; then 604 | if (( ! ASYNC_ZPTY_RETURNS_FD )); then 605 | REPLY=$zptyfd # Use the guessed value for the file desciptor. 606 | fi 607 | 608 | ASYNC_PTYS[$REPLY]=$worker # Map the file desciptor to the worker. 609 | fi 610 | } 611 | 612 | # 613 | # Stop one or multiple workers that are running, all unfetched and incomplete work will be lost. 614 | # 615 | # usage: 616 | # async_stop_worker [] 617 | # 618 | async_stop_worker() { 619 | setopt localoptions noshwordsplit 620 | 621 | local ret=0 worker k v 622 | for worker in $@; do 623 | # Find and unregister the zle handler for the worker 624 | for k v in ${(@kv)ASYNC_PTYS}; do 625 | if [[ $v == $worker ]]; then 626 | zle -F $k 627 | unset "ASYNC_PTYS[$k]" 628 | fi 629 | done 630 | async_unregister_callback $worker 631 | zpty -d $worker 2>/dev/null || ret=$? 632 | 633 | # Clear any partial buffers. 634 | typeset -gA ASYNC_PROCESS_BUFFER 635 | unset "ASYNC_PROCESS_BUFFER[$worker]" 636 | done 637 | 638 | return $ret 639 | } 640 | 641 | # 642 | # Initialize the required modules for zsh-async. To be called before using the zsh-async library. 643 | # 644 | # usage: 645 | # async_init 646 | # 647 | async_init() { 648 | (( ASYNC_INIT_DONE )) && return 649 | typeset -g ASYNC_INIT_DONE=1 650 | 651 | zmodload zsh/zpty 652 | zmodload zsh/datetime 653 | 654 | # Load is-at-least for reliable version check. 655 | autoload -Uz is-at-least 656 | 657 | # Check if zsh/zpty returns a file descriptor or not, 658 | # shell must also be interactive with zle enabled. 659 | typeset -g ASYNC_ZPTY_RETURNS_FD=0 660 | [[ -o interactive ]] && [[ -o zle ]] && { 661 | typeset -h REPLY 662 | zpty _async_test : 663 | (( REPLY )) && ASYNC_ZPTY_RETURNS_FD=1 664 | zpty -d _async_test 665 | } 666 | } 667 | 668 | async() { 669 | async_init 670 | } 671 | 672 | async "$@" 673 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/.nojekyll -------------------------------------------------------------------------------- /docs/CNAME: -------------------------------------------------------------------------------- 1 | typewritten.dev -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |

2 | typewritten 3 |

4 | 5 |

typewritten

6 | 7 |

A minimal zsh prompt

8 | 9 |
10 | 11 |

12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |

22 |

23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |

33 | 34 |

35 | typewritten zsh prompt demo 36 |

37 | 38 | ## Quick start 39 | 40 | ### [npm](https://npmjs.com/get-npm) 41 | 42 | ```shell 43 | npm install -g typewritten 44 | ``` 45 | 46 | That's it. The script will make the necessary symlinks to `fpath` and set the prompt in your `.zshrc`. 47 | -------------------------------------------------------------------------------- /docs/_media/adaptive_home_relative_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/adaptive_home_relative_path.png -------------------------------------------------------------------------------- /docs/_media/arrow_symbols/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/arrow_symbols/default.png -------------------------------------------------------------------------------- /docs/_media/arrow_symbols/glyph_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/arrow_symbols/glyph_arrow.png -------------------------------------------------------------------------------- /docs/_media/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/bg.png -------------------------------------------------------------------------------- /docs/_media/configuration_examples/bash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/configuration_examples/bash.png -------------------------------------------------------------------------------- /docs/_media/configuration_examples/dracula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/configuration_examples/dracula.png -------------------------------------------------------------------------------- /docs/_media/configuration_examples/half_pure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/configuration_examples/half_pure.png -------------------------------------------------------------------------------- /docs/_media/configuration_examples/pure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/configuration_examples/pure.png -------------------------------------------------------------------------------- /docs/_media/cursors/beam.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/cursors/beam.png -------------------------------------------------------------------------------- /docs/_media/cursors/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/cursors/block.png -------------------------------------------------------------------------------- /docs/_media/cursors/underscore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/cursors/underscore.png -------------------------------------------------------------------------------- /docs/_media/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/favicon.ico -------------------------------------------------------------------------------- /docs/_media/git_relative_path/git_no_relative_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/git_relative_path/git_no_relative_path.png -------------------------------------------------------------------------------- /docs/_media/git_relative_path/git_relative_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/git_relative_path/git_relative_path.png -------------------------------------------------------------------------------- /docs/_media/home_relative_path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/home_relative_path.png -------------------------------------------------------------------------------- /docs/_media/layouts/half_pure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/layouts/half_pure.png -------------------------------------------------------------------------------- /docs/_media/layouts/multiline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/layouts/multiline.png -------------------------------------------------------------------------------- /docs/_media/layouts/pure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/layouts/pure.png -------------------------------------------------------------------------------- /docs/_media/layouts/pure_verbose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/layouts/pure_verbose.png -------------------------------------------------------------------------------- /docs/_media/layouts/singleline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/layouts/singleline.png -------------------------------------------------------------------------------- /docs/_media/layouts/singleline_verbose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/layouts/singleline_verbose.png -------------------------------------------------------------------------------- /docs/_media/left_prompt_prefix/custom_command.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/left_prompt_prefix/custom_command.png -------------------------------------------------------------------------------- /docs/_media/left_prompt_prefix/date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/left_prompt_prefix/date.png -------------------------------------------------------------------------------- /docs/_media/left_prompt_prefix/date_with_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/left_prompt_prefix/date_with_options.png -------------------------------------------------------------------------------- /docs/_media/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/_media/relative_path_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/relative_path_off.png -------------------------------------------------------------------------------- /docs/_media/return_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/return_code.png -------------------------------------------------------------------------------- /docs/_media/right_prompt_prefix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/right_prompt_prefix.png -------------------------------------------------------------------------------- /docs/_media/symbols/arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/symbols/arrow.png -------------------------------------------------------------------------------- /docs/_media/symbols/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/symbols/default.png -------------------------------------------------------------------------------- /docs/_media/symbols/dollar_sign.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/symbols/dollar_sign.png -------------------------------------------------------------------------------- /docs/_media/typewritten.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/reobin/typewritten/0dd11cc5b2681158820f06881b5cdb3b42f9c924/docs/_media/typewritten.gif -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * [Home](/ "typewritten | A minimal zsh prompt") 2 | * [Installation](installation.md "Installation | typewritten") 3 | * [Prompt customization](prompt_customization.md "Prompt customization | typewritten") 4 | * [Prompt color customization](prompt_color_customization.md "Prompt color customization | typewritten") 5 | * [git status indicators](git_status_indicators.md "git status indicators | typewritten") 6 | * [Return code](return_code.md "Return code display | typewritten") 7 | * [Credits](credits.md "Credits | typewritten") 8 | -------------------------------------------------------------------------------- /docs/credits.md: -------------------------------------------------------------------------------- 1 | # Credits 🎉 2 | 3 | ## Contributors 4 | 5 | A special thanks to all the contributors to this project 6 | 7 | - [@thbe](https://github.com/thbe) 8 | - [@erikr](https://github.com/erikr) 9 | - [@artem-zinnatullin](https://github.com/artem-zinnatullin) 10 | - [@nizarmah](https://github.com/nizarmah) 11 | - [@jletey](https://github.com/jletey) 12 | - [@pfandzelter](https://github.com/pfandzelter) 13 | - [@eleven4y](https://github.com/eleven4y) 14 | - [@ninja18](https://github.com/ninja18) 15 | 16 | ## Inspiration 17 | 18 | `pure` layout is inspired by [Pure](https://github.com/sindresorhus/pure) 19 | -------------------------------------------------------------------------------- /docs/git_status_indicators.md: -------------------------------------------------------------------------------- 1 | # git status indicators 2 | 3 | When the current git repository is "dirty", a symbol indicating what the changes are is displayed. 4 | 5 | - `?`   — untracked change(s); 6 | - `+`   — staged change(s); 7 | - `!`   — file(s) modified in the repo; 8 | - `»`   — renamed file(s); 9 | - `—`   — deleted file(s); 10 | - `$`   — stashed change(s); 11 | - `#`   — unmerged change(s); 12 | - `•|`   — behind of remote branch; 13 | - `|•`   — ahead of remote branch; 14 | - `~`   — Branches have diverged; 15 | 16 | Git status can be disabled by setting the `git config` value in a repo or globally like so: 17 | 18 | ```bash 19 | git config --add oh-my-zsh.hide-status 1 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | typewritten | A minimal zsh prompt 6 | 7 | 8 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 36 |
37 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | ## npm 4 | 5 | ```shell 6 | npm install -g typewritten 7 | ``` 8 | 9 | That's it. The script will make the necessary symlinks to `fpath` and set the prompt in your `.zshrc`. 10 | 11 | ### [Homebrew](https://brew.sh) 12 | 13 | ```shell 14 | brew install typewritten 15 | ``` 16 | 17 | Then load typewritten in your `.zshrc` by using zsh prompinit: 18 | 19 | ```shell 20 | autoload -U promptinit; promptinit 21 | prompt typewritten 22 | ``` 23 | 24 | ## Manual 25 | 26 | Clone the typewritten repository somewhere you can easily link. I recommend creating a `.zsh` directory at root. 27 | 28 | ```shell 29 | mkdir -p "$HOME/.zsh" 30 | git clone https://github.com/reobin/typewritten.git "$HOME/.zsh/typewritten" 31 | ``` 32 | 33 | Load typewritten in your `.zshrc` by using zsh prompinit: 34 | 35 | ```shell 36 | fpath+=$HOME/.zsh/typewritten 37 | autoload -U promptinit; promptinit 38 | prompt typewritten 39 | ``` 40 | 41 | Note: if using `oh-my-zsh`, set `ZSH_THEME=""` in your `.zshrc` to disable oh-my-zsh themes. 42 | 43 | ## oh-my-zsh 44 | 45 | Clone the repository into your custom oh-my-zsh themes directory: 46 | 47 | ```shell 48 | git clone https://github.com/reobin/typewritten.git $ZSH_CUSTOM/themes/typewritten 49 | ``` 50 | 51 | Symlink `typewritten.zsh-theme` to your oh-my-zsh custom themes directory: 52 | 53 | ```shell 54 | ln -s "$ZSH_CUSTOM/themes/typewritten/typewritten.zsh-theme" "$ZSH_CUSTOM/themes/typewritten.zsh-theme" 55 | ln -s "$ZSH_CUSTOM/themes/typewritten/async.zsh" "$ZSH_CUSTOM/themes/async" 56 | ``` 57 | 58 | Set `ZSH_THEME="typewritten"` in your `.zshrc` file. 59 | 60 | Note: If creating the symlinks is a problem, you can skip the step and set `ZSH_THEME="typewritten/typewritten"` instead. 61 | 62 | ## antibody 63 | 64 | Add `antibody bundle reobin/typewritten` to your `.zshrc`. 65 | 66 | ## antigen 67 | 68 | Add `antigen bundle reobin/typewritten@main` to your `.zshrc`. 69 | 70 | ## zgen 71 | 72 | Add `zgen load reobin/typewritten typewritten` to your `.zshrc`. 73 | 74 | ## zim 75 | 76 | Add `zmodule reobin/typewritten --name typewritten` to your `.zimrc` and run `zimfw install`. 77 | 78 | ## zplug 79 | 80 | Add `zplug reobin/typewritten, as:theme` to your `.zshrc`. 81 | 82 | ## zinit 83 | 84 | Add the following config to your `.zshrc`: 85 | 86 | ```sh 87 | zinit ice compile'(typewritten|async).zsh' pick'async.zsh' src'typewritten.zsh' 88 | zinit light reobin/typewritten 89 | ``` 90 | -------------------------------------------------------------------------------- /docs/prompt_color_customization.md: -------------------------------------------------------------------------------- 1 | # Prompt color customization 2 | 3 | All colors on the prompt are customizable. If colors for a section is not defined, the default one is used. 4 | 5 | **[Jump to examples](#examples)** 6 | 7 | ## How to configure general colors 8 | 9 | General color mappings are configured through `TYPEWRITTEN_COLOR_MAPPINGS`. 10 | 11 | To ease the process of changing around the colors in typewritten, semantic names have been given to groups of sections. 12 | 13 | | Name | Section | Default value | 14 | | ---------------- | -------------------------------------------------------------------------------------------- | ------------- | 15 | | `primary` | The current directory and git branch. | `magenta` | 16 | | `secondary` | The prompt symbol. | `blue` | 17 | | `accent` | The arrow, the host-user connector, the virtual env, and the right prompt prefix. | `default` | 18 | | `notice` | The symbol when user is root | `yellow` | 19 | | `info_negative` | The symbol when there is an error, the return error code, and the git status deleted symbol. | `red` | 20 | | `info_positive` | The git status staged symbol. | `green` | 21 | | `info_neutral_1` | The host, the user, and the git status stash and modified symbols. | `yellow` | 22 | | `info_neutral_2` | The git status new, diverged, ahead and behind symbols | `blue` | 23 | | `info_special` | The git status renamed and unmerged symbols. | `cyan` | 24 | 25 | ### Variable format 26 | 27 | These colors are configured through an environment variable named `TYPEWRITTEN_COLOR_MAPPINGS`. 28 | 29 | Color for a semantic group is configured with key, being the group, and value being the color value. The two are separated by a colon (`:`). 30 | 31 | For multiple custom colors, separate the key-values with semicolons (`;`). 32 | 33 | A simple example would be: 34 | 35 | ```shell 36 | # primary -> red 37 | # current_directory -> #008080 38 | export TYPEWRITTEN_COLOR_MAPPINGS="primary:red;secondary:#008080" 39 | ``` 40 | 41 | ### Supported colors 42 | 43 | - HEX colors (i.e.: `#008080`) 44 | - 256 (xterm) 45 | - `default` (foreground color) 46 | - `black` 47 | - `red` 48 | - `green` 49 | - `yellow` 50 | - `blue` 51 | - `magenta` 52 | - `cyan` 53 | - `white` 54 | 55 | Named colors will follow your terminal color scheme. 56 | 57 | ## Customize the color of a single section 58 | 59 | Precise section color mappings are configured through `TYPEWRITTEN_COLOR`. 60 | 61 | To change the color of a single section, regardless of its semantic group, the `TYPEWRITTEN_COLORS` variable is used. 62 | 63 | Both `TYPEWRITTEN_COLORS` and `TYPEWRITTEN_COLOR_MAPPINGS` use the same [format](#variable-format). Only the key values are different. 64 | 65 | | Section | Description | Default value | 66 | | --------------------- | ---------------------------------------------------------------------------------------------------- | ------------- | 67 | | `prompt` | The input of the command line (what you write). | `default` | 68 | | `symbol` | The prompt symbol. | `blue` | 69 | | `symbol_error` | The prompt symbol when an error return code is detected. | `red` | 70 | | `symbol_root` | The prompt symbol when the user is root | `red` | 71 | | `error_code` | The displayed error return code. | `red` | 72 | | `git_branch` | The current git branch. | `magenta` | 73 | | `current_directory` | The current directory and/or git home | `magenta` | 74 | | `arrow` | The arrow between the current directory and the git branch (`->`). | `default` | 75 | | `right_prompt_prefix` | When a right prompt prefix is set, it can be colored. | `default` | 76 | | `host` | The current host on `multiline` or `singleline_verbose` layouts. | `yellow` | 77 | | `host_user_connector` | The `@` between host and user on `multiline` or `singleline_verbose` layouts. | `default` | 78 | | `user` | The user between on `multiline` or `singleline_verbose` layouts. | `yellow` | 79 | | `virtual_env` | The current python virtual environment. | `default` | 80 | | `git_rebasing` | The word `rebasing` replaces the git status when the current git repository in is currently rebasing | `magenta` | 81 | | `git_status_staged` | The displayed `+` symbol coming from git status. | `green` | 82 | | `git_status_new` | The displayed `?` symbol coming from git status. | `blue` | 83 | | `git_status_modified` | The displayed `!` symbol coming from git status. | `yellow` | 84 | | `git_status_renamed` | The displayed `»` symbol coming from git status. | `cyan` | 85 | | `git_status_deleted` | The displayed `—` symbol coming from git status. | `red` | 86 | | `git_status_unmerged` | The displayed `#` symbol coming from git status. (merge conflicts) | `default` | 87 | | `git_status_diverged` | The displayed `~` symbol coming from git status. (branch has diverged from origin) | `blue` | 88 | | `git_status_ahead` | The displayed `\|•` symbol coming from git status. (branch is ahead of origin) | `blue` | 89 | | `git_status_behind` | The displayed `•\|` symbol coming from git status. (branch is behind of origin) | `blue` | 90 | | `git_status_stash` | The displayed `$` symbol coming from git status. | `yellow` | 91 | 92 | Note: `TYPEWRITTEN_COLORS` values will always override the ones of `TYPEWRITTEN_COLOR_MAPPINGS` 93 | 94 | ## Examples 95 | 96 | Here are some examples of configuring colors (and more) for the prompt: 97 | 98 | ### Example #1 (Dracula) 99 | 100 | ```shell 101 | export TYPEWRITTEN_COLOR_MAPPINGS="primary:#9580FF;secondary:#8AFF80;accent:#FFFF80;info_negative:#FF80BF;info_positive:#8AFF80;info_neutral_1:#FF9580;info_neutral_2:#FFFF80;info_special:#80FFEA" 102 | ``` 103 | 104 |

105 | example #1 106 |

107 | 108 | ### Example #2 109 | 110 | ```shell 111 | export TYPEWRITTEN_SYMBOL="#" 112 | export TYPEWRITTEN_COLOR_MAPPINGS="primary:red;secondary:red;accent:black;foreground:black" 113 | ``` 114 | 115 |

116 | example #2 117 |

118 | 119 | ### Example #3 120 | 121 | ```shell 122 | export TYPEWRITTEN_PROMPT_LAYOUT="pure" 123 | export TYPEWRITTEN_COLOR_MAPPINGS="primary:blue" 124 | export TYPEWRITTEN_COLORS="arrow:yellow;symbol:yellow" 125 | ``` 126 | 127 |

128 | example #3 129 |

130 | 131 | ### Example #4 (wrong format) 132 | 133 | ```shell 134 | export TYPEWRITTEN_PROMPT_LAYOUT="half_pure" 135 | export TYPEWRITTEN_COLORS=";wrong_format:" # default values will be used 136 | ``` 137 | 138 |

139 | example #4 140 |

141 | -------------------------------------------------------------------------------- /docs/prompt_customization.md: -------------------------------------------------------------------------------- 1 | # Prompt customization 2 | 3 | Here lie all the options related to how or where the information is displayed on the prompt. 4 | 5 | Click on an option's name to see more info. 6 | 7 | | Option | Description | Available options | Default value | 8 | | --------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------- | 9 | | [TYPEWRITTEN_PROMPT_LAYOUT](#typewritten_prompt_layout) | Defines how the prompt is displayed. | `singleline`, `half_pure` , `pure`, `singleline_verbose`, and `multiline` | `singleline` | 10 | | [TYPEWRITTEN_SYMBOL](#typewritten_symbol) | Defines the prompt symbol. | Any string value | `❯` | 11 | | [TYPEWRITTEN_ARROW_SYMBOL](#typewritten_arrow_symbol) | Defines the arrow symbol. | Any string value | `->` | 12 | | [TYPEWRITTEN_RELATIVE_PATH](#typewritten_relative_path) | Defines what the current directory display is relative to. | `git`, `home`, `adaptive`, or `off` | `git` | 13 | | [TYPEWRITTEN_CURSOR](#typewritten_cursor) | Defines the used cursor. | `underscore`, `beam`, `block`, or `terminal` | `underscore` | 14 | | [TYPEWRITTEN_LEFT_PROMPT_PREFIX](#typewritten_left_prompt_prefix-and-typewritten_right_prompt_prefix) | Defines what is displayed just before the prompt symbol on the left. | Any string | | 15 | | [TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION](#typewritten_left_prompt_prefix_function-and-typewritten_right_prompt_prefix_function) | Defines what is displayed just before the prompt symbol on the left. Takes in a function name. | Any function name | | 16 | | [TYPEWRITTEN_RIGHT_PROMPT_PREFIX](#typewritten_left_prompt_prefix-and-typewritten_right_prompt_prefix) | Defines what is displayed just before the right part of the prompt. | Any string | | 17 | | [TYPEWRITTEN_RIGHT_PROMPT_PREFIX_FUNCTION](#typewritten_left_prompt_prefix_function-and-typewritten_right_prompt_prefix_function) | Defines what is displayed just before the prompt symbol on the left. Takes in a function name. | Any function name | | 18 | 19 | > All of these options are configurable through your `.zshrc` file like this: 20 | > 21 | > ```shell 22 | > export TYPEWRITTEN_PROMPT_LAYOUT="singleline" 23 | > ``` 24 | 25 | ## TYPEWRITTEN_PROMPT_LAYOUT 26 | 27 | **Default single line (`TYPEWRITTEN_PROMPT_LAYOUT="singleline"`)** 28 | 29 |

30 | singleline prompt layout 31 |

32 | 33 | **Half pure (`TYPEWRITTEN_PROMPT_LAYOUT="half_pure"`)** 34 | 35 |

36 | half pure prompt layout 37 |

38 | 39 | **[Pure](https://github.com/sindresorhus/pure) (`TYPEWRITTEN_PROMPT_LAYOUT="pure"`)** 40 | 41 |

42 | pure prompt layout 43 |

44 | 45 | **Pure - verbose variation (`TYPEWRITTEN_PROMPT_LAYOUT="pure_verbose"`)** 46 | 47 |

48 | pure verbose prompt layout 49 |

50 | 51 | **Single line - verbose variation (`TYPEWRITTEN_PROMPT_LAYOUT="singleline_verbose"`)** 52 | 53 |

54 | single line verbose prompt layout 55 |

56 | 57 | **Multiline (`TYPEWRITTEN_PROMPT_LAYOUT="multiline"`)** 58 | 59 |

60 | multiline prompt layout 61 |

62 | 63 | ## TYPEWRITTEN_SYMBOL 64 | 65 | Here are some examples of customized prompt symbols. 66 | 67 | **Default (`TYPEWRITTEN_SYMBOL="❯"`)** 68 | 69 |

70 | default symbol 71 |

72 | 73 | **Dollar sign (`TYPEWRITTEN_SYMBOL="$"`)** 74 | 75 |

76 | dollar sign symbol 77 |

78 | 79 | **Full arrow (`TYPEWRITTEN_SYMBOL="->"`)** 80 | 81 |

82 | arrow symbol 83 |

84 | 85 | ## TYPEWRITTEN_ARROW_SYMBOL 86 | 87 | Here are some examples of customized prompt arrow symbols. 88 | 89 | **Default (`TYPEWRITTEN_ARROW_SYMBOL="->"`)** 90 | 91 |

92 | default arrow symbol 93 |

94 | 95 | **Glyph arrow (`TYPEWRITTEN_ARROW_SYMBOL="➜"`)** 96 | 97 |

98 | glyph arrow symbol 99 |

100 | 101 | ## TYPEWRITTEN_RELATIVE_PATH 102 | 103 | By default, when in a git repository, the git root directory is always displayed no matter how far you are inside it. 104 | 105 | **Default behaviour (`TYPEWRITTEN_RELATIVE_PATH="git"`)** 106 | 107 | `/.../` is displayed when the nesting gets more than one level deep. 108 | 109 |

110 | default git relative path 111 |

112 | 113 | When outside of a git repository, only the basename of the current directory is displayed. 114 | 115 |

116 | relative path off 117 |

118 | 119 | **Relative to `$HOME` (`TYPEWRITTEN_RELATIVE_PATH="home"`)** 120 | 121 | When set to `home`, the full directory path relative to `$HOME` is displayed at all times. 122 | 123 |

124 | display path relative to home 125 |

126 | 127 | **Adaptive (`git` and `home`) (`TYPEWRITTEN_RELATIVE_PATH="adaptive"`)** 128 | 129 | Adaptive display means that if you are in a git repository, the current directory will show the current path relative to the git root directory. 130 | 131 |

132 | default git relative path 133 |

134 | 135 | If you are outside of a git repository, the path will be displayed relative to `$HOME`. 136 | 137 |

138 | display path relative to home 139 |

140 | 141 | **Off (`TYPEWRITTEN_RELATIVE_PATH="off"`)** 142 | 143 | This option being off means that at all times, the current directory display only shows the basename of the current directory. 144 | 145 |

146 | hide git home directory 147 |

148 | 149 | ## TYPEWRITTEN_CURSOR 150 | 151 | **Default underscore (`TYPEWRITTEN_CURSOR="underscore"`)** 152 | 153 |

154 | underscore cursor 155 |

156 | 157 | **Beam (`TYPEWRITTEN_CURSOR="beam"`)** 158 | 159 |

160 | beam cursor 161 |

162 | 163 | **Block (`TYPEWRITTEN_CURSOR="block"`)** 164 | 165 |

166 | block cursor 167 |

168 | 169 | **Terminal (`TYPEWRITTEN_CURSOR="terminal"`)** 170 | 171 | By using this option, typewritten stops managing cursor preference. The cursor used will be the one configured by your terminal emulator. 172 | 173 | ## TYPEWRITTEN_LEFT_PROMPT_PREFIX and TYPEWRITTEN_RIGHT_PROMPT_PREFIX 174 | 175 | This option is stricly used as a string value. To use functions, take a look at [TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION](#typewritten_left_prompt_prefix_function-and-typewritten_right_prompt_prefix_function). 176 | 177 | **Display a string value** 178 | 179 | ```sh 180 | export TYPEWRITTEN_RIGHT_PROMPT_PREFIX="# " 181 | ``` 182 | 183 |

184 | bash comment prefix 185 |

186 | 187 | ## TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION and TYPEWRITTEN_RIGHT_PROMPT_PREFIX_FUNCTION 188 | 189 | This variable should be assigned to a function name, and will be evaluated whenever the prompt is rendered. 190 | 191 | ### Display the `date` 192 | 193 | Since `date` is a function name, it will execute and the output will be displayed as the prefix: 194 | 195 | ```sh 196 | export TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION=date 197 | ``` 198 | 199 |

200 | bash prompt date prefix 201 |

202 | 203 | ### Display `date` with options 204 | 205 | To customize what the timestamp will look like, you can use options: 206 | 207 | ```sh 208 | export TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION=(date +%H:%M:%S) 209 | ``` 210 | 211 |

212 | bash prompt date prefix 213 |

214 | 215 | ### Use a custom function 216 | 217 | You can create your own function to display more complex values: 218 | 219 | ```sh 220 | complex_time() { 221 | local time=$(date +%H:%M:%S) 222 | echo "time: $time" 223 | } 224 | 225 | export TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION=complex_time 226 | ``` 227 | 228 |

229 | bash prompt date prefix 230 |

231 | 232 | **Bonus example** 233 | 234 | Display kube_context: 235 | 236 | ```sh 237 | display_kube_context() { 238 | tw_kube_context="$(kubectl config current-context 2> /dev/null)" 239 | 240 | if [[ $tw_kube_context != "" ]]; then 241 | echo "($(basename $tw_kube_context))" 242 | fi 243 | } 244 | 245 | export TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION=display_kube_context 246 | ``` 247 | -------------------------------------------------------------------------------- /docs/return_code.md: -------------------------------------------------------------------------------- 1 | # Return code 2 | 3 | When an error happens, the prompt symbol changes to a red color and the return code is displayed on the left. 4 | 5 |

6 | 127 return code 7 |

8 | 9 | The return code display can be disabled by setting `TYPEWRITTEN_DISABLE_RETURN_CODE` to `true` in your `.zshrc` 10 | 11 | -------------------------------------------------------------------------------- /docs/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: 3 | Sitemap: https://typewritten.dev/sitemap.xml 4 | Host: https://typewritten.dev 5 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | https://typewritten.dev/ daily 0.7 4 | https://typewritten.dev/#/installation/ daily 0.7 5 | https://typewritten.dev/#/prompt_customization/ daily 0.7 6 | https://typewritten.dev/#/prompt_color_customization/ daily 0.7 7 | https://typewritten.dev/#/git_status_indicator/ daily 0.7 8 | https://typewritten.dev/#/return_code/ daily 0.7 9 | https://typewritten.dev/#/credits/ daily 0.7 10 | 11 | -------------------------------------------------------------------------------- /lib/colors.zsh: -------------------------------------------------------------------------------- 1 | declare -Ag tw_color_mappings=( 2 | "foreground" "default" 3 | "primary" "magenta" 4 | "secondary" "blue" 5 | "notice" "yellow" 6 | "accent" "default" 7 | 8 | "info_positive" "green" 9 | "info_negative" "red" 10 | "info_neutral_1" "yellow" 11 | "info_neutral_2" "blue" 12 | "info_special" "cyan" 13 | ) 14 | 15 | if [[ $TYPEWRITTEN_COLOR_MAPPINGS =~ ^[#_0-9a-zA-Z]+:[#_0-9a-zA-Z]+(\;[#_0-9a-zA-Z]+:[#_0-9a-zA-Z]+)*$ ]]; then 16 | tw_values=($(echo $TYPEWRITTEN_COLOR_MAPPINGS | tr ";" "\n")) 17 | for tw_value in $tw_values; do 18 | tw_value_definition=($(echo $tw_value | tr ":" "\n")) 19 | tw_color_mappings[$tw_value_definition[1]]=$tw_value_definition[2] 20 | done 21 | elif [[ ! -z $TYPEWRITTEN_COLOR_MAPPINGS ]]; then 22 | echo "$TYPEWRITTEN_COLOR_MAPPINGS is not formatted correctly. 23 | Format it like so: \"value:#009090;value:red\", etc." 24 | fi 25 | 26 | declare -Ag tw_colors=( 27 | "prompt" $tw_color_mappings[foreground] 28 | "current_directory" $tw_color_mappings[primary] 29 | "symbol" $tw_color_mappings[secondary] 30 | "symbol_root" $tw_color_mappings[notice] 31 | 32 | "arrow" $tw_color_mappings[accent] 33 | "right_prompt_prefix" $tw_color_mappings[accent] 34 | "left_prompt_prefix" $tw_color_mappings[accent] 35 | "virtual_env" $tw_color_mappings[accent] 36 | 37 | "symbol_error" $tw_color_mappings[info_negative] 38 | "error_code" $tw_color_mappings[info_negative] 39 | 40 | "host_user_connector" $tw_color_mappings[accent] 41 | "host" $tw_color_mappings[info_neutral_1] 42 | "user" $tw_color_mappings[info_neutral_1] 43 | 44 | "git_branch" $tw_color_mappings[primary] 45 | "git_rebasing" $tw_color_mappings[primary] 46 | "git_status_deleted" $tw_color_mappings[info_negative] 47 | "git_status_staged" $tw_color_mappings[info_positive] 48 | "git_status_stash" $tw_color_mappings[info_neutral_1] 49 | "git_status_modified" $tw_color_mappings[info_neutral_1] 50 | "git_status_new" $tw_color_mappings[info_neutral_2] 51 | "git_status_diverged" $tw_color_mappings[info_neutral_2] 52 | "git_status_ahead" $tw_color_mappings[info_neutral_2] 53 | "git_status_behind" $tw_color_mappings[info_neutral_2] 54 | "git_status_renamed" $tw_color_mappings[info_special] 55 | "git_status_unmerged" $tw_color_mappings[info_special] 56 | ) 57 | 58 | if [[ $TYPEWRITTEN_COLORS =~ ^[#_0-9a-zA-Z]+:[#_0-9a-zA-Z]+(\;[#_0-9a-zA-Z]+:[#_0-9a-zA-Z]+)*$ ]]; then 59 | tw_values=($(echo $TYPEWRITTEN_COLORS | tr ";" "\n")) 60 | for tw_value in $tw_values; do 61 | tw_value_definition=($(echo $tw_value | tr ":" "\n")) 62 | tw_colors[$tw_value_definition[1]]=$tw_value_definition[2] 63 | done 64 | elif [[ ! -z $TYPEWRITTEN_COLORS ]]; then 65 | echo "$TYPEWRITTEN_COLORS is not formatted correctly. 66 | Format it like so: \"value:#009090;value:red\", etc." 67 | fi 68 | -------------------------------------------------------------------------------- /lib/git.zsh: -------------------------------------------------------------------------------- 1 | tw_git_home() { 2 | local tw_current_directory="$1" 3 | local tw_git_toplevel="$2" 4 | local tw_git_home="" 5 | if [ "$tw_git_toplevel" != "" -a "$tw_git_toplevel" != "$tw_current_directory" ]; then 6 | local tw_repo_name=`basename $tw_git_toplevel` 7 | tw_git_home="$tw_repo_name" 8 | fi; 9 | if [ "$tw_git_home" != "" ]; then 10 | # check how many directories are between 11 | local tw_current_nesting="${tw_current_directory//[^\/]}" 12 | local tw_repo_nesting="${tw_git_toplevel//[^\/]}" 13 | local tw_diff=`expr ${#tw_current_nesting} - ${#tw_repo_nesting}` 14 | if [ $tw_diff -eq 1 ]; then 15 | echo "$tw_git_home/" 16 | else 17 | echo "$tw_git_home/.../" 18 | fi; 19 | else 20 | echo "" 21 | fi; 22 | } 23 | 24 | tw_git_branch() { 25 | echo "$(command git symbolic-ref --short -q HEAD)" 26 | } 27 | 28 | tw_git_status() { 29 | local tw_git_status_response=$(command git status --porcelain -b 2> /dev/null) 30 | 31 | local tw_git_status_display="" 32 | 33 | # rebasing 34 | if $(command grep "^## HEAD (no branch)" <<< "$tw_git_status_response" &> /dev/null); then 35 | tw_git_status_display="%F{$tw_colors[git_rebasing]}rebasing" 36 | else 37 | # staged changes 38 | if $(command grep "^A. " <<< "$tw_git_status_response" &> /dev/null) || 39 | $(command grep "^M. " <<< "$tw_git_status_response" &> /dev/null) || 40 | $(command grep "^D. " <<< "$tw_git_status_response" &> /dev/null); then 41 | tw_git_status_display+=" %F{$tw_colors[git_status_staged]}+" 42 | fi 43 | 44 | # new file 45 | if $(command grep "?? " <<< "$tw_git_status_response" &> /dev/null); then 46 | tw_git_status_display+=" %F{$tw_colors[git_status_new]}?" 47 | fi 48 | 49 | # modified 50 | if $(command grep "^.M " <<< "$tw_git_status_response" &> /dev/null); then 51 | tw_git_status_display+=" %F{$tw_colors[git_status_modified]}!" 52 | fi 53 | 54 | # renamed 55 | if $(command grep "^R. " <<< "$tw_git_status_response" &> /dev/null); then 56 | tw_git_status_display+=" %F{$tw_colors[git_status_renamed]}»" 57 | fi 58 | 59 | # deleted 60 | if $(command grep "^.D " <<< "$tw_git_status_response" &> /dev/null); then 61 | tw_git_status_display+=" %F{$tw_colors[git_status_deleted]}—" 62 | fi 63 | 64 | # unmerged 65 | if $(command grep "^UU " <<< "$tw_git_status_response" &> /dev/null); then 66 | tw_git_status_display+=" %F{$tw_colors[git_status_unmerged]}#" 67 | fi 68 | 69 | local tw_is_ahead=false 70 | if $(command grep "^## .*ahead" <<< "$tw_git_status_response" &> /dev/null); then 71 | tw_is_ahead=true 72 | fi 73 | 74 | local tw_is_behind=false 75 | if $(command grep "^## .*behind" <<< "$tw_git_status_response" &> /dev/null); then 76 | tw_is_behind=true 77 | fi 78 | 79 | if [[ "$tw_is_ahead" == true && "$tw_is_behind" == true ]]; then 80 | # diverged 81 | tw_git_status_display+=" %F{$tw_colors[git_status_diverged]}~" 82 | elif [[ "$tw_is_ahead" == true ]]; then 83 | tw_git_status_display+=" %F{$tw_colors[git_status_ahead]}|•" 84 | elif [[ "$tw_is_behind" == true ]]; then 85 | tw_git_status_display+=" %F{$tw_colors[git_status_behind]}•|" 86 | fi 87 | 88 | # stashed 89 | local tw_stash_count=`git stash list | wc -l` 90 | if [[ $tw_stash_count -gt 0 ]]; then 91 | tw_git_status_display+=" %F{$tw_colors[git_status_stash]}$" 92 | fi 93 | fi 94 | 95 | echo "$tw_git_status_display" 96 | } 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typewritten", 3 | "version": "1.5.2", 4 | "description": "A minimal, lightweight, informative zsh prompt theme", 5 | "files": [ 6 | "typewritten.zsh", 7 | "async.zsh", 8 | "lib", 9 | "scripts" 10 | ], 11 | "scripts": { 12 | "postinstall": "./scripts/install.sh", 13 | "postuninstall": "./scripts/uninstall.sh" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "git+https://github.com/reobin/typewritten.git" 18 | }, 19 | "keywords": [ 20 | "typewritten", 21 | "zsh", 22 | "prompt", 23 | "theme", 24 | "minimal", 25 | "shell", 26 | "git", 27 | "terminal" 28 | ], 29 | "author": "Robin Gagnon (https://reobin.dev)", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/reobin/typewritten/issues" 33 | }, 34 | "homepage": "https://typewritten.dev", 35 | "directories": { 36 | "lib": "lib" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /prompt_typewritten_setup: -------------------------------------------------------------------------------- 1 | typewritten.zsh -------------------------------------------------------------------------------- /scripts/install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | # 3 | # This script is a clone/fork of the spaceship-prompt install script and it was 4 | # changed in order to install the typewritten prompt instead. 5 | # 6 | # Original author: Denys Dovhan, denysdovhan.com 7 | # From: https://github.com/spaceship-prompt/spaceship-prompt 8 | 9 | # ------------------------------------------------------------------------------ 10 | # Colors 11 | # Set color variables for colorful output 12 | # ------------------------------------------------------------------------------ 13 | 14 | # If we have tput, let's set colors 15 | if [[ ! -z $(which tput 2> /dev/null) ]]; then 16 | reset=$(tput sgr0) 17 | bold=$(tput bold) 18 | red=$(tput setaf 1) 19 | green=$(tput setaf 2) 20 | yellow=$(tput setaf 3) 21 | blue=$(tput setaf 4) 22 | magenta=$(tput setaf 5) 23 | cyan=$(tput setaf 6) 24 | fi 25 | 26 | # ------------------------------------------------------------------------------ 27 | # VARIABLES 28 | # Paths to important resources 29 | # ------------------------------------------------------------------------------ 30 | 31 | ZSHRC="${ZDOTDIR:-$HOME}/.zshrc" 32 | REPO='https://github.com/reobin/typewritten.git' 33 | 34 | SOURCE="$PWD/typewritten.zsh" 35 | ASYNC_SOURCE="$PWD/async.zsh" 36 | USER_SOURCE="${ZDOTDIR:-$HOME}/.typewritten-prompt" 37 | 38 | DEST='/usr/local/share/zsh/site-functions' 39 | USER_DEST="${ZDOTDIR:-$HOME}/.zfunctions" 40 | 41 | # ------------------------------------------------------------------------------ 42 | # HELPERS 43 | # Useful functions for common tasks 44 | # ------------------------------------------------------------------------------ 45 | 46 | # Paint text in specific color with reset 47 | # USAGE: 48 | # paint [text...] 49 | paint() { 50 | local color=$1 rest=${@:2} 51 | echo "$color$rest$reset" 52 | } 53 | 54 | # Aliases for common used colors 55 | # Colon at the end is required: https://askubuntu.com/a/521942 56 | # USAGE: 57 | # info|warn|error|success|code [...text] 58 | info() { paint "$cyan" "typewritten: $@" ; } 59 | warn() { paint "$yellow" "typewritten: $@" ; } 60 | error() { paint "$red" "typewritten: $@" ; } 61 | success() { paint "$green" "typewritten: $@" ; } 62 | code() { paint "$bold" "typewritten: $@" ; } 63 | 64 | # Append text in .zshrc 65 | # USAGE: 66 | # append_zshrc [text...] 67 | append_zshrc() { 68 | info "These lines will be added to your \"${ZDOTDIR:-$HOME}/.zshrc\" file:" 69 | code "$@" 70 | echo "$@" >> "${ZDOTDIR:-$HOME}/.zshrc" 71 | } 72 | 73 | # ------------------------------------------------------------------------------ 74 | # MAIN 75 | # Checkings and installing process 76 | # ------------------------------------------------------------------------------ 77 | 78 | main() { 79 | # How we install typewritten: 80 | # 1. Install via NPM 81 | # 2. Install via curl or wget 82 | if [[ ! -f "$SOURCE" ]]; then 83 | warn "typewritten is not present in current directory" 84 | # Clone repo into the ${ZDOTDIR:-$HOME}/.typewritten-prompt and change SOURCE 85 | git clone "$REPO" "$USER_SOURCE" 86 | SOURCE="$USER_SOURCE/typewritten.zsh" 87 | ASYNC_SOURCE="$USER_SOURCE/async.zsh" 88 | else 89 | info "typewritten is present in current directory" 90 | fi 91 | 92 | # If we can't symlink to the site-functions, then try to use .zfunctions instead 93 | if [[ ! -w "$DEST" ]]; then 94 | error "Failed to symlink $SOURCE to $DEST." 95 | error "Failed to symlink $ASYNC_SOURCE to $DEST." 96 | 97 | # Use $USER_DEST instead 98 | DEST="$USER_DEST" 99 | 100 | info "Adding $DEST to fpath..." 101 | echo 'fpath=($fpath "'"$DEST"'")' >> "$ZSHRC" 102 | 103 | info "Trying to symlink $SOURCE to $DEST" 104 | info "Trying to symlink $ASYNC_SOURCE to $DEST" 105 | fi 106 | 107 | # Link prompt entry point to fpath 108 | info "Linking $SOURCE to $DEST/prompt_typewritten_setup..." 109 | info "Linking $ASYNC_SOURCE to $DEST/async..." 110 | mkdir -p "$DEST" 111 | ln -sf "$SOURCE" "$DEST/prompt_typewritten_setup" 112 | ln -sf "$ASYNC_SOURCE" "$DEST/async" 113 | 114 | # If 'prompt typewritten' is already present in .zshrc, then skip 115 | if sed 's/#.*//' "$ZSHRC" | grep -q "prompt typewritten"; then 116 | warn "typewritten is already present in .zshrc!" 117 | exit 118 | fi 119 | 120 | # Enabling statements for .zshrc 121 | msg="\n# Set typewritten ZSH as a prompt" 122 | msg+="\nautoload -U promptinit; promptinit" 123 | msg+="\nprompt typewritten" 124 | 125 | # Check if appending was successful and perform corresponding actions 126 | if append_zshrc "$msg"; then 127 | success "Done! Please, reload your terminal." 128 | echo 129 | else 130 | error "Cannot automatically insert prompt init commands." 131 | error "Please insert these line into your \"${ZDOTDIR:-$HOME}/.zshrc\" file:" 132 | code "$msg" 133 | exit 1 134 | fi 135 | } 136 | 137 | main "$@" 138 | -------------------------------------------------------------------------------- /scripts/uninstall.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # This script is a clone/fork of the spaceship-prompt uninstall script and it was 4 | # changed in order to install the typewritten prompt instead. 5 | # 6 | # Original author: Denys Dovhan, denysdovhan.com 7 | # From: https://github.com/spaceship-prompt/spaceship-prompt 8 | 9 | # ------------------------------------------------------------------------------ 10 | # Colors 11 | # Set color variables for colorful output 12 | # ------------------------------------------------------------------------------ 13 | 14 | # If we have tput, let's set colors 15 | if [[ ! -z $(which tput 2> /dev/null) ]]; then 16 | reset=$(tput sgr0) 17 | bold=$(tput bold) 18 | red=$(tput setaf 1) 19 | green=$(tput setaf 2) 20 | yellow=$(tput setaf 3) 21 | blue=$(tput setaf 4) 22 | magenta=$(tput setaf 5) 23 | cyan=$(tput setaf 6) 24 | fi 25 | 26 | # ------------------------------------------------------------------------------ 27 | # VARIABLES 28 | # Paths to important resources 29 | # ------------------------------------------------------------------------------ 30 | 31 | ZSHRC="${ZDOTDIR:-$HOME}/.zshrc" 32 | USER_SOURCE="${ZDOTDIR:-$HOME}/.typewritten-prompt" 33 | 34 | PROMPT_SETUP="prompt_typewritten_setup" 35 | PROMPT_ASYNC="async" 36 | 37 | GLOBAL_DEST_SETUP="/usr/local/share/zsh/site-functions/$PROMPT_SETUP" 38 | USER_DEST_SETUP="${ZDOTDIR:-$HOME}/.zfunctions/$PROMPT_SETUP" 39 | 40 | GLOBAL_DEST_ASYNC="/usr/local/share/zsh/site-functions/$PROMPT_ASYNC" 41 | USER_DEST_ASYNC="${ZDOTDIR:-$HOME}/.zfunctions/$PROMPT_ASYNC" 42 | 43 | # ------------------------------------------------------------------------------ 44 | # HELPERS 45 | # Useful functions for common tasks 46 | # ------------------------------------------------------------------------------ 47 | 48 | # Paint text in specific color with reset 49 | # USAGE: 50 | # paint [text...] 51 | paint() { 52 | local color=$1 rest=${@:2} 53 | echo "$color$rest$reset" 54 | } 55 | 56 | # Aliases for common used colors 57 | # Colon at the end is required: https://askubuntu.com/a/521942 58 | # USAGE: 59 | # info|warn|error|success|code [...text] 60 | info() { paint "$cyan" "typewritten: $@" ; } 61 | warn() { paint "$yellow" "typewritten: $@" ; } 62 | error() { paint "$red" "typewritten: $@" ; } 63 | success() { paint "$green" "typewritten: $@" ; } 64 | code() { paint "$bold" "typewritten: $@" ; } 65 | 66 | # Check if symlink is exists and remove it 67 | # USAGE: 68 | # rmln 69 | rmln() { 70 | local target=$1 71 | if [[ -L "$target" ]]; then 72 | info "Removing $target..." 73 | rm -f "$target" 74 | fi 75 | } 76 | 77 | # ------------------------------------------------------------------------------ 78 | # MAIN 79 | # Checkings and uninstalling process 80 | # ------------------------------------------------------------------------------ 81 | 82 | remove_zshrc_content() { 83 | info "Removing typewritten from \"${ZDOTDIR:-$HOME}/.zshrc\"" 84 | # Remove enabling statements from .zshrc 85 | # and remove typewritten configuration 86 | sed '/^# Set typewritten ZSH as a prompt$/d' "$ZSHRC" | \ 87 | sed '/^autoload -U promptinit; promptinit$/d' | \ 88 | sed '/^prompt typewritten$/d' | \ 89 | sed '/.*TYPEWRITTEN_.*=.*$/d' > "$ZSHRC.bak" && \ 90 | mv -- "$ZSHRC.bak" "$ZSHRC" 91 | } 92 | 93 | main() { 94 | # Remove prompt setup symlink 95 | if [[ -L "$GLOBAL_DEST_SETUP" || -L "$USER_DEST_SETUP" ]]; then 96 | rmln "$GLOBAL_DEST_SETUP" 97 | rmln "$USER_DEST_SETUP" 98 | else 99 | warn "Symlinks to typewritten setup are not found." 100 | fi 101 | 102 | # Remove prompt async symlink 103 | if [[ -L "$GLOBAL_DEST_ASYNC" || -L "$USER_DEST_ASYNC" ]]; then 104 | rmln "$GLOBAL_DEST_ASYNC" 105 | rmln "$USER_DEST_ASYNC" 106 | else 107 | warn "Symlinks to typewritten async are not found." 108 | fi 109 | 110 | # Remove typewritten from .zshrc 111 | if grep -q "typewritten" "$ZSHRC"; then 112 | if [[ '-y' == $1 ]]; then 113 | remove_zshrc_content 114 | else 115 | read "answer?Would you like to remove you typewritten ZSH configuration from .zshrc? (y/N)" 116 | if [[ 'y' == ${answer:l} ]]; then 117 | read "answer?Are you sure? Any symlinks to your ZSH configuration file might be removed? (y/N)" 118 | if [[ 'y' == ${answer:l} ]]; then 119 | remove_zshrc_content 120 | fi 121 | fi 122 | fi 123 | else 124 | warn "typewritten configuration not found in \"${ZDOTDIR:-$HOME}/.zshrc\"!" 125 | fi 126 | 127 | success "Done! typewritten installation has been removed!" 128 | success "Please, reload your terminal." 129 | } 130 | 131 | main "$@" 132 | -------------------------------------------------------------------------------- /typewritten.plugin.zsh: -------------------------------------------------------------------------------- 1 | typewritten.zsh -------------------------------------------------------------------------------- /typewritten.zsh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ ____ 4 | # ||t |||y |||p |||e |||w |||r |||i |||t |||t |||e |||n || 5 | # ||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|||__|| 6 | # |/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\|/__\| 7 | # 8 | # A minimal, informative zsh prompt theme 9 | # 10 | 11 | export TYPEWRITTEN_ROOT=${${(%):-%x}:A:h} 12 | 13 | source "$TYPEWRITTEN_ROOT/async.zsh" 14 | async_init 15 | 16 | source "$TYPEWRITTEN_ROOT/lib/colors.zsh" 17 | source "$TYPEWRITTEN_ROOT/lib/git.zsh" 18 | 19 | BREAK_LINE=" 20 | " 21 | 22 | local tw_prompt_symbol="❯" 23 | if [ ! -z "$TYPEWRITTEN_SYMBOL" ]; then 24 | tw_prompt_symbol="$TYPEWRITTEN_SYMBOL" 25 | fi; 26 | 27 | local tw_base_symbol_color="%F{$tw_colors[symbol]}" 28 | if [[ $(id -u) -eq 0 ]]; then 29 | tw_base_symbol_color="%F{$tw_colors[symbol_root]}" 30 | fi 31 | 32 | local tw_prompt_color="%(?,$tw_base_symbol_color,%F{$tw_colors[symbol_error]})" 33 | local tw_return_code="%(?,,%F{$tw_colors[error_code]}%? )" 34 | if [ "$TYPEWRITTEN_DISABLE_RETURN_CODE" = true ]; then 35 | tw_prompt_color="$tw_base_symbol_color" 36 | tw_return_code="" 37 | fi; 38 | 39 | tw_user_host="%F{$tw_colors[host]}%n%F{$tw_colors[host_user_connector]}@%F{$tw_colors[user]}%m" 40 | tw_prompt="$tw_prompt_color$tw_return_code$tw_prompt_symbol %F{$tw_colors[prompt]}" 41 | 42 | tw_current_directory_color="$tw_colors[current_directory]" 43 | tw_git_branch_color="$tw_colors[git_branch]" 44 | 45 | local tw_arrow_symbol="->" 46 | if [ ! -z "$TYPEWRITTEN_ARROW_SYMBOL" ]; then 47 | tw_arrow_symbol="$TYPEWRITTEN_ARROW_SYMBOL" 48 | fi; 49 | tw_arrow="%F{$tw_colors[arrow]}$tw_arrow_symbol" 50 | 51 | tw_get_virtual_env() { 52 | if [[ -z $VIRTUAL_ENV_DISABLE_PROMPT ]]; then 53 | local tw_virtual_env="" 54 | if [[ ! -z $VIRTUAL_ENV ]]; then 55 | tw_virtual_env="($(basename $VIRTUAL_ENV)) " 56 | elif [[ ! -z $CONDA_PROMPT_MODIFIER ]]; then 57 | tw_virtual_env="$(basename $CONDA_PROMPT_MODIFIER)" 58 | fi; 59 | 60 | if [[ $tw_virtual_env != "" ]]; then 61 | echo "%F{$tw_colors[virtual_env]}$tw_virtual_env" 62 | fi; 63 | fi; 64 | } 65 | 66 | tw_get_displayed_wd() { 67 | local tw_git_branch=$tw_prompt_data[tw_git_branch] 68 | local tw_git_home=$tw_prompt_data[tw_git_home] 69 | 70 | local tw_home_relative_wd="%~" 71 | local tw_git_relative_wd="$tw_git_home%c" 72 | 73 | local tw_displayed_wd="$tw_git_relative_wd" 74 | 75 | # The pure layout defaults to home relative working directory, but allows customization 76 | if [[ "$TYPEWRITTEN_PROMPT_LAYOUT" = pure* && "$TYPEWRITTEN_RELATIVE_PATH" = "" ]]; then 77 | tw_displayed_wd=$tw_home_relative_wd 78 | fi; 79 | 80 | if [[ "$TYPEWRITTEN_RELATIVE_PATH" = "home" ]]; then 81 | tw_displayed_wd=$tw_home_relative_wd 82 | fi; 83 | 84 | if [[ "$TYPEWRITTEN_RELATIVE_PATH" = "adaptive" ]]; then 85 | if [[ "$tw_git_branch" = "" ]]; then 86 | tw_displayed_wd=$tw_home_relative_wd 87 | fi; 88 | fi; 89 | 90 | echo "%F{$tw_current_directory_color}$tw_displayed_wd" 91 | } 92 | 93 | tw_get_left_prompt_prefix() { 94 | local tw_left_prompt_prefix="" 95 | 96 | if [[ ! -z $TYPEWRITTEN_LEFT_PROMPT_PREFIX || ! -z $TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION ]]; then 97 | tw_left_prompt_prefix="%F{$tw_colors[left_prompt_prefix]}" 98 | fi; 99 | 100 | if [[ ! -z $TYPEWRITTEN_LEFT_PROMPT_PREFIX ]]; then 101 | tw_left_prompt_prefix="$tw_left_prompt_prefix$TYPEWRITTEN_LEFT_PROMPT_PREFIX " 102 | fi; 103 | 104 | if [[ ! -z $TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION ]]; then 105 | local value=$($TYPEWRITTEN_LEFT_PROMPT_PREFIX_FUNCTION) 2>/dev/null 106 | 107 | if [[ ! -z $value ]]; then 108 | tw_left_prompt_prefix="$tw_left_prompt_prefix$value " 109 | fi; 110 | fi; 111 | 112 | echo $tw_left_prompt_prefix 113 | } 114 | 115 | tw_get_right_prompt_prefix() { 116 | local tw_right_prompt_prefix="" 117 | 118 | if [[ ! -z $TYPEWRITTEN_RIGHT_PROMPT_PREFIX || ! -z $TYPEWRITTEN_RIGHT_PROMPT_PREFIX_FUNCTION ]]; then 119 | tw_right_prompt_prefix="%F{$tw_colors[right_prompt_prefix]}" 120 | fi; 121 | 122 | if [[ ! -z $TYPEWRITTEN_RIGHT_PROMPT_PREFIX ]]; then 123 | tw_right_prompt_prefix="$tw_right_prompt_prefix$TYPEWRITTEN_RIGHT_PROMPT_PREFIX " 124 | fi; 125 | 126 | if [[ ! -z $TYPEWRITTEN_RIGHT_PROMPT_PREFIX_FUNCTION ]]; then 127 | local value=$($TYPEWRITTEN_RIGHT_PROMPT_PREFIX_FUNCTION) 2>/dev/null 128 | 129 | if [[ ! -z $value ]]; then 130 | tw_right_prompt_prefix="$tw_right_prompt_prefix$value " 131 | fi; 132 | fi; 133 | 134 | echo $tw_right_prompt_prefix 135 | } 136 | 137 | tw_redraw() { 138 | local tw_displayed_wd="$(tw_get_displayed_wd)" 139 | 140 | local tw_full_prompt="$(tw_get_virtual_env)$(tw_get_left_prompt_prefix)$tw_prompt" 141 | 142 | local tw_layout="$TYPEWRITTEN_PROMPT_LAYOUT" 143 | local tw_git_info="$tw_prompt_data[tw_git_branch]$tw_prompt_data[tw_git_status]" 144 | 145 | if [ "$tw_layout" = "half_pure" ]; then 146 | PROMPT="$BREAK_LINE%F{$tw_git_branch_color}$tw_git_info$BREAK_LINE$tw_full_prompt" 147 | RPROMPT="$(tw_get_right_prompt_prefix)$tw_displayed_wd" 148 | else 149 | local tw_git_arrow_info="" 150 | if [ "$tw_git_info" != "" ]; then 151 | tw_git_arrow_info=" $tw_arrow %F{$tw_git_branch_color}$tw_git_info" 152 | fi; 153 | 154 | local tw_right_prompt_prefix="$(tw_get_right_prompt_prefix)" 155 | 156 | PROMPT="$tw_full_prompt" 157 | RPROMPT="$tw_right_prompt_prefix$tw_displayed_wd$tw_git_arrow_info" 158 | 159 | if [ "$tw_layout" = "pure" ]; then 160 | PROMPT="$BREAK_LINE$tw_displayed_wd$tw_git_arrow_info$BREAK_LINE$tw_full_prompt" 161 | RPROMPT="" 162 | fi; 163 | 164 | if [ "$tw_layout" = "pure_verbose" ]; then 165 | PROMPT="$BREAK_LINE$tw_user_host $tw_displayed_wd$tw_git_arrow_info$BREAK_LINE$tw_full_prompt" 166 | RPROMPT="" 167 | fi; 168 | 169 | if [ "$tw_layout" = "singleline_verbose" ]; then 170 | PROMPT="$tw_user_host $tw_full_prompt" 171 | RPROMPT="$tw_right_prompt_prefix$tw_displayed_wd$tw_git_arrow_info" 172 | fi; 173 | 174 | if [ "$tw_layout" = "multiline" ]; then 175 | PROMPT="$BREAK_LINE$tw_user_host$BREAK_LINE$tw_full_prompt" 176 | RPROMPT="$tw_right_prompt_prefix$tw_displayed_wd$tw_git_arrow_info" 177 | fi; 178 | fi; 179 | 180 | zle -R && zle reset-prompt 181 | } 182 | 183 | tw_async_init_worker() { 184 | async_start_worker tw_worker -n 185 | async_register_callback tw_worker tw_prompt_callback 186 | } 187 | 188 | tw_prompt_callback() { 189 | local tw_name=$1 tw_code=$2 tw_output=$3 190 | if (( tw_code == 2 )) || (( tw_code == 3 )) || (( tw_code == 130 )); then 191 | # reinit async workers 192 | async_stop_worker tw_worker 193 | tw_async_init_worker 194 | tw_async_init_tasks 195 | elif (( tw_code )); then 196 | tw_async_init_tasks 197 | fi; 198 | tw_prompt_data[$tw_name]=$tw_output 199 | tw_redraw 200 | } 201 | 202 | tw_async_init_tasks() { 203 | typeset -Ag tw_prompt_data 204 | 205 | local tw_current_pwd="$PWD" 206 | async_worker_eval tw_worker builtin cd -q $tw_current_pwd 207 | 208 | local tw_git_hide_status="$(git config --get oh-my-zsh.hide-status 2>/dev/null)" 209 | if [[ "$tw_git_hide_status" != "1" ]]; then 210 | local tw_git_toplevel="$(git rev-parse --show-toplevel 2>/dev/null)" 211 | 212 | if [[ "$tw_current_pwd" != $tw_prompt_data[tw_current_pwd] ]]; then 213 | async_flush_jobs tw_worker 214 | tw_prompt_data[tw_git_home]= 215 | fi; 216 | 217 | if [[ "$tw_git_toplevel" != $tw_prompt_data[tw_git_toplevel] ]]; then 218 | async_flush_jobs tw_worker 219 | tw_prompt_data[tw_git_branch]= 220 | tw_prompt_data[tw_git_status]= 221 | fi; 222 | 223 | tw_prompt_data[tw_git_toplevel]="$tw_git_toplevel" 224 | tw_prompt_data[tw_current_pwd]="$tw_current_pwd" 225 | if [[ "$TYPEWRITTEN_RELATIVE_PATH" = "git" || "$TYPEWRITTEN_RELATIVE_PATH" = "adaptive" ]]; then 226 | async_job tw_worker tw_git_home $tw_current_pwd $tw_git_toplevel 227 | fi; 228 | async_job tw_worker tw_git_branch 229 | async_job tw_worker tw_git_status 230 | else 231 | tw_prompt_data[tw_git_branch]= 232 | tw_prompt_data[tw_git_status]= 233 | fi; 234 | 235 | tw_redraw 236 | } 237 | 238 | # prompt cursor fix when exiting vim 239 | tw_fix_cursor() { 240 | local tw_cursor="\e[3 q" 241 | if [ "$TYPEWRITTEN_CURSOR" = "block" ]; then 242 | tw_cursor="\e[1 q" 243 | elif [ "$TYPEWRITTEN_CURSOR" = "beam" ]; then 244 | tw_cursor="\e[5 q" 245 | fi; 246 | echo -ne "$tw_cursor" 247 | } 248 | 249 | tw_setup() { 250 | tw_async_init_worker 251 | tw_async_init_tasks 252 | 253 | zmodload zsh/zle 254 | autoload -Uz add-zsh-hook 255 | if [ "$TYPEWRITTEN_CURSOR" != "terminal" ]; then 256 | add-zsh-hook precmd tw_fix_cursor 257 | fi; 258 | add-zsh-hook precmd tw_async_init_tasks 259 | 260 | PROMPT="$tw_prompt" 261 | } 262 | tw_setup 263 | 264 | zle_highlight=( default:fg=$tw_colors[prompt] ) 265 | -------------------------------------------------------------------------------- /typewritten.zsh-theme: -------------------------------------------------------------------------------- 1 | typewritten.zsh --------------------------------------------------------------------------------