1 " tlib.vim -- Some utility functions
2 " @Author: Thomas Link (micathom AT gmail com?subject=[vim])
3 " @Website: http://www.vim.org/account/profile.php?user_id=4037
4 " @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
5 " @Created: 2007-04-10.
6 " @Last Change: 2008-06-15.
8 " GetLatestVimScripts: 1863 1 tlib.vim
10 " Please see also ../test/tlib.vim for usage examples.
13 " - tlib#agent#SwitchLayout(): switch between horizontal and vertical
15 " - tlib#cache#Purge(): delete old cache files (for the moment use find)
16 " - tlib#file#Relative(): currently relies on cwd to be set
17 " - tlib#input#EditList(): Disable selection by index number
18 " - tlib#input#List(): Some kind of command line to edit some
19 " preferences (sort etc.) on the fly
20 " - tlib#input#List(): Make commands accessible via popup-menu
22 if &cp || exists("loaded_tlib")
25 if v:version < 700 "{{{2
26 echoerr "tlib requires Vim >= 7"
35 " :display: :TLet VAR = VALUE
36 " Set a variable only if it doesn't already exist.
42 command! -nargs=+ TLet if !exists(matchstr(<q-args>, '^[^=[:space:]]\+')) | exec 'let '. <q-args> | endif
45 " Open a scratch buffer (a buffer without a file).
46 " TScratch ... use split window
47 " TScratch! ... use the whole frame
48 " This command takes an (inner) dictionnary as optional argument.
50 " TScratch 'scratch': '__FOO__'
51 " => Open a scratch buffer named __FOO__
52 command! -bar -nargs=* -bang TScratch call tlib#scratch#UseScratch({'scratch_split': '<bang>' != '!', <args>})
55 " :display: :TVarArg VAR1, [VAR2, DEFAULT2] ...
56 " A convenience wrapper for |tlib#arg#Let|.
59 " TVarArg ['a', 1], 'b'
63 command! -nargs=+ TVarArg exec tlib#arg#Let([<args>])
66 " :display: :TKeyArg DICT, VAR1, [VAR2, DEFAULT2] ...
67 " A convenience wrapper for |tlib#arg#Let|.
69 " function! Foo(keyargs)
70 " TKeyArg a:keyargs, ['a', 1], 'b'
74 command! -nargs=+ TKeyArg exec tlib#arg#Key([<args>])
77 " :display: TBrowseOutput COMMAND
78 " Every wondered how to effciently browse the output of a command
79 " without redirecting it to a file? This command takes a command as
80 " argument and presents the output via |tlib#input#List()| so that you
81 " can easily search for a keyword (e.g. the name of a variable or
82 " function) and the like.
84 " If you press enter, the selected line will be copied to the command
85 " line. Press ESC to cancel browsing.
88 " TBrowseOutput 20verb TeaseTheCulprit
89 command! -nargs=1 -complete=command TBrowseOutput call tlib#cmd#BrowseOutput(<q-args>)
95 " When 1, automatically select a the last remaining item after applying
97 TLet g:tlib_pick_last_item = 1
99 " If a list is bigger than this value, don't try to be smart when
100 " selecting an item. Be slightly faster instead.
101 TLet g:tlib_sortprefs_threshold = 200
103 " Scratch window position
104 TLet g:tlib_scratch_pos = 'botright'
106 " Size of the input list window (in percent) from the main size (of &lines).
107 TLet g:tlib_inputlist_pct = 70
109 " Size of filename columns when listing filenames
110 TLet g:tlib_inputlist_width_filename = '&co / 3'
111 " TLet g:tlib_inputlist_width_filename = 25
113 " The highlight group to use for showing matches in the input list window.
114 TLet g:tlib_inputlist_higroup = 'IncSearch'
116 " If a list contains more items, don't do an incremental "live search",
117 " but use |input()| the quere the user for a filter. This is useful on
118 " slower machines or with very long lists.
119 TLet g:tlib_inputlist_livesearch_threshold = 500
121 " If true, show some indicators about the status of a filename (eg
122 " buflisted(), bufloaded() etc.).
123 " This is disabled by default because vim checks also for the file on
124 " disk when doing this.
125 TLet g:tlib_inputlist_filename_indicators = 0
127 " Extra tags for |tlib#tag#Retrieve()| (see there). Can also be buffer-local.
128 TLet g:tlib_tags_extra = ''
130 " Filter the tag description through |substitute()| for these filetypes.
131 " This applies only if the tag cmd field (see |taglist()|) is used.
133 TLet g:tlib_tag_substitute = {
134 \ 'java': [['\s*{\s*$', '', '']],
135 \ 'ruby': [['\<\(def\|class\|module\)\>\s\+', '', '']],
137 \ ['^\s*com\%[mand]!\?\(\s\+-\S\+\)*\s*\u\w*\zs.*$', '', ''],
138 \ ['^\s*\(let\|aug\%[roup]\|fu\%[nction]!\?\|com\%[mand]!\?\(\s\+-\S\+\)*\)\s*', '', ''],
139 \ ['"\?\s*{{{\d.*$', '', ''],
143 TLet g:tlib_filename_sep = '/'
144 " TLet g:tlib_filename_sep = exists('+shellslash') && !&shellslash ? '\' : '/' " {{{2
146 " The cache directory. If empty, use |tlib#dir#MyRuntime|.'/cache'
147 TLet g:tlib_cache = ''
149 " Where to display the line when using |tlib#buffer#ViewLine|.
150 " For possible values for position see |scroll-cursor|.
151 TLet g:tlib_viewline_position = 'zz'
154 " Keys for |tlib#input#List|~
156 TLet g:tlib_inputlist_and = ' '
157 TLet g:tlib_inputlist_or = '|'
158 TLet g:tlib_inputlist_not = '-'
160 " When editing a list with |tlib#input#List|, typing these numeric chars
161 " (as returned by getchar()) will select an item based on its index, not
162 " based on its name. I.e. in the default setting, typing a "4" will
163 " select the fourth item, not the item called "4".
164 " In order to make keys 0-9 filter the items in the list and make
165 " <m-[0-9]> select an item by its index, remove the keys 48 to 57 from
167 " Format: [KEY] = BASE ... the number is calculated as KEY - BASE.
169 TLet g:tlib_numeric_chars = {
193 TLet g:tlib_keyagents_InputList_s = {
194 \ "\<PageUp>": 'tlib#agent#PageUp',
195 \ "\<PageDown>": 'tlib#agent#PageDown',
196 \ "\<Up>": 'tlib#agent#Up',
197 \ "\<Down>": 'tlib#agent#Down',
198 \ "\<c-Up>": 'tlib#agent#UpN',
199 \ "\<c-Down>": 'tlib#agent#DownN',
200 \ "\<Left>": 'tlib#agent#ShiftLeft',
201 \ "\<Right>": 'tlib#agent#ShiftRight',
202 \ 18: 'tlib#agent#Reset',
203 \ 242: 'tlib#agent#Reset',
204 \ 17: 'tlib#agent#Input',
205 \ 241: 'tlib#agent#Input',
206 \ 27: 'tlib#agent#Exit',
207 \ 26: 'tlib#agent#Suspend',
208 \ 250: 'tlib#agent#Suspend',
209 \ 15: 'tlib#agent#SuspendToParentWindow',
210 \ 63: 'tlib#agent#Help',
211 \ "\<F1>": 'tlib#agent#Help',
212 \ "\<bs>": 'tlib#agent#ReduceFilter',
213 \ "\<del>": 'tlib#agent#ReduceFilter',
214 \ "\<c-bs>": 'tlib#agent#PopFilter',
215 \ "\<m-bs>": 'tlib#agent#PopFilter',
216 \ "\<c-del>": 'tlib#agent#PopFilter',
217 \ "\<m-del>": 'tlib#agent#PopFilter',
218 \ 191: 'tlib#agent#Debug',
219 \ char2nr(g:tlib_inputlist_or): 'tlib#agent#OR',
220 \ char2nr(g:tlib_inputlist_and): 'tlib#agent#AND',
223 " Number of items to move when pressing <c-up/down> in the input list window.
224 TLet g:tlib_scroll_lines = 10
227 TLet g:tlib_keyagents_InputList_m = {
228 \ 35: 'tlib#agent#Select',
229 \ "\<s-up>": 'tlib#agent#SelectUp',
230 \ "\<s-down>": 'tlib#agent#SelectDown',
231 \ 1: 'tlib#agent#SelectAll',
232 \ 225: 'tlib#agent#SelectAll',
234 " "\<c-space>": 'tlib#agent#Select'
237 TLet g:tlib_handlers_EditList = [
238 \ {'key': 5, 'agent': 'tlib#agent#EditItem', 'key_name': '<c-e>', 'help': 'Edit item'},
239 \ {'key': 4, 'agent': 'tlib#agent#DeleteItems', 'key_name': '<c-d>', 'help': 'Delete item(s)'},
240 \ {'key': 14, 'agent': 'tlib#agent#NewItem', 'key_name': '<c-n>', 'help': 'New item'},
241 \ {'key': 24, 'agent': 'tlib#agent#Cut', 'key_name': '<c-x>', 'help': 'Cut item(s)'},
242 \ {'key': 3, 'agent': 'tlib#agent#Copy', 'key_name': '<c-c>', 'help': 'Copy item(s)'},
243 \ {'key': 22, 'agent': 'tlib#agent#Paste', 'key_name': '<c-v>', 'help': 'Paste item(s)'},
244 \ {'pick_last_item': 0},
245 \ {'return_agent': 'tlib#agent#EditReturnValue'},
254 let &cpo = s:save_cpo
258 -----------------------------------------------------------------------
265 - More list convenience functions
267 - tlib#InputList(): properly handle duplicate items; it type contains
268 'i', the list index + 1 is returned, not the element
271 - tlib#InputList(): Show feedback in statusline instead of the echo area
272 - tlib#GetVar(), tlib#GetValue()
275 - tlib#InputList(): Up/Down keys wrap around list
276 - tlib#InputList(): FIX: Problem when reducing the filter & using AND
277 - tlib#InputList(): Made <a-numeric> work (can be configured via
278 - tlib#InputList(): special display_format: "filename"
279 - tlib#Object: experimental support for some kind of OOP
280 - tlib#World: Extracted some functions from tlib.vim to tlib/World.vim
281 - tlib#FileJoin(), tlib#FileSplit(), tlib#RelativeFilename()
283 - tlib#EnsureDirectoryExists(dir)
285 - tlib#DecodeURL(url), tlib#EncodeChar(char), tlib#EncodeURL(url)
286 - FIX: Problem when using shift-up/down with filtered lists
289 - tlib#InputList(): FIX: Selecting items in filtered view
290 - tlib#InputList(): <c-bs>: Remove last AND pattern from filter
293 - tlib#InputList(): Disabled <c-space> map
294 - tlib#InputList(): try to be smart about user itentions only if a
295 list's length is < g:tlib_sortprefs_threshold (default: 200)
296 - tlib#Object: Super() method
297 - tlib#MyRuntimeDir()
298 - tlib#GetCacheName(), tlib#CacheSave(), tlib#CacheGet()
299 - tlib#Args(), tlib#GetArg()
300 - FIX: tlib#InputList(): Display problem with first item
303 - tlib#InputList(): <c-z> ... Suspend/Resume input
304 - tlib#InputList(): <c-q> ... Input text on the command line (useful on
305 slow systems when working with very large lists)
306 - tlib#InputList(): AND-pattern starting with '!' will work as 'exclude
308 - tlib#InputList(): FIX <c-bs> pop OR-patterns properly
309 - tlib#InputList(): display_format == filename: don't add '/' to
310 directory names (avoid filesystem access)
313 - FIX: Return empty cache name for buffers that have no files attached to it
317 - Re-arrangements & modularization (this means many function names have
318 changed, on the other hand only those functions are loaded that are
320 - tlib#input#List(): Added maps with m-modifiers for <c-q>, <c-z>, <c-a>
321 - tlib#input#List(): Make sure &fdm is manual
322 - tlib#input#List(): When exiting the list view, consume the next 5
323 characters in the queue (if any)
324 - tlib#input#EditList(): Now has cut, copy, paste functionality.
325 - Added documentation and examples
328 - tlib#input#List(): (v)split type of commands leave the original window
329 untouched (you may use <c-w> to replace its contents)
330 - tlib#file#With(): Check whether an existing buffer is loaded.
331 - Scratch related functions went to tlib/scratch.vim so that they are
332 accessible from other scripts.
333 - Configure the list window height via g:tlib_inputlist_pct (1..100%)
337 - The :TLet command replaces :TLLet (which was removed)
338 - :TScratch[!] command (with ! don't split but use the whole window)
339 - tlib#rx#Escape(text, ?magic='m')
340 - tlib#buffer#GetList(?show_hidden=0)
341 - tlib#dir#CD(), tlib#dir#Push(), tlib#dir#Pop()
342 - tlib#input#ListW: A slightly remodeled version of tlib#input#List
343 that takes a World as second argument.
344 - Added some documentation doc/tlib.txt (most of it is automatically
345 compiled from the source files)
347 - tlib#input#List(): The default keys for AND, NOT have changed to
348 be more Google-like (space, minus); the keys can be configured via
351 - In file listings, indicate if a file is loaded, listed, modified
353 - tlib#input#List(): Highlight the filter pattern
354 - tlib#input#List(): <c-up/down> scrolls g:tlib_scroll_lines
357 - tlib#input#List(): Centering line, clear match, clear & restore
359 - tlib#input#List(): Ensure the window layout doesn't change (if the
360 number of windows hasn't changed)
361 - tlib#arg#Ex(): Don't escape backslashes by default
367 - Renamed tlib#win#SetWin() to tlib#win#Set()
369 - tlib#input#List(): <left>, <right> keys work in some lists
370 - tlib#input#List(): If an index_table is provided this will be used
371 instead of the item's list index.
373 - tlib#input#List(): Problem with scrolling, when the list was
374 shorter than the window (eg when using a vertical window).
375 - tlib#cache#Filename(): Don't rewrite name as relative filename if
376 explicitly given as argument. Avoid double (back)slashes.
381 - Scratch: Set &fdc=0.
382 - The cache directory can be configured via g:tlib_cache
383 - Renamed tlib#buffer#SetBuffer() to tlib#buffer#Set().
385 - tlib#input#List(): Select the active item per mouse.
390 - tlib#buffer#InsertText()
392 - tlib#win#[SG]etLayout(): Use a dictionnary, set &cmdheight.
394 - Wrong order with pre-defined filters.
398 - tlib#string#TrimLeft(), tlib#string#TrimRight(), tlib#string#Strip()
403 - tlib#string#Printf1()
413 - g:tlib_inputlist_livesearch_threshold
415 - tlib#input#ListD(), World: Don't redisplay the list while typing
416 new letters; calculate filter regexps only once before filtering the
418 - World.vim: Minor changes to how filenames are handled.
424 - dir.vim: Use plain dir name in tlib#dir#Ensure()
425 - tlib#input#List(): An initial filter argument creates [[filter]]
426 and not as before [[''], [filter]].
427 - tlib#input#List(): When type was "si" and the item was picked by
428 filter, the wrong index was returned.
429 - tlib#input#List(): Don't check if chars are typed when displaying
430 the list for the first time.
433 - The arguments of tlib#tag#Collect() have changed.
434 - tlib#input#List(): The view can be "suspended" on initial display.
435 - tlib#input#List(): Follow/trace cursor functionality
438 - tlib#buffer#InsertText(): Respect tabs and (experimental) formatoptions+=or
439 - tlib/syntax.vim: Syntax-related functions
442 - FIX: very magic mode for tlib#rx#Escape() (thanks A Politz)
443 - FIX: tlib#arg#Ex: escape "!"
446 - Respect the setting of g:tlib_inputlist_filename_indicators
447 - tlib#input#List(): Reset syntax on resume; option to make list window "sticky"
448 - tlib#agent#ToggleStickyList()
449 - Simplified tlib#url#Decode()
450 - tlib#arg#Ex(): use fnameescape() if available