├── .gitignore
├── README.md
├── autoload
└── onestatus.vim
└── plugin
└── onestatus.vim
/.gitignore:
--------------------------------------------------------------------------------
1 | tags
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | *Disclaimer*: This plugin has been tested with neovim so vim support is not garanteed. Feel free to open a PR if you want to contribute !
2 |
3 | # Motivation
4 | OneStatus is an interface that helps you interact with your tmux.
5 | One of my goal with it was to get rid of vim's redundant statusline and instead use tmux's.
6 |
7 | Much better !
8 |
9 | 
10 |
11 | # Requirements
12 | If you just want to quickly use the plugin :
13 | - a font that supports powerline to have those nice arrow separators
14 | - https://github.com/tpope/vim-fugitive or https://github.com/itchyny/vim-gitbranch installed to display your git head
15 | - copy the `onestatus.json` example given below (this file must be present in your vim config directory)
16 |
17 | If you want to play with the API :
18 | - make sure to disable the default config by setting
19 | `let g:onestatus_default_layout = 0`
20 | - create your own personal `onestatus.json`
21 | Have fun !
22 |
23 | # Usage
24 | Since v0.2.0 you can very easily customize your statusline via a `onestatus.json` file that you put in your **config folder ($HOME for vim and $HOME/.config/nvim for nvim)**.
25 | If you want another path you can override `g:onestatus_config_path`
26 | Here's an example of configuration file that you can copy
27 |
28 | ```json
29 | {
30 | "status-right": [
31 | { "fg": "#ffd167", "bg": "default", "label": "" },
32 | { "fg": "#218380", "bg": "#ffd167", "labelFunc": "s:getCWD" },
33 | { "fg": "#218380", "bg": "#ffd167", "label": "" },
34 | { "fg": "#fcfcfc", "bg": "#218380", "labelFunc": "s:getHead" }
35 | ],
36 | "status-left": [
37 | { "fg": "default", "bg": "default", "labelFunc": "s:getFileName" }
38 | ],
39 | "status-style": "s:getDefaultColor",
40 | "window-status-style": [
41 | { "fg": "#6c757d", "bg": "default", "isStyleOnly": true }
42 | ],
43 | "window-status-current-style": [
44 | { "fg": "#ffd167", "bg": "default", "isStyleOnly": true }
45 | ]
46 | }
47 | ```
48 |
49 | Which will give your current git head and the name of the focused file just like shown in the screenshot
50 |
51 | Then you can use the full power of onestatus like in this example
52 | ```
53 | if !empty($TMUX)
54 | au BufEnter,BufLeave,FocusGained * :OneStatus
55 | au VimLeave * :OneStatusClean
56 | set noshowmode noruler
57 | set laststatus=0
58 | endif
59 | ```
60 | For `OneStatus` you can use `BufEnter` and use `WinEnter` or some other events but I found it sufficient for my everyday use.
61 | `OneStatusClean` on the other end is optional and is a convinient way to clean your tmux status bar when you exit your current vim process.
62 |
63 | ## The Internals
64 | The plugin's implementation is simple, it runs `tmux source 'the content of your json file'`, everything else is just deserialization and formatting.
65 |
66 | Let us write an example that displays the current file extension on the left.
67 | In your onestatus.json
68 | ```json
69 | "status-left": [
70 | { "fg": "default", "bg": "default", "labelFunc": "CurrentFileExtension" }
71 | ]
72 | ```
73 | And make a function in your `$MYVIMRC` to return the file type.
74 | ```vim
75 | fun CurrentFileExtension()
76 | return expand('%:e')
77 | endfun
78 | ```
79 |
80 | The `labelFunc` attribute takes a function name and sends its output to tmux
81 | ```
82 | tmux set-option status-left -g fg=default bg=default "{the output of function}"
83 | ```
84 |
85 | ## The API
86 | You must have noticed that the json file has these types of attributes
87 | - tmux option: an option that will be sent to tmux, you can learn more about them in `man tmux`
88 | - tmux color: can be any color format supported by tmux (ex: #ffd167)
89 | - onestatus' builtin function: they begin with `s:` like `s:getFileName`
90 |
91 | and has this form
92 | ```
93 | {
94 | option: attributes
95 | }
96 | ```
97 |
98 | In order to give a maximum amount of flexibility, attributes can either be an array of attribute of this shape:
99 | ```
100 | {
101 | "fg": optional tmux color (will default to tmux's default),
102 | "bg": optional tmux color (will default to tmux's default),
103 | "label": the text to be displayed if your option takes a string as an argument (ex: status-left ),
104 | "labelFunc": you can dynamicaly display labels by using one of the functions exposed by onestatus (will take precedance over "label"),
105 | "isStyleOnly": a boolean that has to be set to true if your option does not display a label
106 | }
107 | ```
108 |
109 | **NB1**: You can also use also use a onestatus function to dynamically generate your attributes.
110 | Currently only `s:getDefaultColor` is supported.
111 | **NB2**: You can call any global function in labelFunc. Try putting directly the name of a function of your own !
112 |
113 | ## Exposed functions
114 | labelFunc:
115 | - `s:getCWD`
116 | - `s:getFileName`
117 | - `s:getHead`
118 |
119 | attributes:
120 | - `s:getDefaultColor` (it will make your statusline's background match with your vim's theme)
121 |
122 | ## Exposed global variables
123 | - `g:onestatus_default_layout`: can be `0` or `1`. Defaults to `1`
124 | Setting it to 0 prevents onestatus from applying some arbitrary layout style. Useful when you want to fully customize your statusline.
125 | - `g:onestatus_config_path`: a path string
126 | It contains the default path where onestatus will look for a `onestatus.json`. You can override it if you want to use a custom path.
127 | - `g:onestatus_right_length`: the max length of your right status. Defaults to 50
128 | - `g:onestatus_left_length`: the max length of your left status. Defaults to 50
129 |
130 | ## For even more customization
131 | OneStatus also provides a helper to send more straightforward commands to tmux
132 |
133 | ```vim
134 | call onestatus#build([
135 | \{'command' : 'set-option status-justify centre'},
136 | \{'command': 'set-option status-right-length 30'},
137 | \{'command': 'set-option status-left-length 50'},
138 | \])
139 | ```
140 |
141 | # TODO
142 | - Write a proper `:h`
143 | - Add more default templates
144 | - Improve default template theme integration
145 | - Add more builtin functions
146 | - Setup automated tests on develop branch
147 |
148 | # License
149 | Distributed under the same terms as Vim itself. See the vim license.
150 |
--------------------------------------------------------------------------------
/autoload/onestatus.vim:
--------------------------------------------------------------------------------
1 | fun onestatus#build(cmds) abort
2 | let index = 0
3 | while index < len(a:cmds)
4 | if !has_key(a:cmds[index], 'command')
5 | echoer 'command attribute missing in object ' . index
6 | endif
7 | let index = index + 1
8 | endwhile
9 | call s:apply(s:buildLine(a:cmds))
10 | endfun
11 |
12 | fun s:wrap_in_quotes(text)
13 | return '"' . escape(a:text, '"') . '"'
14 | endfun
15 |
16 | fun s:apply(line_settings) abort
17 | try
18 | let save_cpo = &cpo
19 | set cpo&vim
20 | let temp_file = tempname()
21 | call writefile(a:line_settings, temp_file)
22 | call system("tmux source ". s:wrap_in_quotes(temp_file))
23 | finally
24 | let &cpo = save_cpo
25 | unlet save_cpo
26 | call delete(temp_file)
27 | endtry
28 | endfun
29 |
30 | fun s:buildLine(parts)
31 | let status = []
32 | for sections in a:parts
33 | call add(status, s:buildPart(sections))
34 | endfor
35 | return status
36 | endfun
37 |
38 | fun s:buildSection(attrs)
39 | let bg = get(a:attrs, 'bg', '')
40 | let fg = get(a:attrs, 'fg', '')
41 | let label = get(a:attrs, 'label', '')
42 | let fmt = get(a:attrs, 'isStyleOnly', v:false) ? 'fg=%s,bg=%s%s' : '"#[fg=%s,bg=%s]%s"'
43 | let parts = printf(fmt, fg, bg, label)
44 | return parts
45 | endfun
46 |
47 | fun s:buildPart(sections)
48 | let part = []
49 | if has_key(a:sections, 'attributes')
50 | for sect in a:sections.attributes
51 | call add(part, s:buildSection(sect))
52 | endfor
53 | endif
54 | let res = printf('%s %s', a:sections.command, join(part, ''))
55 | return res
56 | endfun
57 |
--------------------------------------------------------------------------------
/plugin/onestatus.vim:
--------------------------------------------------------------------------------
1 | if !exists(':OneStatus')
2 | if !exists('g:onestatus_default_layout')
3 | let g:onestatus_default_layout = 1
4 | command! OneStatus call s:setCurDir() | call onestatus#build(s:onestatusDefault())
5 | endif
6 | command! OneStatusClean call s:cleanUp() | call onestatus#build(s:onestatusDefault())
7 | endif
8 |
9 | if exists('g:loaded_onestatus')
10 | finish
11 | endif
12 |
13 | if !exists('g:onestatus_config_path')
14 | let s:currentPath = expand('$HOME')
15 | if has('nvim')
16 | let s:currentPath = s:currentPath . '/.config/nvim'
17 | endif
18 | let g:onestatus_config_path = s:currentPath . '/onestatus.json'
19 | endif
20 |
21 | if !exists('g:onestatus_right_length')
22 | let g:onestatus_right_length = 50
23 | endif
24 |
25 | if !exists('g:onestatus_left_length')
26 | let g:onestatus_left_length = 50
27 | endif
28 |
29 | let g:loaded_onestatus = 1
30 | let g:cwd_formated = ""
31 | let g:isVimLeaving = v:false
32 |
33 | function s:setCurDir()
34 | let cwd = getcwd()
35 | let g:cwd_formated = printf(' ~/%s ', get(split(cwd, '/')[-1:], 0, 'root'))
36 | endfun
37 |
38 | fun s:cleanUp()
39 | let g:isVimLeaving = v:true
40 | endfun
41 |
42 | fun s:getCWD()
43 | if g:isVimLeaving
44 | return ''
45 | endif
46 |
47 | return g:cwd_formated
48 | endfun
49 |
50 | fun s:getFileName()
51 | if g:isVimLeaving
52 | return ''
53 | endif
54 |
55 | return &filetype != '' ? printf(' %s ', expand("%:t")) : ''
56 | endfun
57 |
58 | fun s:getHead()
59 | if g:isVimLeaving
60 | return ''
61 | endif
62 |
63 | let s:headRef = { -> '' }
64 | if exists('g:loaded_fugitive')
65 | let s:headRef = funcref('FugitiveHead')
66 | elseif exists('g:loaded_gitbranch')
67 | let s:headRef = funcref('gitbranch#name')
68 | else
69 | echo 'OneStatus: please install vim-gitbranch or vim-fugitive to use s:getHead'
70 | return ''
71 | endif
72 | let head = s:headRef()
73 | if (head == "")
74 | return ""
75 | endif
76 | return printf(" %s ", head)
77 | endfun
78 |
79 | fun s:getDefaultColor() abort
80 | let s:fg = synIDattr(synIDtrans(hlID('Normal')), 'fg#')
81 | let s:bg = synIDattr(synIDtrans(hlID('Normal')), 'bg#')
82 | let s:attrs = {'isStyleOnly': v:true, 'fg': s:fg, 'bg': (len(s:bg) == 0 ? 'default' : s:bg)}
83 | return [s:attrs]
84 | endfun
85 |
86 | fun s:execLabelFuncs(val)
87 | for [key, val] in items(a:val)
88 | if key == "labelFunc"
89 | let a:val.label = function(val)()
90 | unlet a:val.labelFunc
91 | endif
92 | endfor
93 | return a:val
94 | endfun
95 |
96 | fun s:getConfig(path) abort
97 | let config = json_decode(readfile(a:path))
98 | let template = []
99 | for [key, val] in items(config)
100 |
101 | if type(val) == v:t_list
102 | let fmtVal = map(val, { _,dict -> s:execLabelFuncs(dict) })
103 | elseif type(val) == v:t_string
104 | let fmtVal = function(val)()
105 | else
106 | throw printf('% has bad attribute type', key)
107 | endif
108 |
109 | call add(template, { 'command': 'set-window-option -g ' . key, 'attributes': fmtVal })
110 | endfor
111 | return template
112 | endfun
113 |
114 | fun s:onestatusDefault()
115 | let configPath = expand(g:onestatus_config_path)
116 | if !filereadable(configPath)
117 | echo 'OneStatus: onestatus.json not found. Please Provide one at ' . s:currentPath . ' or override g:onestatus_config_path'
118 | return []
119 | endif
120 | return s:getConfig(configPath)
121 | endfun
122 |
123 | " set default config
124 | if g:onestatus_default_layout == 1
125 | call onestatus#build([
126 | \{'command' : 'set-option status-justify centre'},
127 | \{'command': 'set-option status-right-length ' . g:onestatus_right_length},
128 | \{'command': 'set-option status-left-length ' . g:onestatus_left_length},
129 | \])
130 | endif
131 |
--------------------------------------------------------------------------------