]> git.wincent.com - pinnacle.git/blob - autoload/pinnacle.vim
Add utility functions for constructing highlights piecemeal
[pinnacle.git] / autoload / pinnacle.vim
1 ""
2 " @plugin Pinnacle Highlight group manipulation for Vim
3 "
4 " # Intro
5 "
6 " Pinnacle provides functions for manipulating |:highlight| groups.
7 "
8 "
9 " # Installation
10 "
11 " To install Pinnacle, use your plug-in management system of choice.
12 "
13 " If you don't have a "plug-in management system of choice", I recommend
14 " Pathogen (https://github.com/tpope/vim-pathogen) due to its simplicity and
15 " robustness. Assuming that you have Pathogen installed and configured, and that
16 " you want to install Pinnacle into `~/.vim/bundle`, you can do so with:
17 "
18 " ```
19 " git clone https://github.com/wincent/pinnacle.git ~/.vim/bundle/pinnacle
20 " ```
21 "
22 " Alternatively, if you use a Git submodule for each Vim plug-in, you could do
23 " the following after `cd`-ing into the top-level of your Git superproject:
24 "
25 " ```
26 " git submodule add https://github.com/wincent/pinnacle.git ~/vim/bundle/pinnacle
27 " git submodule init
28 " ```
29 "
30 " To generate help tags under Pathogen, you can do so from inside Vim with:
31 "
32 " ```
33 " :call pathogen#helptags()
34 " ```
35 "
36 "
37 " # Website
38 "
39 " The official Pinnacle source code repo is at:
40 "
41 "   http://git.wincent.com/pinnacle.git
42 "
43 " Mirrors exist at:
44 "
45 "   - https://github.com/wincent/pinnacle
46 "   - https://gitlab.com/wincent/pinnacle
47 "   - https://bitbucket.org/ghurrell/pinnacle
48 "
49 " Official releases are listed at:
50 "
51 "   http://www.vim.org/scripts/script.php?script_id=5360
52 "
53 "
54 " # License
55 "
56 " Copyright (c) 2016-present Greg Hurrell
57 "
58 " Permission is hereby granted, free of charge, to any person obtaining
59 " a copy of this software and associated documentation files (the
60 " "Software"), to deal in the Software without restriction, including
61 " without limitation the rights to use, copy, modify, merge, publish,
62 " distribute, sublicense, and/or sell copies of the Software, and to
63 " permit persons to whom the Software is furnished to do so, subject to
64 " the following conditions:
65 "
66 " The above copyright notice and this permission notice shall be
67 " included in all copies or substantial portions of the Software.
68 "
69 " THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
70 " EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
71 " MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
72 " NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
73 " LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
74 " OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
75 " WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76 "
77 "
78 " # Development
79 "
80 " ## Contributing patches
81 "
82 " Patches can be sent via mail to greg@hurrell.net, or as GitHub pull requests
83 " at: https://github.com/wincent/pinnacle/pulls
84 "
85 " ## Cutting a new release
86 "
87 " At the moment the release process is manual:
88 "
89 " - Perform final sanity checks and manual testing
90 " - Update the |pinnacle-history| section of the documentation
91 " - Verify clean work tree:
92 "
93 " ```
94 " git status
95 " ```
96 "
97 " - Tag the release:
98 "
99 " ```
100 " git tag -s -m "$VERSION release" $VERSION
101 " ```
102 "
103 " - Publish the code:
104 "
105 " ```
106 " git push origin master --follow-tags
107 " git push github master --follow-tags
108 " ```
109 "
110 " - Produce the release archive:
111 "
112 " ```
113 " git archive -o pinnacle-$VERSION.zip HEAD -- .
114 " ```
115 "
116 " - Upload to http://www.vim.org/scripts/script.php?script_id=5360
117 "
118 "
119 " # Authors
120 "
121 " Pinnacle is written and maintained by Greg Hurrell <greg@hurrell.net>.
122 "
123 " Other contributors that have submitted patches include (in alphabetical
124 " order):
125 "
126 " - Kyle Poole
127 "
128 "
129 " # History
130 "
131 " 0.2 (9 January 2016)
132 "
133 " - Added `pinnacle#underline`.
134 "
135 " ## 0.1 (30 March 2016)
136 "
137 " - Initial release.
138
139 " Replaces newlines with spaces.
140 function! pinnacle#sub_newlines(string) abort
141   return tr(a:string, "\r\n", '  ')
142 endfunction
143
144 " Runs a command and returns the captured output as a single line.
145 "
146 " Useful when we don't want to let long lines on narrow windows produce unwanted
147 " embedded newlines.
148 function! pinnacle#capture_line(command) abort
149   redir => l:capture
150   execute a:command
151   redir END
152
153   return pinnacle#sub_newlines(l:capture)
154 endfunction
155
156 " Gets the current value of a highlight group.
157 function! pinnacle#capture_highlight(group) abort
158   return pinnacle#capture_line('0verbose silent highlight ' . a:group)
159 endfunction
160
161 " Extracts a highlight string from a group, recursively traversing linked
162 " groups, and returns a string suitable for passing to `:highlight`.
163 function! pinnacle#extract_highlight(group) abort
164   let l:group = pinnacle#capture_highlight(a:group)
165
166   " Traverse links back to authoritative group.
167   while l:group =~# 'links to'
168     let l:index = stridx(l:group, 'links to') + len('links to')
169     let l:linked = strpart(l:group, l:index + 1)
170     let l:group = pinnacle#capture_highlight(l:linked)
171   endwhile
172
173   " Extract the highlighting details (the bit after "xxx")
174   let l:matches = matchlist(l:group, '\<xxx\>\s\+\(.*\)')
175   let l:original = l:matches[1]
176   return l:original
177 endfunction
178
179 let s:prefix=has('gui') || has('termguicolors') ? 'gui' : 'cterm'
180
181 function! pinnacle#extract_bg(group) abort
182   return pinnacle#extract_component(a:group, 'bg')
183 endfunction
184
185 function! pinnacle#extract_fg(group) abort
186   return pinnacle#extract_component(a:group, 'fg')
187 endfunction
188
189 function! pinnacle#extract_component(group, component) abort
190   return synIDattr(synIDtrans(hlID(a:group)), a:component, s:prefix)
191 endfunction
192
193 function! pinnacle#highlight(highlight) abort
194   let l:result=[]
195   if has_key(a:highlight, 'bg')
196     call insert(l:result, s:prefix . 'bg=' . a:highlight['bg'])
197   endif
198   if has_key(a:highlight, 'fg')
199     call insert(l:result, s:prefix . 'fg=' . a:highlight['fg'])
200   endif
201   if has_key(a:highlight, 'term')
202     call insert(l:result, s:prefix . '=' . a:highlight['term'])
203   endif
204   return join(l:result, ' ')
205 endfunction
206
207 " Returns an italicized copy of `group` suitable for passing to `:highlight`.
208 function! pinnacle#italicize(group) abort
209   return pinnacle#decorate('italic', a:group)
210 endfunction
211
212 " Returns a bold copy of `group` suitable for passing to `:highlight`.
213 function! pinnacle#embolden(group) abort
214   return pinnacle#decorate('bold', a:group)
215 endfunction
216
217 " Returns an underlined copy of `group` suitable for passing to `:highlight`.
218 function! pinnacle#underline(group) abort
219   return pinnacle#decorate('undercurl', a:group)
220 endfunction
221
222 " Returns a copy of `group` decorated with `style` (eg. "bold", "italic" etc)
223 " suitable for passing to `:highlight`.
224 function! pinnacle#decorate(style, group) abort
225   let l:original = pinnacle#extract_highlight(a:group)
226
227   for l:lhs in ['gui', 'term', 'cterm']
228     " Check for existing setting.
229     let l:matches = matchlist(
230       \   l:original,
231       \   '^\([^ ]\+ \)\?' .
232       \   '\(' . l:lhs . '=[^ ]\+\)' .
233       \   '\( .\+\)\?$'
234       \ )
235     if l:matches == []
236       " No setting, add one with just a:style in it
237       let l:original .= ' ' . l:lhs . '=' . a:style
238     else
239       " Existing setting; check whether a:style is already in it.
240       let l:start = l:matches[1]
241       let l:value = l:matches[2]
242       let l:end = l:matches[3]
243       if l:value =~# '.*' . a:style . '.*'
244         continue
245       else
246         let l:original = l:start . l:value . ',' . a:style . l:end
247       endif
248     endif
249   endfor
250
251   return pinnacle#sub_newlines(l:original)
252 endfunction