├── LICENSE ├── README.md ├── git.elv ├── screenshots └── powerline.png └── theme ├── muesli.elv └── powerline.elv /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Christian Muehlhaeuser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elvish-libs 2 | Libs & Themes for [elvish](https://github.com/elves/elvish) 3 | 4 | ## Install 5 | 6 | Make sure you run elvish 0.11 or newer. Install this module by running the 7 | following commands in your shell: 8 | 9 | ``` 10 | use epm 11 | epm:install github.com/muesli/elvish-libs 12 | ``` 13 | 14 | ## Themes 15 | 16 | ### powerline 17 | 18 | ![powerline](screenshots/powerline.png) 19 | 20 | To use the `powerline` theme, put this line in your `rc.elv`: 21 | 22 | ``` 23 | use github.com/muesli/elvish-libs/theme/powerline 24 | set edit:prompt-stale-transform = {|x| put $x } 25 | set edit:rprompt-stale-transform = {|x| put $x } 26 | ``` 27 | 28 | ## Modules 29 | 30 | ### git 31 | 32 | The `git` module provides convenient elvish functions to extract stats from a 33 | git repository. It lets you query the repo how many commits you are ahead or 34 | behind of master and how many files have been changed or added to it. 35 | 36 | Enjoy! 37 | -------------------------------------------------------------------------------- /git.elv: -------------------------------------------------------------------------------- 1 | # 2 | # Git methods for elvish 3 | # Copyright (c) 2017-2018, Christian Muehlhaeuser 4 | # Diego Zamboni 5 | # 6 | # For license see LICENSE 7 | # 8 | # To use this module, first install it via epm: 9 | # use epm 10 | # epm:install github.com/muesli/elvish-libs 11 | # 12 | # Then add the following line to import it somewhere: 13 | # use github.com/muesli/elvish-libs/git 14 | # 15 | 16 | use re 17 | 18 | # You can configure the commands to use here - only change if you know 19 | # what you are doing. 20 | 21 | # The status command must produce output in Porcelain v2 format. See 22 | # https://git-scm.com/docs/git-status for details 23 | var git-status-cmd = { git --no-optional-locks status --porcelain=v2 --branch --ignore-submodules=all 2>&- } 24 | 25 | # Get remotes 26 | var git-remote-cmd = { git remote 2>&- } 27 | 28 | # Switch statement to make the code in `status` simpler 29 | fn -switch {|a b| 30 | if (has-key $b $a) { 31 | $b[$a] 32 | } 33 | } 34 | 35 | # Runs $git-status-cmd, parses it and returns a data structure with 36 | # information. If &counts=$true, it precomputes the element count for 37 | # all key elements, and adds them in the result with the same names 38 | # but with "-count" at the end. 39 | fn status {|&counts=$false| 40 | var staged-modified = [] 41 | var staged-deleted = [] 42 | var staged-added = [] 43 | var local-modified = [] 44 | var local-deleted = [] 45 | var untracked = [] 46 | var unmerged = [] 47 | var ignored = [] 48 | var renamed = [] 49 | var copied = [] 50 | var branch-name = "" 51 | var branch-oid = "" 52 | var rev-ahead = 0 53 | var rev-behind = 0 54 | var is-git-repo = $false 55 | 56 | var is-ok = ?($git-status-cmd | eawk {|line @f| 57 | # pprint "@f=" $f 58 | -switch $f[0] [ 59 | &"#"= { 60 | -switch $f[1] [ 61 | &"branch.head"= { set branch-name = $f[2] } 62 | &"branch.oid"= { set branch-oid = $f[2] } 63 | &"branch.ab"= { 64 | set rev-ahead = (re:find '\+(\d+)' $f[2])[groups][1][text] 65 | set rev-behind = (re:find '-(\d+)' $f[3])[groups][1][text] 66 | } 67 | ] 68 | } 69 | &"1"= { 70 | -switch $f[1] [ 71 | &"M."= { set staged-modified = [ $@staged-modified $f[8] ] } 72 | &".M"= { set local-modified = [ $@local-modified $f[8] ] } 73 | &"MM"= { set staged-modified = [ $@staged-modified $f[8] ]; set local-modified = [ $@local-modified $f[8] ] } 74 | &"D."= { set staged-deleted = [ $@staged-deleted $f[8] ] } 75 | &".D"= { set local-deleted = [ $@local-deleted $f[8] ] } 76 | &"DD"= { set staged-deleted = [ $@staged-deleted $f[8] ]; set local-deleted = [ $@local-deleted $f[8] ] } 77 | &"A."= { set staged-added = [ $@staged-added $f[8] ] } 78 | ] 79 | } 80 | &"2"= { 81 | if (re:match '(\.C|C\.)' $f[1]) { 82 | set copied = [ $@copied $f[9] ] 83 | } elif (re:match '(\.R|R\.)' $f[1]) { 84 | set renamed = [ $@renamed $f[9] ] 85 | } 86 | } 87 | &"?"= { set untracked = [ $@untracked $f[1] ] } 88 | &"!"= { set ignored = [ $@ignored $f[1] ] } 89 | &"u"= { set unmerged = [ $@unmerged $f[10] ] } 90 | ] 91 | } 92 | ) 93 | 94 | var result = [ 95 | &staged-modified= $staged-modified 96 | &staged-deleted= $staged-deleted 97 | &staged-added= $staged-added 98 | &local-modified= $local-modified 99 | &local-deleted= $local-deleted 100 | &untracked= $untracked 101 | &unmerged= $unmerged 102 | &ignored= $ignored 103 | &renamed= $renamed 104 | &copied= $copied 105 | &branch-name= $branch-name 106 | &branch-oid= $branch-oid 107 | &rev-ahead= $rev-ahead 108 | &rev-behind= $rev-behind 109 | &is-git-repo= (bool $is-ok) 110 | ] 111 | if $counts { 112 | keys $result | each {|k| 113 | if (eq (kind-of $result[$k]) list) { 114 | set result[$k'-count'] = (count $result[$k]) 115 | } 116 | } 117 | } 118 | put $result 119 | } 120 | 121 | # Return the git branch name of the current directory 122 | fn branch_name { 123 | put (status)[branch-name] 124 | } 125 | 126 | # Return how many commits this repo is ahead & behind of master 127 | fn rev_count { 128 | var data = (status) 129 | put $data[rev-ahead] $data[rev-behind] 130 | } 131 | 132 | # Return how many files in the current git repo are "dirty" (modified in any way) or untracked 133 | fn change_count { 134 | var data = (status) 135 | put (count $data[local-modified]) (count $data[untracked]) (count $data[local-deleted]) 136 | } 137 | 138 | # Return how many files in the current git repo are staged 139 | fn staged_count { 140 | var data = (status) 141 | + (count $data[staged-modified]) (count $data[staged-deleted]) (count $data[staged-added]) (count $data[renamed]) (count $data[copied]) 142 | } 143 | 144 | # Automatically "git rm" files which have been deleted from the file 145 | # system. Can be used to clean up when you remove files by hand before 146 | # telling git about it. Use with care. 147 | fn auto-rm { 148 | all (status)[local-deleted] | each {|f| 149 | echo (edit:styled "Removing "$f red) 150 | git rm $f 151 | } 152 | } 153 | 154 | fn remotes { 155 | set _ = ?($git-remote-cmd) 156 | } 157 | 158 | fn remotes-transform {|transform-fn @remotes| 159 | if (eq $remotes []) { 160 | set remotes = [(remotes)] 161 | } 162 | each {|r| 163 | var url = (git remote get-url $r) 164 | var new-url = ($transform-fn $url) 165 | if (not-eq $url $new-url) { 166 | git remote set-url $r $new-url 167 | echo (edit:styled "Moved remote "$r" from "$url" to "$new-url green) 168 | } 169 | } $remotes 170 | } 171 | 172 | fn remotes-ssh-to-https {|@remotes| 173 | remotes-transform {|url| re:replace 'git(?:@|://)(.*)[:/](.*)/(.*)' 'https://$1/$2/$3' $url } $@remotes 174 | } 175 | 176 | fn remotes-https-to-ssh {|@remotes| 177 | remotes-transform {|url| re:replace 'https://(.*)/(.*)/(.*)' 'git@$1:$2/$3' $url } $@remotes 178 | } 179 | -------------------------------------------------------------------------------- /screenshots/powerline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/muesli/elvish-libs/bfdc441990d95eec02489e071418a8718f3e3794/screenshots/powerline.png -------------------------------------------------------------------------------- /theme/muesli.elv: -------------------------------------------------------------------------------- 1 | # Muesli's prompt theme, based on the fish theme at https://github.com/oh-my-fish/theme-chain 2 | # Ported to Elvish by Diego Zamboni 3 | # Personal style changes by Christian Muehlhaeuser 4 | # 5 | # To use, put this file in ~/.elvish/lib/theme and add the following to your ~/.elvish/rc.elv file: 6 | # use theme:muesli 7 | # theme:muesli:setup 8 | # 9 | # You can also assign the prompt functions manually instead of calling `theme:muesli:setup`: 10 | # edit:prompt = $theme:muesli:&prompt 11 | # edit:rprompt = $theme:muesli:&rprompt 12 | # 13 | # The chains on both sides can be configured by assigning to `theme:muesli:prompt_segments` and 14 | # `theme:muesli:rprompt_segments`, respectively. These variables must be arrays, and the given 15 | # segments will be automatically linked by `$theme:muesli:glyph[chain]`. Each element can be any 16 | # of the following: 17 | # 18 | # - The name of one of the built-in segments. Available segments: `prefix` `userhost` `arrow` `timestamp` `su` `dir` `git_branch` `git_dirty` 19 | # - A string or the output of `edit:styled`, which will be displayed as-is. 20 | # - A lambda, which will be called and its output displayed 21 | # - The output of a call to `theme:muesli:segment