1
2 Author:peter@peterodding.com
3 Last Change:
4 URL:http://peterodding.com/code/vim/shell/
5
6 if !exists('s:script')
7 let s:script = expand('<sfile>:p:~')
8 let s:enoimpl = "%s() hasn't been implemented on your platform! %s"
9 let s:contact = "If you have suggestions, please contact the vim_dev mailing-list or peter@peterodding.com."
10 let s:fullscreen_enabled = 0
11 endif
12
13 function! xolox#shell#open_cmd(arg) :Open
14 if a:arg !~ '\S'
15 if !s:open_at_cursor()
16 call xolox#shell#open_with(expand('%:p:h'))
17 endif
18 elseif a:arg =~ g:shell_patt_url || a:arg =~ g:shell_patt_mail
19 call xolox#shell#open_url(a:arg)
20 else
21 let arg = fnamemodify(a:arg, ':p')
22 if isdirectory(arg) || filereadable(arg)
23 call xolox#shell#open_with(arg)
24 else
25 let msg = "%s: I don't know how to open %s!"
26 echoerr printf(msg, s:script, string(a:arg))
27 endif
28 endif
29 endfunction
30
31 function! s:open_at_cursor()
32 let cWORD = expand('<cWORD>')
33
34
35 let match = matchstr(cWORD, g:shell_patt_url)
36 if match == ''
37
38
39 let match = matchstr(cWORD, g:shell_patt_mail)
40 if match == ''
41
42 let line = getline('.')
43 let idx = col('.') - 1
44 let match = matchstr(line[0 : idx], '\f*$')
45 let match .= matchstr(line[idx+1 : -1], '^\f*')
46
47 if match =~ '^\~' || match =~ '\$'
48 TODO
49 let match = expand(match)
50 endif
51 if !isdirectory(match) && !filereadable(match)
52 let match = ''
53 endif
54 endif
55 endif
56 if match != ''
57 call xolox#shell#open_url(match)
58 return 1
59 endif
60 endfunction
61
62 function! xolox#shell#open_url(url)
63 try
64 let url = a:url
65 if url =~ g:shell_patt_mail && url !~ '^mailto:'
66 let url = 'mailto:' . url
67 endif
68 if s:is_windows()
69 if s:has_dll()
70 call s:library_call('openurl', url)
71 else
72 call s:execute('CMD /C START "" %s', [url])
73 endif
74 return 1
75 elseif has('macunix')
76
77
78 call s:execute('open %s', [url])
79 return 1
80 elseif has('unix')
81 if !has('gui_running') && $DISPLAY == ''
82 for browser in ['lynx', 'links', 'w3m']
83 if executable(browser)
84 execute '!' . browser fnameescape(url)
85 return 1
86 endif
87 endfor
88 let msg = "Failed to find command-line web browser. %s"
89 throw printf(msg, s:contact)
90 elseif xolox#shell#open_with(url, 'firefox', 'google-chrome')
91 return 1
92 else
93 let msg = "Failed to find graphical web browser. %s"
94 throw printf(msg, s:contact)
95 endif
96 endif
97 throw printf(s:enoimpl, 'openurl', s:contact)
98 catch
99 call xolox#warning("%s: %s at %s", s:script, v:exception, v:throwpoint)
100 endtry
101 endfunction
102
103 function! xolox#shell#open_with(location, ...)
104 if s:is_windows()
105 if s:has_dll()
106 openurl()
107 ShellExecute()
108 call s:library_call('openurl', a:location)
109 else
110 call s:execute('CMD /C START "" %s', [a:location])
111 endif
112 return 1
113 else
114 for handler in g:shell_open_cmds + a:000
115 if executable(handler)
116 let location = a:location
117 if a:location !~ g:shell_patt_url && a:location !~ g:shell_patt_mail
118 let location = fnamemodify(location, ':p:~')
119 endif
120 call xolox#message("Opening %s with %s", location, handler)
121 call s:execute('%s %s', [handler, a:location])
122 return 1
123 endif
124 endfor
125 endif
126 endfunction
127
128 function! xolox#shell#highlight_urls()
129 if exists('g:syntax_on') && &ft !~ g:shell_hl_exclude
130 if &ft == 'help'
131 let command = 'syntax match %s /%s/'
132 let urlgroup = 'HelpURL'
133 let mailgroup = 'HelpEmail'
134 else
135 let command = 'syntax match %s /%s/ contained containedin=.*Comment.*'
136 let urlgroup = 'CommentURL'
137 let mailgroup = 'CommentEmail'
138 endif
139 execute printf(command, urlgroup, escape(g:shell_patt_url, '/'))
140 execute printf(command, mailgroup, escape(g:shell_patt_mail, '/'))
141 execute 'highlight def link' urlgroup 'Underlined'
142 execute 'highlight def link' mailgroup 'Underlined'
143 endif
144 endfunction
145
146 function! xolox#shell#execute(command, synchronous, ...)
147 try
148 let cmd = a:command
149 let has_input = a:0 > 0
150 if has_input
151 let tempin = tempname()
152 call writefile(type(a:1) == type([]) ? a:1 : split(a:1, "\n"), tempin)
153 let cmd .= ' < ' . shellescape(tempin)
154 endif
155 if a:synchronous
156 let tempout = tempname()
157 let cmd .= ' > ' . shellescape(tempout) . ' 2>&1'
158 endif
159 if s:is_windows() && s:has_dll()
160 let fn = 'execute_' . (a:synchronous ? '' : 'a') . 'synchronous'
161 let cmd = ($COMSPEC != '' ? $COMSPEC : 'CMD.EXE') . ' /C ' . cmd
162 let error = s:library_call(fn, cmd)
163 if error != ''
164 let msg = '%s: %s(%s) failed! (error: %s)'
165 throw printf(msg, s:script, fn, strtrans(cmd), strtrans(error))
166 endif
167 else
168 if has('unix') && !a:synchronous
169 let cmd = '(' . cmd . ') &'
170 endif
171 let output = split(system(cmd), "\n")
172 call s:handle_error(cmd, output)
173 endif
174 if a:synchronous
175 if !filereadable(tempout)
176 let msg = '%s: Failed to execute %s!'
177 throw printf(msg, s:script, strtrans(cmd))
178 endif
179 return readfile(tempout)
180 else
181 return 1
182 endif
183 catch
184 call xolox#warning("%s: %s at %s", s:script, v:exception, v:throwpoint)
185 finally
186 if exists('tempin') | call delete(tempin) | endif
187 if exists('tempout') | call delete(tempout) | endif
188 endtry
189 endfunction
190
191 function! xolox#shell#fullscreen()
192
193
194
195
196 if !s:fullscreen_enabled
197 let s:go_toggled = ''
198 for item in split(g:shell_fullscreen_items, '.\zs')
199 if &go =~# item
200 let s:go_toggled .= item
201 execute 'set go-=' . item
202 endif
203 endfor
204 if g:shell_fullscreen_items =~# 'e' && &stal != 0
205 let s:stal_save = &stal
206 set showtabline=0
207 endif
208 endif
209
210
211 "wmctrl"
212 try
213 if s:is_windows()
214 if !s:has_dll()
215 let msg = "The DLL library %s is missing!"
216 throw printf(msg, string(s:library))
217 endif
218 let error = s:library_call('fullscreen', !s:fullscreen_enabled)
219 if error != ''
220 throw "shell.dll failed with: " . error
221 endif
222 elseif has('unix')
223 if !executable('wmctrl')
224 let msg = "Full-screen on UNIX requires the `wmctrl' program!"
225 throw msg . " On Debian/Ubuntu you can install it by executing `sudo apt-get install wmctrl'."
226 endif
227 call s:execute('wmctrl -r %s -b toggle,fullscreen 2>&1', [':ACTIVE:'])
228 else
229 throw printf(s:enoimpl, 'fullscreen', s:contact)
230 endif
231 catch
232 call xolox#warning("%s: %s at %s", s:script, v:exception, v:throwpoint)
233 endtry
234
235
236 if s:fullscreen_enabled
237 let &go .= s:go_toggled
238 if exists('s:stal_save')
239 let &stal = s:stal_save
240 unlet s:stal_save
241 endif
242 endif
243
244 xolox#shell#is_fullscreen()
245 let s:fullscreen_enabled = !s:fullscreen_enabled
246
247
248 if s:fullscreen_enabled
249 sleep 50 m
250 call xolox#message("To return from full-screen type <F11> or execute :Fullscreen.")
251 endif
252
253 endfunction
254
255 function! xolox#shell#is_fullscreen()
256 return s:fullscreen_enabled
257 endfunction
258
259 function! xolox#shell#build_cmd(cmd, args)
260 if a:args == []
261 return a:cmd
262 else
263 let args = map(copy(a:args), 'shellescape(v:val)')
264 call insert(args, a:cmd, 0)
265 return call('printf', args)
266 endif
267 endfunction
268
269
270
271 function! s:is_windows()
272 return has('win32') || has('win64')
273 endfunction
274
275 if s:is_windows()
276
277 let s:library = expand('<sfile>:p:h') . '\shell.dll'
278
279 function! s:library_call(fn, arg)
280 return libcall(s:library, a:fn, a:arg)
281 endfunction
282
283 function! s:find_dll_version()
284 try
285 return s:library_call('libversion', '')
286 catch
287 let msg = "%s: Failed to load %s DLL!"
288 let lib = fnamemodify(s:library, ':~')
289 echohl warningmsg
290 echomsg printf(msg, s:script, lib)
291 echohl none
292 endtry
293 return '?'
294 endfunction
295
296 function! s:has_dll()
297 libversion()
298
299
300 if !exists('s:library_version')
301 let s:library_version = s:find_dll_version()
302 endif
303 return s:library_version == '0.2'
304 endfunction
305
306 endif
307
308 function! s:execute(cmd, args)
309 let cmd = xolox#shell#build_cmd(a:cmd, a:args)
310 let output = system(cmd)
311 call s:handle_error(cmd, output)
312 return output
313 endfunction
314
315 function! s:handle_error(cmd, output)
316 if v:shell_error
317 if type(a:output) == type([])
318 let output = join(a:output, "\n")
319 else
320 let output = a:output
321 endif
322 let msg = "Command %s failed!"
323 if output =~ '^\_s*$'
324 throw printf(msg, string(a:cmd))
325 else
326 let msg .= ' (output: %s)'
327 throw printf(msg, string(a:cmd), strtrans(output))
328 endif
329 endif
330 endfunction
331
332