This file is indexed.

/usr/share/vim/addons/autoload/tovl/ui/filter_list.vim is in vim-addon-mw-utils 0.1-5.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
" OLD CODE !
" I should contribute the multiple filter feature to tlib

" filter list displays a list of items
" you can white / black filter them by regular expressions (similar to the
" tlib TToC command
" However you can edit the filters afterwards and select the cols which should
" be shown

fun! tovl#ui#filter_list#ListTest()
  call tovl#ui#filter_list#ListView({
	\ 'aligned' : 1,
	\ 'Continuation' : funcref#Function('echo string(ARGS[0])'),
	\ 'items' : [ {"aa" : "a\nAAAAAAAAAAA", 'bb' : "bbbbbbbbbbbbb\nB" }, 
		   \  {"aa" : "2a\n2AAAAAAAAAAAA", "bb" : "2 bbbbbbbbbbbbb\n2B"},
		   \  {"aa" : "XXX", "bb" : "YY"} ],
	\ })

endfun

fun! s:Intersection(a, b)
  return filter(copy(a:a), 'index(a:b, v:val) >= 0')
endf

fun! tovl#ui#filter_list#ListTestGotoLineCurrentBuf()
  let nr=1
  let lines = []
  for l in getline(0,line('$'))
    call add(lines, {'nr': nr, 'line' :l})
    let nr = nr +1
  endfor
  call tovl#ui#filter_list#ListView({
	\ 'aligned' : 0,
	\ 'keys' : ['nr','line'],
	\ 'number' : 1,
	\ 'selectByIdOrFilter' : 1,
	\ 'Continuation' : funcref#Function('exec ARGS[0]["nr"]'),
	\ 'items' : lines,
	\ })
endfun

