Compare commits

..

127 Commits

Author SHA1 Message Date
Matan Kushner 29eedeb698 chore(bump): v0.16.0 2019-09-08 00:21:18 -04:00
Matan Kushner dcc105ea1b ci: Add a build target for musl 2019-09-08 00:20:21 -04:00
Kevin Song 9721666d33 feat: Add the ability to configure per-module color styles (#285)
Add parsing logic, config support, docs, and integration with other modules 
for custom styling of each module.
2019-09-07 19:33:06 -05:00
allcontributors[bot] 3e5cac9852 docs: add nickwb as a contributor (#310) 2019-09-07 15:17:00 -04:00
Neil Kistner 86c4a4bdcf refactor: Cleanup unwraps in create_fixture_repo function (#311) 2019-09-07 12:27:29 -05:00
Neil Kistner 6658b7f0aa fix: Fixture repo will now clone and set git config locally (#307) 2019-09-07 11:25:01 -05:00
allcontributors[bot] 3435b9cdc2 docs: add g2p as a contributor (#309) 2019-09-07 11:13:10 -04:00
Gabriel de Perthuis 69ebab46a4 fix: Don't trigger an extension match on hidden files (#299)
Addresses #52, closes #280.
2019-09-07 11:05:25 -04:00
Matan Kushner 61abe6dd7a chore(bump): v0.15.0 2019-09-05 23:05:20 -04:00
allcontributors[bot] 313def1d92 docs: add wyze as a contributor (#297)
* docs: update README.md

* docs: update .all-contributorsrc
2019-09-05 12:47:45 -04:00
allcontributors[bot] 80f0600b4f docs: add nickwb as a contributor (#296) 2019-09-05 12:47:09 -04:00
Nick Young eb724279da feat: Adds Git State module for showing "REBASING 2/3", etc. (#276)
- Adds the git_state module.
- Adds git_state to the default prompt order
- Updates the documentation to describe the git_state module
2019-09-05 12:45:04 -04:00
Thomas O'Donnell 4f17bae315 fix: Add missing module to list of modules (#294)
Have added the missing hostname module to the list of all modules.
2019-09-05 11:33:24 -04:00
Matan Kushner 2bdfcb1373 chore(bump): v0.14.1 2019-09-05 00:38:55 -04:00
Matan Kushner f8ca3fd007 ci: Fix rust cross installation 2019-09-05 00:36:27 -04:00
Matan Kushner 29325c6b50 chore(bump): v0.14.0 2019-09-05 00:15:29 -04:00
Neil Kistner 1c66869117 feat: Add config for ahead/behind count of tracked branch (#281)
Add a configuration option (show_sync_count) to the git_status module that will show/hide the counts ahead/behind of the tracked branch. Currently have this default to false, and would opt-in to show this information.
2019-09-05 00:09:51 -04:00
Matan Kushner c5e693b638 ci: Update Actions events to include pull_request 2019-09-04 20:56:06 -04:00
Matan Kushner 8d353f72c6 docs: Move starship badge to be above "License" 2019-09-04 19:23:55 -04:00
Matan Kushner 23cf3e5b12 docs: Add "Inspired By" to README.md (#291) 2019-09-04 19:22:28 -04:00
Matan Kushner e66d7bae1c ci: Migrate CI from Azure Pipelines to GitHub Actions (#233)
Migrated CI from Azure Pipelines to GitHub Actions.
Until the release process is figured out in Actions, we'll stick to using Azure pipelines for releases.
2019-09-04 19:13:53 -04:00
allcontributors[bot] 68754208c1 docs: add ahouts as a contributor (#288) 2019-09-04 13:05:00 -04:00
Andrew Houts 84688e4981 feat: add hostname module (#286)
Add a hostname module as requested by @chipbuster.
Displays the system hostname as provided by gethostname.
2019-09-04 13:03:31 -04:00
Nick Young 5a0f269d85 fix: Be more restrictive with bash init fallback (#278)
This should improve compatibility with "Git Bash" with Git for Windows by
using psub+source init for all bash shells v4.1 and newer.
2019-09-04 09:23:31 -05:00
Thomas O'Donnell 789d504a44 Chore: Update PR template to add semver types (#287)
Have upded the PR template to add the semantic versioning types 
this should make it easier to pass the semantic-pull-requests checks.
2019-09-04 08:37:18 -05:00
Neil Kistner dfade6d629 refactor: Move create_fixture_repo into common in integration tests (#282) 2019-09-04 00:20:22 -04:00
Kevin Song 6db0e20585 Change ZSH init to use jobstates for num jobs (#252) 2019-09-03 23:44:44 -04:00
dependabot-preview[bot] f2f7815960 chore(deps): Bump ansi_term from 0.12.0 to 0.12.1 (#277)
Bumps [ansi_term](https://github.com/ogham/rust-ansi-term) from 0.12.0 to 0.12.1.
- [Release notes](https://github.com/ogham/rust-ansi-term/releases)
- [Commits](https://github.com/ogham/rust-ansi-term/compare/v0.12.0...v0.12.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-03 11:04:47 -04:00
allcontributors[bot] b4fccc46d7 docs: add oblitum as a contributor (#275) 2019-09-02 20:36:33 -04:00
allcontributors[bot] 5e2c8c5745 docs: add tivervac as a contributor (#274) 2019-09-02 20:27:50 -04:00
Matan Kushner 470648000f test: Add an integration test for disabling untracked files 2019-09-02 20:27:04 -04:00
Francisco Lopes 722a0652fd feat: Respect status.showUntrackedFiles 2019-09-02 20:27:04 -04:00
Titouan Vervack 59e8b1fc92 feat: added truncation_length/symbol to git_branch (#268)
Git branches can become very long (e.g. gitlab auto-generated branch
names), thus it would be nice to be able to truncate them to keep your
prompt lenght in line.

This patch adds two new options to the git_branch module:
* truncation_length: The amount of graphemes to of a gitbranch to
truncate to
* truncation_symbol: The symbol that should be used to indicate that a
branch name was trunctated

To be able to correctly work with UTF-8 graphemes, unicode-segmentation
was added as a dependency.
2019-09-02 15:56:59 -04:00
dependabot-preview[bot] f8929c2d7d chore(deps): Bump rayon from 1.1.0 to 1.2.0 (#269)
Bumps [rayon](https://github.com/rayon-rs/rayon) from 1.1.0 to 1.2.0.
- [Release notes](https://github.com/rayon-rs/rayon/releases)
- [Changelog](https://github.com/rayon-rs/rayon/blob/master/RELEASES.md)
- [Commits](https://github.com/rayon-rs/rayon/compare/rayon-core-v1.1.0...v1.2.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-09-02 14:00:26 -04:00
Thomas O'Donnell de4a715333 docs: "staged" git config option in docs (#271)
Have corrected the documentation for the git module. The docs now use
the correct option `staged` rather than `added`.
2019-09-02 11:44:20 -04:00
allcontributors[bot] ba225a6581 docs: update bbigras as a contributor (#266) 2019-08-31 19:34:29 -04:00
allcontributors[bot] b802fb6ed8 docs: add qstrahl as a contributor (#265) 2019-08-31 19:29:38 -04:00
Quinn Strahl 3dd035056d Support vicmd_symbol in fish-shell (#254) 2019-08-31 00:59:18 -07:00
Nick Young 4eb7beca48 fix: Adds nix_shell to module::ALL_MODULES (#264)
So that it can be configured in the user's prompt
2019-08-30 09:39:21 -04:00
dependabot-preview[bot] 5f05d9e7af chore(deps): [Security] Bump spin from 0.5.0 to 0.5.2 (#256)
Bumps [spin](https://github.com/mvdnes/spin-rs) from 0.5.0 to 0.5.2. **This update includes a security fix.**
- [Release notes](https://github.com/mvdnes/spin-rs/releases)
- [Commits](https://github.com/mvdnes/spin-rs/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-29 13:53:00 -04:00
Matan Kushner c121dd4d44 docs: Add undocumented config options (#262) 2019-08-29 13:09:36 -04:00
Harry Mills 9918dd1aac docs: Correct a copy/paste error in the docs (#259) 2019-08-29 12:41:09 -04:00
Harry Mills c2a1803681 Fix typo in comment (#260) 2019-08-29 12:40:25 -04:00
Bruno Bigras ad8cd7334f Add repology badge to README (#249) 2019-08-27 22:36:43 -07:00
Neil Kistner 9853743eda feat: Add commit count for ahead/behind symbols (#247)
Add logic for the git status module to display the number of commits the index is ahead or behind next to the symbol.
2019-08-27 20:11:42 -07:00
Bruno Bigras ed27cf4a2c docs: add termux install instructions (#248) 2019-08-27 19:32:26 -04:00
Matan Kushner cacaf66efe chore(bump): v0.13.1 2019-08-27 14:10:48 -04:00
Bruno Bigras fa2d1c05a6 fix: use procsub in bash since termux has no stdin (#241) 2019-08-27 00:02:52 -07:00
Matan Kushner f61e7e2f87 chore(bump): v0.13.0 2019-08-26 23:10:58 -04:00
allcontributors[bot] 656e0bb52e docs: add wyze as a contributor (#245)
* docs: update README.md

* docs: update .all-contributorsrc
2019-08-26 22:29:32 -04:00
Neil Kistner e034253a5e feat: Add ability to use an alternate directory truncation style (#239)
* Add ability to use an alternate directory truncation style
2019-08-26 21:52:45 -04:00
Matan Kushner 81ea165cec chore: Add homepage to Cargo.toml 2019-08-26 15:07:47 -04:00
Ivan Tham cdea401589 refactor: just match enum (#236)
Remove forced unwrap since match is already exhausted
2019-08-26 14:47:34 -04:00
Bruno Bigras 0fa862a2e9 make the battery module optional for now (#234)
The 'battery' crate doesn't support Termux, so we are temporarily making the battery module optional.
2019-08-26 14:09:39 -04:00
dependabot-preview[bot] f7754455e6 chore(deps): Bump lazy_static from 1.3.0 to 1.4.0 (#242)
Bumps [lazy_static](https://github.com/rust-lang-nursery/lazy-static.rs) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/rust-lang-nursery/lazy-static.rs/releases)
- [Commits](https://github.com/rust-lang-nursery/lazy-static.rs/compare/1.3.0...1.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-26 12:53:40 -04:00
TsubasaKawajiri 08aef016cd fix: battery percentage character on Zsh. #226 (#237)
on Zsh, battery percentage character would print %
this PR fixes print %{ -> %
2019-08-25 21:52:44 -04:00
Bruno Bigras feb737190e Add nix-shell support (#173) 2019-08-25 11:41:20 -04:00
Matan Kushner 57e807fec6 style: Fix clippy warnings 2019-08-23 13:13:04 -04:00
Matan Kushner 2d10cb2b30 chore(bump): v0.12.2 2019-08-23 10:41:05 -04:00
allcontributors[bot] a5db918cfd docs: add bbigras as a contributor (#230) 2019-08-22 20:41:29 -04:00
Matan Kushner e31b3391f1 docs: Add new demo gif to README (#231)
Since the prompt has been updated to have a new default character symbol, it's time we update the demo gif to reflect those changes.
2019-08-22 20:03:45 -04:00
Matan Kushner b70f6f1ad3 chore(bump): v0.12.1 2019-08-22 19:04:10 -04:00
Bruno Bigras 68cbcb91b7 Use full path to starship in all phases of init (#224) 2019-08-22 12:57:32 -07:00
allcontributors[bot] 70d53ee7a9 docs: add andytom as a contributor (#223) 2019-08-22 10:36:34 -04:00
Shu Kutsuzawa f74e639c49 docs: fix LICENSE and CONTRIBUTING links (#228) 2019-08-22 10:35:15 -04:00
Thomas O'Donnell 1478f8c2e9 Add support for detecting Python from Pipenv files (#221)
Added the ability to enable the Python module based on the existence of the a `Pipfile`.
2019-08-21 15:54:22 -07:00
Kevin Song 360ea988e5 Add ruby to default module ordering (#217) 2019-08-21 12:41:01 -07:00
dependabot-preview[bot] 1943da86ce chore(deps): Bump git2 from 0.9.2 to 0.10.0 (#216)
Bumps [git2](https://github.com/rust-lang/git2-rs) from 0.9.2 to 0.10.0.
- [Release notes](https://github.com/rust-lang/git2-rs/releases)
- [Commits](https://github.com/rust-lang/git2-rs/compare/git2-curl-0.9.2...git2-curl-0.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-21 13:17:13 -04:00
Kevin Song da86b4f847 fix: Failing Tests if home is a git directory (#214) 2019-08-21 09:37:43 -07:00
Shu Kutsuzawa faa2280620 Correct description of Rust symbol in docs (#219)
Signed-off-by: cappyzawa <cappyzawa@yahoo.ne.jp>
2019-08-21 09:08:56 -07:00
Kevin Song f06247d5d3 fix: Correct ZSH init on older ZSH versions (#213) 2019-08-20 23:49:07 -04:00
Matan Kushner dcb78a4e0b docs: Add a GA tag 2019-08-20 11:13:19 -04:00
Oran Simhony 2f9922ff2f docs: Fix the good first issue link (#207)
Fixed hyperlink to point to the correct location (added 🌱 emoji and a whitespace in the start)
2019-08-20 09:51:00 -04:00
Bruno Bigras ff8b2a3387 docs: Add Nix installation instructions (#191) 2019-08-20 00:50:35 -04:00
Matan Kushner a08cc971ab chore(bump): v0.12.0 2019-08-20 00:45:42 -04:00
Saurav Sharma 075a76897c fix: Change panicking on unknown module to error print and support module listing flag (#197) 2019-08-20 00:42:25 -04:00
Kevin Song 0e82c19f37 feat: Implement a two-phase init which allows us to write normal init scripts (#168)
Implement a two-phase init procedure in starship. The first phase causes the shell to source a subshell, while the second phase (in the subshell) prints the main init script.

This allows us to have nice init scripts with good styling, comments, and no pile of semicolons. Even better, it works as a drop-in replacement, so we don't need to update the docs.
2019-08-19 18:44:53 -07:00
Matan Kushner 2e39c6d0fa docs: Small README.md fixes 2019-08-19 15:50:36 -04:00
Saghm Rossi 7240a81e98 chore(deps): Update crossbeam-epoch dependency (#200) 2019-08-19 13:55:41 -04:00
Matan Kushner 7f7d77b3d9 chore: Add labels to issue templates 2019-08-19 13:00:32 -04:00
dependabot-preview[bot] 5b3641e50b chore(deps): Bump pretty_env_logger from 0.3.0 to 0.3.1 (#195)
Bumps [pretty_env_logger](https://github.com/seanmonstar/pretty-env-logger) from 0.3.0 to 0.3.1.
- [Release notes](https://github.com/seanmonstar/pretty-env-logger/releases)
- [Commits](https://github.com/seanmonstar/pretty-env-logger/compare/v0.3.0...v0.3.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-19 11:51:55 -04:00
Matan Kushner b39d31aaa7 chore(bump): v0.11.0 2019-08-19 11:18:00 -04:00
Kevin Song a8a553578b docs: Add AUR install instructions (#187) 2019-08-19 11:10:25 -04:00
allcontributors[bot] a965b2587d docs: add iamsauravsharma as a contributor (#189) 2019-08-18 22:02:39 -07:00
Saurav Sharma f54322f2ab feat: Add configuration for reordering the prompt module and disabling default order (#171)
Adds functionality for reordering the prompt module through the use of the prompt_order configuration option in starship.toml
2019-08-18 21:35:11 -07:00
allcontributors[bot] 51f723df22 docs: add iamsauravsharma as a contributor (#186) 2019-08-18 21:14:28 -07:00
Saurav Sharma 664df257bf fix: Solve bash & zsh cursor location confusion issue (#183)
Solves the issue of cursor location confusion on bash and zsh (#110) . Solution: modify ANSIString and wrap non-printing characters with correct escape sequences.
2019-08-18 20:33:12 -07:00
Matan Kushner f7a77edb35 docs: Update setup instructions on landing page (#184) 2019-08-18 13:45:36 -04:00
John Merchant 5af70b9699 fix: Fix directory_in_root integration test on Windows (#181) 2019-08-18 11:55:45 -04:00
Kevin Song 85ac0a6801 fix: Set default prompt character to ❯ (#177) 2019-08-18 11:34:45 -04:00
Kevin Song 572a07c72d fix: Correct broken zsh init in absence of precmd_functions (#180) 2019-08-18 07:07:38 -04:00
Saghm Rossi dfe2ae643a fix a few typos (#178) 2019-08-17 20:50:42 -07:00
Kevin Song 8782e300fc feat: Allow bash users to specify a precmd function (#166)
Allows bash users to run a function before the shell is drawn, by defining a function and setting its name equal to starship_precmd_user_func.
2019-08-17 16:53:59 -07:00
Matan Kushner 7475c3dd72 docs: Small doc touch-ups (#176) 2019-08-17 16:38:20 -04:00
allcontributors[bot] 421d22ed5c docs: add cappyzawa as a contributor (#175) 2019-08-17 16:03:26 -04:00
Shu Kutsuzawa d90c43b8b1 feat: Display Vi mode as PROMPT (#169)
Add Vi-mode indicator for zsh
2019-08-17 12:33:19 -07:00
Matan Kushner 9c213b36b0 docs: Update the all-contributors badge 2019-08-17 12:47:01 -04:00
allcontributors[bot] 3b8d7c040b docs: add saghm as a contributor (#167) 2019-08-17 00:16:22 -04:00
Saghm Rossi 84c394e7b0 feat: Add option to control git directory truncation (#165) 2019-08-16 20:29:22 -07:00
Matan Kushner d065dff695 chore(bump): v0.10.1 2019-08-16 15:04:12 -04:00
Bruno Bigras 7124e353db fix: Fix compilation on NixOS with sandboxing (#164) 2019-08-16 15:01:09 -04:00
Saghm Rossi 5ad07bf2d9 docs: Fix typo in directory module description (#163) 2019-08-16 14:16:29 -04:00
Matan Kushner 6c62c427ea chore(bump): v0.10.0 2019-08-16 13:27:30 -04:00
Kevin Lane e262187f4c feat: Display Python package version from poetry (#153) 2019-08-15 16:41:06 -04:00
Kevin Song e250e71019 fix: Don't run tests for ruby outside of the integration tests (#155) 2019-08-14 21:50:25 -04:00
Matan Kushner 717ee3339e chore: Delete empty test file 2019-08-14 13:31:36 -04:00
dependabot-preview[bot] 3f4bd493d4 chore(deps): Bump toml from 0.5.1 to 0.5.3 (#151)
Bumps [toml](https://github.com/alexcrichton/toml-rs) from 0.5.1 to 0.5.3.
- [Release notes](https://github.com/alexcrichton/toml-rs/releases)
- [Commits](https://github.com/alexcrichton/toml-rs/compare/0.5.1...0.5.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-14 11:28:07 -04:00
Linus Unnebäck 8671fe89db docs: Fix typo in Ruby module description (#152) 2019-08-14 11:27:38 -04:00
allcontributors[bot] 0f1018e6fb docs: add AZanellato as a contributor (#150) 2019-08-14 10:50:11 -04:00
Kevin Song 22c8c3459f feat: implement cmd_duration for bash (#144) 2019-08-13 22:49:47 -04:00
Matan Kushner 56f4797a25 fix: Fix issues with the init script for login shells (#147) 2019-08-13 22:38:17 -04:00
Matan Kushner c5404e0495 ci: Remove remaining reference to bump brew formula 2019-08-13 19:42:25 -04:00
Matan Kushner eb9c19dfe0 ci: Remove brew bump formula from CI 2019-08-13 19:41:42 -04:00
Matan Kushner 03f99e18da chore(bump): v0.9.1 2019-08-13 19:25:23 -04:00
Matan Kushner 6be33284a6 ci: export the Homebrew GitHub API token 2019-08-13 19:25:00 -04:00
Matan Kushner 95401c688f chore(bump): v0.9.0 2019-08-13 18:44:26 -04:00
André Zanellato b06249d61c feat: implement the ruby module (#131) 2019-08-13 18:43:29 -04:00
Matan Kushner f10bfe4616 chore(bump): v0.8.7 2019-08-13 15:08:52 -04:00
Matan Kushner d296432908 fix: Fix exception caused by the golang module
Fixes #148
2019-08-13 15:06:10 -04:00
Matan Kushner bab69c01c4 chore(bump): v0.8.6 2019-08-13 14:59:00 -04:00
Matan Kushner abf5311664 ci: Use the credential.helper config for git 2019-08-13 14:58:36 -04:00
Matan Kushner 6c120dcd2f chore(bump): v0.8.5 2019-08-13 12:31:47 -04:00
Matan Kushner 7424e9674c fix: Fix issues with nodejs and golang configuration (#146)
* fix: Give all modules a single name
* test: Add missing config tests for nodejs and golang
* test: Rename dir to directory
2019-08-13 12:30:59 -04:00
Matan Kushner 589b6cf712 chore(bump): v0.8.4 2019-08-12 23:42:59 -04:00
Matan Kushner 4c26bf06e9 ci: Update Homebrew token storage 2019-08-12 23:42:14 -04:00
Kevin Song a87c0750cc fix: Fix issue with jobs and extra whitespace on MacOS with BSD… (#145)
MacOS wc has a habit of leaving nasty spaces in the output, which was
messing up our argparser.

To fix, quote the output from the jobs command, then have Rust trim out
whitespace in the jobs module before parsing.
2019-08-12 23:41:59 -04:00
Matan Kushner 1d6ce77a81 chore(bump): v0.8.3 2019-08-12 23:18:52 -04:00
73 changed files with 3666 additions and 644 deletions
+135
View File
@@ -122,6 +122,141 @@
"doc",
"test"
]
},
{
"login": "AZanellato",
"name": "André Zanellato",
"avatar_url": "https://avatars3.githubusercontent.com/u/30451287?v=4",
"profile": "https://github.com/AZanellato",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "saghm",
"name": "Saghm Rossi",
"avatar_url": "https://avatars2.githubusercontent.com/u/5875560?v=4",
"profile": "https://saghm.com",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "cappyzawa",
"name": "Shu Kutsuzawa",
"avatar_url": "https://avatars3.githubusercontent.com/u/12455284?v=4",
"profile": "https://medium.com/@cappyzawa",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "iamsauravsharma",
"name": "Saurav Sharma",
"avatar_url": "https://avatars0.githubusercontent.com/u/38726015?v=4",
"profile": "https://github.com/iamsauravsharma",
"contributions": [
"code",
"doc"
]
},
{
"login": "andytom",
"name": "Thomas O'Donnell",
"avatar_url": "https://avatars1.githubusercontent.com/u/108836?v=4",
"profile": "https://github.com/andytom",
"contributions": [
"code",
"test"
]
},
{
"login": "bbigras",
"name": "Bruno Bigras",
"avatar_url": "https://avatars1.githubusercontent.com/u/24027?v=4",
"profile": "https://github.com/bbigras",
"contributions": [
"code",
"review"
]
},
{
"login": "wyze",
"name": "Neil Kistner",
"avatar_url": "https://avatars1.githubusercontent.com/u/186971?v=4",
"profile": "https://neilkistner.com/",
"contributions": [
"code",
"test",
"review"
]
},
{
"login": "qstrahl",
"name": "Quinn Strahl",
"avatar_url": "https://avatars3.githubusercontent.com/u/2235277?v=4",
"profile": "http://ca.linkedin.com/in/qstrahl",
"contributions": [
"code",
"test"
]
},
{
"login": "tivervac",
"name": "Titouan Vervack",
"avatar_url": "https://avatars2.githubusercontent.com/u/3389524?v=4",
"profile": "https://github.com/tivervac",
"contributions": [
"code",
"test"
]
},
{
"login": "oblitum",
"name": "Francisco Lopes",
"avatar_url": "https://avatars1.githubusercontent.com/u/1269815?v=4",
"profile": "http://nosubstance.me",
"contributions": [
"code"
]
},
{
"login": "ahouts",
"name": "Andrew Houts",
"avatar_url": "https://avatars1.githubusercontent.com/u/16907671?v=4",
"profile": "https://github.com/ahouts",
"contributions": [
"code",
"doc",
"test"
]
},
{
"login": "nickwb",
"name": "Nick Young",
"avatar_url": "https://avatars2.githubusercontent.com/u/594211?v=4",
"profile": "https://github.com/nickwb",
"contributions": [
"code",
"doc",
"test",
"review"
]
},
{
"login": "g2p",
"name": "Gabriel de Perthuis",
"avatar_url": "https://avatars1.githubusercontent.com/u/61678?v=4",
"profile": "https://github.com/g2p",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7
+6 -2
View File
@@ -1,6 +1,10 @@
---
name: 🐛 Bug Report
about: If something isn't working as expected 🤔.
name: "\U0001F41B Bug Report"
about: "If something isn't working as expected \U0001F914."
title: ''
labels: "\U0001F41B bug"
assignees: ''
---
## Bug Report
+6 -3
View File
@@ -1,10 +1,13 @@
---
name: 🚀 Feature Request
about: I have a suggestion (and may want to implement it 🙂)!
name: "\U0001F680 Feature Request"
about: "I have a suggestion (and may want to implement it \U0001F642)!"
title: ''
labels: "✨ enhancement"
assignees: ''
---
## Feature Request
<!-- Please keep in mind that we are in the beginning phases of Starship and it may take some time to implement features until we have our base set up. -->
#### Is your feature request related to a problem? Please describe.
<!-- A clear and concise description of what the problem is. Ex. I have an issue when [...] -->
+2
View File
@@ -1,4 +1,6 @@
<!--- Provide a general summary of your changes in the Title above -->
<!--- To help with semantic versioning the PR title should start with one of the conventional commit types. -->
<!--- The conventional commit types for Semantic PR are: feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert -->
#### Description
<!--- Describe your changes in detail -->
@@ -0,0 +1,93 @@
name: Continuous Integration
on: [push, pull_request]
jobs:
# Run the `rustfmt` code formatter
rustfmt:
name: Rustfmt [Formatter]
runs-on: ubuntu-latest
steps:
- uses: hecrj/setup-rust-action@master
- uses: actions/checkout@master
- name: Install rustfmt
run: rustup component add rustfmt
- name: Run rustfmt
run: cargo fmt --all -- --check
# Run the `clippy` linting tool
clippy:
name: Clippy [Linter]
runs-on: ubuntu-latest
steps:
- uses: hecrj/setup-rust-action@master
- uses: actions/checkout@master
- name: Install clippy
run: rustup component add clippy
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D clippy::all
# Ensure that the project could be successfully compiled
cargo_check:
name: Compile
runs-on: ubuntu-latest
steps:
- uses: hecrj/setup-rust-action@master
- uses: actions/checkout@master
- run: cargo check --all
# Run tests on Linux, and macOS
# On both Rust stable and Rust nightly
test:
name: Test Suite
needs: [rustfmt, clippy, cargo_check]
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macOS-latest]
rust: [stable, nightly]
steps:
# Install all the required dependencies for testing
- uses: hecrj/setup-rust-action@master
with:
rust-version: ${{ matrix.rust }}
# Install Node.js at a fixed version
- uses: actions/setup-node@master
with:
node-version: "12.0.0"
# Install Golang at a fixed version
- uses: actions/setup-go@master
with:
go-version: "1.12.1"
# Install Ruby at a fixed version
- uses: actions/setup-ruby@master
with:
ruby-version: "2.6.3"
# Install Python at a fixed version
- uses: actions/setup-python@master
with:
python-version: "3.6.9"
# Run the ignored tests that expect the above setup
- uses: actions/checkout@master
- name: Run all tests
run: cargo test -- -Z unstable-options --include-ignored
# Run the tests in the Docker image
docker_test:
name: Test in Docker
needs: [rustfmt, clippy, cargo_check]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Pull the pre-built Docker image
run: docker pull starshipcommand/starship-test
- name: Fix file permissions
run: chmod -R a+w .
- name: Build the Docker image
run: docker build -f tests/Dockerfile --tag starshipcommand/starship-test --cache-from starshipcommand/starship-test .
- name: Run tests in Docker
run: docker run --rm -v $(pwd):/src/starship starshipcommand/starship-test
+1
View File
@@ -13,6 +13,7 @@ Cargo.lock
# Intellij IDE configuration
.idea/
/*.iml
# Compiled files for documentation
docs/node_modules
+2
View File
@@ -70,6 +70,8 @@ Unit tests are written using the built-in Rust testing library in the same file
Unit tests should be fully isolated, only testing a given function's expected output given a specific input, and should be reproducible on any machine. Unit tests should not expect the computer running them to be in any particular state. This includes having any applications pre-installed, having any environment variables set, etc.
The previous point should be emphasized: even seemingly innocuous ideas like "if we can see the directory, we can read it" or "nobody will have their home directory be a git repo" have bitten us in the past. Having even a single test fail can completely break installation on some platforms, so be careful with tests!
### Acceptance Testing
Acceptance tests are located in the [`tests/`](tests) directory and are also written using the built-in Rust testing library.
Generated
+105 -60
View File
@@ -18,7 +18,7 @@ dependencies = [
[[package]]
name = "ansi_term"
version = "0.12.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -96,7 +96,7 @@ dependencies = [
[[package]]
name = "bitflags"
version = "1.0.4"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -113,7 +113,7 @@ name = "c2-chacha"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -144,7 +144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -156,7 +156,7 @@ name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -180,24 +180,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "crossbeam-deque"
version = "0.6.3"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "crossbeam-epoch"
version = "0.7.1"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -214,7 +214,7 @@ version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -244,7 +244,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "env_logger"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -279,23 +279,32 @@ name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "gethostname"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "getrandom"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "git2"
version = "0.9.2"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
"libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libgit2-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-sys 0.9.46 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -327,10 +336,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "lazy_static"
version = "1.3.0"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -345,7 +354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libgit2-sys"
version = "0.8.2"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -408,15 +417,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "memoffset"
version = "0.2.1"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "nix"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -493,11 +505,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "pretty_env_logger"
version = "0.3.0"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -588,23 +600,23 @@ dependencies = [
[[package]]
name = "rayon"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon-core"
version = "1.5.0"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -673,6 +685,14 @@ name = "rustc-demangle"
version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "1.0.0"
@@ -685,12 +705,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "scopeguard"
version = "0.3.3"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.91"
version = "1.0.98"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -700,7 +733,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -710,26 +743,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "spin"
version = "0.5.0"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "starship"
version = "0.8.2"
version = "0.16.0"
dependencies = [
"ansi_term 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
"battery 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gethostname 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"git2 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"path-slash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -803,7 +838,7 @@ name = "thread_local"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -818,10 +853,10 @@ dependencies = [
[[package]]
name = "toml"
version = "0.5.1"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -850,6 +885,11 @@ dependencies = [
"smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "unicode-segmentation"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-width"
version = "0.1.5"
@@ -938,7 +978,7 @@ dependencies = [
[metadata]
"checksum aho-corasick 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e6f484ae0c99fec2e858eb6134949117399f222608d84cadb3f58c1f97c2364c"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum ansi_term 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "eaa72766c3585a1f812a3387a7e2c6cab780f899c2f43ff6ea06c8d071fcbb36"
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
"checksum argon2rs 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f67b0b6a86dae6e67ff4ca2b6201396074996379fba2b92ff649126f37cb392"
"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71"
"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
@@ -946,7 +986,7 @@ dependencies = [
"checksum backtrace 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f106c02a3604afcdc0df5d36cc47b44b55917dbaf3d808f71c163a0ddba64637"
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
"checksum battery 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6d6fe5630049e900227cd89afce4c1204b88ec8e61a2581bb96fcce26f047b"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
"checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
"checksum cc 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a0c56216487bb80eec9c4516337b2588a4f2a2290d72a1416d930e4dcdb0c90d"
@@ -957,33 +997,34 @@ dependencies = [
"checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e"
"checksum core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d"
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4"
"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c"
"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
"checksum env_logger 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b61fa891024a945da30a9581546e8cfaf5602c7b3f4c137a2805cf388f92075a"
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
"checksum gethostname 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4ab273ca2a31eb6ca40b15837ccf1aa59a43c5db69ac10c542be342fae2e01d"
"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55"
"checksum git2 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cb400360e8a4d61b10e648285bbfa919bbf9519d0d5d5720354456f44349226"
"checksum git2 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "327d698f86a7ebdfeb86a4238ccdb004828939d3a3555b6ead679541d14e36c0"
"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319"
"checksum libgit2-sys 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4c179ed6d19cd3a051e68c177fbbc214e79ac4724fac3a850ec9f3d3eb8a5578"
"checksum libgit2-sys 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c2078aec6f4b16d1b89f6a72e4f6eb1e75ffa85312023291e89c6d3087bc8fb"
"checksum libssh2-sys 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "126a1f4078368b163bfdee65fbab072af08a1b374a5551b21e87ade27b1fbf9d"
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
"checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39"
"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
"checksum nix 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d10caafde29a846a82ae0af70414e4643e072993441033b2c93217957e2f867"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
@@ -996,7 +1037,7 @@ dependencies = [
"checksum percent-encoding 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba4f28a6faf4ffea762ba8f4baef48c61a6db348647c73095034041fc79dd954"
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61"
"checksum pretty_env_logger 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "717ee476b1690853d222af4634056d830b5197ffd747726a9a1eee6da9f49074"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db"
@@ -1007,8 +1048,8 @@ dependencies = [
"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca"
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4"
"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2"
"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123"
"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
@@ -1017,13 +1058,16 @@ dependencies = [
"checksum regex-syntax 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dcfd8681eebe297b81d98498869d4aae052137651ad7b96822f09ceb690d0a96"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
"checksum serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)" = "a72e9b96fa45ce22a4bc23da3858dfccfd60acd28a25bcd328a98fdd6bea43fd"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113"
"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
"checksum syn 0.15.34 (registry+https://github.com/rust-lang/crates.io-index)" = "a1393e4a97a19c01e900df2aec855a29f71cf02c402e2f443b8d2747c25c5dbe"
"checksum synstructure 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "73687139bf99285483c96ac0add482c3776528beac1d97d444f6e91f203a2015"
@@ -1033,11 +1077,12 @@ dependencies = [
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
"checksum toml 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b8c96d7873fa7ef8bdeb3a9cda3ac48389b4154f32b9803b4bc26220b677b039"
"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum uom 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "347fe3ff20637a62ab9749a5c90d167302bcbdab77ec961dda7f62a5ca6d368a"
+17 -9
View File
@@ -1,10 +1,11 @@
[package]
name = "starship"
version = "0.8.2"
version = "0.16.0"
edition = "2018"
authors = ["Matan Kushner <hello@matchai.me>"]
repository = "https://github.com/starship/starship"
homepage = "https://starship.rs"
documentation = "https://starship.rs/guide/"
repository = "https://github.com/starship/starship"
readme = "README.md"
license = "ISC"
keywords = ["prompt", "shell", "bash", "fish", "zsh"]
@@ -20,19 +21,26 @@ is-it-maintained-issue-resolution = { repository = "starship/starship" }
is-it-maintained-open-issues = { repository = "starship/starship" }
maintenance = { status = "actively-developed" }
[features]
default = ["battery"]
[dependencies]
clap = "2.33.0"
ansi_term = "0.12.0"
ansi_term = "0.12.1"
dirs = "2.0.2"
git2 = "0.9.2"
toml = "0.5.1"
git2 = "0.10.0"
toml = "0.5.3"
serde_json = "1.0.40"
rayon = "1.1.0"
pretty_env_logger = "0.3.0"
rayon = "1.2.0"
pretty_env_logger = "0.3.1"
log = "0.4.8"
battery = "0.7.4"
lazy_static = "1.3.0"
# battery is optional (on by default) because the crate doesn't currently build for Termux
# see: https://github.com/svartalf/rust-battery/issues/33
battery = { version = "0.7.4", optional = true }
lazy_static = "1.4.0"
path-slash = "0.1.1"
unicode-segmentation = "1.3.0"
gethostname = "0.2.0"
[dev-dependencies]
tempfile = "3.1.0"
+126 -33
View File
@@ -1,39 +1,75 @@
<p align="center">
<br>
<img width="400" src="https://raw.githubusercontent.com/starship/starship/master/media/logo.png" alt="Starship Cross-shell prompt">
<p align="center">
<a href="https://crates.io/crates/starship"><img src="https://badgen.net/crates/v/starship" alt="Crates.io version"></a>
<a href="https://dev.azure.com/starship-control/starship/_build"><img src="https://badgen.net/azure-pipelines/starship-control/starship/Starship%20Test%20Suite" alt="Azure Pipelines Build Status"></a>
<a href="#contributors"><img src="https://badgen.net/badge/all%20contributors/10/orange" alt="All Contributors"></a>
<a href="https://discord.gg/8Jzqu3T"><img src="https://badgen.net/badge/chat/on%20discord/7289da" alt="Chat on Discord"></a>
</p>
<br />
<img
width="400"
src="https://raw.githubusercontent.com/starship/starship/master/media/logo.png"
alt="Starship Cross-shell prompt"
/>
</p>
<p align="center">
<a href="https://crates.io/crates/starship">
<img src="https://badgen.net/crates/v/starship" alt="Crates.io version" />
</a>
<a href="https://dev.azure.com/starship-control/starship/_build">
<img
src="https://badgen.net/azure-pipelines/starship-control/starship/Starship%20Test%20Suite"
alt="Azure Pipelines Build Status"
/>
</a>
<a href="https://repology.org/project/starship/versions">
<img src="https://repology.org/badge/tiny-repos/starship.svg" alt="Packaging status">
</a><br>
<a href="#contributors">
<img
src="https://badgen.net/badge/all%20contributors/20/orange"
alt="All Contributors"
/>
</a>
<a href="https://discord.gg/8Jzqu3T">
<img
src="https://badgen.net/badge/chat/on%20discord/7289da"
alt="Chat on Discord"
/>
</a>
</p>
<h4 align="center">
<br>
<a href="https://starship.rs">Website</a> ·
<a href="#-installation">Installation</a> ·
<a href="https://starship.rs/config/">Configuration</a>
<br />
<a href="https://starship.rs">Website</a>
·
<a href="#-installation">Installation</a>
·
<a href="https://starship.rs/config/">Configuration</a>
</h4>
<h1></h1>
<p align="center">
Starship is the minimal, blazing fast, and extremely customizable prompt for any shell!<br>
The prompt shows information you need while you're working, while staying sleek and out of the way.
<p>
<p align="center">
<img alt="Starship with Hyper and One Dark" src="https://raw.githubusercontent.com/starship/starship/master/media/demo.gif">
<br>
<img alt="Starship with iTerm2 and the Snazzy theme" src="https://raw.githubusercontent.com/starship/starship/master/media/demo.gif" width="80%">
<br>
<br>
</p>
## 🍬 Features
- Prompt character turns red if the last command exits with non-zero code.
- Current username if not the same as the logged-in user.
- Current Node.js version(`⬢`).
- Current Rust version (`🦀`).
- Current Python version (`🐍`).
- Current Go version (`🐹`).
- Package version of package in current directory (`📦`).
- Current battery level and status.
- Prompt character turns red if the last command exits with non-zero code
- Current username if not the same as the logged-in user
- Current Node.js version(`⬢`)
- Current Rust version (`🦀`)
- Current Ruby version (`💎`)
- Current Python version (`🐍`)
- Current Go version (`🐹`)
- Nix-shell environment detection
- Current version of package in current directory (`📦`)
- npm (Node.js)
- cargo (Rust)
- poetry (Python)
- Current battery level and status
- Current Git branch and rich repo status:
- `=` — conflicting changes
- `⇡` — ahead of remote branch
@@ -45,8 +81,8 @@ The prompt shows information you need while you're working, while staying sleek
- `+` — added files
- `»` — renamed files
- `✘` — deleted files
- Execution time of the last command if it exceeds the set threshold.
- Indicator for jobs in the background (`✦`).
- Execution time of the last command if it exceeds the set threshold
- Indicator for jobs in the background (`✦`)
## 🚀 Installation
@@ -67,21 +103,41 @@ The prompt shows information you need while you're working, while staying sleek
```
#### Rust (v1.33 or higher)
```sh
$ cargo install starship
```
1. Add the init script to your shell's config file:
#### Arch Linux (AUR)
#### Bash / Zsh
Add the following to the end of `~/.bashrc` or `~/.zshrc`:
Starship is available on the AUR under the name `starship`. Install it with `yay` or your favorite AUR helper.
```sh
# ~/.bashrc or ~/.zshrc
$ yay -S starship
```
eval "$(starship init $0)"
#### Nix (unstable)
```sh
$ nix-env --install starship
```
#### Termux
```sh
$ pkg install starship
```
1. Add the init script to your shell's config file:
#### Bash
Add the following to the end of `~/.bashrc`:
```sh
# ~/.bashrc
eval "$(starship init bash)"
```
#### Fish
@@ -94,13 +150,23 @@ The prompt shows information you need while you're working, while staying sleek
eval (starship init fish)
```
#### Zsh
Add the following to the end of `~/.zshrc`:
```sh
# ~/.zshrc
eval "$(starship init zsh)"
```
## 🔧 Configuration
For details on how to configure Starship, check out our [documentation](https://starship.rs/config/).
## 🤝 Contributing
We are always looking for contributors of **all skill levels**! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/starship/starship/labels/good%20first%20issue).
We are always looking for contributors of **all skill levels**! If you're looking to ease your way into the project, try out a [good first issue](https://github.com/starship/starship/labels/🌱%20good%20first%20issue).
### High Priority Needs
@@ -111,7 +177,7 @@ We are always looking for contributors of **all skill levels**! If you're lookin
- 👩‍💻 **Rust Developer**
- There is _a lot_ of low-hanging fruit when it comes to writing idiomatic Rust, designing effective Rust architecture, performance optimizations, cross-platform build optimizations, and more! I ([@matchai](https://github.com/matchai)) am a beginner to Rust. Come point us in the right direction!
If you are interested in helping contribute to starship, please take a look at our [Contributing Guide](./CONTRIBUTING.md). Also, feel free to drop into our [Discord server](https://discord.gg/8Jzqu3T) and say hi. 👋
If you are interested in helping contribute to starship, please take a look at our [Contributing Guide](https://github.com/starship/starship/blob/master/CONTRIBUTING.md). Also, feel free to drop into our [Discord server](https://discord.gg/8Jzqu3T) and say hi. 👋
### Contributors
@@ -133,6 +199,23 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center"><a href="https://github.com/chipbuster"><img src="https://avatars2.githubusercontent.com/u/4605384?v=4" width="100px;" alt="Kevin Song"/><br /><sub><b>Kevin Song</b></sub></a><br /><a href="https://github.com/starship/starship/issues?q=author%3Achipbuster" title="Bug reports">🐛</a> <a href="https://github.com/starship/starship/commits?author=chipbuster" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=chipbuster" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=chipbuster" title="Tests">⚠️</a></td>
<td align="center"><a href="https://andrewda.me"><img src="https://avatars1.githubusercontent.com/u/10191084?v=4" width="100px;" alt="Andrew Dassonville"/><br /><sub><b>Andrew Dassonville</b></sub></a><br /><a href="https://github.com/starship/starship/issues?q=author%3Aandrewda" title="Bug reports">🐛</a> <a href="https://github.com/starship/starship/commits?author=andrewda" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/MaT1g3R"><img src="https://avatars1.githubusercontent.com/u/15258494?v=4" width="100px;" alt="MaT1g3R"/><br /><sub><b>MaT1g3R</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=MaT1g3R" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=MaT1g3R" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=MaT1g3R" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/AZanellato"><img src="https://avatars3.githubusercontent.com/u/30451287?v=4" width="100px;" alt="André Zanellato"/><br /><sub><b>André Zanellato</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=AZanellato" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=AZanellato" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=AZanellato" title="Tests">⚠️</a></td>
<td align="center"><a href="https://saghm.com"><img src="https://avatars2.githubusercontent.com/u/5875560?v=4" width="100px;" alt="Saghm Rossi"/><br /><sub><b>Saghm Rossi</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=saghm" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=saghm" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=saghm" title="Tests">⚠️</a></td>
<td align="center"><a href="https://medium.com/@cappyzawa"><img src="https://avatars3.githubusercontent.com/u/12455284?v=4" width="100px;" alt="Shu Kutsuzawa"/><br /><sub><b>Shu Kutsuzawa</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=cappyzawa" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=cappyzawa" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=cappyzawa" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/iamsauravsharma"><img src="https://avatars0.githubusercontent.com/u/38726015?v=4" width="100px;" alt="Saurav Sharma"/><br /><sub><b>Saurav Sharma</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=iamsauravsharma" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=iamsauravsharma" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/andytom"><img src="https://avatars1.githubusercontent.com/u/108836?v=4" width="100px;" alt="Thomas O'Donnell"/><br /><sub><b>Thomas O'Donnell</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=andytom" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=andytom" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/bbigras"><img src="https://avatars1.githubusercontent.com/u/24027?v=4" width="100px;" alt="Bruno Bigras"/><br /><sub><b>Bruno Bigras</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=bbigras" title="Code">💻</a> <a href="#review-bbigras" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://neilkistner.com/"><img src="https://avatars1.githubusercontent.com/u/186971?v=4" width="100px;" alt="Neil Kistner"/><br /><sub><b>Neil Kistner</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=wyze" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=wyze" title="Tests">⚠️</a> <a href="#review-wyze" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="http://ca.linkedin.com/in/qstrahl"><img src="https://avatars3.githubusercontent.com/u/2235277?v=4" width="100px;" alt="Quinn Strahl"/><br /><sub><b>Quinn Strahl</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=qstrahl" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=qstrahl" title="Tests">⚠️</a></td>
<td align="center"><a href="https://github.com/tivervac"><img src="https://avatars2.githubusercontent.com/u/3389524?v=4" width="100px;" alt="Titouan Vervack"/><br /><sub><b>Titouan Vervack</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=tivervac" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=tivervac" title="Tests">⚠️</a></td>
<td align="center"><a href="http://nosubstance.me"><img src="https://avatars1.githubusercontent.com/u/1269815?v=4" width="100px;" alt="Francisco Lopes"/><br /><sub><b>Francisco Lopes</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=oblitum" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/ahouts"><img src="https://avatars1.githubusercontent.com/u/16907671?v=4" width="100px;" alt="Andrew Houts"/><br /><sub><b>Andrew Houts</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=ahouts" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=ahouts" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=ahouts" title="Tests">⚠️</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/nickwb"><img src="https://avatars2.githubusercontent.com/u/594211?v=4" width="100px;" alt="Nick Young"/><br /><sub><b>Nick Young</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=nickwb" title="Code">💻</a> <a href="https://github.com/starship/starship/commits?author=nickwb" title="Documentation">📖</a> <a href="https://github.com/starship/starship/commits?author=nickwb" title="Tests">⚠️</a> <a href="#review-nickwb" title="Reviewed Pull Requests">👀</a></td>
<td align="center"><a href="https://github.com/g2p"><img src="https://avatars1.githubusercontent.com/u/61678?v=4" width="100px;" alt="Gabriel de Perthuis"/><br /><sub><b>Gabriel de Perthuis</b></sub></a><br /><a href="https://github.com/starship/starship/commits?author=g2p" title="Code">💻</a></td>
</tr>
</table>
@@ -140,6 +223,16 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
## 💭 Inspired By
Please check out these previous works that helped inspire the creation of starship. 🙏
- **[denysdovhan/spaceship-prompt](https://github.com/denysdovhan/spaceship-prompt)** - A ZSH prompt for astronauts.
- **[denysdovhan/robbyrussell-node](https://github.com/denysdovhan/robbyrussell-node)** - Cross-shell robbyrussell theme written in JavaScript.
- **[reujab/silver](https://github.com/reujab/silver)** - A cross-shell customizable powerline-like prompt with icons.
<p align="center">
<br>
<img width="100" src="media/icon.png" alt="Starship rocket icon">
@@ -148,4 +241,4 @@ This project follows the [all-contributors](https://github.com/all-contributors/
## 📝 License
Copyright © 2019-present, [Starship Contributors](https://github.com/starship/starship/graphs/contributors).<br>
This project is [ISC](./LICENSE) licensed.
This project is [ISC](https://github.com/starship/starship/blob/master/LICENSE) licensed.
+2 -56
View File
@@ -1,59 +1,10 @@
trigger:
branches:
include: ["*"]
tags:
include: ["*"]
stages:
- stage: Checks
jobs:
# Check formatting
- template: ci/rustfmt.yml
parameters:
name: rustfmt
displayName: Check formatting
# Run linter
- template: ci/cargo-clippy.yml
parameters:
name: cargo_clippy
displayName: Run linter
# Cargo check
- template: ci/cargo-check.yml
parameters:
name: cargo_check
displayName: Cargo check
- stage: Test
dependsOn: Checks
jobs:
# Test stable
- template: ci/test.yml
parameters:
name: cargo_test_stable
displayName: Cargo test
cross: true # Test on Windows and macOS
# Test nightly
- template: ci/test.yml
parameters:
name: cargo_test_nightly
displayName: Cargo test
rust_version: nightly
# Test docker
# Runs integration tests as a starship developer would run them locally
- template: ci/test-docker.yml
parameters:
name: test_docker
displayName: Docker test
- stage: Release
dependsOn:
- Checks
- Test
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags/v')
jobs:
# Release binary on GitHub
- template: ci/github-release.yml
@@ -67,6 +18,7 @@ stages:
!.*
targets:
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
# Windows support temporarily disabled
# - x86_64-pc-windows-gnu
# - x86_64-pc-windows-msvc
@@ -81,9 +33,3 @@ stages:
parameters:
name: cargo_publish
displayName: Publish to Crates.io
# Open a PR on Homebrew/homebrew-core with an update to the starship formula
- template: ci/bump-brew-formula.yml
parameters:
name: bump_brew_formula
displayName: Bump the Homebrew formula
-15
View File
@@ -1,15 +0,0 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: macOS-10.13
steps:
- script: |
GIT_TAG="$(Build.SourceBranch)"
git config --global user.name "matchai"
git config --global user.email "hello@matchai.me"
git config --global config.helper store
echo "https://matchai:${HOMEBREW_GITHUB_API_TOKEN}@github.com" >> ~/.git-credentials
brew update
brew bump-formula-pr --url=https://github.com/starship/starship/archive/${GIT_TAG}.tar.gz --message="Automated release pull request using continuous integration." --no-browse -v starship
displayName: Bump the Homebrew formula
-13
View File
@@ -1,13 +0,0 @@
parameters:
rust_version: stable
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: ubuntu-16.04
steps:
- template: install-rust.yml
- script: cargo check
displayName: Check features
-13
View File
@@ -1,13 +0,0 @@
parameters:
rust_version: stable
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: ubuntu-16.04
steps:
- template: install-rust.yml
- script: cargo clippy -- -D clippy::all
displayName: Run clippy
-4
View File
@@ -32,10 +32,6 @@ steps:
git config --global user.name "I merge the things"
git clone https://github.com/rust-embedded/cross
cd cross
git remote add pitkley https://github.com/pitkley/cross
git fetch pitkley
git checkout 718a19c
git merge -m "No pseudo tty" pitkley/docker-no-pseudo-tty
cargo install --force --path .
displayName: Install cross
# All platforms
-16
View File
@@ -1,16 +0,0 @@
jobs:
# Check formatting
- job: ${{ parameters.name }}
displayName: Check rustfmt
pool:
vmImage: ubuntu-16.04
steps:
- template: install-rust.yml
parameters:
rust_version: stable
- script: |
rustup component add rustfmt
displayName: Install rustfmt
- script: |
cargo fmt --all -- --check
displayName: Check formatting
-25
View File
@@ -1,25 +0,0 @@
steps:
# Install Node.js
- task: NodeTool@0
inputs:
versionSpec: "12.0.0"
displayName: "Install a fixed version of Node"
# Install Go
- task: GoTool@0
inputs:
versionSpec: "1.10"
displayName: "Install a fixed version of Go"
# We are using pyenv to install Python for integration tests
# Install Python
- script: |
echo "##vso[task.setvariable variable=PYTHON_VERSION;]3.6.9"
echo "##vso[task.setvariable variable=PYENV_ROOT;]$HOME/.pyenv"
- script: |
curl https://pyenv.run | bash
echo "##vso[task.setvariable variable=PATH;]$PYENV_ROOT/bin:$PYENV_ROOT/shims:$PATH"
- script: |
eval "$(pyenv init -)"
pyenv install $PYTHON_VERSION
pyenv global $PYTHON_VERSION
displayName: "Install a fixed version of Python"
-23
View File
@@ -1,23 +0,0 @@
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
pool:
vmImage: ubuntu-16.04
steps:
- script: docker pull starshipcommand/starship-test
displayName: Pull docker image
- script: |
# In order to run tests as a non-root user in docker,
# the files need to be accessible to non-root users
chmod -R a+w .
./integration_test
displayName: Run integration test suite
- script: |
docker login -u $(dockerUsername) -p $(dockerPassword)
docker push starshipcommand/starship-test
# Only push new image if on master and build is passing
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
displayName: Push image to dockerhub
-28
View File
@@ -1,28 +0,0 @@
parameters:
rust_version: stable
jobs:
- job: ${{ parameters.name }}
displayName: ${{ parameters.displayName }} ${{parameters.rust_version}}
strategy:
matrix:
Linux:
vmImage: ubuntu-16.04
${{ if parameters.cross }}:
MacOS:
vmImage: macOS-10.13
# Temporarily disable Windows support
# Windows:
# vmImage: vs2017-win2016
pool:
vmImage: $(vmImage)
steps:
- template: install-rust.yml
- template: setup-test-env.yml
- script: |
cargo test -- -Z unstable-options --include-ignored
env:
CI: "true"
displayName: cargo test
+11 -2
View File
@@ -9,7 +9,8 @@ module.exports = {
sidebar: [
'/',
['/guide/', 'Guide'],
['/config/', 'Configuration']
['/config/', 'Configuration'],
['/advanced-config/', 'Advanced Configuration']
],
nav: [
{ text: 'Configuration', link: '/config/' },
@@ -24,5 +25,13 @@ module.exports = {
editLinks: true,
// custom text for edit link. Defaults to "Edit this page"
editLinkText: 'Edit this page on GitHub'
}
},
plugins: [
[
'@vuepress/google-analytics',
{
'ga': 'UA-71160903-4'
}
]
]
}
Binary file not shown.
Binary file not shown.
+8 -1
View File
@@ -8,8 +8,15 @@ $codeBgColor = #282c34
min-width: 300px
width: 100%
.center
margin 0 auto;
width: 80%
.demo-video
width: 100%
margin: 50px 0
#main-title
display: none
.hero
margin: 150px 25px
margin: 150px 25px 70px
+63 -16
View File
@@ -21,32 +21,79 @@ footer: ISC Licensed | Copyright © 2019-present Starship Contributors
</div>
</div>
<div class="center">
<video class="demo-video" autoplay muted loop>
<source src="/demo.webm" type="video/webm">
<source src="/demo.mp4" type="video/mp4">
</video>
</div>
### Quick Install
1. Install the **starship** binary:
```bash
cargo install starship
```
**[Download archives of precompiled binaries](https://github.com/starship/starship/releases)** if you don't use the platforms below.
#### Homebrew
```sh
$ brew install starship
```
#### Rust (v1.33 or higher)
```sh
$ cargo install starship
```
#### Arch Linux (AUR)
Starship is available on the AUR under the name `starship`. Install it with `yay` or your favorite AUR helper.
```sh
$ yay -S starship
```
#### Nix (unstable)
```sh
$ nix-env --install starship
```
#### Termux
```sh
$ pkg install starship
```
1. Add the init script to your shell's config file:
#### Bash / Zsh
#### Bash
Add the following to the end of `~/.bashrc` or `~/.zshrc`:
Add the following to the end of `~/.bashrc`:
```bash
# ~/.bashrc or ~/.zshrc
eval "$(starship init $0)"
```
```sh
# ~/.bashrc
#### Fish
eval "$(starship init bash)"
```
Add the following to the end of `~/.config/fish/config.fish`:
#### Fish
```sh
# ~/.config/fish/config.fish
Add the following to the end of `~/.config/fish/config.fish`:
eval (starship init fish)
```
```sh
# ~/.config/fish/config.fish
eval (starship init fish)
```
#### Zsh
Add the following to the end of `~/.zshrc`:
```sh
# ~/.zshrc
eval "$(starship init zsh)"
```
+101
View File
@@ -0,0 +1,101 @@
# Advanced Configuration
While Starship is a versatile shell, sometimes you need to do more than edit
`starship.toml` to get it to do certain things. This page details some of the more
advanced configuration techniques used in starship.
::: warning
The configurations in this section are subject to change in future releases of Starship.
:::
## Custom pre-prompt and pre-execution Commands in Bash
Bash does not have a formal preexec/precmd framework like most other shells.
Because of this, it is difficult to provide fully customizable hooks in `bash`.
However, Starship does give you limited ability to insert your own functions
into the prompt-rendering procedure:
- To run a custom function right before the prompt is drawn, define a new
function and then assign its name to `starship_precmd_user_func`. For example,
to draw a rocket before the prompt, you would do
```bash
function blastoff(){
echo "🚀"
}
starship_precmd_user_func="blastoff"
```
- To run a custom function right before a command runs, you can use the
[`DEBUG` trap mechanism](https://jichu4n.com/posts/debug-trap-and-prompt_command-in-bash/).
However, you **must** trap the DEBUG signal *before* initializing Starship!
Starship can preserve the value of the DEBUG trap, but if the trap is overwritten
after starship starts up, some functionality will break.
```bash
function blastoff(){
echo "🚀"
}
trap blastoff DEBUG # Trap DEBUG *before* running starship
eval $(starship init bash)
```
## Change Window Title
Some shell prompts will automatically change the window title for you (e.g. to
reflect your working directory). Fish even does it by default.
Starship does not do this, but it's fairly straightforward to add this
functionality to `bash` or `zsh`.
First, define a window title change function (identical in bash and zsh):
```bash
function set_win_title(){
echo -ne "\033]0; YOUR_WINDOW_TITLE_HERE \007"
}
```
You can use variables to customize this title (`$USER`, `$HOSTNAME`, and `$PWD`
are popular choices).
In `bash`, set this function to be the precmd starship function:
```bash
starship_precmd_user_func="set_win_title"
```
In `zsh`, add this to the `precmd_functions` array:
```bash
precmd_functions+=(set_win_title)
```
If you like the result, add these lines to your shell configuration file
(`~/.bashrc` or `~/.zsrhc`) to make it permanent.
## Style Strings
Style strings are a list of words, separated by whitespace. The words are not case sensitive (i.e. `bold` and `BoLd` are considered the same string). Each word can be one of the following:
- `bold`
- `underline`
- `dimmed`
- `bg:<color>`
- `fg:<color>`
- `<color>`
- `none`
where `<color>` is a color specifier (discussed below). `fg:<color>` and `<color>` currently do the same thing , though this may change in the future. The order of words in the string does not matter.
The `none` token overrides all other tokens in a string, so that e.g. `fg:red none fg:blue` will still create a string with no styling. It may become an error to use `none` in conjunction with other tokens in the future.
A color specifier can be one of the following:
- One of the standard terminal colors: `black`, `red`, `green`, `blue`,
`yellow`, `purple`, `cyan`, `white`. You can optionally prefix these
with `bright-` to get the bright version (e.g. `bright-white`).
- A `#` followed by a six-digit hexadecimal number. This specifies an
[RGB color hex code](https://www.w3schools.com/colors/colors_hexadecimal.asp).
- A number between 0-255. This specifies an [8-bit ANSI Color Code](https://i.stack.imgur.com/KTSQa.png).
If multiple colors are specified for foreground/background, the last one in the string will take priority.
+278 -83
View File
@@ -17,9 +17,9 @@ All configuration for starship is done in this [TOML](https://github.com/toml-la
# Don't print a new line at the start of the prompt
add_newline = false
# Replace the "" symbol in the prompt with ""
# Replace the "" symbol in the prompt with ""
[character] # The name of the module we are confguring is "character"
symbol = "" # The "symbol" segment is being set to ""
symbol = "" # The "symbol" segment is being set to ""
# Disable the package module, hiding it from the prompt completely
[package]
@@ -40,15 +40,28 @@ are segments within it. Every module also has a prefix and suffix that are the d
"via " "⬢" "v10.4.1" ""
```
### Style Strings
Most modules in starship allow you to configure their display styles. This is done with an entry (usually called `style`) which is a string specifying the configuration. Here are some examples of style strings along with what they do. For details on the full syntax, consult the [advanced config guide](/advanced-config/).
- `"fg:green bg:blue"` sets green text on a blue background
- `"bg:blue fg:bright-green"` sets bright green text on a blue background
- `"bold fg:27"` sets bold text with [ANSI color](https://i.stack.imgur.com/KTSQa.png) 27
- `"underline bg:#bf5700"` sets underlined text on a burnt orange background
- `""` explicitly disables all styling
Note that what styling looks like will be controlled by your terminal emulator. For example, some terminal emulators will brighten the colors instead of bolding text, and some color themes use the same values for the normal and bright colors.
## Prompt
This is the list of prompt-wide configuration options.
### Options
| Variable | Default | Description |
| ------------- | ------- | ---------------------------------------------- |
| `add_newline` | `true` | Add a new line before the start of the prompt. |
| Variable | Default | Description |
| -------------- | ----------------------------- | ------------------------------------------------------ |
| `add_newline` | `true` | Add a new line before the start of the prompt. |
| `prompt_order` | [link](#default-prompt-order) | Configure the order in which the prompt module occurs. |
### Example
@@ -57,6 +70,35 @@ This is the list of prompt-wide configuration options.
# Disable the newline at the start of the prompt
add_newline = false
# Overwrite a default_prompt_order and use custom prompt_order
prompt_order=["rust","line_break","package","line_break","character"]
```
### Default prompt order
The `default_prompt_order` configuration option is used to define the order in which modules are shown in the prompt, if empty or no `prompt_order` is provided. The default is as shown:
```
default_prompt_order = [
"username",
"hostname",
"directory",
"git_branch",
"git_state",
"git_status",
"package",
"nodejs",
"ruby",
"rust",
"python",
"golang",
"nix_shell",
"cmd_duration",
"line_break",
"jobs",
"battery",
"character",
]
```
## Battery
@@ -66,12 +108,13 @@ The module is only visible when the device's battery is below 10%.
### Options
| Variable | Default | Description |
| -------------------- | ------- | ------------------------------------------------- |
| `full_symbol` | `"•"` | The symbol shown when the battery is full. |
| `charging_symbol` | `"⇡"` | The symbol shown when the battery is charging. |
| `discharging_symbol` | `"⇣"` | The symbol shown when the battery is discharging. |
| `disabled` | `false` | Disables the `battery` module. |
| Variable | Default | Description |
| -------------------- | ------------ | ------------------------------------------------- |
| `full_symbol` | `"•"` | The symbol shown when the battery is full. |
| `charging_symbol` | `"⇡"` | The symbol shown when the battery is charging. |
| `discharging_symbol` | `"⇣"` | The symbol shown when the battery is discharging. |
| `style` | `"bold red"` | The style for the module. |
| `disabled` | `false` | Disables the `battery` module. |
### Example
@@ -89,18 +132,21 @@ discharging_symbol = "💀"
The `character` module shows a character (usually an arrow) beside where the text
is entered in your terminal.
The character will tell you whether the last command was successful or not. It
can do this in two ways: by changing color (red/green) or by changing its shape
(/✖). The latter will only be done if `use_symbol_for_status` is set to `true`.
The character will tell you whether the last command was successful or not. It
can do this in two ways: by changing color (red/green) or by changing its shape
(/✖). The latter will only be done if `use_symbol_for_status` is set to `true`.
### Options
| Variable | Default | Description |
| ---------- | ------- | ---------------------------------------------------- |
| `symbol` | `""` | The symbol used before the text input in the prompt. |
| `error_symbol` | `"✖"` | The symbol used before text input if the previous command failed. |
| `use_symbol_for_status` | `false` | Indicate error status by changing the symbol. |
| `disabled` | `false` | Disables the `character` module. |
| Variable | Default | Description |
| ----------------------- | -------------- | ----------------------------------------------------------------------------------- |
| `symbol` | `""` | The symbol used before the text input in the prompt. |
| `error_symbol` | `"✖"` | The symbol used before text input if the previous command failed. |
| `use_symbol_for_status` | `false` | Indicate error status by changing the symbol. |
| `vicmd_symbol` | `""` | The symbol used before the text input in the prompt if shell is in vim normal mode. |
| `style_success` | `"bold green"` | The style used if the last command was successful. |
| `style_failure` | `"bold red"` | The style used if the last command failed. |
| `disabled` | `false` | Disables the `character` module. |
### Example
@@ -108,7 +154,7 @@ can do this in two ways: by changing color (red/green) or by changing its shape
# ~/.config/starship.toml
[character]
symbol = ""
symbol = ""
error_symbol = "✗"
use_symbol_for_status = true
```
@@ -119,17 +165,23 @@ The `cmd_duration` module shows how long the last command took to execute.
The module will be shown only if the command took longer than two seconds, or
the `min_time` config value, if it exists.
::: warning NOTE
Command duration is currently not supported in `bash`. See
[this issue](https://github.com/starship/starship/issues/124) for more details.
::: warning Do not hook the DEBUG trap in Bash
If you are running Starship in `bash`, do not hook the `DEBUG` trap after running
`eval $(starship init $0)`, or this module **will** break.
:::
Bash users who need preexec-like functionality can use
[rcaloras's bash_preexec framework](https://github.com/rcaloras/bash-preexec).
Simply define the arrays `preexec_functions` and `precmd_functions` before
running `eval $(starship init $0)`, and then proceed as normal.
### Options
| Variable | Default | Description |
| ---------- | ------- | ----------------------------------- |
| `min_time` | `2` | Shortest duration to show time for. |
| `disabled` | `false` | Disables the `cmd_duration` module. |
| Variable | Default | Description |
| ---------- | --------------- | ----------------------------------- |
| `min_time` | `2` | Shortest duration to show time for. |
| `style` | `"bold yellow"` | The style for the module. |
| `disabled` | `false` | Disables the `cmd_duration` module. |
### Example
@@ -146,12 +198,23 @@ The `directory` module shows the path to your current directory, truncated to
three parent folders. Your directory will also be truncated to the root of the
git repo that you're currently in.
When using the fish style pwd option, instead of hiding the path that is
truncated, you will see a shortened name of each directory based on the number
you enable for the option.
For example, given `~/Dev/Nix/nixpkgs/pkgs` where `nixpkgs` is the repo root,
and the option set to `1`. You will now see `~/D/N/nixpkgs/pkgs`, whereas before
it would have been `nixpkgs/pkgs`.
### Options
| Variable | Default | Description |
| ------------------- | ------- | ------------------------------------------------------------------------------- |
| `truncation_length` | `3` | The number of parent folders that the current directory should be truncated to. |
| `disabled` | `false` | Disables the `directory` module. |
| Variable | Default | Description |
| --------------------------- | ------------- | -------------------------------------------------------------------------------- |
| `truncation_length` | `3` | The number of parent folders that the current directory should be truncated to. |
| `truncate_to_repo` | `true` | Whether or not to truncate to the root of the git repo that you're currently in. |
| `fish_style_pwd_dir_length` | `0` | The number of characters to use when applying fish shell pwd path logic. |
| `style` | `"bold cyan"` | The style for the module. |
| `disabled` | `false` | Disables the `directory` module. |
### Example
@@ -168,10 +231,13 @@ The `git_branch` module shows the active branch of the repo in your current dire
### Options
| Variable | Default | Description |
| ---------- | ------- | ----------------------------------------------------------------------------- |
| `symbol` | `" "` | The symbol used before the branch name of the repo in your current directory. |
| `disabled` | `false` | Disables the `git_branch` module. |
| Variable | Default | Description |
| ------------------- | --------------- | ------------------------------------------------------------------------------------- |
| `symbol` | `" "` | The symbol used before the branch name of the repo in your current directory. |
| `truncation_length` | `2^63 - 1` | Truncates a git branch to X graphemes |
| `truncation_symbol` | `"…"` | The symbol used to indicate a branch name was truncated. You can use "" for no symbol |
| `style` | `"bold purple"` | The style for the module. |
| `disabled` | `false` | Disables the `git_branch` module. |
### Example
@@ -180,6 +246,40 @@ The `git_branch` module shows the active branch of the repo in your current dire
[git_branch]
symbol = "🌱 "
truncation_length = "4"
truncation_symbol = ""
```
## Git State
The `git_state` module will show in directories which are part of a git
repository, and where there is an operation in progress, such as: _REBASING_,
_BISECTING_, etc. If there is progress information (e.g., REBASING 3/10),
that information will be shown too.
### Options
| Variable | Default | Description |
| ------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------- |
| `rebase` | `"REBASING"` | The text displayed when a `rebase` is in progress. |
| `merge` | `"MERGING"` | The text displayed when a `merge` is in progress. |
| `revert` | `"REVERTING"` | The text displayed when a `revert` is in progress. |
| `cherry_pick` | `"CHERRY-PICKING"` | The text displayed when a `cherry-pick` is in progress. |
| `bisect` | `"BISECTING"` | The text displayed when a `bisect` is in progress. |
| `am` | `"AM"` | The text displayed when an `apply-mailbox` (`git am`) is in progress. |
| `am_or_rebase` | `"AM/REBASE"` | The text displayed when an ambiguous `apply-mailbox` or `rebase` is in progress. |
| `progress_divider` | `"/"` | The symbol or text which will separate the current and total progress amounts. (e.g., `" of "`, for `"3 of 10"`) |
| `style` | `"bold yellow"` | The style for the module. |
| `disabled` | `false` | Disables the `git_state` module. |
### Example
```toml
# ~/.config/starship.toml
[git_state]
progress_divider = " of "
cherry_pick = "🍒 PICKING"
```
## Git Status
@@ -189,19 +289,21 @@ current directory.
### Options
| Variable | Default | Description |
| ------------ | ------- | ------------------------------------------------------- |
| `conflicted` | `"="` | This branch has merge conflicts. |
| `ahead` | `"⇡"` | This branch is ahead of the branch being tracked. |
| `behind` | `"⇣"` | This branch is behind of the branch being tracked. |
| `diverged` | `"⇕"` | This branch has diverged from the branch being tracked. |
| `untracked` | `"?"` | There are untracked files in the working directory. |
| `stashed` | `"$"` | A stash exists for the local repository. |
| `modified` | `"!"` | There are file modifications in the working directory. |
| `added` | `"+"` | A new file has been added to the staging area. |
| `renamed` | `"»"` | A renamed file has been added to the staging area. |
| `deleted` | `"✘"` | A file's deletion has been added to the staging area. |
| `disabled` | `false` | Disables the `git_status` module. |
| Variable | Default | Description |
| ----------------- | ------------ | ------------------------------------------------------- |
| `conflicted` | `"="` | This branch has merge conflicts. |
| `ahead` | `"⇡"` | This branch is ahead of the branch being tracked. |
| `behind` | `"⇣"` | This branch is behind of the branch being tracked. |
| `diverged` | `"⇕"` | This branch has diverged from the branch being tracked. |
| `untracked` | `"?"` | There are untracked files in the working directory. |
| `stashed` | `"$"` | A stash exists for the local repository. |
| `modified` | `"!"` | There are file modifications in the working directory. |
| `staged` | `"+"` | A new file has been added to the staging area. |
| `renamed` | `"»"` | A renamed file has been added to the staging area. |
| `deleted` | `"✘"` | A file's deletion has been added to the staging area. |
| `show_sync_count` | `false` | Show ahead/behind count of the branch being tracked. |
| `style` | `"bold red"` | The style for the module. |
| `disabled` | `false` | Disables the `git_status` module. |
### Example
@@ -216,7 +318,7 @@ diverged = "😵"
untracked = "🤷‍"
stashed = "📦"
modified = "📝"
added = ""
staged = ""
renamed = "👅"
deleted = "🗑"
```
@@ -236,10 +338,11 @@ The module will be shown if any of the following conditions are met:
### Options
| Variable | Default | Description |
| ---------- | ------- | -------------------------------------------------------- |
| `symbol` | `"🐹 "` | The symbol used before displaying the version of Golang. |
| `disabled` | `false` | Disables the `golang` module. |
| Variable | Default | Description |
| ---------- | ------------- | -------------------------------------------------------- |
| `symbol` | `"🐹 "` | The symbol used before displaying the version of Golang. |
| `style` | `"bold cyan"` | The style for the module. |
| `disabled` | `false` | Disables the `golang` module. |
### Example
@@ -250,6 +353,34 @@ The module will be shown if any of the following conditions are met:
symbol = "🏎💨 "
```
## Hostname
The `hostname` module shows the system hostname.
### Options
| Variable | Default | Description |
| ---------- | --------------------- | ---------------------------------------------------- |
| `ssh_only` | `true` | Only show hostname when connected to an SSH session. |
| `prefix` | `""` | Prefix to display immediately before the hostname. |
| `suffix` | `""` | Suffix to display immediately after the hostname. |
| `style` | `"bold dimmed green"` | The style for the module. |
| `disabled` | `false` | Disables the `hostname` module. |
### Example
```toml
# ~/.config/starship.toml
[hostname]
ssh_only = false
prefix = "⟪"
suffix = "⟫"
disabled = false
```
## Jobs
The `jobs` module shows the current number of jobs running.
@@ -259,10 +390,12 @@ more than the `threshold` config value, if it exists.
### Options
| Variable | Default | Description |
| ----------- | ------- | -------------------------------- |
| `threshold` | `1` | Show number of jobs if execeded. |
| `disabled` | `false` | Disables the `jobs` module. |
| Variable | Default | Description |
| ----------- | ------------- | ----------------------------------------------------- |
| `symbol` | `"✦ "` | The symbol used before displaying the number of jobs. |
| `threshold` | `1` | Show number of jobs if exceeded. |
| `style` | `"bold blue"` | The style for the module. |
| `disabled` | `false` | Disables the `jobs` module. |
### Example
@@ -270,6 +403,7 @@ more than the `threshold` config value, if it exists.
# ~/.config/starship.toml
[jobs]
symbol = "+ "
threshold = 4
```
@@ -292,6 +426,44 @@ The `line_break` module separates the prompt into two lines.
disabled = true
```
### Example
```toml
# ~/.config/starship.toml
[ruby]
symbol = "🔺 "
```
## Nix-shell
The `nix_shell` module shows the nix-shell environment.
The module will be shown when inside a nix-shell environment.
### Options
| Variable | Default | Description |
| ------------ | ------------ | ---------------------------------- |
| `use_name` | `false` | Display the name of the nix-shell. |
| `impure_msg` | `impure` | Customize the "impure" msg. |
| `pure_msg` | `pure` | Customize the "pure" msg. |
| `style` | `"bold red"` | The style for the module. |
| `disabled` | `false` | Disables the `nix_shell` module. |
### Example
```toml
# ~/.config/starship.toml
[nix_shell]
disabled = true
use_name = true
impure_msg = "impure shell"
pure_msg = "pure shell"
```
## NodeJS
The `nodejs` module shows the currently installed version of NodeJS.
@@ -303,10 +475,11 @@ The module will be shown if any of the following conditions are met:
### Options
| Variable | Default | Description |
| ---------- | ------- | -------------------------------------------------------- |
| `symbol` | `"⬢ "` | The symbol used before displaying the version of NodeJS. |
| `disabled` | `false` | Disables the `nodejs` module. |
| Variable | Default | Description |
| ---------- | -------------- | -------------------------------------------------------- |
| `symbol` | `"⬢ "` | The symbol used before displaying the version of NodeJS. |
| `style` | `"bold green"` | The style for the module. |
| `disabled` | `false` | Disables the `nodejs` module. |
### Example
@@ -320,23 +493,26 @@ symbol = "🤖 "
## Package Version
The `package` module is shown when the current directory is the repository for a
package, and shows its current version. The module currently supports `npm` and
`cargo` packages.
package, and shows its current version. The module currently supports `npm`, `cargo`,
and `poetry` packages.
- **npm** The `npm` package version is extracted from the `package.json` present
in the current directory
- **cargo** The `cargo` package version is extracted from the `Cargo.toml` present
in the current directory
- **poetry** The `poetry` package version is extracted from the `pyproject.toml` present
in the current directory
> ⚠️ The version being shown is that of the package whose source code is in your
> current directory, not your package manager.
### Options
| Variable | Default | Description |
| ---------- | ------- | ---------------------------------------------------------- |
| `symbol` | `"📦 "` | The symbol used before displaying the version the package. |
| `disabled` | `false` | Disables the `package` module. |
| Variable | Default | Description |
| ---------- | ------------ | ---------------------------------------------------------- |
| `symbol` | `"📦 "` | The symbol used before displaying the version the package. |
| `style` | `"bold red"` | The style for the module. |
| `disabled` | `false` | Disables the `package` module. |
### Example
@@ -363,16 +539,17 @@ The module will be shown if any of the following conditions are met:
- The current directory contains a `requirements.txt` file
- The current directory contains a `pyproject.toml` file
- The current directory contains a file with the `.py` extension
- The current directory contains a `Pipfile` file
### Options
| Variable | Default | Description |
| ---------- | ------- | -------------------------------------------------------- |
| `symbol` | `"🐍 "` | The symbol used before displaying the version of Python. |
| `disabled` | `false` | Disables the `python` module. |
| `pyenv_version_name` | `false` | Use pyenv to get Python version |
| `pyenv_prefix` | `"pyenv "` | Prefix before pyenv version display (default display is `pyenv MY_VERSION`) |
| Variable | Default | Description |
| -------------------- | --------------- | --------------------------------------------------------------------------- |
| `symbol` | `"🐍 "` | The symbol used before displaying the version of Python. |
| `pyenv_version_name` | `false` | Use pyenv to get Python version |
| `pyenv_prefix` | `"pyenv "` | Prefix before pyenv version display (default display is `pyenv MY_VERSION`) |
| `style` | `"bold yellow"` | The style for the module. |
| `disabled` | `false` | Disables the `python` module. |
### Example
@@ -385,6 +562,22 @@ pyenv_version_name = true
pyenv_prefix = "foo "
```
## Ruby
The `ruby` module shows the currently installed version of Ruby.
The module will be shown if any of the following conditions are met:
- The current directory contains a `Gemfile` file
- The current directory contains a `.rb` file
### Options
| Variable | Default | Description |
| ---------- | ------------ | ------------------------------------------------------ |
| `symbol` | `"💎 "` | The symbol used before displaying the version of Ruby. |
| `style` | `"bold red"` | The style for the module. |
| `disabled` | `false` | Disables the `ruby` module. |
## Rust
The `rust` module shows the currently installed version of Rust.
@@ -395,10 +588,11 @@ The module will be shown if any of the following conditions are met:
### Options
| Variable | Default | Description |
| ---------- | ------- | -------------------------------------------------------- |
| `symbol` | `"🦀 "` | The symbol used before displaying the version of Python. |
| `disabled` | `false` | Disables the `rust` module. |
| Variable | Default | Description |
| ---------- | ------------ | ------------------------------------------------------ |
| `symbol` | `"🦀 "` | The symbol used before displaying the version of Rust. |
| `style` | `"bold red"` | The style for the module. |
| `disabled` | `false` | Disables the `rust` module. |
### Example
@@ -420,9 +614,11 @@ The module will be shown if any of the following conditions are met:
### Options
| Variable | Default | Description |
| ---------- | ------- | ------------------------------- |
| `disabled` | `false` | Disables the `username` module. |
| Variable | Default | Description |
| ------------ | --------------- | ------------------------------------- |
| `style_root` | `"bold red"` | The style used when the user is root. |
| `style_user` | `"bold yellow"` | The style used for non-root users. |
| `disabled` | `false` | Disables the `username` module. |
### Example
@@ -432,4 +628,3 @@ The module will be shown if any of the following conditions are met:
[username]
disabled = true
```
+6
View File
@@ -1060,6 +1060,12 @@
"lodash.throttle": "^4.1.1"
}
},
"@vuepress/plugin-google-analytics": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@vuepress/plugin-google-analytics/-/plugin-google-analytics-1.0.3.tgz",
"integrity": "sha512-mqFFQSJjQp5zscZJ0Ik+YDLV7sZSAO8w13CG8c5WsUCjy+0oWhqAw/NjpVrEK8Y/PdYPe4l/OE5jMUU5AqRRjg==",
"dev": true
},
"@vuepress/plugin-last-updated": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@vuepress/plugin-last-updated/-/plugin-last-updated-1.0.2.tgz",
+1
View File
@@ -4,6 +4,7 @@
"build": "vuepress build"
},
"devDependencies": {
"@vuepress/plugin-google-analytics": "^1.0.3",
"vuepress": "^1.0.2"
}
}
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

+216 -1
View File
@@ -4,6 +4,8 @@ use std::env;
use dirs::home_dir;
use toml::value::Table;
use ansi_term::Color;
pub trait Config {
fn initialize() -> Table;
fn config_from_file() -> Option<Table>;
@@ -13,6 +15,8 @@ pub trait Config {
fn get_as_bool(&self, key: &str) -> Option<bool>;
fn get_as_str(&self, key: &str) -> Option<&str>;
fn get_as_i64(&self, key: &str) -> Option<i64>;
fn get_as_array(&self, key: &str) -> Option<&Vec<toml::value::Value>>;
fn get_as_ansi_style(&self, key: &str) -> Option<ansi_term::Style>;
// Internal implementation for accessors
fn get_config(&self, key: &str) -> Option<&toml::value::Value>;
@@ -35,7 +39,7 @@ impl Config for Table {
log::debug!("STARSHIP_CONFIG is set: \n{}", &path);
path
} else {
// Default to using ~/.config/starhip.toml
// Default to using ~/.config/starship.toml
log::debug!("STARSHIP_CONFIG is not set");
let config_path = home_dir()?.join(".config/starship.toml");
let config_path_str = config_path.to_str()?.to_owned();
@@ -141,11 +145,147 @@ impl Config for Table {
i64_value
}
/// Get a key from a module's configuration as a vector
fn get_as_array(&self, key: &str) -> Option<&Vec<toml::value::Value>> {
let value = self.get_config(key)?;
let array_value = value.as_array();
if array_value.is_none() {
log::debug!(
"Expected \"{}\" to be a array. Instead received {} of type {}.",
key,
value,
value.type_str()
);
}
array_value
}
/// Get a text key and attempt to interpret it into an ANSI style.
fn get_as_ansi_style(&self, key: &str) -> Option<ansi_term::Style> {
let style_string = self.get_as_str(key)?;
parse_style_string(style_string)
}
}
/** Parse a style string which represents an ansi style. Valid tokens in the style
string include the following:
- 'fg:<color>' (specifies that the color read should be a foreground color)
- 'bg:<color>' (specifies that the color read should be a background color)
- 'underline'
- 'bold'
- '<color>' (see the parse_color_string doc for valid color strings)
*/
fn parse_style_string(style_string: &str) -> Option<ansi_term::Style> {
let tokens = style_string.split_whitespace();
let mut style = ansi_term::Style::new();
// If col_fg is true, color the foreground. If it's false, color the background.
let mut col_fg: bool;
for token in tokens {
let token = token.to_lowercase();
// Check for FG/BG identifiers and strip them off if appropriate
let token = if token.as_str().starts_with("fg:") {
col_fg = true;
token.trim_start_matches("fg:").to_owned()
} else if token.as_str().starts_with("bg:") {
col_fg = false;
token.trim_start_matches("bg:").to_owned()
} else {
col_fg = true; // Bare colors are assumed to color the foreground
token
};
match token.as_str() {
"underline" => style = style.underline(),
"bold" => style = style.bold(),
"dimmed" => style = style.dimmed(),
"none" => return Some(ansi_term::Style::new()), // Overrides other toks
// Try to see if this token parses as a valid color string
color_string => {
// Match found: set either fg or bg color
if let Some(ansi_color) = parse_color_string(color_string) {
if col_fg {
style = style.fg(ansi_color);
} else {
style = style.on(ansi_color);
}
} else {
// Match failed: skip this token and log it
log::debug!("Could not parse token in color string: {}", token)
}
}
}
}
Some(style)
}
/** Parse a string that represents a color setting, returning None if this fails
There are three valid color formats:
- #RRGGBB (a hash followed by an RGB hex)
- u8 (a number from 0-255, representing an ANSI color)
- colstring (one of the 16 predefined color strings)
*/
fn parse_color_string(color_string: &str) -> Option<ansi_term::Color> {
// Parse RGB hex values
log::trace!("Parsing color_string: {}", color_string);
if color_string.starts_with('#') {
log::trace!(
"Attempting to read hexadecimal color string: {}",
color_string
);
let r: u8 = u8::from_str_radix(&color_string[1..3], 16).ok()?;
let g: u8 = u8::from_str_radix(&color_string[3..5], 16).ok()?;
let b: u8 = u8::from_str_radix(&color_string[5..7], 16).ok()?;
log::trace!("Read RGB color string: {},{},{}", r, g, b);
return Some(Color::RGB(r, g, b));
}
// Parse a u8 (ansi color)
if let Result::Ok(ansi_color_num) = color_string.parse::<u8>() {
log::trace!("Read ANSI color string: {}", ansi_color_num);
return Some(Color::Fixed(ansi_color_num));
}
// Check for any predefined color strings
// There are no predefined enums for bright colors, so we use Color::Fixed
let predefined_color = match color_string.to_lowercase().as_str() {
"black" => Some(Color::Black),
"red" => Some(Color::Red),
"green" => Some(Color::Green),
"yellow" => Some(Color::Yellow),
"blue" => Some(Color::Blue),
"purple" => Some(Color::Purple),
"cyan" => Some(Color::Cyan),
"white" => Some(Color::White),
"bright-black" => Some(Color::Fixed(8)), // "bright-black" is dark grey
"bright-red" => Some(Color::Fixed(9)),
"bright-green" => Some(Color::Fixed(10)),
"bright-yellow" => Some(Color::Fixed(11)),
"bright-blue" => Some(Color::Fixed(12)),
"bright-purple" => Some(Color::Fixed(13)),
"bright-cyan" => Some(Color::Fixed(14)),
"bright-white" => Some(Color::Fixed(15)),
_ => None,
};
if predefined_color.is_some() {
log::trace!("Read predefined color: {}", color_string);
return predefined_color;
}
// All attempts to parse have failed
None
}
#[cfg(test)]
mod tests {
use super::*;
use ansi_term::Style;
#[test]
fn table_get_as_bool() {
@@ -194,4 +334,79 @@ mod tests {
);
assert_eq!(table.get_as_bool("string"), None);
}
#[test]
fn table_get_styles_simple() {
let mut table = toml::value::Table::new();
// Test for a bold underline green module (with SiLlY cApS)
table.insert(
String::from("mystyle"),
toml::value::Value::String(String::from("bOlD uNdErLiNe GrEeN")),
);
assert!(table.get_as_ansi_style("mystyle").unwrap().is_bold);
assert!(table.get_as_ansi_style("mystyle").unwrap().is_underline);
assert_eq!(
table.get_as_ansi_style("mystyle").unwrap(),
ansi_term::Style::new().bold().underline().fg(Color::Green)
);
// Test a "plain" style with no formatting
table.insert(
String::from("plainstyle"),
toml::value::Value::String(String::from("")),
);
assert_eq!(
table.get_as_ansi_style("plainstyle").unwrap(),
ansi_term::Style::new()
);
// Test a string that's clearly broken
table.insert(
String::from("broken"),
toml::value::Value::String(String::from("djklgfhjkldhlhk;j")),
);
assert_eq!(
table.get_as_ansi_style("broken").unwrap(),
ansi_term::Style::new()
);
// Test a string that's nullified by `none`
table.insert(
String::from("nullified"),
toml::value::Value::String(String::from("fg:red bg:green bold none")),
);
assert_eq!(
table.get_as_ansi_style("nullified").unwrap(),
ansi_term::Style::new()
);
}
#[test]
fn table_get_styles_ordered() {
let mut table = toml::value::Table::new();
// Test a background style with inverted order (also test hex + ANSI)
table.insert(
String::from("flipstyle"),
toml::value::Value::String(String::from("bg:#050505 underline fg:120")),
);
assert_eq!(
table.get_as_ansi_style("flipstyle").unwrap(),
Style::new()
.underline()
.fg(Color::Fixed(120))
.on(Color::RGB(5, 5, 5))
);
// Test that the last color style is always the one used
table.insert(
String::from("multistyle"),
toml::value::Value::String(String::from("bg:120 bg:125 bg:127 fg:127 122 125")),
);
assert_eq!(
table.get_as_ansi_style("multistyle").unwrap(),
Style::new().fg(Color::Fixed(125)).on(Color::Fixed(127))
);
}
}
+16 -13
View File
@@ -37,7 +37,7 @@ impl<'a> Context<'a> {
/// Identify the current working directory and create an instance of Context
/// for it.
pub fn new(arguments: ArgMatches) -> Context {
// Retreive the "path" flag. If unavailable, use the current directory instead.
// Retrieve the "path" flag. If unavailable, use the current directory instead.
let path = arguments
.value_of("path")
.map(From::from)
@@ -177,20 +177,20 @@ pub fn path_has_name<'a>(dir_entry: &PathBuf, names: &'a [&'a str]) -> bool {
}
}
/// checks if pathbuf matches the extension provided
/// checks if pathbuf doesn't start with a dot and matches any provided extension
pub fn has_extension<'a>(dir_entry: &PathBuf, extensions: &'a [&'a str]) -> bool {
let found_ext = extensions.iter().find(|ext| {
dir_entry
.extension()
.and_then(OsStr::to_str)
.unwrap_or_default()
== **ext
});
match found_ext {
Some(extension) => !extension.is_empty(),
None => false,
if let Some(file_name) = dir_entry.file_name() {
if file_name.to_string_lossy().starts_with('.') {
return false;
}
return extensions.iter().any(|ext| {
dir_entry
.extension()
.and_then(OsStr::to_str)
.map_or(false, |e| e == *ext)
});
}
false
}
fn get_current_branch(repository: &Repository) -> Option<String> {
@@ -228,6 +228,9 @@ mod tests {
buf.set_file_name("some-file.rs");
assert_eq!(has_extension(&buf, &extensions), false);
buf.set_file_name(".some-file.js");
assert_eq!(has_extension(&buf, &extensions), false);
buf.set_file_name("some-file.js");
assert_eq!(has_extension(&buf, &extensions), true)
}
+244 -52
View File
@@ -1,26 +1,92 @@
use std::ffi::OsStr;
use std::path::Path;
use std::{env, io};
/* We need to send execution time to the prompt for the cmd_duration module. For fish,
this is fairly straightforward. For bash and zsh, we'll need to use several
shell utilities to get the time, as well as render the prompt */
/* We use a two-phase init here: the first phase gives a simple command to the
shell. This command evaluates a more complicated script using `source` and
process substitution.
pub fn init(shell_name: &str) {
Directly using `eval` on a shell script causes it to be evaluated in
a single line, which sucks because things like comments will comment out the
rest of the script, and you have to spam semicolons everywhere. By using
source and process substitutions, we make it possible to comment and debug
the init scripts. */
fn path_to_starship() -> io::Result<String> {
let current_exe = env::current_exe()?
.to_str()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "can't convert to str"))?
.to_string();
Ok(current_exe)
}
/* This prints the setup stub, the short piece of code which sets up the main
init code. The stub produces the main init script, then evaluates it with
`source` and process substitution */
pub fn init_stub(shell_name: &str) -> io::Result<()> {
log::debug!("Shell name: {}", shell_name);
let shell_basename = Path::new(shell_name).file_stem().and_then(OsStr::to_str);
let setup_script = match shell_basename {
let starship = path_to_starship()?.replace("\"", "\"'\"'\"");
let setup_stub = match shell_basename {
Some("bash") => {
let script = BASH_INIT;
/*
* The standard bash bootstrap is:
* `source <(starship init bash --print-full-init)`
*
* Unfortunately there is an issue with bash 3.2 (the MacOS
* default) which prevents this from working. It does not support
* `source` with process substitution.
*
* There are more details here: https://stackoverflow.com/a/32596626
*
* The workaround for MacOS is to use the `/dev/stdin` trick you
* see below. However, there are some systems with emulated POSIX
* environments which do not support `/dev/stdin`. For example,
* `Git Bash` within `Git for Windows and `Termux` on Android.
*
* Fortunately, these apps ship with recent-ish versions of bash.
* Git Bash is currently shipping bash 4.4 and Termux is shipping
* bash 5.0.
*
* Some testing has suggested that bash 4.0 is also incompatible
* with the standard bootstrap, whereas bash 4.1 appears to be
* consistently compatible.
*
* The upshot of all of this, is that we will use the standard
* bootstrap whenever the bash version is 4.1 or higher. Otherwise,
* we fall back to the `/dev/stdin` solution.
*
* More background can be found in these pull requests:
* https://github.com/starship/starship/pull/241
* https://github.com/starship/starship/pull/278
*/
let script = {
format!(
r#"if [ "${{BASH_VERSINFO[0]}}" -gt 4 ] || ([ "${{BASH_VERSINFO[0]}}" -eq 4 ] && [ "${{BASH_VERSINFO[1]}}" -ge 1 ])
then
source <("{}" init bash --print-full-init)
else
source /dev/stdin <<<"$("{}" init bash --print-full-init)"
fi"#,
starship, starship
)
};
Some(script)
}
Some("zsh") => {
let script = ZSH_INIT;
let script = format!("source <(\"{}\" init zsh --print-full-init)", starship);
Some(script)
}
Some("fish") => {
let script = FISH_INIT;
// Fish does process substitution with pipes and psub instead of bash syntax
let script = format!(
"source (\"{}\" init fish --print-full-init | psub)",
starship
);
Some(script)
}
None => {
@@ -33,81 +99,207 @@ pub fn init(shell_name: &str) {
);
None
}
_ => {
/* Calling unwrap() here is fine because the None case will have
already matched on the previous arm */
Some(shell_basename) => {
println!(
"printf \"\\n{0} is not yet supported by starship.\\n\
For the time being, we support bash, zsh, and fish.\\n\
Please open an issue in the starship repo if you would like to \
see support for {0}:\\nhttps://github.com/starship/starship/issues/new\"\\n\\n",
shell_basename.unwrap()
shell_basename
);
None
}
};
if let Some(script) = setup_script {
if let Some(script) = setup_stub {
print!("{}", script);
}
};
Ok(())
}
/* Bash does not currently support command durations (see issue #124) for details
https://github.com/starship/starship/issues/124
/* This function (called when `--print-full-init` is passed to `starship init`)
prints out the main initialization script */
pub fn init_main(shell_name: &str) -> io::Result<()> {
let starship_path = path_to_starship()?.replace("\"", "\"'\"'\"");
let setup_script = match shell_name {
"bash" => Some(BASH_INIT.replace("## STARSHIP ##", &format!("\"{}\"", starship_path))),
"zsh" => Some(ZSH_INIT.replace("## STARSHIP ##", &format!("\"{}\"", starship_path))),
"fish" => Some(FISH_INIT.replace("## STARSHIP ##", &format!("\"{}\"", starship_path))),
_ => {
println!(
"printf \"Shell name detection failed on phase two init.\\n\
This probably indicates a bug within starship: please open\\n\
an issue at https://github.com/starship/starship/issues/new\\n\""
);
None
}
};
if let Some(script) = setup_script {
print!("{}", script);
};
Ok(())
}
/* GENERAL INIT SCRIPT NOTES
Each init script will be passed as-is. Global notes for init scripts are in this
comment, with additional per-script comments in the strings themselves.
JOBS: The argument to `--jobs` is quoted because MacOS's `wc` leaves whitespace
in the output. We pass it to starship and do the whitespace removal in Rust,
to avoid the cost of an additional shell fork every shell draw.
*/
/* BASH INIT SCRIPT
We use PROMPT_COMMAND and the DEBUG trap to generate timing information. We try
to avoid clobbering what we can, and try to give the user ways around our
clobbers, if it's unavoidable.
A bash quirk is that the DEBUG trap is fired every time a command runs, even
if it's later on in the pipeline. If uncorrected, this could cause bad timing
data for commands like `slow | slow | fast`, since the timer starts at the start
of the "fast" command.
To solve this, we set a flag `PREEXEC_READY` when the prompt is drawn, and only
start the timer if this flag is present. That way, timing is for the entire command,
and not just a portion of it
*/
const BASH_INIT: &str = r##"
# Will be run before *every* command (even ones in pipes!)
starship_preexec() {
# Avoid restarting the timer for commands in the same pipeline
if [ "$PREEXEC_READY" = "true" ]; then
PREEXEC_READY=false
STARSHIP_START_TIME=$(date +%s)
fi
}
# Will be run before the prompt is drawn
starship_precmd() {
PS1="$(starship prompt --status=$? --jobs=$(jobs -p | wc -l))";
};
PROMPT_COMMAND=starship_precmd;
# Save the status, because commands in this pipeline will change $?
STATUS=$?
# Run the bash precmd function, if it's set. If not set, evaluates to no-op
"${starship_precmd_user_func-:}"
# Prepare the timer data, if needed.
if [[ $STARSHIP_START_TIME ]]; then
STARSHIP_END_TIME=$(date +%s)
STARSHIP_DURATION=$((STARSHIP_END_TIME - STARSHIP_START_TIME))
PS1="$(## STARSHIP ## prompt --status=$STATUS --jobs="$(jobs -p | wc -l)" --cmd-duration=$STARSHIP_DURATION)"
unset STARSHIP_START_TIME
else
PS1="$(## STARSHIP ## prompt --status=$STATUS --jobs="$(jobs -p | wc -l)")"
fi
PREEXEC_READY=true; # Signal that we can safely restart the timer
}
# If the user appears to be using https://github.com/rcaloras/bash-preexec,
# then hook our functions into their framework.
if [[ $preexec_functions ]]; then
preexec_functions+=(starship_preexec)
precmd_functions+=(starship_precmd)
else
# We want to avoid destroying an existing DEBUG hook. If we detect one, create
# a new function that runs both the existing function AND our function, then
# re-trap DEBUG to use this new function. This prevents a trap clobber.
dbg_trap="$(trap -p DEBUG | cut -d' ' -f3 | tr -d \')"
if [[ -z "$dbg_trap" ]]; then
trap starship_preexec DEBUG
elif [[ "$dbg_trap" != "starship_preexec" && "$dbg_trap" != "starship_preexec_all" ]]; then
function starship_preexec_all(){
$dbg_trap; starship_preexec
}
trap starship_preexec_all DEBUG
fi
# Finally, prepare the precmd function and set up the start time.
PROMPT_COMMAND=starship_precmd
fi
# Set up the start time and STARSHIP_SHELL, which controls shell-specific sequences
STARSHIP_START_TIME=$(date +%s)
export STARSHIP_SHELL="bash"
"##;
/* TODO: Once warning/error system is implemented in starship, print a warning
if starship will not be printing timing due to DEBUG clobber error */
/* For zsh: preexec_functions and precmd_functions provide preexec/precmd in a
way that lets us avoid clobbering them.
/* ZSH INIT SCRIPT
Zsh quirk: preexec() is only fired if a command is actually run (unlike in
bash, where spamming empty commands still triggers DEBUG). This means a user
spamming ENTER at an empty command line will see increasing runtime (since
preexec never actually fires to reset the start time).
ZSH has a quirk where `preexec` is only run if a command is actually run (i.e
pressing ENTER at an empty command line will not cause preexec to fire). This
can cause timing issues, as a user who presses "ENTER" without running a command
will see the time to the start of the last command, which may be very large.
To fix this, only pass the time if STARSHIP_START_TIME is defined, and unset
it after passing the time, so that we only measure actual commands.
To fix this, we create STARSHIP_START_TIME upon preexec() firing, and destroy it
after drawing the prompt. This ensures that the timing for one command is only
ever drawn once (for the prompt immediately after it is run).
*/
const ZSH_INIT: &str = r##"
zmodload zsh/parameter # Needed to access jobstates variable for NUM_JOBS
# Will be run before every prompt draw
starship_precmd() {
STATUS=$?;
if [[ $STARSHIP_START_TIME ]]; then
STARSHIP_END_TIME="$(date +%s)";
STARSHIP_DURATION=$((STARSHIP_END_TIME - STARSHIP_START_TIME));
PROMPT="$(starship prompt --status=$STATUS --cmd-duration=$STARSHIP_DURATION --jobs=$(jobs | wc -l))";
unset STARSHIP_START_TIME;
# Save the status, because commands in this pipeline will change $?
STATUS=$?
# Use length of jobstates array as number of jobs. Expansion fails inside
# quotes so we set it here and then use the value later on.
NUM_JOBS=$#jobstates
# Compute cmd_duration, if we have a time to consume
if [[ ! -z "${STARSHIP_START_TIME+1}" ]]; then
STARSHIP_END_TIME="$(date +%s)"
STARSHIP_DURATION=$((STARSHIP_END_TIME - STARSHIP_START_TIME))
PROMPT="$(## STARSHIP ## prompt --status=$STATUS --cmd-duration=$STARSHIP_DURATION --jobs="$NUM_JOBS")"
unset STARSHIP_START_TIME
else
PROMPT="$(starship prompt --status=$STATUS --jobs=$(jobs | wc -l))";
PROMPT="$(## STARSHIP ## prompt --status=$STATUS --jobs="$NUM_JOBS")"
fi
};
}
starship_preexec(){
STARSHIP_START_TIME="$(date +%s)"
};
}
# If precmd/preexec arrays are not already set, set them. If we don't do this,
# the code to detect whether starship_precmd is already in precmd_functions will
# fail because the array doesn't exist (and same for starship_preexec)
[[ -z "${precmd_functions+1}" ]] && precmd_functions=()
[[ -z "${preexec_functions+1}" ]] && preexec_functions=()
# If starship precmd/preexec functions are already hooked, don't double-hook them
# to avoid unnecessary performance degradation in nested shells
if [[ ${precmd_functions[(ie)starship_precmd]} -gt ${#precmd_functions} ]]; then
precmd_functions+=(starship_precmd);
fi;
precmd_functions+=(starship_precmd)
fi
if [[ ${preexec_functions[(ie)starship_preexec]} -gt ${#preexec_functions} ]]; then
preexec_functions+=(starship_preexec);
fi;
STARSHIP_START_TIME="$(date +%s)";
preexec_functions+=(starship_preexec)
fi
# Set up a function to redraw the prompt if the user switches vi modes
function zle-keymap-select
{
PROMPT=$(## STARSHIP ## prompt --keymap=$KEYMAP --jobs="$(jobs | wc -l)")
zle reset-prompt
}
STARSHIP_START_TIME="$(date +%s)"
zle -N zle-keymap-select
export STARSHIP_SHELL="zsh"
"##;
/* Fish setup is simple because they give us CMD_DURATION. Just account for name
changes between 2.7/3.0 and do some math to convert ms->s and we can use it */
const FISH_INIT: &str = r##"
function fish_prompt;
set -l exit_code $status;
set -l CMD_DURATION "$CMD_DURATION$cmd_duration";
set -l starship_duration (math --scale=0 "$CMD_DURATION / 1000");
starship prompt --status=$exit_code --cmd-duration=$starship_duration --jobs=(count (jobs -p));
end;
function fish_prompt
switch "$fish_key_bindings"
case fish_hybrid_key_bindings fish_vi_key_bindings
set keymap "$fish_bind_mode"
case '*'
set keymap insert
end
set -l exit_code $status
# Account for changes in variable name between v2.7 and v3.0
set -l CMD_DURATION "$CMD_DURATION$cmd_duration"
set -l starship_duration (math --scale=0 "$CMD_DURATION / 1000")
## STARSHIP ## prompt --status=$exit_code --keymap=$keymap --cmd-duration=$starship_duration --jobs=(count (jobs -p))
end
function fish_mode_prompt; end
export STARSHIP_SHELL="fish"
"##;
+40 -5
View File
@@ -10,6 +10,7 @@ mod print;
mod segment;
mod utils;
use crate::module::ALL_MODULES;
use clap::{App, AppSettings, Arg, SubCommand};
fn main() {
@@ -43,6 +44,14 @@ fn main() {
.help("The execution duration of the last command, in seconds")
.takes_value(true);
let keymap_arg = Arg::with_name("keymap")
.short("k")
.long("keymap")
.value_name("KEYMAP")
// fish/zsh only
.help("The keymap of fish/zsh")
.takes_value(true);
let jobs_arg = Arg::with_name("jobs")
.short("j")
.long("jobs")
@@ -50,6 +59,10 @@ fn main() {
.help("The number of currently running jobs")
.takes_value(true);
let init_scripts_arg = Arg::with_name("print_full_init")
.long("print-full-init")
.help("Print the main initialization script (as opposed to the init stub)");
let matches = App::new("starship")
.about("The cross-shell prompt for astronauts. ☄🌌️")
// pull the version number from Cargo.toml
@@ -61,7 +74,8 @@ fn main() {
.subcommand(
SubCommand::with_name("init")
.about("Prints the shell function used to execute starship")
.arg(&shell_arg),
.arg(&shell_arg)
.arg(&init_scripts_arg),
)
.subcommand(
SubCommand::with_name("prompt")
@@ -69,6 +83,7 @@ fn main() {
.arg(&status_code_arg)
.arg(&path_arg)
.arg(&cmd_duration_arg)
.arg(&keymap_arg)
.arg(&jobs_arg),
)
.subcommand(
@@ -77,11 +92,19 @@ fn main() {
.arg(
Arg::with_name("name")
.help("The name of the module to be printed")
.required(true),
.required(true)
.required_unless("list"),
)
.arg(
Arg::with_name("list")
.short("l")
.long("list")
.help("List out all supported modules"),
)
.arg(&status_code_arg)
.arg(&path_arg)
.arg(&cmd_duration_arg)
.arg(&keymap_arg)
.arg(&jobs_arg),
)
.get_matches();
@@ -89,12 +112,24 @@ fn main() {
match matches.subcommand() {
("init", Some(sub_m)) => {
let shell_name = sub_m.value_of("shell").expect("Shell name missing.");
init::init(shell_name)
if sub_m.is_present("print_full_init") {
init::init_main(shell_name).expect("can't init_main");
} else {
init::init_stub(shell_name).expect("can't init_stub");
}
}
("prompt", Some(sub_m)) => print::prompt(sub_m.clone()),
("module", Some(sub_m)) => {
let module_name = sub_m.value_of("name").expect("Module name missing.");
print::module(module_name, sub_m.clone());
if sub_m.is_present("list") {
println!("Supported modules list");
println!("----------------------");
for modules in ALL_MODULES {
println!("{}", modules);
}
}
if let Some(module_name) = sub_m.value_of("name") {
print::module(module_name, sub_m.clone());
}
}
_ => {}
}
+78 -1
View File
@@ -4,6 +4,29 @@ use ansi_term::Style;
use ansi_term::{ANSIString, ANSIStrings};
use std::fmt;
// List of all modules
pub const ALL_MODULES: &[&str] = &[
#[cfg(feature = "battery")]
"battery",
"character",
"cmd_duration",
"directory",
"git_branch",
"git_state",
"git_status",
"golang",
"hostname",
"jobs",
"line_break",
"nix_shell",
"nodejs",
"package",
"python",
"ruby",
"rust",
"username",
];
/// A module is a collection of segments showing data for a single integration
/// (e.g. The git module shows the current git branch and status)
pub struct Module<'a> {
@@ -79,12 +102,19 @@ impl<'a> Module<'a> {
/// Returns a vector of colored ANSIString elements to be later used with
/// `ANSIStrings()` to optimize ANSI codes
pub fn ansi_strings(&self) -> Vec<ANSIString> {
let mut ansi_strings = self
let shell = std::env::var("STARSHIP_SHELL").unwrap_or_default();
let ansi_strings = self
.segments
.iter()
.map(Segment::ansi_string)
.collect::<Vec<ANSIString>>();
let mut ansi_strings = match shell.as_str() {
"bash" => ansi_strings_modified(ansi_strings, shell),
"zsh" => ansi_strings_modified(ansi_strings, shell),
_ => ansi_strings,
};
ansi_strings.insert(0, self.prefix.ansi_string());
ansi_strings.push(self.suffix.ansi_string());
@@ -109,6 +139,11 @@ impl<'a> Module<'a> {
pub fn config_value_bool(&self, key: &str) -> Option<bool> {
self.config.and_then(|config| config.get_as_bool(key))
}
/// Get a module's config value as a style
pub fn config_value_style(&self, key: &str) -> Option<Style> {
self.config.and_then(|config| config.get_as_ansi_style(key))
}
}
impl<'a> fmt::Display for Module<'a> {
@@ -118,6 +153,48 @@ impl<'a> fmt::Display for Module<'a> {
}
}
/// Many shells cannot deal with raw unprintable characters (like ANSI escape sequences) and
/// miscompute the cursor position as a result, leading to strange visual bugs. Here, we wrap these
/// characters in shell-specific escape codes to indicate to the shell that they are zero-length.
fn ansi_strings_modified(ansi_strings: Vec<ANSIString>, shell: String) -> Vec<ANSIString> {
const ESCAPE_BEGIN: char = '\u{1b}';
const MAYBE_ESCAPE_END: char = 'm';
ansi_strings
.iter()
.map(|ansi| {
let mut escaped = false;
let final_string: String = ansi
.to_string()
.chars()
.map(|x| match x {
ESCAPE_BEGIN => {
escaped = true;
match shell.as_str() {
"bash" => String::from("\u{5c}\u{5b}\u{1b}"), // => \[ESC
"zsh" => String::from("\u{25}\u{7b}\u{1b}"), // => %{ESC
_ => x.to_string(),
}
}
MAYBE_ESCAPE_END => {
if escaped {
escaped = false;
match shell.as_str() {
"bash" => String::from("m\u{5c}\u{5d}"), // => m\]
"zsh" => String::from("m\u{25}\u{7d}"), // => m%}
_ => x.to_string(),
}
} else {
x.to_string()
}
}
_ => x.to_string(),
})
.collect();
ANSIString::from(final_string)
})
.collect::<Vec<ANSIString>>()
}
/// Module affixes are to be used for the prefix or suffix of a module.
pub struct Affix {
/// The affix's name, to be used in configuration and logging.
+12 -2
View File
@@ -8,6 +8,13 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const BATTERY_CHARGING: &str = "";
const BATTERY_DISCHARGING: &str = "";
const BATTERY_THRESHOLD: f32 = 10.0;
// TODO: Update when v1.0 printing refactor is implemented to only
// print escapes in a prompt context.
let shell = std::env::var("STARSHIP_SHELL").unwrap_or_default();
let percentage_char = match shell.as_str() {
"zsh" => "%%", // % is an escape in zsh, see PROMPT in `man zshmisc`
_ => "%",
};
let battery_status = get_battery_status()?;
let BatteryStatus { state, percentage } = battery_status;
@@ -23,7 +30,10 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// TODO: Set style based on percentage when threshold is modifiable
let mut module = context.new_module("battery")?;
module.set_style(Color::Red.bold());
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Red.bold());
module.set_style(module_style);
module.get_prefix().set_value("");
match state {
@@ -42,7 +52,7 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut percent_string = Vec::<String>::with_capacity(2);
// Round the percentage to a whole number
percent_string.push(percentage.round().to_string());
percent_string.push("%".to_string());
percent_string.push(percentage_char.to_string());
module.new_segment("percentage", percent_string.join("").as_ref());
Some(module)
+35 -8
View File
@@ -5,37 +5,64 @@ use ansi_term::Color;
///
/// The character segment prints an arrow character in a color dependant on the exit-
/// code of the last executed command:
/// - If the exit-code was "0", the arrow will be formatted with `COLOR_SUCCESS`
/// - If the exit-code was "0", the arrow will be formatted with `style_success`
/// (green by default)
/// - If the exit-code was anything else, the arrow will be formatted with
/// `COLOR_FAILURE` (red by default)
/// `style_failure` (red by default)
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const SUCCESS_CHAR: &str = "";
const SUCCESS_CHAR: &str = "";
const FAILURE_CHAR: &str = "";
let color_success = Color::Green.bold();
let color_failure = Color::Red.bold();
const VICMD_CHAR: &str = "";
enum ShellEditMode {
Normal,
Insert,
};
const ASSUMED_MODE: ShellEditMode = ShellEditMode::Insert;
// TODO: extend config to more modes
let mut module = context.new_module("character")?;
module.get_prefix().set_value("");
let style_success = module
.config_value_style("style_success")
.unwrap_or_else(|| Color::Green.bold());
let style_failure = module
.config_value_style("style_failure")
.unwrap_or_else(|| Color::Red.bold());
let arguments = &context.arguments;
let use_symbol = module
.config_value_bool("use_symbol_for_status")
.unwrap_or(false);
let exit_success = arguments.value_of("status_code").unwrap_or("0") == "0";
let shell = std::env::var("STARSHIP_SHELL").unwrap_or_default();
let keymap = arguments.value_of("keymap").unwrap_or("viins");
// Match shell "keymap" names to normalized vi modes
// NOTE: in vi mode, fish reports normal mode as "default".
// Unfortunately, this is also the name of the non-vi default mode.
// We do some environment detection in src/init.rs to translate.
// The result: in non-vi fish, keymap is always reported as "insert"
let mode = match (shell.as_str(), keymap) {
("fish", "default") | ("zsh", "vicmd") => ShellEditMode::Normal,
_ => ASSUMED_MODE,
};
/* If an error symbol is set in the config, use symbols to indicate
success/failure, in addition to color */
let symbol = if use_symbol && !exit_success {
module.new_segment("error_symbol", FAILURE_CHAR)
} else {
module.new_segment("symbol", SUCCESS_CHAR)
match mode {
ShellEditMode::Normal => module.new_segment("vicmd_symbol", VICMD_CHAR),
ShellEditMode::Insert => module.new_segment("symbol", SUCCESS_CHAR),
}
};
if exit_success {
symbol.set_style(color_success.bold());
symbol.set_style(style_success);
} else {
symbol.set_style(color_failure.bold());
symbol.set_style(style_failure);
};
Some(module)
+3 -1
View File
@@ -32,7 +32,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let module_color = match elapsed {
time if time < config_min => return None,
_ => Color::Yellow.bold(),
_ => module
.config_value_style("style")
.unwrap_or_else(|| Color::Yellow.bold()),
};
module.set_style(module_color);
+93 -12
View File
@@ -8,7 +8,7 @@ use super::{Context, Module};
///
/// Will perform path contraction and truncation.
/// **Contraction**
/// - Paths begining with the home directory will be contracted to `~`
/// - Paths beginning with the home directory will be contracted to `~`
/// - Paths containing a git repo will contract to begin at the repo root
///
/// **Truncation**
@@ -16,33 +16,52 @@ use super::{Context, Module};
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const HOME_SYMBOL: &str = "~";
const DIR_TRUNCATION_LENGTH: i64 = 3;
let module_color = Color::Cyan.bold();
const FISH_STYLE_PWD_DIR_LENGTH: i64 = 0;
let mut module = context.new_module("directory")?;
let module_color = module
.config_value_style("style")
.unwrap_or_else(|| Color::Cyan.bold());
module.set_style(module_color);
let truncation_length = module
.config_value_i64("truncation_length")
.unwrap_or(DIR_TRUNCATION_LENGTH);
let truncate_to_repo = module.config_value_bool("truncate_to_repo").unwrap_or(true);
let fish_style_pwd_dir_length = module
.config_value_i64("fish_style_pwd_dir_length")
.unwrap_or(FISH_STYLE_PWD_DIR_LENGTH);
let home_dir = dirs::home_dir().unwrap();
let current_dir = &context.current_dir;
log::debug!("Current directory: {:?}", current_dir);
let dir_string;
if let Some(repo_root) = &context.repo_root {
// Contract the path to the git repo root
let repo_folder_name = repo_root.file_name().unwrap().to_str().unwrap();
let dir_string = match &context.repo_root {
Some(repo_root) if truncate_to_repo => {
let repo_folder_name = repo_root.file_name().unwrap().to_str().unwrap();
dir_string = contract_path(current_dir, repo_root, repo_folder_name);
} else {
// Contract the path to the git repo root
contract_path(current_dir, repo_root, repo_folder_name)
}
// Contract the path to the home directory
let home_dir = dirs::home_dir().unwrap();
dir_string = contract_path(current_dir, &home_dir, HOME_SYMBOL);
}
_ => contract_path(current_dir, &home_dir, HOME_SYMBOL),
};
// Truncate the dir string to the maximum number of path components
let truncated_dir_string = truncate(dir_string, truncation_length as usize);
if fish_style_pwd_dir_length > 0 {
// If user is using fish style path, we need to add the segment first
let contracted_home_dir = contract_path(current_dir, &home_dir, HOME_SYMBOL);
let fish_style_dir = to_fish_style(
fish_style_pwd_dir_length as usize,
contracted_home_dir,
&truncated_dir_string,
);
module.new_segment("path", &fish_style_dir);
}
module.new_segment("path", &truncated_dir_string);
module.get_prefix().set_value("in ");
@@ -111,6 +130,38 @@ fn truncate(dir_string: String, length: usize) -> String {
truncated_components.join("/")
}
/// Takes part before contracted path and replaces it with fish style path
///
/// Will take the first letter of each directory before the contracted path and
/// use that in the path instead. See the following example.
///
/// Absolute Path: `/Users/Bob/Projects/work/a_repo`
/// Contracted Path: `a_repo`
/// With Fish Style: `~/P/w/a_repo`
///
/// Absolute Path: `/some/Path/not/in_a/repo/but_nested`
/// Contracted Path: `in_a/repo/but_nested`
/// With Fish Style: `/s/P/n/in_a/repo/but_nested`
fn to_fish_style(pwd_dir_length: usize, dir_string: String, truncated_dir_string: &str) -> String {
let replaced_dir_string = dir_string.replace(truncated_dir_string, "");
let components = replaced_dir_string.split('/').collect::<Vec<&str>>();
if components.is_empty() {
return replaced_dir_string;
}
components
.into_iter()
.map(|word| match word {
"" => "",
_ if word.len() <= pwd_dir_length => word,
_ if word.starts_with('.') => &word[..=pwd_dir_length],
_ => &word[..pwd_dir_length],
})
.collect::<Vec<_>>()
.join("/")
}
#[cfg(test)]
mod tests {
use super::*;
@@ -200,4 +251,34 @@ mod tests {
let output = truncate(path.to_string(), 3);
assert_eq!(output, "engines/booster/rocket")
}
#[test]
fn fish_style_with_user_home_contracted_path() {
let path = "~/starship/engines/booster/rocket";
let output = to_fish_style(1, path.to_string(), "engines/booster/rocket");
assert_eq!(output, "~/s/");
}
#[test]
fn fish_style_with_user_home_contracted_path_and_dot_dir() {
let path = "~/.starship/engines/booster/rocket";
let output = to_fish_style(1, path.to_string(), "engines/booster/rocket");
assert_eq!(output, "~/.s/");
}
#[test]
fn fish_style_with_no_contracted_path() {
// `truncatation_length = 2`
let path = "/absolute/Path/not/in_a/repo/but_nested";
let output = to_fish_style(1, path.to_string(), "repo/but_nested");
assert_eq!(output, "/a/P/n/i/");
}
#[test]
fn fish_style_with_pwd_dir_len_no_contracted_path() {
// `truncatation_length = 2`
let path = "/absolute/Path/not/in_a/repo/but_nested";
let output = to_fish_style(2, path.to_string(), "repo/but_nested");
assert_eq!(output, "/ab/Pa/no/in/");
}
}
+46 -4
View File
@@ -1,4 +1,5 @@
use ansi_term::Color;
use unicode_segmentation::UnicodeSegmentation;
use super::{Context, Module};
@@ -8,15 +9,56 @@ use super::{Context, Module};
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
const GIT_BRANCH_CHAR: &str = "";
let branch_name = context.branch_name.as_ref()?;
let segment_color = Color::Purple.bold();
let mut module = context.new_module("git_branch")?;
let segment_color = module
.config_value_style("style")
.unwrap_or_else(|| Color::Purple.bold());
module.set_style(segment_color);
module.get_prefix().set_value("on ");
let unsafe_truncation_length = module
.config_value_i64("truncation_length")
.unwrap_or(std::i64::MAX);
let truncation_symbol = get_graphemes(
module.config_value_str("truncation_symbol").unwrap_or(""),
1,
);
module.new_segment("symbol", GIT_BRANCH_CHAR);
module.new_segment("name", branch_name);
// TODO: Once error handling is implemented, warn the user if their config
// truncation length is nonsensical
let len = if unsafe_truncation_length <= 0 {
log::debug!(
"[WARN]: \"truncation_length\" should be a positive value, found {}",
unsafe_truncation_length
);
std::usize::MAX
} else {
unsafe_truncation_length as usize
};
let branch_name = context.branch_name.as_ref()?;
let truncated_graphemes = get_graphemes(&branch_name, len);
// The truncation symbol should only be added if we truncated
let truncated_and_symbol = if len < graphemes_len(&branch_name) {
truncated_graphemes + &truncation_symbol
} else {
truncated_graphemes
};
module.new_segment("name", &truncated_and_symbol);
Some(module)
}
fn get_graphemes(text: &str, length: usize) -> String {
UnicodeSegmentation::graphemes(text, true)
.take(length)
.collect::<Vec<&str>>()
.concat()
}
fn graphemes_len(text: &str) -> usize {
UnicodeSegmentation::graphemes(&text[..], true).count()
}
+169
View File
@@ -0,0 +1,169 @@
use ansi_term::Color;
use git2::{Repository, RepositoryState};
use std::path::Path;
use super::{Context, Module};
/// Creates a module with the state of the git repository at the current directory
///
/// During a git operation it will show: REBASING, BISECTING, MERGING, etc.
/// If the progress information is available (e.g. rebasing 3/10), it will show that too.
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("git_state")?;
let repo_root = context.repo_root.as_ref()?;
let mut repository = Repository::open(repo_root).ok()?;
let state_description = get_state_description(&mut repository);
if let StateDescription::Clean = state_description {
return None;
}
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Yellow.bold());
module.set_style(module_style);
module.get_prefix().set_value("(");
module.get_suffix().set_value(") ");
let label = match state_description {
StateDescription::Label(label) => label,
StateDescription::LabelAndProgress(label, _) => label,
// Should only be possible if you've added a new variant to StateDescription
_ => panic!("Expected to have a label at this point in the control flow."),
};
module.new_segment(label.segment_name, label.message_default);
if let StateDescription::LabelAndProgress(_, progress) = state_description {
module.new_segment("progress_current", &format!(" {}", progress.current));
module.new_segment("progress_divider", "/");
module.new_segment("progress_total", &format!("{}", progress.total));
}
Some(module)
}
static MERGE_LABEL: StateLabel = StateLabel {
segment_name: "merge",
message_default: "MERGING",
};
static REVERT_LABEL: StateLabel = StateLabel {
segment_name: "revert",
message_default: "REVERTING",
};
static CHERRY_LABEL: StateLabel = StateLabel {
segment_name: "cherry_pick",
message_default: "CHERRY-PICKING",
};
static BISECT_LABEL: StateLabel = StateLabel {
segment_name: "bisect",
message_default: "BISECTING",
};
static AM_LABEL: StateLabel = StateLabel {
segment_name: "am",
message_default: "AM",
};
static REBASE_LABEL: StateLabel = StateLabel {
segment_name: "rebase",
message_default: "REBASING",
};
static AM_OR_REBASE_LABEL: StateLabel = StateLabel {
segment_name: "am_or_rebase",
message_default: "AM/REBASE",
};
fn get_state_description(repository: &mut Repository) -> StateDescription {
match repository.state() {
RepositoryState::Clean => StateDescription::Clean,
RepositoryState::Merge => StateDescription::Label(&MERGE_LABEL),
RepositoryState::Revert => StateDescription::Label(&REVERT_LABEL),
RepositoryState::RevertSequence => StateDescription::Label(&REVERT_LABEL),
RepositoryState::CherryPick => StateDescription::Label(&CHERRY_LABEL),
RepositoryState::CherryPickSequence => StateDescription::Label(&CHERRY_LABEL),
RepositoryState::Bisect => StateDescription::Label(&BISECT_LABEL),
RepositoryState::ApplyMailbox => StateDescription::Label(&AM_LABEL),
RepositoryState::ApplyMailboxOrRebase => StateDescription::Label(&AM_OR_REBASE_LABEL),
RepositoryState::Rebase => describe_rebase(repository),
RepositoryState::RebaseInteractive => describe_rebase(repository),
RepositoryState::RebaseMerge => describe_rebase(repository),
}
}
fn describe_rebase(repository: &mut Repository) -> StateDescription {
/*
* Sadly, libgit2 seems to have some issues with reading the state of
* interactive rebases. So, instead, we'll poke a few of the .git files
* ourselves. This might be worth re-visiting this in the future...
*
* The following is based heavily on: https://github.com/magicmonty/bash-git-prompt
*/
let just_label = StateDescription::Label(&REBASE_LABEL);
let dot_git = repository
.workdir()
.and_then(|d| Some(d.join(Path::new(".git"))));
let dot_git = match dot_git {
None => {
// We didn't find the .git directory.
// Something very odd is going on. We'll just back away slowly.
return just_label;
}
Some(path) => path,
};
let has_path = |relative_path: &str| {
let path = dot_git.join(Path::new(relative_path));
path.exists()
};
let file_to_usize = |relative_path: &str| {
let path = dot_git.join(Path::new(relative_path));
let contents = crate::utils::read_file(path).ok()?;
let quantity = contents.trim().parse::<usize>().ok()?;
Some(quantity)
};
let paths_to_progress = |current_path: &str, total_path: &str| {
let current = file_to_usize(current_path)?;
let total = file_to_usize(total_path)?;
Some(StateProgress { current, total })
};
let progress = if has_path("rebase-merge") {
paths_to_progress("rebase-merge/msgnum", "rebase-merge/end")
} else if has_path("rebase-apply") {
paths_to_progress("rebase-apply/next", "rebase-apply/last")
} else {
None
};
match progress {
None => just_label,
Some(progress) => StateDescription::LabelAndProgress(&REBASE_LABEL, progress),
}
}
enum StateDescription {
Clean,
Label(&'static StateLabel),
LabelAndProgress(&'static StateLabel, StateProgress),
}
struct StateLabel {
segment_name: &'static str,
message_default: &'static str,
}
struct StateProgress {
current: usize,
total: usize,
}
+42 -6
View File
@@ -34,8 +34,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let repo_root = context.repo_root.as_ref()?;
let repository = Repository::open(repo_root).ok()?;
let module_style = Color::Red.bold();
let mut module = context.new_module("git_status")?;
let show_sync_count = module.config_value_bool("show_sync_count").unwrap_or(false);
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Red.bold());
module.get_prefix().set_value("[").set_style(module_style);
module.get_suffix().set_value("] ").set_style(module_style);
module.set_style(module_style);
@@ -66,12 +70,37 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
// Add the ahead/behind segment
if let Ok((ahead, behind)) = ahead_behind {
let add_ahead = |m: &mut Module<'a>| {
m.new_segment("ahead", GIT_STATUS_AHEAD);
if show_sync_count {
m.new_segment("ahead_count", &ahead.to_string());
}
};
let add_behind = |m: &mut Module<'a>| {
m.new_segment("behind", GIT_STATUS_BEHIND);
if show_sync_count {
m.new_segment("behind_count", &behind.to_string());
}
};
if ahead > 0 && behind > 0 {
module.new_segment("diverged", GIT_STATUS_DIVERGED);
} else if ahead > 0 {
module.new_segment("ahead", GIT_STATUS_AHEAD);
} else if behind > 0 {
module.new_segment("behind", GIT_STATUS_BEHIND);
if show_sync_count {
add_ahead(&mut module);
add_behind(&mut module);
}
}
if ahead > 0 && behind == 0 {
add_ahead(&mut module);
}
if behind > 0 && ahead == 0 {
add_behind(&mut module);
}
}
@@ -113,7 +142,14 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
/// Gets the bitflags associated with the repo's git status
fn get_repo_status(repository: &Repository) -> Result<Status, git2::Error> {
let mut status_options = git2::StatusOptions::new();
status_options.include_untracked(true);
match repository.config()?.get_entry("status.showUntrackedFiles") {
Ok(entry) => status_options.include_untracked(entry.value() != Some("no")),
_ => status_options.include_untracked(true),
};
status_options.renames_from_rewrites(true);
status_options.renames_head_to_index(true);
status_options.renames_index_to_workdir(true);
let repo_file_statuses = repository.statuses(Some(&mut status_options))?;
+5 -3
View File
@@ -28,10 +28,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
match get_go_version() {
Some(go_version) => {
const GO_CHAR: &str = "🐹 ";
let module_color = Color::Cyan.bold();
let mut module = context.new_module("go")?;
module.set_style(module_color);
let mut module = context.new_module("golang")?;
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Cyan.bold());
module.set_style(module_style);
let formatted_version = format_go_version(&go_version)?;
module.new_segment("symbol", GO_CHAR);
+41
View File
@@ -0,0 +1,41 @@
use ansi_term::Color;
use std::env;
use super::{Context, Module};
use std::ffi::OsString;
/// Creates a module with the system hostname
///
/// Will display the hostname if all of the following criteria are met:
/// - hostname.disabled is absent or false
/// - hostname.ssh_only is false OR the user is currently connected as an SSH session (`$SSH_CONNECTION`)
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("hostname")?;
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Green.bold().dimmed());
let ssh_connection = env::var("SSH_CONNECTION").ok();
if module.config_value_bool("ssh_only").unwrap_or(true) && ssh_connection.is_none() {
return None;
}
let os_hostname: OsString = gethostname::gethostname();
let host = match os_hostname.into_string() {
Ok(host) => host,
Err(bad) => {
log::debug!("hostname is not valid UTF!\n{:?}", bad);
return None;
}
};
let prefix = module.config_value_str("prefix").unwrap_or("").to_owned();
let suffix = module.config_value_str("suffix").unwrap_or("").to_owned();
module.set_style(module_style);
module.new_segment("hostname", &format!("{}{}{}", prefix, host, suffix));
module.get_prefix().set_value("on ");
Some(module)
}
+5 -3
View File
@@ -9,14 +9,16 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let threshold = module.config_value_i64("threshold").unwrap_or(1);
const JOB_CHAR: &str = "";
let module_color = Color::Blue.bold();
module.set_style(module_color);
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Blue.bold());
module.set_style(module_style);
let arguments = &context.arguments;
let num_of_jobs = arguments
.value_of("jobs")
.unwrap_or("0")
.trim()
.parse::<i64>()
.ok()?;
if num_of_jobs == 0 {
+22 -7
View File
@@ -1,38 +1,53 @@
mod battery;
// While adding out new module add out module to src/module.rs ALL_MODULES const array also.
mod character;
mod cmd_duration;
mod directory;
mod git_branch;
mod git_state;
mod git_status;
mod golang;
mod hostname;
mod jobs;
mod line_break;
mod nix_shell;
mod nodejs;
mod package;
mod python;
mod ruby;
mod rust;
mod username;
#[cfg(feature = "battery")]
mod battery;
use crate::context::Context;
use crate::module::Module;
pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
match module {
"dir" | "directory" => directory::module(context),
"char" | "character" => character::module(context),
"node" | "nodejs" => nodejs::module(context),
"rust" | "rustlang" => rust::module(context),
"directory" => directory::module(context),
"character" => character::module(context),
"nodejs" => nodejs::module(context),
"rust" => rust::module(context),
"python" => python::module(context),
"go" | "golang" => golang::module(context),
"ruby" => ruby::module(context),
"golang" => golang::module(context),
"line_break" => line_break::module(context),
"package" => package::module(context),
"git_branch" => git_branch::module(context),
"git_state" => git_state::module(context),
"git_status" => git_status::module(context),
"username" => username::module(context),
#[cfg(feature = "battery")]
"battery" => battery::module(context),
"cmd_duration" => cmd_duration::module(context),
"jobs" => jobs::module(context),
"nix_shell" => nix_shell::module(context),
"hostname" => hostname::module(context),
_ => panic!("Unknown module: {}", module),
_ => {
eprintln!("Error: Unknown module {}. Use starship module --list to list out all supported modules.", module);
None
}
}
}
+56
View File
@@ -0,0 +1,56 @@
use ansi_term::Color;
use std::env;
use super::{Context, Module};
// IN_NIX_SHELL should be "pure" or "impure" but lorri uses "1" for "impure"
// https://github.com/target/lorri/issues/140
/// Creates a module showing if inside a nix-shell
///
/// The module will use the `$IN_NIX_SHELL` and `$name` environment variable to
/// determine if it's inside a nix-shell and the name of it.
///
/// The following options are availables:
/// - use_name (bool) // print the name of the nix-shell
/// - impure_msg (string) // change the impure msg
/// - pure_msg (string) // change the pure msg
///
/// Will display the following:
/// - name (pure) // use_name == true in a pure nix-shell
/// - name (impure) // use_name == true in an impure nix-shell
/// - pure // use_name == false in a pure nix-shell
/// - impure // use_name == false in an impure nix-shell
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let mut module = context.new_module("nix_shell")?;
env::var("IN_NIX_SHELL")
.ok()
.and_then(|shell_type| {
if shell_type == "1" || shell_type == "impure" {
Some(module.config_value_str("impure_msg").unwrap_or("impure"))
} else if shell_type == "pure" {
Some(module.config_value_str("pure_msg").unwrap_or("pure"))
} else {
None
}
})
.map(|shell_type| {
if module.config_value_bool("use_name").unwrap_or(false) {
match env::var("name").ok() {
Some(name) => format!("{} ({})", name, shell_type),
None => shell_type.to_string(),
}
} else {
shell_type.to_string()
}
})
.map(|segment| {
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Red.bold());
module.set_style(module_style);
module.new_segment("nix_shell", &segment);
module
})
}
+5 -3
View File
@@ -24,10 +24,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
match get_node_version() {
Some(node_version) => {
const NODE_CHAR: &str = "";
let module_color = Color::Green.bold();
let mut module = context.new_module("node")?;
module.set_style(module_color);
let mut module = context.new_module("nodejs")?;
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Green.bold());
module.set_style(module_style);
let formatted_version = node_version.trim();
module.new_segment("symbol", NODE_CHAR);
+52 -12
View File
@@ -12,10 +12,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
match get_package_version() {
Some(package_version) => {
const PACKAGE_CHAR: &str = "📦 ";
let module_color = Color::Red.bold();
let mut module = context.new_module("package")?;
module.set_style(module_color);
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Red.bold());
module.set_style(module_style);
module.get_prefix().set_value("is ");
module.new_segment("symbol", PACKAGE_CHAR);
@@ -46,18 +48,28 @@ fn extract_package_version(file_contents: &str) -> Option<String> {
Some(formatted_version)
}
fn extract_poetry_version(file_contents: &str) -> Option<String> {
let poetry_toml: toml::Value = toml::from_str(file_contents).ok()?;
let raw_version = poetry_toml
.get("tool")?
.get("poetry")?
.get("version")?
.as_str()?;
let formatted_version = format_version(raw_version);
Some(formatted_version)
}
fn get_package_version() -> Option<String> {
let cargo_toml = utils::read_file("Cargo.toml");
if let Ok(cargo_toml) = cargo_toml {
return extract_cargo_version(&cargo_toml);
if let Ok(cargo_toml) = utils::read_file("Cargo.toml") {
extract_cargo_version(&cargo_toml)
} else if let Ok(package_json) = utils::read_file("package.json") {
extract_package_version(&package_json)
} else if let Ok(poetry_toml) = utils::read_file("pyproject.toml") {
extract_poetry_version(&poetry_toml)
} else {
None
}
let package_json = utils::read_file("package.json");
if let Ok(package_json) = package_json {
return extract_package_version(&package_json);
}
None
}
fn format_version(version: &str) -> String {
@@ -123,4 +135,32 @@ mod tests {
expected_version
);
}
#[test]
fn test_extract_poetry_version() {
let poetry_with_version = toml::toml! {
[tool.poetry]
name = "starship"
version = "0.1.0"
}
.to_string();
let expected_version = Some("v0.1.0".to_string());
assert_eq!(
extract_poetry_version(&poetry_with_version),
expected_version
);
let poetry_without_version = toml::toml! {
[tool.poetry]
name = "starship"
}
.to_string();
let expected_version = None;
assert_eq!(
extract_poetry_version(&poetry_without_version),
expected_version
);
}
}
+10 -17
View File
@@ -4,8 +4,6 @@ use std::process::Command;
use ansi_term::Color;
use crate::config::Config;
use super::{Context, Module};
/// Creates a module with the current Python version
@@ -15,10 +13,16 @@ use super::{Context, Module};
/// - Current directory contains a `requirements.txt` file
/// - Current directory contains a `pyproject.toml` file
/// - Current directory contains a file with the `.py` extension
/// - Current directory contains a `Pipfile` file
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_py_project = context
.new_scan_dir()
.set_files(&["requirements.txt", ".python-version", "pyproject.toml"])
.set_files(&[
"requirements.txt",
".python-version",
"pyproject.toml",
"Pipfile",
])
.set_extensions(&["py"])
.scan();
@@ -32,7 +36,9 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
.unwrap_or(false);
const PYTHON_CHAR: &str = "🐍 ";
let module_color = Color::Yellow.bold();
let module_color = module
.config_value_style("style")
.unwrap_or_else(|| Color::Yellow.bold());
module.set_style(module_color);
module.new_segment("symbol", PYTHON_CHAR);
@@ -111,17 +117,4 @@ mod tests {
let input = "Python 3.7.2";
assert_eq!(format_python_version(input), "v3.7.2");
}
#[test]
fn test_no_virtual_env() {
env::set_var("VIRTUAL_ENV", "");
assert_eq!(get_python_virtual_env(), None)
}
#[test]
fn test_virtual_env() {
env::set_var("VIRTUAL_ENV", "/foo/bar/my_venv");
assert_eq!(get_python_virtual_env().unwrap(), "my_venv")
}
}
+61
View File
@@ -0,0 +1,61 @@
use ansi_term::Color;
use std::process::Command;
use super::{Context, Module};
/// Creates a module with the current Ruby version
///
/// Will display the Ruby version if any of the following criteria are met:
/// - Current directory contains a `.rb` file
/// - Current directory contains a `Gemfile` file
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let is_rb_project = context
.new_scan_dir()
.set_files(&["Gemfile"])
.set_extensions(&["rb"])
.scan();
if !is_rb_project {
return None;
}
match get_ruby_version() {
Some(ruby_version) => {
const RUBY_CHAR: &str = "💎 ";
let mut module = context.new_module("ruby")?;
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Red.bold());
module.set_style(module_style);
let formatted_version = format_ruby_version(&ruby_version)?;
module.new_segment("symbol", RUBY_CHAR);
module.new_segment("version", &formatted_version);
Some(module)
}
None => None,
}
}
fn get_ruby_version() -> Option<String> {
match Command::new("ruby").arg("-v").output() {
Ok(output) => Some(String::from_utf8(output.stdout).unwrap()),
Err(_) => None,
}
}
fn format_ruby_version(ruby_version: &str) -> Option<String> {
let version = ruby_version
// split into ["ruby", "2.6.0p0", "linux/amd64"]
.split_whitespace()
// return "2.6.0p0"
.nth(1)?
.get(0..5)?;
let mut formatted_version = String::with_capacity(version.len() + 1);
formatted_version.push('v');
formatted_version.push_str(version);
Some(formatted_version)
}
+4 -2
View File
@@ -22,10 +22,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
match get_rust_version() {
Some(rust_version) => {
const RUST_CHAR: &str = "🦀 ";
let module_color = Color::Red.bold();
let mut module = context.new_module("rust")?;
module.set_style(module_color);
let module_style = module
.config_value_style("style")
.unwrap_or_else(|| Color::Red.bold());
module.set_style(module_style);
let formatted_version = format_rustc_version(rust_version);
module.new_segment("symbol", RUST_CHAR);
+14 -13
View File
@@ -6,7 +6,7 @@ use super::{Context, Module};
/// Creates a module with the current user's username
///
/// Will display the usename if any of the following criteria are met:
/// Will display the username if any of the following criteria are met:
/// - The current user isn't the same as the one that is logged in (`$LOGNAME` != `$USER`)
/// - The current user is root (UID = 0)
/// - The user is currently connected as an SSH session (`$SSH_CONNECTION`)
@@ -15,11 +15,12 @@ pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
let logname = env::var("LOGNAME").ok();
let ssh_connection = env::var("SSH_CONNECTION").ok();
let mut module_color = Color::Yellow.bold();
if user != logname || ssh_connection.is_some() || is_root(&mut module_color) {
const ROOT_UID: Option<u32> = Some(0);
let user_uid = get_uid();
if user != logname || ssh_connection.is_some() || user_uid == ROOT_UID {
let mut module = context.new_module("username")?;
module.set_style(module_color);
let module_style = get_mod_style(user_uid, &module);
module.set_style(module_style);
module.new_segment("username", &user?);
return Some(module);
@@ -37,13 +38,13 @@ fn get_uid() -> Option<u32> {
}
}
fn is_root(style: &mut Style) -> bool {
match get_uid() {
Some(uid) if uid == 0 => {
style.clone_from(&Color::Red.bold());
true
}
_ => false,
fn get_mod_style(user_uid: Option<u32>, module: &Module) -> Style {
match user_uid {
Some(0) => module
.config_value_style("style_root")
.unwrap_or_else(|| Color::Red.bold()),
_ => module
.config_value_style("style_user")
.unwrap_or_else(|| Color::Yellow.bold()),
}
}
+46 -3
View File
@@ -5,21 +5,30 @@ use std::io::{self, Write};
use crate::config::Config;
use crate::context::Context;
use crate::module::Module;
use crate::module::ALL_MODULES;
use crate::modules;
const PROMPT_ORDER: &[&str] = &[
// List of default prompt order
// NOTE: If this const value is changed then Default prompt order subheading inside
// prompt heading of config docs needs to be updated according to changes made here.
const DEFAULT_PROMPT_ORDER: &[&str] = &[
"username",
"hostname",
"directory",
"git_branch",
"git_state",
"git_status",
"package",
"nodejs",
"ruby",
"rust",
"python",
"go",
"golang",
"nix_shell",
"cmd_duration",
"line_break",
"jobs",
#[cfg(feature = "battery")]
"battery",
"character",
];
@@ -36,7 +45,41 @@ pub fn prompt(args: ArgMatches) {
writeln!(handle).unwrap();
}
let modules = PROMPT_ORDER
let mut prompt_order: Vec<&str> = Vec::new();
// Write out a custom prompt order
if let Some(modules) = config.get_as_array("prompt_order") {
// if prompt_order = [] use default_prompt_order
if !modules.is_empty() {
for module in modules {
let str_value = module.as_str();
if let Some(value) = str_value {
if ALL_MODULES.contains(&value) {
prompt_order.push(value);
} else {
log::debug!(
"Expected prompt_order to contain value from {:?}. Instead received {}",
ALL_MODULES,
value,
);
}
} else {
log::debug!(
"Expected prompt_order to be an array of strings. Instead received {} of type {}",
module,
module.type_str()
);
}
}
} else {
prompt_order = DEFAULT_PROMPT_ORDER.to_vec();
}
} else {
prompt_order = DEFAULT_PROMPT_ORDER.to_vec();
}
let modules = &prompt_order
.par_iter()
.map(|module| modules::handle(module, &context)) // Compute modules
.flatten()
+2 -1
View File
@@ -1,8 +1,9 @@
use std::fs::File;
use std::io::{Read, Result};
use std::path::Path;
/// Return the string contents of a file
pub fn read_file(file_name: &str) -> Result<String> {
pub fn read_file<P: AsRef<Path>>(file_name: P) -> Result<String> {
let mut file = File::open(file_name)?;
let mut data = String::new();
+11 -1
View File
@@ -16,7 +16,7 @@ RUN curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | ba
RUN node --version
# Install Go
ENV GO_VERSION 1.10.0
ENV GO_VERSION 1.12.1
ENV GOENV_ROOT /home/nonroot/.goenv
ENV PATH $GOENV_ROOT/bin:$GOENV_ROOT/shims:$PATH
RUN git clone https://github.com/syndbg/goenv.git $GOENV_ROOT \
@@ -27,6 +27,16 @@ RUN git clone https://github.com/syndbg/goenv.git $GOENV_ROOT \
# Check that Go was correctly installed
RUN go version
# Install Ruby
ENV RUBY_VERSION 2.6.3
ENV RBENV_ROOT /home/nonroot/.rbenv
ENV PATH $RBENV_ROOT/bin:$RBENV_ROOT/shims:$PATH
RUN curl -fsSL https://github.com/rbenv/rbenv-installer/raw/master/bin/rbenv-installer | bash \
&& rbenv install $RUBY_VERSION \
&& rbenv global $RUBY_VERSION
# Check that Ruby was correctly installed
RUN ruby --version
# Install Python
ENV PYTHON_VERSION 3.6.9
ENV PYENV_ROOT /home/nonroot/.pyenv
BIN
View File
Binary file not shown.
+79 -3
View File
@@ -5,7 +5,7 @@ use crate::common::{self, TestCommand};
#[test]
fn char_module_success_status() -> io::Result<()> {
let expected = format!("{} ", Color::Green.bold().paint(""));
let expected = format!("{} ", Color::Green.bold().paint(""));
// Status code 0
let output = common::render_module("character")
@@ -24,7 +24,7 @@ fn char_module_success_status() -> io::Result<()> {
#[test]
fn char_module_failure_status() -> io::Result<()> {
let expected = format!("{} ", Color::Red.bold().paint(""));
let expected = format!("{} ", Color::Red.bold().paint(""));
let exit_values = ["1", "54321", "-5000"];
@@ -41,7 +41,7 @@ fn char_module_failure_status() -> io::Result<()> {
#[test]
fn char_module_symbolyes_status() -> io::Result<()> {
let expected_fail = format!("{} ", Color::Red.bold().paint(""));
let expected_success = format!("{} ", Color::Green.bold().paint(""));
let expected_success = format!("{} ", Color::Green.bold().paint(""));
let exit_values = ["1", "54321", "-5000"];
@@ -72,3 +72,79 @@ fn char_module_symbolyes_status() -> io::Result<()> {
Ok(())
}
#[test]
fn char_module_zsh_keymap() -> io::Result<()> {
let expected_vicmd = "";
// TODO make this less... well, stupid when ANSI escapes can be mocked out
let expected_specified = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT";
let expected_other = "";
// zle keymap is vicmd
let output = common::render_module("character")
.env("STARSHIP_SHELL", "zsh")
.arg("--keymap=vicmd")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert!(actual.contains(&expected_vicmd));
// specified vicmd character
let output = common::render_module("character")
.use_config(toml::toml! {
[character]
vicmd_symbol = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT"
})
.env("STARSHIP_SHELL", "zsh")
.arg("--keymap=vicmd")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert!(actual.contains(&expected_specified));
// zle keymap is other
let output = common::render_module("character")
.env("STARSHIP_SHELL", "zsh")
.arg("--keymap=visual")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert!(actual.contains(&expected_other));
Ok(())
}
#[test]
fn char_module_fish_keymap() -> io::Result<()> {
let expected_vicmd = "";
// TODO make this less... well, stupid when ANSI escapes can be mocked out
let expected_specified = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT";
let expected_other = "";
// fish keymap is default
let output = common::render_module("character")
.env("STARSHIP_SHELL", "fish")
.arg("--keymap=default")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert!(actual.contains(&expected_vicmd));
// specified vicmd character
let output = common::render_module("character")
.use_config(toml::toml! {
[character]
vicmd_symbol = "I HIGHLY DOUBT THIS WILL SHOW UP IN OTHER OUTPUT"
})
.env("STARSHIP_SHELL", "fish")
.arg("--keymap=default")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert!(actual.contains(&expected_specified));
// fish keymap is other
let output = common::render_module("character")
.env("STARSHIP_SHELL", "fish")
.arg("--keymap=visual")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert!(actual.contains(&expected_other));
Ok(())
}
-3
View File
@@ -1,8 +1,5 @@
use ansi_term::Color;
use std::fs;
use std::io;
use std::path::Path;
use tempfile::TempDir;
use crate::common::{self, TestCommand};
+40 -2
View File
@@ -1,7 +1,9 @@
use lazy_static::lazy_static;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::path::{Path, PathBuf};
use std::{io, process};
use std::process::Command;
use std::{env, fs, io, process};
lazy_static! {
static ref MANIFEST_DIR: &'static Path = Path::new(env!("CARGO_MANIFEST_DIR"));
@@ -24,7 +26,8 @@ pub fn render_prompt() -> process::Command {
/// Render a specific starship module by name
pub fn render_module(module_name: &str) -> process::Command {
let mut command = process::Command::new("./target/debug/starship");
let binary = fs::canonicalize("./target/debug/starship").unwrap();
let mut command = process::Command::new(binary);
command
.arg("module")
@@ -43,6 +46,41 @@ pub fn new_tempdir() -> io::Result<tempfile::TempDir> {
tempfile::tempdir_in("/tmp")
}
/// Create a repo from the fixture to be used in git module tests
pub fn create_fixture_repo() -> io::Result<PathBuf> {
let fixture_repo_path = new_tempdir()?.path().join("fixture");
let repo_path = new_tempdir()?.path().join("rocket");
let fixture_path = env::current_dir()?.join("tests/fixtures/rocket.bundle");
let fixture_repo_dir = path_str(&fixture_repo_path)?;
let repo_dir = path_str(&repo_path)?;
let fixture = path_str(&fixture_path)?;
Command::new("git")
.args(&["clone", "-b", "master", fixture, fixture_repo_dir])
.output()?;
git2::Repository::clone(fixture_repo_dir, repo_dir).ok();
Command::new("git")
.args(&["config", "--local", "user.email", "starship@example.com"])
.current_dir(repo_dir)
.output()?;
Command::new("git")
.args(&["config", "--local", "user.name", "starship"])
.current_dir(repo_dir)
.output()?;
Ok(repo_path)
}
fn path_str(repo_dir: &PathBuf) -> io::Result<&str> {
repo_dir
.to_str()
.ok_or_else(|| Error::from(ErrorKind::Other))
}
/// Extends `std::process::Command` with methods for testing
pub trait TestCommand {
fn use_config(&mut self, toml: toml::value::Value) -> &mut process::Command;
+229 -12
View File
@@ -10,7 +10,13 @@ use crate::common::{self, TestCommand};
#[test]
fn home_directory() -> io::Result<()> {
let output = common::render_module("dir").arg("--path=~").output()?;
let output = common::render_module("directory")
.arg("--path=~")
.use_config(toml::toml! { // Necessary if homedir is a git repo
[directory]
truncate_to_repo = false
})
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("in {} ", Color::Cyan.bold().paint("~"));
@@ -24,7 +30,7 @@ fn directory_in_home() -> io::Result<()> {
let dir = home_dir().unwrap().join("starship/engine");
fs::create_dir_all(&dir)?;
let output = common::render_module("dir")
let output = common::render_module("directory")
.arg("--path")
.arg(dir)
.output()?;
@@ -41,7 +47,7 @@ fn truncated_directory_in_home() -> io::Result<()> {
let dir = home_dir().unwrap().join("starship/engine/schematics");
fs::create_dir_all(&dir)?;
let output = common::render_module("dir")
let output = common::render_module("directory")
.arg("--path")
.arg(dir)
.output()?;
@@ -55,9 +61,33 @@ fn truncated_directory_in_home() -> io::Result<()> {
Ok(())
}
#[test]
#[ignore]
fn fish_directory_in_home() -> io::Result<()> {
let dir = home_dir().unwrap().join("starship/engine/schematics");
fs::create_dir_all(&dir)?;
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
truncation_length = 1
fish_style_pwd_dir_length = 2
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("in {} ", Color::Cyan.bold().paint("~/st/en/schematics"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn root_directory() -> io::Result<()> {
let output = common::render_module("dir").arg("--path=/").output()?;
let output = common::render_module("directory")
.arg("--path=/")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("in {} ", Color::Cyan.bold().paint("/"));
@@ -66,11 +96,25 @@ fn root_directory() -> io::Result<()> {
}
#[test]
#[cfg(not(target_os = "windows"))]
fn directory_in_root() -> io::Result<()> {
let output = common::render_module("dir").arg("--path=/usr").output()?;
let output = common::render_module("directory")
.arg("--path=/etc")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("in {} ", Color::Cyan.bold().paint("/usr"));
let expected = format!("in {} ", Color::Cyan.bold().paint("/etc"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[cfg(target_os = "windows")]
fn directory_in_root() -> io::Result<()> {
let output = common::render_module("dir").arg("--path=C:\\").output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("in {} ", Color::Cyan.bold().paint("/c"));
assert_eq!(expected, actual);
Ok(())
}
@@ -81,7 +125,7 @@ fn truncated_directory_in_root() -> io::Result<()> {
let dir = Path::new("/tmp/starship/thrusters/rocket");
fs::create_dir_all(&dir)?;
let output = common::render_module("dir")
let output = common::render_module("directory")
.arg("--path")
.arg(dir)
.output()?;
@@ -101,7 +145,7 @@ fn truncated_directory_config_large() -> io::Result<()> {
let dir = Path::new("/tmp/starship/thrusters/rocket");
fs::create_dir_all(&dir)?;
let output = common::render_module("dir")
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
truncation_length = 100
@@ -119,13 +163,38 @@ fn truncated_directory_config_large() -> io::Result<()> {
Ok(())
}
#[test]
#[ignore]
fn fish_style_directory_config_large() -> io::Result<()> {
let dir = Path::new("/tmp/starship/thrusters/rocket");
fs::create_dir_all(&dir)?;
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
truncation_length = 1
fish_style_pwd_dir_length = 100
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!(
"in {} ",
Color::Cyan.bold().paint("/tmp/starship/thrusters/rocket")
);
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn truncated_directory_config_small() -> io::Result<()> {
let dir = Path::new("/tmp/starship/thrusters/rocket");
fs::create_dir_all(&dir)?;
let output = common::render_module("dir")
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
truncation_length = 2
@@ -140,6 +209,28 @@ fn truncated_directory_config_small() -> io::Result<()> {
Ok(())
}
#[test]
#[ignore]
fn fish_directory_config_small() -> io::Result<()> {
let dir = Path::new("/tmp/starship/thrusters/rocket");
fs::create_dir_all(&dir)?;
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
truncation_length = 2
fish_style_pwd_dir_length = 1
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("in {} ", Color::Cyan.bold().paint("/t/s/thrusters/rocket"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn git_repo_root() -> io::Result<()> {
@@ -151,7 +242,7 @@ fn git_repo_root() -> io::Result<()> {
fs::create_dir(&repo_dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("dir")
let output = common::render_module("directory")
.arg("--path")
.arg(repo_dir)
.output()?;
@@ -171,7 +262,7 @@ fn directory_in_git_repo() -> io::Result<()> {
fs::create_dir_all(&dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("dir")
let output = common::render_module("directory")
.arg("--path")
.arg(dir)
.output()?;
@@ -191,7 +282,7 @@ fn truncated_directory_in_git_repo() -> io::Result<()> {
fs::create_dir_all(&dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("dir")
let output = common::render_module("directory")
.arg("--path")
.arg(dir)
.output()?;
@@ -201,3 +292,129 @@ fn truncated_directory_in_git_repo() -> io::Result<()> {
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn directory_in_git_repo_truncate_to_repo_false() -> io::Result<()> {
let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?;
let repo_dir = tmp_dir.path().join("above-repo").join("rocket-controls");
let dir = repo_dir.join("src/meters/fuel-gauge");
fs::create_dir_all(&dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
// Don't truncate the path at all.
truncation_length = 5
truncate_to_repo = false
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!(
"in {} ",
Color::Cyan
.bold()
.paint("above-repo/rocket-controls/src/meters/fuel-gauge")
);
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn fish_path_directory_in_git_repo_truncate_to_repo_false() -> io::Result<()> {
let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?;
let repo_dir = tmp_dir.path().join("above-repo").join("rocket-controls");
let dir = repo_dir.join("src/meters/fuel-gauge");
fs::create_dir_all(&dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
// Don't truncate the path at all.
truncation_length = 5
truncate_to_repo = false
fish_style_pwd_dir_length = 1
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!(
"in {} ",
Color::Cyan
.bold()
.paint("~/.t/above-repo/rocket-controls/src/meters/fuel-gauge")
);
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn fish_path_directory_in_git_repo_truncate_to_repo_true() -> io::Result<()> {
let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?;
let repo_dir = tmp_dir.path().join("above-repo").join("rocket-controls");
let dir = repo_dir.join("src/meters/fuel-gauge");
fs::create_dir_all(&dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
// `truncate_to_repo = true` should display the truncated path
truncation_length = 5
truncate_to_repo = true
fish_style_pwd_dir_length = 1
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!(
"in {} ",
Color::Cyan
.bold()
.paint("~/.t/a/rocket-controls/src/meters/fuel-gauge")
);
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn directory_in_git_repo_truncate_to_repo_true() -> io::Result<()> {
let tmp_dir = TempDir::new_in(dirs::home_dir().unwrap())?;
let repo_dir = tmp_dir.path().join("above-repo").join("rocket-controls");
let dir = repo_dir.join("src/meters/fuel-gauge");
fs::create_dir_all(&dir)?;
Repository::init(&repo_dir).unwrap();
let output = common::render_module("directory")
.use_config(toml::toml! {
[directory]
// `truncate_to_repo = true` should display the truncated path
truncation_length = 5
truncate_to_repo = true
})
.arg("--path")
.arg(dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!(
"in {} ",
Color::Cyan
.bold()
.paint("rocket-controls/src/meters/fuel-gauge")
);
assert_eq!(expected, actual);
Ok(())
}
+141
View File
@@ -0,0 +1,141 @@
use ansi_term::Color;
use git2::Repository;
use std::env;
use std::io;
use std::process::Command;
use crate::common::{self, TestCommand};
#[test]
fn test_changed_truncation_symbol() -> io::Result<()> {
test_truncate_length_with_config(
"1337_hello_world",
15,
"1337_hello_worl",
"%",
"truncation_symbol = \"%\"",
)
}
#[test]
fn test_no_truncation_symbol() -> io::Result<()> {
test_truncate_length_with_config(
"1337_hello_world",
15,
"1337_hello_worl",
"",
"truncation_symbol = \"\"",
)
}
#[test]
fn test_multi_char_truncation_symbol() -> io::Result<()> {
test_truncate_length_with_config(
"1337_hello_world",
15,
"1337_hello_worl",
"a",
"truncation_symbol = \"apple\"",
)
}
#[test]
fn test_ascii_boundary_below() -> io::Result<()> {
test_truncate_length("1337_hello_world", 15, "1337_hello_worl", "")
}
#[test]
fn test_ascii_boundary_on() -> io::Result<()> {
test_truncate_length("1337_hello_world", 16, "1337_hello_world", "")
}
#[test]
fn test_ascii_boundary_above() -> io::Result<()> {
test_truncate_length("1337_hello_world", 17, "1337_hello_world", "")
}
#[test]
fn test_one() -> io::Result<()> {
test_truncate_length("1337_hello_world", 1, "1", "")
}
#[test]
fn test_zero() -> io::Result<()> {
test_truncate_length("1337_hello_world", 0, "1337_hello_world", "")
}
#[test]
fn test_negative() -> io::Result<()> {
test_truncate_length("1337_hello_world", -1, "1337_hello_world", "")
}
#[test]
fn test_hindi_truncation() -> io::Result<()> {
test_truncate_length("नमस्ते", 3, "नमस्", "")
}
#[test]
fn test_hindi_truncation2() -> io::Result<()> {
test_truncate_length("नमस्त", 3, "नमस्", "")
}
#[test]
fn test_japanese_truncation() -> io::Result<()> {
test_truncate_length("がんばってね", 4, "がんばっ", "")
}
fn test_truncate_length(
branch_name: &str,
truncate_length: i64,
expected_name: &str,
truncation_symbol: &str,
) -> io::Result<()> {
test_truncate_length_with_config(
branch_name,
truncate_length,
expected_name,
truncation_symbol,
"",
)
}
fn test_truncate_length_with_config(
branch_name: &str,
truncate_length: i64,
expected_name: &str,
truncation_symbol: &str,
config_options: &str,
) -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["checkout", "-b", branch_name])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_branch")
.use_config(
toml::from_str(&format!(
"
[git_branch]
truncation_length = {}
{}
",
truncate_length, config_options
))
.unwrap(),
)
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!(
"on {} ",
Color::Purple
.bold()
.paint(format!("\u{e0a0} {}{}", expected_name, truncation_symbol)),
);
assert_eq!(expected, actual);
Ok(())
}
+177
View File
@@ -0,0 +1,177 @@
use super::common;
use std::ffi::OsStr;
use std::fs::OpenOptions;
use std::io::{self, Error, ErrorKind, Write};
use std::process::{Command, Stdio};
#[test]
#[ignore]
fn shows_rebasing() -> io::Result<()> {
let repo_dir = create_repo_with_conflict()?;
let path = path_str(&repo_dir)?;
run_git_cmd(&["rebase", "other-branch"], Some(path), false)?;
let output = common::render_module("git_state")
.current_dir(path)
.output()?;
let text = String::from_utf8(output.stdout).unwrap();
assert!(text.contains("REBASING 1/1"));
Ok(())
}
#[test]
#[ignore]
fn shows_merging() -> io::Result<()> {
let repo_dir = create_repo_with_conflict()?;
let path = path_str(&repo_dir)?;
run_git_cmd(&["merge", "other-branch"], Some(path), false)?;
let output = common::render_module("git_state")
.current_dir(path)
.output()?;
let text = String::from_utf8(output.stdout).unwrap();
assert!(text.contains("MERGING"));
Ok(())
}
#[test]
#[ignore]
fn shows_cherry_picking() -> io::Result<()> {
let repo_dir = create_repo_with_conflict()?;
let path = path_str(&repo_dir)?;
run_git_cmd(&["cherry-pick", "other-branch"], Some(path), false)?;
let output = common::render_module("git_state")
.current_dir(path)
.output()?;
let text = String::from_utf8(output.stdout).unwrap();
assert!(text.contains("CHERRY-PICKING"));
Ok(())
}
#[test]
#[ignore]
fn shows_bisecting() -> io::Result<()> {
let repo_dir = create_repo_with_conflict()?;
let path = path_str(&repo_dir)?;
run_git_cmd(&["bisect", "start"], Some(path), false)?;
let output = common::render_module("git_state")
.current_dir(path)
.output()?;
let text = String::from_utf8(output.stdout).unwrap();
assert!(text.contains("BISECTING"));
Ok(())
}
#[test]
#[ignore]
fn shows_reverting() -> io::Result<()> {
let repo_dir = create_repo_with_conflict()?;
let path = path_str(&repo_dir)?;
run_git_cmd(&["revert", "--no-commit", "HEAD~1"], Some(path), false)?;
let output = common::render_module("git_state")
.current_dir(path)
.output()?;
let text = String::from_utf8(output.stdout).unwrap();
assert!(text.contains("REVERTING"));
Ok(())
}
fn run_git_cmd<A, S>(args: A, dir: Option<&str>, expect_ok: bool) -> io::Result<()>
where
A: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let mut command = Command::new("git");
command
.args(args)
.stdout(Stdio::null())
.stderr(Stdio::null())
.stdin(Stdio::null());
if let Some(dir) = dir {
command.current_dir(dir);
}
let status = command.status()?;
if expect_ok && !status.success() {
Err(Error::from(ErrorKind::Other))
} else {
Ok(())
}
}
fn create_repo_with_conflict() -> io::Result<tempfile::TempDir> {
let repo_dir = common::new_tempdir()?;
let path = path_str(&repo_dir)?;
let conflicted_file = repo_dir.path().join("the_file");
let write_file = |text: &str| {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(&conflicted_file)?;
write!(file, "{}", text)
};
// Initialise a new git repo
run_git_cmd(&["init", "--quiet", path], None, true)?;
// Set local author info
run_git_cmd(
&["config", "--local", "user.email", "starship@example.com"],
Some(path),
true,
)?;
run_git_cmd(
&["config", "--local", "user.name", "starship"],
Some(path),
true,
)?;
// Write a file on master and commit it
write_file("Version A")?;
run_git_cmd(&["add", "the_file"], Some(path), true)?;
run_git_cmd(&["commit", "--message", "Commit A"], Some(path), true)?;
// Switch to another branch, and commit a change to the file
run_git_cmd(&["checkout", "-b", "other-branch"], Some(path), true)?;
write_file("Version B")?;
run_git_cmd(
&["commit", "--all", "--message", "Commit B"],
Some(path),
true,
)?;
// Switch back to master, and commit a third change to the file
run_git_cmd(&["checkout", "master"], Some(path), true)?;
write_file("Version C")?;
run_git_cmd(
&["commit", "--all", "--message", "Commit C"],
Some(path),
true,
)?;
Ok(repo_dir)
}
fn path_str(repo_dir: &tempfile::TempDir) -> io::Result<&str> {
repo_dir
.path()
.to_str()
.ok_or_else(|| Error::from(ErrorKind::Other))
}
+374
View File
@@ -0,0 +1,374 @@
use ansi_term::Color;
use git2::Repository;
use std::env;
use std::fs::{self, File};
use std::io;
use std::process::Command;
use crate::common::{self, TestCommand};
#[test]
#[ignore]
fn shows_behind() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["reset", "--hard", "HEAD^"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_behind_with_count() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["reset", "--hard", "HEAD^"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.use_config(toml::toml! {
[git_status]
show_sync_count = true
})
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red
.bold()
.paint(format!("[{}] ", "⇣1"))
.to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_ahead() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("readme.md"))?;
Command::new("git")
.args(&["commit", "-am", "Update readme"])
.current_dir(&repo_dir)
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_ahead_with_count() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("readme.md"))?;
Command::new("git")
.args(&["commit", "-am", "Update readme"])
.current_dir(&repo_dir)
.output()?;
let output = common::render_module("git_status")
.use_config(toml::toml! {
[git_status]
show_sync_count = true
})
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red
.bold()
.paint(format!("[{}] ", "⇡1"))
.to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_diverged() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["reset", "--hard", "HEAD^"])
.current_dir(repo_dir.as_path())
.output()?;
fs::write(repo_dir.join("Cargo.toml"), " ")?;
Command::new("git")
.args(&["commit", "-am", "Update readme"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_diverged_with_count() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["reset", "--hard", "HEAD^"])
.current_dir(repo_dir.as_path())
.output()?;
fs::write(repo_dir.join("Cargo.toml"), " ")?;
Command::new("git")
.args(&["commit", "-am", "Update readme"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.use_config(toml::toml! {
[git_status]
show_sync_count = true
})
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red
.bold()
.paint(format!("[{}] ", "⇕⇡1⇣1"))
.to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_conflicted() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["reset", "--hard", "HEAD^"])
.current_dir(repo_dir.as_path())
.output()?;
fs::write(repo_dir.join("readme.md"), "# goodbye")?;
Command::new("git")
.args(&["add", "."])
.current_dir(repo_dir.as_path())
.output()?;
Command::new("git")
.args(&["commit", "-m", "Change readme"])
.current_dir(repo_dir.as_path())
.output()?;
Command::new("git")
.args(&["pull", "--rebase"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "=")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_untracked_file() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("license"))?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "?")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn doesnt_show_untracked_file_if_disabled() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("license"))?;
Command::new("git")
.args(&["config", "status.showUntrackedFiles", "no"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = "";
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_stashed() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("readme.md"))?;
Command::new("git")
.arg("stash")
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "$")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_modified() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("readme.md"))?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "!")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_staged_file() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
File::create(repo_dir.join("license"))?;
Command::new("git")
.args(&["add", "."])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "+")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_renamed_file() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
Command::new("git")
.args(&["mv", "readme.md", "readme.md.bak"])
.current_dir(repo_dir.as_path())
.output()?;
Command::new("git")
.args(&["add", "-A"])
.current_dir(repo_dir.as_path())
.output()?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "»")).to_string();
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn shows_deleted_file() -> io::Result<()> {
let repo_dir = common::create_fixture_repo()?;
fs::remove_file(repo_dir.join("readme.md"))?;
let output = common::render_module("git_status")
.arg("--path")
.arg(repo_dir)
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = Color::Red.bold().paint(format!("[{}] ", "")).to_string();
assert_eq!(expected, actual);
Ok(())
}
+29 -8
View File
@@ -2,7 +2,7 @@ use ansi_term::Color;
use std::fs::{self, File};
use std::io;
use crate::common;
use crate::common::{self, TestCommand};
#[test]
fn folder_without_go_files() -> io::Result<()> {
@@ -31,7 +31,7 @@ fn folder_with_go_file() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
@@ -48,7 +48,7 @@ fn folder_with_go_mod() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
@@ -65,7 +65,7 @@ fn folder_with_go_sum() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
@@ -83,7 +83,7 @@ fn folder_with_godeps() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
@@ -100,7 +100,7 @@ fn folder_with_glide_yaml() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
@@ -117,7 +117,7 @@ fn folder_with_gopkg_yml() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
@@ -134,7 +134,28 @@ fn folder_with_gopkg_lock() -> io::Result<()> {
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.10"));
let expected = format!("via {} ", Color::Cyan.bold().paint("🐹 v1.12.1"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn config_disabled() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("main.go"))?;
let output = common::render_module("golang")
.use_config(toml::toml! {
[golang]
disabled = true
})
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = "";
assert_eq!(expected, actual);
Ok(())
}
+117
View File
@@ -0,0 +1,117 @@
use ansi_term::{Color, Style};
use std::io;
use crate::common;
use crate::common::TestCommand;
#[test]
fn ssh_only_false() -> io::Result<()> {
let hostname = match get_hostname() {
Some(h) => h,
None => return hostname_not_tested(),
};
let output = common::render_module("hostname")
.env_clear()
.use_config(toml::toml! {
[hostname]
ssh_only = false
})
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("on {} ", style().paint(hostname));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn no_ssh() -> io::Result<()> {
let output = common::render_module("hostname")
.env_clear()
.use_config(toml::toml! {
[hostname]
ssh_only = true
})
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert_eq!("", actual);
Ok(())
}
#[test]
fn ssh() -> io::Result<()> {
let hostname = match get_hostname() {
Some(h) => h,
None => return hostname_not_tested(),
};
let output = common::render_module("hostname")
.env_clear()
.use_config(toml::toml! {
[hostname]
ssh_only = true
})
.env("SSH_CONNECTION", "something")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("on {} ", style().paint(hostname));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn prefix() -> io::Result<()> {
let hostname = match get_hostname() {
Some(h) => h,
None => return hostname_not_tested(),
};
let output = common::render_module("hostname")
.env_clear()
.use_config(toml::toml! {
[hostname]
ssh_only = false
prefix = "<"
})
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("on {} ", style().paint(format!("<{}", hostname)));
assert_eq!(actual, expected);
Ok(())
}
#[test]
fn suffix() -> io::Result<()> {
let hostname = match get_hostname() {
Some(h) => h,
None => return hostname_not_tested(),
};
let output = common::render_module("hostname")
.env_clear()
.use_config(toml::toml! {
[hostname]
ssh_only = false
suffix = ">"
})
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("on {} ", style().paint(format!("{}>", hostname)));
assert_eq!(actual, expected);
Ok(())
}
fn get_hostname() -> Option<String> {
match gethostname::gethostname().into_string() {
Ok(hostname) => Some(hostname),
Err(_) => None,
}
}
fn style() -> Style {
Color::Green.bold().dimmed()
}
fn hostname_not_tested() -> io::Result<()> {
println!(
"hostname was not tested because gethostname failed! \
This could be caused by your hostname containing invalid UTF."
);
Ok(())
}
-3
View File
@@ -1,8 +1,5 @@
use ansi_term::Color;
use std::fs;
use std::io;
use std::path::Path;
use tempfile::TempDir;
use crate::common::{self, TestCommand};
+7
View File
@@ -3,9 +3,16 @@ mod cmd_duration;
mod common;
mod configuration;
mod directory;
mod git_branch;
mod git_state;
mod git_status;
mod golang;
mod hostname;
mod jobs;
mod line_break;
mod modules;
mod nix_shell;
mod nodejs;
mod python;
mod ruby;
mod username;
+31
View File
@@ -0,0 +1,31 @@
use std::io;
use crate::common;
#[test]
fn unknown_module_name() -> io::Result<()> {
let unknown_module_name = "some_random_name";
let output = common::render_module(unknown_module_name).output()?;
let actual_stdout = String::from_utf8(output.stdout).unwrap();
let actual_stderr = String::from_utf8(output.stderr).unwrap();
let expected_stdout = "";
let expected_stderr = format!(
"Error: Unknown module {}. Use starship module --list to list out all supported modules.\n",
unknown_module_name
);
assert_eq!(expected_stdout, actual_stdout);
assert_eq!(expected_stderr, actual_stderr);
Ok(())
}
#[test]
fn known_module_name() -> io::Result<()> {
let output = common::render_module("line_break").output()?;
let actual_stdout = String::from_utf8(output.stdout).unwrap();
let actual_stderr = String::from_utf8(output.stderr).unwrap();
let expected_stdout = "\n";
let expected_stderr = "";
assert_eq!(expected_stdout, actual_stdout);
assert_eq!(expected_stderr, actual_stderr);
Ok(())
}
+58
View File
@@ -0,0 +1,58 @@
use ansi_term::Color;
use std::io;
use crate::common;
#[test]
fn no_env_variables() -> io::Result<()> {
let output = common::render_module("nix_shell").output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert_eq!("", actual);
Ok(())
}
#[test]
fn invalid_env_variables() -> io::Result<()> {
let output = common::render_module("nix_shell")
.env("IN_NIX_SHELL", "something_wrong")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert_eq!("", actual);
Ok(())
}
#[test]
fn pure_shell() -> io::Result<()> {
let output = common::render_module("nix_shell")
.env("IN_NIX_SHELL", "pure")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Red.bold().paint("pure"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn impure_shell() -> io::Result<()> {
let output = common::render_module("nix_shell")
.env("IN_NIX_SHELL", "impure")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Red.bold().paint("impure"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
fn lorri_shell() -> io::Result<()> {
let output = common::render_module("nix_shell")
.env("IN_NIX_SHELL", "1")
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Red.bold().paint("impure"));
assert_eq!(expected, actual);
Ok(())
}
+22 -1
View File
@@ -2,7 +2,7 @@ use ansi_term::Color;
use std::fs::{self, File};
use std::io;
use crate::common;
use crate::common::{self, TestCommand};
#[test]
fn folder_without_node_files() -> io::Result<()> {
@@ -70,3 +70,24 @@ fn folder_with_node_modules() -> io::Result<()> {
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn config_disabled() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("package.json"))?;
let output = common::render_module("nodejs")
.use_config(toml::toml! {
[nodejs]
disabled = true
})
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = "";
assert_eq!(expected, actual);
Ok(())
}
View File
+17 -40
View File
@@ -4,7 +4,6 @@ use std::io;
use ansi_term::Color;
use crate::common;
use crate::common::TestCommand;
#[test]
#[ignore]
@@ -57,6 +56,23 @@ fn folder_with_pyproject_toml() -> io::Result<()> {
Ok(())
}
#[test]
#[ignore]
fn folder_with_pipfile() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("Pipfile"))?;
let output = common::render_module("python")
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 v3.6.9"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn folder_with_py_file() -> io::Result<()> {
@@ -93,42 +109,3 @@ fn with_virtual_env() -> io::Result<()> {
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn with_pyenv() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("main.py"))?;
let output = common::render_module("python")
.use_config(toml::toml! {
[python]
pyenv_version_name = true
})
.env("VIRTUAL_ENV", "/foo/bar/my_venv")
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Yellow.bold().paint("🐍 pyenv system"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn with_pyenv_no_output() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("main.py"))?;
let output = common::render_module("python")
.use_config(toml::toml! {
[python]
pyenv_version_name = true
})
.env("PATH", "")
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
assert_eq!("", actual);
Ok(())
}
+54
View File
@@ -0,0 +1,54 @@
use ansi_term::Color;
use std::fs::File;
use std::io;
use crate::common;
#[test]
fn folder_without_ruby_files() -> io::Result<()> {
let dir = common::new_tempdir()?;
let output = common::render_module("ruby")
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = "";
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn folder_with_gemfile() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("Gemfile"))?;
let output = common::render_module("ruby")
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Red.bold().paint("💎 v2.6.3"));
assert_eq!(expected, actual);
Ok(())
}
#[test]
#[ignore]
fn folder_with_rb_file() -> io::Result<()> {
let dir = common::new_tempdir()?;
File::create(dir.path().join("any.rb"))?;
let output = common::render_module("ruby")
.arg("--path")
.arg(dir.path())
.output()?;
let actual = String::from_utf8(output.stdout).unwrap();
let expected = format!("via {} ", Color::Red.bold().paint("💎 v2.6.3"));
assert_eq!(expected, actual);
Ok(())
}