" opens a new filtered list
" keys of opts parameters:
" Continuation: This function will be called with the selected items
" items: { key : (string or dict) }
"        items willl be modified. use copy(youritems) as argument to prevent
"        this. An item is either a string or a dict 
"        (eg {'file' : .., 'line': ... , 'msg' : .. )
" keys: list of keys to be shown (optional)
" filter: list of inital filters which must be applied
" contains [ { filter: .. , keep : .. }, ] see FilterItems() below
" aligned: default 0
" sp_cmd: the command to be used to create the new buffer (default ':e')
" init : 0 / 1 (default 1): wether to show the view right now
" number: 0 /1 (default 1): number items ?
" selectByIdOrFilter: 1: start in getchar() loop so that the user can select
"                        the item even faster
"                     auto: only do this if all items fit on screen
"                     (recommend)
" cmds: extra cmds to be run
" cursorAt : at which item to put the cursor?
"
" If you don't like the default view you can override UpdateDisplay
"
" Usage examples of this list control:
" - db results
" - replacement of the quickfix window
" - select a buffer etc
fun! tovl#ui#filter_list#ListView(opts)
  " ActivateAddons theonevimlib
  let d = {}
  let d.items = a:opts.items
  let d.cursorAt = get(a:opts, 'cursorAt', 0)
  let d.aligned = get(a:opts, 'aligned', 0)
  let d.sep = '  '
  let d.filter = get(a:opts, 'filter', [])
  " using sp because of bd! (FIXME)
  let d.sp_cmd = get(a:opts, 'sp_cmd', 'sp')
  let d.allKeys = {}
  let d.closeOnContinuation = get(a:opts,'closeOnContinuation',1)
  " don't recommend OnSingleMatch, use OnSingleMatchCR instead
  let d.continueOnSingleMatch = get(a:opts, 'continueOnSingleMatch',0)
  let d.continueOnSingleMatchCR = get(a:opts, 'continueOnSingleMatchCR',1)
  let d.selectByIdOrFilter = get(a:opts, 'selectByIdOrFilter', 0)
  let d.linesToItems = {}
  let d.number = get(a:opts, 'number', 1)
  let d.cmds = get(a:opts, 'cmds', [])
  let d.syn_cmds = get(a:opts, 'syn_cmds', [])

  if has_key(a:opts,'keys') | let d.keys = a:opts.keys | endif
  if has_key(a:opts,'Continuation') | let d.Continuation = a:opts.Continuation | endif

  " cache already filtered items in case we want to view really long results
  " contains [ { filter : { regex: .. , keep : .. } , items : .. , cursorAt :}, 
  "            { filter : { ... } , items: .. , cursorAt : }
  let d.cached = []
  " id of buffer
  let d.buffer = -1
  let d.modeText = ''

  fun d.HelpText()
    return [ "you've entered the the help of the powerful filtered view buffer",
	   \ "",
	   \ "type f to start filtering items by regex",
	   \ "type F to start dropping items by regex",
	   \ "k / K will ask you for the key to apply the filter to first",
	   \ "apply the filter by <cr> and press <cr> again to select item",
	   \ "",
	   \ "use :ShowAppliedFilters to list active filters",
	   \ "use :ToggleAlignment to toggle alignment",
	   \ "",
	   \ "TODO: Implement sorting, implement interface to change keys (displayed columns)"
	   \ ]
  endfun

  " create new scratch buffer
  " preprocess items calculating line count and maxwidth for all items
  fun d.NewBufferAndInit()
    let self.bufferId = bufnr(bufname('%'))
    for idx in range(0,len(self.items)-1)
      if type(self.items[idx]) != 4
	" no dict yet, make it one
	let self.items[idx] = {'string_line' : self.items[idx]}
      endif
      let new = {}
      for [k,v] in items(self.items[idx])
	let lines = split(v,"\n")
	let self.items[idx][k] = { 'text' : v, 'rows' : len(lines), 'cols' : max(map(copy(lines),'len(v:val)')), 'lines' : lines }
	let self.allKeys[k] = 1
        unlet k v
      endfor
    endfor
    call tovl#scratch_buffer#ScratchBuffer({
	  \ 'help' : funcref#Function(self.HelpText,{ 'self' : self }),
	  \ 'sp_cmd' : self.sp_cmd,
	  \ 'cmds' : self.cmds
	  \ })
    " I assume we have some kind of formatting anyway. Thus breaking lines is bad!
    set nowrap
    setlocal cursorline
    let b:filtered_view = self
    command! -buffer -nargs=0 ToggleAlignment call b:filtered_view.ToggleAlignment()
    command! -buffer -nargs=0 ShowAppliedFilters call b:filtered_view.ShowAppliedFilters()
    command! -buffer -nargs=0 RemoveFilters call b:filtered_view.RemoveFilters()
    noremap <buffer> f :call b:filtered_view.FilterFromKeyboard(1,'')<cr>
    " noremap <buffer> f :call b:filtered_view.FilterFromKeyboard(1)<cr>
    noremap <buffer> F :call b:filtered_view.FilterFromKeyboard(0,'')<cr>
    if has_key(self,'Continuation')
      nnoremap <buffer> <cr> :call b:filtered_view.Continue()<cr>
    endif
    "noremap <buffer> k
    "noremap <buffer> K

    let [items, cursorAt] = self.FilteredItems()
    " len(items) is an approximation because one item can have multiple
    " lines.. However adding the lines first to check takes too much time
    if self.selectByIdOrFilter == 1 || (self.selectByIdOrFilter == 'auto' && winheight('%') > len(items) )
      call self.SelectByIdOrFilter()
    else
      " user should choose how to proceed
      call self.UpdateDisplay()
    endif
  endfun

  " user interface
  fun d.ToggleAlignment()
    let self.aligned = !self.aligned
    call self.UpdateDisplay()
  endfun
  fun d.ShowAppliedFilters()
    for i in self.filter | echo string(i) | endfor
  endfun
  fun d.RemoveFilters()
    let self.filter = []
    call self.UpdateDisplay()
  endfun
  fun d.Continue()
    let item = self.CurrentItem()
    call self.DoContinue(item)
  endfun
  fun d.DoContinue(v)
    if self.closeOnContinuation | bw! | endif
    call funcref#Call(self.Continuation,[a:v])
  endfun

  fun d.MapToOriginal(v)
    if has_key(a:v, 'string_line')
      return a:v.string_line.text
    else
      let d = {}
      for [k,v] in items(a:v)
	let d[k] = v.text
	unlet k v
      endfor
      return d
    endif
  endfun

  fun d.CurrentItem()
    let idx=line('.')-len(self.headerLines)
    while idx >= 0
      if has_key(self.linesToItems, idx)
	return self.MapToOriginal(self.FilteredItems()[0][self.linesToItems[idx]])
      else
	let idx = idx -1
      endif
    endwhile
    throw "internal error, couldn't determine selected item!"
  endfun

  " updates the filter cache and returns the final filtered items
  fun d.FilteredItems()
    " update cache
    let idx = 0
    let [items, cursorAt] = [self.items, self.cursorAt]
    for idx in range(0, len(self.filter)-1)
      if idx +1 > len(self.cached) || self.cached[idx]['filter'] != self.filter[idx]
	let self.cached = self.cached[:idx-1]
	let [items, cursorAt] = self.FilterItem(copy(items), self.filter[idx], cursorAt)
	call add(self.cached, { 'cursorAt' : cursorAt, 'items' : items, 'filter' : self.filter[idx]})
      else
        let ci = self.cached[idx]
	let [items, cursorAt] = [ci['items'], ci['cursorAt']]
      endif
    endfor
    return [items, cursorAt]
  endfun

  " calling this will return a set of lines which are expected to be the new
  " buffer contents. The self.linesToItems dict is updated
  fun d.UpdateDisplay()

    if empty(self.filter)
      let self.statusline= 'no filter applied, :Help for help'
    else
      let self.statusline = len(self.filter).' '.string(self.filter[-1])
    endif

    let self.linesToItems = {}
    let [items, cursorAt] = self.FilteredItems()
    "let num_width = printf('%.0f', trunc(log10(len(items))+1))
    let num_width = 4
    if self.aligned
      " get column width.. (probably will not work with unicde characters.. I
      " don't have a better solution)
      let maxlens={}
      for i in items
	for [k,v] in items(i)
	  if get(maxlens,k,0) < v.cols
	    let maxlens[k] = v.cols
	  endif
	endfor
      endfor
    endif

    " format lines
    let self.headerLines = [self.modeText]
    let lines = copy(self.headerLines)
    let lines_count = 0
    if self.number
      let fmt_startA = '%'.num_width.'s)'
      let fmt_startB = '%'.num_width.'s'
    else
      let fmt_startA = '' | let fmt_startB = ''
    endif
    let cursorAtLine = 1 " sane default
    for idx in range(0,len(items)-1)
      let self.linesToItems[lines_count + 1] = idx
      let i = items[idx]
      let keys = has_key(self,'keys')
	    \ ? s:Intersection(self.keys, keys(i))
	    \ : keys(i)
      let fmt = ''
      let args =  [i]
      let cols = []
      for k in keys
	let fmt .= self.sep.'%-'.(self.aligned ? maxlens[k] : i[k]['cols']).'s'
	call add(cols, i[k])
      endfor
      for row in range(0, max([1] + map(copy(cols),'v:val["rows"]'))-1)
	let fmt_args = row == 0 ? [fmt_startA.fmt] :  [fmt_startB.fmt]
	if self.number
	  call add(fmt_args, row == 0 ? idx : '')
	endif
	for c in cols
	  call add(fmt_args, c.rows <= row ? '' : c.lines[row])
	endfor
	call add(lines, call('printf', fmt_args))
	let lines_count += 1
      endfor
      if idx == cursorAt
        let cursorAtLine = lines_count
      endif
    endfor
    " update stauts line to show last applied filter
    " disabled cause it causes trouble on :wincmd w
    " setlocal statusline=%!b:filtered_view.statusline

    " syntax
    syn clear
    for s in self.syn_cmds | exec s | endfor
    let id = 0
    " highlight filter regex in buffer as well
    let syn_ids = [ 'Underlined', 'Todo', 'Error', 'Type', 'Statement' ]
    for f in self.filter
      if !f.keep || !has_key(f, 'regex') | continue | endif
      if f.regex != ''
        try
	exec 'syn match '.syn_ids[id % len(syn_ids)].' '.string(f.regex)
        catch /.*/
          " ignore errors such as \ without following characters. Thus just
          " ignore and wait for the next character
        endtry
      endif
      let id = id +1
    endfor
    if len(lines) > winheight('%')
      call extend(lines, self.headerLines)
    endif
    normal ggdG
    call append(0, lines)
    " place cursor
    exec (cursorAtLine+1)
    " move cursor into the middle of the window
    normal zz
  endf

  " filter = keys :
  "  filter = string to be executed containing Val
  "  keep = 1  keep on match 
  "       = 0  drop on match
  "  key (optional)
  "  cursorAt: at which item to put the cursor
  "            if that item is deleted it will be placed at the item above
  " optional: key of dict if dict
  fun d.FilterItem(items, filter, cursorAt)
    let filter = 'Val =~ '.string(a:filter.regex)
    let keep = a:filter.keep
    let cursorAt = a:cursorAt

    for idx in reverse(range(0, len(a:items)-1))
      let i = a:items[idx]
      if has_key(a:filter,'key')
	let key = a:filter.key
	if has_key(i, key)
	  " key given, only filter by this column
	  let Val = i[key]['text']
	  exec 'let any = '.filter
	else
	  let any = 0
	endif
      else
	let any = 0
	" no key given, try all
	for x in values(i)
	  let Val = x['text']
	  exec 'let any =  '.filter
	  if any | break | endif
	endfor
      endif
      if any != keep
	call remove(a:items, idx)
        if idx <= cursorAt
          let cursorAt = cursorAt -1
        endif
      endif
    endfor
    return [a:items, cursorAt]
  endfun

  " if the user enters a number select by index else start filtering..
  fun d.SelectByIdOrFilter()
    let idx=''
    let items = self.FilteredItems()[0]
    try
      let self.modeText = '[0-9]* : select by index| <esc>: escape getchar() loop, any char: start filtering'
      call self.UpdateDisplay() | redraw
      while 1
	let c=getchar()
	if index([13,10],c) >= 0
	  return self.DoContinue(self.MapToOriginal(items[idx]))
	elseif index([27], c) >=0
	  " esc, abort
	  return
	else
	  if type(c) == 0
	    let c = nr2char(c)
	  endif
	  if c == "\<bs>" || index(map(range(0,10),'v:val.""'),c) >= 0
	    if c == "\<bs>"
	      let idx = idx[:-2]
	    else
	      let idx .= c
	    endif
	    if idx < len(items) && idx.'0' > len(items) || idx == 0 && len(items) < 10
	      " only match
	      return self.DoContinue(self.MapToOriginal(items[idx]))
	    endif
	  else
	    return self.FilterFromKeyboard(1,c)
	  endif
	endif
      endwhile
    finally
      let self.modeText = ''
    endtry
  endfun

  " gets a regular expresion filter by keybaord and updates the display while
  " you're typing. The regex ist shown in the statusline
  fun d.FilterFromKeyboard(keep, start, ...)
    let self.modeText = 'press ESC to exit getchar() loop'
    call self.UpdateDisplay() | redraw

    try
      let key_text = a:0 > 0 ? 'key : '.a:1 : ''
      let filter_bak = self.filter
      let filter = copy(self.filter)
      let start = a:start
      let filter_new = ''
      while 1
	if start != ''
	  " use c= last char to force updating display etc
	  let filter_new = start[:-2]
	  let c = start[-1:]
	  let start = ''
	else
	  let c=getchar()
	endif 
	if index([13,10],c) >= 0
	  " c-j or return, accept new filter
	  let items = self.FilteredItems()
	  if len(items) == 1 && has_key(self, 'Continuation') && self.continueOnSingleMatchCR
	    call self.DoContinue(self.MapToOriginal(items[0]))
	  endif
	  return
	elseif index([27], c) >=0
	  " esc, abort
	  let self.filter = filter_bak
	  call self.UpdateDisplay()
	  return
	else
	  if type(c) == 0
	    let c = nr2char(c)
	  endif
	  if c == "\<bs>"
	    let filter_new = filter_new[:-2]
	  else
	    let filter_new .= c
	  endif
	  let d = {'keep' : a:keep, 'regex' : filter_new }
	  if a:0 > 0
	    let d['key'] = a:1
	  endif
	  let self.filter = copy(filter_bak)
	  call add(self.filter, d)
	  let items = self.FilteredItems()
	  if len(items) == 1 && has_key(self, 'Continuation') && self.continueOnSingleMatch
	    call self.DoContinue(self.MapToOriginal(items[0]))
	    return
	  endif
	  call self.UpdateDisplay() | redraw
	endif
      endwhile
    finally
      let self.modeText = ''
    endtry
  endfun

  if get(a:opts,'init',1)
    call d.NewBufferAndInit()
  endif
endfun