mirror of
https://github.com/harish2704/dotFiles.git
synced 2026-09-10 15:21:09 +00:00
Adding a skel for plasma workspace
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<!-- ISSUES NOT FOLLOWING THIS TEMPLATE WILL BE CLOSED AND DELETED -->
|
||||
|
||||
<!-- Check all that apply [x] -->
|
||||
|
||||
- [ ] I have read through https://github.com/junegunn/fzf.vim/blob/master/README.md
|
||||
- [ ] I have read through https://github.com/junegunn/fzf/blob/master/README-VIM.md
|
||||
- [ ] I have read through the manual page of fzf (`man fzf`)
|
||||
- [ ] I have searched through the existing issues
|
||||
|
||||
<!--
|
||||
|
||||
Before submitting
|
||||
=================
|
||||
|
||||
- Make sure that you have the latest version of fzf and fzf.vim
|
||||
- Check if your problem is reproducible with a minimal configuration
|
||||
|
||||
Start Vim with a minimal configuration
|
||||
======================================
|
||||
|
||||
vim -Nu <(curl https://gist.githubusercontent.com/junegunn/6936bf79fedd3a079aeb1dd2f3c81ef5/raw)
|
||||
|
||||
-->
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
doc/tags
|
||||
@@ -0,0 +1,413 @@
|
||||
fzf :heart: vim
|
||||
===============
|
||||
|
||||
Things you can do with [fzf][fzf] and Vim.
|
||||
|
||||
Rationale
|
||||
---------
|
||||
|
||||
[fzf][fzf] in itself is not a Vim plugin, and the official repository only
|
||||
provides the [basic wrapper function][run] for Vim and it's up to the users to
|
||||
write their own Vim commands with it. However, I've learned that many users of
|
||||
fzf are not familiar with Vimscript and are looking for the "default"
|
||||
implementation of the features they can find in the alternative Vim plugins.
|
||||
|
||||
This repository is a bundle of fzf-based commands and mappings extracted from
|
||||
my [.vimrc][vimrc] to address such needs. They are *not* designed to be
|
||||
flexible or configurable, and there's no guarantee of backward-compatibility.
|
||||
|
||||
Why you should use fzf on Vim
|
||||
-----------------------------
|
||||
|
||||
Because you can and you love fzf.
|
||||
|
||||
fzf runs asynchronously and can be orders of magnitude faster than similar Vim
|
||||
plugins. However, the benefit may not be noticeable if the size of the input
|
||||
is small, which is the case for many of the commands provided here.
|
||||
Nevertheless I wrote them anyway since it's really easy to implement custom
|
||||
selector with fzf.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
fzf.vim depends on the basic Vim plugin of [the main fzf
|
||||
repository][fzf-main], which means you need to **set up both "fzf" and
|
||||
"fzf.vim" on Vim**. To learn more about fzf/Vim integration, see
|
||||
[README-VIM][README-VIM].
|
||||
|
||||
[fzf-main]: https://github.com/junegunn/fzf
|
||||
[README-VIM]: https://github.com/junegunn/fzf/blob/master/README-VIM.md
|
||||
|
||||
### Using [vim-plug](https://github.com/junegunn/vim-plug)
|
||||
|
||||
```vim
|
||||
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||
Plug 'junegunn/fzf.vim'
|
||||
```
|
||||
|
||||
`fzf#install()` makes sure that you have the latest binary, but it's optional,
|
||||
so you can omit it if you use a plugin manager that doesn't support hooks.
|
||||
|
||||
Commands
|
||||
--------
|
||||
|
||||
| Command | List |
|
||||
| --- | --- |
|
||||
| `:Files [PATH]` | Files (runs `$FZF_DEFAULT_COMMAND` if defined) |
|
||||
| `:GFiles [OPTS]` | Git files (`git ls-files`) |
|
||||
| `:GFiles?` | Git files (`git status`) |
|
||||
| `:Buffers` | Open buffers |
|
||||
| `:Colors` | Color schemes |
|
||||
| `:Ag [PATTERN]` | [ag][ag] search result (`ALT-A` to select all, `ALT-D` to deselect all) |
|
||||
| `:Rg [PATTERN]` | [rg][rg] search result (`ALT-A` to select all, `ALT-D` to deselect all) |
|
||||
| `:Lines [QUERY]` | Lines in loaded buffers |
|
||||
| `:BLines [QUERY]` | Lines in the current buffer |
|
||||
| `:Tags [QUERY]` | Tags in the project (`ctags -R`) |
|
||||
| `:BTags [QUERY]` | Tags in the current buffer |
|
||||
| `:Marks` | Marks |
|
||||
| `:Windows` | Windows |
|
||||
| `:Locate PATTERN` | `locate` command output |
|
||||
| `:History` | `v:oldfiles` and open buffers |
|
||||
| `:History:` | Command history |
|
||||
| `:History/` | Search history |
|
||||
| `:Snippets` | Snippets ([UltiSnips][us]) |
|
||||
| `:Commits` | Git commits (requires [fugitive.vim][f]) |
|
||||
| `:BCommits` | Git commits for the current buffer |
|
||||
| `:Commands` | Commands |
|
||||
| `:Maps` | Normal mode mappings |
|
||||
| `:Helptags` | Help tags <sup id="a1">[1](#helptags)</sup> |
|
||||
| `:Filetypes` | File types
|
||||
|
||||
- Most commands support `CTRL-T` / `CTRL-X` / `CTRL-V` key
|
||||
bindings to open in a new tab, a new split, or in a new vertical split
|
||||
- Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen
|
||||
- You can set `g:fzf_command_prefix` to give the same prefix to the commands
|
||||
- e.g. `let g:fzf_command_prefix = 'Fzf'` and you have `FzfFiles`, etc.
|
||||
|
||||
(<a name="helptags">1</a>: `Helptags` will shadow the command of the same name
|
||||
from [pathogen][pat]. But its functionality is still available via `call
|
||||
pathogen#helptags()`. [↩](#a1))
|
||||
|
||||
[pat]: https://github.com/tpope/vim-pathogen
|
||||
[f]: https://github.com/tpope/vim-fugitive
|
||||
|
||||
Customization
|
||||
-------------
|
||||
|
||||
### Global options
|
||||
|
||||
Every command in fzf.vim internally calls `fzf#wrap` function of the main
|
||||
repository which supports a set of global option variables. So please read
|
||||
through [README-VIM][README-VIM] to learn more about them.
|
||||
|
||||
#### Preview window
|
||||
|
||||
If the width of the screen is wider than 120 columns, some commands will show
|
||||
the preview window on the right. You can customize the behavior with
|
||||
`g:fzf_preview_window`. Here are some examples:
|
||||
|
||||
```vim
|
||||
" Empty value to disable preview window altogether
|
||||
let g:fzf_preview_window = ''
|
||||
|
||||
" Always enable preview window on the right with 60% width
|
||||
let g:fzf_preview_window = 'right:60%'
|
||||
```
|
||||
|
||||
### Command-local options
|
||||
|
||||
A few commands in fzf.vim can be customized with global option variables shown
|
||||
below.
|
||||
|
||||
```vim
|
||||
" [Buffers] Jump to the existing window if possible
|
||||
let g:fzf_buffers_jump = 1
|
||||
|
||||
" [[B]Commits] Customize the options used by 'git log':
|
||||
let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'
|
||||
|
||||
" [Tags] Command to generate tags file
|
||||
let g:fzf_tags_command = 'ctags -R'
|
||||
|
||||
" [Commands] --expect expression for directly executing the command
|
||||
let g:fzf_commands_expect = 'alt-enter,ctrl-x'
|
||||
```
|
||||
|
||||
### Advanced customization
|
||||
|
||||
#### Vim functions
|
||||
|
||||
Each command in fzf.vim is backed by a Vim function. You can override
|
||||
a command or define a variation of it by calling its corresponding function.
|
||||
|
||||
| Command | Vim function |
|
||||
| --- | --- |
|
||||
| `Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])` |
|
||||
| `GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])` |
|
||||
| `GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])` |
|
||||
| `Buffers` | `fzf#vim#buffers([spec dict], [fullscreen bool])` |
|
||||
| `Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])` |
|
||||
| `Rg` | `fzf#vim#grep(command, [has_column bool], [spec dict], [fullscreen bool])` |
|
||||
| ... | ... |
|
||||
|
||||
(We can see that the last two optional arguments of each function are
|
||||
identical. They are directly passed to `fzf#wrap` function. If you haven't
|
||||
read [README-VIM][README-VIM] already, please read it before proceeding.)
|
||||
|
||||
#### Example: Customizing `Files` command
|
||||
|
||||
This is the default definition of `Files` command:
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=? -complete=dir Files call fzf#vim#files(<q-args>, <bang>0)
|
||||
```
|
||||
|
||||
Let's say you want to a variation of it called `ProjectFiles` that only
|
||||
searches inside `~/projects` directory. Then you can do it like this:
|
||||
|
||||
```vim
|
||||
command! -bang ProjectFiles call fzf#vim#files('~/projects', <bang>0)
|
||||
```
|
||||
|
||||
Or, if you want to override the command with different fzf options, just pass
|
||||
a custom spec to the function.
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline']}, <bang>0)
|
||||
```
|
||||
|
||||
Want a preview window?
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline', '--preview', 'cat {}']}, <bang>0)
|
||||
```
|
||||
|
||||
It kind of works, but you probably want a nicer previewer program than `cat`.
|
||||
fzf.vim ships [a versatile preview script](bin/preview.sh) you can readily
|
||||
use. It internally executes [bat](https://github.com/sharkdp/bat) for syntax
|
||||
highlighting, so make sure to install it.
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline', '--preview', '~/.vim/plugged/fzf.vim/bin/preview.sh {}']}, <bang>0)
|
||||
```
|
||||
|
||||
However, it's not ideal to hard-code the path to the script which can be
|
||||
different in different circumstances. So in order to make it easier to set up
|
||||
the previewer, fzf.vim provides `fzf#vim#with_preview` helper function.
|
||||
Similarly to `fzf#wrap`, it takes a spec dictionary and returns a copy of it
|
||||
with additional preview options.
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview({'options': ['--layout=reverse', '--info=inline']}), <bang>0)
|
||||
```
|
||||
|
||||
You can just omit the spec argument if you only want the previewer.
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)
|
||||
```
|
||||
|
||||
#### Example: `git grep` wrapper
|
||||
|
||||
The following example implements `GGrep` command that works similarly to
|
||||
predefined `Ag` or `Rg` using `fzf#vim#grep`.
|
||||
|
||||
- The second argument to `fzf#vim#grep` is 0 (false), because `git grep` does
|
||||
not print column numbers.
|
||||
- We set the base directory to git root by setting `dir` attribute in spec
|
||||
dictionary.
|
||||
- [The preview script](bin/preview.sh) supports `grep` format
|
||||
(`FILE_PATH:LINE_NO:...`), so we can just wrap the spec with
|
||||
`fzf#vim#with_preview` as before to enable previewer.
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=* GGrep
|
||||
\ call fzf#vim#grep(
|
||||
\ 'git grep --line-number -- '.shellescape(<q-args>), 0,
|
||||
\ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), <bang>0)
|
||||
```
|
||||
|
||||
#### Example: `Rg` command with preview window
|
||||
|
||||
You can see the definition of `Rg` command with `:command Rg`. With the
|
||||
information, you can redefine it with the preview window enabled. In this
|
||||
case, we're only interested in setting up the preview window, so we will omit
|
||||
the spec argument to `fzf#vim#preview`.
|
||||
|
||||
```vim
|
||||
command! -bang -nargs=* Rg
|
||||
\ call fzf#vim#grep(
|
||||
\ 'rg --column --line-number --no-heading --color=always --smart-case -- '.shellescape(<q-args>), 1,
|
||||
\ fzf#vim#with_preview(), <bang>0)
|
||||
```
|
||||
|
||||
#### Example: Advanced ripgrep integration
|
||||
|
||||
In the default implementation of `Rg`, ripgrep process starts only once with
|
||||
the initial query (e.g. `:Rg foo`) and fzf filters the output of the process.
|
||||
|
||||
This is okay in most cases because fzf is quite performant even with millions
|
||||
of lines, but we can make fzf completely delegate its search responsibliity to
|
||||
ripgrep process by making it restart ripgrep whenever the query string is
|
||||
updated. In this scenario, fzf becomes a simple selector interface rather than
|
||||
a "fuzzy finder".
|
||||
|
||||
- We will name the new command all-uppercase `RG` so we can still access the
|
||||
default version.
|
||||
- `--bind 'change:reload:rg ... {q}'` will make fzf restart ripgrep process
|
||||
whenever the query string, denoted by `{q}`, is changed.
|
||||
- With `--phony` option, fzf will no longer perform search. The query string
|
||||
you type on fzf prompt is only used for restarting ripgrep process.
|
||||
- Also note that we enabled previewer with `fzf#vim#with_preview`.
|
||||
|
||||
```vim
|
||||
function! RipgrepFzf(query, fullscreen)
|
||||
let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case -- %s || true'
|
||||
let initial_command = printf(command_fmt, shellescape(a:query))
|
||||
let reload_command = printf(command_fmt, '{q}')
|
||||
let spec = {'options': ['--phony', '--query', a:query, '--bind', 'change:reload:'.reload_command]}
|
||||
call fzf#vim#grep(initial_command, 1, fzf#vim#with_preview(spec), a:fullscreen)
|
||||
endfunction
|
||||
|
||||
command! -nargs=* -bang RG call RipgrepFzf(<q-args>, <bang>0)
|
||||
```
|
||||
|
||||
Mappings
|
||||
--------
|
||||
|
||||
| Mapping | Description |
|
||||
| --- | --- |
|
||||
| `<plug>(fzf-maps-n)` | Normal mode mappings |
|
||||
| `<plug>(fzf-maps-i)` | Insert mode mappings |
|
||||
| `<plug>(fzf-maps-x)` | Visual mode mappings |
|
||||
| `<plug>(fzf-maps-o)` | Operator-pending mappings |
|
||||
| `<plug>(fzf-complete-word)` | `cat /usr/share/dict/words` |
|
||||
| `<plug>(fzf-complete-path)` | Path completion using `find` (file + dir) |
|
||||
| `<plug>(fzf-complete-file)` | File completion using `find` |
|
||||
| `<plug>(fzf-complete-line)` | Line completion (all open buffers) |
|
||||
| `<plug>(fzf-complete-buffer-line)` | Line completion (current buffer only) |
|
||||
|
||||
```vim
|
||||
" Mapping selecting mappings
|
||||
nmap <leader><tab> <plug>(fzf-maps-n)
|
||||
xmap <leader><tab> <plug>(fzf-maps-x)
|
||||
omap <leader><tab> <plug>(fzf-maps-o)
|
||||
|
||||
" Insert mode completion
|
||||
imap <c-x><c-k> <plug>(fzf-complete-word)
|
||||
imap <c-x><c-f> <plug>(fzf-complete-path)
|
||||
imap <c-x><c-l> <plug>(fzf-complete-line)
|
||||
```
|
||||
|
||||
Completion functions
|
||||
--------------------
|
||||
|
||||
| Function | Description |
|
||||
| --- | --- |
|
||||
| `fzf#vim#complete#path(command, [spec])` | Path completion |
|
||||
| `fzf#vim#complete#word([spec])` | Word completion |
|
||||
| `fzf#vim#complete#line([spec])` | Line completion (all open buffers) |
|
||||
| `fzf#vim#complete#buffer_line([spec])` | Line completion (current buffer only) |
|
||||
|
||||
```vim
|
||||
" Path completion with custom source command
|
||||
inoremap <expr> <c-x><c-f> fzf#vim#complete#path('fd')
|
||||
inoremap <expr> <c-x><c-f> fzf#vim#complete#path('rg --files')
|
||||
|
||||
" Word completion with custom spec with popup layout option
|
||||
inoremap <expr> <c-x><c-k> fzf#vim#complete#word({'window': { 'width': 0.2, 'height': 0.9, 'xoffset': 1 }})
|
||||
```
|
||||
|
||||
Custom completion
|
||||
-----------------
|
||||
|
||||
`fzf#vim#complete` is a helper function for creating custom fuzzy completion
|
||||
using fzf. If the first parameter is a command string or a Vim list, it will
|
||||
be used as the source.
|
||||
|
||||
```vim
|
||||
" Replace the default dictionary completion with fzf-based fuzzy completion
|
||||
inoremap <expr> <c-x><c-k> fzf#vim#complete('cat /usr/share/dict/words')
|
||||
```
|
||||
|
||||
For advanced uses, you can pass an options dictionary to the function. The set
|
||||
of options is pretty much identical to that for `fzf#run` only with the
|
||||
following exceptions:
|
||||
|
||||
- `reducer` (funcref)
|
||||
- Reducer transforms the output lines of fzf into a single string value
|
||||
- `prefix` (string or funcref; default: `\k*$`)
|
||||
- Regular expression pattern to extract the completion prefix
|
||||
- Or a function to extract completion prefix
|
||||
- Both `source` and `options` can be given as funcrefs that take the
|
||||
completion prefix as the argument and return the final value
|
||||
- `sink` or `sink*` are ignored
|
||||
|
||||
```vim
|
||||
" Global line completion (not just open buffers. ripgrep required.)
|
||||
inoremap <expr> <c-x><c-l> fzf#vim#complete(fzf#wrap({
|
||||
\ 'prefix': '^.*$',
|
||||
\ 'source': 'rg -n ^ --color always',
|
||||
\ 'options': '--ansi --delimiter : --nth 3..',
|
||||
\ 'reducer': { lines -> join(split(lines[0], ':\zs')[2:], '') }}))
|
||||
```
|
||||
|
||||
### Reducer example
|
||||
|
||||
```vim
|
||||
function! s:make_sentence(lines)
|
||||
return substitute(join(a:lines), '^.', '\=toupper(submatch(0))', '').'.'
|
||||
endfunction
|
||||
|
||||
inoremap <expr> <c-x><c-s> fzf#vim#complete({
|
||||
\ 'source': 'cat /usr/share/dict/words',
|
||||
\ 'reducer': function('<sid>make_sentence'),
|
||||
\ 'options': '--multi --reverse --margin 15%,0',
|
||||
\ 'left': 20})
|
||||
```
|
||||
|
||||
Status line of terminal buffer
|
||||
------------------------------
|
||||
|
||||
When fzf starts in a terminal buffer (see [fzf/README-VIM.md][termbuf]), you
|
||||
may want to customize the statusline of the containing buffer.
|
||||
|
||||
[termbuf]: https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzf-inside-terminal-buffer
|
||||
|
||||
### Hide statusline
|
||||
|
||||
```vim
|
||||
autocmd! FileType fzf set laststatus=0 noshowmode noruler
|
||||
\| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
|
||||
```
|
||||
|
||||
### Custom statusline
|
||||
|
||||
```vim
|
||||
function! s:fzf_statusline()
|
||||
" Override statusline as you like
|
||||
highlight fzf1 ctermfg=161 ctermbg=251
|
||||
highlight fzf2 ctermfg=23 ctermbg=251
|
||||
highlight fzf3 ctermfg=237 ctermbg=251
|
||||
setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
|
||||
endfunction
|
||||
|
||||
autocmd! User FzfStatusLine call <SID>fzf_statusline()
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
MIT
|
||||
|
||||
[fzf]: https://github.com/junegunn/fzf
|
||||
[run]: https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzfrun
|
||||
[vimrc]: https://github.com/junegunn/dotfiles/blob/master/vimrc
|
||||
[ag]: https://github.com/ggreer/the_silver_searcher
|
||||
[rg]: https://github.com/BurntSushi/ripgrep
|
||||
[us]: https://github.com/SirVer/ultisnips
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
" Copyright (c) 2015 Junegunn Choi
|
||||
"
|
||||
" MIT License
|
||||
"
|
||||
" Permission is hereby granted, free of charge, to any person obtaining
|
||||
" a copy of this software and associated documentation files (the
|
||||
" "Software"), to deal in the Software without restriction, including
|
||||
" without limitation the rights to use, copy, modify, merge, publish,
|
||||
" distribute, sublicense, and/or sell copies of the Software, and to
|
||||
" permit persons to whom the Software is furnished to do so, subject to
|
||||
" the following conditions:
|
||||
"
|
||||
" The above copyright notice and this permission notice shall be
|
||||
" included in all copies or substantial portions of the Software.
|
||||
"
|
||||
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
let s:is_win = has('win32') || has('win64')
|
||||
|
||||
function! s:extend(base, extra)
|
||||
let base = copy(a:base)
|
||||
if has_key(a:extra, 'options')
|
||||
let extra = copy(a:extra)
|
||||
let extra.extra_options = remove(extra, 'options')
|
||||
return extend(base, extra)
|
||||
endif
|
||||
return extend(base, a:extra)
|
||||
endfunction
|
||||
|
||||
if v:version >= 704
|
||||
function! s:function(name)
|
||||
return function(a:name)
|
||||
endfunction
|
||||
else
|
||||
function! s:function(name)
|
||||
" By Ingo Karkat
|
||||
return function(substitute(a:name, '^s:', matchstr(expand('<sfile>'), '<SNR>\d\+_\zefunction$'), ''))
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! fzf#vim#complete#word(...)
|
||||
return fzf#vim#complete(s:extend({
|
||||
\ 'source': 'cat /usr/share/dict/words'},
|
||||
\ get(a:000, 0, fzf#wrap())))
|
||||
endfunction
|
||||
|
||||
" ----------------------------------------------------------------------------
|
||||
" <plug>(fzf-complete-path)
|
||||
" <plug>(fzf-complete-file)
|
||||
" <plug>(fzf-complete-file-ag)
|
||||
" ----------------------------------------------------------------------------
|
||||
function! s:file_split_prefix(prefix)
|
||||
let expanded = expand(a:prefix)
|
||||
let slash = (s:is_win && !&shellslash) ? '\\' : '/'
|
||||
return isdirectory(expanded) ?
|
||||
\ [expanded,
|
||||
\ substitute(a:prefix, '[/\\]*$', slash, ''),
|
||||
\ ''] :
|
||||
\ [fnamemodify(expanded, ':h'),
|
||||
\ substitute(fnamemodify(a:prefix, ':h'), '[/\\]*$', slash, ''),
|
||||
\ fnamemodify(expanded, ':t')]
|
||||
endfunction
|
||||
|
||||
function! s:file_source(prefix)
|
||||
let [dir, head, tail] = s:file_split_prefix(a:prefix)
|
||||
return printf(
|
||||
\ "cd %s && ".s:file_cmd." | sed %s",
|
||||
\ fzf#shellescape(dir), fzf#shellescape('s:^:'.(empty(a:prefix) || a:prefix == tail ? '' : head).':'))
|
||||
endfunction
|
||||
|
||||
function! s:file_options(prefix)
|
||||
let [_, head, tail] = s:file_split_prefix(a:prefix)
|
||||
return ['--prompt', head, '--query', tail]
|
||||
endfunction
|
||||
|
||||
function! s:fname_prefix(str)
|
||||
let isf = &isfname
|
||||
let white = []
|
||||
let black = []
|
||||
if isf =~ ',,,'
|
||||
call add(white, ',')
|
||||
let isf = substitute(isf, ',,,', ',', 'g')
|
||||
endif
|
||||
if isf =~ ',^,,'
|
||||
call add(black, ',')
|
||||
let isf = substitute(isf, ',^,,', ',', 'g')
|
||||
endif
|
||||
|
||||
for token in split(isf, ',')
|
||||
let target = white
|
||||
if token[0] == '^'
|
||||
let target = black
|
||||
let token = token[1:]
|
||||
endif
|
||||
|
||||
let ends = matchlist(token, '\(.\+\)-\(.\+\)')
|
||||
if empty(ends)
|
||||
call add(target, token)
|
||||
else
|
||||
let ends = map(ends[1:2], "len(v:val) == 1 ? char2nr(v:val) : str2nr(v:val)")
|
||||
for i in range(ends[0], ends[1])
|
||||
call add(target, nr2char(i))
|
||||
endfor
|
||||
endif
|
||||
endfor
|
||||
|
||||
let prefix = a:str
|
||||
for offset in range(1, len(a:str))
|
||||
let char = a:str[len(a:str) - offset]
|
||||
if (char =~ '\w' || index(white, char) >= 0) && index(black, char) < 0
|
||||
continue
|
||||
endif
|
||||
let prefix = strpart(a:str, len(a:str) - offset + 1)
|
||||
break
|
||||
endfor
|
||||
|
||||
return prefix
|
||||
endfunction
|
||||
|
||||
function! fzf#vim#complete#path(command, ...)
|
||||
let s:file_cmd = a:command
|
||||
return fzf#vim#complete(s:extend({
|
||||
\ 'prefix': s:function('s:fname_prefix'),
|
||||
\ 'source': s:function('s:file_source'),
|
||||
\ 'options': s:function('s:file_options')}, get(a:000, 0, fzf#wrap())))
|
||||
endfunction
|
||||
|
||||
" ----------------------------------------------------------------------------
|
||||
" <plug>(fzf-complete-line)
|
||||
" <plug>(fzf-complete-buffer-line)
|
||||
" ----------------------------------------------------------------------------
|
||||
function! s:reduce_line(lines)
|
||||
return join(split(a:lines[0], '\t\zs')[3:], '')
|
||||
endfunction
|
||||
|
||||
|
||||
function! fzf#vim#complete#line(...)
|
||||
let [display_bufnames, lines] = fzf#vim#_lines(0)
|
||||
let nth = display_bufnames ? 4 : 3
|
||||
return fzf#vim#complete(s:extend({
|
||||
\ 'prefix': '^.*$',
|
||||
\ 'source': lines,
|
||||
\ 'options': '--tiebreak=index --ansi --nth '.nth.'.. --tabstop=1',
|
||||
\ 'reducer': s:function('s:reduce_line')}, get(a:000, 0, fzf#wrap())))
|
||||
endfunction
|
||||
|
||||
function! fzf#vim#complete#buffer_line(...)
|
||||
return fzf#vim#complete(s:extend({
|
||||
\ 'prefix': '^.*$',
|
||||
\ 'source': fzf#vim#_uniq(getline(1, '$'))}, get(a:000, 0, fzf#wrap())))
|
||||
endfunction
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
puts 'preview.rb is deprecated. Use preview.sh instead.'
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
REVERSE="\x1b[7m"
|
||||
RESET="\x1b[m"
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "usage: $0 FILENAME[:LINENO][:IGNORED]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IFS=':' read -r -a INPUT <<< "$1"
|
||||
FILE=${INPUT[0]}
|
||||
CENTER=${INPUT[1]}
|
||||
|
||||
if [[ $1 =~ ^[A-Z]:\\ ]]; then
|
||||
FILE=$FILE:${INPUT[1]}
|
||||
CENTER=${INPUT[2]}
|
||||
fi
|
||||
|
||||
if [[ -n "$CENTER" && ! "$CENTER" =~ ^[0-9] ]]; then
|
||||
exit 1
|
||||
fi
|
||||
CENTER=${CENTER/[^0-9]*/}
|
||||
|
||||
FILE="${FILE/#\~\//$HOME/}"
|
||||
if [ ! -r "$FILE" ]; then
|
||||
echo "File not found ${FILE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MIME=$(file --dereference --mime "$FILE")
|
||||
if [[ "$MIME" =~ binary ]]; then
|
||||
echo "$MIME"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -z "$CENTER" ]; then
|
||||
CENTER=0
|
||||
fi
|
||||
|
||||
if [ -n "$FZF_PREVIEW_LINES" ]; then
|
||||
LINES=$FZF_PREVIEW_LINES
|
||||
else
|
||||
if [ -r /dev/tty ]; then
|
||||
LINES=$(stty size < /dev/tty | awk '{print $1}')
|
||||
else
|
||||
LINES=40
|
||||
fi
|
||||
fi
|
||||
|
||||
FIRST=$(($CENTER-$LINES/3))
|
||||
FIRST=$(($FIRST < 1 ? 1 : $FIRST))
|
||||
LAST=$((${FIRST}+${LINES}-1))
|
||||
|
||||
if [ -z "$FZF_PREVIEW_COMMAND" ] && command -v bat > /dev/null; then
|
||||
bat --style="${BAT_STYLE:-numbers}" --color=always --pager=never \
|
||||
--line-range=$FIRST:$LAST --highlight-line=$CENTER "$FILE"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
DEFAULT_COMMAND="highlight -O ansi -l {} || coderay {} || rougify {} || cat {}"
|
||||
CMD=${FZF_PREVIEW_COMMAND:-$DEFAULT_COMMAND}
|
||||
CMD=${CMD//{\}/$(printf %q "$FILE")}
|
||||
|
||||
eval "$CMD" 2> /dev/null | awk "NR >= $FIRST && NR <= $LAST { \
|
||||
if (NR == $CENTER) \
|
||||
{ gsub(/\x1b[[0-9;]*m/, \"&$REVERSE\"); printf(\"$REVERSE%s\n$RESET\", \$0); } \
|
||||
else printf(\"$RESET%s\n\", \$0); \
|
||||
}"
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
|
||||
foreach my $file (@ARGV) {
|
||||
open my $lines, $file;
|
||||
while (<$lines>) {
|
||||
unless (/^\!/) {
|
||||
s/^[^\t]*/sprintf("%-24s", $&)/e;
|
||||
s/$/\t$file/;
|
||||
print;
|
||||
}
|
||||
}
|
||||
close $lines;
|
||||
}
|
||||
@@ -0,0 +1,470 @@
|
||||
fzf-vim.txt fzf-vim Last change: May 3 2020
|
||||
FZF-VIM - TABLE OF CONTENTS *fzf-vim* *fzf-vim-toc*
|
||||
==============================================================================
|
||||
|
||||
fzf :heart: vim
|
||||
Rationale
|
||||
Why you should use fzf on Vim
|
||||
Installation
|
||||
Using vim-plug
|
||||
Commands
|
||||
Customization
|
||||
Global options
|
||||
Preview window
|
||||
Command-local options
|
||||
Advanced customization
|
||||
Vim functions
|
||||
Example: Customizing Files command
|
||||
Example: git grep wrapper
|
||||
Example: Rg command with preview window
|
||||
Example: Advanced ripgrep integration
|
||||
Mappings
|
||||
Completion functions
|
||||
Custom completion
|
||||
Reducer example
|
||||
Status line of terminal buffer
|
||||
Hide statusline
|
||||
Custom statusline
|
||||
License
|
||||
|
||||
FZF :HEART: VIM *fzf-vim-fzfheart-vim*
|
||||
==============================================================================
|
||||
|
||||
Things you can do with {fzf}{1} and Vim.
|
||||
|
||||
{1} https://github.com/junegunn/fzf
|
||||
|
||||
|
||||
RATIONALE *fzf-vim-rationale*
|
||||
==============================================================================
|
||||
|
||||
{fzf}{1} in itself is not a Vim plugin, and the official repository only
|
||||
provides the {basic wrapper function}{2} for Vim and it's up to the users to
|
||||
write their own Vim commands with it. However, I've learned that many users of
|
||||
fzf are not familiar with Vimscript and are looking for the "default"
|
||||
implementation of the features they can find in the alternative Vim plugins.
|
||||
|
||||
This repository is a bundle of fzf-based commands and mappings extracted from
|
||||
my {.vimrc}{3} to address such needs. They are not designed to be flexible or
|
||||
configurable, and there's no guarantee of backward-compatibility.
|
||||
|
||||
{1} https://github.com/junegunn/fzf
|
||||
{2} https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzfrun
|
||||
{3} https://github.com/junegunn/dotfiles/blob/master/vimrc
|
||||
|
||||
|
||||
WHY YOU SHOULD USE FZF ON VIM *fzf-vim-why-you-should-use-fzf-on-vim*
|
||||
==============================================================================
|
||||
|
||||
Because you can and you love fzf.
|
||||
|
||||
fzf runs asynchronously and can be orders of magnitude faster than similar Vim
|
||||
plugins. However, the benefit may not be noticeable if the size of the input
|
||||
is small, which is the case for many of the commands provided here.
|
||||
Nevertheless I wrote them anyway since it's really easy to implement custom
|
||||
selector with fzf.
|
||||
|
||||
|
||||
INSTALLATION *fzf-vim-installation*
|
||||
==============================================================================
|
||||
|
||||
fzf.vim depends on the basic Vim plugin of {the main fzf repository}{1}, which
|
||||
means you need to set up both "fzf" and "fzf.vim" on Vim. To learn more about
|
||||
fzf/Vim integration, see {README-VIM}{4}.
|
||||
|
||||
{1} https://github.com/junegunn/fzf
|
||||
{4} https://github.com/junegunn/fzf/blob/master/README-VIM.md
|
||||
|
||||
|
||||
< Using vim-plug >____________________________________________________________~
|
||||
*fzf-vim-using-vim-plug*
|
||||
>
|
||||
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||
Plug 'junegunn/fzf.vim'
|
||||
<
|
||||
`fzf#install()` makes sure that you have the latest binary, but it's optional,
|
||||
so you can omit it if you use a plugin manager that doesn't support hooks.
|
||||
|
||||
|
||||
COMMANDS *fzf-vim-commands*
|
||||
==============================================================================
|
||||
|
||||
*:Files* *:GFiles* *:Buffers* *:Colors* *:Ag* *:Rg* *:Lines* *:BLines* *:Tags* *:BTags* *:Marks*
|
||||
*:Windows* *:Locate* *:History* *:Snippets* *:Commits* *:BCommits* *:Commands* *:Maps*
|
||||
*:Helptags* *:Filetypes*
|
||||
|
||||
------------------+-----------------------------------------------------------------------
|
||||
Command | List ~
|
||||
------------------+-----------------------------------------------------------------------
|
||||
`:Files [PATH]` | Files (runs `$FZF_DEFAULT_COMMAND` if defined)
|
||||
`:GFiles [OPTS]` | Git files ( `git ls-files` )
|
||||
`:GFiles?` | Git files ( `git status` )
|
||||
`:Buffers` | Open buffers
|
||||
`:Colors` | Color schemes
|
||||
`:Ag [PATTERN]` | {ag}{5} search result ( `ALT-A` to select all, `ALT-D` to deselect all)
|
||||
`:Rg [PATTERN]` | {rg}{6} search result ( `ALT-A` to select all, `ALT-D` to deselect all)
|
||||
`:Lines [QUERY]` | Lines in loaded buffers
|
||||
`:BLines [QUERY]` | Lines in the current buffer
|
||||
`:Tags [QUERY]` | Tags in the project ( `ctags -R` )
|
||||
`:BTags [QUERY]` | Tags in the current buffer
|
||||
`:Marks` | Marks
|
||||
`:Windows` | Windows
|
||||
`:Locate PATTERN` | `locate` command output
|
||||
`:History` | `v:oldfiles` and open buffers
|
||||
`:History:` | Command history
|
||||
`:History/` | Search history
|
||||
`:Snippets` | Snippets ({UltiSnips}{7})
|
||||
`:Commits` | Git commits (requires {fugitive.vim}{8})
|
||||
`:BCommits` | Git commits for the current buffer
|
||||
`:Commands` | Commands
|
||||
`:Maps` | Normal mode mappings
|
||||
`:Helptags` | Help tags [1]
|
||||
`:Filetypes` | File types
|
||||
------------------+-----------------------------------------------------------------------
|
||||
|
||||
*g:fzf_command_prefix*
|
||||
|
||||
- Most commands support CTRL-T / CTRL-X / CTRL-V key bindings to open in a new
|
||||
tab, a new split, or in a new vertical split
|
||||
- Bang-versions of the commands (e.g. `Ag!`) will open fzf in fullscreen
|
||||
- You can set `g:fzf_command_prefix` to give the same prefix to the commands
|
||||
- e.g. `let g:fzf_command_prefix = 'Fzf'` and you have `FzfFiles`, etc.
|
||||
|
||||
(1: `Helptags` will shadow the command of the same name from {pathogen}{9}.
|
||||
But its functionality is still available via `call pathogen#helptags()`.)
|
||||
|
||||
{5} https://github.com/ggreer/the_silver_searcher
|
||||
{6} https://github.com/BurntSushi/ripgrep
|
||||
{7} https://github.com/SirVer/ultisnips
|
||||
{8} https://github.com/tpope/vim-fugitive
|
||||
{9} https://github.com/tpope/vim-pathogen
|
||||
|
||||
|
||||
CUSTOMIZATION *fzf-vim-customization*
|
||||
==============================================================================
|
||||
|
||||
|
||||
< Global options >____________________________________________________________~
|
||||
*fzf-vim-global-options*
|
||||
|
||||
Every command in fzf.vim internally calls `fzf#wrap` function of the main
|
||||
repository which supports a set of global option variables. So please read
|
||||
through {README-VIM}{4} to learn more about them.
|
||||
|
||||
{4} https://github.com/junegunn/fzf/blob/master/README-VIM.md
|
||||
|
||||
|
||||
Preview window~
|
||||
*fzf-vim-preview-window*
|
||||
|
||||
*g:fzf_preview_window*
|
||||
|
||||
If the width of the screen is wider than 120 columns, some commands will show
|
||||
the preview window on the right. You can customize the behavior with
|
||||
`g:fzf_preview_window`. Here are some examples:
|
||||
>
|
||||
" Empty value to disable preview window altogether
|
||||
let g:fzf_preview_window = ''
|
||||
|
||||
" Always enable preview window on the right with 60% width
|
||||
let g:fzf_preview_window = 'right:60%'
|
||||
<
|
||||
|
||||
< Command-local options >_____________________________________________________~
|
||||
*fzf-vim-command-local-options*
|
||||
|
||||
A few commands in fzf.vim can be customized with global option variables shown
|
||||
below.
|
||||
|
||||
*g:fzf_buffers_jump* *g:fzf_commits_log_options* *g:fzf_tags_command*
|
||||
*g:fzf_commands_expect*
|
||||
>
|
||||
" [Buffers] Jump to the existing window if possible
|
||||
let g:fzf_buffers_jump = 1
|
||||
|
||||
" [[B]Commits] Customize the options used by 'git log':
|
||||
let g:fzf_commits_log_options = '--graph --color=always --format="%C(auto)%h%d %s %C(black)%C(bold)%cr"'
|
||||
|
||||
" [Tags] Command to generate tags file
|
||||
let g:fzf_tags_command = 'ctags -R'
|
||||
|
||||
" [Commands] --expect expression for directly executing the command
|
||||
let g:fzf_commands_expect = 'alt-enter,ctrl-x'
|
||||
<
|
||||
|
||||
< Advanced customization >____________________________________________________~
|
||||
*fzf-vim-advanced-customization*
|
||||
|
||||
|
||||
Vim functions~
|
||||
*fzf-vim-vim-functions*
|
||||
|
||||
Each command in fzf.vim is backed by a Vim function. You can override a
|
||||
command or define a variation of it by calling its corresponding function.
|
||||
|
||||
----------+---------------------------------------------------------------------------
|
||||
Command | Vim function ~
|
||||
----------+---------------------------------------------------------------------------
|
||||
`Files` | `fzf#vim#files(dir, [spec dict], [fullscreen bool])`
|
||||
`GFiles` | `fzf#vim#gitfiles(git_options, [spec dict], [fullscreen bool])`
|
||||
`GFiles?` | `fzf#vim#gitfiles('?', [spec dict], [fullscreen bool])`
|
||||
`Buffers` | `fzf#vim#buffers([spec dict], [fullscreen bool])`
|
||||
`Colors` | `fzf#vim#colors([spec dict], [fullscreen bool])`
|
||||
`Rg` | `fzf#vim#grep(command, [has_column bool], [spec dict], [fullscreen bool])`
|
||||
... | ...
|
||||
----------+---------------------------------------------------------------------------
|
||||
|
||||
(We can see that the last two optional arguments of each function are
|
||||
identical. They are directly passed to `fzf#wrap` function. If you haven't
|
||||
read {README-VIM}{4} already, please read it before proceeding.)
|
||||
|
||||
{4} https://github.com/junegunn/fzf/blob/master/README-VIM.md
|
||||
|
||||
|
||||
Example: Customizing Files command~
|
||||
*fzf-vim-example-customizing-files-command*
|
||||
|
||||
This is the default definition of `Files` command:
|
||||
>
|
||||
command! -bang -nargs=? -complete=dir Files call fzf#vim#files(<q-args>, <bang>0)
|
||||
<
|
||||
Let's say you want to a variation of it called `ProjectFiles` that only
|
||||
searches inside `~/projects` directory. Then you can do it like this:
|
||||
>
|
||||
command! -bang ProjectFiles call fzf#vim#files('~/projects', <bang>0)
|
||||
<
|
||||
Or, if you want to override the command with different fzf options, just pass
|
||||
a custom spec to the function.
|
||||
>
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline']}, <bang>0)
|
||||
<
|
||||
Want a preview window?
|
||||
>
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline', '--preview', 'cat {}']}, <bang>0)
|
||||
<
|
||||
It kind of works, but you probably want a nicer previewer program than `cat`.
|
||||
fzf.vim ships {a versatile preview script}{10} you can readily use. It
|
||||
internally executes {bat}{11} for syntax highlighting, so make sure to install
|
||||
it.
|
||||
>
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, {'options': ['--layout=reverse', '--info=inline', '--preview', '~/.vim/plugged/fzf.vim/bin/preview.sh {}']}, <bang>0)
|
||||
<
|
||||
However, it's not ideal to hard-code the path to the script which can be
|
||||
different in different circumstances. So in order to make it easier to set up
|
||||
the previewer, fzf.vim provides `fzf#vim#with_preview` helper function.
|
||||
Similarly to `fzf#wrap`, it takes a spec dictionary and returns a copy of it
|
||||
with additional preview options.
|
||||
>
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview({'options': ['--layout=reverse', '--info=inline']}), <bang>0)
|
||||
<
|
||||
You can just omit the spec argument if you only want the previewer.
|
||||
>
|
||||
command! -bang -nargs=? -complete=dir Files
|
||||
\ call fzf#vim#files(<q-args>, fzf#vim#with_preview(), <bang>0)
|
||||
<
|
||||
{10} bin/preview.sh
|
||||
{11} https://github.com/sharkdp/bat
|
||||
|
||||
|
||||
Example: git grep wrapper~
|
||||
*fzf-vim-example-git-grep-wrapper*
|
||||
|
||||
The following example implements `GGrep` command that works similarly to
|
||||
predefined `Ag` or `Rg` using `fzf#vim#grep`.
|
||||
|
||||
- The second argument to `fzf#vim#grep` is 0 (false), because `git grep` does
|
||||
not print column numbers.
|
||||
- We set the base directory to git root by setting `dir` attribute in spec
|
||||
dictionary.
|
||||
- {The preview script}{10} supports `grep` format (`FILE_PATH:LINE_NO:...`), so
|
||||
we can just wrap the spec with `fzf#vim#with_preview` as before to enable
|
||||
previewer.
|
||||
>
|
||||
command! -bang -nargs=* GGrep
|
||||
\ call fzf#vim#grep(
|
||||
\ 'git grep --line-number -- '.shellescape(<q-args>), 0,
|
||||
\ fzf#vim#with_preview({'dir': systemlist('git rev-parse --show-toplevel')[0]}), <bang>0)
|
||||
<
|
||||
{10} bin/preview.sh
|
||||
|
||||
|
||||
Example: Rg command with preview window~
|
||||
*fzf-vim-example-rg-command-with-preview-window*
|
||||
|
||||
You can see the definition of `Rg` command with `:command Rg`. With the
|
||||
information, you can redefine it with the preview window enabled. In this
|
||||
case, we're only interested in setting up the preview window, so we will omit
|
||||
the spec argument to `fzf#vim#preview`.
|
||||
>
|
||||
command! -bang -nargs=* Rg
|
||||
\ call fzf#vim#grep(
|
||||
\ 'rg --column --line-number --no-heading --color=always --smart-case -- '.shellescape(<q-args>), 1,
|
||||
\ fzf#vim#with_preview(), <bang>0)
|
||||
<
|
||||
|
||||
Example: Advanced ripgrep integration~
|
||||
*fzf-vim-example-advanced-ripgrep-integration*
|
||||
|
||||
In the default implementation of `Rg`, ripgrep process starts only once with
|
||||
the initial query (e.g. `:Rg foo`) and fzf filters the output of the process.
|
||||
|
||||
This is okay in most cases because fzf is quite performant even with millions
|
||||
of lines, but we can make fzf completely delegate its search responsibliity to
|
||||
ripgrep process by making it restart ripgrep whenever the query string is
|
||||
updated. In this scenario, fzf becomes a simple selector interface rather than
|
||||
a "fuzzy finder".
|
||||
|
||||
- We will name the new command all-uppercase `RG` so we can still access the
|
||||
default version.
|
||||
- `--bind 'change:reload:rg ... {q}'` will make fzf restart ripgrep process
|
||||
whenever the query string, denoted by `{q}`, is changed.
|
||||
- With `--phony` option, fzf will no longer perform search. The query string you
|
||||
type on fzf prompt is only used for restarting ripgrep process.
|
||||
- Also note that we enabled previewer with `fzf#vim#with_preview`.
|
||||
>
|
||||
function! RipgrepFzf(query, fullscreen)
|
||||
let command_fmt = 'rg --column --line-number --no-heading --color=always --smart-case -- %s || true'
|
||||
let initial_command = printf(command_fmt, shellescape(a:query))
|
||||
let reload_command = printf(command_fmt, '{q}')
|
||||
let spec = {'options': ['--phony', '--query', a:query, '--bind', 'change:reload:'.reload_command]}
|
||||
call fzf#vim#grep(initial_command, 1, fzf#vim#with_preview(spec), a:fullscreen)
|
||||
endfunction
|
||||
|
||||
command! -nargs=* -bang RG call RipgrepFzf(<q-args>, <bang>0)
|
||||
<
|
||||
|
||||
MAPPINGS *fzf-vim-mappings*
|
||||
==============================================================================
|
||||
|
||||
---------------------------------+------------------------------------------
|
||||
Mapping | Description ~
|
||||
---------------------------------+------------------------------------------
|
||||
<plug>(fzf-maps-n) | Normal mode mappings
|
||||
<plug>(fzf-maps-i) | Insert mode mappings
|
||||
<plug>(fzf-maps-x) | Visual mode mappings
|
||||
<plug>(fzf-maps-o) | Operator-pending mappings
|
||||
<plug>(fzf-complete-word) | `cat /usr/share/dict/words`
|
||||
<plug>(fzf-complete-path) | Path completion using `find` (file + dir)
|
||||
<plug>(fzf-complete-file) | File completion using `find`
|
||||
<plug>(fzf-complete-line) | Line completion (all open buffers)
|
||||
<plug>(fzf-complete-buffer-line) | Line completion (current buffer only)
|
||||
---------------------------------+------------------------------------------
|
||||
>
|
||||
" Mapping selecting mappings
|
||||
nmap <leader><tab> <plug>(fzf-maps-n)
|
||||
xmap <leader><tab> <plug>(fzf-maps-x)
|
||||
omap <leader><tab> <plug>(fzf-maps-o)
|
||||
|
||||
" Insert mode completion
|
||||
imap <c-x><c-k> <plug>(fzf-complete-word)
|
||||
imap <c-x><c-f> <plug>(fzf-complete-path)
|
||||
imap <c-x><c-l> <plug>(fzf-complete-line)
|
||||
<
|
||||
|
||||
COMPLETION FUNCTIONS *fzf-vim-completion-functions*
|
||||
==============================================================================
|
||||
|
||||
-----------------------------------------+--------------------------------------
|
||||
Function | Description ~
|
||||
-----------------------------------------+--------------------------------------
|
||||
`fzf#vim#complete#path(command, [spec])` | Path completion
|
||||
`fzf#vim#complete#word([spec])` | Word completion
|
||||
`fzf#vim#complete#line([spec])` | Line completion (all open buffers)
|
||||
`fzf#vim#complete#buffer_line([spec])` | Line completion (current buffer only)
|
||||
-----------------------------------------+--------------------------------------
|
||||
>
|
||||
" Path completion with custom source command
|
||||
inoremap <expr> <c-x><c-f> fzf#vim#complete#path('fd')
|
||||
inoremap <expr> <c-x><c-f> fzf#vim#complete#path('rg --files')
|
||||
|
||||
" Word completion with custom spec with popup layout option
|
||||
inoremap <expr> <c-x><c-k> fzf#vim#complete#word({'window': { 'width': 0.2, 'height': 0.9, 'xoffset': 1 }})
|
||||
<
|
||||
|
||||
CUSTOM COMPLETION *fzf-vim-custom-completion*
|
||||
==============================================================================
|
||||
|
||||
`fzf#vim#complete` is a helper function for creating custom fuzzy completion
|
||||
using fzf. If the first parameter is a command string or a Vim list, it will
|
||||
be used as the source.
|
||||
>
|
||||
" Replace the default dictionary completion with fzf-based fuzzy completion
|
||||
inoremap <expr> <c-x><c-k> fzf#vim#complete('cat /usr/share/dict/words')
|
||||
<
|
||||
For advanced uses, you can pass an options dictionary to the function. The set
|
||||
of options is pretty much identical to that for `fzf#run` only with the
|
||||
following exceptions:
|
||||
|
||||
- `reducer` (funcref)
|
||||
- Reducer transforms the output lines of fzf into a single string value
|
||||
- `prefix` (string or funcref; default: `\k*$`)
|
||||
- Regular expression pattern to extract the completion prefix
|
||||
- Or a function to extract completion prefix
|
||||
- Both `source` and `options` can be given as funcrefs that take the completion
|
||||
prefix as the argument and return the final value
|
||||
- `sink` or `sink*` are ignored
|
||||
>
|
||||
" Global line completion (not just open buffers. ripgrep required.)
|
||||
inoremap <expr> <c-x><c-l> fzf#vim#complete(fzf#wrap({
|
||||
\ 'prefix': '^.*$',
|
||||
\ 'source': 'rg -n ^ --color always',
|
||||
\ 'options': '--ansi --delimiter : --nth 3..',
|
||||
\ 'reducer': { lines -> join(split(lines[0], ':\zs')[2:], '') }}))
|
||||
<
|
||||
|
||||
< Reducer example >___________________________________________________________~
|
||||
*fzf-vim-reducer-example*
|
||||
>
|
||||
function! s:make_sentence(lines)
|
||||
return substitute(join(a:lines), '^.', '\=toupper(submatch(0))', '').'.'
|
||||
endfunction
|
||||
|
||||
inoremap <expr> <c-x><c-s> fzf#vim#complete({
|
||||
\ 'source': 'cat /usr/share/dict/words',
|
||||
\ 'reducer': function('<sid>make_sentence'),
|
||||
\ 'options': '--multi --reverse --margin 15%,0',
|
||||
\ 'left': 20})
|
||||
<
|
||||
|
||||
STATUS LINE OF TERMINAL BUFFER *fzf-vim-status-line-of-terminal-buffer*
|
||||
==============================================================================
|
||||
|
||||
When fzf starts in a terminal buffer (see {fzf/README-VIM.md}{12}), you may
|
||||
want to customize the statusline of the containing buffer.
|
||||
|
||||
{12} https://github.com/junegunn/fzf/blob/master/README-VIM.md#fzf-inside-terminal-buffer
|
||||
|
||||
|
||||
< Hide statusline >___________________________________________________________~
|
||||
*fzf-vim-hide-statusline*
|
||||
>
|
||||
autocmd! FileType fzf set laststatus=0 noshowmode noruler
|
||||
\| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
|
||||
<
|
||||
|
||||
< Custom statusline >_________________________________________________________~
|
||||
*fzf-vim-custom-statusline*
|
||||
>
|
||||
function! s:fzf_statusline()
|
||||
" Override statusline as you like
|
||||
highlight fzf1 ctermfg=161 ctermbg=251
|
||||
highlight fzf2 ctermfg=23 ctermbg=251
|
||||
highlight fzf3 ctermfg=237 ctermbg=251
|
||||
setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
|
||||
endfunction
|
||||
|
||||
autocmd! User FzfStatusLine call <SID>fzf_statusline()
|
||||
<
|
||||
|
||||
LICENSE *fzf-vim-license*
|
||||
==============================================================================
|
||||
|
||||
MIT
|
||||
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap:
|
||||
@@ -0,0 +1,157 @@
|
||||
" Copyright (c) 2015 Junegunn Choi
|
||||
"
|
||||
" MIT License
|
||||
"
|
||||
" Permission is hereby granted, free of charge, to any person obtaining
|
||||
" a copy of this software and associated documentation files (the
|
||||
" "Software"), to deal in the Software without restriction, including
|
||||
" without limitation the rights to use, copy, modify, merge, publish,
|
||||
" distribute, sublicense, and/or sell copies of the Software, and to
|
||||
" permit persons to whom the Software is furnished to do so, subject to
|
||||
" the following conditions:
|
||||
"
|
||||
" The above copyright notice and this permission notice shall be
|
||||
" included in all copies or substantial portions of the Software.
|
||||
"
|
||||
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
let s:is_win = has('win32') || has('win64')
|
||||
|
||||
function! s:defs(commands)
|
||||
let prefix = get(g:, 'fzf_command_prefix', '')
|
||||
if prefix =~# '^[^A-Z]'
|
||||
echoerr 'g:fzf_command_prefix must start with an uppercase letter'
|
||||
return
|
||||
endif
|
||||
for command in a:commands
|
||||
let name = ':'.prefix.matchstr(command, '\C[A-Z]\S\+')
|
||||
if 2 != exists(name)
|
||||
execute substitute(command, '\ze\C[A-Z]', prefix, '')
|
||||
endif
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
function! s:p(bang, ...)
|
||||
let preview_window = get(g:, 'fzf_preview_window', a:bang && &columns >= 80 || &columns >= 120 ? 'right': '')
|
||||
if len(preview_window)
|
||||
return call('fzf#vim#with_preview', add(copy(a:000), preview_window))
|
||||
endif
|
||||
return {}
|
||||
endfunction
|
||||
|
||||
call s:defs([
|
||||
\'command! -bang -nargs=? -complete=dir Files call fzf#vim#files(<q-args>, s:p(<bang>0), <bang>0)',
|
||||
\'command! -bang -nargs=? GitFiles call fzf#vim#gitfiles(<q-args>, <q-args> == "?" ? {} : s:p(<bang>0), <bang>0)',
|
||||
\'command! -bang -nargs=? GFiles call fzf#vim#gitfiles(<q-args>, <q-args> == "?" ? {} : s:p(<bang>0), <bang>0)',
|
||||
\'command! -bar -bang -nargs=? -complete=buffer Buffers call fzf#vim#buffers(<q-args>, s:p(<bang>0, { "placeholder": "{1}", "options": ["-d", "\t"] }), <bang>0)',
|
||||
\'command! -bang -nargs=* Lines call fzf#vim#lines(<q-args>, <bang>0)',
|
||||
\'command! -bang -nargs=* BLines call fzf#vim#buffer_lines(<q-args>, <bang>0)',
|
||||
\'command! -bar -bang Colors call fzf#vim#colors(<bang>0)',
|
||||
\'command! -bang -nargs=+ -complete=dir Locate call fzf#vim#locate(<q-args>, s:p(<bang>0), <bang>0)',
|
||||
\'command! -bang -nargs=* Ag call fzf#vim#ag(<q-args>, s:p(<bang>0), <bang>0)',
|
||||
\'command! -bang -nargs=* Rg call fzf#vim#grep("rg --column --line-number --no-heading --color=always --smart-case -- ".shellescape(<q-args>), 1, s:p(<bang>0), <bang>0)',
|
||||
\'command! -bang -nargs=* Tags call fzf#vim#tags(<q-args>, <bang>0)',
|
||||
\'command! -bang -nargs=* BTags call fzf#vim#buffer_tags(<q-args>, s:p(<bang>0, { "placeholder": "{2}:{3}", "options": ["-d", "\t"] }), <bang>0)',
|
||||
\'command! -bar -bang Snippets call fzf#vim#snippets(<bang>0)',
|
||||
\'command! -bar -bang Commands call fzf#vim#commands(<bang>0)',
|
||||
\'command! -bar -bang Marks call fzf#vim#marks(<bang>0)',
|
||||
\'command! -bar -bang Helptags call fzf#vim#helptags(<bang>0)',
|
||||
\'command! -bar -bang Windows call fzf#vim#windows(<bang>0)',
|
||||
\'command! -bar -bang Commits call fzf#vim#commits(<bang>0)',
|
||||
\'command! -bar -bang BCommits call fzf#vim#buffer_commits(<bang>0)',
|
||||
\'command! -bar -bang Maps call fzf#vim#maps("n", <bang>0)',
|
||||
\'command! -bar -bang Filetypes call fzf#vim#filetypes(<bang>0)',
|
||||
\'command! -bang -nargs=* History call s:history(<q-args>, s:p(<bang>0), <bang>0)'])
|
||||
|
||||
function! s:history(arg, extra, bang)
|
||||
let bang = a:bang || a:arg[len(a:arg)-1] == '!'
|
||||
if a:arg[0] == ':'
|
||||
call fzf#vim#command_history(bang)
|
||||
elseif a:arg[0] == '/'
|
||||
call fzf#vim#search_history(bang)
|
||||
else
|
||||
call fzf#vim#history(a:extra, bang)
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! fzf#complete(...)
|
||||
return call('fzf#vim#complete', a:000)
|
||||
endfunction
|
||||
|
||||
if (has('nvim') || has('terminal') && has('patch-8.0.995')) && (get(g:, 'fzf_statusline', 1) || get(g:, 'fzf_nvim_statusline', 1))
|
||||
function! s:fzf_restore_colors()
|
||||
if exists('#User#FzfStatusLine')
|
||||
doautocmd User FzfStatusLine
|
||||
else
|
||||
if $TERM !~ "256color"
|
||||
highlight default fzf1 ctermfg=1 ctermbg=8 guifg=#E12672 guibg=#565656
|
||||
highlight default fzf2 ctermfg=2 ctermbg=8 guifg=#BCDDBD guibg=#565656
|
||||
highlight default fzf3 ctermfg=7 ctermbg=8 guifg=#D9D9D9 guibg=#565656
|
||||
else
|
||||
highlight default fzf1 ctermfg=161 ctermbg=238 guifg=#E12672 guibg=#565656
|
||||
highlight default fzf2 ctermfg=151 ctermbg=238 guifg=#BCDDBD guibg=#565656
|
||||
highlight default fzf3 ctermfg=252 ctermbg=238 guifg=#D9D9D9 guibg=#565656
|
||||
endif
|
||||
setlocal statusline=%#fzf1#\ >\ %#fzf2#fz%#fzf3#f
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:fzf_vim_term()
|
||||
if get(w:, 'airline_active', 0)
|
||||
let w:airline_disabled = 1
|
||||
autocmd BufWinLeave <buffer> let w:airline_disabled = 0
|
||||
endif
|
||||
autocmd WinEnter,ColorScheme <buffer> call s:fzf_restore_colors()
|
||||
|
||||
setlocal nospell
|
||||
call s:fzf_restore_colors()
|
||||
endfunction
|
||||
|
||||
augroup _fzf_statusline
|
||||
autocmd!
|
||||
autocmd FileType fzf call s:fzf_vim_term()
|
||||
augroup END
|
||||
endif
|
||||
|
||||
if !exists('g:fzf#vim#buffers')
|
||||
let g:fzf#vim#buffers = {}
|
||||
endif
|
||||
|
||||
augroup fzf_buffers
|
||||
autocmd!
|
||||
if exists('*reltimefloat')
|
||||
autocmd BufWinEnter,WinEnter * let g:fzf#vim#buffers[bufnr('')] = reltimefloat(reltime())
|
||||
else
|
||||
autocmd BufWinEnter,WinEnter * let g:fzf#vim#buffers[bufnr('')] = localtime()
|
||||
endif
|
||||
autocmd BufDelete * silent! call remove(g:fzf#vim#buffers, expand('<abuf>'))
|
||||
augroup END
|
||||
|
||||
inoremap <expr> <plug>(fzf-complete-word) fzf#vim#complete#word()
|
||||
if s:is_win
|
||||
inoremap <expr> <plug>(fzf-complete-path) fzf#vim#complete#path('dir /s/b')
|
||||
inoremap <expr> <plug>(fzf-complete-file) fzf#vim#complete#path('dir /s/b/a:-d')
|
||||
else
|
||||
inoremap <expr> <plug>(fzf-complete-path) fzf#vim#complete#path("find . -path '*/\.*' -prune -o -print \| sed '1d;s:^..::'")
|
||||
inoremap <expr> <plug>(fzf-complete-file) fzf#vim#complete#path("find . -path '*/\.*' -prune -o -type f -print -o -type l -print \| sed 's:^..::'")
|
||||
endif
|
||||
inoremap <expr> <plug>(fzf-complete-file-ag) fzf#vim#complete#path('ag -l -g ""')
|
||||
inoremap <expr> <plug>(fzf-complete-line) fzf#vim#complete#line()
|
||||
inoremap <expr> <plug>(fzf-complete-buffer-line) fzf#vim#complete#buffer_line()
|
||||
|
||||
nnoremap <silent> <plug>(fzf-maps-n) :<c-u>call fzf#vim#maps('n', 0)<cr>
|
||||
inoremap <silent> <plug>(fzf-maps-i) <c-o>:call fzf#vim#maps('i', 0)<cr>
|
||||
xnoremap <silent> <plug>(fzf-maps-x) :<c-u>call fzf#vim#maps('x', 0)<cr>
|
||||
onoremap <silent> <plug>(fzf-maps-o) <c-c>:<c-u>call fzf#vim#maps('o', 0)<cr>
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
Building fzf
|
||||
============
|
||||
|
||||
Build instructions
|
||||
------------------
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Go 1.11 or above
|
||||
|
||||
### Using Makefile
|
||||
|
||||
```sh
|
||||
# Build fzf binary for your platform in target
|
||||
make
|
||||
|
||||
# Build fzf binary and copy it to bin directory
|
||||
make install
|
||||
|
||||
# Build 32-bit and 64-bit executables and tarballs in target
|
||||
make release
|
||||
|
||||
# Make release archives for all supported platforms in target
|
||||
make release-all
|
||||
```
|
||||
|
||||
### Using `go get`
|
||||
|
||||
Alternatively, you can build fzf directly with `go get` command without
|
||||
manually cloning the repository.
|
||||
|
||||
```sh
|
||||
go get -u github.com/junegunn/fzf
|
||||
```
|
||||
|
||||
Third-party libraries used
|
||||
--------------------------
|
||||
|
||||
- [mattn/go-runewidth](https://github.com/mattn/go-runewidth)
|
||||
- Licensed under [MIT](http://mattn.mit-license.org)
|
||||
- [mattn/go-shellwords](https://github.com/mattn/go-shellwords)
|
||||
- Licensed under [MIT](http://mattn.mit-license.org)
|
||||
- [mattn/go-isatty](https://github.com/mattn/go-isatty)
|
||||
- Licensed under [MIT](http://mattn.mit-license.org)
|
||||
- [tcell](https://github.com/gdamore/tcell)
|
||||
- Licensed under [Apache License 2.0](https://github.com/gdamore/tcell/blob/master/LICENSE)
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
[MIT](LICENSE)
|
||||
@@ -0,0 +1,870 @@
|
||||
CHANGELOG
|
||||
=========
|
||||
|
||||
0.21.1
|
||||
------
|
||||
- Shell extension
|
||||
- CTRL-R will remove duplicate commands
|
||||
- fzf-tmux
|
||||
- Supports tmux popup window (require tmux 3.2 or above)
|
||||
- ```sh
|
||||
# 50% width and height
|
||||
fzf-tmux -p
|
||||
|
||||
# 80% width and height
|
||||
fzf-tmux -p 80%
|
||||
|
||||
# 80% width and 40% height
|
||||
fzf-tmux -p 80%,40%
|
||||
fzf-tmux -w 80% -h 40%
|
||||
|
||||
# Window position
|
||||
fzf-tmux -w 80% -h 40% -x 0 -y 0
|
||||
fzf-tmux -w 80% -h 40% -y 1000
|
||||
|
||||
# Write ordinary fzf options after --
|
||||
fzf-tmux -p -- --reverse --info=inline --margin 2,4 --border
|
||||
```
|
||||
- On macOS, you can build the latest tmux from the source with
|
||||
`brew install tmux --HEAD`
|
||||
- Bug fixes
|
||||
- Fixed Windows file traversal not to include directories
|
||||
- Fixed ANSI colors with `--keep-right`
|
||||
- Fixed _fzf_complete for zsh
|
||||
- Built with Go 1.14.1
|
||||
|
||||
0.21.0
|
||||
------
|
||||
- `--height` option is now available on Windows as well (@kelleyma49)
|
||||
- Added `--pointer` and `--marker` options
|
||||
- Added `--keep-right` option that keeps the right end of the line visible
|
||||
when it's too long
|
||||
- Style changes
|
||||
- `--border` will now print border with rounded corners around the
|
||||
finder instead of printing horizontal lines above and below it.
|
||||
The previous style is available via `--border=horizontal`
|
||||
- Unicode spinner
|
||||
- More keys and actions for `--bind`
|
||||
- Added PowerShell script for downloading Windows binary
|
||||
- Vim plugin: Built-in floating windows support
|
||||
```vim
|
||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||
```
|
||||
- bash: Various improvements in key bindings (CTRL-T, CTRL-R, ALT-C)
|
||||
- CTRL-R will start with the current command-line as the initial query
|
||||
- CTRL-R properly supports multi-line commands
|
||||
- Fuzzy completion API changed
|
||||
```sh
|
||||
# Previous: fzf arguments given as a single string argument
|
||||
# - This style is still supported, but it's deprecated
|
||||
_fzf_complete "--multi --reverse --prompt=\"doge> \"" "$@" < <(
|
||||
echo foo
|
||||
)
|
||||
|
||||
# New API: multiple fzf arguments before "--"
|
||||
# - Easier to write multiple options
|
||||
_fzf_complete --multi --reverse --prompt="doge> " -- "$@" < <(
|
||||
echo foo
|
||||
)
|
||||
```
|
||||
- Bug fixes and improvements
|
||||
|
||||
0.20.0
|
||||
------
|
||||
- Customizable preview window color (`preview-fg` and `preview-bg` for `--color`)
|
||||
```sh
|
||||
fzf --preview 'cat {}' \
|
||||
--color 'fg:#bbccdd,fg+:#ddeeff,bg:#334455,preview-bg:#223344,border:#778899' \
|
||||
--border --height 20 --layout reverse --info inline
|
||||
```
|
||||
- Removed the immediate flicking of the screen on `reload` action.
|
||||
```sh
|
||||
: | fzf --bind 'change:reload:seq {q}' --phony
|
||||
```
|
||||
- Added `clear-query` and `clear-selection` actions for `--bind`
|
||||
- It is now possible to split a composite bind action over multiple `--bind`
|
||||
expressions by prefixing the later ones with `+`.
|
||||
```sh
|
||||
fzf --bind 'ctrl-a:up+up'
|
||||
|
||||
# Can be now written as
|
||||
fzf --bind 'ctrl-a:up' --bind 'ctrl-a:+up'
|
||||
|
||||
# This is useful when you need to write special execute/reload form (i.e. `execute:...`)
|
||||
# to avoid parse errors and add more actions to the same key
|
||||
fzf --multi --bind 'ctrl-l:select-all+execute:less {+f}' --bind 'ctrl-l:+deselect-all'
|
||||
```
|
||||
- Fixed parse error of `--bind` expression where concatenated execute/reload
|
||||
action contains `+` character.
|
||||
```sh
|
||||
fzf --multi --bind 'ctrl-l:select-all+execute(less {+f})+deselect-all'
|
||||
```
|
||||
- Fixed bugs of reload action
|
||||
- Not triggered when there's no match even when the command doesn't have
|
||||
any placeholder expressions
|
||||
- Screen not properly cleared when `--header-lines` not filled on reload
|
||||
|
||||
0.19.0
|
||||
------
|
||||
|
||||
- Added `--phony` option which completely disables search functionality.
|
||||
Useful when you want to use fzf only as a selector interface. See below.
|
||||
- Added "reload" action for dynamically updating the input list without
|
||||
restarting fzf. See https://github.com/junegunn/fzf/issues/1750 to learn
|
||||
more about it.
|
||||
```sh
|
||||
# Using fzf as the selector interface for ripgrep
|
||||
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
||||
INITIAL_QUERY="foo"
|
||||
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY' || true" \
|
||||
fzf --bind "change:reload:$RG_PREFIX {q} || true" \
|
||||
--ansi --phony --query "$INITIAL_QUERY"
|
||||
```
|
||||
- `--multi` now takes an optional integer argument which indicates the maximum
|
||||
number of items that can be selected
|
||||
```sh
|
||||
seq 100 | fzf --multi 3 --reverse --height 50%
|
||||
```
|
||||
- If a placeholder expression for `--preview` and `execute` action (and the
|
||||
new `reload` action) contains `f` flag, it is replaced to the
|
||||
path of a temporary file that holds the evaluated list. This is useful
|
||||
when you multi-select a large number of items and the length of the
|
||||
evaluated string may exceed [`ARG_MAX`][argmax].
|
||||
```sh
|
||||
# Press CTRL-A to select 100K items and see the sum of all the numbers
|
||||
seq 100000 | fzf --multi --bind ctrl-a:select-all \
|
||||
--preview "awk '{sum+=\$1} END {print sum}' {+f}"
|
||||
```
|
||||
- `deselect-all` no longer deselects unmatched items. It is now consistent
|
||||
with `select-all` and `toggle-all` in that it only affects matched items.
|
||||
- Due to the limitation of bash, fuzzy completion is enabled by default for
|
||||
a fixed set of commands. A helper function for easily setting up fuzzy
|
||||
completion for any command is now provided.
|
||||
```sh
|
||||
# usage: _fzf_setup_completion path|dir COMMANDS...
|
||||
_fzf_setup_completion path git kubectl
|
||||
```
|
||||
- Info line style can be changed by `--info=STYLE`
|
||||
- `--info=default`
|
||||
- `--info=inline` (same as old `--inline-info`)
|
||||
- `--info=hidden`
|
||||
- Preview window border can be disabled by adding `noborder` to
|
||||
`--preview-window`.
|
||||
- When you transform the input with `--with-nth`, the trailing white spaces
|
||||
are removed.
|
||||
- `ctrl-\`, `ctrl-]`, `ctrl-^`, and `ctrl-/` can now be used with `--bind`
|
||||
- See https://github.com/junegunn/fzf/milestone/15?closed=1 for more details
|
||||
|
||||
[argmax]: https://unix.stackexchange.com/questions/120642/what-defines-the-maximum-size-for-a-command-single-argument
|
||||
|
||||
0.18.0
|
||||
------
|
||||
|
||||
- Added placeholder expression for zero-based item index: `{n}` and `{+n}`
|
||||
- `fzf --preview 'echo {n}: {}'`
|
||||
- Added color option for the gutter: `--color gutter:-1`
|
||||
- Added `--no-unicode` option for drawing borders in non-Unicode, ASCII
|
||||
characters
|
||||
- `FZF_PREVIEW_LINES` and `FZF_PREVIEW_COLUMNS` are exported to preview process
|
||||
- fzf still overrides `LINES` and `COLUMNS` as before, but they may be
|
||||
reset by the default shell.
|
||||
- Bug fixes and improvements
|
||||
- See https://github.com/junegunn/fzf/milestone/14?closed=1
|
||||
- Built with Go 1.12.1
|
||||
|
||||
0.17.5
|
||||
------
|
||||
|
||||
- Bug fixes and improvements
|
||||
- See https://github.com/junegunn/fzf/milestone/13?closed=1
|
||||
- Search query longer than the screen width is allowed (up to 300 chars)
|
||||
- Built with Go 1.11.1
|
||||
|
||||
0.17.4
|
||||
------
|
||||
|
||||
- Added `--layout` option with a new layout called `reverse-list`.
|
||||
- `--layout=reverse` is a synonym for `--reverse`
|
||||
- `--layout=default` is a synonym for `--no-reverse`
|
||||
- Preview window will be updated even when there is no match for the query
|
||||
if any of the placeholder expressions (e.g. `{q}`, `{+}`) evaluates to
|
||||
a non-empty string.
|
||||
- More keys for binding: `shift-{up,down}`, `alt-{up,down,left,right}`
|
||||
- fzf can now start even when `/dev/tty` is not available by making an
|
||||
educated guess.
|
||||
- Updated the default command for Windows.
|
||||
- Fixes and improvements on bash/zsh completion
|
||||
- install and uninstall scripts now supports generating files under
|
||||
`XDG_CONFIG_HOME` on `--xdg` flag.
|
||||
|
||||
See https://github.com/junegunn/fzf/milestone/12?closed=1 for the full list of
|
||||
changes.
|
||||
|
||||
0.17.3
|
||||
------
|
||||
- `$LINES` and `$COLUMNS` are exported to preview command so that the command
|
||||
knows the exact size of the preview window.
|
||||
- Better error messages when the default command or `$FZF_DEFAULT_COMMAND`
|
||||
fails.
|
||||
- Reverted #1061 to avoid having duplicate entries in the list when find
|
||||
command detected a file system loop (#1120). The default command now
|
||||
requires that find supports `-fstype` option.
|
||||
- fzf now distinguishes mouse left click and right click (#1130)
|
||||
- Right click is now bound to `toggle` action by default
|
||||
- `--bind` understands `left-click` and `right-click`
|
||||
- Added `replace-query` action (#1137)
|
||||
- Replaces query string with the current selection
|
||||
- Added `accept-non-empty` action (#1162)
|
||||
- Same as accept, except that it prevents fzf from exiting without any
|
||||
selection
|
||||
|
||||
0.17.1
|
||||
------
|
||||
|
||||
- Fixed custom background color of preview window (#1046)
|
||||
- Fixed background color issues of Windows binary
|
||||
- Fixed Windows binary to execute command using cmd.exe with no parsing and
|
||||
escaping (#1072)
|
||||
- Added support for `window` layout on Vim 8 using Vim 8 terminal (#1055)
|
||||
|
||||
0.17.0-2
|
||||
--------
|
||||
|
||||
A maintenance release for auxiliary scripts. fzf binaries are not updated.
|
||||
|
||||
- Experimental support for the builtin terminal of Vim 8
|
||||
- fzf can now run inside GVim
|
||||
- Updated Vim plugin to better handle `&shell` issue on fish
|
||||
- Fixed a bug of fzf-tmux where invalid output is generated
|
||||
- Fixed fzf-tmux to work even when `tput` does not work
|
||||
|
||||
0.17.0
|
||||
------
|
||||
- Performance optimization
|
||||
- One can match literal spaces in extended-search mode with a space prepended
|
||||
by a backslash.
|
||||
- `--expect` is now additive and can be specified multiple times.
|
||||
|
||||
0.16.11
|
||||
-------
|
||||
- Performance optimization
|
||||
- Fixed missing preview update
|
||||
|
||||
0.16.10
|
||||
-------
|
||||
- Fixed invalid handling of ANSI colors in preview window
|
||||
- Further improved `--ansi` performance
|
||||
|
||||
0.16.9
|
||||
------
|
||||
- Memory and performance optimization
|
||||
- Around 20% performance improvement for general use cases
|
||||
- Up to 5x faster processing of `--ansi`
|
||||
- Up to 50% reduction of memory usage
|
||||
- Bug fixes and usability improvements
|
||||
- Fixed handling of bracketed paste mode
|
||||
- [ERROR] on info line when the default command failed
|
||||
- More efficient rendering of preview window
|
||||
- `--no-clear` updated for repetitive relaunching scenarios
|
||||
|
||||
0.16.8
|
||||
------
|
||||
- New `change` event and `top` action for `--bind`
|
||||
- `fzf --bind change:top`
|
||||
- Move cursor to the top result whenever the query string is changed
|
||||
- `fzf --bind 'ctrl-w:unix-word-rubout+top,ctrl-u:unix-line-discard+top'`
|
||||
- `top` combined with `unix-word-rubout` and `unix-line-discard`
|
||||
- Fixed inconsistent tiebreak scores when `--nth` is used
|
||||
- Proper display of tab characters in `--prompt`
|
||||
- Fixed not to `--cycle` on page-up/page-down to prevent overshoot
|
||||
- Git revision in `--version` output
|
||||
- Basic support for Cygwin environment
|
||||
- Many fixes in Vim plugin on Windows/Cygwin (thanks to @janlazo)
|
||||
|
||||
0.16.7
|
||||
------
|
||||
- Added support for `ctrl-alt-[a-z]` key chords
|
||||
- CTRL-Z (SIGSTOP) now works with fzf
|
||||
- fzf will export `$FZF_PREVIEW_WINDOW` so that the scripts can use it
|
||||
- Bug fixes and improvements in Vim plugin and shell extensions
|
||||
|
||||
0.16.6
|
||||
------
|
||||
- Minor bug fixes and improvements
|
||||
- Added `--no-clear` option for scripting purposes
|
||||
|
||||
0.16.5
|
||||
------
|
||||
- Minor bug fixes
|
||||
- Added `toggle-preview-wrap` action
|
||||
- Built with Go 1.8
|
||||
|
||||
0.16.4
|
||||
------
|
||||
- Added `--border` option to draw border above and below the finder
|
||||
- Bug fixes and improvements
|
||||
|
||||
0.16.3
|
||||
------
|
||||
- Fixed a bug where fzf incorrectly display the lines when straddling tab
|
||||
characters are trimmed
|
||||
- Placeholder expression used in `--preview` and `execute` action can
|
||||
optionally take `+` flag to be used with multiple selections
|
||||
- e.g. `git log --oneline | fzf --multi --preview 'git show {+1}'`
|
||||
- Added `execute-silent` action for executing a command silently without
|
||||
switching to the alternate screen. This is useful when the process is
|
||||
short-lived and you're not interested in its output.
|
||||
- e.g. `fzf --bind 'ctrl-y:execute!(echo -n {} | pbcopy)'`
|
||||
- `ctrl-space` is allowed in `--bind`
|
||||
|
||||
0.16.2
|
||||
------
|
||||
- Dropped ncurses dependency
|
||||
- Binaries for freebsd, openbsd, arm5, arm6, arm7, and arm8
|
||||
- Official 24-bit color support
|
||||
- Added support for composite actions in `--bind`. Multiple actions can be
|
||||
chained using `+` separator.
|
||||
- e.g. `fzf --bind 'ctrl-y:execute(echo -n {} | pbcopy)+abort'`
|
||||
- `--preview-window` with size 0 is allowed. This is used to make fzf execute
|
||||
preview command in the background without displaying the result.
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
0.16.1
|
||||
------
|
||||
- Fixed `--height` option to properly fill the window with the background
|
||||
color
|
||||
- Added `half-page-up` and `half-page-down` actions
|
||||
- Added `-L` flag to the default find command
|
||||
|
||||
0.16.0
|
||||
------
|
||||
- *Added `--height HEIGHT[%]` option*
|
||||
- fzf can now display finder without occupying the full screen
|
||||
- Preview window will truncate long lines by default. Line wrap can be enabled
|
||||
by `:wrap` flag in `--preview-window`.
|
||||
- Latin script letters will be normalized before matching so that it's easier
|
||||
to match against accented letters. e.g. `sodanco` can match `Só Danço Samba`.
|
||||
- Normalization can be disabled via `--literal`
|
||||
- Added `--filepath-word` to make word-wise movements/actions (`alt-b`,
|
||||
`alt-f`, `alt-bs`, `alt-d`) respect path separators
|
||||
|
||||
0.15.9
|
||||
------
|
||||
- Fixed rendering glitches introduced in 0.15.8
|
||||
- The default escape delay is reduced to 50ms and is configurable via
|
||||
`$ESCDELAY`
|
||||
- Scroll indicator at the top-right corner of the preview window is always
|
||||
displayed when there's overflow
|
||||
- Can now be built with ncurses 6 or tcell to support extra features
|
||||
- *ncurses 6*
|
||||
- Supports more than 256 color pairs
|
||||
- Supports italics
|
||||
- *tcell*
|
||||
- 24-bit color support
|
||||
- See https://github.com/junegunn/fzf/blob/master/BUILD.md
|
||||
|
||||
0.15.8
|
||||
------
|
||||
- Updated ANSI processor to handle more VT-100 escape sequences
|
||||
- Added `--no-bold` (and `--bold`) option
|
||||
- Improved escape sequence processing for WSL
|
||||
- Added support for `alt-[0-9]`, `f11`, and `f12` for `--bind` and `--expect`
|
||||
|
||||
0.15.7
|
||||
------
|
||||
- Fixed panic when color is disabled and header lines contain ANSI colors
|
||||
|
||||
0.15.6
|
||||
------
|
||||
- Windows binaries! (@kelleyma49)
|
||||
- Fixed the bug where header lines are cleared when preview window is toggled
|
||||
- Fixed not to display ^N and ^O on screen
|
||||
- Fixed cursor keys (or any key sequence that starts with ESC) on WSL by
|
||||
making fzf wait for additional keystrokes after ESC for up to 100ms
|
||||
|
||||
0.15.5
|
||||
------
|
||||
- Setting foreground color will no longer set background color to black
|
||||
- e.g. `fzf --color fg:153`
|
||||
- `--tiebreak=end` will consider relative position instead of absolute distance
|
||||
- Updated `fzf#wrap` function to respect `g:fzf_colors`
|
||||
|
||||
0.15.4
|
||||
------
|
||||
- Added support for range expression in preview and execute action
|
||||
- e.g. `ls -l | fzf --preview="echo user={3} when={-4..-2}; cat {-1}" --header-lines=1`
|
||||
- `{q}` will be replaced to the single-quoted string of the current query
|
||||
- Fixed to properly handle unicode whitespace characters
|
||||
- Display scroll indicator in preview window
|
||||
- Inverse search term will use exact matcher by default
|
||||
- This is a breaking change, but I believe it makes much more sense. It is
|
||||
almost impossible to predict which entries will be filtered out due to
|
||||
a fuzzy inverse term. You can still perform inverse-fuzzy-match by
|
||||
prepending `!'` to the term.
|
||||
|
||||
0.15.3
|
||||
------
|
||||
- Added support for more ANSI attributes: dim, underline, blink, and reverse
|
||||
- Fixed race condition in `toggle-preview`
|
||||
|
||||
0.15.2
|
||||
------
|
||||
- Preview window is now scrollable
|
||||
- With mouse scroll or with bindable actions
|
||||
- `preview-up`
|
||||
- `preview-down`
|
||||
- `preview-page-up`
|
||||
- `preview-page-down`
|
||||
- Updated ANSI processor to support high intensity colors and ignore
|
||||
some VT100-related escape sequences
|
||||
|
||||
0.15.1
|
||||
------
|
||||
- Fixed panic when the pattern occurs after 2^15-th column
|
||||
- Fixed rendering delay when displaying extremely long lines
|
||||
|
||||
0.15.0
|
||||
------
|
||||
- Improved fuzzy search algorithm
|
||||
- Added `--algo=[v1|v2]` option so one can still choose the old algorithm
|
||||
which values the search performance over the quality of the result
|
||||
- Advanced scoring criteria
|
||||
- `--read0` to read input delimited by ASCII NUL character
|
||||
- `--print0` to print output delimited by ASCII NUL character
|
||||
|
||||
0.13.5
|
||||
------
|
||||
- Memory and performance optimization
|
||||
- Up to 2x performance with half the amount of memory
|
||||
|
||||
0.13.4
|
||||
------
|
||||
- Performance optimization
|
||||
- Memory footprint for ascii string is reduced by 60%
|
||||
- 15 to 20% improvement of query performance
|
||||
- Up to 45% better performance of `--nth` with non-regex delimiters
|
||||
- Fixed invalid handling of `hidden` property of `--preview-window`
|
||||
|
||||
0.13.3
|
||||
------
|
||||
- Fixed duplicate rendering of the last line in preview window
|
||||
|
||||
0.13.2
|
||||
------
|
||||
- Fixed race condition where preview window is not properly cleared
|
||||
|
||||
0.13.1
|
||||
------
|
||||
- Fixed UI issue with large `--preview` output with many ANSI codes
|
||||
|
||||
0.13.0
|
||||
------
|
||||
- Added preview feature
|
||||
- `--preview CMD`
|
||||
- `--preview-window POS[:SIZE][:hidden]`
|
||||
- `{}` in execute action is now replaced to the single-quoted (instead of
|
||||
double-quoted) string of the current line
|
||||
- Fixed to ignore control characters for bracketed paste mode
|
||||
|
||||
0.12.2
|
||||
------
|
||||
|
||||
- 256-color capability detection does not require `256` in `$TERM`
|
||||
- Added `print-query` action
|
||||
- More named keys for binding; <kbd>F1</kbd> ~ <kbd>F10</kbd>,
|
||||
<kbd>ALT-/</kbd>, <kbd>ALT-space</kbd>, and <kbd>ALT-enter</kbd>
|
||||
- Added `jump` and `jump-accept` actions that implement [EasyMotion][em]-like
|
||||
movement
|
||||
![][jump]
|
||||
|
||||
[em]: https://github.com/easymotion/vim-easymotion
|
||||
[jump]: https://cloud.githubusercontent.com/assets/700826/15367574/b3999dc4-1d64-11e6-85da-28ceeb1a9bc2.png
|
||||
|
||||
0.12.1
|
||||
------
|
||||
|
||||
- Ranking algorithm introduced in 0.12.0 is now universally applied
|
||||
- Fixed invalid cache reference in exact mode
|
||||
- Fixes and improvements in Vim plugin and shell extensions
|
||||
|
||||
0.12.0
|
||||
------
|
||||
|
||||
- Enhanced ranking algorithm
|
||||
- Minor bug fixes
|
||||
|
||||
0.11.4
|
||||
------
|
||||
|
||||
- Added `--hscroll-off=COL` option (default: 10) (#513)
|
||||
- Some fixes in Vim plugin and shell extensions
|
||||
|
||||
0.11.3
|
||||
------
|
||||
|
||||
- Graceful exit on SIGTERM (#482)
|
||||
- `$SHELL` instead of `sh` for `execute` action and `$FZF_DEFAULT_COMMAND` (#481)
|
||||
- Changes in fuzzy completion API
|
||||
- [`_fzf_compgen_{path,dir}`](https://github.com/junegunn/fzf/commit/9617647)
|
||||
- [`_fzf_complete_COMMAND_post`](https://github.com/junegunn/fzf/commit/8206746)
|
||||
for post-processing
|
||||
|
||||
0.11.2
|
||||
------
|
||||
|
||||
- `--tiebreak` now accepts comma-separated list of sort criteria
|
||||
- Each criterion should appear only once in the list
|
||||
- `index` is only allowed at the end of the list
|
||||
- `index` is implicitly appended to the list when not specified
|
||||
- Default is `length` (or equivalently `length,index`)
|
||||
- `begin` criterion will ignore leading whitespaces when calculating the index
|
||||
- Added `toggle-in` and `toggle-out` actions
|
||||
- Switch direction depending on `--reverse`-ness
|
||||
- `export FZF_DEFAULT_OPTS="--bind tab:toggle-out,shift-tab:toggle-in"`
|
||||
- Reduced the initial delay when `--tac` is not given
|
||||
- fzf defers the initial rendering of the screen up to 100ms if the input
|
||||
stream is ongoing to prevent unnecessary redraw during the initial
|
||||
phase. However, 100ms delay is quite noticeable and might give the
|
||||
impression that fzf is not snappy enough. This commit reduces the
|
||||
maximum delay down to 20ms when `--tac` is not specified, in which case
|
||||
the input list quickly fills the entire screen.
|
||||
|
||||
0.11.1
|
||||
------
|
||||
|
||||
- Added `--tabstop=SPACES` option
|
||||
|
||||
0.11.0
|
||||
------
|
||||
|
||||
- Added OR operator for extended-search mode
|
||||
- Added `--execute-multi` action
|
||||
- Fixed incorrect cursor position when unicode wide characters are used in
|
||||
`--prompt`
|
||||
- Fixes and improvements in shell extensions
|
||||
|
||||
0.10.9
|
||||
------
|
||||
|
||||
- Extended-search mode is now enabled by default
|
||||
- `--extended-exact` is deprecated and instead we have `--exact` for
|
||||
orthogonally controlling "exactness" of search
|
||||
- Fixed not to display non-printable characters
|
||||
- Added `double-click` for `--bind` option
|
||||
- More robust handling of SIGWINCH
|
||||
|
||||
0.10.8
|
||||
------
|
||||
|
||||
- Fixed panic when trying to set colors after colors are disabled (#370)
|
||||
|
||||
0.10.7
|
||||
------
|
||||
|
||||
- Fixed unserialized interrupt handling during execute action which often
|
||||
caused invalid memory access and crash
|
||||
- Changed `--tiebreak=length` (default) to use trimmed length when `--nth` is
|
||||
used
|
||||
|
||||
0.10.6
|
||||
------
|
||||
|
||||
- Replaced `--header-file` with `--header` option
|
||||
- `--header` and `--header-lines` can be used together
|
||||
- Changed exit status
|
||||
- 0: Okay
|
||||
- 1: No match
|
||||
- 2: Error
|
||||
- 130: Interrupted
|
||||
- 64-bit linux binary is statically-linked with ncurses to avoid
|
||||
compatibility issues.
|
||||
|
||||
0.10.5
|
||||
------
|
||||
|
||||
- `'`-prefix to unquote the term in `--extended-exact` mode
|
||||
- Backward scan when `--tiebreak=end` is set
|
||||
|
||||
0.10.4
|
||||
------
|
||||
|
||||
- Fixed to remove ANSI code from output when `--with-nth` is set
|
||||
|
||||
0.10.3
|
||||
------
|
||||
|
||||
- Fixed slow performance of `--with-nth` when used with `--delimiter`
|
||||
- Regular expression engine of Golang as of now is very slow, so the fixed
|
||||
version will treat the given delimiter pattern as a plain string instead
|
||||
of a regular expression unless it contains special characters and is
|
||||
a valid regular expression.
|
||||
- Simpler regular expression for delimiter for better performance
|
||||
|
||||
0.10.2
|
||||
------
|
||||
|
||||
### Fixes and improvements
|
||||
|
||||
- Improvement in perceived response time of queries
|
||||
- Eager, efficient rune array conversion
|
||||
- Graceful exit when failed to initialize ncurses (invalid $TERM)
|
||||
- Improved ranking algorithm when `--nth` option is set
|
||||
- Changed the default command not to fail when there are files whose names
|
||||
start with dash
|
||||
|
||||
0.10.1
|
||||
------
|
||||
|
||||
### New features
|
||||
|
||||
- Added `--margin` option
|
||||
- Added options for sticky header
|
||||
- `--header-file`
|
||||
- `--header-lines`
|
||||
- Added `cancel` action which clears the input or closes the finder when the
|
||||
input is already empty
|
||||
- e.g. `export FZF_DEFAULT_OPTS="--bind esc:cancel"`
|
||||
- Added `delete-char/eof` action to differentiate `CTRL-D` and `DEL`
|
||||
|
||||
### Minor improvements/fixes
|
||||
|
||||
- Fixed to allow binding colon and comma keys
|
||||
- Fixed ANSI processor to handle color regions spanning multiple lines
|
||||
|
||||
0.10.0
|
||||
------
|
||||
|
||||
### New features
|
||||
|
||||
- More actions for `--bind`
|
||||
- `select-all`
|
||||
- `deselect-all`
|
||||
- `toggle-all`
|
||||
- `ignore`
|
||||
- `execute(...)` action for running arbitrary command without leaving fzf
|
||||
- `fzf --bind "ctrl-m:execute(less {})"`
|
||||
- `fzf --bind "ctrl-t:execute(tmux new-window -d 'vim {}')"`
|
||||
- If the command contains parentheses, use any of the follows alternative
|
||||
notations to avoid parse errors
|
||||
- `execute[...]`
|
||||
- `execute~...~`
|
||||
- `execute!...!`
|
||||
- `execute@...@`
|
||||
- `execute#...#`
|
||||
- `execute$...$`
|
||||
- `execute%...%`
|
||||
- `execute^...^`
|
||||
- `execute&...&`
|
||||
- `execute*...*`
|
||||
- `execute;...;`
|
||||
- `execute/.../`
|
||||
- `execute|...|`
|
||||
- `execute:...`
|
||||
- This is the special form that frees you from parse errors as it
|
||||
does not expect the closing character
|
||||
- The catch is that it should be the last one in the
|
||||
comma-separated list
|
||||
- Added support for optional search history
|
||||
- `--history HISTORY_FILE`
|
||||
- When used, `CTRL-N` and `CTRL-P` are automatically remapped to
|
||||
`next-history` and `previous-history`
|
||||
- `--history-size MAX_ENTRIES` (default: 1000)
|
||||
- Cyclic scrolling can be enabled with `--cycle`
|
||||
- Fixed the bug where the spinner was not spinning on idle input stream
|
||||
- e.g. `sleep 100 | fzf`
|
||||
|
||||
### Minor improvements/fixes
|
||||
|
||||
- Added synonyms for key names that can be specified for `--bind`,
|
||||
`--toggle-sort`, and `--expect`
|
||||
- Fixed the color of multi-select marker on the current line
|
||||
- Fixed to allow `^pattern$` in extended-search mode
|
||||
|
||||
|
||||
0.9.13
|
||||
------
|
||||
|
||||
### New features
|
||||
|
||||
- Color customization with the extended `--color` option
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed premature termination of Reader in the presence of a long line which
|
||||
is longer than 64KB
|
||||
|
||||
0.9.12
|
||||
------
|
||||
|
||||
### New features
|
||||
|
||||
- Added `--bind` option for custom key bindings
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed to update "inline-info" immediately after terminal resize
|
||||
- Fixed ANSI code offset calculation
|
||||
|
||||
0.9.11
|
||||
------
|
||||
|
||||
### New features
|
||||
|
||||
- Added `--inline-info` option for saving screen estate (#202)
|
||||
- Useful inside Neovim
|
||||
- e.g. `let $FZF_DEFAULT_OPTS = $FZF_DEFAULT_OPTS.' --inline-info'`
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Invalid mutation of input on case conversion (#209)
|
||||
- Smart-case for each term in extended-search mode (#208)
|
||||
- Fixed double-click result when scroll offset is positive
|
||||
|
||||
0.9.10
|
||||
------
|
||||
|
||||
### Improvements
|
||||
|
||||
- Performance optimization
|
||||
- Less aggressive memoization to limit memory usage
|
||||
|
||||
### New features
|
||||
|
||||
- Added color scheme for light background: `--color=light`
|
||||
|
||||
0.9.9
|
||||
-----
|
||||
|
||||
### New features
|
||||
|
||||
- Added `--tiebreak` option (#191)
|
||||
- Added `--no-hscroll` option (#193)
|
||||
- Visual indication of `--toggle-sort` (#194)
|
||||
|
||||
0.9.8
|
||||
-----
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed Unicode case handling (#186)
|
||||
- Fixed to terminate on RuneError (#185)
|
||||
|
||||
0.9.7
|
||||
-----
|
||||
|
||||
### New features
|
||||
|
||||
- Added `--toggle-sort` option (#173)
|
||||
- `--toggle-sort=ctrl-r` is applied to `CTRL-R` shell extension
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed to print empty line if `--expect` is set and fzf is completed by
|
||||
`--select-1` or `--exit-0` (#172)
|
||||
- Fixed to allow comma character as an argument to `--expect` option
|
||||
|
||||
0.9.6
|
||||
-----
|
||||
|
||||
### New features
|
||||
|
||||
#### Added `--expect` option (#163)
|
||||
|
||||
If you provide a comma-separated list of keys with `--expect` option, fzf will
|
||||
allow you to select the match and complete the finder when any of the keys is
|
||||
pressed. Additionally, fzf will print the name of the key pressed as the first
|
||||
line of the output so that your script can decide what to do next based on the
|
||||
information.
|
||||
|
||||
```sh
|
||||
fzf --expect=ctrl-v,ctrl-t,alt-s,f1,f2,~,@
|
||||
```
|
||||
|
||||
The updated vim plugin uses this option to implement
|
||||
[ctrlp](https://github.com/kien/ctrlp.vim)-compatible key bindings.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed to ignore ANSI escape code `\e[K` (#162)
|
||||
|
||||
0.9.5
|
||||
-----
|
||||
|
||||
### New features
|
||||
|
||||
#### Added `--ansi` option (#150)
|
||||
|
||||
If you give `--ansi` option to fzf, fzf will interpret ANSI color codes from
|
||||
the input, display the item with the ANSI colors (true colors are not
|
||||
supported), and strips the codes from the output. This option is off by
|
||||
default as it entails some overhead.
|
||||
|
||||
### Improvements
|
||||
|
||||
#### Reduced initial memory footprint (#151)
|
||||
|
||||
By removing unnecessary copy of pointers, fzf will use significantly smaller
|
||||
amount of memory when it's started. The difference is hugely noticeable when
|
||||
the input is extremely large. (e.g. `locate / | fzf`)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
- Fixed panic on `--no-sort --filter ''` (#149)
|
||||
|
||||
0.9.4
|
||||
-----
|
||||
|
||||
### New features
|
||||
|
||||
#### Added `--tac` option to reverse the order of the input.
|
||||
|
||||
One might argue that this option is unnecessary since we can already put `tac`
|
||||
or `tail -r` in the command pipeline to achieve the same result. However, the
|
||||
advantage of `--tac` is that it does not block until the input is complete.
|
||||
|
||||
### *Backward incompatible changes*
|
||||
|
||||
#### Changed behavior on `--no-sort`
|
||||
|
||||
`--no-sort` option will no longer reverse the display order within finder. You
|
||||
may want to use the new `--tac` option with `--no-sort`.
|
||||
|
||||
```
|
||||
history | fzf +s --tac
|
||||
```
|
||||
|
||||
### Improvements
|
||||
|
||||
#### `--filter` will not block when sort is disabled
|
||||
|
||||
When fzf works in filtering mode (`--filter`) and sort is disabled
|
||||
(`--no-sort`), there's no need to block until input is complete. The new
|
||||
version of fzf will print the matches on-the-fly when the following condition
|
||||
is met:
|
||||
|
||||
--filter TERM --no-sort [--no-tac --no-sync]
|
||||
|
||||
or simply:
|
||||
|
||||
-f TERM +s
|
||||
|
||||
This change removes unnecessary delay in the use cases like the following:
|
||||
|
||||
fzf -f xxx +s | head -5
|
||||
|
||||
However, in this case, fzf processes the lines sequentially, so it cannot
|
||||
utilize multiple cores, and fzf will run slightly slower than the previous
|
||||
mode of execution where filtering is done in parallel after the entire input
|
||||
is loaded. If the user is concerned about this performance problem, one can
|
||||
add `--sync` option to re-enable buffering.
|
||||
|
||||
0.9.3
|
||||
-----
|
||||
|
||||
### New features
|
||||
- Added `--sync` option for multi-staged filtering
|
||||
|
||||
### Improvements
|
||||
- `--select-1` and `--exit-0` will start finder immediately when the condition
|
||||
cannot be met
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Junegunn Choi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -0,0 +1,435 @@
|
||||
FZF Vim integration
|
||||
===================
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
Once you have fzf installed, you can enable it inside Vim simply by adding the
|
||||
directory to `&runtimepath` in your Vim configuration file. The path may
|
||||
differ depending on the package manager.
|
||||
|
||||
```vim
|
||||
" If installed using Homebrew
|
||||
set rtp+=/usr/local/opt/fzf
|
||||
|
||||
" If installed using git
|
||||
set rtp+=~/.fzf
|
||||
```
|
||||
|
||||
If you use [vim-plug](https://github.com/junegunn/vim-plug), the same can be
|
||||
written as:
|
||||
|
||||
```vim
|
||||
" If installed using Homebrew
|
||||
Plug '/usr/local/opt/fzf'
|
||||
|
||||
" If installed using git
|
||||
Plug '~/.fzf'
|
||||
```
|
||||
|
||||
But if you want the latest Vim plugin file from GitHub rather than the one
|
||||
included in the package, write:
|
||||
|
||||
```vim
|
||||
Plug 'junegunn/fzf'
|
||||
```
|
||||
|
||||
The Vim plugin will pick up fzf binary available on the system. If fzf is not
|
||||
found on `$PATH`, it will ask you if it should download the latest binary for
|
||||
you.
|
||||
|
||||
To make sure that you have the latest version of the binary, set up
|
||||
post-update hook like so:
|
||||
|
||||
```vim
|
||||
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||
```
|
||||
|
||||
Summary
|
||||
-------
|
||||
|
||||
The Vim plugin of fzf provides two core functions, and `:FZF` command which is
|
||||
the basic file selector command built on top of them.
|
||||
|
||||
1. **`fzf#run([spec dict])`**
|
||||
- Starts fzf inside Vim with the given spec
|
||||
- `:call fzf#run({'source': 'ls'})`
|
||||
2. **`fzf#wrap([spec dict]) -> (dict)`**
|
||||
- Takes a spec for `fzf#run` and returns an extended version of it with
|
||||
additional options for addressing global preferences (`g:fzf_xxx`)
|
||||
- `:echo fzf#wrap({'source': 'ls'})`
|
||||
- We usually *wrap* a spec with `fzf#wrap` before passing it to `fzf#run`
|
||||
- `:call fzf#run(fzf#wrap({'source': 'ls'}))`
|
||||
3. **`:FZF [fzf_options string] [path string]`**
|
||||
- Basic fuzzy file selector
|
||||
- A reference implementation for those who don't want to write VimScript
|
||||
to implement custom commands
|
||||
- If you're looking for more such commands, check out [fzf.vim](https://github.com/junegunn/fzf.vim) project.
|
||||
|
||||
The most important of all is `fzf#run`, but it would be easier to understand
|
||||
the whole if we start off with `:FZF` command.
|
||||
|
||||
`:FZF[!]`
|
||||
---------
|
||||
|
||||
```vim
|
||||
" Look for files under current directory
|
||||
:FZF
|
||||
|
||||
" Look for files under your home directory
|
||||
:FZF ~
|
||||
|
||||
" With fzf command-line options
|
||||
:FZF --reverse --info=inline /tmp
|
||||
|
||||
" Bang version starts fzf in fullscreen mode
|
||||
:FZF!
|
||||
```
|
||||
|
||||
Similarly to [ctrlp.vim](https://github.com/kien/ctrlp.vim), use enter key,
|
||||
`CTRL-T`, `CTRL-X` or `CTRL-V` to open selected files in the current window,
|
||||
in new tabs, in horizontal splits, or in vertical splits respectively.
|
||||
|
||||
Note that the environment variables `FZF_DEFAULT_COMMAND` and
|
||||
`FZF_DEFAULT_OPTS` also apply here.
|
||||
|
||||
### Configuration
|
||||
|
||||
- `g:fzf_action`
|
||||
- Customizable extra key bindings for opening selected files in different ways
|
||||
- `g:fzf_layout`
|
||||
- Determines the size and position of fzf window
|
||||
- `g:fzf_colors`
|
||||
- Customizes fzf colors to match the current color scheme
|
||||
- `g:fzf_history_dir`
|
||||
- Enables history feature
|
||||
|
||||
#### Examples
|
||||
|
||||
```vim
|
||||
" This is the default extra key bindings
|
||||
let g:fzf_action = {
|
||||
\ 'ctrl-t': 'tab split',
|
||||
\ 'ctrl-x': 'split',
|
||||
\ 'ctrl-v': 'vsplit' }
|
||||
|
||||
" An action can be a reference to a function that processes selected lines
|
||||
function! s:build_quickfix_list(lines)
|
||||
call setqflist(map(copy(a:lines), '{ "filename": v:val }'))
|
||||
copen
|
||||
cc
|
||||
endfunction
|
||||
|
||||
let g:fzf_action = {
|
||||
\ 'ctrl-q': function('s:build_quickfix_list'),
|
||||
\ 'ctrl-t': 'tab split',
|
||||
\ 'ctrl-x': 'split',
|
||||
\ 'ctrl-v': 'vsplit' }
|
||||
|
||||
" Default fzf layout
|
||||
" - down / up / left / right
|
||||
let g:fzf_layout = { 'down': '~40%' }
|
||||
|
||||
" You can set up fzf window using a Vim command (Neovim or latest Vim 8 required)
|
||||
let g:fzf_layout = { 'window': 'enew' }
|
||||
let g:fzf_layout = { 'window': '-tabnew' }
|
||||
let g:fzf_layout = { 'window': '10new' }
|
||||
|
||||
" Customize fzf colors to match your color scheme
|
||||
" - fzf#wrap translates this to a set of `--color` options
|
||||
let g:fzf_colors =
|
||||
\ { 'fg': ['fg', 'Normal'],
|
||||
\ 'bg': ['bg', 'Normal'],
|
||||
\ 'hl': ['fg', 'Comment'],
|
||||
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
|
||||
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
|
||||
\ 'hl+': ['fg', 'Statement'],
|
||||
\ 'info': ['fg', 'PreProc'],
|
||||
\ 'border': ['fg', 'Ignore'],
|
||||
\ 'prompt': ['fg', 'Conditional'],
|
||||
\ 'pointer': ['fg', 'Exception'],
|
||||
\ 'marker': ['fg', 'Keyword'],
|
||||
\ 'spinner': ['fg', 'Label'],
|
||||
\ 'header': ['fg', 'Comment'] }
|
||||
|
||||
" Enable per-command history
|
||||
" - History files will be stored in the specified directory
|
||||
" - When set, CTRL-N and CTRL-P will be bound to 'next-history' and
|
||||
" 'previous-history' instead of 'down' and 'up'.
|
||||
let g:fzf_history_dir = '~/.local/share/fzf-history'
|
||||
```
|
||||
|
||||
##### Explanation of `g:fzf_colors`
|
||||
|
||||
`g:fzf_colors` is a dictionary mapping fzf elements to a color specification
|
||||
list:
|
||||
|
||||
element: [ component, group1 [, group2, ...] ]
|
||||
|
||||
- `element` is an fzf element to apply a color to:
|
||||
|
||||
| Element | Description |
|
||||
| --- | --- |
|
||||
| `fg` / `bg` / `hl` | Item (foreground / background / highlight) |
|
||||
| `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight) |
|
||||
| `hl` / `hl+` | Highlighted substrings (normal / current) |
|
||||
| `gutter` | Background of the gutter on the left |
|
||||
| `pointer` | Pointer to the current line (`>`) |
|
||||
| `marker` | Multi-select marker (`>`) |
|
||||
| `border` | Border around the window (`--border` and `--preview`) |
|
||||
| `header` | Header (`--header` or `--header-lines`) |
|
||||
| `info` | Info line (match counters) |
|
||||
| `spinner` | Streaming input indicator |
|
||||
| `prompt` | Prompt before query (`> `) |
|
||||
|
||||
- `component` specifies the component (`fg` / `bg`) from which to extract the
|
||||
color when considering each of the following highlight groups
|
||||
|
||||
- `group1 [, group2, ...]` is a list of highlight groups that are searched (in
|
||||
order) for a matching color definition
|
||||
|
||||
For example, consider the following specification:
|
||||
|
||||
```vim
|
||||
'prompt': ['fg', 'Conditional', 'Comment'],
|
||||
```
|
||||
|
||||
This means we color the **prompt**
|
||||
- using the `fg` attribute of the `Conditional` if it exists,
|
||||
- otherwise use the `fg` attribute of the `Comment` highlight group if it exists,
|
||||
- otherwise fall back to the default color settings for the **prompt**.
|
||||
|
||||
You can examine the color option generated according the setting by printing
|
||||
the result of `fzf#wrap()` function like so:
|
||||
|
||||
```vim
|
||||
:echo fzf#wrap()
|
||||
```
|
||||
|
||||
`fzf#run`
|
||||
---------
|
||||
|
||||
`fzf#run()` function is the core of Vim integration. It takes a single
|
||||
dictionary argument, *a spec*, and starts fzf process accordingly. At the very
|
||||
least, specify `sink` option to tell what it should do with the selected
|
||||
entry.
|
||||
|
||||
```vim
|
||||
call fzf#run({'sink': 'e'})
|
||||
```
|
||||
|
||||
We haven't specified the `source`, so this is equivalent to starting fzf on
|
||||
command line without standard input pipe; fzf will use find command (or
|
||||
`$FZF_DEFAULT_COMMAND` if defined) to list the files under the current
|
||||
directory. When you select one, it will open it with the sink, `:e` command.
|
||||
If you want to open it in a new tab, you can pass `:tabedit` command instead
|
||||
as the sink.
|
||||
|
||||
```vim
|
||||
call fzf#run({'sink': 'tabedit'})
|
||||
```
|
||||
|
||||
Instead of using the default find command, you can use any shell command as
|
||||
the source. The following example will list the files managed by git. It's
|
||||
equivalent to running `git ls-files | fzf` on shell.
|
||||
|
||||
```vim
|
||||
call fzf#run({'source': 'git ls-files', 'sink': 'e'})
|
||||
```
|
||||
|
||||
fzf options can be specified as `options` entry in spec dictionary.
|
||||
|
||||
```vim
|
||||
call fzf#run({'sink': 'tabedit', 'options': '--multi --reverse'})
|
||||
```
|
||||
|
||||
You can also pass a layout option if you don't want fzf window to take up the
|
||||
entire screen.
|
||||
|
||||
```vim
|
||||
" up / down / left / right / window are allowed
|
||||
call fzf#run({'source': 'git ls-files', 'sink': 'e', 'left': '40%'})
|
||||
call fzf#run({'source': 'git ls-files', 'sink': 'e', 'window': '30vnew'})
|
||||
```
|
||||
|
||||
`source` doesn't have to be an external shell command, you can pass a Vim
|
||||
array as the source. In the next example, we pass the names of color
|
||||
schemes as the source to implement a color scheme selector.
|
||||
|
||||
```vim
|
||||
call fzf#run({'source': map(split(globpath(&rtp, 'colors/*.vim')),
|
||||
\ 'fnamemodify(v:val, ":t:r")'),
|
||||
\ 'sink': 'colo', 'left': '25%'})
|
||||
```
|
||||
|
||||
The following table summarizes the available options.
|
||||
|
||||
| Option name | Type | Description |
|
||||
| -------------------------- | ------------- | ---------------------------------------------------------------- |
|
||||
| `source` | string | External command to generate input to fzf (e.g. `find .`) |
|
||||
| `source` | list | Vim list as input to fzf |
|
||||
| `sink` | string | Vim command to handle the selected item (e.g. `e`, `tabe`) |
|
||||
| `sink` | funcref | Reference to function to process each selected item |
|
||||
| `sink*` | funcref | Similar to `sink`, but takes the list of output lines at once |
|
||||
| `options` | string/list | Options to fzf |
|
||||
| `dir` | string | Working directory |
|
||||
| `up`/`down`/`left`/`right` | number/string | (Layout) Window position and size (e.g. `20`, `50%`) |
|
||||
| `tmux` | string | (Layout) fzf-tmux options (e.g. `-p90%,60%`) |
|
||||
| `window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new`) |
|
||||
| `window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}`) |
|
||||
|
||||
`options` entry can be either a string or a list. For simple cases, string
|
||||
should suffice, but prefer to use list type to avoid escaping issues.
|
||||
|
||||
```vim
|
||||
call fzf#run({'options': '--reverse --prompt "C:\\Program Files\\"'})
|
||||
call fzf#run({'options': ['--reverse', '--prompt', 'C:\Program Files\']})
|
||||
```
|
||||
|
||||
When `window` entry is a dictionary, fzf will start in a popup window. The
|
||||
following options are allowed:
|
||||
|
||||
- Required:
|
||||
- `width` [float range [0 ~ 1]]
|
||||
- `height` [float range [0 ~ 1]]
|
||||
- Optional:
|
||||
- `yoffset` [float default 0.5 range [0 ~ 1]]
|
||||
- `xoffset` [float default 0.5 range [0 ~ 1]]
|
||||
- `highlight` [string default `'Comment'`]: Highlight group for border
|
||||
- `border` [string default `rounded`]: Border style
|
||||
- `rounded` / `sharp` / `horizontal` / `vertical` / `top` / `bottom` / `left` / `right`
|
||||
|
||||
`fzf#wrap`
|
||||
----------
|
||||
|
||||
We have seen that several aspects of `:FZF` command can be configured with
|
||||
a set of global option variables; different ways to open files
|
||||
(`g:fzf_action`), window position and size (`g:fzf_layout`), color palette
|
||||
(`g:fzf_colors`), etc.
|
||||
|
||||
So how can we make our custom `fzf#run` calls also respect those variables?
|
||||
Simply by *"wrapping"* the spec dictionary with `fzf#wrap` before passing it
|
||||
to `fzf#run`.
|
||||
|
||||
- **`fzf#wrap([name string], [spec dict], [fullscreen bool]) -> (dict)`**
|
||||
- All arguments are optional. Usually we only need to pass a spec dictionary.
|
||||
- `name` is for managing history files. It is ignored if
|
||||
`g:fzf_history_dir` is not defined.
|
||||
- `fullscreen` can be either `0` or `1` (default: 0).
|
||||
|
||||
`fzf#wrap` takes a spec and returns an extended version of it (also
|
||||
a dictionary) with additional options for addressing global preferences. You
|
||||
can examine the return value of it like so:
|
||||
|
||||
```vim
|
||||
echo fzf#wrap({'source': 'ls'})
|
||||
```
|
||||
|
||||
After we *"wrap"* our spec, we pass it to `fzf#run`.
|
||||
|
||||
```vim
|
||||
call fzf#run(fzf#wrap({'source': 'ls'}))
|
||||
```
|
||||
|
||||
Now it supports `CTRL-T`, `CTRL-V`, and `CTRL-X` key bindings and it opens fzf
|
||||
window according to `g:fzf_layout` setting.
|
||||
|
||||
To make it easier to use, let's define `LS` command.
|
||||
|
||||
```vim
|
||||
command! LS call fzf#run(fzf#wrap({'source': 'ls'}))
|
||||
```
|
||||
|
||||
Type `:LS` and see how it works.
|
||||
|
||||
We would like to make `:LS!` (bang version) open fzf in fullscreen, just like
|
||||
`:FZF!`. Add `-bang` to command definition, and use `<bang>` value to set
|
||||
the last `fullscreen` argument of `fzf#wrap` (see `:help <bang>`).
|
||||
|
||||
```vim
|
||||
" On :LS!, <bang> evaluates to '!', and '!0' becomes 1
|
||||
command! -bang LS call fzf#run(fzf#wrap({'source': 'ls'}, <bang>0))
|
||||
```
|
||||
|
||||
Our `:LS` command will be much more useful if we can pass a directory argument
|
||||
to it, so that something like `:LS /tmp` is possible.
|
||||
|
||||
```vim
|
||||
command! -bang -complete=dir -nargs=* LS
|
||||
\ call fzf#run(fzf#wrap({'source': 'ls', 'dir': <q-args>}, <bang>0))
|
||||
```
|
||||
|
||||
Lastly, if you have enabled `g:fzf_history_dir`, you might want to assign
|
||||
a unique name to our command and pass it as the first argument to `fzf#wrap`.
|
||||
|
||||
```vim
|
||||
" The query history for this command will be stored as 'ls' inside g:fzf_history_dir.
|
||||
" The name is ignored if g:fzf_history_dir is not defined.
|
||||
command! -bang -complete=dir -nargs=* LS
|
||||
\ call fzf#run(fzf#wrap('ls', {'source': 'ls', 'dir': <q-args>}, <bang>0))
|
||||
```
|
||||
|
||||
Tips
|
||||
----
|
||||
|
||||
### fzf inside terminal buffer
|
||||
|
||||
The latest versions of Vim and Neovim include builtin terminal emulator
|
||||
(`:terminal`) and fzf will start in a terminal buffer in the following cases:
|
||||
|
||||
- On Neovim
|
||||
- On GVim
|
||||
- On Terminal Vim with a non-default layout
|
||||
- `call fzf#run({'left': '30%'})` or `let g:fzf_layout = {'left': '30%'}`
|
||||
|
||||
#### Starting fzf in a popup window
|
||||
|
||||
```vim
|
||||
" Required:
|
||||
" - width [float range [0 ~ 1]]
|
||||
" - height [float range [0 ~ 1]]
|
||||
"
|
||||
" Optional:
|
||||
" - xoffset [float default 0.5 range [0 ~ 1]]
|
||||
" - yoffset [float default 0.5 range [0 ~ 1]]
|
||||
" - highlight [string default 'Comment']: Highlight group for border
|
||||
" - border [string default 'rounded']: Border style
|
||||
" - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
|
||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||
```
|
||||
|
||||
Alternatively, you can make fzf open in a tmux popup window (requires tmux 3.2
|
||||
or above) by putting fzf-tmux options in `tmux` key.
|
||||
|
||||
```vim
|
||||
" See `man fzf-tmux` for available options
|
||||
if exists('$TMUX')
|
||||
let g:fzf_layout = { 'tmux': '-p90%,60%' }
|
||||
else
|
||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||
endif
|
||||
```
|
||||
|
||||
#### Hide statusline
|
||||
|
||||
When fzf starts in a terminal buffer, the file type of the buffer is set to
|
||||
`fzf`. So you can set up `FileType fzf` autocmd to customize the settings of
|
||||
the window.
|
||||
|
||||
For example, if you use the default layout (`{'down': '~40%'}`) on Neovim, you
|
||||
might want to temporarily disable the statusline for a cleaner look.
|
||||
|
||||
```vim
|
||||
if has('nvim') && !exists('g:fzf_layout')
|
||||
autocmd! FileType fzf
|
||||
autocmd FileType fzf set laststatus=0 noshowmode noruler
|
||||
\| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
|
||||
endif
|
||||
```
|
||||
|
||||
[License](LICENSE)
|
||||
------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Junegunn Choi
|
||||
@@ -0,0 +1,655 @@
|
||||
<img src="https://raw.githubusercontent.com/junegunn/i/master/fzf.png" height="170" alt="fzf - a command-line fuzzy finder"> [](https://travis-ci.org/junegunn/fzf)
|
||||
===
|
||||
|
||||
fzf is a general-purpose command-line fuzzy finder.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/junegunn/i/master/fzf-preview.png" width=640>
|
||||
|
||||
It's an interactive Unix filter for command-line that can be used with any
|
||||
list; files, command history, processes, hostnames, bookmarks, git commits,
|
||||
etc.
|
||||
|
||||
Pros
|
||||
----
|
||||
|
||||
- Portable, no dependencies
|
||||
- Blazingly fast
|
||||
- The most comprehensive feature set
|
||||
- Flexible layout
|
||||
- Batteries included
|
||||
- Vim/Neovim plugin, key bindings and fuzzy auto-completion
|
||||
|
||||
Table of Contents
|
||||
-----------------
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Using Homebrew or Linuxbrew](#using-homebrew-or-linuxbrew)
|
||||
* [Using git](#using-git)
|
||||
* [Using Linux package managers](#using-linux-package-managers)
|
||||
* [Windows](#windows)
|
||||
* [As Vim plugin](#as-vim-plugin)
|
||||
* [Upgrading fzf](#upgrading-fzf)
|
||||
* [Building fzf](#building-fzf)
|
||||
* [Usage](#usage)
|
||||
* [Using the finder](#using-the-finder)
|
||||
* [Layout](#layout)
|
||||
* [Search syntax](#search-syntax)
|
||||
* [Environment variables](#environment-variables)
|
||||
* [Options](#options)
|
||||
* [Demo](#demo)
|
||||
* [Examples](#examples)
|
||||
* [fzf-tmux script](#fzf-tmux-script)
|
||||
* [Key bindings for command line](#key-bindings-for-command-line)
|
||||
* [Fuzzy completion for bash and zsh](#fuzzy-completion-for-bash-and-zsh)
|
||||
* [Files and directories](#files-and-directories)
|
||||
* [Process IDs](#process-ids)
|
||||
* [Host names](#host-names)
|
||||
* [Environment variables / Aliases](#environment-variables--aliases)
|
||||
* [Settings](#settings)
|
||||
* [Supported commands](#supported-commands)
|
||||
* [Custom fuzzy completion](#custom-fuzzy-completion)
|
||||
* [Vim plugin](#vim-plugin)
|
||||
* [Advanced topics](#advanced-topics)
|
||||
* [Performance](#performance)
|
||||
* [Executing external programs](#executing-external-programs)
|
||||
* [Preview window](#preview-window)
|
||||
* [Tips](#tips)
|
||||
* [Respecting .gitignore](#respecting-gitignore)
|
||||
* [Fish shell](#fish-shell)
|
||||
* [Related projects](#related-projects)
|
||||
* [<a href="LICENSE">License</a>](#license)
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
fzf project consists of the following components:
|
||||
|
||||
- `fzf` executable
|
||||
- `fzf-tmux` script for launching fzf in a tmux pane
|
||||
- Shell extensions
|
||||
- Key bindings (`CTRL-T`, `CTRL-R`, and `ALT-C`) (bash, zsh, fish)
|
||||
- Fuzzy auto-completion (bash, zsh)
|
||||
- Vim/Neovim plugin
|
||||
|
||||
You can [download fzf executable][bin] alone if you don't need the extra
|
||||
stuff.
|
||||
|
||||
[bin]: https://github.com/junegunn/fzf-bin/releases
|
||||
|
||||
### Using Homebrew or Linuxbrew
|
||||
|
||||
You can use [Homebrew](http://brew.sh/) or [Linuxbrew](http://linuxbrew.sh/)
|
||||
to install fzf.
|
||||
|
||||
```sh
|
||||
brew install fzf
|
||||
|
||||
# To install useful key bindings and fuzzy completion:
|
||||
$(brew --prefix)/opt/fzf/install
|
||||
```
|
||||
|
||||
fzf is also available [via MacPorts][portfile]: `sudo port install fzf`
|
||||
|
||||
[portfile]: https://github.com/macports/macports-ports/blob/master/sysutils/fzf/Portfile
|
||||
|
||||
### Using git
|
||||
|
||||
Alternatively, you can "git clone" this repository to any directory and run
|
||||
[install](https://github.com/junegunn/fzf/blob/master/install) script.
|
||||
|
||||
```sh
|
||||
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
|
||||
~/.fzf/install
|
||||
```
|
||||
|
||||
### Using Linux package managers
|
||||
|
||||
| Package Manager | Linux Distribution | Command |
|
||||
| --- | --- | --- |
|
||||
| APK | Alpine Linux | `sudo apk add fzf` |
|
||||
| APT | Debian 9+/Ubuntu 19.10+ | `sudo apt-get install fzf` |
|
||||
| Conda | | `conda install -c conda-forge fzf` |
|
||||
| DNF | Fedora | `sudo dnf install fzf` |
|
||||
| Nix | NixOS | `nix-env -iA nixpkgs.fzf` |
|
||||
| Pacman | Arch Linux | `sudo pacman -S fzf` |
|
||||
| pkg | FreeBSD | `pkg install fzf` |
|
||||
| pkg_add | OpenBSD | `pkg_add fzf` |
|
||||
| Zypper | openSUSE | `sudo zypper install fzf` |
|
||||
|
||||
Shell extensions (key bindings and fuzzy auto-completion) and Vim/Neovim
|
||||
plugin may or may not be enabled by default depending on the package manager.
|
||||
Refer to the package documentation for more information.
|
||||
|
||||
### Windows
|
||||
|
||||
Pre-built binaries for Windows can be downloaded [here][bin]. fzf is also
|
||||
available via [Chocolatey][choco] and [Scoop][scoop]:
|
||||
|
||||
| Package manager | Command |
|
||||
| --- | --- |
|
||||
| Chocolatey | `choco install fzf` |
|
||||
| Scoop | `scoop install fzf` |
|
||||
|
||||
[choco]: https://chocolatey.org/packages/fzf
|
||||
[scoop]: https://github.com/ScoopInstaller/Main/blob/master/bucket/fzf.json
|
||||
|
||||
Known issues and limitations on Windows can be found on [the wiki
|
||||
page][windows-wiki].
|
||||
|
||||
[windows-wiki]: https://github.com/junegunn/fzf/wiki/Windows
|
||||
|
||||
### As Vim plugin
|
||||
|
||||
If you use
|
||||
[vim-plug](https://github.com/junegunn/vim-plug), add this line to your Vim
|
||||
configuration file:
|
||||
|
||||
```vim
|
||||
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||
```
|
||||
|
||||
`fzf#install()` makes sure that you have the latest binary, but it's optional,
|
||||
so you can omit it if you use a plugin manager that doesn't support hooks.
|
||||
|
||||
For more installation options, see [README-VIM.md](README-VIM.md).
|
||||
|
||||
Upgrading fzf
|
||||
-------------
|
||||
|
||||
fzf is being actively developed and you might want to upgrade it once in a
|
||||
while. Please follow the instruction below depending on the installation
|
||||
method used.
|
||||
|
||||
- git: `cd ~/.fzf && git pull && ./install`
|
||||
- brew: `brew update; brew reinstall fzf`
|
||||
- macports: `sudo port upgrade fzf`
|
||||
- chocolatey: `choco upgrade fzf`
|
||||
- vim-plug: `:PlugUpdate fzf`
|
||||
|
||||
Building fzf
|
||||
------------
|
||||
|
||||
See [BUILD.md](BUILD.md).
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
fzf will launch interactive finder, read the list from STDIN, and write the
|
||||
selected item to STDOUT.
|
||||
|
||||
```sh
|
||||
find * -type f | fzf > selected
|
||||
```
|
||||
|
||||
Without STDIN pipe, fzf will use find command to fetch the list of
|
||||
files excluding hidden ones. (You can override the default command with
|
||||
`FZF_DEFAULT_COMMAND`)
|
||||
|
||||
```sh
|
||||
vim $(fzf)
|
||||
```
|
||||
|
||||
#### Using the finder
|
||||
|
||||
- `CTRL-J` / `CTRL-K` (or `CTRL-N` / `CTRL-P`) to move cursor up and down
|
||||
- `Enter` key to select the item, `CTRL-C` / `CTRL-G` / `ESC` to exit
|
||||
- On multi-select mode (`-m`), `TAB` and `Shift-TAB` to mark multiple items
|
||||
- Emacs style key bindings
|
||||
- Mouse: scroll, click, double-click; shift-click and shift-scroll on
|
||||
multi-select mode
|
||||
|
||||
#### Layout
|
||||
|
||||
fzf by default starts in fullscreen mode, but you can make it start below the
|
||||
cursor with `--height` option.
|
||||
|
||||
```sh
|
||||
vim $(fzf --height 40%)
|
||||
```
|
||||
|
||||
Also check out `--reverse` and `--layout` options if you prefer
|
||||
"top-down" layout instead of the default "bottom-up" layout.
|
||||
|
||||
```sh
|
||||
vim $(fzf --height 40% --reverse)
|
||||
```
|
||||
|
||||
You can add these options to `$FZF_DEFAULT_OPTS` so that they're applied by
|
||||
default. For example,
|
||||
|
||||
```sh
|
||||
export FZF_DEFAULT_OPTS='--height 40% --layout=reverse --border'
|
||||
```
|
||||
|
||||
#### Search syntax
|
||||
|
||||
Unless otherwise specified, fzf starts in "extended-search mode" where you can
|
||||
type in multiple search terms delimited by spaces. e.g. `^music .mp3$ sbtrkt
|
||||
!fire`
|
||||
|
||||
| Token | Match type | Description |
|
||||
| --------- | -------------------------- | ------------------------------------ |
|
||||
| `sbtrkt` | fuzzy-match | Items that match `sbtrkt` |
|
||||
| `'wild` | exact-match (quoted) | Items that include `wild` |
|
||||
| `^music` | prefix-exact-match | Items that start with `music` |
|
||||
| `.mp3$` | suffix-exact-match | Items that end with `.mp3` |
|
||||
| `!fire` | inverse-exact-match | Items that do not include `fire` |
|
||||
| `!^music` | inverse-prefix-exact-match | Items that do not start with `music` |
|
||||
| `!.mp3$` | inverse-suffix-exact-match | Items that do not end with `.mp3` |
|
||||
|
||||
If you don't prefer fuzzy matching and do not wish to "quote" every word,
|
||||
start fzf with `-e` or `--exact` option. Note that when `--exact` is set,
|
||||
`'`-prefix "unquotes" the term.
|
||||
|
||||
A single bar character term acts as an OR operator. For example, the following
|
||||
query matches entries that start with `core` and end with either `go`, `rb`,
|
||||
or `py`.
|
||||
|
||||
```
|
||||
^core go$ | rb$ | py$
|
||||
```
|
||||
|
||||
#### Environment variables
|
||||
|
||||
- `FZF_DEFAULT_COMMAND`
|
||||
- Default command to use when input is tty
|
||||
- e.g. `export FZF_DEFAULT_COMMAND='fd --type f'`
|
||||
- `FZF_DEFAULT_OPTS`
|
||||
- Default options
|
||||
- e.g. `export FZF_DEFAULT_OPTS="--layout=reverse --inline-info"`
|
||||
|
||||
#### Options
|
||||
|
||||
See the man page (`man fzf`) for the full list of options.
|
||||
|
||||
#### Demo
|
||||
If you learn by watching videos, check out this screencast by [@samoshkin](https://github.com/samoshkin) to explore `fzf` features.
|
||||
|
||||
<a title="fzf - command-line fuzzy finder" href="https://www.youtube.com/watch?v=qgG5Jhi_Els">
|
||||
<img src="https://i.imgur.com/vtG8olE.png" width="640">
|
||||
</a>
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Many useful examples can be found on [the wiki
|
||||
page](https://github.com/junegunn/fzf/wiki/examples). Feel free to add your
|
||||
own as well.
|
||||
|
||||
`fzf-tmux` script
|
||||
-----------------
|
||||
|
||||
[fzf-tmux](bin/fzf-tmux) is a bash script that opens fzf in a tmux pane.
|
||||
|
||||
```sh
|
||||
# usage: fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
|
||||
|
||||
# See available options
|
||||
fzf-tmux --help
|
||||
|
||||
# select git branches in horizontal split below (15 lines)
|
||||
git branch | fzf-tmux -d 15
|
||||
|
||||
# select multiple words in vertical split on the left (20% of screen width)
|
||||
cat /usr/share/dict/words | fzf-tmux -l 20% --multi --reverse
|
||||
```
|
||||
|
||||
It will still work even when you're not on tmux, silently ignoring `-[pudlr]`
|
||||
options, so you can invariably use `fzf-tmux` in your scripts.
|
||||
|
||||
Alternatively, you can use `--height HEIGHT[%]` option not to start fzf in
|
||||
fullscreen mode.
|
||||
|
||||
```sh
|
||||
fzf --height 40%
|
||||
```
|
||||
|
||||
Key bindings for command-line
|
||||
-----------------------------
|
||||
|
||||
The install script will setup the following key bindings for bash, zsh, and
|
||||
fish.
|
||||
|
||||
- `CTRL-T` - Paste the selected files and directories onto the command-line
|
||||
- Set `FZF_CTRL_T_COMMAND` to override the default command
|
||||
- Set `FZF_CTRL_T_OPTS` to pass additional options
|
||||
- `CTRL-R` - Paste the selected command from history onto the command-line
|
||||
- If you want to see the commands in chronological order, press `CTRL-R`
|
||||
again which toggles sorting by relevance
|
||||
- Set `FZF_CTRL_R_OPTS` to pass additional options
|
||||
- `ALT-C` - cd into the selected directory
|
||||
- Set `FZF_ALT_C_COMMAND` to override the default command
|
||||
- Set `FZF_ALT_C_OPTS` to pass additional options
|
||||
|
||||
If you're on a tmux session, you can start fzf in a tmux split pane or in
|
||||
a tmux popup window by setting `FZF_TMUX_OPTS` (e.g. `-d 40%`).
|
||||
See `fzf-tmux --help` for available options.
|
||||
|
||||
More tips can be found on [the wiki page](https://github.com/junegunn/fzf/wiki/Configuring-shell-key-bindings).
|
||||
|
||||
Fuzzy completion for bash and zsh
|
||||
---------------------------------
|
||||
|
||||
#### Files and directories
|
||||
|
||||
Fuzzy completion for files and directories can be triggered if the word before
|
||||
the cursor ends with the trigger sequence which is by default `**`.
|
||||
|
||||
- `COMMAND [DIRECTORY/][FUZZY_PATTERN]**<TAB>`
|
||||
|
||||
```sh
|
||||
# Files under current directory
|
||||
# - You can select multiple items with TAB key
|
||||
vim **<TAB>
|
||||
|
||||
# Files under parent directory
|
||||
vim ../**<TAB>
|
||||
|
||||
# Files under parent directory that match `fzf`
|
||||
vim ../fzf**<TAB>
|
||||
|
||||
# Files under your home directory
|
||||
vim ~/**<TAB>
|
||||
|
||||
|
||||
# Directories under current directory (single-selection)
|
||||
cd **<TAB>
|
||||
|
||||
# Directories under ~/github that match `fzf`
|
||||
cd ~/github/fzf**<TAB>
|
||||
```
|
||||
|
||||
#### Process IDs
|
||||
|
||||
Fuzzy completion for PIDs is provided for kill command. In this case,
|
||||
there is no trigger sequence, just press tab key after kill command.
|
||||
|
||||
```sh
|
||||
# Can select multiple processes with <TAB> or <Shift-TAB> keys
|
||||
kill -9 <TAB>
|
||||
```
|
||||
|
||||
#### Host names
|
||||
|
||||
For ssh and telnet commands, fuzzy completion for host names is provided. The
|
||||
names are extracted from /etc/hosts and ~/.ssh/config.
|
||||
|
||||
```sh
|
||||
ssh **<TAB>
|
||||
telnet **<TAB>
|
||||
```
|
||||
|
||||
#### Environment variables / Aliases
|
||||
|
||||
```sh
|
||||
unset **<TAB>
|
||||
export **<TAB>
|
||||
unalias **<TAB>
|
||||
```
|
||||
|
||||
#### Settings
|
||||
|
||||
```sh
|
||||
# Use ~~ as the trigger sequence instead of the default **
|
||||
export FZF_COMPLETION_TRIGGER='~~'
|
||||
|
||||
# Options to fzf command
|
||||
export FZF_COMPLETION_OPTS='+c -x'
|
||||
|
||||
# Use fd (https://github.com/sharkdp/fd) instead of the default find
|
||||
# command for listing path candidates.
|
||||
# - The first argument to the function ($1) is the base path to start traversal
|
||||
# - See the source code (completion.{bash,zsh}) for the details.
|
||||
_fzf_compgen_path() {
|
||||
fd --hidden --follow --exclude ".git" . "$1"
|
||||
}
|
||||
|
||||
# Use fd to generate the list for directory completion
|
||||
_fzf_compgen_dir() {
|
||||
fd --type d --hidden --follow --exclude ".git" . "$1"
|
||||
}
|
||||
|
||||
# (EXPERIMENTAL) Advanced customization of fzf options via _fzf_comprun function
|
||||
# - The first argument to the function is the name of the command.
|
||||
# - You should make sure to pass the rest of the arguments to fzf.
|
||||
_fzf_comprun() {
|
||||
local command=$1
|
||||
shift
|
||||
|
||||
case "$command" in
|
||||
cd) fzf "$@" --preview 'tree -C {} | head -200' ;;
|
||||
export|unset) fzf "$@" --preview "eval 'echo \$'{}" ;;
|
||||
ssh) fzf "$@" --preview 'dig {}' ;;
|
||||
*) fzf "$@" ;;
|
||||
esac
|
||||
}
|
||||
```
|
||||
|
||||
#### Supported commands
|
||||
|
||||
On bash, fuzzy completion is enabled only for a predefined set of commands
|
||||
(`complete | grep _fzf` to see the list). But you can enable it for other
|
||||
commands as well by using `_fzf_setup_completion` helper function.
|
||||
|
||||
```sh
|
||||
# usage: _fzf_setup_completion path|dir|var|alias|host COMMANDS...
|
||||
_fzf_setup_completion path ag git kubectl
|
||||
_fzf_setup_completion dir tree
|
||||
```
|
||||
|
||||
#### Custom fuzzy completion
|
||||
|
||||
_**(Custom completion API is experimental and subject to change)**_
|
||||
|
||||
For a command named _"COMMAND"_, define `_fzf_complete_COMMAND` function using
|
||||
`_fzf_complete` helper.
|
||||
|
||||
```sh
|
||||
# Custom fuzzy completion for "doge" command
|
||||
# e.g. doge **<TAB>
|
||||
_fzf_complete_doge() {
|
||||
_fzf_complete --multi --reverse --prompt="doge> " -- "$@" < <(
|
||||
echo very
|
||||
echo wow
|
||||
echo such
|
||||
echo doge
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
- The arguments before `--` are the options to fzf.
|
||||
- After `--`, simply pass the original completion arguments unchanged (`"$@"`).
|
||||
- Then write a set of commands that generates the completion candidates and
|
||||
feed its output to the function using process substitution (`< <(...)`).
|
||||
|
||||
zsh will automatically pick up the function using the naming convention but in
|
||||
bash you have to manually associate the function with the command using
|
||||
`complete` command.
|
||||
|
||||
```sh
|
||||
[ -n "$BASH" ] && complete -F _fzf_complete_doge -o default -o bashdefault doge
|
||||
```
|
||||
|
||||
If you need to post-process the output from fzf, define
|
||||
`_fzf_complete_COMMAND_post` as follows.
|
||||
|
||||
```sh
|
||||
_fzf_complete_foo() {
|
||||
_fzf_complete --multi --reverse --header-lines=3 -- "$@" < <(
|
||||
ls -al
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_foo_post() {
|
||||
awk '{print $NF}'
|
||||
}
|
||||
|
||||
[ -n "$BASH" ] && complete -F _fzf_complete_foo -o default -o bashdefault foo
|
||||
```
|
||||
|
||||
Vim plugin
|
||||
----------
|
||||
|
||||
See [README-VIM.md](README-VIM.md).
|
||||
|
||||
Advanced topics
|
||||
---------------
|
||||
|
||||
### Performance
|
||||
|
||||
fzf is fast and is [getting even faster][perf]. Performance should not be
|
||||
a problem in most use cases. However, you might want to be aware of the
|
||||
options that affect the performance.
|
||||
|
||||
- `--ansi` tells fzf to extract and parse ANSI color codes in the input and it
|
||||
makes the initial scanning slower. So it's not recommended that you add it
|
||||
to your `$FZF_DEFAULT_OPTS`.
|
||||
- `--nth` makes fzf slower as fzf has to tokenize each line.
|
||||
- `--with-nth` makes fzf slower as fzf has to tokenize and reassemble each
|
||||
line.
|
||||
- If you absolutely need better performance, you can consider using
|
||||
`--algo=v1` (the default being `v2`) to make fzf use a faster greedy
|
||||
algorithm. However, this algorithm is not guaranteed to find the optimal
|
||||
ordering of the matches and is not recommended.
|
||||
|
||||
[perf]: https://junegunn.kr/images/fzf-0.17.0.png
|
||||
|
||||
### Executing external programs
|
||||
|
||||
You can set up key bindings for starting external processes without leaving
|
||||
fzf (`execute`, `execute-silent`).
|
||||
|
||||
```bash
|
||||
# Press F1 to open the file with less without leaving fzf
|
||||
# Press CTRL-Y to copy the line to clipboard and aborts fzf (requires pbcopy)
|
||||
fzf --bind 'f1:execute(less -f {}),ctrl-y:execute-silent(echo {} | pbcopy)+abort'
|
||||
```
|
||||
|
||||
See *KEY BINDINGS* section of the man page for details.
|
||||
|
||||
### Preview window
|
||||
|
||||
When `--preview` option is set, fzf automatically starts an external process with
|
||||
the current line as the argument and shows the result in the split window. Your
|
||||
`$SHELL` is used to execute the command with `$SHELL -c COMMAND`.
|
||||
|
||||
```bash
|
||||
# {} is replaced to the single-quoted string of the focused line
|
||||
fzf --preview 'cat {}'
|
||||
```
|
||||
|
||||
Since the preview window is updated only after the process is complete, it's
|
||||
important that the command finishes quickly.
|
||||
|
||||
```bash
|
||||
# Use head instead of cat so that the command doesn't take too long to finish
|
||||
fzf --preview 'head -100 {}'
|
||||
```
|
||||
|
||||
Preview window supports ANSI colors, so you can use any program that
|
||||
syntax-highlights the content of a file.
|
||||
|
||||
- Bat: https://github.com/sharkdp/bat
|
||||
- Highlight: http://www.andre-simon.de/doku/highlight/en/highlight.php
|
||||
|
||||
```bash
|
||||
fzf --preview 'bat --style=numbers --color=always {} | head -500'
|
||||
```
|
||||
|
||||
You can customize the size, position, and border of the preview window using
|
||||
`--preview-window` option, and the foreground and background color of it with
|
||||
`--color` option. For example,
|
||||
|
||||
```bash
|
||||
fzf --height 40% --layout reverse --info inline --border \
|
||||
--preview 'file {}' --preview-window down:1:noborder \
|
||||
--color 'fg:#bbccdd,fg+:#ddeeff,bg:#334455,preview-bg:#223344,border:#778899'
|
||||
```
|
||||
|
||||
See the man page (`man fzf`) for the full list of options.
|
||||
|
||||
For more advanced examples, see [Key bindings for git with fzf][fzf-git]
|
||||
([code](https://gist.github.com/junegunn/8b572b8d4b5eddd8b85e5f4d40f17236)).
|
||||
|
||||
[fzf-git]: https://junegunn.kr/2016/07/fzf-git/
|
||||
|
||||
----
|
||||
|
||||
Since fzf is a general-purpose text filter rather than a file finder, **it is
|
||||
not a good idea to add `--preview` option to your `$FZF_DEFAULT_OPTS`**.
|
||||
|
||||
```sh
|
||||
# *********************
|
||||
# ** DO NOT DO THIS! **
|
||||
# *********************
|
||||
export FZF_DEFAULT_OPTS='--preview "bat --style=numbers --color=always {} | head -500"'
|
||||
|
||||
# bat doesn't work with any input other than the list of files
|
||||
ps -ef | fzf
|
||||
seq 100 | fzf
|
||||
history | fzf
|
||||
```
|
||||
|
||||
Tips
|
||||
----
|
||||
|
||||
#### Respecting `.gitignore`
|
||||
|
||||
You can use [fd](https://github.com/sharkdp/fd),
|
||||
[ripgrep](https://github.com/BurntSushi/ripgrep), or [the silver
|
||||
searcher](https://github.com/ggreer/the_silver_searcher) instead of the
|
||||
default find command to traverse the file system while respecting
|
||||
`.gitignore`.
|
||||
|
||||
```sh
|
||||
# Feed the output of fd into fzf
|
||||
fd --type f | fzf
|
||||
|
||||
# Setting fd as the default source for fzf
|
||||
export FZF_DEFAULT_COMMAND='fd --type f'
|
||||
|
||||
# Now fzf (w/o pipe) will use fd instead of find
|
||||
fzf
|
||||
|
||||
# To apply the command to CTRL-T as well
|
||||
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
|
||||
```
|
||||
|
||||
If you want the command to follow symbolic links, and don't want it to exclude
|
||||
hidden files, use the following command:
|
||||
|
||||
```sh
|
||||
export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git'
|
||||
```
|
||||
|
||||
#### Fish shell
|
||||
|
||||
`CTRL-T` key binding of fish, unlike those of bash and zsh, will use the last
|
||||
token on the command-line as the root directory for the recursive search. For
|
||||
instance, hitting `CTRL-T` at the end of the following command-line
|
||||
|
||||
```sh
|
||||
ls /var/
|
||||
```
|
||||
|
||||
will list all files and directories under `/var/`.
|
||||
|
||||
When using a custom `FZF_CTRL_T_COMMAND`, use the unexpanded `$dir` variable to
|
||||
make use of this feature. `$dir` defaults to `.` when the last token is not a
|
||||
valid directory. Example:
|
||||
|
||||
```sh
|
||||
set -g FZF_CTRL_T_COMMAND "command find -L \$dir -type f 2> /dev/null | sed '1d; s#^\./##'"
|
||||
```
|
||||
|
||||
Related projects
|
||||
----------------
|
||||
|
||||
https://github.com/junegunn/fzf/wiki/Related-projects
|
||||
|
||||
[License](LICENSE)
|
||||
------------------
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Junegunn Choi
|
||||
Executable
+236
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env bash
|
||||
# fzf-tmux: starts fzf in a tmux pane
|
||||
# usage: fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
|
||||
|
||||
fail() {
|
||||
>&2 echo "$1"
|
||||
exit 2
|
||||
}
|
||||
|
||||
fzf="$(command -v fzf 2> /dev/null)" || fzf="$(dirname "$0")/fzf"
|
||||
[[ -x "$fzf" ]] || fail 'fzf executable not found'
|
||||
|
||||
tmux_args=()
|
||||
args=()
|
||||
opt=""
|
||||
skip=""
|
||||
swap=""
|
||||
close=""
|
||||
term=""
|
||||
[[ -n "$LINES" ]] && lines=$LINES || lines=$(tput lines) || lines=$(tmux display-message -p "#{pane_height}")
|
||||
[[ -n "$COLUMNS" ]] && columns=$COLUMNS || columns=$(tput cols) || columns=$(tmux display-message -p "#{pane_width}")
|
||||
|
||||
help() {
|
||||
>&2 echo 'usage: fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
|
||||
|
||||
LAYOUT OPTIONS:
|
||||
(default layout: -d 50%)
|
||||
|
||||
Popup window (requires tmux 3.2 or above):
|
||||
-p [WIDTH[%][,HEIGHT[%]]] (default: 50%)
|
||||
-w WIDTH[%]
|
||||
-h HEIGHT[%]
|
||||
-x COL
|
||||
-y ROW
|
||||
|
||||
Split pane:
|
||||
-u [HEIGHT[%]] Split above (up)
|
||||
-d [HEIGHT[%]] Split below (down)
|
||||
-l [WIDTH[%]] Split left
|
||||
-r [WIDTH[%]] Split right
|
||||
'
|
||||
exit
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
arg="$1"
|
||||
shift
|
||||
[[ -z "$skip" ]] && case "$arg" in
|
||||
-)
|
||||
term=1
|
||||
;;
|
||||
--help)
|
||||
help
|
||||
;;
|
||||
--version)
|
||||
echo "fzf-tmux (with fzf $("$fzf" --version))"
|
||||
exit
|
||||
;;
|
||||
-p*|-w*|-h*|-x*|-y*|-d*|-u*|-r*|-l*)
|
||||
if [[ "$arg" =~ ^-[pwhxy] ]]; then
|
||||
[[ "$opt" =~ "-K -E" ]] || opt="-K -E"
|
||||
elif [[ "$arg" =~ ^.[lr] ]]; then
|
||||
opt="-h"
|
||||
if [[ "$arg" =~ ^.l ]]; then
|
||||
opt="$opt -d"
|
||||
swap="; swap-pane -D ; select-pane -L"
|
||||
close="; tmux swap-pane -D"
|
||||
fi
|
||||
else
|
||||
opt=""
|
||||
if [[ "$arg" =~ ^.u ]]; then
|
||||
opt="$opt -d"
|
||||
swap="; swap-pane -D ; select-pane -U"
|
||||
close="; tmux swap-pane -D"
|
||||
fi
|
||||
fi
|
||||
if [[ ${#arg} -gt 2 ]]; then
|
||||
size="${arg:2}"
|
||||
else
|
||||
if [[ "$1" =~ ^[0-9%,]+$ ]] || [[ "$1" =~ ^[A-Z]$ ]]; then
|
||||
size="$1"
|
||||
shift
|
||||
else
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$arg" =~ ^-p ]]; then
|
||||
if [[ -n "$size" ]]; then
|
||||
w=${size%%,*}
|
||||
h=${size##*,}
|
||||
opt="$opt -w$w -h$h"
|
||||
fi
|
||||
elif [[ "$arg" =~ ^-[whxy] ]]; then
|
||||
opt="$opt ${arg:0:2}$size"
|
||||
elif [[ "$size" =~ %$ ]]; then
|
||||
size=${size:0:((${#size}-1))}
|
||||
if [[ -n "$swap" ]]; then
|
||||
opt="$opt -p $(( 100 - size ))"
|
||||
else
|
||||
opt="$opt -p $size"
|
||||
fi
|
||||
else
|
||||
if [[ -n "$swap" ]]; then
|
||||
if [[ "$arg" =~ ^.l ]]; then
|
||||
max=$columns
|
||||
else
|
||||
max=$lines
|
||||
fi
|
||||
size=$(( max - size ))
|
||||
[[ $size -lt 0 ]] && size=0
|
||||
opt="$opt -l $size"
|
||||
else
|
||||
opt="$opt -l $size"
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
--)
|
||||
# "--" can be used to separate fzf-tmux options from fzf options to
|
||||
# avoid conflicts
|
||||
skip=1
|
||||
tmux_args=("${args[@]}")
|
||||
args=()
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
args+=("$arg")
|
||||
;;
|
||||
esac
|
||||
[[ -n "$skip" ]] && args+=("$arg")
|
||||
done
|
||||
|
||||
if [[ -z "$TMUX" ]]; then
|
||||
"$fzf" "${args[@]}"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# --height option is not allowed
|
||||
args=("--no-height" "${args[@]}")
|
||||
|
||||
# Handle zoomed tmux pane by moving it to a temp window
|
||||
if tmux list-panes -F '#F' | grep -q Z; then
|
||||
zoomed=1
|
||||
original_window=$(tmux display-message -p "#{window_id}")
|
||||
tmp_window=$(tmux new-window -d -P -F "#{window_id}" "bash -c 'while :; do for c in \\| / - '\\;' do sleep 0.2; printf \"\\r\$c fzf-tmux is running\\r\"; done; done'")
|
||||
tmux swap-pane -t $tmp_window \; select-window -t $tmp_window
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
# Clean up named pipes on exit
|
||||
id=$RANDOM
|
||||
argsf="${TMPDIR:-/tmp}/fzf-args-$id"
|
||||
fifo1="${TMPDIR:-/tmp}/fzf-fifo1-$id"
|
||||
fifo2="${TMPDIR:-/tmp}/fzf-fifo2-$id"
|
||||
fifo3="${TMPDIR:-/tmp}/fzf-fifo3-$id"
|
||||
cleanup() {
|
||||
\rm -f $argsf $fifo1 $fifo2 $fifo3
|
||||
|
||||
# Restore tmux window options
|
||||
if [[ "${#tmux_win_opts[@]}" -gt 0 ]]; then
|
||||
eval "tmux ${tmux_win_opts[@]}"
|
||||
fi
|
||||
|
||||
# Remove temp window if we were zoomed
|
||||
if [[ -n "$zoomed" ]]; then
|
||||
tmux display-message -p "#{window_id}" > /dev/null
|
||||
tmux swap-pane -t $original_window \; \
|
||||
select-window -t $original_window \; \
|
||||
kill-window -t $tmp_window \; \
|
||||
resize-pane -Z
|
||||
fi
|
||||
|
||||
if [ $# -gt 0 ]; then
|
||||
trap - EXIT
|
||||
exit 130
|
||||
fi
|
||||
}
|
||||
trap 'cleanup 1' SIGUSR1
|
||||
trap 'cleanup' EXIT
|
||||
|
||||
envs="env TERM=$TERM "
|
||||
[[ "$opt" =~ "-K -E" ]] && FZF_DEFAULT_OPTS="--margin 0,1 $FZF_DEFAULT_OPTS"
|
||||
[[ -n "$FZF_DEFAULT_OPTS" ]] && envs="$envs FZF_DEFAULT_OPTS=$(printf %q "$FZF_DEFAULT_OPTS")"
|
||||
[[ -n "$FZF_DEFAULT_COMMAND" ]] && envs="$envs FZF_DEFAULT_COMMAND=$(printf %q "$FZF_DEFAULT_COMMAND")"
|
||||
|
||||
mkfifo -m o+w $fifo2
|
||||
mkfifo -m o+w $fifo3
|
||||
|
||||
# Build arguments to fzf
|
||||
opts=""
|
||||
for arg in "${args[@]}"; do
|
||||
arg="${arg//\\/\\\\}"
|
||||
arg="${arg//\"/\\\"}"
|
||||
arg="${arg//\`/\\\`}"
|
||||
arg="${arg//$/\\$}"
|
||||
opts="$opts \"$arg\""
|
||||
done
|
||||
|
||||
pppid=$$
|
||||
echo -n "trap 'kill -SIGUSR1 -$pppid' EXIT SIGINT SIGTERM;" > $argsf
|
||||
close="; trap - EXIT SIGINT SIGTERM $close"
|
||||
|
||||
tmux_win_opts=( $(tmux show-window-options remain-on-exit \; show-window-options synchronize-panes | sed '/ off/d; s/^/set-window-option /; s/$/ \\;/') )
|
||||
|
||||
if [[ "$opt" =~ "-K -E" ]]; then
|
||||
cat $fifo2 &
|
||||
if [[ -n "$term" ]] || [[ -t 0 ]]; then
|
||||
cat <<< "\"$fzf\" $opts > $fifo2; out=\$? $close; exit \$out" >> $argsf
|
||||
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux popup -d "$PWD" "${tmux_args[@]}" $opt -R "$envs bash $argsf" > /dev/null 2>&1
|
||||
else
|
||||
mkfifo $fifo1
|
||||
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; out=\$? $close; exit \$out" >> $argsf
|
||||
cat <&0 > $fifo1 &
|
||||
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux popup -d "$PWD" "${tmux_args[@]}" $opt -R "$envs bash $argsf" > /dev/null 2>&1
|
||||
fi
|
||||
exit $?
|
||||
fi
|
||||
|
||||
if [[ -n "$term" ]] || [[ -t 0 ]]; then
|
||||
cat <<< "\"$fzf\" $opts > $fifo2; echo \$? > $fifo3 $close" >> $argsf
|
||||
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux set-window-option synchronize-panes off \;\
|
||||
set-window-option remain-on-exit off \;\
|
||||
split-window $opt "${tmux_args[@]}" "$envs bash -c 'cd $(printf %q "$PWD"); exec -a fzf bash $argsf'" $swap \
|
||||
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
|
||||
else
|
||||
mkfifo $fifo1
|
||||
cat <<< "\"$fzf\" $opts < $fifo1 > $fifo2; echo \$? > $fifo3 $close" >> $argsf
|
||||
TMUX=$(echo $TMUX | cut -d , -f 1,2) tmux set-window-option synchronize-panes off \;\
|
||||
set-window-option remain-on-exit off \;\
|
||||
split-window $opt "${tmux_args[@]}" "$envs bash -c 'exec -a fzf bash $argsf'" $swap \
|
||||
> /dev/null 2>&1 || { "$fzf" "${args[@]}"; exit $?; }
|
||||
cat <&0 > $fifo1 &
|
||||
fi
|
||||
cat $fifo2
|
||||
exit "$(cat $fifo3)"
|
||||
@@ -0,0 +1,447 @@
|
||||
fzf.txt fzf Last change: April 4 2020
|
||||
FZF - TABLE OF CONTENTS *fzf* *fzf-toc*
|
||||
==============================================================================
|
||||
|
||||
FZF Vim integration
|
||||
Installation
|
||||
Summary
|
||||
:FZF[!]
|
||||
Configuration
|
||||
Examples
|
||||
Explanation of g:fzf_colors
|
||||
fzf#run
|
||||
fzf#wrap
|
||||
Tips
|
||||
fzf inside terminal buffer
|
||||
Starting fzf in a popup window
|
||||
Hide statusline
|
||||
License
|
||||
|
||||
FZF VIM INTEGRATION *fzf-vim-integration*
|
||||
==============================================================================
|
||||
|
||||
|
||||
INSTALLATION *fzf-installation*
|
||||
==============================================================================
|
||||
|
||||
Once you have fzf installed, you can enable it inside Vim simply by adding the
|
||||
directory to 'runtimepath' in your Vim configuration file. The path may differ
|
||||
depending on the package manager.
|
||||
>
|
||||
" If installed using Homebrew
|
||||
set rtp+=/usr/local/opt/fzf
|
||||
|
||||
" If installed using git
|
||||
set rtp+=~/.fzf
|
||||
<
|
||||
If you use {vim-plug}{1}, the same can be written as:
|
||||
>
|
||||
" If installed using Homebrew
|
||||
Plug '/usr/local/opt/fzf'
|
||||
|
||||
" If installed using git
|
||||
Plug '~/.fzf'
|
||||
<
|
||||
But if you want the latest Vim plugin file from GitHub rather than the one
|
||||
included in the package, write:
|
||||
>
|
||||
Plug 'junegunn/fzf'
|
||||
<
|
||||
The Vim plugin will pick up fzf binary available on the system. If fzf is not
|
||||
found on `$PATH`, it will ask you if it should download the latest binary for
|
||||
you.
|
||||
|
||||
To make sure that you have the latest version of the binary, set up
|
||||
post-update hook like so:
|
||||
|
||||
*fzf#install*
|
||||
>
|
||||
Plug 'junegunn/fzf', { 'do': { -> fzf#install() } }
|
||||
<
|
||||
{1} https://github.com/junegunn/vim-plug
|
||||
|
||||
|
||||
SUMMARY *fzf-summary*
|
||||
==============================================================================
|
||||
|
||||
The Vim plugin of fzf provides two core functions, and `:FZF` command which is
|
||||
the basic file selector command built on top of them.
|
||||
|
||||
1. `fzf#run([spec dict])`
|
||||
- Starts fzf inside Vim with the given spec
|
||||
- `:call fzf#run({'source': 'ls'})`
|
||||
2. `fzf#wrap([spec dict]) -> (dict)`
|
||||
- Takes a spec for `fzf#run` and returns an extended version of it with
|
||||
additional options for addressing global preferences (`g:fzf_xxx`)
|
||||
- `:echo fzf#wrap({'source': 'ls'})`
|
||||
- We usually wrap a spec with `fzf#wrap` before passing it to `fzf#run`
|
||||
- `:call fzf#run(fzf#wrap({'source': 'ls'}))`
|
||||
3. `:FZF [fzf_options string] [path string]`
|
||||
- Basic fuzzy file selector
|
||||
- A reference implementation for those who don't want to write VimScript to
|
||||
implement custom commands
|
||||
- If you're looking for more such commands, check out {fzf.vim}{2} project.
|
||||
|
||||
The most important of all is `fzf#run`, but it would be easier to understand
|
||||
the whole if we start off with `:FZF` command.
|
||||
|
||||
{2} https://github.com/junegunn/fzf.vim
|
||||
|
||||
|
||||
:FZF[!]
|
||||
==============================================================================
|
||||
|
||||
*:FZF*
|
||||
>
|
||||
" Look for files under current directory
|
||||
:FZF
|
||||
|
||||
" Look for files under your home directory
|
||||
:FZF ~
|
||||
|
||||
" With fzf command-line options
|
||||
:FZF --reverse --info=inline /tmp
|
||||
|
||||
" Bang version starts fzf in fullscreen mode
|
||||
:FZF!
|
||||
<
|
||||
Similarly to {ctrlp.vim}{2}, use enter key, CTRL-T, CTRL-X or CTRL-V to open
|
||||
selected files in the current window, in new tabs, in horizontal splits, or in
|
||||
vertical splits respectively.
|
||||
|
||||
Note that the environment variables `FZF_DEFAULT_COMMAND` and
|
||||
`FZF_DEFAULT_OPTS` also apply here.
|
||||
|
||||
{2} https://github.com/kien/ctrlp.vim
|
||||
|
||||
|
||||
< Configuration >_____________________________________________________________~
|
||||
*fzf-configuration*
|
||||
|
||||
*g:fzf_action* *g:fzf_layout* *g:fzf_colors* *g:fzf_history_dir*
|
||||
|
||||
- `g:fzf_action`
|
||||
- Customizable extra key bindings for opening selected files in different
|
||||
ways
|
||||
- `g:fzf_layout`
|
||||
- Determines the size and position of fzf window
|
||||
- `g:fzf_colors`
|
||||
- Customizes fzf colors to match the current color scheme
|
||||
- `g:fzf_history_dir`
|
||||
- Enables history feature
|
||||
|
||||
|
||||
Examples~
|
||||
*fzf-examples*
|
||||
>
|
||||
" This is the default extra key bindings
|
||||
let g:fzf_action = {
|
||||
\ 'ctrl-t': 'tab split',
|
||||
\ 'ctrl-x': 'split',
|
||||
\ 'ctrl-v': 'vsplit' }
|
||||
|
||||
" An action can be a reference to a function that processes selected lines
|
||||
function! s:build_quickfix_list(lines)
|
||||
call setqflist(map(copy(a:lines), '{ "filename": v:val }'))
|
||||
copen
|
||||
cc
|
||||
endfunction
|
||||
|
||||
let g:fzf_action = {
|
||||
\ 'ctrl-q': function('s:build_quickfix_list'),
|
||||
\ 'ctrl-t': 'tab split',
|
||||
\ 'ctrl-x': 'split',
|
||||
\ 'ctrl-v': 'vsplit' }
|
||||
|
||||
" Default fzf layout
|
||||
" - down / up / left / right
|
||||
let g:fzf_layout = { 'down': '~40%' }
|
||||
|
||||
" You can set up fzf window using a Vim command (Neovim or latest Vim 8 required)
|
||||
let g:fzf_layout = { 'window': 'enew' }
|
||||
let g:fzf_layout = { 'window': '-tabnew' }
|
||||
let g:fzf_layout = { 'window': '10new' }
|
||||
|
||||
" Customize fzf colors to match your color scheme
|
||||
" - fzf#wrap translates this to a set of `--color` options
|
||||
let g:fzf_colors =
|
||||
\ { 'fg': ['fg', 'Normal'],
|
||||
\ 'bg': ['bg', 'Normal'],
|
||||
\ 'hl': ['fg', 'Comment'],
|
||||
\ 'fg+': ['fg', 'CursorLine', 'CursorColumn', 'Normal'],
|
||||
\ 'bg+': ['bg', 'CursorLine', 'CursorColumn'],
|
||||
\ 'hl+': ['fg', 'Statement'],
|
||||
\ 'info': ['fg', 'PreProc'],
|
||||
\ 'border': ['fg', 'Ignore'],
|
||||
\ 'prompt': ['fg', 'Conditional'],
|
||||
\ 'pointer': ['fg', 'Exception'],
|
||||
\ 'marker': ['fg', 'Keyword'],
|
||||
\ 'spinner': ['fg', 'Label'],
|
||||
\ 'header': ['fg', 'Comment'] }
|
||||
|
||||
" Enable per-command history
|
||||
" - History files will be stored in the specified directory
|
||||
" - When set, CTRL-N and CTRL-P will be bound to 'next-history' and
|
||||
" 'previous-history' instead of 'down' and 'up'.
|
||||
let g:fzf_history_dir = '~/.local/share/fzf-history'
|
||||
<
|
||||
|
||||
Explanation of g:fzf_colors~
|
||||
*fzf-explanation-of-gfzfcolors*
|
||||
|
||||
`g:fzf_colors` is a dictionary mapping fzf elements to a color specification
|
||||
list:
|
||||
>
|
||||
element: [ component, group1 [, group2, ...] ]
|
||||
<
|
||||
- `element` is an fzf element to apply a color to:
|
||||
|
||||
----------------------+------------------------------------------------------
|
||||
Element | Description ~
|
||||
----------------------+------------------------------------------------------
|
||||
`fg` / `bg` / `hl` | Item (foreground / background / highlight)
|
||||
`fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight)
|
||||
`hl` / `hl+` | Highlighted substrings (normal / current)
|
||||
`gutter` | Background of the gutter on the left
|
||||
`pointer` | Pointer to the current line ( `>` )
|
||||
`marker` | Multi-select marker ( `>` )
|
||||
`border` | Border around the window ( `--border` and `--preview` )
|
||||
`header` | Header ( `--header` or `--header-lines` )
|
||||
`info` | Info line (match counters)
|
||||
`spinner` | Streaming input indicator
|
||||
`prompt` | Prompt before query ( `> ` )
|
||||
----------------------+------------------------------------------------------
|
||||
- `component` specifies the component (`fg` / `bg`) from which to extract the
|
||||
color when considering each of the following highlight groups
|
||||
- `group1 [, group2, ...]` is a list of highlight groups that are searched (in
|
||||
order) for a matching color definition
|
||||
|
||||
For example, consider the following specification:
|
||||
>
|
||||
'prompt': ['fg', 'Conditional', 'Comment'],
|
||||
<
|
||||
This means we color the prompt - using the `fg` attribute of the `Conditional`
|
||||
if it exists, - otherwise use the `fg` attribute of the `Comment` highlight
|
||||
group if it exists, - otherwise fall back to the default color settings for
|
||||
the prompt.
|
||||
|
||||
You can examine the color option generated according the setting by printing
|
||||
the result of `fzf#wrap()` function like so:
|
||||
>
|
||||
:echo fzf#wrap()
|
||||
<
|
||||
|
||||
FZF#RUN
|
||||
==============================================================================
|
||||
|
||||
*fzf#run*
|
||||
|
||||
`fzf#run()` function is the core of Vim integration. It takes a single
|
||||
dictionary argument, a spec, and starts fzf process accordingly. At the very
|
||||
least, specify `sink` option to tell what it should do with the selected
|
||||
entry.
|
||||
>
|
||||
call fzf#run({'sink': 'e'})
|
||||
<
|
||||
We haven't specified the `source`, so this is equivalent to starting fzf on
|
||||
command line without standard input pipe; fzf will use find command (or
|
||||
`$FZF_DEFAULT_COMMAND` if defined) to list the files under the current
|
||||
directory. When you select one, it will open it with the sink, `:e` command.
|
||||
If you want to open it in a new tab, you can pass `:tabedit` command instead
|
||||
as the sink.
|
||||
>
|
||||
call fzf#run({'sink': 'tabedit'})
|
||||
<
|
||||
Instead of using the default find command, you can use any shell command as
|
||||
the source. The following example will list the files managed by git. It's
|
||||
equivalent to running `git ls-files | fzf` on shell.
|
||||
>
|
||||
call fzf#run({'source': 'git ls-files', 'sink': 'e'})
|
||||
<
|
||||
fzf options can be specified as `options` entry in spec dictionary.
|
||||
>
|
||||
call fzf#run({'sink': 'tabedit', 'options': '--multi --reverse'})
|
||||
<
|
||||
You can also pass a layout option if you don't want fzf window to take up the
|
||||
entire screen.
|
||||
>
|
||||
" up / down / left / right / window are allowed
|
||||
call fzf#run({'source': 'git ls-files', 'sink': 'e', 'left': '40%'})
|
||||
call fzf#run({'source': 'git ls-files', 'sink': 'e', 'window': '30vnew'})
|
||||
<
|
||||
`source` doesn't have to be an external shell command, you can pass a Vim
|
||||
array as the source. In the next example, we pass the names of color schemes
|
||||
as the source to implement a color scheme selector.
|
||||
>
|
||||
call fzf#run({'source': map(split(globpath(&rtp, 'colors/*.vim')),
|
||||
\ 'fnamemodify(v:val, ":t:r")'),
|
||||
\ 'sink': 'colo', 'left': '25%'})
|
||||
<
|
||||
The following table summarizes the available options.
|
||||
|
||||
---------------------------+---------------+----------------------------------------------------------------------
|
||||
Option name | Type | Description ~
|
||||
---------------------------+---------------+----------------------------------------------------------------------
|
||||
`source` | string | External command to generate input to fzf (e.g. `find .` )
|
||||
`source` | list | Vim list as input to fzf
|
||||
`sink` | string | Vim command to handle the selected item (e.g. `e` , `tabe` )
|
||||
`sink` | funcref | Reference to function to process each selected item
|
||||
`sink*` | funcref | Similar to `sink` , but takes the list of output lines at once
|
||||
`options` | string/list | Options to fzf
|
||||
`dir` | string | Working directory
|
||||
`up` / `down` / `left` / `right` | number/string | (Layout) Window position and size (e.g. `20` , `50%` )
|
||||
`tmux` | string | (Layout) fzf-tmux options (e.g. `-p90%,60%` )
|
||||
`window` (Vim 8 / Neovim) | string | (Layout) Command to open fzf window (e.g. `vertical aboveleft 30new` )
|
||||
`window` (Vim 8 / Neovim) | dict | (Layout) Popup window settings (e.g. `{'width': 0.9, 'height': 0.6}` )
|
||||
---------------------------+---------------+----------------------------------------------------------------------
|
||||
|
||||
`options` entry can be either a string or a list. For simple cases, string
|
||||
should suffice, but prefer to use list type to avoid escaping issues.
|
||||
>
|
||||
call fzf#run({'options': '--reverse --prompt "C:\\Program Files\\"'})
|
||||
call fzf#run({'options': ['--reverse', '--prompt', 'C:\Program Files\']})
|
||||
<
|
||||
When `window` entry is a dictionary, fzf will start in a popup window. The
|
||||
following options are allowed:
|
||||
|
||||
- Required:
|
||||
- `width` [float range [0 ~ 1]]
|
||||
- `height` [float range [0 ~ 1]]
|
||||
- Optional:
|
||||
- `yoffset` [float default 0.5 range [0 ~ 1]]
|
||||
- `xoffset` [float default 0.5 range [0 ~ 1]]
|
||||
- `highlight` [string default `'Comment'`]: Highlight group for border
|
||||
- `border` [string default `rounded`]: Border style
|
||||
- `rounded` / `sharp` / `horizontal` / `vertical` / `top` / `bottom` / `left` / `right`
|
||||
|
||||
|
||||
FZF#WRAP
|
||||
==============================================================================
|
||||
|
||||
*fzf#wrap*
|
||||
|
||||
We have seen that several aspects of `:FZF` command can be configured with a
|
||||
set of global option variables; different ways to open files (`g:fzf_action`),
|
||||
window position and size (`g:fzf_layout`), color palette (`g:fzf_colors`),
|
||||
etc.
|
||||
|
||||
So how can we make our custom `fzf#run` calls also respect those variables?
|
||||
Simply by "wrapping" the spec dictionary with `fzf#wrap` before passing it to
|
||||
`fzf#run`.
|
||||
|
||||
- `fzf#wrap([name string], [spec dict], [fullscreen bool]) -> (dict)`
|
||||
- All arguments are optional. Usually we only need to pass a spec
|
||||
dictionary.
|
||||
- `name` is for managing history files. It is ignored if `g:fzf_history_dir`
|
||||
is not defined.
|
||||
- `fullscreen` can be either `0` or `1` (default: 0).
|
||||
|
||||
`fzf#wrap` takes a spec and returns an extended version of it (also a
|
||||
dictionary) with additional options for addressing global preferences. You can
|
||||
examine the return value of it like so:
|
||||
>
|
||||
echo fzf#wrap({'source': 'ls'})
|
||||
<
|
||||
After we "wrap" our spec, we pass it to `fzf#run`.
|
||||
>
|
||||
call fzf#run(fzf#wrap({'source': 'ls'}))
|
||||
<
|
||||
Now it supports CTRL-T, CTRL-V, and CTRL-X key bindings and it opens fzf
|
||||
window according to `g:fzf_layout` setting.
|
||||
|
||||
To make it easier to use, let's define `LS` command.
|
||||
>
|
||||
command! LS call fzf#run(fzf#wrap({'source': 'ls'}))
|
||||
<
|
||||
Type `:LS` and see how it works.
|
||||
|
||||
We would like to make `:LS!` (bang version) open fzf in fullscreen, just like
|
||||
`:FZF!`. Add `-bang` to command definition, and use <bang> value to set the
|
||||
last `fullscreen` argument of `fzf#wrap` (see :help <bang>).
|
||||
>
|
||||
" On :LS!, <bang> evaluates to '!', and '!0' becomes 1
|
||||
command! -bang LS call fzf#run(fzf#wrap({'source': 'ls'}, <bang>0))
|
||||
<
|
||||
Our `:LS` command will be much more useful if we can pass a directory argument
|
||||
to it, so that something like `:LS /tmp` is possible.
|
||||
>
|
||||
command! -bang -complete=dir -nargs=* LS
|
||||
\ call fzf#run(fzf#wrap({'source': 'ls', 'dir': <q-args>}, <bang>0))
|
||||
<
|
||||
Lastly, if you have enabled `g:fzf_history_dir`, you might want to assign a
|
||||
unique name to our command and pass it as the first argument to `fzf#wrap`.
|
||||
>
|
||||
" The query history for this command will be stored as 'ls' inside g:fzf_history_dir.
|
||||
" The name is ignored if g:fzf_history_dir is not defined.
|
||||
command! -bang -complete=dir -nargs=* LS
|
||||
\ call fzf#run(fzf#wrap('ls', {'source': 'ls', 'dir': <q-args>}, <bang>0))
|
||||
<
|
||||
|
||||
TIPS *fzf-tips*
|
||||
==============================================================================
|
||||
|
||||
|
||||
< fzf inside terminal buffer >________________________________________________~
|
||||
*fzf-inside-terminal-buffer*
|
||||
|
||||
The latest versions of Vim and Neovim include builtin terminal emulator
|
||||
(`:terminal`) and fzf will start in a terminal buffer in the following cases:
|
||||
|
||||
- On Neovim
|
||||
- On GVim
|
||||
- On Terminal Vim with a non-default layout
|
||||
- `call fzf#run({'left': '30%'})` or `let g:fzf_layout = {'left': '30%'}`
|
||||
|
||||
|
||||
Starting fzf in a popup window~
|
||||
*fzf-starting-fzf-in-a-popup-window*
|
||||
>
|
||||
" Required:
|
||||
" - width [float range [0 ~ 1]]
|
||||
" - height [float range [0 ~ 1]]
|
||||
"
|
||||
" Optional:
|
||||
" - xoffset [float default 0.5 range [0 ~ 1]]
|
||||
" - yoffset [float default 0.5 range [0 ~ 1]]
|
||||
" - highlight [string default 'Comment']: Highlight group for border
|
||||
" - border [string default 'rounded']: Border style
|
||||
" - 'rounded' / 'sharp' / 'horizontal' / 'vertical' / 'top' / 'bottom' / 'left' / 'right'
|
||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||
<
|
||||
Alternatively, you can make fzf open in a tmux popup window (requires tmux 3.2
|
||||
or above) by putting fzf-tmux options in `tmux` key.
|
||||
>
|
||||
" See `man fzf-tmux` for available options
|
||||
if exists('$TMUX')
|
||||
let g:fzf_layout = { 'tmux': '-p90%,60%' }
|
||||
else
|
||||
let g:fzf_layout = { 'window': { 'width': 0.9, 'height': 0.6 } }
|
||||
endif
|
||||
<
|
||||
|
||||
Hide statusline~
|
||||
*fzf-hide-statusline*
|
||||
|
||||
When fzf starts in a terminal buffer, the file type of the buffer is set to
|
||||
`fzf`. So you can set up `FileType fzf` autocmd to customize the settings of
|
||||
the window.
|
||||
|
||||
For example, if you use the default layout (`{'down': '~40%'}`) on Neovim, you
|
||||
might want to temporarily disable the statusline for a cleaner look.
|
||||
>
|
||||
if has('nvim') && !exists('g:fzf_layout')
|
||||
autocmd! FileType fzf
|
||||
autocmd FileType fzf set laststatus=0 noshowmode noruler
|
||||
\| autocmd BufLeave <buffer> set laststatus=2 showmode ruler
|
||||
endif
|
||||
<
|
||||
|
||||
LICENSE *fzf-license*
|
||||
==============================================================================
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Junegunn Choi
|
||||
|
||||
==============================================================================
|
||||
vim:tw=78:sw=2:ts=2:ft=help:norl:nowrap:
|
||||
@@ -0,0 +1,21 @@
|
||||
:FZF fzf.txt /*:FZF*
|
||||
fzf fzf.txt /*fzf*
|
||||
fzf#install fzf.txt /*fzf#install*
|
||||
fzf#run fzf.txt /*fzf#run*
|
||||
fzf#wrap fzf.txt /*fzf#wrap*
|
||||
fzf-configuration fzf.txt /*fzf-configuration*
|
||||
fzf-examples fzf.txt /*fzf-examples*
|
||||
fzf-explanation-of-gfzfcolors fzf.txt /*fzf-explanation-of-gfzfcolors*
|
||||
fzf-hide-statusline fzf.txt /*fzf-hide-statusline*
|
||||
fzf-inside-terminal-buffer fzf.txt /*fzf-inside-terminal-buffer*
|
||||
fzf-installation fzf.txt /*fzf-installation*
|
||||
fzf-license fzf.txt /*fzf-license*
|
||||
fzf-starting-fzf-in-a-popup-window fzf.txt /*fzf-starting-fzf-in-a-popup-window*
|
||||
fzf-summary fzf.txt /*fzf-summary*
|
||||
fzf-tips fzf.txt /*fzf-tips*
|
||||
fzf-toc fzf.txt /*fzf-toc*
|
||||
fzf-vim-integration fzf.txt /*fzf-vim-integration*
|
||||
g:fzf_action fzf.txt /*g:fzf_action*
|
||||
g:fzf_colors fzf.txt /*g:fzf_colors*
|
||||
g:fzf_history_dir fzf.txt /*g:fzf_history_dir*
|
||||
g:fzf_layout fzf.txt /*g:fzf_layout*
|
||||
@@ -0,0 +1,68 @@
|
||||
.ig
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Junegunn Choi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf-tmux 1 "Apr 2020" "fzf 0.21.1" "fzf-tmux - open fzf in tmux split pane"
|
||||
|
||||
.SH NAME
|
||||
fzf-tmux - open fzf in tmux split pane
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B fzf-tmux [LAYOUT OPTIONS] [--] [FZF OPTIONS]
|
||||
|
||||
.SH DESCRIPTION
|
||||
fzf-tmux is a wrapper script for fzf that opens fzf in a tmux split pane or in
|
||||
a tmux popup window. It is designed to work just like fzf except that it does
|
||||
not take up the whole screen. You can safely use fzf-tmux instead of fzf in
|
||||
your scripts as the extra options will be silently ignored if you're not on
|
||||
tmux.
|
||||
|
||||
.SH LAYOUT OPTIONS
|
||||
|
||||
(default layout: \fB-d 50%\fR)
|
||||
|
||||
.SS Popup window
|
||||
(requires tmux 3.2 or above)
|
||||
.TP
|
||||
.B "-p [WIDTH[%][,HEIGHT[%]]]"
|
||||
.TP
|
||||
.B "-w WIDTH[%]"
|
||||
.TP
|
||||
.B "-h WIDTH[%]"
|
||||
.TP
|
||||
.B "-x COL"
|
||||
.TP
|
||||
.B "-y ROW"
|
||||
|
||||
.SS Split pane
|
||||
.TP
|
||||
.B "-u [height[%]]"
|
||||
Split above (up)
|
||||
.TP
|
||||
.B "-d [height[%]]"
|
||||
Split below (down)
|
||||
.TP
|
||||
.B "-l [width[%]]"
|
||||
Split left
|
||||
.TP
|
||||
.B "-r [width[%]]"
|
||||
Split right
|
||||
@@ -0,0 +1,791 @@
|
||||
.ig
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013-2020 Junegunn Choi
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
..
|
||||
.TH fzf 1 "Apr 2020" "fzf 0.21.1" "fzf - a command-line fuzzy finder"
|
||||
|
||||
.SH NAME
|
||||
fzf - a command-line fuzzy finder
|
||||
|
||||
.SH SYNOPSIS
|
||||
fzf [options]
|
||||
|
||||
.SH DESCRIPTION
|
||||
fzf is a general-purpose command-line fuzzy finder.
|
||||
|
||||
.SH OPTIONS
|
||||
.SS Search mode
|
||||
.TP
|
||||
.B "-x, --extended"
|
||||
Extended-search mode. Since 0.10.9, this is enabled by default. You can disable
|
||||
it with \fB+x\fR or \fB--no-extended\fR.
|
||||
.TP
|
||||
.B "-e, --exact"
|
||||
Enable exact-match
|
||||
.TP
|
||||
.B "-i"
|
||||
Case-insensitive match (default: smart-case match)
|
||||
.TP
|
||||
.B "+i"
|
||||
Case-sensitive match
|
||||
.TP
|
||||
.B "--literal"
|
||||
Do not normalize latin script letters for matching.
|
||||
.TP
|
||||
.BI "--algo=" TYPE
|
||||
Fuzzy matching algorithm (default: v2)
|
||||
|
||||
.br
|
||||
.BR v2 " Optimal scoring algorithm (quality)"
|
||||
.br
|
||||
.BR v1 " Faster but not guaranteed to find the optimal result (performance)"
|
||||
.br
|
||||
|
||||
.TP
|
||||
.BI "-n, --nth=" "N[,..]"
|
||||
Comma-separated list of field index expressions for limiting search scope.
|
||||
See \fBFIELD INDEX EXPRESSION\fR for the details.
|
||||
.TP
|
||||
.BI "--with-nth=" "N[,..]"
|
||||
Transform the presentation of each line using field index expressions
|
||||
.TP
|
||||
.BI "-d, --delimiter=" "STR"
|
||||
Field delimiter regex for \fB--nth\fR and \fB--with-nth\fR (default: AWK-style)
|
||||
.TP
|
||||
.BI "--phony"
|
||||
Do not perform search. With this option, fzf becomes a simple selector
|
||||
interface rather than a "fuzzy finder".
|
||||
.SS Search result
|
||||
.TP
|
||||
.B "+s, --no-sort"
|
||||
Do not sort the result
|
||||
.TP
|
||||
.B "--tac"
|
||||
Reverse the order of the input
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBhistory | fzf --tac --no-sort\fR
|
||||
.RE
|
||||
.TP
|
||||
.BI "--tiebreak=" "CRI[,..]"
|
||||
Comma-separated list of sort criteria to apply when the scores are tied.
|
||||
.br
|
||||
|
||||
.br
|
||||
.BR length " Prefers line with shorter length"
|
||||
.br
|
||||
.BR begin " Prefers line with matched substring closer to the beginning"
|
||||
.br
|
||||
.BR end " Prefers line with matched substring closer to the end"
|
||||
.br
|
||||
.BR index " Prefers line that appeared earlier in the input stream"
|
||||
.br
|
||||
|
||||
.br
|
||||
- Each criterion should appear only once in the list
|
||||
.br
|
||||
- \fBindex\fR is only allowed at the end of the list
|
||||
.br
|
||||
- \fBindex\fR is implicitly appended to the list when not specified
|
||||
.br
|
||||
- Default is \fBlength\fR (or equivalently \fBlength\fR,index)
|
||||
.br
|
||||
- If \fBend\fR is found in the list, fzf will scan each line backwards
|
||||
.SS Interface
|
||||
.TP
|
||||
.B "-m, --multi"
|
||||
Enable multi-select with tab/shift-tab. It optionally takes an integer argument
|
||||
which denotes the maximum number of items that can be selected.
|
||||
.TP
|
||||
.B "+m, --no-multi"
|
||||
Disable multi-select
|
||||
.TP
|
||||
.B "--no-mouse"
|
||||
Disable mouse
|
||||
.TP
|
||||
.BI "--bind=" "KEYBINDS"
|
||||
Comma-separated list of custom key bindings. See \fBKEY/EVENT BINDINGS\fR for
|
||||
the details.
|
||||
.TP
|
||||
.B "--cycle"
|
||||
Enable cyclic scroll
|
||||
.TP
|
||||
.B "--keep-right"
|
||||
Keep the right end of the line visible when it's too long. Effective only when
|
||||
the query string is empty.
|
||||
.TP
|
||||
.B "--no-hscroll"
|
||||
Disable horizontal scroll
|
||||
.TP
|
||||
.BI "--hscroll-off=" "COL"
|
||||
Number of screen columns to keep to the right of the highlighted substring
|
||||
(default: 10). Setting it to a large value will cause the text to be positioned
|
||||
on the center of the screen.
|
||||
.TP
|
||||
.B "--filepath-word"
|
||||
Make word-wise movements and actions respect path separators. The following
|
||||
actions are affected:
|
||||
|
||||
\fBbackward-kill-word\fR
|
||||
.br
|
||||
\fBbackward-word\fR
|
||||
.br
|
||||
\fBforward-word\fR
|
||||
.br
|
||||
\fBkill-word\fR
|
||||
.TP
|
||||
.BI "--jump-labels=" "CHARS"
|
||||
Label characters for \fBjump\fR and \fBjump-accept\fR
|
||||
.SS Layout
|
||||
.TP
|
||||
.BI "--height=" "HEIGHT[%]"
|
||||
Display fzf window below the cursor with the given height instead of using
|
||||
the full screen.
|
||||
.TP
|
||||
.BI "--min-height=" "HEIGHT"
|
||||
Minimum height when \fB--height\fR is given in percent (default: 10).
|
||||
Ignored when \fB--height\fR is not specified.
|
||||
.TP
|
||||
.BI "--layout=" "LAYOUT"
|
||||
Choose the layout (default: default)
|
||||
|
||||
.br
|
||||
.BR default " Display from the bottom of the screen"
|
||||
.br
|
||||
.BR reverse " Display from the top of the screen"
|
||||
.br
|
||||
.BR reverse-list " Display from the top of the screen, prompt at the bottom"
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B "--reverse"
|
||||
A synonym for \fB--layout=reverse\fB
|
||||
|
||||
.TP
|
||||
.BI "--border" [=STYLE]
|
||||
Draw border around the finder
|
||||
|
||||
.br
|
||||
.BR rounded " Border with rounded corners (default)"
|
||||
.br
|
||||
.BR sharp " Border with sharp corners"
|
||||
.br
|
||||
.BR horizontal " Horizontal lines above and below the finder"
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B "--no-unicode"
|
||||
Use ASCII characters instead of Unicode box drawing characters to draw border
|
||||
|
||||
.TP
|
||||
.BI "--margin=" MARGIN
|
||||
Comma-separated expression for margins around the finder.
|
||||
.br
|
||||
|
||||
.br
|
||||
.RS
|
||||
.BR TRBL " Same margin for top, right, bottom, and left"
|
||||
.br
|
||||
.BR TB,RL " Vertical, horizontal margin"
|
||||
.br
|
||||
.BR T,RL,B " Top, horizontal, bottom margin"
|
||||
.br
|
||||
.BR T,R,B,L " Top, right, bottom, left margin"
|
||||
.br
|
||||
|
||||
.br
|
||||
Each part can be given in absolute number or in percentage relative to the
|
||||
terminal size with \fB%\fR suffix.
|
||||
.br
|
||||
|
||||
.br
|
||||
e.g.
|
||||
\fBfzf --margin 10%
|
||||
fzf --margin 1,5%\fR
|
||||
.RE
|
||||
.TP
|
||||
.BI "--info=" "STYLE"
|
||||
Determines the display style of finder info.
|
||||
|
||||
.br
|
||||
.BR default " Display on the next line to the prompt"
|
||||
.br
|
||||
.BR inline " Display on the same line"
|
||||
.br
|
||||
.BR hidden " Do not display finder info"
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B "--no-info"
|
||||
A synonym for \fB--info=hidden\fB
|
||||
|
||||
.TP
|
||||
.BI "--prompt=" "STR"
|
||||
Input prompt (default: '> ')
|
||||
.TP
|
||||
.BI "--pointer=" "STR"
|
||||
Pointer to the current line (default: '>')
|
||||
.TP
|
||||
.BI "--marker=" "STR"
|
||||
Multi-select marker (default: '>')
|
||||
.TP
|
||||
.BI "--header=" "STR"
|
||||
The given string will be printed as the sticky header. The lines are displayed
|
||||
in the given order from top to bottom regardless of \fB--layout\fR option, and
|
||||
are not affected by \fB--with-nth\fR. ANSI color codes are processed even when
|
||||
\fB--ansi\fR is not set.
|
||||
.TP
|
||||
.BI "--header-lines=" "N"
|
||||
The first N lines of the input are treated as the sticky header. When
|
||||
\fB--with-nth\fR is set, the lines are transformed just like the other
|
||||
lines that follow.
|
||||
.SS Display
|
||||
.TP
|
||||
.B "--ansi"
|
||||
Enable processing of ANSI color codes
|
||||
.TP
|
||||
.BI "--tabstop=" SPACES
|
||||
Number of spaces for a tab character (default: 8)
|
||||
.TP
|
||||
.BI "--color=" "[BASE_SCHEME][,COLOR:ANSI]"
|
||||
Color configuration. The name of the base color scheme is followed by custom
|
||||
color mappings. Ansi color code of -1 denotes terminal default
|
||||
foreground/background color. You can also specify 24-bit color in \fB#rrggbb\fR
|
||||
format.
|
||||
|
||||
.RS
|
||||
.B BASE SCHEME:
|
||||
(default: dark on 256-color terminal, otherwise 16)
|
||||
|
||||
\fBdark \fRColor scheme for dark 256-color terminal
|
||||
\fBlight \fRColor scheme for light 256-color terminal
|
||||
\fB16 \fRColor scheme for 16-color terminal
|
||||
\fBbw \fRNo colors (equivalent to \fB--no-color\fR)
|
||||
|
||||
.B COLOR:
|
||||
\fBfg \fRText
|
||||
\fBbg \fRBackground
|
||||
\fBpreview-fg \fRPreview window text
|
||||
\fBpreview-bg \fRPreview window background
|
||||
\fBhl \fRHighlighted substrings
|
||||
\fBfg+ \fRText (current line)
|
||||
\fBbg+ \fRBackground (current line)
|
||||
\fBgutter \fRGutter on the left (defaults to \fBbg+\fR)
|
||||
\fBhl+ \fRHighlighted substrings (current line)
|
||||
\fBinfo \fRInfo line (match counters)
|
||||
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
|
||||
\fBprompt \fRPrompt
|
||||
\fBpointer \fRPointer to the current line
|
||||
\fBmarker \fRMulti-select marker
|
||||
\fBspinner \fRStreaming input indicator
|
||||
\fBheader \fRHeader
|
||||
|
||||
.B EXAMPLES:
|
||||
|
||||
\fB# Seoul256 theme with 8-bit colors
|
||||
# (https://github.com/junegunn/seoul256.vim)
|
||||
fzf --color='bg:237,bg+:236,info:143,border:240,spinner:108' \\
|
||||
--color='hl:65,fg:252,header:65,fg+:252' \\
|
||||
--color='pointer:161,marker:168,prompt:110,hl+:108'
|
||||
|
||||
# Seoul256 theme with 24-bit colors
|
||||
fzf --color='bg:#4B4B4B,bg+:#3F3F3F,info:#BDBB72,border:#6B6B6B,spinner:#98BC99' \\
|
||||
--color='hl:#719872,fg:#D9D9D9,header:#719872,fg+:#D9D9D9' \\
|
||||
--color='pointer:#E12672,marker:#E17899,prompt:#98BEDE,hl+:#98BC99'\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "--no-bold"
|
||||
Do not use bold text
|
||||
.TP
|
||||
.B "--black"
|
||||
Use black background
|
||||
.SS History
|
||||
.TP
|
||||
.BI "--history=" "HISTORY_FILE"
|
||||
Load search history from the specified file and update the file on completion.
|
||||
When enabled, \fBCTRL-N\fR and \fBCTRL-P\fR are automatically remapped to
|
||||
\fBnext-history\fR and \fBprevious-history\fR.
|
||||
.TP
|
||||
.BI "--history-size=" "N"
|
||||
Maximum number of entries in the history file (default: 1000). The file is
|
||||
automatically truncated when the number of the lines exceeds the value.
|
||||
.SS Preview
|
||||
.TP
|
||||
.BI "--preview=" "COMMAND"
|
||||
Execute the given command for the current line and display the result on the
|
||||
preview window. \fB{}\fR in the command is the placeholder that is replaced to
|
||||
the single-quoted string of the current line. To transform the replacement
|
||||
string, specify field index expressions between the braces (See \fBFIELD INDEX
|
||||
EXPRESSION\fR for the details).
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBfzf --preview='head -$LINES {}'
|
||||
ls -l | fzf --preview="echo user={3} when={-4..-2}; cat {-1}" --header-lines=1\fR
|
||||
|
||||
fzf exports \fB$FZF_PREVIEW_LINES\fR and \fB$FZF_PREVIEW_COLUMNS\fR so that
|
||||
they represent the exact size of the preview window. (It also overrides
|
||||
\fB$LINES\fR and \fB$COLUMNS\fR with the same values but they can be reset
|
||||
by the default shell, so prefer to refer to the ones with \fBFZF_PREVIEW_\fR
|
||||
prefix.)
|
||||
|
||||
A placeholder expression starting with \fB+\fR flag will be replaced to the
|
||||
space-separated list of the selected lines (or the current line if no selection
|
||||
was made) individually quoted.
|
||||
|
||||
e.g.
|
||||
\fBfzf --multi --preview='head -10 {+}'
|
||||
git log --oneline | fzf --multi --preview 'git show {+1}'\fR
|
||||
|
||||
When using a field index expression, leading and trailing whitespace is stripped
|
||||
from the replacement string. To preserve the whitespace, use the \fBs\fR flag.
|
||||
|
||||
Also, \fB{q}\fR is replaced to the current query string, and \fB{n}\fR is
|
||||
replaced to zero-based ordinal index of the line. Use \fB{+n}\fR if you want
|
||||
all index numbers when multiple lines are selected.
|
||||
|
||||
A placeholder expression with \fBf\fR flag is replaced to the path of
|
||||
a temporary file that holds the evaluated list. This is useful when you
|
||||
multi-select a large number of items and the length of the evaluated string may
|
||||
exceed \fBARG_MAX\fR.
|
||||
|
||||
e.g.
|
||||
\fB# Press CTRL-A to select 100K items and see the sum of all the numbers.
|
||||
# This won't work properly without 'f' flag due to ARG_MAX limit.
|
||||
seq 100000 | fzf --multi --bind ctrl-a:select-all \\
|
||||
--preview "awk '{sum+=\$1} END {print sum}' {+f}"\fR
|
||||
|
||||
Note that you can escape a placeholder pattern by prepending a backslash.
|
||||
|
||||
Preview window will be updated even when there is no match for the current
|
||||
query if any of the placeholder expressions evaluates to a non-empty string.
|
||||
.RE
|
||||
.TP
|
||||
.BI "--preview-window=" "[POSITION][:SIZE[%]][:noborder][:wrap][:hidden]"
|
||||
Determines the layout of the preview window. If the argument contains
|
||||
\fB:hidden\fR, the preview window will be hidden by default until
|
||||
\fBtoggle-preview\fR action is triggered. Long lines are truncated by default.
|
||||
Line wrap can be enabled with \fB:wrap\fR flag.
|
||||
|
||||
If size is given as 0, preview window will not be visible, but fzf will still
|
||||
execute the command in the background.
|
||||
|
||||
.RS
|
||||
.B POSITION: (default: right)
|
||||
\fBup
|
||||
\fBdown
|
||||
\fBleft
|
||||
\fBright
|
||||
.RE
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBfzf --preview="head {}" --preview-window=up:30%
|
||||
fzf --preview="file {}" --preview-window=down:1\fR
|
||||
.RE
|
||||
.SS Scripting
|
||||
.TP
|
||||
.BI "-q, --query=" "STR"
|
||||
Start the finder with the given query
|
||||
.TP
|
||||
.B "-1, --select-1"
|
||||
Automatically select the only match
|
||||
.TP
|
||||
.B "-0, --exit-0"
|
||||
Exit immediately when there's no match
|
||||
.TP
|
||||
.BI "-f, --filter=" "STR"
|
||||
Filter mode. Do not start interactive finder. When used with \fB--no-sort\fR,
|
||||
fzf becomes a fuzzy-version of grep.
|
||||
.TP
|
||||
.B "--print-query"
|
||||
Print query as the first line
|
||||
.TP
|
||||
.BI "--expect=" "KEY[,..]"
|
||||
Comma-separated list of keys that can be used to complete fzf in addition to
|
||||
the default enter key. When this option is set, fzf will print the name of the
|
||||
key pressed as the first line of its output (or as the second line if
|
||||
\fB--print-query\fR is also used). The line will be empty if fzf is completed
|
||||
with the default enter key. If \fB--expect\fR option is specified multiple
|
||||
times, fzf will expect the union of the keys. \fB--no-expect\fR will clear the
|
||||
list.
|
||||
|
||||
.RS
|
||||
e.g.
|
||||
\fBfzf --expect=ctrl-v,ctrl-t,alt-s --expect=f1,f2,~,@\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "--read0"
|
||||
Read input delimited by ASCII NUL characters instead of newline characters
|
||||
.TP
|
||||
.B "--print0"
|
||||
Print output delimited by ASCII NUL characters instead of newline characters
|
||||
.TP
|
||||
.B "--no-clear"
|
||||
Do not clear finder interface on exit. If fzf was started in full screen mode,
|
||||
it will not switch back to the original screen, so you'll have to manually run
|
||||
\fBtput rmcup\fR to return. This option can be used to avoid flickering of the
|
||||
screen when your application needs to start fzf multiple times in order.
|
||||
.TP
|
||||
.B "--sync"
|
||||
Synchronous search for multi-staged filtering. If specified, fzf will launch
|
||||
ncurses finder only after the input stream is complete.
|
||||
|
||||
.RS
|
||||
e.g. \fBfzf --multi | fzf --sync\fR
|
||||
.RE
|
||||
.TP
|
||||
.B "--version"
|
||||
Display version information and exit
|
||||
|
||||
.TP
|
||||
Note that most options have the opposite versions with \fB--no-\fR prefix.
|
||||
|
||||
.SH ENVIRONMENT VARIABLES
|
||||
.TP
|
||||
.B FZF_DEFAULT_COMMAND
|
||||
Default command to use when input is tty. On *nix systems, fzf runs the command
|
||||
with \fBsh -c\fR, so make sure that it's POSIX-compliant.
|
||||
.TP
|
||||
.B FZF_DEFAULT_OPTS
|
||||
Default options. e.g. \fBexport FZF_DEFAULT_OPTS="--extended --cycle"\fR
|
||||
|
||||
.SH EXIT STATUS
|
||||
.BR 0 " Normal exit"
|
||||
.br
|
||||
.BR 1 " No match"
|
||||
.br
|
||||
.BR 2 " Error"
|
||||
.br
|
||||
.BR 130 " Interrupted with \fBCTRL-C\fR or \fBESC\fR"
|
||||
|
||||
.SH FIELD INDEX EXPRESSION
|
||||
|
||||
A field index expression can be a non-zero integer or a range expression
|
||||
([BEGIN]..[END]). \fB--nth\fR and \fB--with-nth\fR take a comma-separated list
|
||||
of field index expressions.
|
||||
|
||||
.SS Examples
|
||||
.BR 1 " The 1st field"
|
||||
.br
|
||||
.BR 2 " The 2nd field"
|
||||
.br
|
||||
.BR -1 " The last field"
|
||||
.br
|
||||
.BR -2 " The 2nd to last field"
|
||||
.br
|
||||
.BR 3..5 " From the 3rd field to the 5th field"
|
||||
.br
|
||||
.BR 2.. " From the 2nd field to the last field"
|
||||
.br
|
||||
.BR ..-3 " From the 1st field to the 3rd to the last field"
|
||||
.br
|
||||
.BR .. " All the fields"
|
||||
.br
|
||||
|
||||
.SH EXTENDED SEARCH MODE
|
||||
|
||||
Unless specified otherwise, fzf will start in "extended-search mode". In this
|
||||
mode, you can specify multiple patterns delimited by spaces, such as: \fB'wild
|
||||
^music .mp3$ sbtrkt !rmx\fR
|
||||
|
||||
You can prepend a backslash to a space (\fB\\ \fR) to match a literal space
|
||||
character.
|
||||
|
||||
.SS Exact-match (quoted)
|
||||
A term that is prefixed by a single-quote character (\fB'\fR) is interpreted as
|
||||
an "exact-match" (or "non-fuzzy") term. fzf will search for the exact
|
||||
occurrences of the string.
|
||||
|
||||
.SS Anchored-match
|
||||
A term can be prefixed by \fB^\fR, or suffixed by \fB$\fR to become an
|
||||
anchored-match term. Then fzf will search for the lines that start with or end
|
||||
with the given string. An anchored-match term is also an exact-match term.
|
||||
|
||||
.SS Negation
|
||||
If a term is prefixed by \fB!\fR, fzf will exclude the lines that satisfy the
|
||||
term from the result. In this case, fzf performs exact match by default.
|
||||
|
||||
.SS Exact-match by default
|
||||
If you don't prefer fuzzy matching and do not wish to "quote" (prefixing with
|
||||
\fB'\fR) every word, start fzf with \fB-e\fR or \fB--exact\fR option. Note that
|
||||
when \fB--exact\fR is set, \fB'\fR-prefix "unquotes" the term.
|
||||
|
||||
.SS OR operator
|
||||
A single bar character term acts as an OR operator. For example, the following
|
||||
query matches entries that start with \fBcore\fR and end with either \fBgo\fR,
|
||||
\fBrb\fR, or \fBpy\fR.
|
||||
|
||||
e.g. \fB^core go$ | rb$ | py$\fR
|
||||
|
||||
.SH KEY/EVENT BINDINGS
|
||||
\fB--bind\fR option allows you to bind \fBa key\fR or \fBan event\fR to one or
|
||||
more \fBactions\fR. You can use it to customize key bindings or implement
|
||||
dynamic behaviors.
|
||||
|
||||
\fB--bind\fR takes a comma-separated list of binding expressions. Each binding
|
||||
expression is \fBKEY:ACTION\fR or \fBEVENT:ACTION\fR.
|
||||
|
||||
e.g.
|
||||
\fBfzf --bind=ctrl-j:accept,ctrl-k:kill-line\fR
|
||||
|
||||
.SS AVAILABLE KEYS: (SYNONYMS)
|
||||
\fIctrl-[a-z]\fR
|
||||
.br
|
||||
\fIctrl-space\fR
|
||||
.br
|
||||
\fIctrl-\\\fR
|
||||
.br
|
||||
\fIctrl-]\fR
|
||||
.br
|
||||
\fIctrl-^\fR (\fIctrl-6\fR)
|
||||
.br
|
||||
\fIctrl-/\fR (\fIctrl-_\fR)
|
||||
.br
|
||||
\fIctrl-alt-[a-z]\fR
|
||||
.br
|
||||
\fIalt-[a-z]\fR
|
||||
.br
|
||||
\fIalt-[0-9]\fR
|
||||
.br
|
||||
\fIf[1-12]\fR
|
||||
.br
|
||||
\fIenter\fR (\fIreturn\fR \fIctrl-m\fR)
|
||||
.br
|
||||
\fIspace\fR
|
||||
.br
|
||||
\fIbspace\fR (\fIbs\fR)
|
||||
.br
|
||||
\fIalt-up\fR
|
||||
.br
|
||||
\fIalt-down\fR
|
||||
.br
|
||||
\fIalt-left\fR
|
||||
.br
|
||||
\fIalt-right\fR
|
||||
.br
|
||||
\fIalt-enter\fR
|
||||
.br
|
||||
\fIalt-space\fR
|
||||
.br
|
||||
\fIalt-bspace\fR (\fIalt-bs\fR)
|
||||
.br
|
||||
\fIalt-/\fR
|
||||
.br
|
||||
\fItab\fR
|
||||
.br
|
||||
\fIbtab\fR (\fIshift-tab\fR)
|
||||
.br
|
||||
\fIesc\fR
|
||||
.br
|
||||
\fIdel\fR
|
||||
.br
|
||||
\fIup\fR
|
||||
.br
|
||||
\fIdown\fR
|
||||
.br
|
||||
\fIleft\fR
|
||||
.br
|
||||
\fIright\fR
|
||||
.br
|
||||
\fIhome\fR
|
||||
.br
|
||||
\fIend\fR
|
||||
.br
|
||||
\fIinsert\fR
|
||||
.br
|
||||
\fIpgup\fR (\fIpage-up\fR)
|
||||
.br
|
||||
\fIpgdn\fR (\fIpage-down\fR)
|
||||
.br
|
||||
\fIshift-up\fR
|
||||
.br
|
||||
\fIshift-down\fR
|
||||
.br
|
||||
\fIshift-left\fR
|
||||
.br
|
||||
\fIshift-right\fR
|
||||
.br
|
||||
\fIleft-click\fR
|
||||
.br
|
||||
\fIright-click\fR
|
||||
.br
|
||||
\fIdouble-click\fR
|
||||
.br
|
||||
or any single character
|
||||
|
||||
.SS AVAILABLE EVENTS:
|
||||
\fIchange\fR (triggered whenever the query string is changed)
|
||||
.br
|
||||
|
||||
e.g.
|
||||
\fB# Moves cursor to the top (or bottom depending on --layout) whenever the query is changed
|
||||
fzf --bind change:top\fR
|
||||
|
||||
.SS AVAILABLE ACTIONS:
|
||||
A key or an event can be bound to one or more of the following actions.
|
||||
|
||||
\fBACTION: DEFAULT BINDINGS (NOTES):
|
||||
\fBabort\fR \fIctrl-c ctrl-g ctrl-q esc\fR
|
||||
\fBaccept\fR \fIenter double-click\fR
|
||||
\fBaccept-non-empty\fR (same as \fBaccept\fR except that it prevents fzf from exiting without selection)
|
||||
\fBbackward-char\fR \fIctrl-b left\fR
|
||||
\fBbackward-delete-char\fR \fIctrl-h bspace\fR
|
||||
\fBbackward-delete-char/eof\fR (same as \fBbackward-delete-char\fR except aborts fzf if query is empty)
|
||||
\fBbackward-kill-word\fR \fIalt-bs\fR
|
||||
\fBbackward-word\fR \fIalt-b shift-left\fR
|
||||
\fBbeginning-of-line\fR \fIctrl-a home\fR
|
||||
\fBcancel\fR (clear query string if not empty, abort fzf otherwise)
|
||||
\fBclear-screen\fR \fIctrl-l\fR
|
||||
\fBclear-selection\fR (clear multi-selection)
|
||||
\fBclear-query\fR (clear query string)
|
||||
\fBdelete-char\fR \fIdel\fR
|
||||
\fBdelete-char/eof\fR \fIctrl-d\fR (same as \fBdelete-char\fR except aborts fzf if query is empty)
|
||||
\fBdeselect-all\fR (deselect all matches)
|
||||
\fBdown\fR \fIctrl-j ctrl-n down\fR
|
||||
\fBend-of-line\fR \fIctrl-e end\fR
|
||||
\fBexecute(...)\fR (see below for the details)
|
||||
\fBexecute-silent(...)\fR (see below for the details)
|
||||
\fRexecute-multi(...)\fR (deprecated in favor of \fB{+}\fR expression)
|
||||
\fBforward-char\fR \fIctrl-f right\fR
|
||||
\fBforward-word\fR \fIalt-f shift-right\fR
|
||||
\fBignore\fR
|
||||
\fBjump\fR (EasyMotion-like 2-keystroke movement)
|
||||
\fBjump-accept\fR (jump and accept)
|
||||
\fBkill-line\fR
|
||||
\fBkill-word\fR \fIalt-d\fR
|
||||
\fBnext-history\fR (\fIctrl-n\fR on \fB--history\fR)
|
||||
\fBpage-down\fR \fIpgdn\fR
|
||||
\fBpage-up\fR \fIpgup\fR
|
||||
\fBhalf-page-down\fR
|
||||
\fBhalf-page-up\fR
|
||||
\fBpreview-down\fR \fIshift-down\fR
|
||||
\fBpreview-up\fR \fIshift-up\fR
|
||||
\fBpreview-page-down\fR
|
||||
\fBpreview-page-up\fR
|
||||
\fBprevious-history\fR (\fIctrl-p\fR on \fB--history\fR)
|
||||
\fBprint-query\fR (print query and exit)
|
||||
\fBreload(...)\fR (see below for the details)
|
||||
\fBreplace-query\fR (replace query string with the current selection)
|
||||
\fBselect-all\fR (select all matches)
|
||||
\fBtoggle\fR (\fIright-click\fR)
|
||||
\fBtoggle-all\fR (toggle all matches)
|
||||
\fBtoggle+down\fR \fIctrl-i (tab)\fR
|
||||
\fBtoggle-in\fR (\fB--layout=reverse*\fR ? \fBtoggle+up\fR : \fBtoggle+down\fR)
|
||||
\fBtoggle-out\fR (\fB--layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR)
|
||||
\fBtoggle-preview\fR
|
||||
\fBtoggle-preview-wrap\fR
|
||||
\fBtoggle-sort\fR
|
||||
\fBtoggle+up\fR \fIbtab (shift-tab)\fR
|
||||
\fBtop\fR (move to the top result)
|
||||
\fBunix-line-discard\fR \fIctrl-u\fR
|
||||
\fBunix-word-rubout\fR \fIctrl-w\fR
|
||||
\fBup\fR \fIctrl-k ctrl-p up\fR
|
||||
\fByank\fR \fIctrl-y\fR
|
||||
|
||||
.SS ACTION COMPOSITION
|
||||
|
||||
Multiple actions can be chained using \fB+\fR separator.
|
||||
|
||||
e.g.
|
||||
\fBfzf --bind 'ctrl-a:select-all+accept'\fR
|
||||
|
||||
.SS COMMAND EXECUTION
|
||||
|
||||
With \fBexecute(...)\fR action, you can execute arbitrary commands without
|
||||
leaving fzf. For example, you can turn fzf into a simple file browser by
|
||||
binding \fBenter\fR key to \fBless\fR command like follows.
|
||||
|
||||
\fBfzf --bind "enter:execute(less {})"\fR
|
||||
|
||||
You can use the same placeholder expressions as in \fB--preview\fR.
|
||||
|
||||
If the command contains parentheses, fzf may fail to parse the expression. In
|
||||
that case, you can use any of the following alternative notations to avoid
|
||||
parse errors.
|
||||
|
||||
\fBexecute[...]\fR
|
||||
\fBexecute~...~\fR
|
||||
\fBexecute!...!\fR
|
||||
\fBexecute@...@\fR
|
||||
\fBexecute#...#\fR
|
||||
\fBexecute$...$\fR
|
||||
\fBexecute%...%\fR
|
||||
\fBexecute^...^\fR
|
||||
\fBexecute&...&\fR
|
||||
\fBexecute*...*\fR
|
||||
\fBexecute;...;\fR
|
||||
\fBexecute/.../\fR
|
||||
\fBexecute|...|\fR
|
||||
\fBexecute:...\fR
|
||||
.RS
|
||||
The last one is the special form that frees you from parse errors as it does
|
||||
not expect the closing character. The catch is that it should be the last one
|
||||
in the comma-separated list of key-action pairs.
|
||||
.RE
|
||||
|
||||
fzf switches to the alternate screen when executing a command. However, if the
|
||||
command is expected to complete quickly, and you are not interested in its
|
||||
output, you might want to use \fBexecute-silent\fR instead, which silently
|
||||
executes the command without the switching. Note that fzf will not be
|
||||
responsive until the command is complete. For asynchronous execution, start
|
||||
your command as a background process (i.e. appending \fB&\fR).
|
||||
|
||||
.SS RELOAD INPUT
|
||||
|
||||
\fBreload(...)\fR action is used to dynamically update the input list
|
||||
without restarting fzf. It takes the same command template with placeholder
|
||||
expressions as \fBexecute(...)\fR.
|
||||
|
||||
See \fIhttps://github.com/junegunn/fzf/issues/1750\fR for more info.
|
||||
|
||||
e.g.
|
||||
\fB# Update the list of processes by pressing CTRL-R
|
||||
ps -ef | fzf --bind 'ctrl-r:reload(ps -ef)' --header 'Press CTRL-R to reload' \\
|
||||
--header-lines=1 --layout=reverse
|
||||
|
||||
# Integration with ripgrep
|
||||
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case "
|
||||
INITIAL_QUERY="foobar"
|
||||
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \\
|
||||
fzf --bind "change:reload:$RG_PREFIX {q} || true" \\
|
||||
--ansi --phony --query "$INITIAL_QUERY"\fR
|
||||
|
||||
.SH AUTHOR
|
||||
Junegunn Choi (\fIjunegunn.c@gmail.com\fR)
|
||||
|
||||
.SH SEE ALSO
|
||||
.B Project homepage:
|
||||
.RS
|
||||
.I https://github.com/junegunn/fzf
|
||||
.RE
|
||||
.br
|
||||
|
||||
.br
|
||||
.B Extra Vim plugin:
|
||||
.RS
|
||||
.I https://github.com/junegunn/fzf.vim
|
||||
.RE
|
||||
|
||||
.SH LICENSE
|
||||
MIT
|
||||
@@ -0,0 +1,949 @@
|
||||
" Copyright (c) 2017 Junegunn Choi
|
||||
"
|
||||
" MIT License
|
||||
"
|
||||
" Permission is hereby granted, free of charge, to any person obtaining
|
||||
" a copy of this software and associated documentation files (the
|
||||
" "Software"), to deal in the Software without restriction, including
|
||||
" without limitation the rights to use, copy, modify, merge, publish,
|
||||
" distribute, sublicense, and/or sell copies of the Software, and to
|
||||
" permit persons to whom the Software is furnished to do so, subject to
|
||||
" the following conditions:
|
||||
"
|
||||
" The above copyright notice and this permission notice shall be
|
||||
" included in all copies or substantial portions of the Software.
|
||||
"
|
||||
" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
" NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
" LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
" OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
" WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
if exists('g:loaded_fzf')
|
||||
finish
|
||||
endif
|
||||
let g:loaded_fzf = 1
|
||||
|
||||
let s:is_win = has('win32') || has('win64')
|
||||
if s:is_win && &shellslash
|
||||
set noshellslash
|
||||
let s:base_dir = expand('<sfile>:h:h')
|
||||
set shellslash
|
||||
else
|
||||
let s:base_dir = expand('<sfile>:h:h')
|
||||
endif
|
||||
if s:is_win
|
||||
let s:term_marker = '&::FZF'
|
||||
|
||||
function! s:fzf_call(fn, ...)
|
||||
let shellslash = &shellslash
|
||||
try
|
||||
set noshellslash
|
||||
return call(a:fn, a:000)
|
||||
finally
|
||||
let &shellslash = shellslash
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
" Use utf-8 for fzf.vim commands
|
||||
" Return array of shell commands for cmd.exe
|
||||
function! s:enc_to_cp(str)
|
||||
if !has('iconv')
|
||||
return a:str
|
||||
endif
|
||||
if !exists('s:codepage')
|
||||
let s:codepage = libcallnr('kernel32.dll', 'GetACP', 0)
|
||||
endif
|
||||
return iconv(a:str, &encoding, 'cp'.s:codepage)
|
||||
endfunction
|
||||
function! s:wrap_cmds(cmds)
|
||||
return map([
|
||||
\ '@echo off',
|
||||
\ 'setlocal enabledelayedexpansion']
|
||||
\ + (has('gui_running') ? ['set TERM= > nul'] : [])
|
||||
\ + (type(a:cmds) == type([]) ? a:cmds : [a:cmds])
|
||||
\ + ['endlocal'],
|
||||
\ '<SID>enc_to_cp(v:val."\r")')
|
||||
endfunction
|
||||
else
|
||||
let s:term_marker = ";#FZF"
|
||||
|
||||
function! s:fzf_call(fn, ...)
|
||||
return call(a:fn, a:000)
|
||||
endfunction
|
||||
|
||||
function! s:wrap_cmds(cmds)
|
||||
return a:cmds
|
||||
endfunction
|
||||
|
||||
function! s:enc_to_cp(str)
|
||||
return a:str
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:shellesc_cmd(arg)
|
||||
let escaped = substitute(a:arg, '[&|<>()@^]', '^&', 'g')
|
||||
let escaped = substitute(escaped, '%', '%%', 'g')
|
||||
let escaped = substitute(escaped, '"', '\\^&', 'g')
|
||||
let escaped = substitute(escaped, '\(\\\+\)\(\\^\)', '\1\1\2', 'g')
|
||||
return '^"'.substitute(escaped, '\(\\\+\)$', '\1\1', '').'^"'
|
||||
endfunction
|
||||
|
||||
function! fzf#shellescape(arg, ...)
|
||||
let shell = get(a:000, 0, s:is_win ? 'cmd.exe' : 'sh')
|
||||
if shell =~# 'cmd.exe$'
|
||||
return s:shellesc_cmd(a:arg)
|
||||
endif
|
||||
return s:fzf_call('shellescape', a:arg)
|
||||
endfunction
|
||||
|
||||
function! s:fzf_getcwd()
|
||||
return s:fzf_call('getcwd')
|
||||
endfunction
|
||||
|
||||
function! s:fzf_fnamemodify(fname, mods)
|
||||
return s:fzf_call('fnamemodify', a:fname, a:mods)
|
||||
endfunction
|
||||
|
||||
function! s:fzf_expand(fmt)
|
||||
return s:fzf_call('expand', a:fmt, 1)
|
||||
endfunction
|
||||
|
||||
function! s:fzf_tempname()
|
||||
return s:fzf_call('tempname')
|
||||
endfunction
|
||||
|
||||
let s:default_layout = { 'down': '~40%' }
|
||||
let s:layout_keys = ['window', 'tmux', 'up', 'down', 'left', 'right']
|
||||
let s:fzf_go = s:base_dir.'/bin/fzf'
|
||||
let s:fzf_tmux = s:base_dir.'/bin/fzf-tmux'
|
||||
|
||||
let s:cpo_save = &cpo
|
||||
set cpo&vim
|
||||
|
||||
function! fzf#install()
|
||||
if s:is_win && !has('win32unix')
|
||||
let script = s:base_dir.'/install.ps1'
|
||||
if !filereadable(script)
|
||||
throw script.' not found'
|
||||
endif
|
||||
let script = 'powershell -ExecutionPolicy Bypass -file ' . script
|
||||
else
|
||||
let script = s:base_dir.'/install'
|
||||
if !executable(script)
|
||||
throw script.' not found'
|
||||
endif
|
||||
let script .= ' --bin'
|
||||
endif
|
||||
|
||||
call s:warn('Running fzf installer ...')
|
||||
call system(script)
|
||||
if v:shell_error
|
||||
throw 'Failed to download fzf: '.script
|
||||
endif
|
||||
endfunction
|
||||
|
||||
function! s:fzf_exec()
|
||||
if !exists('s:exec')
|
||||
if executable(s:fzf_go)
|
||||
let s:exec = s:fzf_go
|
||||
elseif executable('fzf')
|
||||
let s:exec = 'fzf'
|
||||
elseif input('fzf executable not found. Download binary? (y/n) ') =~? '^y'
|
||||
redraw
|
||||
call fzf#install()
|
||||
return s:fzf_exec()
|
||||
else
|
||||
redraw
|
||||
throw 'fzf executable not found'
|
||||
endif
|
||||
endif
|
||||
return fzf#shellescape(s:exec)
|
||||
endfunction
|
||||
|
||||
function! s:tmux_enabled()
|
||||
if has('gui_running') || !exists('$TMUX')
|
||||
return 0
|
||||
endif
|
||||
|
||||
if exists('s:tmux')
|
||||
return s:tmux
|
||||
endif
|
||||
|
||||
let s:tmux = 0
|
||||
if !executable(s:fzf_tmux)
|
||||
if executable('fzf-tmux')
|
||||
let s:fzf_tmux = 'fzf-tmux'
|
||||
else
|
||||
return 0
|
||||
endif
|
||||
endif
|
||||
|
||||
let output = system('tmux -V')
|
||||
let s:tmux = !v:shell_error && output >= 'tmux 1.7'
|
||||
return s:tmux
|
||||
endfunction
|
||||
|
||||
function! s:escape(path)
|
||||
let path = fnameescape(a:path)
|
||||
return s:is_win ? escape(path, '$') : path
|
||||
endfunction
|
||||
|
||||
function! s:error(msg)
|
||||
echohl ErrorMsg
|
||||
echom a:msg
|
||||
echohl None
|
||||
endfunction
|
||||
|
||||
function! s:warn(msg)
|
||||
echohl WarningMsg
|
||||
echom a:msg
|
||||
echohl None
|
||||
endfunction
|
||||
|
||||
function! s:has_any(dict, keys)
|
||||
for key in a:keys
|
||||
if has_key(a:dict, key)
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! s:open(cmd, target)
|
||||
if stridx('edit', a:cmd) == 0 && s:fzf_fnamemodify(a:target, ':p') ==# s:fzf_expand('%:p')
|
||||
return
|
||||
endif
|
||||
execute a:cmd s:escape(a:target)
|
||||
endfunction
|
||||
|
||||
function! s:common_sink(action, lines) abort
|
||||
if len(a:lines) < 2
|
||||
return
|
||||
endif
|
||||
let key = remove(a:lines, 0)
|
||||
let Cmd = get(a:action, key, 'e')
|
||||
if type(Cmd) == type(function('call'))
|
||||
return Cmd(a:lines)
|
||||
endif
|
||||
if len(a:lines) > 1
|
||||
augroup fzf_swap
|
||||
autocmd SwapExists * let v:swapchoice='o'
|
||||
\| call s:warn('fzf: E325: swap file exists: '.s:fzf_expand('<afile>'))
|
||||
augroup END
|
||||
endif
|
||||
try
|
||||
let empty = empty(s:fzf_expand('%')) && line('$') == 1 && empty(getline(1)) && !&modified
|
||||
let autochdir = &autochdir
|
||||
set noautochdir
|
||||
for item in a:lines
|
||||
if empty
|
||||
execute 'e' s:escape(item)
|
||||
let empty = 0
|
||||
else
|
||||
call s:open(Cmd, item)
|
||||
endif
|
||||
if !has('patch-8.0.0177') && !has('nvim-0.2') && exists('#BufEnter')
|
||||
\ && isdirectory(item)
|
||||
doautocmd BufEnter
|
||||
endif
|
||||
endfor
|
||||
catch /^Vim:Interrupt$/
|
||||
finally
|
||||
let &autochdir = autochdir
|
||||
silent! autocmd! fzf_swap
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:get_color(attr, ...)
|
||||
let gui = !s:is_win && !has('win32unix') && has('termguicolors') && &termguicolors
|
||||
let fam = gui ? 'gui' : 'cterm'
|
||||
let pat = gui ? '^#[a-f0-9]\+' : '^[0-9]\+$'
|
||||
for group in a:000
|
||||
let code = synIDattr(synIDtrans(hlID(group)), a:attr, fam)
|
||||
if code =~? pat
|
||||
return code
|
||||
endif
|
||||
endfor
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
function! s:defaults()
|
||||
let rules = copy(get(g:, 'fzf_colors', {}))
|
||||
let colors = join(map(items(filter(map(rules, 'call("s:get_color", v:val)'), '!empty(v:val)')), 'join(v:val, ":")'), ',')
|
||||
return empty(colors) ? '' : fzf#shellescape('--color='.colors)
|
||||
endfunction
|
||||
|
||||
function! s:validate_layout(layout)
|
||||
for key in keys(a:layout)
|
||||
if index(s:layout_keys, key) < 0
|
||||
throw printf('Invalid entry in g:fzf_layout: %s (allowed: %s)%s',
|
||||
\ key, join(s:layout_keys, ', '), key == 'options' ? '. Use $FZF_DEFAULT_OPTS.' : '')
|
||||
endif
|
||||
endfor
|
||||
return a:layout
|
||||
endfunction
|
||||
|
||||
function! s:evaluate_opts(options)
|
||||
return type(a:options) == type([]) ?
|
||||
\ join(map(copy(a:options), 'fzf#shellescape(v:val)')) : a:options
|
||||
endfunction
|
||||
|
||||
" [name string,] [opts dict,] [fullscreen boolean]
|
||||
function! fzf#wrap(...)
|
||||
let args = ['', {}, 0]
|
||||
let expects = map(copy(args), 'type(v:val)')
|
||||
let tidx = 0
|
||||
for arg in copy(a:000)
|
||||
let tidx = index(expects, type(arg), tidx)
|
||||
if tidx < 0
|
||||
throw 'Invalid arguments (expected: [name string] [opts dict] [fullscreen boolean])'
|
||||
endif
|
||||
let args[tidx] = arg
|
||||
let tidx += 1
|
||||
unlet arg
|
||||
endfor
|
||||
let [name, opts, bang] = args
|
||||
|
||||
if len(name)
|
||||
let opts.name = name
|
||||
end
|
||||
|
||||
" Layout: g:fzf_layout (and deprecated g:fzf_height)
|
||||
if bang
|
||||
for key in s:layout_keys
|
||||
if has_key(opts, key)
|
||||
call remove(opts, key)
|
||||
endif
|
||||
endfor
|
||||
elseif !s:has_any(opts, s:layout_keys)
|
||||
if !exists('g:fzf_layout') && exists('g:fzf_height')
|
||||
let opts.down = g:fzf_height
|
||||
else
|
||||
let opts = extend(opts, s:validate_layout(get(g:, 'fzf_layout', s:default_layout)))
|
||||
endif
|
||||
endif
|
||||
|
||||
" Colors: g:fzf_colors
|
||||
let opts.options = s:defaults() .' '. s:evaluate_opts(get(opts, 'options', ''))
|
||||
|
||||
" History: g:fzf_history_dir
|
||||
if len(name) && len(get(g:, 'fzf_history_dir', ''))
|
||||
let dir = s:fzf_expand(g:fzf_history_dir)
|
||||
if !isdirectory(dir)
|
||||
call mkdir(dir, 'p')
|
||||
endif
|
||||
let history = fzf#shellescape(dir.'/'.name)
|
||||
let opts.options = join(['--history', history, opts.options])
|
||||
endif
|
||||
|
||||
" Action: g:fzf_action
|
||||
if !s:has_any(opts, ['sink', 'sink*'])
|
||||
let opts._action = get(g:, 'fzf_action', s:default_action)
|
||||
let opts.options .= ' --expect='.join(keys(opts._action), ',')
|
||||
function! opts.sink(lines) abort
|
||||
return s:common_sink(self._action, a:lines)
|
||||
endfunction
|
||||
let opts['sink*'] = remove(opts, 'sink')
|
||||
endif
|
||||
|
||||
return opts
|
||||
endfunction
|
||||
|
||||
function! s:use_sh()
|
||||
let [shell, shellslash, shellcmdflag, shellxquote] = [&shell, &shellslash, &shellcmdflag, &shellxquote]
|
||||
if s:is_win
|
||||
set shell=cmd.exe
|
||||
set noshellslash
|
||||
let &shellcmdflag = has('nvim') ? '/s /c' : '/c'
|
||||
let &shellxquote = has('nvim') ? '"' : '('
|
||||
else
|
||||
set shell=sh
|
||||
endif
|
||||
return [shell, shellslash, shellcmdflag, shellxquote]
|
||||
endfunction
|
||||
|
||||
function! fzf#run(...) abort
|
||||
try
|
||||
let [shell, shellslash, shellcmdflag, shellxquote] = s:use_sh()
|
||||
|
||||
let dict = exists('a:1') ? copy(a:1) : {}
|
||||
let temps = { 'result': s:fzf_tempname() }
|
||||
let optstr = s:evaluate_opts(get(dict, 'options', ''))
|
||||
try
|
||||
let fzf_exec = s:fzf_exec()
|
||||
catch
|
||||
throw v:exception
|
||||
endtry
|
||||
|
||||
if !has_key(dict, 'dir')
|
||||
let dict.dir = s:fzf_getcwd()
|
||||
endif
|
||||
if has('win32unix') && has_key(dict, 'dir')
|
||||
let dict.dir = fnamemodify(dict.dir, ':p')
|
||||
endif
|
||||
|
||||
if has_key(dict, 'source')
|
||||
let source = dict.source
|
||||
let type = type(source)
|
||||
if type == 1
|
||||
let prefix = '( '.source.' )|'
|
||||
elseif type == 3
|
||||
let temps.input = s:fzf_tempname()
|
||||
call writefile(map(source, '<SID>enc_to_cp(v:val)'), temps.input)
|
||||
let prefix = (s:is_win ? 'type ' : 'cat ').fzf#shellescape(temps.input).'|'
|
||||
else
|
||||
throw 'Invalid source type'
|
||||
endif
|
||||
else
|
||||
let prefix = ''
|
||||
endif
|
||||
|
||||
let prefer_tmux = get(g:, 'fzf_prefer_tmux', 0) || has_key(dict, 'tmux')
|
||||
let use_height = has_key(dict, 'down') && !has('gui_running') &&
|
||||
\ !(has('nvim') || s:is_win || has('win32unix') || s:present(dict, 'up', 'left', 'right', 'window')) &&
|
||||
\ executable('tput') && filereadable('/dev/tty')
|
||||
let has_vim8_term = has('terminal') && has('patch-8.0.995')
|
||||
let has_nvim_term = has('nvim-0.2.1') || has('nvim') && !s:is_win
|
||||
let use_term = has_nvim_term ||
|
||||
\ has_vim8_term && !has('win32unix') && (has('gui_running') || s:is_win || !use_height && s:present(dict, 'down', 'up', 'left', 'right', 'window'))
|
||||
let use_tmux = (has_key(dict, 'tmux') || (!use_height && !use_term || prefer_tmux) && !has('win32unix') && s:splittable(dict)) && s:tmux_enabled()
|
||||
if prefer_tmux && use_tmux
|
||||
let use_height = 0
|
||||
let use_term = 0
|
||||
endif
|
||||
if use_height
|
||||
let height = s:calc_size(&lines, dict.down, dict)
|
||||
let optstr .= ' --height='.height
|
||||
elseif use_term
|
||||
let optstr .= ' --no-height'
|
||||
endif
|
||||
let command = prefix.(use_tmux ? s:fzf_tmux(dict) : fzf_exec).' '.optstr.' > '.temps.result
|
||||
|
||||
if use_term
|
||||
return s:execute_term(dict, command, temps)
|
||||
endif
|
||||
|
||||
let lines = use_tmux ? s:execute_tmux(dict, command, temps)
|
||||
\ : s:execute(dict, command, use_height, temps)
|
||||
call s:callback(dict, lines)
|
||||
return lines
|
||||
finally
|
||||
let [&shell, &shellslash, &shellcmdflag, &shellxquote] = [shell, shellslash, shellcmdflag, shellxquote]
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:present(dict, ...)
|
||||
for key in a:000
|
||||
if !empty(get(a:dict, key, ''))
|
||||
return 1
|
||||
endif
|
||||
endfor
|
||||
return 0
|
||||
endfunction
|
||||
|
||||
function! s:fzf_tmux(dict)
|
||||
let size = get(a:dict, 'tmux', '')
|
||||
if empty(size)
|
||||
for o in ['up', 'down', 'left', 'right']
|
||||
if s:present(a:dict, o)
|
||||
let spec = a:dict[o]
|
||||
if (o == 'up' || o == 'down') && spec[0] == '~'
|
||||
let size = '-'.o[0].s:calc_size(&lines, spec, a:dict)
|
||||
else
|
||||
" Legacy boolean option
|
||||
let size = '-'.o[0].(spec == 1 ? '' : substitute(spec, '^\~', '', ''))
|
||||
endif
|
||||
break
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return printf('LINES=%d COLUMNS=%d %s %s %s --',
|
||||
\ &lines, &columns, fzf#shellescape(s:fzf_tmux), size, (has_key(a:dict, 'source') ? '' : '-'))
|
||||
endfunction
|
||||
|
||||
function! s:splittable(dict)
|
||||
return s:present(a:dict, 'up', 'down') && &lines > 15 ||
|
||||
\ s:present(a:dict, 'left', 'right') && &columns > 40
|
||||
endfunction
|
||||
|
||||
function! s:pushd(dict)
|
||||
if s:present(a:dict, 'dir')
|
||||
let cwd = s:fzf_getcwd()
|
||||
let w:fzf_pushd = {
|
||||
\ 'command': haslocaldir() ? 'lcd' : (exists(':tcd') && haslocaldir(-1) ? 'tcd' : 'cd'),
|
||||
\ 'origin': cwd,
|
||||
\ 'bufname': bufname('')
|
||||
\ }
|
||||
execute 'lcd' s:escape(a:dict.dir)
|
||||
let cwd = s:fzf_getcwd()
|
||||
let w:fzf_pushd.dir = cwd
|
||||
let a:dict.pushd = w:fzf_pushd
|
||||
return cwd
|
||||
endif
|
||||
return ''
|
||||
endfunction
|
||||
|
||||
augroup fzf_popd
|
||||
autocmd!
|
||||
autocmd WinEnter * call s:dopopd()
|
||||
augroup END
|
||||
|
||||
function! s:dopopd()
|
||||
if !exists('w:fzf_pushd')
|
||||
return
|
||||
endif
|
||||
|
||||
" FIXME: We temporarily change the working directory to 'dir' entry
|
||||
" of options dictionary (set to the current working directory if not given)
|
||||
" before running fzf.
|
||||
"
|
||||
" e.g. call fzf#run({'dir': '/tmp', 'source': 'ls', 'sink': 'e'})
|
||||
"
|
||||
" After processing the sink function, we have to restore the current working
|
||||
" directory. But doing so may not be desirable if the function changed the
|
||||
" working directory on purpose.
|
||||
"
|
||||
" So how can we tell if we should do it or not? A simple heuristic we use
|
||||
" here is that we change directory only if the current working directory
|
||||
" matches 'dir' entry. However, it is possible that the sink function did
|
||||
" change the directory to 'dir'. In that case, the user will have an
|
||||
" unexpected result.
|
||||
if s:fzf_getcwd() ==# w:fzf_pushd.dir && (!&autochdir || w:fzf_pushd.bufname ==# bufname(''))
|
||||
execute w:fzf_pushd.command s:escape(w:fzf_pushd.origin)
|
||||
endif
|
||||
unlet w:fzf_pushd
|
||||
endfunction
|
||||
|
||||
function! s:xterm_launcher()
|
||||
let fmt = 'xterm -T "[fzf]" -bg "%s" -fg "%s" -geometry %dx%d+%d+%d -e bash -ic %%s'
|
||||
if has('gui_macvim')
|
||||
let fmt .= '&& osascript -e "tell application \"MacVim\" to activate"'
|
||||
endif
|
||||
return printf(fmt,
|
||||
\ escape(synIDattr(hlID("Normal"), "bg"), '#'), escape(synIDattr(hlID("Normal"), "fg"), '#'),
|
||||
\ &columns, &lines/2, getwinposx(), getwinposy())
|
||||
endfunction
|
||||
unlet! s:launcher
|
||||
if s:is_win || has('win32unix')
|
||||
let s:launcher = '%s'
|
||||
else
|
||||
let s:launcher = function('s:xterm_launcher')
|
||||
endif
|
||||
|
||||
function! s:exit_handler(code, command, ...)
|
||||
if a:code == 130
|
||||
return 0
|
||||
elseif has('nvim') && a:code == 129
|
||||
" When deleting the terminal buffer while fzf is still running,
|
||||
" Nvim sends SIGHUP.
|
||||
return 0
|
||||
elseif a:code > 1
|
||||
call s:error('Error running ' . a:command)
|
||||
if !empty(a:000)
|
||||
sleep
|
||||
endif
|
||||
return 0
|
||||
endif
|
||||
return 1
|
||||
endfunction
|
||||
|
||||
function! s:execute(dict, command, use_height, temps) abort
|
||||
call s:pushd(a:dict)
|
||||
if has('unix') && !a:use_height
|
||||
silent! !clear 2> /dev/null
|
||||
endif
|
||||
let escaped = (a:use_height || s:is_win) ? a:command : escape(substitute(a:command, '\n', '\\n', 'g'), '%#!')
|
||||
if has('gui_running')
|
||||
let Launcher = get(a:dict, 'launcher', get(g:, 'Fzf_launcher', get(g:, 'fzf_launcher', s:launcher)))
|
||||
let fmt = type(Launcher) == 2 ? call(Launcher, []) : Launcher
|
||||
if has('unix')
|
||||
let escaped = "'".substitute(escaped, "'", "'\"'\"'", 'g')."'"
|
||||
endif
|
||||
let command = printf(fmt, escaped)
|
||||
else
|
||||
let command = escaped
|
||||
endif
|
||||
if s:is_win
|
||||
let batchfile = s:fzf_tempname().'.bat'
|
||||
call writefile(s:wrap_cmds(command), batchfile)
|
||||
let command = batchfile
|
||||
let a:temps.batchfile = batchfile
|
||||
if has('nvim')
|
||||
let fzf = {}
|
||||
let fzf.dict = a:dict
|
||||
let fzf.temps = a:temps
|
||||
function! fzf.on_exit(job_id, exit_status, event) dict
|
||||
call s:pushd(self.dict)
|
||||
let lines = s:collect(self.temps)
|
||||
call s:callback(self.dict, lines)
|
||||
endfunction
|
||||
let cmd = 'start /wait cmd /c '.command
|
||||
call jobstart(cmd, fzf)
|
||||
return []
|
||||
endif
|
||||
elseif has('win32unix') && $TERM !=# 'cygwin'
|
||||
let shellscript = s:fzf_tempname()
|
||||
call writefile([command], shellscript)
|
||||
let command = 'cmd.exe /C '.fzf#shellescape('set "TERM=" & start /WAIT sh -c '.shellscript)
|
||||
let a:temps.shellscript = shellscript
|
||||
endif
|
||||
if a:use_height
|
||||
let stdin = has_key(a:dict, 'source') ? '' : '< /dev/tty'
|
||||
call system(printf('tput cup %d > /dev/tty; tput cnorm > /dev/tty; %s %s 2> /dev/tty', &lines, command, stdin))
|
||||
else
|
||||
execute 'silent !'.command
|
||||
endif
|
||||
let exit_status = v:shell_error
|
||||
redraw!
|
||||
return s:exit_handler(exit_status, command) ? s:collect(a:temps) : []
|
||||
endfunction
|
||||
|
||||
function! s:execute_tmux(dict, command, temps) abort
|
||||
let command = a:command
|
||||
let cwd = s:pushd(a:dict)
|
||||
if len(cwd)
|
||||
" -c '#{pane_current_path}' is only available on tmux 1.9 or above
|
||||
let command = join(['cd', fzf#shellescape(cwd), '&&', command])
|
||||
endif
|
||||
|
||||
call system(command)
|
||||
let exit_status = v:shell_error
|
||||
redraw!
|
||||
return s:exit_handler(exit_status, command) ? s:collect(a:temps) : []
|
||||
endfunction
|
||||
|
||||
function! s:calc_size(max, val, dict)
|
||||
let val = substitute(a:val, '^\~', '', '')
|
||||
if val =~ '%$'
|
||||
let size = a:max * str2nr(val[:-2]) / 100
|
||||
else
|
||||
let size = min([a:max, str2nr(val)])
|
||||
endif
|
||||
|
||||
let srcsz = -1
|
||||
if type(get(a:dict, 'source', 0)) == type([])
|
||||
let srcsz = len(a:dict.source)
|
||||
endif
|
||||
|
||||
let opts = $FZF_DEFAULT_OPTS.' '.s:evaluate_opts(get(a:dict, 'options', ''))
|
||||
let margin = match(opts, '--inline-info\|--info[^-]\{-}inline') > match(opts, '--no-inline-info\|--info[^-]\{-}\(default\|hidden\)') ? 1 : 2
|
||||
let margin += stridx(opts, '--border') > stridx(opts, '--no-border') ? 2 : 0
|
||||
if stridx(opts, '--header') > stridx(opts, '--no-header')
|
||||
let margin += len(split(opts, "\n"))
|
||||
endif
|
||||
return srcsz >= 0 ? min([srcsz + margin, size]) : size
|
||||
endfunction
|
||||
|
||||
function! s:getpos()
|
||||
return {'tab': tabpagenr(), 'win': winnr(), 'winid': win_getid(), 'cnt': winnr('$'), 'tcnt': tabpagenr('$')}
|
||||
endfunction
|
||||
|
||||
function! s:split(dict)
|
||||
let directions = {
|
||||
\ 'up': ['topleft', 'resize', &lines],
|
||||
\ 'down': ['botright', 'resize', &lines],
|
||||
\ 'left': ['vertical topleft', 'vertical resize', &columns],
|
||||
\ 'right': ['vertical botright', 'vertical resize', &columns] }
|
||||
let ppos = s:getpos()
|
||||
let is_popup = 0
|
||||
try
|
||||
if s:present(a:dict, 'window')
|
||||
if type(a:dict.window) == type({})
|
||||
if !has('nvim') && !has('patch-8.2.191')
|
||||
throw 'Vim 8.2.191 or later is required for pop-up window'
|
||||
end
|
||||
call s:popup(a:dict.window)
|
||||
let is_popup = 1
|
||||
else
|
||||
execute 'keepalt' a:dict.window
|
||||
endif
|
||||
elseif !s:splittable(a:dict)
|
||||
execute (tabpagenr()-1).'tabnew'
|
||||
else
|
||||
for [dir, triple] in items(directions)
|
||||
let val = get(a:dict, dir, '')
|
||||
if !empty(val)
|
||||
let [cmd, resz, max] = triple
|
||||
if (dir == 'up' || dir == 'down') && val[0] == '~'
|
||||
let sz = s:calc_size(max, val, a:dict)
|
||||
else
|
||||
let sz = s:calc_size(max, val, {})
|
||||
endif
|
||||
execute cmd sz.'new'
|
||||
execute resz sz
|
||||
return [ppos, {}, is_popup]
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return [ppos, is_popup ? {} : { '&l:wfw': &l:wfw, '&l:wfh': &l:wfh }, is_popup]
|
||||
finally
|
||||
if !is_popup
|
||||
setlocal winfixwidth winfixheight
|
||||
endif
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:execute_term(dict, command, temps) abort
|
||||
let winrest = winrestcmd()
|
||||
let pbuf = bufnr('')
|
||||
let [ppos, winopts, is_popup] = s:split(a:dict)
|
||||
call s:use_sh()
|
||||
let b:fzf = a:dict
|
||||
let fzf = { 'buf': bufnr(''), 'pbuf': pbuf, 'ppos': ppos, 'dict': a:dict, 'temps': a:temps,
|
||||
\ 'winopts': winopts, 'winrest': winrest, 'lines': &lines,
|
||||
\ 'columns': &columns, 'command': a:command }
|
||||
function! fzf.switch_back(inplace)
|
||||
if a:inplace && bufnr('') == self.buf
|
||||
if bufexists(self.pbuf)
|
||||
execute 'keepalt b' self.pbuf
|
||||
endif
|
||||
" No other listed buffer
|
||||
if bufnr('') == self.buf
|
||||
enew
|
||||
endif
|
||||
endif
|
||||
endfunction
|
||||
function! fzf.on_exit(id, code, ...)
|
||||
if s:getpos() == self.ppos " {'window': 'enew'}
|
||||
for [opt, val] in items(self.winopts)
|
||||
execute 'let' opt '=' val
|
||||
endfor
|
||||
call self.switch_back(1)
|
||||
else
|
||||
if bufnr('') == self.buf
|
||||
" We use close instead of bd! since Vim does not close the split when
|
||||
" there's no other listed buffer (nvim +'set nobuflisted')
|
||||
close
|
||||
endif
|
||||
silent! execute 'tabnext' self.ppos.tab
|
||||
silent! execute self.ppos.win.'wincmd w'
|
||||
endif
|
||||
|
||||
if bufexists(self.buf)
|
||||
execute 'bd!' self.buf
|
||||
endif
|
||||
|
||||
if &lines == self.lines && &columns == self.columns && s:getpos() == self.ppos
|
||||
execute self.winrest
|
||||
endif
|
||||
|
||||
if !s:exit_handler(a:code, self.command, 1)
|
||||
return
|
||||
endif
|
||||
|
||||
call s:pushd(self.dict)
|
||||
let lines = s:collect(self.temps)
|
||||
call s:callback(self.dict, lines)
|
||||
call self.switch_back(s:getpos() == self.ppos)
|
||||
endfunction
|
||||
|
||||
try
|
||||
call s:pushd(a:dict)
|
||||
if s:is_win
|
||||
let fzf.temps.batchfile = s:fzf_tempname().'.bat'
|
||||
call writefile(s:wrap_cmds(a:command), fzf.temps.batchfile)
|
||||
let command = fzf.temps.batchfile
|
||||
else
|
||||
let command = a:command
|
||||
endif
|
||||
let command .= s:term_marker
|
||||
if has('nvim')
|
||||
call termopen(command, fzf)
|
||||
else
|
||||
let term_opts = {'exit_cb': function(fzf.on_exit)}
|
||||
if is_popup
|
||||
let term_opts.hidden = 1
|
||||
else
|
||||
let term_opts.curwin = 1
|
||||
endif
|
||||
let fzf.buf = term_start([&shell, &shellcmdflag, command], term_opts)
|
||||
if is_popup && exists('#TerminalWinOpen')
|
||||
doautocmd <nomodeline> TerminalWinOpen
|
||||
endif
|
||||
if !has('patch-8.0.1261') && !s:is_win
|
||||
call term_wait(fzf.buf, 20)
|
||||
endif
|
||||
endif
|
||||
finally
|
||||
call s:dopopd()
|
||||
endtry
|
||||
setlocal nospell bufhidden=wipe nobuflisted nonumber
|
||||
setf fzf
|
||||
startinsert
|
||||
return []
|
||||
endfunction
|
||||
|
||||
function! s:collect(temps) abort
|
||||
try
|
||||
return filereadable(a:temps.result) ? readfile(a:temps.result) : []
|
||||
finally
|
||||
for tf in values(a:temps)
|
||||
silent! call delete(tf)
|
||||
endfor
|
||||
endtry
|
||||
endfunction
|
||||
|
||||
function! s:callback(dict, lines) abort
|
||||
let popd = has_key(a:dict, 'pushd')
|
||||
if popd
|
||||
let w:fzf_pushd = a:dict.pushd
|
||||
endif
|
||||
|
||||
try
|
||||
if has_key(a:dict, 'sink')
|
||||
for line in a:lines
|
||||
if type(a:dict.sink) == 2
|
||||
call a:dict.sink(line)
|
||||
else
|
||||
execute a:dict.sink s:escape(line)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
if has_key(a:dict, 'sink*')
|
||||
call a:dict['sink*'](a:lines)
|
||||
endif
|
||||
catch
|
||||
if stridx(v:exception, ':E325:') < 0
|
||||
echoerr v:exception
|
||||
endif
|
||||
endtry
|
||||
|
||||
" We may have opened a new window or tab
|
||||
if popd
|
||||
let w:fzf_pushd = a:dict.pushd
|
||||
call s:dopopd()
|
||||
endif
|
||||
endfunction
|
||||
|
||||
if has('nvim')
|
||||
function s:create_popup(hl, opts) abort
|
||||
let buf = nvim_create_buf(v:false, v:true)
|
||||
let opts = extend({'relative': 'editor', 'style': 'minimal'}, a:opts)
|
||||
let border = has_key(opts, 'border') ? remove(opts, 'border') : []
|
||||
let win = nvim_open_win(buf, v:true, opts)
|
||||
call setwinvar(win, '&winhighlight', 'NormalFloat:'..a:hl)
|
||||
call setwinvar(win, '&colorcolumn', '')
|
||||
if !empty(border)
|
||||
call nvim_buf_set_lines(buf, 0, -1, v:true, border)
|
||||
endif
|
||||
return buf
|
||||
endfunction
|
||||
else
|
||||
function! s:create_popup(hl, opts) abort
|
||||
let is_frame = has_key(a:opts, 'border')
|
||||
let s:popup_create = {buf -> popup_create(buf, #{
|
||||
\ line: a:opts.row,
|
||||
\ col: a:opts.col,
|
||||
\ minwidth: a:opts.width,
|
||||
\ minheight: a:opts.height,
|
||||
\ zindex: 50 - is_frame,
|
||||
\ })}
|
||||
if is_frame
|
||||
let id = s:popup_create('')
|
||||
call setwinvar(id, '&wincolor', a:hl)
|
||||
call setbufline(winbufnr(id), 1, a:opts.border)
|
||||
execute 'autocmd BufWipeout * ++once call popup_close('..id..')'
|
||||
return winbufnr(id)
|
||||
else
|
||||
autocmd TerminalOpen * ++once call s:popup_create(str2nr(expand('<abuf>')))
|
||||
endif
|
||||
endfunction
|
||||
endif
|
||||
|
||||
function! s:popup(opts) abort
|
||||
" Support ambiwidth == 'double'
|
||||
let ambidouble = &ambiwidth == 'double' ? 2 : 1
|
||||
|
||||
" Size and position
|
||||
let width = min([max([0, float2nr(&columns * a:opts.width)]), &columns])
|
||||
let width += width % ambidouble
|
||||
let height = min([max([0, float2nr(&lines * a:opts.height)]), &lines - has('nvim')])
|
||||
let row = float2nr(get(a:opts, 'yoffset', 0.5) * (&lines - height))
|
||||
let col = float2nr(get(a:opts, 'xoffset', 0.5) * (&columns - width))
|
||||
|
||||
" Managing the differences
|
||||
let row = min([max([0, row]), &lines - has('nvim') - height])
|
||||
let col = min([max([0, col]), &columns - width])
|
||||
let row += !has('nvim')
|
||||
let col += !has('nvim')
|
||||
|
||||
" Border style
|
||||
let style = tolower(get(a:opts, 'border', 'rounded'))
|
||||
if !has_key(a:opts, 'border') && !get(a:opts, 'rounded', 1)
|
||||
let style = 'sharp'
|
||||
endif
|
||||
|
||||
if style =~ 'vertical\|left\|right'
|
||||
let mid = style == 'vertical' ? '│' .. repeat(' ', width - 2 * ambidouble) .. '│' :
|
||||
\ style == 'left' ? '│' .. repeat(' ', width - 1 * ambidouble)
|
||||
\ : repeat(' ', width - 1 * ambidouble) .. '│'
|
||||
let border = repeat([mid], height)
|
||||
let shift = { 'row': 0, 'col': style == 'right' ? 0 : 2, 'width': style == 'vertical' ? -4 : -2, 'height': 0 }
|
||||
elseif style =~ 'horizontal\|top\|bottom'
|
||||
let hor = repeat('─', width / ambidouble)
|
||||
let mid = repeat(' ', width)
|
||||
let border = style == 'horizontal' ? [hor] + repeat([mid], height - 2) + [hor] :
|
||||
\ style == 'top' ? [hor] + repeat([mid], height - 1)
|
||||
\ : repeat([mid], height - 1) + [hor]
|
||||
let shift = { 'row': style == 'bottom' ? 0 : 1, 'col': 0, 'width': 0, 'height': style == 'horizontal' ? -2 : -1 }
|
||||
else
|
||||
let edges = style == 'sharp' ? ['┌', '┐', '└', '┘'] : ['╭', '╮', '╰', '╯']
|
||||
let bar = repeat('─', width / ambidouble - 2)
|
||||
let top = edges[0] .. bar .. edges[1]
|
||||
let mid = '│' .. repeat(' ', width - 2 * ambidouble) .. '│'
|
||||
let bot = edges[2] .. bar .. edges[3]
|
||||
let border = [top] + repeat([mid], height - 2) + [bot]
|
||||
let shift = { 'row': 1, 'col': 2, 'width': -4, 'height': -2 }
|
||||
endif
|
||||
|
||||
let highlight = get(a:opts, 'highlight', 'Comment')
|
||||
let frame = s:create_popup(highlight, {
|
||||
\ 'row': row, 'col': col, 'width': width, 'height': height, 'border': border
|
||||
\ })
|
||||
call s:create_popup('Normal', {
|
||||
\ 'row': row + shift.row, 'col': col + shift.col, 'width': width + shift.width, 'height': height + shift.height
|
||||
\ })
|
||||
if has('nvim')
|
||||
execute 'autocmd BufWipeout <buffer> bwipeout '..frame
|
||||
endif
|
||||
endfunction
|
||||
|
||||
let s:default_action = {
|
||||
\ 'ctrl-t': 'tab split',
|
||||
\ 'ctrl-x': 'split',
|
||||
\ 'ctrl-v': 'vsplit' }
|
||||
|
||||
function! s:shortpath()
|
||||
let short = fnamemodify(getcwd(), ':~:.')
|
||||
if !has('win32unix')
|
||||
let short = pathshorten(short)
|
||||
endif
|
||||
let slash = (s:is_win && !&shellslash) ? '\' : '/'
|
||||
return empty(short) ? '~'.slash : short . (short =~ escape(slash, '\').'$' ? '' : slash)
|
||||
endfunction
|
||||
|
||||
function! s:cmd(bang, ...) abort
|
||||
let args = copy(a:000)
|
||||
let opts = { 'options': ['--multi'] }
|
||||
if len(args) && isdirectory(expand(args[-1]))
|
||||
let opts.dir = substitute(substitute(remove(args, -1), '\\\(["'']\)', '\1', 'g'), '[/\\]*$', '/', '')
|
||||
if s:is_win && !&shellslash
|
||||
let opts.dir = substitute(opts.dir, '/', '\\', 'g')
|
||||
endif
|
||||
let prompt = opts.dir
|
||||
else
|
||||
let prompt = s:shortpath()
|
||||
endif
|
||||
let prompt = strwidth(prompt) < &columns - 20 ? prompt : '> '
|
||||
call extend(opts.options, ['--prompt', prompt])
|
||||
call extend(opts.options, args)
|
||||
call fzf#run(fzf#wrap('FZF', opts, a:bang))
|
||||
endfunction
|
||||
|
||||
command! -nargs=* -complete=dir -bang FZF call s:cmd(<bang>0, <f-args>)
|
||||
|
||||
let &cpo = s:cpo_save
|
||||
unlet s:cpo_save
|
||||
@@ -0,0 +1,372 @@
|
||||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ completion.bash
|
||||
#
|
||||
# - $FZF_TMUX (default: 0)
|
||||
# - $FZF_TMUX_OPTS (default: empty)
|
||||
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
||||
# - $FZF_COMPLETION_OPTS (default: empty)
|
||||
|
||||
if [[ $- =~ i ]]; then
|
||||
|
||||
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
||||
if ! declare -f _fzf_compgen_path > /dev/null; then
|
||||
_fzf_compgen_path() {
|
||||
echo "$1"
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
||||
_fzf_compgen_dir() {
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
###########################################################
|
||||
|
||||
# To redraw line after fzf closes (printf '\e[5n')
|
||||
bind '"\e[0n": redraw-current-line'
|
||||
|
||||
__fzf_comprun() {
|
||||
if [ "$(type -t _fzf_comprun 2>&1)" = function ]; then
|
||||
_fzf_comprun "$@"
|
||||
elif [ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; }; then
|
||||
shift
|
||||
fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- "$@"
|
||||
else
|
||||
shift
|
||||
fzf "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_orig_completion_filter() {
|
||||
sed 's/^\(.*-F\) *\([^ ]*\).* \([^ ]*\)$/export _fzf_orig_completion_\3="\1 %s \3 #\2"; [[ "\1" = *" -o nospace "* ]] \&\& [[ ! "$__fzf_nospace_commands" = *" \3 "* ]] \&\& __fzf_nospace_commands="$__fzf_nospace_commands \3 ";/' |
|
||||
awk -F= '{OFS = FS} {gsub(/[^A-Za-z0-9_= ;]/, "_", $1);}1'
|
||||
}
|
||||
|
||||
_fzf_opts_completion() {
|
||||
local cur prev opts
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
opts="
|
||||
-x --extended
|
||||
-e --exact
|
||||
--algo
|
||||
-i +i
|
||||
-n --nth
|
||||
--with-nth
|
||||
-d --delimiter
|
||||
+s --no-sort
|
||||
--tac
|
||||
--tiebreak
|
||||
-m --multi
|
||||
--no-mouse
|
||||
--bind
|
||||
--cycle
|
||||
--no-hscroll
|
||||
--jump-labels
|
||||
--height
|
||||
--literal
|
||||
--reverse
|
||||
--margin
|
||||
--inline-info
|
||||
--prompt
|
||||
--pointer
|
||||
--marker
|
||||
--header
|
||||
--header-lines
|
||||
--ansi
|
||||
--tabstop
|
||||
--color
|
||||
--no-bold
|
||||
--history
|
||||
--history-size
|
||||
--preview
|
||||
--preview-window
|
||||
-q --query
|
||||
-1 --select-1
|
||||
-0 --exit-0
|
||||
-f --filter
|
||||
--print-query
|
||||
--expect
|
||||
--sync"
|
||||
|
||||
case "${prev}" in
|
||||
--tiebreak)
|
||||
COMPREPLY=( $(compgen -W "length begin end index" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
--color)
|
||||
COMPREPLY=( $(compgen -W "dark light 16 bw" -- "$cur") )
|
||||
return 0
|
||||
;;
|
||||
--history)
|
||||
COMPREPLY=()
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$cur" =~ ^-|\+ ]]; then
|
||||
COMPREPLY=( $(compgen -W "${opts}" -- "$cur") )
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_fzf_handle_dynamic_completion() {
|
||||
local cmd orig_var orig ret orig_cmd orig_complete
|
||||
cmd="$1"
|
||||
shift
|
||||
orig_cmd="$1"
|
||||
orig_var="_fzf_orig_completion_$cmd"
|
||||
orig="${!orig_var##*#}"
|
||||
if [ -n "$orig" ] && type "$orig" > /dev/null 2>&1; then
|
||||
$orig "$@"
|
||||
elif [ -n "$_fzf_completion_loader" ]; then
|
||||
orig_complete=$(complete -p "$orig_cmd" 2> /dev/null)
|
||||
_completion_loader "$@"
|
||||
ret=$?
|
||||
# _completion_loader may not have updated completion for the command
|
||||
if [ "$(complete -p "$orig_cmd" 2> /dev/null)" != "$orig_complete" ]; then
|
||||
eval "$(complete | command grep " -F.* $orig_cmd$" | __fzf_orig_completion_filter)"
|
||||
if [[ "$__fzf_nospace_commands" = *" $orig_cmd "* ]]; then
|
||||
eval "${orig_complete/ -F / -o nospace -F }"
|
||||
else
|
||||
eval "$orig_complete"
|
||||
fi
|
||||
fi
|
||||
return $ret
|
||||
fi
|
||||
}
|
||||
|
||||
__fzf_generic_path_completion() {
|
||||
local cur base dir leftover matches trigger cmd
|
||||
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
||||
COMPREPLY=()
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == *"$trigger" ]]; then
|
||||
base=${cur:0:${#cur}-${#trigger}}
|
||||
eval "base=$base"
|
||||
|
||||
[[ $base = *"/"* ]] && dir="$base"
|
||||
while true; do
|
||||
if [ -z "$dir" ] || [ -d "$dir" ]; then
|
||||
leftover=${base/#"$dir"}
|
||||
leftover=${leftover/#\/}
|
||||
[ -z "$dir" ] && dir='.'
|
||||
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
||||
matches=$(eval "$1 $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $2" __fzf_comprun "$4" -q "$leftover" | while read -r item; do
|
||||
printf "%q$3 " "$item"
|
||||
done)
|
||||
matches=${matches% }
|
||||
[[ -z "$3" ]] && [[ "$__fzf_nospace_commands" = *" ${COMP_WORDS[0]} "* ]] && matches="$matches "
|
||||
if [ -n "$matches" ]; then
|
||||
COMPREPLY=( "$matches" )
|
||||
else
|
||||
COMPREPLY=( "$cur" )
|
||||
fi
|
||||
printf '\e[5n'
|
||||
return 0
|
||||
fi
|
||||
dir=$(dirname "$dir")
|
||||
[[ "$dir" =~ /$ ]] || dir="$dir"/
|
||||
done
|
||||
else
|
||||
shift
|
||||
shift
|
||||
shift
|
||||
_fzf_handle_dynamic_completion "$cmd" "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
_fzf_complete() {
|
||||
# Split arguments around --
|
||||
local args rest str_arg i sep
|
||||
args=("$@")
|
||||
sep=
|
||||
for i in "${!args[@]}"; do
|
||||
if [[ "${args[$i]}" = -- ]]; then
|
||||
sep=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -n "$sep" ]]; then
|
||||
str_arg=
|
||||
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
|
||||
args=("${args[@]:0:$sep}")
|
||||
else
|
||||
str_arg=$1
|
||||
args=()
|
||||
shift
|
||||
rest=("$@")
|
||||
fi
|
||||
|
||||
local cur selected trigger cmd post
|
||||
post="$(caller 0 | awk '{print $2}')_post"
|
||||
type -t "$post" > /dev/null 2>&1 || post=cat
|
||||
|
||||
cmd="${COMP_WORDS[0]//[^A-Za-z0-9_=]/_}"
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ "$cur" == *"$trigger" ]]; then
|
||||
cur=${cur:0:${#cur}-${#trigger}}
|
||||
|
||||
selected=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "${rest[0]}" "${args[@]}" -q "$cur" | $post | tr '\n' ' ')
|
||||
selected=${selected% } # Strip trailing space not to repeat "-o nospace"
|
||||
if [ -n "$selected" ]; then
|
||||
COMPREPLY=("$selected")
|
||||
else
|
||||
COMPREPLY=("$cur")
|
||||
fi
|
||||
printf '\e[5n'
|
||||
return 0
|
||||
else
|
||||
_fzf_handle_dynamic_completion "$cmd" "${rest[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
_fzf_path_completion() {
|
||||
__fzf_generic_path_completion _fzf_compgen_path "-m" "" "$@"
|
||||
}
|
||||
|
||||
# Deprecated. No file only completion.
|
||||
_fzf_file_completion() {
|
||||
_fzf_path_completion "$@"
|
||||
}
|
||||
|
||||
_fzf_dir_completion() {
|
||||
__fzf_generic_path_completion _fzf_compgen_dir "" "/" "$@"
|
||||
}
|
||||
|
||||
_fzf_complete_kill() {
|
||||
local trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
local cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
if [[ -z "$cur" ]]; then
|
||||
COMP_WORDS[$COMP_CWORD]=$trigger
|
||||
elif [[ "$cur" != *"$trigger" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_fzf_proc_completion "$@"
|
||||
}
|
||||
|
||||
_fzf_proc_completion() {
|
||||
_fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
|
||||
command ps -ef | sed 1d
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_proc_completion_post() {
|
||||
awk '{print $2}'
|
||||
}
|
||||
|
||||
_fzf_host_completion() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
cat <(cat ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \
|
||||
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
|
||||
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
|
||||
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_var_completion() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_alias_completion() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
alias | sed 's/=.*//' | sed 's/.* //'
|
||||
)
|
||||
}
|
||||
|
||||
# fzf options
|
||||
complete -o default -F _fzf_opts_completion fzf
|
||||
|
||||
d_cmds="${FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir}"
|
||||
a_cmds="
|
||||
awk cat diff diff3
|
||||
emacs emacsclient ex file ftp g++ gcc gvim head hg java
|
||||
javac ld less more mvim nvim patch perl python ruby
|
||||
sed sftp sort source tail tee uniq vi view vim wc xdg-open
|
||||
basename bunzip2 bzip2 chmod chown curl cp dirname du
|
||||
find git grep gunzip gzip hg jar
|
||||
ln ls mv open rm rsync scp
|
||||
svn tar unzip zip"
|
||||
|
||||
# Preserve existing completion
|
||||
eval "$(complete |
|
||||
sed -E '/-F/!d; / _fzf/d; '"/ ($(echo $d_cmds $a_cmds | sed 's/ /|/g; s/+/\\+/g'))$/"'!d' |
|
||||
__fzf_orig_completion_filter)"
|
||||
|
||||
if type _completion_loader > /dev/null 2>&1; then
|
||||
_fzf_completion_loader=1
|
||||
fi
|
||||
|
||||
__fzf_defc() {
|
||||
local cmd func opts orig_var orig def
|
||||
cmd="$1"
|
||||
func="$2"
|
||||
opts="$3"
|
||||
orig_var="_fzf_orig_completion_${cmd//[^A-Za-z0-9_]/_}"
|
||||
orig="${!orig_var}"
|
||||
if [ -n "$orig" ]; then
|
||||
printf -v def "$orig" "$func"
|
||||
eval "$def"
|
||||
else
|
||||
complete -F "$func" $opts "$cmd"
|
||||
fi
|
||||
}
|
||||
|
||||
# Anything
|
||||
for cmd in $a_cmds; do
|
||||
__fzf_defc "$cmd" _fzf_path_completion "-o default -o bashdefault"
|
||||
done
|
||||
|
||||
# Directory
|
||||
for cmd in $d_cmds; do
|
||||
__fzf_defc "$cmd" _fzf_dir_completion "-o nospace -o dirnames"
|
||||
done
|
||||
|
||||
# Kill completion (supports empty completion trigger)
|
||||
complete -F _fzf_complete_kill -o default -o bashdefault kill
|
||||
|
||||
unset cmd d_cmds a_cmds
|
||||
|
||||
_fzf_setup_completion() {
|
||||
local kind fn cmd
|
||||
kind=$1
|
||||
fn=_fzf_${1}_completion
|
||||
if [[ $# -lt 2 ]] || ! type -t "$fn" > /dev/null; then
|
||||
echo "usage: ${FUNCNAME[0]} path|dir|var|alias|host|proc COMMANDS..."
|
||||
return 1
|
||||
fi
|
||||
shift
|
||||
eval "$(complete -p "$@" 2> /dev/null | grep -v "$fn" | __fzf_orig_completion_filter)"
|
||||
for cmd in "$@"; do
|
||||
case "$kind" in
|
||||
dir) __fzf_defc "$cmd" "$fn" "-o nospace -o dirnames" ;;
|
||||
var) __fzf_defc "$cmd" "$fn" "-o default -o nospace -v" ;;
|
||||
alias) __fzf_defc "$cmd" "$fn" "-a" ;;
|
||||
*) __fzf_defc "$cmd" "$fn" "-o default -o bashdefault" ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Environment variables / Aliases / Hosts
|
||||
_fzf_setup_completion 'var' export unset
|
||||
_fzf_setup_completion 'alias' unalias
|
||||
_fzf_setup_completion 'host' ssh telnet
|
||||
|
||||
fi
|
||||
@@ -0,0 +1,329 @@
|
||||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ completion.zsh
|
||||
#
|
||||
# - $FZF_TMUX (default: 0)
|
||||
# - $FZF_TMUX_OPTS (default: '-d 40%')
|
||||
# - $FZF_COMPLETION_TRIGGER (default: '**')
|
||||
# - $FZF_COMPLETION_OPTS (default: empty)
|
||||
|
||||
# Both branches of the following `if` do the same thing -- define
|
||||
# __fzf_completion_options such that `eval $__fzf_completion_options` sets
|
||||
# all options to the same values they currently have. We'll do just that at
|
||||
# the bottom of the file after changing options to what we prefer.
|
||||
#
|
||||
# IMPORTANT: Until we get to the `emulate` line, all words that *can* be quoted
|
||||
# *must* be quoted in order to prevent alias expansion. In addition, code must
|
||||
# be written in a way works with any set of zsh options. This is very tricky, so
|
||||
# careful when you change it.
|
||||
#
|
||||
# Start by loading the builtin zsh/parameter module. It provides `options`
|
||||
# associative array that stores current shell options.
|
||||
if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
|
||||
# This is the fast branch and it gets taken on virtually all Zsh installations.
|
||||
#
|
||||
# ${(kv)options[@]} expands to array of keys (option names) and values ("on"
|
||||
# or "off"). The subsequent expansion# with (j: :) flag joins all elements
|
||||
# together separated by spaces. __fzf_completion_options ends up with a value
|
||||
# like this: "options=(shwordsplit off aliases on ...)".
|
||||
__fzf_completion_options="options=(${(j: :)${(kv)options[@]}})"
|
||||
else
|
||||
# This branch is much slower because it forks to get the names of all
|
||||
# zsh options. It's possible to eliminate this fork but it's not worth the
|
||||
# trouble because this branch gets taken only on very ancient or broken
|
||||
# zsh installations.
|
||||
() {
|
||||
# That `()` above defines an anonymous function. This is essentially a scope
|
||||
# for local parameters. We use it to avoid polluting global scope.
|
||||
'local' '__fzf_opt'
|
||||
__fzf_completion_options="setopt"
|
||||
# `set -o` prints one line for every zsh option. Each line contains option
|
||||
# name, some spaces, and then either "on" or "off". We just want option names.
|
||||
# Expansion with (@f) flag splits a string into lines. The outer expansion
|
||||
# removes spaces and everything that follow them on every line. __fzf_opt
|
||||
# ends up iterating over option names: shwordsplit, aliases, etc.
|
||||
for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do
|
||||
if [[ -o "$__fzf_opt" ]]; then
|
||||
# Option $__fzf_opt is currently on, so remember to set it back on.
|
||||
__fzf_completion_options+=" -o $__fzf_opt"
|
||||
else
|
||||
# Option $__fzf_opt is currently off, so remember to set it back off.
|
||||
__fzf_completion_options+=" +o $__fzf_opt"
|
||||
fi
|
||||
done
|
||||
# The value of __fzf_completion_options here looks like this:
|
||||
# "setopt +o shwordsplit -o aliases ..."
|
||||
}
|
||||
fi
|
||||
|
||||
# Enable the default zsh options (those marked with <Z> in `man zshoptions`)
|
||||
# but without `aliases`. Aliases in functions are expanded when functions are
|
||||
# defined, so if we disable aliases here, we'll be sure to have no pesky
|
||||
# aliases in any of our functions. This way we won't need prefix every
|
||||
# command with `command` or to quote every word to defend against global
|
||||
# aliases. Note that `aliases` is not the only option that's important to
|
||||
# control. There are several others that could wreck havoc if they are set
|
||||
# to values we don't expect. With the following `emulate` command we
|
||||
# sidestep this issue entirely.
|
||||
'emulate' 'zsh' '-o' 'no_aliases'
|
||||
|
||||
# This brace is the start of try-always block. The `always` part is like
|
||||
# `finally` in lesser languages. We use it to *always* restore user options.
|
||||
{
|
||||
|
||||
# Bail out if not interactive shell.
|
||||
[[ -o interactive ]] || return 0
|
||||
|
||||
# To use custom commands instead of find, override _fzf_compgen_{path,dir}
|
||||
if ! declare -f _fzf_compgen_path > /dev/null; then
|
||||
_fzf_compgen_path() {
|
||||
echo "$1"
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o \( -type d -o -type f -o -type l \) \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
if ! declare -f _fzf_compgen_dir > /dev/null; then
|
||||
_fzf_compgen_dir() {
|
||||
command find -L "$1" \
|
||||
-name .git -prune -o -name .hg -prune -o -name .svn -prune -o -type d \
|
||||
-a -not -path "$1" -print 2> /dev/null | sed 's@^\./@@'
|
||||
}
|
||||
fi
|
||||
|
||||
###########################################################
|
||||
|
||||
__fzf_comprun() {
|
||||
if [[ "$(type _fzf_comprun 2>&1)" =~ function ]]; then
|
||||
_fzf_comprun "$@"
|
||||
elif [ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; }; then
|
||||
shift
|
||||
if [ -n "$FZF_TMUX_OPTS" ]; then
|
||||
fzf-tmux ${(Q)${(Z+n+)FZF_TMUX_OPTS}} -- "$@"
|
||||
else
|
||||
fzf-tmux -d ${FZF_TMUX_HEIGHT:-40%} -- "$@"
|
||||
fi
|
||||
else
|
||||
shift
|
||||
fzf "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
# Extract the name of the command. e.g. foo=1 bar baz**<tab>
|
||||
__fzf_extract_command() {
|
||||
local token tokens
|
||||
tokens=(${(z)1})
|
||||
for token in $tokens; do
|
||||
token=${(Q)token}
|
||||
if [[ "$token" =~ [[:alnum:]] && ! "$token" =~ "=" ]]; then
|
||||
echo "$token"
|
||||
return
|
||||
fi
|
||||
done
|
||||
echo "${tokens[1]}"
|
||||
}
|
||||
|
||||
__fzf_generic_path_completion() {
|
||||
local base lbuf cmd compgen fzf_opts suffix tail dir leftover matches
|
||||
base=$1
|
||||
lbuf=$2
|
||||
cmd=$(__fzf_extract_command "$lbuf")
|
||||
compgen=$3
|
||||
fzf_opts=$4
|
||||
suffix=$5
|
||||
tail=$6
|
||||
|
||||
setopt localoptions nonomatch
|
||||
eval "base=$base"
|
||||
[[ $base = *"/"* ]] && dir="$base"
|
||||
while [ 1 ]; do
|
||||
if [[ -z "$dir" || -d ${dir} ]]; then
|
||||
leftover=${base/#"$dir"}
|
||||
leftover=${leftover/#\/}
|
||||
[ -z "$dir" ] && dir='.'
|
||||
[ "$dir" != "/" ] && dir="${dir/%\//}"
|
||||
matches=$(eval "$compgen $(printf %q "$dir")" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS" __fzf_comprun "$cmd" ${(Q)${(Z+n+)fzf_opts}} -q "$leftover" | while read item; do
|
||||
echo -n "${(q)item}$suffix "
|
||||
done)
|
||||
matches=${matches% }
|
||||
if [ -n "$matches" ]; then
|
||||
LBUFFER="$lbuf$matches$tail"
|
||||
fi
|
||||
zle reset-prompt
|
||||
break
|
||||
fi
|
||||
dir=$(dirname "$dir")
|
||||
dir=${dir%/}/
|
||||
done
|
||||
}
|
||||
|
||||
_fzf_path_completion() {
|
||||
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_path \
|
||||
"-m" "" " "
|
||||
}
|
||||
|
||||
_fzf_dir_completion() {
|
||||
__fzf_generic_path_completion "$1" "$2" _fzf_compgen_dir \
|
||||
"" "/" ""
|
||||
}
|
||||
|
||||
_fzf_feed_fifo() (
|
||||
command rm -f "$1"
|
||||
mkfifo "$1"
|
||||
cat <&0 > "$1" &
|
||||
)
|
||||
|
||||
_fzf_complete() {
|
||||
setopt localoptions ksh_arrays
|
||||
# Split arguments around --
|
||||
local args rest str_arg i sep
|
||||
args=("$@")
|
||||
sep=
|
||||
for i in {0..${#args[@]}}; do
|
||||
if [[ "${args[$i]}" = -- ]]; then
|
||||
sep=$i
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -n "$sep" ]]; then
|
||||
str_arg=
|
||||
rest=("${args[@]:$((sep + 1)):${#args[@]}}")
|
||||
args=("${args[@]:0:$sep}")
|
||||
else
|
||||
str_arg=$1
|
||||
args=()
|
||||
shift
|
||||
rest=("$@")
|
||||
fi
|
||||
|
||||
local fifo lbuf cmd matches post
|
||||
fifo="${TMPDIR:-/tmp}/fzf-complete-fifo-$$"
|
||||
lbuf=${rest[0]}
|
||||
cmd=$(__fzf_extract_command "$lbuf")
|
||||
post="${funcstack[1]}_post"
|
||||
type $post > /dev/null 2>&1 || post=cat
|
||||
|
||||
_fzf_feed_fifo "$fifo"
|
||||
matches=$(FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_COMPLETION_OPTS $str_arg" __fzf_comprun "$cmd" "${args[@]}" -q "${(Q)prefix}" < "$fifo" | $post | tr '\n' ' ')
|
||||
if [ -n "$matches" ]; then
|
||||
LBUFFER="$lbuf$matches"
|
||||
fi
|
||||
zle reset-prompt
|
||||
command rm -f "$fifo"
|
||||
}
|
||||
|
||||
_fzf_complete_telnet() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0' |
|
||||
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_ssh() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
setopt localoptions nonomatch
|
||||
command cat <(cat ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?]') \
|
||||
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
|
||||
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
|
||||
awk '{if (length($2) > 0) {print $2}}' | sort -u
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_export() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_unset() {
|
||||
_fzf_complete -m -- "$@" < <(
|
||||
declare -xp | sed 's/=.*//' | sed 's/.* //'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_unalias() {
|
||||
_fzf_complete +m -- "$@" < <(
|
||||
alias | sed 's/=.*//'
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_kill() {
|
||||
_fzf_complete -m --preview 'echo {}' --preview-window down:3:wrap --min-height 15 -- "$@" < <(
|
||||
command ps -ef | sed 1d
|
||||
)
|
||||
}
|
||||
|
||||
_fzf_complete_kill_post() {
|
||||
awk '{print $2}'
|
||||
}
|
||||
|
||||
fzf-completion() {
|
||||
local tokens cmd prefix trigger tail matches lbuf d_cmds
|
||||
setopt localoptions noshwordsplit noksh_arrays noposixbuiltins
|
||||
|
||||
# http://zsh.sourceforge.net/FAQ/zshfaq03.html
|
||||
# http://zsh.sourceforge.net/Doc/Release/Expansion.html#Parameter-Expansion-Flags
|
||||
tokens=(${(z)LBUFFER})
|
||||
if [ ${#tokens} -lt 1 ]; then
|
||||
zle ${fzf_default_completion:-expand-or-complete}
|
||||
return
|
||||
fi
|
||||
|
||||
cmd=$(__fzf_extract_command "$LBUFFER")
|
||||
|
||||
# Explicitly allow for empty trigger.
|
||||
trigger=${FZF_COMPLETION_TRIGGER-'**'}
|
||||
[ -z "$trigger" -a ${LBUFFER[-1]} = ' ' ] && tokens+=("")
|
||||
|
||||
# When the trigger starts with ';', it becomes a separate token
|
||||
if [[ ${LBUFFER} = *"${tokens[-2]}${tokens[-1]}" ]]; then
|
||||
tokens[-2]="${tokens[-2]}${tokens[-1]}"
|
||||
tokens=(${tokens[0,-2]})
|
||||
fi
|
||||
|
||||
lbuf=$LBUFFER
|
||||
tail=${LBUFFER:$(( ${#LBUFFER} - ${#trigger} ))}
|
||||
# Kill completion (do not require trigger sequence)
|
||||
if [ "$cmd" = kill -a ${LBUFFER[-1]} = ' ' ]; then
|
||||
tail=$trigger
|
||||
tokens+=$trigger
|
||||
lbuf="$lbuf$trigger"
|
||||
fi
|
||||
|
||||
# Trigger sequence given
|
||||
if [ ${#tokens} -gt 1 -a "$tail" = "$trigger" ]; then
|
||||
d_cmds=(${=FZF_COMPLETION_DIR_COMMANDS:-cd pushd rmdir})
|
||||
|
||||
[ -z "$trigger" ] && prefix=${tokens[-1]} || prefix=${tokens[-1]:0:-${#trigger}}
|
||||
[ -n "${tokens[-1]}" ] && lbuf=${lbuf:0:-${#tokens[-1]}}
|
||||
|
||||
if eval "type _fzf_complete_${cmd} > /dev/null"; then
|
||||
prefix="$prefix" eval _fzf_complete_${cmd} ${(q)lbuf}
|
||||
elif [ ${d_cmds[(i)$cmd]} -le ${#d_cmds} ]; then
|
||||
_fzf_dir_completion "$prefix" "$lbuf"
|
||||
else
|
||||
_fzf_path_completion "$prefix" "$lbuf"
|
||||
fi
|
||||
# Fall back to default completion
|
||||
else
|
||||
zle ${fzf_default_completion:-expand-or-complete}
|
||||
fi
|
||||
}
|
||||
|
||||
[ -z "$fzf_default_completion" ] && {
|
||||
binding=$(bindkey '^I')
|
||||
[[ $binding =~ 'undefined-key' ]] || fzf_default_completion=$binding[(s: :w)2]
|
||||
unset binding
|
||||
}
|
||||
|
||||
zle -N fzf-completion
|
||||
bindkey '^I' fzf-completion
|
||||
|
||||
} always {
|
||||
# Restore the original options.
|
||||
eval $__fzf_completion_options
|
||||
'unset' '__fzf_completion_options'
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ key-bindings.bash
|
||||
#
|
||||
# - $FZF_TMUX_OPTS
|
||||
# - $FZF_CTRL_T_COMMAND
|
||||
# - $FZF_CTRL_T_OPTS
|
||||
# - $FZF_CTRL_R_OPTS
|
||||
# - $FZF_ALT_C_COMMAND
|
||||
# - $FZF_ALT_C_OPTS
|
||||
|
||||
# Key bindings
|
||||
# ------------
|
||||
__fzf_select__() {
|
||||
local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type f -print \
|
||||
-o -type d -print \
|
||||
-o -type l -print 2> /dev/null | cut -b3-"}"
|
||||
eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" $(__fzfcmd) -m "$@" | while read -r item; do
|
||||
printf '%q ' "$item"
|
||||
done
|
||||
echo
|
||||
}
|
||||
|
||||
if [[ $- =~ i ]]; then
|
||||
|
||||
__fzfcmd() {
|
||||
[ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; } &&
|
||||
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
|
||||
}
|
||||
|
||||
fzf-file-widget() {
|
||||
local selected="$(__fzf_select__)"
|
||||
READLINE_LINE="${READLINE_LINE:0:$READLINE_POINT}$selected${READLINE_LINE:$READLINE_POINT}"
|
||||
READLINE_POINT=$(( READLINE_POINT + ${#selected} ))
|
||||
}
|
||||
|
||||
__fzf_cd__() {
|
||||
local cmd dir
|
||||
cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type d -print 2> /dev/null | cut -b3-"}"
|
||||
dir=$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m) && printf 'cd %q' "$dir"
|
||||
}
|
||||
|
||||
__fzf_history__() {
|
||||
local output
|
||||
output=$(
|
||||
builtin fc -lnr -2147483648 |
|
||||
last_hist=$(HISTTIMEFORMAT='' builtin history 1) perl -n -l0 -e 'BEGIN { getc; $/ = "\n\t"; $HISTCMD = $ENV{last_hist} + 1 } s/^[ *]//; print $HISTCMD - $. . "\t$_" if !$seen{$_}++' |
|
||||
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m --read0" $(__fzfcmd) --query "$READLINE_LINE"
|
||||
) || return
|
||||
READLINE_LINE=${output#*$'\t'}
|
||||
if [ -z "$READLINE_POINT" ]; then
|
||||
echo "$READLINE_LINE"
|
||||
else
|
||||
READLINE_POINT=0x7fffffff
|
||||
fi
|
||||
}
|
||||
|
||||
# Required to refresh the prompt after fzf
|
||||
bind -m emacs-standard '"\er": redraw-current-line'
|
||||
|
||||
bind -m vi-command '"\C-z": emacs-editing-mode'
|
||||
bind -m vi-insert '"\C-z": emacs-editing-mode'
|
||||
bind -m emacs-standard '"\C-z": vi-editing-mode'
|
||||
|
||||
if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
|
||||
# CTRL-T - Paste the selected file path into the command line
|
||||
bind -m emacs-standard '"\C-t": " \C-b\C-k \C-u`__fzf_select__`\e\C-e\er\C-a\C-y\C-h\C-e\e \C-y\ey\C-x\C-x\C-f"'
|
||||
bind -m vi-command '"\C-t": "\C-z\C-t\C-z"'
|
||||
bind -m vi-insert '"\C-t": "\C-z\C-t\C-z"'
|
||||
|
||||
# CTRL-R - Paste the selected command from history into the command line
|
||||
bind -m emacs-standard '"\C-r": "\C-e \C-u\C-y\ey\C-u"$(__fzf_history__)"\e\C-e\er"'
|
||||
bind -m vi-command '"\C-r": "\C-z\C-r\C-z"'
|
||||
bind -m vi-insert '"\C-r": "\C-z\C-r\C-z"'
|
||||
else
|
||||
# CTRL-T - Paste the selected file path into the command line
|
||||
bind -m emacs-standard -x '"\C-t": fzf-file-widget'
|
||||
bind -m vi-command -x '"\C-t": fzf-file-widget'
|
||||
bind -m vi-insert -x '"\C-t": fzf-file-widget'
|
||||
|
||||
# CTRL-R - Paste the selected command from history into the command line
|
||||
bind -m emacs-standard -x '"\C-r": __fzf_history__'
|
||||
bind -m vi-command -x '"\C-r": __fzf_history__'
|
||||
bind -m vi-insert -x '"\C-r": __fzf_history__'
|
||||
fi
|
||||
|
||||
# ALT-C - cd into the selected directory
|
||||
bind -m emacs-standard '"\ec": " \C-b\C-k \C-u`__fzf_cd__`\e\C-e\er\C-m\C-y\C-h\e \C-y\ey\C-x\C-x\C-d"'
|
||||
bind -m vi-command '"\ec": "\C-z\ec\C-z"'
|
||||
bind -m vi-insert '"\ec": "\C-z\ec\C-z"'
|
||||
|
||||
fi
|
||||
@@ -0,0 +1,161 @@
|
||||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ key-bindings.fish
|
||||
#
|
||||
# - $FZF_TMUX_OPTS
|
||||
# - $FZF_CTRL_T_COMMAND
|
||||
# - $FZF_CTRL_T_OPTS
|
||||
# - $FZF_CTRL_R_OPTS
|
||||
# - $FZF_ALT_C_COMMAND
|
||||
# - $FZF_ALT_C_OPTS
|
||||
|
||||
# Key bindings
|
||||
# ------------
|
||||
function fzf_key_bindings
|
||||
|
||||
# Store current token in $dir as root for the 'find' command
|
||||
function fzf-file-widget -d "List files and folders"
|
||||
set -l commandline (__fzf_parse_commandline)
|
||||
set -l dir $commandline[1]
|
||||
set -l fzf_query $commandline[2]
|
||||
|
||||
# "-path \$dir'*/\\.*'" matches hidden files/folders inside $dir but not
|
||||
# $dir itself, even if hidden.
|
||||
test -n "$FZF_CTRL_T_COMMAND"; or set -l FZF_CTRL_T_COMMAND "
|
||||
command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
|
||||
-o -type f -print \
|
||||
-o -type d -print \
|
||||
-o -type l -print 2> /dev/null | sed 's@^\./@@'"
|
||||
|
||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
||||
begin
|
||||
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS"
|
||||
eval "$FZF_CTRL_T_COMMAND | "(__fzfcmd)' -m --query "'$fzf_query'"' | while read -l r; set result $result $r; end
|
||||
end
|
||||
if [ -z "$result" ]
|
||||
commandline -f repaint
|
||||
return
|
||||
else
|
||||
# Remove last token from commandline.
|
||||
commandline -t ""
|
||||
end
|
||||
for i in $result
|
||||
commandline -it -- (string escape $i)
|
||||
commandline -it -- ' '
|
||||
end
|
||||
commandline -f repaint
|
||||
end
|
||||
|
||||
function fzf-history-widget -d "Show command history"
|
||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
||||
begin
|
||||
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT $FZF_DEFAULT_OPTS --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS +m"
|
||||
|
||||
set -l FISH_MAJOR (echo $version | cut -f1 -d.)
|
||||
set -l FISH_MINOR (echo $version | cut -f2 -d.)
|
||||
|
||||
# history's -z flag is needed for multi-line support.
|
||||
# history's -z flag was added in fish 2.4.0, so don't use it for versions
|
||||
# before 2.4.0.
|
||||
if [ "$FISH_MAJOR" -gt 2 -o \( "$FISH_MAJOR" -eq 2 -a "$FISH_MINOR" -ge 4 \) ];
|
||||
history -z | eval (__fzfcmd) --read0 --print0 -q '(commandline)' | read -lz result
|
||||
and commandline -- $result
|
||||
else
|
||||
history | eval (__fzfcmd) -q '(commandline)' | read -l result
|
||||
and commandline -- $result
|
||||
end
|
||||
end
|
||||
commandline -f repaint
|
||||
end
|
||||
|
||||
function fzf-cd-widget -d "Change directory"
|
||||
set -l commandline (__fzf_parse_commandline)
|
||||
set -l dir $commandline[1]
|
||||
set -l fzf_query $commandline[2]
|
||||
|
||||
test -n "$FZF_ALT_C_COMMAND"; or set -l FZF_ALT_C_COMMAND "
|
||||
command find -L \$dir -mindepth 1 \\( -path \$dir'*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' \\) -prune \
|
||||
-o -type d -print 2> /dev/null | sed 's@^\./@@'"
|
||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
||||
begin
|
||||
set -lx FZF_DEFAULT_OPTS "--height $FZF_TMUX_HEIGHT --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS"
|
||||
eval "$FZF_ALT_C_COMMAND | "(__fzfcmd)' +m --query "'$fzf_query'"' | read -l result
|
||||
|
||||
if [ -n "$result" ]
|
||||
cd $result
|
||||
|
||||
# Remove last token from commandline.
|
||||
commandline -t ""
|
||||
end
|
||||
end
|
||||
|
||||
commandline -f repaint
|
||||
end
|
||||
|
||||
function __fzfcmd
|
||||
test -n "$FZF_TMUX"; or set FZF_TMUX 0
|
||||
test -n "$FZF_TMUX_HEIGHT"; or set FZF_TMUX_HEIGHT 40%
|
||||
if [ -n "$FZF_TMUX_OPTS" ]
|
||||
echo "fzf-tmux $FZF_TMUX_OPTS -- "
|
||||
else if [ $FZF_TMUX -eq 1 ]
|
||||
echo "fzf-tmux -d$FZF_TMUX_HEIGHT -- "
|
||||
else
|
||||
echo "fzf"
|
||||
end
|
||||
end
|
||||
|
||||
bind \ct fzf-file-widget
|
||||
bind \cr fzf-history-widget
|
||||
bind \ec fzf-cd-widget
|
||||
|
||||
if bind -M insert > /dev/null 2>&1
|
||||
bind -M insert \ct fzf-file-widget
|
||||
bind -M insert \cr fzf-history-widget
|
||||
bind -M insert \ec fzf-cd-widget
|
||||
end
|
||||
|
||||
function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath and rest of token'
|
||||
# eval is used to do shell expansion on paths
|
||||
set -l commandline (eval "printf '%s' "(commandline -t))
|
||||
|
||||
if [ -z $commandline ]
|
||||
# Default to current directory with no --query
|
||||
set dir '.'
|
||||
set fzf_query ''
|
||||
else
|
||||
set dir (__fzf_get_dir $commandline)
|
||||
|
||||
if [ "$dir" = "." -a (string sub -l 1 $commandline) != '.' ]
|
||||
# if $dir is "." but commandline is not a relative path, this means no file path found
|
||||
set fzf_query $commandline
|
||||
else
|
||||
# Also remove trailing slash after dir, to "split" input properly
|
||||
set fzf_query (string replace -r "^$dir/?" '' "$commandline")
|
||||
end
|
||||
end
|
||||
|
||||
echo $dir
|
||||
echo $fzf_query
|
||||
end
|
||||
|
||||
function __fzf_get_dir -d 'Find the longest existing filepath from input string'
|
||||
set dir $argv
|
||||
|
||||
# Strip all trailing slashes. Ignore if $dir is root dir (/)
|
||||
if [ (string length $dir) -gt 1 ]
|
||||
set dir (string replace -r '/*$' '' $dir)
|
||||
end
|
||||
|
||||
# Iteratively check if dir exists and strip tail end of path
|
||||
while [ ! -d "$dir" ]
|
||||
# If path is absolute, this can keep going until ends up at /
|
||||
# If path is relative, this can keep going until entire input is consumed, dirname returns "."
|
||||
set dir (dirname "$dir")
|
||||
end
|
||||
|
||||
echo $dir
|
||||
end
|
||||
|
||||
end
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
# ____ ____
|
||||
# / __/___ / __/
|
||||
# / /_/_ / / /_
|
||||
# / __/ / /_/ __/
|
||||
# /_/ /___/_/ key-bindings.zsh
|
||||
#
|
||||
# - $FZF_TMUX_OPTS
|
||||
# - $FZF_CTRL_T_COMMAND
|
||||
# - $FZF_CTRL_T_OPTS
|
||||
# - $FZF_CTRL_R_OPTS
|
||||
# - $FZF_ALT_C_COMMAND
|
||||
# - $FZF_ALT_C_OPTS
|
||||
|
||||
# Key bindings
|
||||
# ------------
|
||||
|
||||
# The code at the top and the bottom of this file is the same as in completion.zsh.
|
||||
# Refer to that file for explanation.
|
||||
if 'zmodload' 'zsh/parameter' 2>'/dev/null' && (( ${+options} )); then
|
||||
__fzf_key_bindings_options="options=(${(j: :)${(kv)options[@]}})"
|
||||
else
|
||||
() {
|
||||
__fzf_key_bindings_options="setopt"
|
||||
'local' '__fzf_opt'
|
||||
for __fzf_opt in "${(@)${(@f)$(set -o)}%% *}"; do
|
||||
if [[ -o "$__fzf_opt" ]]; then
|
||||
__fzf_key_bindings_options+=" -o $__fzf_opt"
|
||||
else
|
||||
__fzf_key_bindings_options+=" +o $__fzf_opt"
|
||||
fi
|
||||
done
|
||||
}
|
||||
fi
|
||||
|
||||
'emulate' 'zsh' '-o' 'no_aliases'
|
||||
|
||||
{
|
||||
|
||||
[[ -o interactive ]] || return 0
|
||||
|
||||
# CTRL-T - Paste the selected file path(s) into the command line
|
||||
__fsel() {
|
||||
local cmd="${FZF_CTRL_T_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type f -print \
|
||||
-o -type d -print \
|
||||
-o -type l -print 2> /dev/null | cut -b3-"}"
|
||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||
eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_CTRL_T_OPTS" $(__fzfcmd) -m "$@" | while read item; do
|
||||
echo -n "${(q)item} "
|
||||
done
|
||||
local ret=$?
|
||||
echo
|
||||
return $ret
|
||||
}
|
||||
|
||||
__fzfcmd() {
|
||||
[ -n "$TMUX_PANE" ] && { [ "${FZF_TMUX:-0}" != 0 ] || [ -n "$FZF_TMUX_OPTS" ]; } &&
|
||||
echo "fzf-tmux ${FZF_TMUX_OPTS:--d${FZF_TMUX_HEIGHT:-40%}} -- " || echo "fzf"
|
||||
}
|
||||
|
||||
fzf-file-widget() {
|
||||
LBUFFER="${LBUFFER}$(__fsel)"
|
||||
local ret=$?
|
||||
zle reset-prompt
|
||||
return $ret
|
||||
}
|
||||
zle -N fzf-file-widget
|
||||
bindkey '^T' fzf-file-widget
|
||||
|
||||
# Ensure precmds are run after cd
|
||||
fzf-redraw-prompt() {
|
||||
local precmd
|
||||
for precmd in $precmd_functions; do
|
||||
$precmd
|
||||
done
|
||||
zle reset-prompt
|
||||
}
|
||||
zle -N fzf-redraw-prompt
|
||||
|
||||
# ALT-C - cd into the selected directory
|
||||
fzf-cd-widget() {
|
||||
local cmd="${FZF_ALT_C_COMMAND:-"command find -L . -mindepth 1 \\( -path '*/\\.*' -o -fstype 'sysfs' -o -fstype 'devfs' -o -fstype 'devtmpfs' -o -fstype 'proc' \\) -prune \
|
||||
-o -type d -print 2> /dev/null | cut -b3-"}"
|
||||
setopt localoptions pipefail no_aliases 2> /dev/null
|
||||
local dir="$(eval "$cmd" | FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} --reverse $FZF_DEFAULT_OPTS $FZF_ALT_C_OPTS" $(__fzfcmd) +m)"
|
||||
if [[ -z "$dir" ]]; then
|
||||
zle redisplay
|
||||
return 0
|
||||
fi
|
||||
cd "$dir"
|
||||
unset dir # ensure this doesn't end up appearing in prompt expansion
|
||||
local ret=$?
|
||||
zle fzf-redraw-prompt
|
||||
return $ret
|
||||
}
|
||||
zle -N fzf-cd-widget
|
||||
bindkey '\ec' fzf-cd-widget
|
||||
|
||||
# CTRL-R - Paste the selected command from history into the command line
|
||||
fzf-history-widget() {
|
||||
local selected num
|
||||
setopt localoptions noglobsubst noposixbuiltins pipefail no_aliases 2> /dev/null
|
||||
selected=( $(fc -rl 1 | perl -ne 'print if !$seen{(/^\s*[0-9]+\s+(.*)/, $1)}++' |
|
||||
FZF_DEFAULT_OPTS="--height ${FZF_TMUX_HEIGHT:-40%} $FZF_DEFAULT_OPTS -n2..,.. --tiebreak=index --bind=ctrl-r:toggle-sort $FZF_CTRL_R_OPTS --query=${(qqq)LBUFFER} +m" $(__fzfcmd)) )
|
||||
local ret=$?
|
||||
if [ -n "$selected" ]; then
|
||||
num=$selected[1]
|
||||
if [ -n "$num" ]; then
|
||||
zle vi-fetch-history -n $num
|
||||
fi
|
||||
fi
|
||||
zle reset-prompt
|
||||
return $ret
|
||||
}
|
||||
zle -N fzf-history-widget
|
||||
bindkey '^R' fzf-history-widget
|
||||
|
||||
} always {
|
||||
eval $__fzf_key_bindings_options
|
||||
'unset' '__fzf_key_bindings_options'
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
set suffixesadd=.js,.html
|
||||
@@ -0,0 +1,74 @@
|
||||
let s:bundlePath = resolve( expand('<sfile>:p:h' ) . '/../../' )
|
||||
|
||||
" Popout current split window to a new tab by saving curor position
|
||||
fun! OpenInNewTab(fname, ... )
|
||||
" let l:cWinPos = winnr()
|
||||
let l:totalWins = winnr('$')
|
||||
let l:tabOffset = 0
|
||||
let l:currentTabNo = tabpagenr()
|
||||
if l:totalWins == 1
|
||||
let l:tabOffset=1
|
||||
end
|
||||
if exists('a:1')
|
||||
if a:1 < l:currentTabNo
|
||||
let l:tabOffset = 0
|
||||
endif
|
||||
let l:targetTabNo = ( a:1-l:tabOffset )
|
||||
echo l:targetTabNo
|
||||
if l:targetTabNo < 1
|
||||
return
|
||||
endif
|
||||
|
||||
let save_cursor = getcurpos()
|
||||
execute 'close'
|
||||
execute 'tabn'.( l:targetTabNo)
|
||||
execute 'vs '.a:fname
|
||||
call setpos('.', save_cursor)
|
||||
else
|
||||
execute 'tabedit ' . a:fname
|
||||
end
|
||||
endfunction
|
||||
|
||||
" Open current window in n'th tab after current tab
|
||||
fun! OpenInNewTabI( ... )
|
||||
if exists('a:1')
|
||||
let l:targetTab = a:1
|
||||
else
|
||||
let l:targetTab = input('Enter tabNo: ')
|
||||
endif
|
||||
call OpenInNewTab( @%, l:targetTab )
|
||||
endfunction
|
||||
|
||||
fun! SpList( files, ... )
|
||||
let l:prefix = ''
|
||||
let l:suffix = ''
|
||||
if exists('a:1')
|
||||
let l:prefix = a:1
|
||||
endif
|
||||
if exists('a:2')
|
||||
let l:suffix = a:2
|
||||
endif
|
||||
|
||||
execute 'e ' . l:prefix . a:files[0] . l:suffix
|
||||
call remove( a:files, 0 )
|
||||
for file in a:files
|
||||
execute 'sp ' . l:prefix . file . l:suffix
|
||||
endfor
|
||||
endfunction
|
||||
|
||||
fun! OpenSnippets()
|
||||
let l:ftypes = split( &filetype , '\.')
|
||||
|
||||
let l:prefix = s:bundlePath .'/vim-snippets/snippets/'
|
||||
|
||||
let l:suffix = '.snippets'
|
||||
execute 'tabnew'
|
||||
call SpList( l:ftypes, l:prefix, l:suffix )
|
||||
endfunction
|
||||
|
||||
" Open current window in new tab
|
||||
nmap <C-W>t :call OpenInNewTab(@%)<CR>
|
||||
" Move current window to n'th tab
|
||||
command! -nargs=? Mt call OpenInNewTabI(<args>)
|
||||
" Open all snippet files for current filetype
|
||||
command! OpenSnippets call OpenSnippets()
|
||||
@@ -0,0 +1 @@
|
||||
github: [alerque, scrooloose]
|
||||
@@ -0,0 +1,17 @@
|
||||
name: Vint
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
vint:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@master
|
||||
- name: Run vint with reviewdog
|
||||
uses: reviewdog/action-vint@v1.0.1
|
||||
with:
|
||||
github_token: ${{ secrets.github_token }}
|
||||
reporter: github-pr-review
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
*~
|
||||
*.swp
|
||||
tags
|
||||
DEBUG
|
||||
@@ -0,0 +1,159 @@
|
||||
# NERD Commenter [](https://github.com/preservim/nerdcommenter/actions?workflow=Vint)
|
||||
|
||||
Comment functions so powerful—no comment necessary.
|
||||
|
||||
## Installation
|
||||
|
||||
### Via Plugin Manager (Recommended)
|
||||
|
||||
#### [Vim-Plug](https://github.com/junegunn/vim-plug)
|
||||
|
||||
1. Add `Plug 'preservim/nerdcommenter'` to your vimrc file.
|
||||
2. Reload your vimrc or restart
|
||||
3. Run `:PlugInstall`
|
||||
|
||||
#### [Vundle](https://github.com/VundleVim/Vundle.vim) or similar
|
||||
|
||||
1. Add `Plugin 'preservim/nerdcommenter'` to your vimrc file.
|
||||
2. Reload your vimrc or restart
|
||||
3. Run `:BundleInstall`
|
||||
|
||||
#### [NeoBundle](https://github.com/Shougo/neobundle.vim)
|
||||
|
||||
1. Add `NeoBundle 'preservim/nerdcommenter'` to your vimrc file.
|
||||
2. Reload your vimrc or restart
|
||||
3. Run `:NeoUpdate`
|
||||
|
||||
#### [Pathogen](https://github.com/tpope/vim-pathogen)
|
||||
|
||||
```sh
|
||||
cd ~/.vim/bundle
|
||||
git clone https://github.com/preservim/nerdcommenter.git
|
||||
```
|
||||
|
||||
### Manual Installation
|
||||
|
||||
#### Unix
|
||||
|
||||
(For Neovim, change `~/.vim/` to `~/.config/nvim/`.)
|
||||
|
||||
```sh
|
||||
curl -fLo ~/.vim/plugin/NERD_Commenter.vim --create-dirs \
|
||||
https://raw.githubusercontent.com/preservim/nerdcommenter/master/plugin/NERD_commenter.vim
|
||||
curl -fLo ~/.vim/doc/NERD_Commenter.txt --create-dirs \
|
||||
https://raw.githubusercontent.com/preservim/nerdcommenter/master/doc/NERD_commenter.txt
|
||||
```
|
||||
|
||||
#### Windows (PowerShell)
|
||||
|
||||
```powershell
|
||||
md ~\vimfiles\plugin
|
||||
md ~\vimfiles\doc
|
||||
$pluguri = 'https://raw.githubusercontent.com/preservim/nerdcommenter/master/plugin/NERD_commenter.vim'
|
||||
$docsuri = 'https://raw.githubusercontent.com/preservim/nerdcommenter/master/doc/NERD_commenter.txt'
|
||||
(New-Object Net.WebClient).DownloadFile($pluguri, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("~\vimfiles\plugin\NERD_commenter.vim"))
|
||||
(New-Object Net.WebClient).DownloadFile($docsuri, $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("~\vimfiles\doc\NERD_commenter.txt"))
|
||||
```
|
||||
|
||||
### Post Installation
|
||||
|
||||
Make sure that you have filetype plugins enabled, as the plugin makes use of **|commentstring|** where possible (which is usually set in a filetype plugin). See **|filetype-plugin-on|** for details, but the short version is make sure this line appears in your vimrc:
|
||||
|
||||
```sh
|
||||
filetype plugin on
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Documentation
|
||||
|
||||
Please see the vim help system for full documentation of all options: `:help nerdcommenter`
|
||||
|
||||
### Settings
|
||||
|
||||
Several settings can be added to your vimrc to change the default behavior. Some examples:
|
||||
|
||||
```vim
|
||||
" Add spaces after comment delimiters by default
|
||||
let g:NERDSpaceDelims = 1
|
||||
|
||||
" Use compact syntax for prettified multi-line comments
|
||||
let g:NERDCompactSexyComs = 1
|
||||
|
||||
" Align line-wise comment delimiters flush left instead of following code indentation
|
||||
let g:NERDDefaultAlign = 'left'
|
||||
|
||||
" Set a language to use its alternate delimiters by default
|
||||
let g:NERDAltDelims_java = 1
|
||||
|
||||
" Add your own custom formats or override the defaults
|
||||
let g:NERDCustomDelimiters = { 'c': { 'left': '/**','right': '*/' } }
|
||||
|
||||
" Allow commenting and inverting empty lines (useful when commenting a region)
|
||||
let g:NERDCommentEmptyLines = 1
|
||||
|
||||
" Enable trimming of trailing whitespace when uncommenting
|
||||
let g:NERDTrimTrailingWhitespace = 1
|
||||
|
||||
" Enable NERDCommenterToggle to check all selected lines is commented or not
|
||||
let g:NERDToggleCheckAllLines = 1
|
||||
```
|
||||
|
||||
### Default mappings
|
||||
|
||||
The following key mappings are provided by default (there is also a menu provided that contains menu items corresponding to all the below mappings):
|
||||
|
||||
Most of the following mappings are for normal/visual mode only. The **|NERDCommenterInsert|** mapping is for insert mode only.
|
||||
|
||||
* `[count]<leader>cc` **|NERDCommenterComment|**
|
||||
|
||||
Comment out the current line or text selected in visual mode.
|
||||
|
||||
* `[count]<leader>cn` **|NERDCommenterNested|**
|
||||
|
||||
Same as <leader>cc but forces nesting.
|
||||
|
||||
* `[count]<leader>c<space>` **|NERDCommenterToggle|**
|
||||
|
||||
Toggles the comment state of the selected line(s). If the topmost selected line is commented, all selected lines are uncommented and vice versa.
|
||||
|
||||
* `[count]<leader>cm` **|NERDCommenterMinimal|**
|
||||
|
||||
Comments the given lines using only one set of multipart delimiters.
|
||||
|
||||
* `[count]<leader>ci` **|NERDCommenterInvert|**
|
||||
|
||||
Toggles the comment state of the selected line(s) individually.
|
||||
|
||||
* `[count]<leader>cs` **|NERDCommenterSexy|**
|
||||
|
||||
Comments out the selected lines with a pretty block formatted layout.
|
||||
|
||||
* `[count]<leader>cy` **|NERDCommenterYank|**
|
||||
|
||||
Same as <leader>cc except that the commented line(s) are yanked first.
|
||||
|
||||
* `<leader>c$` **|NERDCommenterToEOL|**
|
||||
|
||||
Comments the current line from the cursor to the end of line.
|
||||
|
||||
* `<leader>cA` **|NERDCommenterAppend|**
|
||||
|
||||
Adds comment delimiters to the end of line and goes into insert mode between them.
|
||||
|
||||
* **|NERDCommenterInsert|**
|
||||
|
||||
Adds comment delimiters at the current cursor position and inserts between. Disabled by default.
|
||||
|
||||
* `<leader>ca` **|NERDCommenterAltDelims|**
|
||||
|
||||
Switches to the alternative set of delimiters.
|
||||
|
||||
* `[count]<leader>cl` **|NERDCommenterAlignLeft**
|
||||
`[count]<leader>cb` **|NERDCommenterAlignBoth**
|
||||
|
||||
Same as **|NERDCommenterComment|** except that the delimiters are aligned down the left side (`<leader>cl`) or both sides (`<leader>cb`).
|
||||
|
||||
* `[count]<leader>cu` **|NERDCommenterUncomment|**
|
||||
|
||||
Uncomments the selected line(s).
|
||||
@@ -0,0 +1,76 @@
|
||||
# written by travis jeffery <travisjeffery@gmail.com>
|
||||
# contributions by scrooloose <github:scrooloose>
|
||||
|
||||
require 'rake'
|
||||
require 'find'
|
||||
require 'pathname'
|
||||
|
||||
IGNORE = [/\.gitignore$/, /Rakefile$/]
|
||||
|
||||
files = `git ls-files`.split("\n")
|
||||
files.reject! { |f| IGNORE.any? { |re| f.match(re) } }
|
||||
|
||||
desc 'Zip up the project files'
|
||||
task :zip do
|
||||
zip_name = File.basename(File.dirname(__FILE__))
|
||||
zip_name.gsub!(/ /, '_')
|
||||
zip_name = "#{zip_name}.zip"
|
||||
|
||||
if File.exist?(zip_name)
|
||||
abort("Zip file #{zip_name} already exists. Remove it first.")
|
||||
end
|
||||
|
||||
puts "Creating zip file: #{zip_name}"
|
||||
system("zip #{zip_name} #{files.join(" ")}")
|
||||
end
|
||||
|
||||
desc 'Install plugin and documentation'
|
||||
task :install do
|
||||
vimfiles = if ENV['VIMFILES']
|
||||
ENV['VIMFILES']
|
||||
elsif RUBY_PLATFORM =~ /(win|w)32$/
|
||||
File.expand_path("~/vimfiles")
|
||||
else
|
||||
File.expand_path("~/.vim")
|
||||
end
|
||||
files.each do |file|
|
||||
target_file = File.join(vimfiles, file)
|
||||
FileUtils.mkdir_p File.dirname(target_file)
|
||||
FileUtils.cp file, target_file
|
||||
|
||||
puts "Installed #{file} to #{target_file}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
desc 'Pulls from origin'
|
||||
task :pull do
|
||||
puts "Updating local repo..."
|
||||
system("cd " << Dir.new(File.dirname(__FILE__)).path << " && git pull")
|
||||
end
|
||||
|
||||
desc 'Calls pull task and then install task'
|
||||
task :update => ['pull', 'install'] do
|
||||
puts "Update of vim script complete."
|
||||
end
|
||||
|
||||
desc 'Uninstall plugin and documentation'
|
||||
task :uninstall do
|
||||
vimfiles = if ENV['VIMFILES']
|
||||
ENV['VIMFILES']
|
||||
elsif RUBY_PLATFORM =~ /(win|w)32$/
|
||||
File.expand_path("~/vimfiles")
|
||||
else
|
||||
File.expand_path("~/.vim")
|
||||
end
|
||||
files.each do |file|
|
||||
target_file = File.join(vimfiles, file)
|
||||
FileUtils.rm target_file
|
||||
|
||||
puts "Uninstalled #{target_file}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
task :default => ['update']
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
.DS_Store
|
||||
.project
|
||||
doc
|
||||
distribution/
|
||||
.sourcescribe_index
|
||||
*.swp
|
||||
*.swo
|
||||
*.pyc
|
||||
cscope.out
|
||||
*~
|
||||
|
||||
# symlinks created for pathogen
|
||||
/ftplugin
|
||||
/doc
|
||||
|
||||
# Distribution files
|
||||
# */sparkup
|
||||
# */sparkup.py
|
||||
@@ -0,0 +1,48 @@
|
||||
# Makefile for sparkup distribution
|
||||
# TODO: this should use a separate build dir to copy SPARKUP_PY into.
|
||||
# SPARKUP_PY should not reside in the Vim runtime dir (getting not updated via Git!)
|
||||
SPARKUP_PY=sparkup.py
|
||||
VERSION=`date '+%Y%m%d'`
|
||||
README=README.md
|
||||
|
||||
.PHONY: all textmate vim textmate-dist vim-dist plugins plugins-pre generic all-dist
|
||||
all: plugins
|
||||
|
||||
plugins-pre:
|
||||
mkdir -p distribution
|
||||
|
||||
plugins: plugins-pre all-dist
|
||||
|
||||
textmate-dist: textmate
|
||||
cd TextMate && zip -9r ../distribution/sparkup-textmate-${VERSION}.zip . && cd ..
|
||||
|
||||
vim-dist: vim
|
||||
cd vim && zip -9r ../distribution/sparkup-vim-${VERSION}.zip . && cd ..
|
||||
|
||||
generic-dist: generic
|
||||
cd generic && zip -9r ../distribution/sparkup-generic-${VERSION}.zip . && cd ..
|
||||
|
||||
all-dist:
|
||||
zip -9r distribution/sparkup-${VERSION}.zip generic vim textmate README.md -x */sparkup-readme.txt
|
||||
cp distribution/sparkup-${VERSION}.zip distribution/sparkup-latest.zip
|
||||
|
||||
generic:
|
||||
cat ${SPARKUP_PY} > generic/sparkup
|
||||
chmod +x generic/sparkup
|
||||
#cp ${README} generic/sparkup-readme.txt
|
||||
|
||||
textmate:
|
||||
#cp ${README} TextMate/sparkup-readme.txt
|
||||
|
||||
vim: vim/doc/sparkup.txt
|
||||
|
||||
# create pathogen friendly structure
|
||||
vim-pathogen: vim ftplugin doc
|
||||
|
||||
ftplugin doc:
|
||||
ln -s vim/$@
|
||||
|
||||
# Add asterisks to title, so it gets matched by `:helptags`
|
||||
vim/doc/sparkup.txt: ${README}
|
||||
mkdir -p $(@D)
|
||||
sed '1s/.*/*\0*/' $< > $@
|
||||
@@ -0,0 +1,175 @@
|
||||
Sparkup
|
||||
=======
|
||||
|
||||
**Sparkup lets you write HTML code faster.** Don't believe us?
|
||||
[See it in action!](http://www.youtube.com/watch?v=Jw3jipcenKc)
|
||||
|
||||
Fixed by Zhao:
|
||||
This is a fork of original version. This version support both python 2 and 3.
|
||||
|
||||
You can write HTML in a CSS-like syntax, and have Sparkup handle the expansion to full HTML
|
||||
code. It is meant to help you write long HTML blocks in your text editor by letting you
|
||||
type less characters than needed.
|
||||
|
||||
Sparkup is written in Python, and requires Python 2.5 or newer (2.5 is preinstalled in
|
||||
Mac OS X Leopard). Sparkup also offers integration into common text editors. Support for VIM
|
||||
and TextMate are currently included.
|
||||
|
||||
A short screencast is available here:
|
||||
[http://www.youtube.com/watch?v=Jw3jipcenKc](http://www.youtube.com/watch?v=Jw3jipcenKc)
|
||||
|
||||
Usage and installation
|
||||
----------------------
|
||||
You may download Sparkup from GitHub. [Download the latest version here](http://github.com/rstacruz/sparkup/downloads).
|
||||
|
||||
- **TextMate**: Simply double-click on the `Sparkup.tmbundle` package in Finder. This
|
||||
will install it automatically. In TextMate, open an HTML file (or set the document type to
|
||||
HTML) type in something (e.g., `#header > h1`), then press `Ctrl` + `E`. Pressing `Tab`
|
||||
will cycle through empty elements.
|
||||
|
||||
- **VIM**: See the `vim/README.txt` file for installation. In VIM,
|
||||
create or open an HTML file (or set the filetype to ``html``), type in something (e.g.
|
||||
`#header > h1`), then press `<C-E>` whilst in **insert mode** to expand to HTML.
|
||||
Pressing `<C-n>` will cycle through empty elements. Variables specified in
|
||||
`vim/README.txt` can be used to customise key mappings, and to add **normal mode** mappings
|
||||
as well.
|
||||
|
||||
- **Others/command line use**: You may put `sparkup` in your `$PATH` somewhere. You may then
|
||||
invoke it by typing `echo "(input here)" | sparkup`, or `sparkup --help` for a list of commands.
|
||||
|
||||
Credits
|
||||
-------
|
||||
|
||||
Sparkup is written by Rico Sta. Cruz and is released under the MIT license.
|
||||
|
||||
This project is inspired by [Zen Coding](http://code.google.com/p/zen-coding/) of
|
||||
[Vadim Makeev](http://pepelsbey.net). The Zen HTML syntax is forward-compatible with Sparkup
|
||||
(anything that Zen HTML can parse, Sparkup can too).
|
||||
|
||||
The following people have contributed code to the project:
|
||||
|
||||
- Guillermo O. Freschi (Tordek @ GitHub)
|
||||
Bugfixes to the parsing system
|
||||
|
||||
- Eric Van Dewoestine (ervandew @ GitHub)
|
||||
Improvements to the VIM plugin
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
**`div`** expands to:
|
||||
|
||||
```html
|
||||
<div></div>
|
||||
```
|
||||
|
||||
**`div#header`** expands to:
|
||||
|
||||
```html
|
||||
<div id="header"></div>
|
||||
```
|
||||
|
||||
**`div.align-left#header`** expands to:
|
||||
|
||||
```html
|
||||
<div id="header" class="align-left"></div>
|
||||
```
|
||||
|
||||
**`div#header + div#footer`** expands to:
|
||||
|
||||
```html
|
||||
<div id="header"></div>
|
||||
<div id="footer"></div>
|
||||
```
|
||||
|
||||
**`#menu > ul`** expands to:
|
||||
|
||||
```html
|
||||
<div id="menu">
|
||||
<ul></ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
**`#menu > h3 + ul`** expands to:
|
||||
|
||||
```html
|
||||
<div id="menu">
|
||||
<h3></h3>
|
||||
<ul></ul>
|
||||
</div>
|
||||
```
|
||||
|
||||
**`#header > h1{Welcome to our site}`** expands to:
|
||||
|
||||
```html
|
||||
<div id="header">
|
||||
<h1>Welcome to our site</h1>
|
||||
</div>
|
||||
```
|
||||
|
||||
**`a[href=index.html]{Home}`** expands to:
|
||||
|
||||
```html
|
||||
<a href="index.html">Home</a>
|
||||
```
|
||||
|
||||
**`ul > li*3`** expands to:
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li></li>
|
||||
<li></li>
|
||||
<li></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
**`ul > li.item-$*3`** expands to:
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li class="item-1"></li>
|
||||
<li class="item-2"></li>
|
||||
<li class="item-3"></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
**`ul > li.item-$*3 > strong`** expands to:
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li class="item-1"><strong></strong></li>
|
||||
<li class="item-2"><strong></strong></li>
|
||||
<li class="item-3"><strong></strong></li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
**`table > tr*2 > td.name + td*3`** expands to:
|
||||
|
||||
```html
|
||||
<table>
|
||||
<tr>
|
||||
<td class="name"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
**`#header > ul > li < p{Footer}`** expands to:
|
||||
|
||||
```html
|
||||
<!-- The < symbol goes back up the parent; i.e., the opposite of >. -->
|
||||
<div id="header">
|
||||
<ul>
|
||||
<li></li>
|
||||
</ul>
|
||||
<p>Footer</p>
|
||||
</div>
|
||||
```
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>beforeRunningCommand</key>
|
||||
<string>nop</string>
|
||||
<key>command</key>
|
||||
<string>#!/usr/bin/env python2
|
||||
import sys; import os; sys.path.append(os.getenv('TM_BUNDLE_SUPPORT')); import sparkup
|
||||
|
||||
# You may change these options to your liking.
|
||||
# Those starting with # are comments (disabled).
|
||||
options = {
|
||||
'textmate': True,
|
||||
'no-last-newline': True,
|
||||
'indent-tabs': False,
|
||||
#'start-guide-format': 'Begin %s',
|
||||
#'end-guide-format': 'End %s',
|
||||
}
|
||||
|
||||
sparkup.Router().start(options=options)</string>
|
||||
<key>fallbackInput</key>
|
||||
<string>line</string>
|
||||
<key>input</key>
|
||||
<string>selection</string>
|
||||
<key>keyEquivalent</key>
|
||||
<string>^e</string>
|
||||
<key>name</key>
|
||||
<string>Sparkup expand</string>
|
||||
<key>output</key>
|
||||
<string>insertAsSnippet</string>
|
||||
<key>uuid</key>
|
||||
<string>73A48D2B-D843-42A1-A288-0D1A6380043B</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1 @@
|
||||
../../../sparkup.py
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>name</key>
|
||||
<string>Sparkup</string>
|
||||
<key>ordering</key>
|
||||
<array>
|
||||
<string>AA687F82-BF47-477C-A832-D3671736EA81</string>
|
||||
</array>
|
||||
<key>uuid</key>
|
||||
<string>0CDE6908-2EF0-4E86-A9C1-5AC12E320414</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1 @@
|
||||
au BufNewFile,BufRead *.hbs set filetype=html
|
||||
@@ -0,0 +1,22 @@
|
||||
Copyright (c) 2009, Rico Sta. Cruz.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
#!/usr/bin/env python2
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import sparkup
|
||||
|
||||
|
||||
class SparkupTest:
|
||||
options = {
|
||||
'textmate': True,
|
||||
'no-last-newline': True,
|
||||
'post-tag-guides': True,
|
||||
}
|
||||
options = {
|
||||
'default': {'textmate': True, 'no-last-newline': True, 'post-tag-guides': True},
|
||||
'guides': {'textmate': True, 'no-last-newline': True, 'post-tag-guides': True, 'start-guide-format': 'Begin %s'},
|
||||
'namespaced-elements': {'textmate': True, 'no-last-newline': True, 'post-tag-guides': True, 'namespaced-elements': True }
|
||||
}
|
||||
cases = {
|
||||
'Simple test': {
|
||||
'options': 'default',
|
||||
'input': 'div',
|
||||
'output': '<div>$1</div>$0'
|
||||
},
|
||||
'Class test': {
|
||||
'input': 'div.lol',
|
||||
'output': '<div class="lol">$1</div><!-- /.lol -->$0'
|
||||
},
|
||||
'ID and class test': {
|
||||
'input': 'div.class#id',
|
||||
'output': '<div class="class" id="id">$1</div><!-- /#id -->$0'
|
||||
},
|
||||
'ID and class test 2': {
|
||||
'input': 'div#id.class',
|
||||
'output': '<div class="class" id="id">$1</div><!-- /#id -->$0'
|
||||
},
|
||||
'Attributes test': {
|
||||
'input': 'div#id.class[style=color:blue]',
|
||||
'output': '<div style="color:blue" class="class" id="id">$1</div><!-- /#id -->$0'
|
||||
},
|
||||
'Multiple attributes test': {
|
||||
'input': 'div[align=center][style=color:blue][rel=none]',
|
||||
'output': '<div align="center" style="color:blue" rel="none">$1</div>$0'
|
||||
},
|
||||
'Multiple class test': {
|
||||
'input': 'div.c1.c2.c3',
|
||||
'output': '<div class="c1 c2 c3">$1</div><!-- /.c1.c2.c3 -->$0'
|
||||
},
|
||||
'Shortcut test': {
|
||||
'input': 'input:button',
|
||||
'output': '<input type="button" class="button" value="$1" name="$2">$0'
|
||||
},
|
||||
'Shortcut synonym test': {
|
||||
'input': 'button',
|
||||
'output': '<button>$1</button>$0',
|
||||
},
|
||||
'Child test': {
|
||||
'input': 'div>ul>li',
|
||||
'output': "<div>\n <ul>\n <li>$1</li>\n </ul>\n</div>$0"
|
||||
},
|
||||
'Sibling test': {
|
||||
'input': 'div#x + ul+ h3.class',
|
||||
'output': '<div id="x">$1</div><!-- /#x -->\n<ul>$2</ul>\n<h3 class="class">$3</h3>$0'
|
||||
},
|
||||
'Child + sibling test': {
|
||||
'input': 'div > ul > li + span',
|
||||
'output': '<div>\n <ul>\n <li>$1</li>\n <span>$2</span>\n </ul>\n</div>$0'
|
||||
},
|
||||
'Multiplier test 1': {
|
||||
'input': 'ul > li*3',
|
||||
'output': '<ul>\n <li>$1</li>\n <li>$2</li>\n <li>$3</li>\n</ul>$0'
|
||||
},
|
||||
'Multiplier test 2': {
|
||||
'input': 'ul > li.item-$*3',
|
||||
'output': '<ul>\n <li class="item-1">$1</li>\n <li class="item-2">$2</li>\n <li class="item-3">$3</li>\n</ul>$0'
|
||||
},
|
||||
'Multiplier test 3': {
|
||||
'input': 'ul > li.item-$*3 > a',
|
||||
'output': '<ul>\n <li class="item-1">\n <a href="$1">$2</a>\n </li>\n <li class="item-2">\n <a href="$3">$4</a>\n </li>\n <li class="item-3">\n <a href="$5">$6</a>\n </li>\n</ul>$0'
|
||||
},
|
||||
'Ampersand test': {
|
||||
'input': 'td > tr.row-$*3 > td.cell-&*2',
|
||||
'output': '<td>\n <tr class="row-1">\n <td class="cell-1">$1</td>\n <td class="cell-2">$2</td>\n </tr>\n <tr class="row-2">\n <td class="cell-3">$3</td>\n <td class="cell-4">$4</td>\n </tr>\n <tr class="row-3">\n <td class="cell-5">$5</td>\n <td class="cell-6">$6</td>\n </tr>\n</td>$0'
|
||||
},
|
||||
'Menu test': {
|
||||
'input': 'ul#menu > li*3 > a > span',
|
||||
'output': '<ul id="menu">\n <li>\n <a href="$1">\n <span>$2</span>\n </a>\n </li>\n <li>\n <a href="$3">\n <span>$4</span>\n </a>\n </li>\n <li>\n <a href="$5">\n <span>$6</span>\n </a>\n </li>\n</ul>$0'
|
||||
},
|
||||
'Back test': {
|
||||
'input': 'ul#menu > li*3 > a < < div',
|
||||
'output': '<ul id="menu">\n <li>\n <a href="$1">$2</a>\n </li>\n <li>\n <a href="$3">$4</a>\n </li>\n <li>\n <a href="$5">$6</a>\n </li>\n</ul>\n<div>$7</div>$0'
|
||||
},
|
||||
'Expand test': {
|
||||
'input': 'p#menu > table+ + ul',
|
||||
'output': '<p id="menu">\n <table>\n <tr>\n <td>$1</td>\n </tr>\n </table>\n <ul>$2</ul>\n</p>$0'
|
||||
},
|
||||
'Text with dot test': {
|
||||
'input': 'p { text.com }',
|
||||
'output': '<p> text.com </p>$0'
|
||||
},
|
||||
'Attribute with dot test': {
|
||||
'input': 'p [attrib=text.com]',
|
||||
'output': '<p attrib="text.com">$1</p>$0'
|
||||
},
|
||||
'PHP tag test': {
|
||||
'input': 'php',
|
||||
'output': '<?php\n $1\n?>$0',
|
||||
},
|
||||
'Eruby tag test': {
|
||||
'input': 'erb:p',
|
||||
'output': '<%= %>$0',
|
||||
},
|
||||
'ERB block test': {
|
||||
'input': 'erb:b',
|
||||
'output': '<% $2 %>\n $1\n<% end %>$0'
|
||||
},
|
||||
'Tag name case (#49)': {
|
||||
'input': 'groupId{foobar}',
|
||||
'output': '<groupId>foobar</groupId>$0'
|
||||
},
|
||||
'Nested curly braces test': {
|
||||
'input': 'p{{{ title }}}',
|
||||
'output': '<p>{{ title }}</p>$0'
|
||||
},
|
||||
'Nested curly braces test (#54)': {
|
||||
'input': 'html>head>title{${title}}',
|
||||
'output': '<html>\n <head>\n <title>${title}</title>\n </head>\n</html>$0'
|
||||
},
|
||||
'HTML component element with dash test': {
|
||||
'input': 'my-html-component',
|
||||
'output': '<my-html-component>$1</my-html-component>$0'
|
||||
},
|
||||
'XML namespaced element': {
|
||||
'options': 'namespaced-elements',
|
||||
'input': 'namespaced-ul',
|
||||
'output': '<namespaced:ul>$1</namespaced:ul>$0'
|
||||
},
|
||||
# Add: text test, broken test, multi-attribute tests, indentation test, start and end comments test
|
||||
}
|
||||
|
||||
def run(self):
|
||||
"""Run Forrest run!"""
|
||||
failures = 0
|
||||
|
||||
print("Test results:")
|
||||
for name, case in self.cases.iteritems():
|
||||
try:
|
||||
options_key = case['options']
|
||||
except:
|
||||
options_key = 'default'
|
||||
|
||||
try:
|
||||
options = self.options[options_key]
|
||||
except:
|
||||
options = self.options['default']
|
||||
|
||||
# Output buffer
|
||||
r = sparkup.Router()
|
||||
input = case['input']
|
||||
output = r.start(options=options, str=input, ret=True)
|
||||
del r
|
||||
|
||||
# Did it work?
|
||||
result = output == case['output']
|
||||
if result:
|
||||
result_str = " OK "
|
||||
else:
|
||||
result_str = "FAIL"
|
||||
|
||||
print(" - %-30s [%s]" % (name, result_str))
|
||||
if not result:
|
||||
failures += 1
|
||||
print("= %s" % input.replace("\n", "\n= "))
|
||||
print("Actual output (condensed):")
|
||||
print(" | '%s'" % output.replace("\n", r"\n").replace('"', '\"'))
|
||||
print("Actual output:")
|
||||
print(" | %s" % output.replace("\n", "\n | "))
|
||||
print("Expected:")
|
||||
print(" | %s" % case['output'].replace("\n", "\ n| "))
|
||||
|
||||
return failures
|
||||
|
||||
if __name__ == '__main__':
|
||||
s = SparkupTest()
|
||||
sys.exit(s.run())
|
||||
Executable
+1171
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
Installation
|
||||
------------
|
||||
|
||||
With Pathogen
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
If you are using tpope's vim-pathogen, install as follows:
|
||||
|
||||
cd ~/.vim/bundle ; git clone https://github.com/rstacruz/sparkup.git
|
||||
cd sparkup
|
||||
make vim-pathogen
|
||||
|
||||
|
||||
With Vundle
|
||||
^^^^^^^^^^^
|
||||
|
||||
If using Vundle, you can specify Sparkup as a bundle and installation will happen
|
||||
automatically. Add this to your Vim configuration:
|
||||
|
||||
Plugin 'rstacruz/sparkup', {'rtp': 'vim/'}
|
||||
|
||||
and run the standard installation command for Vundle:
|
||||
|
||||
:PluginInstall
|
||||
|
||||
|
||||
Manual installation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
1. Copy the contents of vim/ftplugin/ to your ~/.vim/ftplugin directory.
|
||||
|
||||
(Assuming your current dir is sparkup/vim/)
|
||||
$ cp -R ftplugin ~/.vim/
|
||||
|
||||
2. Copy the sparkup.py file to your ~/.vim directory
|
||||
|
||||
(Assuming your current dir is sparkup/vim/)
|
||||
$ cp ../sparkup.py ~/.vim/
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Customise the Sparkup's configuration within Vim by specifying some or all of the following
|
||||
as variables within your Vim configuration using the ``let`` directive.
|
||||
|
||||
g:sparkup (Default: 'sparkup') -
|
||||
Location of the sparkup executable. You shouldn't need to change this
|
||||
setting if you used the install option above.
|
||||
|
||||
g:sparkupArgs (Default: '--no-last-newline') -
|
||||
Additional args passed to sparkup.
|
||||
|
||||
g:sparkupExecuteMapping (Default: '<c-e>') -
|
||||
Mapping used to execute sparkup within insert mode.
|
||||
|
||||
g:sparkupNextMapping (Default: '<c-n>') -
|
||||
Mapping used to jump to the next empty tag/attribute within insert mode.
|
||||
|
||||
g:sparkupMaps (Default: 1) -
|
||||
Set up automatic mappings for Sparkup. If set to 0, this can be
|
||||
used to disable creation of any mappings, which is useful if
|
||||
full customisation is required.
|
||||
|
||||
g:sparkupMapsNormal (Default: 0) -
|
||||
Set up mappings for normal mode within Vim. The same execute and next
|
||||
mappings configured above will apply to normal mode if this option is
|
||||
set.
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
../../../sparkup.py
|
||||
@@ -0,0 +1,129 @@
|
||||
" Sparkup
|
||||
" Installation:
|
||||
" Copy the contents of vim/ftplugin/ to your ~/.vim/ftplugin directory:
|
||||
"
|
||||
" $ cp -R vim/ftplugin ~/.vim/ftplugin/
|
||||
"
|
||||
" or use one of the automated methods specified in the README.txt file.
|
||||
"
|
||||
" Configuration:
|
||||
" g:sparkup (Default: 'sparkup') -
|
||||
" Location of the sparkup executable. You shouldn't need to change this
|
||||
" setting if you used the install option above.
|
||||
"
|
||||
" g:sparkupArgs (Default: '--no-last-newline') -
|
||||
" Additional args passed to sparkup.
|
||||
"
|
||||
" g:sparkupExecuteMapping (Default: '<c-e>') -
|
||||
" Mapping used to execute sparkup within insert mode.
|
||||
"
|
||||
" g:sparkupNextMapping (Default: '<c-n>') -
|
||||
" Mapping used to jump to the next empty tag/attribute within insert mode.
|
||||
"
|
||||
" g:sparkupMaps (Default: 1) -
|
||||
" Set up automatic mappings for Sparkup. If set to 0, this can be
|
||||
" used to disable creation of any mappings, which is useful if
|
||||
" full customisation is required.
|
||||
"
|
||||
" g:sparkupMapsNormal (Default: 0) -
|
||||
" Set up mappings for normal mode within Vim. The same execute and next
|
||||
" mappings configured above will apply to normal mode if this option is
|
||||
" set.
|
||||
|
||||
if !exists('g:sparkupExecuteMapping')
|
||||
let g:sparkupExecuteMapping = '<c-e>'
|
||||
endif
|
||||
|
||||
if !exists('g:sparkupNextMapping')
|
||||
let g:sparkupNextMapping = '<c-n>'
|
||||
endif
|
||||
|
||||
if !exists('g:sparkupMaps')
|
||||
let g:sparkupMaps = 1
|
||||
endif
|
||||
|
||||
if !exists('g:sparkupMapsNormal')
|
||||
let g:sparkupMapsNormal = 0
|
||||
endif
|
||||
|
||||
inoremap <buffer> <Plug>SparkupExecute <c-g>u<Esc>:call <SID>Sparkup()<cr>
|
||||
inoremap <buffer> <Plug>SparkupNext <c-g>u<Esc>:call <SID>SparkupNext()<cr>
|
||||
|
||||
if g:sparkupMaps
|
||||
if ! hasmapto('<Plug>SparkupExecute', 'i')
|
||||
exec 'imap <buffer> ' . g:sparkupExecuteMapping . ' <Plug>SparkupExecute'
|
||||
endif
|
||||
if ! hasmapto('<Plug>SparkupNext', 'i')
|
||||
exec 'imap <buffer> ' . g:sparkupNextMapping . ' <Plug>SparkupNext'
|
||||
endif
|
||||
if g:sparkupMapsNormal
|
||||
if ! hasmapto('<Plug>SparkupExecute', 'n')
|
||||
exec 'nnoremap <buffer> ' . g:sparkupExecuteMapping . ' :call <SID>Sparkup()<cr>'
|
||||
endif
|
||||
if ! hasmapto('<Plug>SparkupNext', 'n')
|
||||
exec 'nnoremap <buffer> ' . g:sparkupNextMapping . ' :call <SID>SparkupNext()<cr>'
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
if exists('*s:Sparkup')
|
||||
finish
|
||||
endif
|
||||
|
||||
function! s:Sparkup()
|
||||
if !exists('s:sparkup')
|
||||
let s:sparkup = exists('g:sparkup') ? g:sparkup : 'sparkup'
|
||||
|
||||
if !executable(s:sparkup)
|
||||
" If g:sparkup is not configured (and/or not found in $PATH),
|
||||
" look for sparkup.vim in Vim's runtimepath.
|
||||
" XXX: quite expensive for a Pathogen-like environment (where &rtp is huge)
|
||||
let paths = substitute(escape(&runtimepath, ' '), '\(,\|$\)', '/**\1', 'g')
|
||||
let s:sparkup = fnamemodify(findfile('sparkup.py', paths), ':p')
|
||||
|
||||
if !filereadable(s:sparkup)
|
||||
echohl WarningMsg
|
||||
echom 'Warning: could not find sparkup/sparkup.py on your path or in your vim runtime path.'
|
||||
echohl None
|
||||
unlet s:sparkup
|
||||
return
|
||||
endif
|
||||
endif
|
||||
let s:sparkup = '"' . s:sparkup . '"'
|
||||
" Workaround for windows, where the Python file cannot be executed via shebang
|
||||
if has('win32') || has('win64')
|
||||
let s:sparkup = 'python ' . s:sparkup
|
||||
endif
|
||||
endif
|
||||
|
||||
" Build arguments list (not cached, g:sparkupArgs might change, also
|
||||
" &filetype, &expandtab etc)
|
||||
let sparkupArgs = exists('g:sparkupArgs') ? g:sparkupArgs : '--no-last-newline'
|
||||
" Pass '--xml' option, if 'xml' is used as filetype (default: none/'html')
|
||||
" NOTE: &filetype can contain multiple values, e.g. 'smarty.html'
|
||||
if index(split(&filetype, '\.'), 'xml') >= 0
|
||||
let sparkupArgs .= ' --xml'
|
||||
endif
|
||||
" If the user's settings are to indent with tabs, do so!
|
||||
" TODO textmate version of this functionality
|
||||
if !&expandtab
|
||||
let sparkupArgs .= ' --indent-tabs'
|
||||
endif
|
||||
|
||||
let sparkupCmd = s:sparkup . printf(' %s --indent-spaces=%s', sparkupArgs, &shiftwidth)
|
||||
exec '.!' . sparkupCmd
|
||||
call s:SparkupNext()
|
||||
endfunction
|
||||
|
||||
function! s:SparkupNext()
|
||||
" 1: empty tag, 2: empty attribute, 3: empty line
|
||||
let n = search('><\/\|\(""\)\|\(^\s*$\)', 'Wp')
|
||||
if n == 3
|
||||
startinsert!
|
||||
else
|
||||
let p = getpos(".")
|
||||
let p[2] = p[2] + 1
|
||||
call setpos(".", p)
|
||||
startinsert
|
||||
endif
|
||||
endfunction
|
||||
@@ -0,0 +1 @@
|
||||
html
|
||||
@@ -0,0 +1 @@
|
||||
html
|
||||
@@ -0,0 +1 @@
|
||||
html
|
||||
@@ -0,0 +1,13 @@
|
||||
tags
|
||||
!doc/tags
|
||||
Makefile
|
||||
TODO.TXT
|
||||
TODO_archived.viki
|
||||
*.vba
|
||||
*.vmb
|
||||
*.zip
|
||||
.last_*
|
||||
test
|
||||
test_*
|
||||
tmp
|
||||
var
|
||||
@@ -0,0 +1,909 @@
|
||||
0.1
|
||||
Initial release
|
||||
|
||||
0.2
|
||||
- More list convenience functions
|
||||
- tlib#EditList()
|
||||
- tlib#InputList(): properly handle duplicate items; it type contains
|
||||
'i', the list index + 1 is returned, not the element
|
||||
|
||||
0.3
|
||||
- tlib#InputList(): Show feedback in statusline instead of the echo area
|
||||
- tlib#GetVar(), tlib#GetValue()
|
||||
|
||||
0.4
|
||||
- tlib#InputList(): Up/Down keys wrap around list
|
||||
- tlib#InputList(): FIX: Problem when reducing the filter & using AND
|
||||
- tlib#InputList(): Made <a-numeric> work (can be configured via
|
||||
- tlib#InputList(): special display_format: "filename"
|
||||
- tlib#Object: experimental support for some kind of OOP
|
||||
- tlib#World: Extracted some functions from tlib.vim to tlib/World.vim
|
||||
- tlib#FileJoin(), tlib#FileSplit(), tlib#RelativeFilename()
|
||||
- tlib#Let()
|
||||
- tlib#EnsureDirectoryExists(dir)
|
||||
- tlib#DirName(dir)
|
||||
- tlib#DecodeURL(url), tlib#EncodeChar(char), tlib#EncodeURL(url)
|
||||
- FIX: Problem when using shift-up/down with filtered lists
|
||||
|
||||
0.5
|
||||
- tlib#InputList(): FIX: Selecting items in filtered view
|
||||
- tlib#InputList(): <c-bs>: Remove last AND pattern from filter
|
||||
|
||||
0.6
|
||||
- tlib#InputList(): Disabled <c-space> map
|
||||
- tlib#InputList(): try to be smart about user itentions only if a
|
||||
list's length is < g:tlib_sortprefs_threshold (default: 200)
|
||||
- tlib#Object: Super() method
|
||||
- tlib#MyRuntimeDir()
|
||||
- tlib#GetCacheName(), tlib#CacheSave(), tlib#CacheGet()
|
||||
- tlib#Args(), tlib#GetArg()
|
||||
- FIX: tlib#InputList(): Display problem with first item
|
||||
|
||||
0.7
|
||||
- tlib#InputList(): <c-z> ... Suspend/Resume input
|
||||
- tlib#InputList(): <c-q> ... Input text on the command line (useful on
|
||||
slow systems when working with very large lists)
|
||||
- tlib#InputList(): AND-pattern starting with '!' will work as 'exclude
|
||||
matches'
|
||||
- tlib#InputList(): FIX <c-bs> pop OR-patterns properly
|
||||
- tlib#InputList(): display_format == filename: don't add '/' to
|
||||
directory names (avoid filesystem access)
|
||||
|
||||
0.8
|
||||
- FIX: Return empty cache name for buffers that have no files attached to it
|
||||
- Some re-arranging
|
||||
|
||||
0.9
|
||||
- Re-arrangements & modularization (this means many function names have
|
||||
changed, on the other hand only those functions are loaded that are
|
||||
actually needed)
|
||||
- tlib#input#List(): Added maps with m-modifiers for <c-q>, <c-z>, <c-a>
|
||||
- tlib#input#List(): Make sure &fdm is manual
|
||||
- tlib#input#List(): When exiting the list view, consume the next 5
|
||||
characters in the queue (if any)
|
||||
- tlib#input#EditList(): Now has cut, copy, paste functionality.
|
||||
- Added documentation and examples
|
||||
|
||||
0.10
|
||||
- tlib#input#List(): (v)split type of commands leave the original window
|
||||
untouched (you may use <c-w> to replace its contents)
|
||||
- tlib#file#With(): Check whether an existing buffer is loaded.
|
||||
- Scratch related functions went to tlib/scratch.vim so that they are
|
||||
accessible from other scripts.
|
||||
- Configure the list window height via g:tlib_inputlist_pct (1..100%)
|
||||
|
||||
0.11
|
||||
NEW:
|
||||
- The :TLet command replaces :TLLet (which was removed)
|
||||
- :TScratch[!] command (with ! don't split but use the whole window)
|
||||
- tlib#rx#Escape(text, ?magic='m')
|
||||
- tlib#buffer#GetList(?show_hidden=0)
|
||||
- tlib#dir#CD(), tlib#dir#Push(), tlib#dir#Pop()
|
||||
- tlib#input#ListW: A slightly remodeled version of tlib#input#List
|
||||
that takes a World as second argument.
|
||||
- Added some documentation doc/tlib.txt (most of it is automatically
|
||||
compiled from the source files)
|
||||
CHANGES:
|
||||
- tlib#input#List(): The default keys for AND, NOT have changed to
|
||||
be more Google-like (space, minus); the keys can be configured via
|
||||
global variables.
|
||||
IMPROVEMENTS:
|
||||
- In file listings, indicate if a file is loaded, listed, modified
|
||||
etc.
|
||||
- tlib#input#List(): Highlight the filter pattern
|
||||
- tlib#input#List(): <c-up/down> scrolls g:tlib_scroll_lines
|
||||
(default=10) lines
|
||||
FIXES:
|
||||
- tlib#input#List(): Centering line, clear match, clear & restore
|
||||
the search register
|
||||
- tlib#input#List(): Ensure the window layout doesn't change (if the
|
||||
number of windows hasn't changed)
|
||||
- tlib#arg#Ex(): Don't escape backslashes by default
|
||||
|
||||
0.12
|
||||
NEW:
|
||||
- tlib/tab.vim
|
||||
CHANGES:
|
||||
- Renamed tlib#win#SetWin() to tlib#win#Set()
|
||||
IMPROVEMENTS:
|
||||
- tlib#input#List(): <left>, <right> keys work in some lists
|
||||
- tlib#input#List(): If an index_table is provided this will be used
|
||||
instead of the item's list index.
|
||||
FIXES:
|
||||
- tlib#input#List(): Problem with scrolling, when the list was
|
||||
shorter than the window (eg when using a vertical window).
|
||||
- tlib#cache#Filename(): Don't rewrite name as relative filename if
|
||||
explicitly given as argument. Avoid double (back)slashes.
|
||||
- TLet: simplified
|
||||
|
||||
0.13
|
||||
CHANGES:
|
||||
- Scratch: Set &fdc=0.
|
||||
- The cache directory can be configured via g:tlib_cache
|
||||
- Renamed tlib#buffer#SetBuffer() to tlib#buffer#Set().
|
||||
FIXES:
|
||||
- tlib#input#List(): Select the active item per mouse.
|
||||
- TLet: simplified
|
||||
|
||||
0.14
|
||||
NEW:
|
||||
- tlib#buffer#InsertText()
|
||||
CHANGES:
|
||||
- tlib#win#[SG]etLayout(): Use a dictionnary, set &cmdheight.
|
||||
FIXES:
|
||||
- Wrong order with pre-defined filters.
|
||||
|
||||
0.15
|
||||
NEW:
|
||||
- tlib#string#TrimLeft(), tlib#string#TrimRight(), tlib#string#Strip()
|
||||
- Progress bar
|
||||
|
||||
0.16
|
||||
NEW:
|
||||
- tlib#string#Printf1()
|
||||
|
||||
0.17
|
||||
NEW:
|
||||
- TBrowseOutput
|
||||
- Some minor changes
|
||||
|
||||
0.18
|
||||
NEW:
|
||||
- tlib/time.vim
|
||||
- g:tlib_inputlist_livesearch_threshold
|
||||
CHANGES:
|
||||
- tlib#input#ListD(), World: Don't redisplay the list while typing
|
||||
new letters; calculate filter regexps only once before filtering the
|
||||
list.
|
||||
- World.vim: Minor changes to how filenames are handled.
|
||||
|
||||
0.19
|
||||
NEW:
|
||||
- tag.vim
|
||||
FIX:
|
||||
- dir.vim: Use plain dir name in tlib#dir#Ensure()
|
||||
- tlib#input#List(): An initial filter argument creates [[filter]]
|
||||
and not as before [[''], [filter]].
|
||||
- tlib#input#List(): When type was "si" and the item was picked by
|
||||
filter, the wrong index was returned.
|
||||
- tlib#input#List(): Don't check if chars are typed when displaying
|
||||
the list for the first time.
|
||||
|
||||
0.20
|
||||
- The arguments of tlib#tag#Collect() have changed.
|
||||
- tlib#input#List(): The view can be "suspended" on initial display.
|
||||
- tlib#input#List(): Follow/trace cursor functionality
|
||||
|
||||
0.21
|
||||
- tlib#buffer#InsertText(): Respect tabs and (experimental) formatoptions+=or
|
||||
- tlib/syntax.vim: Syntax-related functions
|
||||
|
||||
0.22
|
||||
- FIX: very magic mode for tlib#rx#Escape() (thanks A Politz)
|
||||
- FIX: tlib#arg#Ex: escape "!"
|
||||
|
||||
0.23
|
||||
- Respect the setting of g:tlib_inputlist_filename_indicators
|
||||
- tlib#input#List(): Reset syntax on resume; option to make list window "sticky"
|
||||
- tlib#agent#ToggleStickyList()
|
||||
- Simplified tlib#url#Decode()
|
||||
- tlib#arg#Ex(): use fnameescape() if available
|
||||
|
||||
0.24
|
||||
- s:prototype.SetInitialFilter: accept list as argument
|
||||
- Maintain buffer MRU if required
|
||||
|
||||
0.25
|
||||
- NEW: tlib#notify#TrimMessage(): trim message to prevent "Press ENTER"
|
||||
messages (contributed by Erik Falor)
|
||||
- NEW: tlib#notify#Echo()
|
||||
- FIX: World.CloseScratch(): Set window
|
||||
- FIX: tlib#input#ListW(): Set initial_display = 1 on reset
|
||||
|
||||
0.26
|
||||
- NEW: tlib#normal#WithRegister()
|
||||
- FIX: Try not to change numbered registers
|
||||
|
||||
0.27
|
||||
- FIX: Cosmetic bug, wrong packaging (thanks Nathan Neff)
|
||||
- Meaning of World#filter_format changed; new World#filter_options
|
||||
- Filtering didn't work as advertised
|
||||
- tlib#string#Count()
|
||||
|
||||
0.28
|
||||
- tlib#input#List():
|
||||
-- Improved handling of sticky lists; <cr> and <Leftmouse> resume a
|
||||
suspended list and immediately selects the item under the cursor
|
||||
-- Experimental "seq" matching style: the conjunctions are sequentially
|
||||
ordered, they are combined with "OR" (disjunctions), the regexp is
|
||||
'magic', and "." is expanded to '.\{-}'
|
||||
-- Experimental "cnfd" matching style: Same as cnf but with an "elastic"
|
||||
dot "." that matches '\.\{-}'
|
||||
-- Filtering acts as if &ic=1 && $sc=1
|
||||
-- Weighting is done by the filter
|
||||
- tlib#agent#Input(): Consume <esc> when aborting input()
|
||||
- INCOMPATIBLE CHANGE: Changed eligible values of g:tlib_inputlist_match
|
||||
to "cnf", "cnfd", "seq" and "fuzzy"
|
||||
- NEW: tlib#buffer#KeepCursorPosition()
|
||||
- tlib#buffer#InsertText(): Take care of the extra line when appending
|
||||
text to an empty buffer.
|
||||
|
||||
0.29
|
||||
- tlib#string#Strip(): Strip also control characters (newlines etc.)
|
||||
- tlib#rx#Suffixes(): 'suffixes' as Regexp
|
||||
- World#RestoreOrigin(): Don't assume &splitbelow
|
||||
|
||||
0.30
|
||||
- World#RestoreOrigin(): Don't assume &splitright
|
||||
|
||||
0.31
|
||||
- :TRequire command
|
||||
-tlib#input#List: For i-type list views, make sure agents are called
|
||||
with the base indices.
|
||||
|
||||
0.32
|
||||
- tlib#agent#Exit: explicitly return empty value (as a consequence,
|
||||
pressing <esc> when browsing an index-list, returns 0 and not "")
|
||||
- tlib#signs
|
||||
- tlib#input#List: set local statusline
|
||||
|
||||
0.33
|
||||
- Don't reset statusline
|
||||
- Don't use fnamemodify() to split filenames (for performance reasons)
|
||||
- scratch: Set ft after setting up scratch options
|
||||
- tlib#map#PumAccept(key)
|
||||
|
||||
0.34
|
||||
- tlib#buffer#HighlightLine(line): call tlib#autocmdgroup#Init()
|
||||
(reported by Sergey Khorev)
|
||||
|
||||
0.35
|
||||
- tlib#input#EditList(): return the list if the user presses esc
|
||||
|
||||
0.36
|
||||
- Display a message when the filter is for whatever reason invalid
|
||||
- Removed tlib#paragraph#Delete()
|
||||
- New: tlib#paragraph#Define(), tlib#textobjects#StandardParagraph()
|
||||
- Try to speed up list display (a rewrite of World.DisplayList() etc. is
|
||||
required)
|
||||
|
||||
0.37
|
||||
- g:tlib_inputlist_livesearch_threshold defaults to 1000
|
||||
- tlib#World: optional scratch_pos field
|
||||
- tlib#input#List: By default <m-NUMBER> selects by number but NUMBER is
|
||||
interpreted as string
|
||||
- tlib#date
|
||||
- TTimeCommand
|
||||
|
||||
0.38
|
||||
- tlib#World#Resize: set winfix{height|width}
|
||||
|
||||
0.39
|
||||
- g:tlib#cache#dont_purge
|
||||
- tlib#vim#RestoreWindow()
|
||||
- tlib#ballon#...()
|
||||
|
||||
0.40
|
||||
- tlib#agent#ViewFile: Use split/sbuffer if nohidden && modified
|
||||
- tlib#buffer#GetList(): order by "basename"
|
||||
|
||||
version: "0.41"
|
||||
- World.UseScratch(): keepalt
|
||||
- Really include balloon.vim
|
||||
MD5 checksum: 3fcbc4f7556f5378d39622e62ab8f379
|
||||
|
||||
version: "0.42"
|
||||
- tlib#input#List: <s-space> inserts a *-like wildcard (represented as "__")
|
||||
- Check if a cache file cannot be created because a directory of the same name exists (display a message if so)
|
||||
- tlib#cache#Filename: Removed check if a directory of the same name exists (due to inconsistent use)
|
||||
- Minor improvements related to buffer handling (scratch_split)
|
||||
- .gitignore
|
||||
- docs (thanks to blueyed)
|
||||
- There is no "edit" answer possibility.
|
||||
- Fix first purge: do nothing if no timestamp file.
|
||||
- g:tlib_pick_single_item
|
||||
- Removed pick_single_item. Changed the default behavour when a list has only 1 item. See doc for g:tlib_pick_last_item.
|
||||
- Updated help for tlib#input#List(); help_extra attribute
|
||||
- EXPERIMENTAL: cache_var, restore_from_cache, on_leave properties; #Initialize(), #Leave()
|
||||
- added tlib#cmd#BrowseOutputWithCallback function and :TBrowseScriptnames command
|
||||
- tlib#cmd#BrowseOutputWithCallback function and :TBrowseScriptnames command documentation
|
||||
- s:prototype.Initialize(): unlet self.cache_var after restoring values
|
||||
- tlib#input#List: filter-specific help
|
||||
- Removed the seq filter (use cnfd or fuzzy instead)
|
||||
- tlib#input#List: temp_prompt (for help message)
|
||||
MD5 checksum: aa8b5a4602235cc1a5bc9ee45d801b81
|
||||
|
||||
version: "0.42"
|
||||
- g:tlib#cache#silent: don't display messages when purging the cache (fixes #9)
|
||||
- Changed message when deleting directories in the cache.
|
||||
- g:tlib#input#use_popup: Don't rely on has('menu') but also check for gtk & win gui (fixes #10)
|
||||
- debug
|
||||
- tlib#input#ListW(): Didn't return a list when type == "m"
|
||||
- docs (solves #11)
|
||||
MD5 checksum: aa8b5a4602235cc1a5bc9ee45d801b81
|
||||
|
||||
version: "0.45"
|
||||
- fuzzy mode: prototype.highlight defaults to g:tlib_inputlist_higroup
|
||||
- tlib#scratch: Use noautocmd
|
||||
- tlib#input#ListW(): Use world.RestoreOrigin() instead of tlib#win#SetLayout(world.winview)
|
||||
- tlib#input#ListW(): Revert to tlib#win#SetLayout(world.winview)
|
||||
- tlib#cmd#OutputAsList(): Also save output in g:tlib#cmd#last_output
|
||||
- tlib#agent#Suspend(): Resume on BufEnter
|
||||
- tlib#input#Resume(): Make sure we are in the right buffer
|
||||
- tlib#agent#Suspend(): Use only BufEnter event to trigger a Resume
|
||||
- tlib#input#ListW(): When redisplaying a list, make sure prefix > 0
|
||||
- tlib#vcs: Access vcs (initially only git is supported)
|
||||
- tlib#vcs: improved
|
||||
- tlib#persistent: Persistent data file names
|
||||
- tlib#file#With(): Trigger BufRead autocommands
|
||||
- Duplicate help tags (fixes #13)
|
||||
- Make sure scrolloff is 0 while viewing the list (fixes https://github.com/tomtom/vikitasks_vim/issues/2)
|
||||
MD5 checksum: 0af19ebc0e424727a598a988fdc90f4e
|
||||
|
||||
- Support for tinykeymap (move paragraph)
|
||||
- Moved para_move to autoload/tinykeymap/map
|
||||
- tlib#vcs: some "diff" commands were defined as "ls"; updated hg def; %s is optional
|
||||
MD5 checksum: f2f2fe0893e75bb9423c1ddcd01f38f6
|
||||
version: "0.46"
|
||||
|
||||
- tlib#input#List: optimizations
|
||||
- Prepare for multi-mode maps
|
||||
- tlib#input#List: cnfx is new default filter
|
||||
- Filters: minor changes to how the pattern is displayed
|
||||
- g:tlib#input#format_filename: alternative method for formatting filenames
|
||||
- tlib#input#List: allow multiple keymaps / modes
|
||||
- Handle rezise events
|
||||
- Don't initialize the same window twice
|
||||
- Minor optimizations to how help is displayed
|
||||
- Handle VimResize event per buffer
|
||||
- Improve display of filenames & highlighting
|
||||
- Filename highlighter: set Highlight_filename()
|
||||
- RunStateHandlers(): set world variable
|
||||
- Optimize help display
|
||||
MD5 checksum: e3652927722bdc51935eb1a04238546b
|
||||
version: "1.00"
|
||||
|
||||
- Set g:tlib_inputlist_and to ' ' again
|
||||
- g:tlib#input#filename_max_width: maximum display width of filenames
|
||||
- tlib#input#List: <s-esc>, <f10>: run command by name
|
||||
MD5 checksum: a42f90275cdbe9f7d92cac61b884a2d1
|
||||
version: "1.01"
|
||||
|
||||
- #UseInputListScratch(): Make sure the TLib autogroup was created (fixes #14)
|
||||
MD5 checksum: 5a6da7fc99c7fc7584e8fc2f7bf86fe4
|
||||
version: "1.02"
|
||||
|
||||
- tlib#cache#Value(cfile, generator, ftime, ...): cache value & check timestamp
|
||||
- Replaced g:tlib#cache#silent with g:tlib#cache#verbosity
|
||||
- FormatFilenames: improved handling of utf8 characters
|
||||
- tlib#persistent#Value()
|
||||
- tlib#input#List: Allow filename indiactors defined by the caller
|
||||
- Custom filename_indicators are displayed after (and clearly separted from) the standard indicators
|
||||
- Check the return value of an unknown_key agent
|
||||
- Format filename = "l": Allow ".." as start of a directory name
|
||||
- Format filename = "l": If the filename is just a filename's tail, display it on both sides
|
||||
- Set g:tlib_filename_sep to "\" on Windows (again)
|
||||
- g:tlib#cache#max_filename: If the cache filename is longer than N characters, use |pathshorten()|.
|
||||
MD5 checksum: b64ce6764f39f40bfc95f3916bbb0057
|
||||
version: "1.04"
|
||||
|
||||
version: "1.05"
|
||||
- tlib#hash: Adler32 & CRC32 (using zlib via ruby) algorithms
|
||||
- tlib#cache#Filename(): If the cache filename is too long, add the Adler32 checksum to the shortened path
|
||||
- tlib#cache#Filename(): Use tlib#hash#Adler32() only if the or() function exists
|
||||
- tlib#hash#Adler32(): Raise error, if or() doesn't exist
|
||||
- tlib#hash#CRC32(): Alternative implementation of crc32 (doesn't work yet, thus currently disabled)
|
||||
- tlib#bitwise: Bitwise operations for older versions of vim
|
||||
- tlib#number: Base conversion
|
||||
- tlib#input#ListW(): Handle mouse clicks more correctly
|
||||
- tlib#bitwise#Num2Bits(): Supports returning floats
|
||||
- tlib#hash#CRC32(): Alternative implementation of crc32 (doesn't work yet)
|
||||
- tlib#hash#CRC32(): Re-enable ruby version
|
||||
- tlib#hash#CRC32B(): Implementation of CRC32B checksum in vimscript (used only if +ruby isn't available)
|
||||
- tlib#hash#CRC32B(): vim version: cache the crc table
|
||||
- tlib#cache#Filename(): Use tlib#hash#CRC32B(file) instead of not Adler32 for filenames too long
|
||||
- tlib#hash#CRC32B(): ruby version: return upper case hex value
|
||||
- g:tlib#hash#use_crc32: define which crc32b version should be used
|
||||
- Moved spec files from vimtlib to tlib_vim
|
||||
- tlib#bitwise#Add() and tlib#bitwise#Sub()
|
||||
- tlib#file#Relative(): Wrong results for filenames that don't exist
|
||||
- Implementation of hash#Adler32 for earlier vim versions; g:tlib#hash#use_adler32
|
||||
- tlib#cache#Filename(): Use adler32 again
|
||||
- addon-info
|
||||
- tlib#file#Absolute(): remove redundant "." parts in full filename
|
||||
- win32: Fix moving window when using :vertical for tlib#inpu#List()
|
||||
- tlib#cache#Filename(): Don't create wrong directory if the cache filename is too long
|
||||
- tlib#file#Join(): if strip_slashes, also strip redundant (back)slashes
|
||||
- tlib#input#ListW(): Always set post_keys variable
|
||||
- tlib#file#With(): escape backslashes
|
||||
- tlib#cmd#OutputAsList(): Support for nesting
|
||||
- tlib#dir#NativeName(dirname)
|
||||
MD5 checksum: 493f9beca44374de386f20d1613155e3
|
||||
|
||||
- Rename g:tlib_debug to g:tlib#debug
|
||||
- Renamed g:tlib_sortprefs_threshold to g:tlib#input#sortprefs_threshold
|
||||
- Renamed g:tlib#input#livesearch_threshold
|
||||
- Renamed g:tlib_inputlist_match to g:tlib#input#filter_mode
|
||||
- Renamed g:tlib_inputlist_higroup to g:tlib#input#higroup
|
||||
- Renamed g:tlib#debug
|
||||
- Moved g:tlib_pick_last_item
|
||||
- Renamed g:tlib#input#and, g:tlib#input#or, g:tlib#input#not
|
||||
- Moved g:tlib_numeric_chars to autoload/tlib/input.vim
|
||||
- Renamed g:tlib#input#keyagents_InputList_s, g:tlib#input#keyagents_InputList_m, g:tlib#input#handlers_EditList
|
||||
- Moved g:tlib_inputlist_pct, g:tlib_inputlist_width_filename, g:tlib_inputlist_filename_indicators, g:tlib_inputlist_shortmessage to autoload/tlib/World.vim
|
||||
- Renamed tlib#input#pick_last_item (2)
|
||||
- prototype.SelectItemsByNames()
|
||||
- filtered_items: Restricted view
|
||||
- prototype.PrintLines()
|
||||
- Restricted view (2)
|
||||
- Moved g:tlib_scroll_lines to autoload/tlib/agent.vim
|
||||
- prototype.PrintLines() (2)
|
||||
- tlib#input: Improved handling of popup menu (allows submenu)
|
||||
- tlib#input: Allow mods in keys
|
||||
- Moved g:tlib_scratch_pos to autoload/tlib/scratch.vim
|
||||
- Moved g:tlib_tags_extra, g:tlib_tag_substitute to autoload/tlib/tag.vim
|
||||
- tlib#agent#CompleteAgentNames(): Respect Arglead
|
||||
- Move g:tlib_viewline_position to autoload/tlib/buffer.vim
|
||||
- Move g:tlib_cache to autoload/tlib/cache.vim
|
||||
- Renamed g:tlib_filename_sep to g:tlib#dir#sep
|
||||
- prototype.UseScratch(): Set b:tlib_world
|
||||
- tlib#input: f9 toggles resticted view
|
||||
- tlib#input: next_agent, next_eval
|
||||
- tlib#input: Revised use of the popup menu
|
||||
- tlib#input: Disable popup menu for gui_gtk
|
||||
- tlib#input: Re-enabled the popup menu for gtk gui
|
||||
- tlib#input: FIX popup menu on Windows
|
||||
- Renamed g:tlib_numeric_chars to g:tlib#input#numeric_chars (disabled per-buffer values) (fixes #35)
|
||||
- Improve scratch list
|
||||
- New: tlib#grep
|
||||
- Merge branch 'master' of https://github.com/bruno-/tlib_vim into pull16
|
||||
- g:tlib_scratch_hidden: Configure how to "hide" the scratch buffer
|
||||
- tlib#grep#Do: don't escape "*" in patterns
|
||||
- Optimize use of visible scratch buffers
|
||||
- World.scratch_hidden parameter
|
||||
- scratch: Always use keepalt & keepjumps
|
||||
MD5 checksum: 2e40449c47dc606ccef57aa0b1e22e8e
|
||||
version: "1.06"
|
||||
|
||||
version: "1.07"
|
||||
- Help template
|
||||
- prototype.Highlight_filename(): Use matchstr() instead of fnamemodify()
|
||||
- Display buffer-related filename indicators only if g:tlib_inputlist_filename_indicators is true
|
||||
- tlib#file#Join(): strip_slashes defaults to 1
|
||||
MD5 checksum: 6c8fa96fd3747be05df848ee93dd789b
|
||||
|
||||
version: "1.08"
|
||||
- list#input: Improved support for file indicators (closes #17)
|
||||
- tlib#char#Get(): Optionally, also return mod
|
||||
- tlib#input#ListW: Use #DisplayFormat(world.list)
|
||||
- Renamed cnfx filter to glob & minor filter-related enhancements
|
||||
- list#input: Make help available as command; help cannot be called via ?
|
||||
- list#input: Improved help message
|
||||
- list#input: Support Home & End keys
|
||||
- list#input: Added glob filter
|
||||
- tlib#agent#ShowInfo: Show full filename
|
||||
- tlib#cmd#BrowseOutputWithCallback: Support calling callback with multiple results
|
||||
- tlib#cmd#ParseScriptname: Properly parse results from :scriptnames
|
||||
- tlib#tab#Set()
|
||||
- Prepare for proper handling of scratch_split == -1
|
||||
- tlib#vim#CopyFunction()
|
||||
- tlib#cache#Value(): If generator is empty, use the optional argument as start value
|
||||
- tlib#persistent#Get() refers to tlib#cache#Get()
|
||||
MD5 checksum: 459ec620168d1ae9b18c69eb3f991832
|
||||
|
||||
- tlib#cache#Filename(): Use sha256() for VIM >= 7.4
|
||||
- tlib#cache#Value(): Undo previous hack
|
||||
- tlib#list#Uniq(): option to remove empty values
|
||||
- tlib#cache#MTime(); tlib#persistent#Save() calls tlib#cache#Save()
|
||||
- tlib#input#ListW: Temporarily set noshowmode
|
||||
- tlib#list#Uniq(): Fix handling of empty items
|
||||
- lis picker: Remove <C-Space> from help
|
||||
- tlib#list#Uniq(): Implementation based on syntastic#util#unique(list) by scrooloose
|
||||
MD5 checksum: b5fb4107d63930c2c8b1f0f6b3a7ff07
|
||||
version: "1.09"
|
||||
|
||||
- tlib#cache#Filename(): Use sha256() for VIM >= 7.4
|
||||
- tlib#cache#Value(): Undo previous hack
|
||||
- tlib#list#Uniq(): option to remove empty values
|
||||
- tlib#cache#MTime(); tlib#persistent#Save() calls tlib#cache#Save()
|
||||
- tlib#input#ListW: Temporarily set noshowmode
|
||||
- tlib#list#Uniq(): Fix handling of empty items
|
||||
- lis picker: Remove <C-Space> from help
|
||||
- tlib#list#Uniq(): Implementation based on syntastic#util#unique(list) by scrooloose
|
||||
MD5 checksum: b5fb4107d63930c2c8b1f0f6b3a7ff07
|
||||
version: "1.09"
|
||||
|
||||
- tlib#string#Chomp: Optional argument: max number of chars that should be removed
|
||||
MD5 checksum: 8c1b94e25045580874e2f892d509291b
|
||||
version: "1.10"
|
||||
|
||||
- tlib#vcs#FindVCS(filename): Wrong parameters to fnamemodifiy if filename is a directory
|
||||
- Some system-related functions (e.g. facilitate use of cygwin tools)
|
||||
- tlib#arg#StringAsKeyArgsEqual(), tlib#arg#StringAsKeyArgs(): Support "key=val" type argument lists
|
||||
- tlib#vcs#Executable()
|
||||
- scripts/create_crc_table.rb
|
||||
- tlib#var#Get(): For namespaces other than global, replace "#" with "_"
|
||||
MD5 checksum: 4a33f2f23e1fc6600b32e7f8323e001e
|
||||
version: "1.11"
|
||||
|
||||
- tlib#list#ToDictionary()
|
||||
- tlib#dir#CanonicName(): Use tlib#file#Canonic()
|
||||
- tlib#file#Canonic()
|
||||
MD5 checksum: 7995ab58f31eb6673d20deab8761838e
|
||||
version: "1.12"
|
||||
|
||||
- SetInitialFilter(): Use deepcopy()
|
||||
- tlib#var#List(): use keys(namespace) for newer versions of vim
|
||||
- g:tlib#input#user_shortcuts (not functional yet)
|
||||
- tlib#input#List: state "picked"
|
||||
- UseInputListScratch(): Allow customization via self.index_next_syntax
|
||||
- tlib#cmd#Capture()
|
||||
- Facilitate customization of key agents via g:tlib_extend_keyagents_InputList_s, g:tlib_extend_keyagents_InputList_m
|
||||
MD5 checksum: 7dd8b17a1a5b555df979381dcbd4c9aa
|
||||
version: "1.13"
|
||||
|
||||
- SetInitialFilter(): Use deepcopy()
|
||||
- tlib#var#List(): use keys(namespace) for newer versions of vim
|
||||
- g:tlib#input#user_shortcuts (not functional yet)
|
||||
- tlib#input#List: state "picked"
|
||||
- UseInputListScratch(): Allow customization via self.index_next_syntax
|
||||
- tlib#cmd#Capture()
|
||||
- Facilitate customization of key agents via g:tlib_extend_keyagents_InputList_s, g:tlib_extend_keyagents_InputList_m
|
||||
MD5 checksum: 7dd8b17a1a5b555df979381dcbd4c9aa
|
||||
version: "1.13"
|
||||
|
||||
version: "1.14"
|
||||
- FIX #18: Make sure the scratch isn't readonly
|
||||
- FIX: display filter (properly handle backslashes)
|
||||
- Remove loaded_* guard from autoload files
|
||||
- tlib#notify#Echo(): minor changes
|
||||
- tlib#file#Edit() (used by tlib#agent#ViewFile)
|
||||
- tlib#buffer#GetList(): Buffer numbers are converted to numbers
|
||||
- tlib#sys: Change order of functions (move tlib#sys#IsCygwinBin to the (possibly FIX #19)
|
||||
- g:tlib#sys#check_cygpath: Call tlib#sys#IsExecutable('cygpath', 1) (possibly FIX #19)
|
||||
MD5 checksum: 2cf6386218736a2d09db43c8e751e5a4
|
||||
|
||||
version: "1.15"
|
||||
- tlib#file#Join(): New optional argument: maybe_absolute Drop preceding parts if a part looks like an absolute filename
|
||||
- tlib#sys#Open(), tlib#sys#IsSpecial() (moved from viki)
|
||||
- tlib#list#Uniq(): Handle hetergenous lists
|
||||
- FIX #21: duplicate help tag
|
||||
- NEW tlib#dictionary#Rev()
|
||||
- tlib#input#List(): Use <Tab> to complete current word
|
||||
- NEW tlib#arg#GetOpts(); ENH tlib#arg#StringAsKeyArgsEqual()
|
||||
- cache: Allow for in memory cache
|
||||
- NEW tlib#eval#Extend()
|
||||
- Move qfl/loclist browser from trag to tlib
|
||||
- FIX tlib#eval#Extend()
|
||||
- Simplify tlib#eval#Extend()
|
||||
- World.index_next_syntax may be a dict
|
||||
- tlib#qfl#QflList: Use copy()
|
||||
- tlib#arg#GetOpts: Handle exit code
|
||||
MD5 checksum: 13fd8b0e4ba9cd932c57fc40ac3f641f
|
||||
|
||||
version: "1.15"
|
||||
- tlib#file#Join(): New optional argument: maybe_absolute Drop preceding parts if a part looks like an absolute filename
|
||||
- tlib#sys#Open(), tlib#sys#IsSpecial() (moved from viki)
|
||||
- tlib#list#Uniq(): Handle hetergenous lists
|
||||
- FIX #21: duplicate help tag
|
||||
- NEW tlib#dictionary#Rev()
|
||||
- tlib#input#List(): Use <Tab> to complete current word
|
||||
- NEW tlib#arg#GetOpts(); ENH tlib#arg#StringAsKeyArgsEqual()
|
||||
- cache: Allow for in memory cache
|
||||
- NEW tlib#eval#Extend()
|
||||
- Move qfl/loclist browser from trag to tlib
|
||||
- FIX tlib#eval#Extend()
|
||||
- Simplify tlib#eval#Extend()
|
||||
- World.index_next_syntax may be a dict
|
||||
- tlib#qfl#QflList: Use copy()
|
||||
- tlib#arg#GetOpts: Handle exit code
|
||||
MD5 checksum: 13fd8b0e4ba9cd932c57fc40ac3f641f
|
||||
|
||||
- tlib#arg#GetOpts: Handle short options
|
||||
- tlib#arg: support short flags & facilitate completion
|
||||
- NEW :TLibTrace
|
||||
- tlib#sys#system_browser: FIX XDG string
|
||||
- NEW tlib#sys#SystemInDir() (used by tlib#vcs#Ls)
|
||||
- tlib#agent#Complete: improve fltrx
|
||||
- Remove tlib#arg#Key(), :TKeyArg
|
||||
- Move :TRequire, :TTimeCommand to macros/tlib.vim
|
||||
- NEW tlib#cmd#TBrowseScriptnames()
|
||||
- TScratch: use empty('<bang>')
|
||||
- NEW :TLibTrace
|
||||
- tlib#qfl: FIX TTagedFilesFilename regexp
|
||||
- Remove tlib#arg#Key()
|
||||
- tlib#buffer#InsertText(): Don't use TKeyArg
|
||||
- tlib#eval#Extend: don't assign value
|
||||
- NEW :TLibTrace, tlib#trace (was tlib#debug)
|
||||
- NEW tlib#string#SplitCommaList()
|
||||
- NEW tlib#time#FormatNow()
|
||||
- tlib#arg#GetOpts: selectively disable "long", "short" flags
|
||||
- tlib#arg#CComplete(): Support values completion (complete_customlist field)
|
||||
- NEW tlib#date#Shift()
|
||||
- tlib#qfl#Balloon(): Handle items with no bufnr
|
||||
- NEW tlib#file#Glob, tlib#file#Globpath
|
||||
- tlib#progressbar#Display(): optional "always" argument
|
||||
- tlib#vcs#GitLsPostprocess(): Try to handle encoded filenames from git ls-files
|
||||
- tlib#vcs#GitLsPostprocess: Eval only \ddd substrings
|
||||
- FIX #22: duplicate tag
|
||||
- tlib#buffer: Use 2match instead of 3match (incompatibility with matchparen)
|
||||
- FIX #23: duplicate help tag
|
||||
- tlib#string#SplitCommaList: optional "sep" argument
|
||||
- Rename TLibTrace -> Tlibtrace; NEW Tlibtraceset command
|
||||
- Rename s:SetSyntax -> tlib#qfl#SetSyntax
|
||||
- mv tlib#rx#Convert to incubator
|
||||
MD5 checksum: f3656fb35b7b3033084d6c5e504aca61
|
||||
version: "1.16"
|
||||
|
||||
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
|
||||
- TTimeCommand -> Ttimecommand
|
||||
- tlib#eval#Extend: mode argument for expand() compatibility
|
||||
- tlib#input#List: Key handlers can have additional arguments
|
||||
- tlib#qfl#AgentWithSelected: Set world
|
||||
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
|
||||
- tlib#qfl#AgentWithSelected: typo
|
||||
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
|
||||
- tlib#arg: validators
|
||||
- NEW tlib#date#IsDate()
|
||||
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
|
||||
- NEW tlib#balloon#Expand()
|
||||
- NEW tlib#date#Format()
|
||||
- FIX tlib#date#Shift(..., "+Xm") for months
|
||||
- NEW tlib#trace#Backtrace()
|
||||
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
|
||||
- NEW :Tlibassert
|
||||
MD5 checksum: 3c4125a28ff1860accd254846651c251
|
||||
version: "1.17"
|
||||
|
||||
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
|
||||
- TTimeCommand -> Ttimecommand
|
||||
- tlib#eval#Extend: mode argument for expand() compatibility
|
||||
- tlib#input#List: Key handlers can have additional arguments
|
||||
- tlib#qfl#AgentWithSelected: Set world
|
||||
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
|
||||
- tlib#qfl#AgentWithSelected: typo
|
||||
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
|
||||
- tlib#arg: validators
|
||||
- NEW tlib#date#IsDate()
|
||||
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
|
||||
- NEW tlib#balloon#Expand()
|
||||
- NEW tlib#date#Format()
|
||||
- FIX tlib#date#Shift(..., "+Xm") for months
|
||||
- NEW tlib#trace#Backtrace()
|
||||
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
|
||||
- NEW :Tlibassert
|
||||
MD5 checksum: 3c4125a28ff1860accd254846651c251
|
||||
version: "1.17"
|
||||
|
||||
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
|
||||
- TTimeCommand -> Ttimecommand
|
||||
- tlib#eval#Extend: mode argument for expand() compatibility
|
||||
- tlib#input#List: Key handlers can have additional arguments
|
||||
- tlib#qfl#AgentWithSelected: Set world
|
||||
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
|
||||
- tlib#qfl#AgentWithSelected: typo
|
||||
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
|
||||
- tlib#arg: validators
|
||||
- NEW tlib#date#IsDate()
|
||||
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
|
||||
- NEW tlib#balloon#Expand()
|
||||
- NEW tlib#date#Format()
|
||||
- FIX tlib#date#Shift(..., "+Xm") for months
|
||||
- NEW tlib#trace#Backtrace()
|
||||
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
|
||||
- NEW :Tlibassert
|
||||
MD5 checksum: 3c4125a28ff1860accd254846651c251
|
||||
version: "1.17"
|
||||
|
||||
- tlib#input#List: #ReduceFilter: make sure the regexp is valid
|
||||
- TTimeCommand -> Ttimecommand
|
||||
- tlib#eval#Extend: mode argument for expand() compatibility
|
||||
- tlib#input#List: Key handlers can have additional arguments
|
||||
- tlib#qfl#AgentWithSelected: Set world
|
||||
- prototype.UseInputListScratch: Run tlib_UseInputListScratch hook earlier
|
||||
- tlib#qfl#AgentWithSelected: typo
|
||||
- tlib#arg#GetOpts: type conversion (comma-separated lists etc.)
|
||||
- tlib#arg: validators
|
||||
- NEW tlib#date#IsDate()
|
||||
- tlib#balloon#Remove: Unset &ballooneval, &balloonexpr
|
||||
- NEW tlib#balloon#Expand()
|
||||
- NEW tlib#date#Format()
|
||||
- FIX tlib#date#Shift(..., "+Xm") for months
|
||||
- NEW tlib#trace#Backtrace()
|
||||
- NEW tlib#type#Is(), tlib#type#Are(), tlib#type#Has(), tlib#type#Have()
|
||||
- NEW :Tlibassert
|
||||
MD5 checksum: 3c4125a28ff1860accd254846651c251
|
||||
version: "1.17"
|
||||
|
||||
- tlib#arg: Completion for comma-separated lists
|
||||
- Use "silent cd"
|
||||
- NEW tlib#type#DefSchema(); FIX tlib#type#Has()
|
||||
- tlib#cache#Value(): minor change
|
||||
- tlib#date#IsDate() also checks whether the date is valid
|
||||
- ! tlib#sys#Open(): escape special chars only once
|
||||
- tlib#trace#Print: Allow for strings
|
||||
- :Tlibtrace, :Tlibtraceset, :Tlibassert remove `-bar`
|
||||
- NEW :Tlibtype (type/schema assertions); tlib#type#Is() also accepts schemas as "types"
|
||||
- tlib#dir#CD(): Use haslocaldir()
|
||||
- tlib#qfl#AgentGotoQFE: Don't use wincmd w
|
||||
- NEW tlib#string#Input()
|
||||
- FIX g:tlib#sys#system_rx; add OpenOffice exensions to g:tlib#sys#special_suffixes
|
||||
- NEW tlib#selection#GetSelection()
|
||||
- tlib#date#Shift(): Fix "Xm", ++specs
|
||||
- tlib#trace#Set: FIX Properly handly "-label"
|
||||
MD5 checksum: c3a1fe7d3cd86becbd3f7b0ba7ae9cd8
|
||||
version: "1.19"
|
||||
|
||||
version: "1.20"
|
||||
- tlib#arg: Completion for comma-separated lists
|
||||
- Use "silent cd"
|
||||
- NEW tlib#type#DefSchema(); FIX tlib#type#Has()
|
||||
- tlib#cache#Value(): minor change
|
||||
- tlib#date#IsDate() also checks whether the date is valid
|
||||
- ! tlib#sys#Open(): escape special chars only once
|
||||
- tlib#trace#Print: Allow for strings
|
||||
- :Tlibtrace, :Tlibtraceset, :Tlibassert remove `-bar`
|
||||
- NEW :Tlibtype (type/schema assertions); tlib#type#Is() also accepts schemas as "types"
|
||||
- tlib#dir#CD(): Use haslocaldir()
|
||||
- tlib#qfl#AgentGotoQFE: Don't use wincmd w
|
||||
- NEW tlib#string#Input()
|
||||
- FIX g:tlib#sys#system_rx; add OpenOffice exensions to g:tlib#sys#special_suffixes
|
||||
- NEW tlib#selection#GetSelection()
|
||||
- tlib#date#Shift(): Fix "Xm", ++specs
|
||||
- tlib#trace#Set: FIX Properly handly "-label"
|
||||
MD5 checksum: c919e0782931a8c628c6996903f989d3
|
||||
|
||||
- tlib#date#Shift(): Support for business days 'Nb'
|
||||
- tlib#list#Uniq: Properly handle empty strings
|
||||
- tlib#trace: Use g:tlib#trace#printer and tlib#trace#Printer_{printer}
|
||||
- tlib#dictionary#Rev: Optional argument `opts = {}`; properly handle empty values etc.
|
||||
- NEW g:tlib#trace#hl
|
||||
- NEW spec/dictionary.vim
|
||||
- tlib#agent#CompleteAgentNames: case insensitive
|
||||
- tlib#arg#CComplete: --[no-]debug option
|
||||
- tlib#date#Format: use localtime() if no arg is provided
|
||||
- NEW tlib#file#IsAbsolute
|
||||
- NEW tlib#notify#PrintError()
|
||||
- tlib#trace#Print: FIX s/exec/call/
|
||||
- tlib#type#Is() match full type name
|
||||
- NEW tlib#string#MatchAll()
|
||||
- Tlibtraceset, tlib#trace#Set(): If no `+` or `-` is prepended, assume `+`.
|
||||
- tlib#list#Input: fix highlighting for filenames
|
||||
- tlib#input#ListW: use world.CloseScratch(1)
|
||||
- tlib#agent#ViewFile: Ignore errors in :exec back
|
||||
- NEW tlib#agent#EditFileInWindow()
|
||||
- :Tlibtraceset uses tlib#arg#GetOpts(), i.e. you can set the log file more easily
|
||||
MD5 checksum: 20a48e225f32b9f58808096a5377af04
|
||||
version: "1.22"
|
||||
|
||||
- tlib#date#Shift(): Support for business days 'Nb'
|
||||
- tlib#list#Uniq: Properly handle empty strings
|
||||
- tlib#trace: Use g:tlib#trace#printer and tlib#trace#Printer_{printer}
|
||||
- tlib#dictionary#Rev: Optional argument `opts = {}`; properly handle empty values etc.
|
||||
- NEW g:tlib#trace#hl
|
||||
- NEW spec/dictionary.vim
|
||||
- tlib#agent#CompleteAgentNames: case insensitive
|
||||
- tlib#arg#CComplete: --[no-]debug option
|
||||
- tlib#date#Format: use localtime() if no arg is provided
|
||||
- NEW tlib#file#IsAbsolute
|
||||
- NEW tlib#notify#PrintError()
|
||||
- tlib#trace#Print: FIX s/exec/call/
|
||||
- tlib#type#Is() match full type name
|
||||
- NEW tlib#string#MatchAll()
|
||||
- Tlibtraceset, tlib#trace#Set(): If no `+` or `-` is prepended, assume `+`.
|
||||
- tlib#list#Input: fix highlighting for filenames
|
||||
- tlib#input#ListW: use world.CloseScratch(1)
|
||||
- tlib#agent#ViewFile: Ignore errors in :exec back
|
||||
- NEW tlib#agent#EditFileInWindow()
|
||||
- :Tlibtraceset uses tlib#arg#GetOpts(), i.e. you can set the log file more easily
|
||||
MD5 checksum: 20a48e225f32b9f58808096a5377af04
|
||||
version: "1.22"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
- bump version 1.23 + misc changes
|
||||
- FIX #24: avoid vim8 features
|
||||
- tlib#win#GetID(): Alternative implementation sets a window variable to identify the window
|
||||
- tlib#arg#GetOpts(): If args is a dict, return it
|
||||
- tlib#file#FilterFiles(): FIX typo
|
||||
- tlib#trace#Set: Experimental support for log levels
|
||||
- tlib#input#ListW: make sure to close scratch when <= 1 items are in the list
|
||||
- FIX #25: set win_nr again; fix some lint warnings
|
||||
- tlib#progressbar#Init(): returns a statusline definition that can be used for restor
|
||||
MD5 checksum: c4d6e018cbbd3b286a9b1648b748c1f3
|
||||
version: "1.23"
|
||||
|
||||
@@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
@@ -0,0 +1,32 @@
|
||||
This library provides some utility functions. There isn't much need to
|
||||
install it unless another plugin requires you to do so.
|
||||
|
||||
Most of the library is included in autoload files. No autocommands are
|
||||
created. With the exception of loading ../plugin/02tlib.vim at startup
|
||||
the library has no impact on startup time or anything else.
|
||||
|
||||
The change-log is included at the bottom of ../plugin/02tlib.vim
|
||||
(move the cursor over the file name and type gfG)
|
||||
|
||||
Demo of |tlib#input#List()|:
|
||||
http://vimsomnia.blogspot.com/2010/11/selecting-items-from-list-with-tlibs.html
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
Install~
|
||||
|
||||
Edit the vba file and type: >
|
||||
|
||||
:so %
|
||||
|
||||
See :help vimball for details. If you have difficulties, please make
|
||||
sure, you have the current version of vimball (vimscript #1502)
|
||||
installed.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
License: GPLv3 or later
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name" : "tlib",
|
||||
"version" : "dev",
|
||||
"author" : "Tom Link <micathom at gmail com>",
|
||||
"maintainer" : "Tom Link <micathom at gmail com>",
|
||||
"repository" : {"type": "git", "url": "git://github.com/tomtom/tlib_vim.git"},
|
||||
"dependencies" : {},
|
||||
"description" : "tlib -- A library of vim functions"
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
" para_move.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2012-08-28.
|
||||
" @Last Change: 2012-08-29.
|
||||
" @Revision: 3
|
||||
|
||||
" Move paragraphs
|
||||
call tinykeymap#EnterMap("para_move", "gp", {'name': 'move paragraph'})
|
||||
call tinykeymap#Map("para_move", "j", "silent call tlib#paragraph#Move('Down', '<count>')")
|
||||
call tinykeymap#Map("para_move", "k", "silent call tlib#paragraph#Move('Up', '<count>')")
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 13
|
||||
|
||||
" :nodefault:
|
||||
TLet g:tlib#debug = 0
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
" Filter_cnf.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2008-11-25.
|
||||
" @Last Change: 2017-09-28.
|
||||
" @Revision: 11.0.114
|
||||
|
||||
let s:prototype = tlib#Object#New({'_class': ['Filter_cnf'], 'name': 'cnf'}) "{{{2
|
||||
let s:prototype.highlight = g:tlib#input#higroup
|
||||
|
||||
" The search pattern for |tlib#input#List()| is in conjunctive normal
|
||||
" form: (P1 OR P2 ...) AND (P3 OR P4 ...) ...
|
||||
" The pattern is a '/\V' very no-'/magic' regexp pattern.
|
||||
"
|
||||
" Pressing <space> joins two patterns with AND.
|
||||
" Pressing | joins two patterns with OR.
|
||||
" I.e. In order to get "lala AND (foo OR bar)", you type
|
||||
" "lala foo|bar".
|
||||
"
|
||||
" This is also the base class for other filters.
|
||||
function! tlib#Filter_cnf#New(...) "{{{3
|
||||
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Init(world) dict "{{{3
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Help(world) dict "{{{3
|
||||
call a:world.PushHelp(
|
||||
\ printf('"%s", "%s", "%sWORD"', g:tlib#input#and, g:tlib#input#or, g:tlib#input#not),
|
||||
\ 'AND, OR, NOT')
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.AssessName(world, name) dict "{{{3
|
||||
let xa = 0
|
||||
let prefix = self.FilterRxPrefix()
|
||||
for flt in a:world.filter_pos
|
||||
" let flt = prefix . a:world.GetRx(fltl)
|
||||
" if flt =~# '\u' && a:name =~# flt
|
||||
" let xa += 5
|
||||
" endif
|
||||
let rel = 1.0 + 5.0 * len(flt) / len(a:name)
|
||||
let xa += float2nr(rel)
|
||||
if a:name =~ '\^'. flt
|
||||
let xa += 4
|
||||
elseif a:name =~ '\<'. flt
|
||||
let xa += 3
|
||||
" elseif a:name =~ '[[:punct:][:space:][:digit:]]'. flt
|
||||
" let xa += 2
|
||||
elseif a:name =~ '\A'. flt .'\|'. flt .'\A'
|
||||
let xa += 1
|
||||
endif
|
||||
endfor
|
||||
" TLogVAR a:name, xa
|
||||
return xa
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Match(world, text) dict "{{{3
|
||||
" TLogVAR a:text
|
||||
" let sc = &smartcase
|
||||
" let ic = &ignorecase
|
||||
" if &ignorecase
|
||||
" set smartcase
|
||||
" endif
|
||||
" try
|
||||
if !empty(a:world.filter_neg)
|
||||
for rx in a:world.filter_neg
|
||||
" TLogVAR rx
|
||||
if a:text =~ rx
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
if !empty(a:world.filter_pos)
|
||||
for rx in a:world.filter_pos
|
||||
" TLogVAR rx
|
||||
if a:text !~ rx
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
" finally
|
||||
" let &smartcase = sc
|
||||
" let &ignorecase = ic
|
||||
" endtry
|
||||
return 1
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.DisplayFilter(filter) dict "{{{3
|
||||
let filter1 = deepcopy(a:filter)
|
||||
call map(filter1, '"(". join(reverse(self.Pretty(v:val)), " OR ") .")"')
|
||||
return join(reverse(filter1), ' AND ')
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.Pretty(filter) dict "{{{3
|
||||
" call map(a:filter, 'substitute(v:val, ''\\\.\\{-}'', ''=>'', ''g'')')
|
||||
call map(a:filter, 'self.CleanFilter(v:val)')
|
||||
return a:filter
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
|
||||
let a:world.filter[0] = reverse(split(a:pattern, '\s*|\s*')) + a:world.filter[0][1 : -1]
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
|
||||
let a:world.filter[0][0] .= nr2char(a:char)
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.ReduceFrontFilter(world) dict "{{{3
|
||||
let filter = a:world.filter[0][0]
|
||||
" TLogVAR filter
|
||||
let str = matchstr(filter, '\(\\\(\.\\{-}\|[.?*+$^]\)\|\)$')
|
||||
if empty(str)
|
||||
let filter = filter[0 : -2]
|
||||
else
|
||||
let filter = tlib#string#Strcharpart(filter, 0, len(filter) - len(str))
|
||||
endif
|
||||
" TLogVAR str, filter
|
||||
let a:world.filter[0][0] = filter
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.FilterRxPrefix() dict "{{{3
|
||||
return '\V'
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.CleanFilter(filter) dict "{{{3
|
||||
return a:filter
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
" Filter_cnfd.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2008-11-25.
|
||||
" @Last Change: 2014-01-23.
|
||||
" @Revision: 0.0.57
|
||||
|
||||
let s:prototype = tlib#Filter_cnf#New({'_class': ['Filter_cnfd'], 'name': 'cnfd'}) "{{{2
|
||||
let s:prototype.highlight = g:tlib#input#higroup
|
||||
|
||||
|
||||
" The same as |tlib#Filter_cnf#New()| but a dot is expanded to '\.\{-}'.
|
||||
" As a consequence, patterns cannot match dots.
|
||||
" The pattern is a '/\V' very no-'/magic' regexp pattern.
|
||||
function! tlib#Filter_cnfd#New(...) "{{{3
|
||||
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Init(world) dict "{{{3
|
||||
endf
|
||||
|
||||
|
||||
let s:Help = s:prototype.Help
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Help(world) dict "{{{3
|
||||
call call(s:Help, [a:world], self)
|
||||
call a:world.PushHelp('.', 'Any characters')
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
|
||||
let pattern = substitute(a:pattern, '\.', '\\.\\{-}', 'g')
|
||||
let a:world.filter[0] = reverse(split(pattern, '\s*|\s*')) + a:world.filter[0][1 : -1]
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
|
||||
let a:world.filter[0][0] .= a:char == 46 ? '\.\{-}' : nr2char(a:char)
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.CleanFilter(filter) dict "{{{3
|
||||
return substitute(a:filter, '\\.\\{-}', '.', 'g')
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
" Filter_fuzzy.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2008-11-25.
|
||||
" @Last Change: 2013-09-25.
|
||||
" @Revision: 0.0.47
|
||||
|
||||
let s:prototype = tlib#Filter_cnf#New({'_class': ['Filter_fuzzy'], 'name': 'fuzzy'}) "{{{2
|
||||
let s:prototype.highlight = g:tlib#input#higroup
|
||||
|
||||
|
||||
" Support for "fuzzy" pattern matching in |tlib#input#List()|.
|
||||
" Patterns are interpreted as if characters were connected with '.\{-}'.
|
||||
"
|
||||
" In "fuzzy" mode, the pretty printing of filenames is disabled.
|
||||
function! tlib#Filter_fuzzy#New(...) "{{{3
|
||||
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Init(world) dict "{{{3
|
||||
" TLogVAR a:world.display_format
|
||||
" :nodoc:
|
||||
function! a:world.Set_display_format(value) dict
|
||||
if a:value == 'filename'
|
||||
let self.display_format = ''
|
||||
else
|
||||
let self.display_format = a:value
|
||||
endif
|
||||
endf
|
||||
endf
|
||||
|
||||
|
||||
let s:Help = s:prototype.Help
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Help(world) dict "{{{3
|
||||
call call(s:Help, [a:world], self)
|
||||
call a:world.PushHelp('Patterns are interpreted as if characters were connected with .\{-}')
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.DisplayFilter(filter) dict "{{{3
|
||||
" TLogVAR a:filter
|
||||
let filter1 = deepcopy(a:filter)
|
||||
call map(filter1, '"{". join(reverse(v:val), " OR ") ."}"')
|
||||
return join(reverse(filter1), ' AND ')
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
|
||||
let a:world.filter[0] = map(reverse(split(a:pattern, '\s*|\s*')), 'join(map(split(v:val, ''\zs''), ''tlib#rx#Escape(v:val, "V")''), ''\.\{-}'')') + a:world.filter[0][1 : -1]
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
|
||||
let ch = tlib#rx#Escape(nr2char(a:char), 'V')
|
||||
if empty(a:world.filter[0][0])
|
||||
let a:world.filter[0][0] .= ch
|
||||
else
|
||||
let a:world.filter[0][0] .= '\.\{-}'. ch
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.ReduceFrontFilter(world) dict "{{{3
|
||||
let a:world.filter[0][0] = substitute(a:world.filter[0][0], '\(\\\.\\{-}\)\?.$', '', '')
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.CleanFilter(filter) dict "{{{3
|
||||
return substitute(a:filter, '\\\.\\{-}', '', 'g')
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2008-11-25.
|
||||
" @Last Change: 2014-11-18.
|
||||
" @Revision: 0.0.82
|
||||
|
||||
let s:prototype = tlib#Filter_cnf#New({'_class': ['Filter_glob'], 'name': 'glob'}) "{{{2
|
||||
let s:prototype.highlight = g:tlib#input#higroup
|
||||
|
||||
|
||||
" A character that should be expanded to '\.\{-}'.
|
||||
TLet g:tlib#Filter_glob#seq = '*'
|
||||
|
||||
|
||||
" A character that should be expanded to '\.\?'.
|
||||
TLet g:tlib#Filter_glob#char = '?'
|
||||
|
||||
|
||||
" The same as |tlib#Filter_cnf#New()| but a a customizable character
|
||||
" |see tlib#Filter_glob#seq| is expanded to '\.\{-}' and
|
||||
" |g:tlib#Filter_glob#char| is expanded to '\.'.
|
||||
" The pattern is a '/\V' very no-'/magic' regexp pattern.
|
||||
function! tlib#Filter_glob#New(...) "{{{3
|
||||
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
let s:Help = s:prototype.Help
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.Help(world) dict "{{{3
|
||||
call call(s:Help, [a:world], self)
|
||||
call a:world.PushHelp(g:tlib#Filter_glob#seq, 'Any characters')
|
||||
call a:world.PushHelp(g:tlib#Filter_glob#char, 'Single characters')
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.SetFrontFilter(world, pattern) dict "{{{3
|
||||
let pattern = substitute(a:pattern, tlib#rx#Escape(g:tlib#Filter_glob#seq, 'V'), '\\.\\{-}', 'g')
|
||||
let pattern = substitute(a:pattern, tlib#rx#Escape(g:tlib#Filter_glob#char, 'V'), '\\.', 'g')
|
||||
let a:world.filter[0] = reverse(split(pattern, '\s*|\s*')) + a:world.filter[0][1 : -1]
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.PushFrontFilter(world, char) dict "{{{3
|
||||
" TLogVAR a:char, nr2char(a:char)
|
||||
if a:char == char2nr(g:tlib#Filter_glob#seq)
|
||||
let char = '\.\{-}'
|
||||
elseif a:char == char2nr(g:tlib#Filter_glob#char)
|
||||
let char = '\.'
|
||||
else
|
||||
let char = nr2char(a:char)
|
||||
endif
|
||||
let a:world.filter[0][0] .= char
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! s:prototype.CleanFilter(filter) dict "{{{3
|
||||
let filter = substitute(a:filter, '\\\.\\{-}', g:tlib#Filter_glob#seq, 'g')
|
||||
let filter = substitute(filter, '\\\.', g:tlib#Filter_glob#char, 'g')
|
||||
return filter
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 127
|
||||
|
||||
" :filedoc:
|
||||
" Provides a prototype plus some OO-like methods.
|
||||
|
||||
let s:id_counter = 0
|
||||
let s:prototype = {'_class': ['object'], '_super': [], '_id': 0} "{{{2
|
||||
|
||||
" :def: function! tlib#Object#New(?fields={})
|
||||
" This function creates a prototype that provides some kind of
|
||||
" inheritance mechanism and a way to call parent/super methods.
|
||||
"
|
||||
" The usage demonstrated in the following example works best when every
|
||||
" class/prototype is defined in a file of its own.
|
||||
"
|
||||
" The reason for why there is a dedicated constructor function is that
|
||||
" this layout facilitates the use of templates and that methods are
|
||||
" hidden from the user. Other solutions are possible.
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" let s:prototype = tlib#Object#New({
|
||||
" \ '_class': ['FooBar'],
|
||||
" \ 'foo': 1,
|
||||
" \ 'bar': 2,
|
||||
" \ })
|
||||
" " Constructor
|
||||
" function! FooBar(...)
|
||||
" let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
" return object
|
||||
" endf
|
||||
" function! s:prototype.babble() {
|
||||
" echo "I think, therefore I am ". (self.foo * self.bar) ." months old."
|
||||
" }
|
||||
"
|
||||
" < This could now be used like this: >
|
||||
" let myfoo = FooBar({'foo': 3})
|
||||
" call myfoo.babble()
|
||||
" => I think, therefore I am 6 months old.
|
||||
" echo myfoo.IsA('FooBar')
|
||||
" => 1
|
||||
" echo myfoo.IsA('object')
|
||||
" => 1
|
||||
" echo myfoo.IsA('Foo')
|
||||
" => 0
|
||||
" echo myfoo.RespondTo('babble')
|
||||
" => 1
|
||||
" echo myfoo.RespondTo('speak')
|
||||
" => 0
|
||||
function! tlib#Object#New(...) "{{{3
|
||||
return s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.New(...) dict "{{{3
|
||||
let object = deepcopy(self)
|
||||
let s:id_counter += 1
|
||||
let object._id = s:id_counter
|
||||
if a:0 >= 1 && !empty(a:1)
|
||||
" call object.Extend(deepcopy(a:1))
|
||||
call object.Extend(a:1)
|
||||
endif
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.Inherit(object) dict "{{{3
|
||||
let class = copy(self._class)
|
||||
" TLogVAR class
|
||||
let objid = self._id
|
||||
for c in get(a:object, '_class', [])
|
||||
" TLogVAR c
|
||||
if index(class, c) == -1
|
||||
call add(class, c)
|
||||
endif
|
||||
endfor
|
||||
call extend(self, a:object, 'keep')
|
||||
let self._class = class
|
||||
" TLogVAR self._class
|
||||
let self._id = objid
|
||||
" let self._super = [super] + self._super
|
||||
call insert(self._super, a:object)
|
||||
return self
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.Extend(dictionary) dict "{{{3
|
||||
let super = copy(self)
|
||||
let class = copy(self._class)
|
||||
" TLogVAR class
|
||||
let objid = self._id
|
||||
let thisclass = get(a:dictionary, '_class', [])
|
||||
for c in type(thisclass) == 3 ? thisclass : [thisclass]
|
||||
" TLogVAR c
|
||||
if index(class, c) == -1
|
||||
call add(class, c)
|
||||
endif
|
||||
endfor
|
||||
call extend(self, a:dictionary)
|
||||
let self._class = class
|
||||
" TLogVAR self._class
|
||||
let self._id = objid
|
||||
" let self._super = [super] + self._super
|
||||
call insert(self._super, super)
|
||||
return self
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.IsA(class) dict "{{{3
|
||||
return index(self._class, a:class) != -1
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.IsRelated(object) dict "{{{3
|
||||
return len(filter(a:object._class, 'self.IsA(v:val)')) > 1
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.RespondTo(name) dict "{{{3
|
||||
" return has_key(self, a:name) && type(self[a:name]) == 2
|
||||
return has_key(self, a:name)
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.Super(method, arglist) dict "{{{3
|
||||
for o in self._super
|
||||
" TLogVAR o
|
||||
if o.RespondTo(a:method)
|
||||
" let self._tmp_method = o[a:method]
|
||||
" TLogVAR self._tmp_method
|
||||
" return call(self._tmp_method, a:arglist, self)
|
||||
return call(o[a:method], a:arglist, self)
|
||||
endif
|
||||
endfor
|
||||
echoerr 'tlib#Object: Does not respond to '. a:method .': '. string(self)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#Object#Methods(object, ...) "{{{3
|
||||
TVarArg ['pattern', '\d\+']
|
||||
let o = items(a:object)
|
||||
call filter(o, 'type(v:val[1]) == 2 && string(v:val[1]) =~ "^function(''\\d\\+'')"')
|
||||
let acc = {}
|
||||
for e in o
|
||||
let id = matchstr(string(e[1]), pattern)
|
||||
if !empty(id)
|
||||
let acc[id] = e[0]
|
||||
endif
|
||||
endfor
|
||||
return acc
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 11
|
||||
|
||||
" :enddoc:
|
||||
|
||||
|
||||
let s:prototype = tlib#Object#New({'_class': ['Test']}) "{{{2
|
||||
function! tlib#Test#New(...) "{{{3
|
||||
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.Dummy() dict "{{{3
|
||||
return 'Test.vim'
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 15
|
||||
|
||||
" :enddoc:
|
||||
|
||||
|
||||
let s:prototype = tlib#Test#New({'_class': ['TestChild']}) "{{{2
|
||||
function! tlib#TestChild#New(...) "{{{3
|
||||
let object = s:prototype.New(a:0 >= 1 ? a:1 : {})
|
||||
return object
|
||||
endf
|
||||
|
||||
|
||||
function! s:prototype.Dummy() dict "{{{3
|
||||
return 'TestChild.vim'
|
||||
endf
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,716 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 362
|
||||
|
||||
" :filedoc:
|
||||
" Various agents for use as key handlers in tlib#input#List()
|
||||
|
||||
" Number of items to move when pressing <c-up/down> in the input list window.
|
||||
TLet g:tlib_scroll_lines = 10
|
||||
|
||||
|
||||
" General {{{1
|
||||
|
||||
function! tlib#agent#Exit(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if a:world.key_mode ==# 'default'
|
||||
call a:world.CloseScratch()
|
||||
let a:world.state = 'exit empty escape'
|
||||
let a:world.list = []
|
||||
" let a:world.base = []
|
||||
call a:world.ResetSelected()
|
||||
else
|
||||
let a:world.key_mode = 'default'
|
||||
let a:world.state = 'redisplay'
|
||||
endif
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#CopyItems(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let @* = join(a:selected, "\n")
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
|
||||
" InputList related {{{1
|
||||
|
||||
function! tlib#agent#PageUp(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.offset -= (winheight(0) / 2)
|
||||
let a:world.state = 'scroll'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#PageDown(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.offset += (winheight(0) / 2)
|
||||
let a:world.state = 'scroll'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Home(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.prefidx = 1
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#End(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.prefidx = len(a:world.list)
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Up(world, selected, ...) "{{{3
|
||||
TVarArg ['lines', 1]
|
||||
Tlibtrace 'tlib', a:selected, lines
|
||||
let a:world.idx = ''
|
||||
if a:world.prefidx > lines
|
||||
let a:world.prefidx -= lines
|
||||
else
|
||||
let a:world.prefidx = len(a:world.list)
|
||||
endif
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Down(world, selected, ...) "{{{3
|
||||
TVarArg ['lines', 1]
|
||||
Tlibtrace 'tlib', a:selected, lines
|
||||
let a:world.idx = ''
|
||||
if a:world.prefidx <= (len(a:world.list) - lines)
|
||||
let a:world.prefidx += lines
|
||||
else
|
||||
let a:world.prefidx = 1
|
||||
endif
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#UpN(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
return tlib#agent#Up(a:world, a:selected, g:tlib_scroll_lines)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#DownN(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
return tlib#agent#Down(a:world, a:selected, g:tlib_scroll_lines)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ShiftLeft(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.offset_horizontal -= (winwidth(0) / 2)
|
||||
if a:world.offset_horizontal < 0
|
||||
let a:world.offset_horizontal = 0
|
||||
endif
|
||||
let a:world.state = 'display shift'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ShiftRight(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.offset_horizontal += (winwidth(0) / 2)
|
||||
let a:world.state = 'display shift'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Reset(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.state = 'reset'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ToggleRestrictView(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if empty(a:world.filtered_items)
|
||||
return tlib#agent#RestrictView(a:world, a:selected)
|
||||
else
|
||||
return tlib#agent#UnrestrictView(a:world, a:selected)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#RestrictView(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let filtered_items = map(copy(a:selected), 'index(a:world.base, v:val) + 1')
|
||||
Tlibtrace 'tlib', 1, filtered_items
|
||||
let filtered_items = filter(filtered_items, 'v:val > 0')
|
||||
Tlibtrace 'tlib', 2, filtered_items
|
||||
if !empty(filtered_items)
|
||||
let a:world.filtered_items = filtered_items
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#UnrestrictView(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.filtered_items = []
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Input(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let flt0 = a:world.CleanFilter(a:world.filter[0][0])
|
||||
let flt1 = input('Filter: ', flt0)
|
||||
echo
|
||||
if flt1 != flt0
|
||||
if empty(flt1)
|
||||
call getchar(0)
|
||||
else
|
||||
call a:world.SetFrontFilter(flt1)
|
||||
endif
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
" Suspend (see |tlib#agent#Suspend|) the input loop and jump back to the
|
||||
" original position in the parent window.
|
||||
function! tlib#agent#SuspendToParentWindow(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let world = a:world
|
||||
let wid = world.win_id
|
||||
Tlibtrace 'tlib', wid
|
||||
if wid != -1
|
||||
let world = tlib#agent#Suspend(world, a:selected)
|
||||
if world.state =~# '\<suspend\>'
|
||||
call world.SwitchWindow('win')
|
||||
" let pos = world.cursor
|
||||
" Tlibtrace 'tlib', pos
|
||||
" if !empty(pos)
|
||||
" call setpos('.', pos)
|
||||
" endif
|
||||
return world
|
||||
endif
|
||||
endif
|
||||
let world.state = 'redisplay'
|
||||
return world
|
||||
endf
|
||||
|
||||
|
||||
" Suspend lets you temporarily leave the input loop of
|
||||
" |tlib#input#List|. You can resume editing the list by pressing <c-z>,
|
||||
" <m-z>. <space>, <c-LeftMouse> or <MiddleMouse> in the suspended window.
|
||||
" <cr> and <LeftMouse> will immediatly select the item under the cursor.
|
||||
" < will select the item but the window will remain opened.
|
||||
function! tlib#agent#Suspend(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if a:world.allow_suspend
|
||||
" TAssert IsNotEmpty(a:world.scratch)
|
||||
" TLogDBG bufnr('%')
|
||||
let br = tlib#buffer#Set(a:world.scratch)
|
||||
Tlibtrace 'tlib', br, a:world.bufnr, a:world.scratch
|
||||
if bufnr('%') != a:world.scratch
|
||||
echohl WarningMsg
|
||||
echom "tlib#agent#Suspend: Internal error: Not a scratch buffer:" bufname('%')
|
||||
echohl NONE
|
||||
endif
|
||||
Tlibtrace 'tlib', bufnr('%'), bufname('%'), a:world.scratch
|
||||
call tlib#autocmdgroup#Init()
|
||||
exec 'autocmd TLib BufEnter <buffer='. a:world.scratch .'> call tlib#input#Resume("world", 0, '. a:world.scratch .')'
|
||||
let b:tlib_world = a:world
|
||||
exec br
|
||||
let a:world.state = 'exit suspend'
|
||||
else
|
||||
echom 'Suspend disabled'
|
||||
let a:world.state = 'redisplay'
|
||||
endif
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Help(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.state = 'help'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#OR(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:world.filter[0])
|
||||
call insert(a:world.filter[0], '')
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#AND(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:world.filter[0])
|
||||
call insert(a:world.filter, [''])
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ReduceFilter(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.ReduceFilter()
|
||||
let a:world.offset = 1
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#PopFilter(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.PopFilter()
|
||||
let a:world.offset = 1
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Debug(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
" echo string(world.state)
|
||||
echo string(a:world.filter)
|
||||
echo string(a:world.idx)
|
||||
echo string(a:world.prefidx)
|
||||
echo string(a:world.sel_idx)
|
||||
call getchar()
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Select(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.SelectItem('toggle', a:world.prefidx)
|
||||
" let a:world.state = 'display keepcursor'
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#SelectUp(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.SelectItem('toggle', a:world.prefidx)
|
||||
if a:world.prefidx > 1
|
||||
let a:world.prefidx -= 1
|
||||
endif
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#SelectDown(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.SelectItem('toggle', a:world.prefidx)
|
||||
if a:world.prefidx < len(a:world.list)
|
||||
let a:world.prefidx += 1
|
||||
endif
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#SelectAll(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let listrange = range(1, len(a:world.list))
|
||||
let mode = empty(filter(copy(listrange), 'index(a:world.sel_idx, a:world.GetBaseIdx(v:val)) == -1'))
|
||||
\ ? 'toggle' : 'set'
|
||||
for i in listrange
|
||||
call a:world.SelectItem(mode, i)
|
||||
endfor
|
||||
let a:world.state = 'display keepcursor'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ToggleStickyList(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.sticky = !a:world.sticky
|
||||
let a:world.state = 'display keepcursor'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
|
||||
" EditList related {{{1
|
||||
|
||||
function! tlib#agent#EditItem(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let lidx = a:world.prefidx
|
||||
Tlibtrace 'tlib', lidx
|
||||
let bidx = a:world.GetBaseIdx(lidx)
|
||||
Tlibtrace 'tlib', bidx
|
||||
let item = a:world.GetBaseItem(bidx)
|
||||
let item = input(lidx .'@'. bidx .': ', item)
|
||||
if item != ''
|
||||
call a:world.SetBaseItem(bidx, item)
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
" Insert a new item below the current one.
|
||||
function! tlib#agent#NewItem(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let basepi = a:world.GetBaseIdx(a:world.prefidx)
|
||||
let item = input('New item: ')
|
||||
call insert(a:world.base, item, basepi)
|
||||
let a:world.state = 'reset'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#DeleteItems(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let remove = copy(a:world.sel_idx)
|
||||
let basepi = a:world.GetBaseIdx(a:world.prefidx)
|
||||
if index(remove, basepi) == -1
|
||||
call add(remove, basepi)
|
||||
endif
|
||||
" call map(remove, 'a:world.GetBaseIdx(v:val)')
|
||||
for idx in reverse(sort(remove))
|
||||
call remove(a:world.base, idx - 1)
|
||||
endfor
|
||||
let a:world.state = 'display'
|
||||
call a:world.ResetSelected()
|
||||
" let a:world.state = 'reset'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Cut(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let world = tlib#agent#Copy(a:world, a:selected)
|
||||
return tlib#agent#DeleteItems(world, a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Copy(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.clipboard = []
|
||||
let bidxs = copy(a:world.sel_idx)
|
||||
call add(bidxs, a:world.GetBaseIdx(a:world.prefidx))
|
||||
for bidx in sort(bidxs)
|
||||
call add(a:world.clipboard, a:world.GetBaseItem(bidx))
|
||||
endfor
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Paste(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if has_key(a:world, 'clipboard')
|
||||
for e in reverse(copy(a:world.clipboard))
|
||||
call insert(a:world.base, e, a:world.prefidx)
|
||||
endfor
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
call a:world.ResetSelected()
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#EditReturnValue(world, rv) "{{{3
|
||||
Tlibtrace 'tlib', a:rv
|
||||
return [a:world.state !~ '\<exit\>', a:world.base]
|
||||
endf
|
||||
|
||||
|
||||
|
||||
" Files related {{{1
|
||||
|
||||
function! tlib#agent#ViewFile(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:selected)
|
||||
let back = a:world.SwitchWindow('win')
|
||||
Tlibtrace 'tlib', back
|
||||
for filename in a:selected
|
||||
call tlib#file#Edit(filename)
|
||||
endfor
|
||||
call a:world.SetOrigin(1)
|
||||
silent! exec back
|
||||
let a:world.state = 'display'
|
||||
endif
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#EditFile(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
return tlib#agent#Exit(tlib#agent#ViewFile(a:world, a:selected), a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#EditFileInSplit(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.CloseScratch()
|
||||
call tlib#file#With('split', 'sbuffer', a:selected, a:world, 1)
|
||||
call a:world.SetOrigin(1)
|
||||
return tlib#agent#Exit(a:world, a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#EditFileInVSplit(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.CloseScratch()
|
||||
let winpos = tlib#fixes#Winpos()
|
||||
call tlib#file#With('vertical split', 'vertical sbuffer', a:selected, a:world, 1)
|
||||
if !empty(winpos)
|
||||
exec winpos
|
||||
endif
|
||||
call a:world.SetOrigin(1)
|
||||
return tlib#agent#Exit(a:world, a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#EditFileInTab(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.CloseScratch()
|
||||
call tlib#file#With('tabedit', 'tab sbuffer', a:selected, a:world, 1)
|
||||
call a:world.SetOrigin(1)
|
||||
return tlib#agent#Exit(a:world, a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#EditFileInWindow(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
call a:world.CloseScratch()
|
||||
call tlib#file#With('hide edit', 'hide buffer', a:selected, a:world, 1)
|
||||
call a:world.SetOrigin(1)
|
||||
return tlib#agent#Exit(a:world, a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ToggleScrollbind(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.scrollbind = get(a:world, 'scrollbind') ? 0 : 1
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ShowInfo(world, selected)
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let lines = []
|
||||
for f in a:selected
|
||||
if filereadable(f)
|
||||
let desc = [getfperm(f), strftime('%c', getftime(f)), getfsize(f) .' bytes', getftype(f)]
|
||||
call add(lines, fnamemodify(f, ':p'))
|
||||
call add(lines, ' '. join(desc, '; '))
|
||||
endif
|
||||
endfor
|
||||
let a:world.temp_lines = lines
|
||||
let a:world.state = 'printlines'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
|
||||
" Buffer related {{{1
|
||||
|
||||
function! tlib#agent#ViewBufferInWindow(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:selected)
|
||||
let back = a:world.SwitchWindow('win')
|
||||
Tlibtrace 'tlib', back
|
||||
for bufname in a:selected
|
||||
let cmd = &modified && !&hidden ? 'sbuffer' : 'buffer'
|
||||
exec cmd fnameescape(bufname)
|
||||
endfor
|
||||
" exec back
|
||||
endif
|
||||
return tlib#agent#Exit(a:world, a:selected)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#PreviewLine(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let l = a:selected[0]
|
||||
" let ww = winnr()
|
||||
let wid = tlib#win#GetID()
|
||||
call tlib#agent#SuspendToParentWindow(a:world, a:selected)
|
||||
call tlib#buffer#ViewLine(l, 1)
|
||||
call tlib#win#GotoID(wid)
|
||||
" exec ww .'wincmd w'
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
" If not called from the scratch, we assume/guess that we don't have to
|
||||
" suspend the input-evaluation loop.
|
||||
function! tlib#agent#GotoLine(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:selected)
|
||||
let l = a:selected[0]
|
||||
if a:world.win_id != tlib#win#GetID()
|
||||
let world = tlib#agent#Suspend(a:world, a:selected)
|
||||
call tlib#win#GotoID(a:world.win_id)
|
||||
endif
|
||||
call tlib#buffer#ViewLine(l, 1)
|
||||
|
||||
endif
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#DoAtLine(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:selected)
|
||||
let cmd = input('Command: ', '', 'command')
|
||||
if !empty(cmd)
|
||||
call a:world.SwitchWindow('win')
|
||||
" let pos = getpos('.')
|
||||
let view = winsaveview()
|
||||
for l in a:selected
|
||||
call tlib#buffer#ViewLine(l, '')
|
||||
exec cmd
|
||||
endfor
|
||||
" call setpos('.', pos)
|
||||
call winrestview(view)
|
||||
endif
|
||||
endif
|
||||
call a:world.ResetSelected()
|
||||
let a:world.state = 'exit'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Wildcard(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
if !empty(a:world.filter[0])
|
||||
let rx_type = a:world.matcher.FilterRxPrefix()
|
||||
let flt0 = a:world.CleanFilter(a:world.filter[0][0])
|
||||
if rx_type == '\V'
|
||||
let flt0 .= '\.\{-}'
|
||||
else
|
||||
let flt0 .= '.\{-}'
|
||||
endif
|
||||
call a:world.SetFrontFilter(flt0)
|
||||
endif
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Null(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#ExecAgentByName(world, selected) "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let s:agent_names_world = a:world
|
||||
let agent_names = {'Help': 'tlib#agent#Help'}
|
||||
for def in values(a:world.key_map[a:world.key_mode])
|
||||
if has_key(def, 'help') && !empty(def.help) && has_key(def, 'agent') && !empty(def.agent)
|
||||
let agent_names[def.help] = def.agent
|
||||
endif
|
||||
endfor
|
||||
let s:agent_names = sort(keys(agent_names))
|
||||
let command = input('Command: ', '', 'customlist,tlib#agent#CompleteAgentNames')
|
||||
Tlibtrace 'tlib', command
|
||||
if !has_key(agent_names, command)
|
||||
Tlibtrace 'tlib', command
|
||||
silent! let matches = filter(keys(agent_names), 'v:val =~ command')
|
||||
Tlibtrace 'tlib', matches
|
||||
if len(matches) == 1
|
||||
let command = matches[0]
|
||||
endif
|
||||
endif
|
||||
if has_key(agent_names, command)
|
||||
let agent = agent_names[command]
|
||||
return call(agent, [a:world, a:selected])
|
||||
else
|
||||
if !empty(command)
|
||||
echohl WarningMsg
|
||||
echom "Unknown command:" command
|
||||
echohl NONE
|
||||
sleep 1
|
||||
endif
|
||||
let a:world.state = 'display'
|
||||
return a:world
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#CompleteAgentNames(ArgLead, CmdLine, CursorPos)
|
||||
let arglead = tolower(a:Arglead)
|
||||
return filter(copy(s:agent_names), 'stridx(tolower(v:val), arglead) != -1')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#agent#Complete(world, selected) abort "{{{3
|
||||
Tlibtrace 'tlib', a:selected
|
||||
let rxprefix = a:world.matcher.FilterRxPrefix()
|
||||
let flt = a:world.filter[0][0]
|
||||
Tlibtrace 'tlib', flt
|
||||
let fltrx = rxprefix . flt . '\m[^[:space:][:cntrl:][:punct:]<>*+?&~{}()\[\]\\/]\+'
|
||||
let fltrx0 = '\m^' . fltrx
|
||||
Tlibtrace 'tlib', fltrx, fltrx0
|
||||
let words = {}
|
||||
for item in a:world.list
|
||||
let parts = split(item, '\ze'. fltrx)
|
||||
Tlibtrace 'tlib', item, parts
|
||||
for part in parts
|
||||
let word = matchstr(part, fltrx0)
|
||||
Tlibtrace 'tlib', part, word
|
||||
if !empty(word)
|
||||
let words[word] = 1
|
||||
endif
|
||||
endfor
|
||||
endfor
|
||||
Tlibtrace 'tlib', keys(words)
|
||||
let completions = keys(words)
|
||||
" let completions = filter(keys(words), 'matchstr(v:val, fltrx0)')
|
||||
let completions = sort(completions, 's:SortCompletions')
|
||||
let completions = tlib#list#Uniq(completions)
|
||||
Tlibtrace 'tlib', 0, completions
|
||||
while len(completions) > 1
|
||||
let nchar = strwidth(completions[0]) - 1
|
||||
let completions = map(completions, 'tlib#string#Strcharpart(v:val, 0, nchar)')
|
||||
Tlibtrace 'tlib', 'reduce', completions
|
||||
let completions = tlib#list#Uniq(completions)
|
||||
Tlibtrace 'tlib', 'unique', len(completions), completions
|
||||
endwh
|
||||
Tlibtrace 'tlib', 9, completions
|
||||
if empty(completions)
|
||||
let a:world.state = 'redisplay update'
|
||||
else
|
||||
let a:world.filter[0][0] = completions[0]
|
||||
let a:world.state = 'display update'
|
||||
endif
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! s:SortCompletions(a, b) abort "{{{3
|
||||
let i1 = strwidth(a:a)
|
||||
let i2 = strwidth(a:b)
|
||||
return i2 - i1
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2017-09-28.
|
||||
" @Revision: 273
|
||||
|
||||
|
||||
" :def: function! tlib#arg#Get(n, var, ?default="", ?test='')
|
||||
" Set a positional argument from a variable argument list.
|
||||
" See tlib#string#RemoveBackslashes() for an example.
|
||||
function! tlib#arg#Get(n, var, ...) "{{{3
|
||||
let default = a:0 >= 1 ? a:1 : ''
|
||||
let atest = a:0 >= 2 ? a:2 : ''
|
||||
" TLogVAR default, atest
|
||||
if !empty(atest)
|
||||
let atest = ' && (a:'. a:n .' '. atest .')'
|
||||
endif
|
||||
let test = printf('a:0 >= %d', a:n) . atest
|
||||
return printf('let %s = %s ? a:%d : %s', a:var, test, a:n, string(default))
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#arg#Let(list, ?default='')
|
||||
" Set a positional arguments from a variable argument list.
|
||||
" See tlib#input#List() for an example.
|
||||
function! tlib#arg#Let(list, ...) "{{{3
|
||||
let default = a:0 >= 1 ? a:1 : ''
|
||||
let list = map(copy(a:list), 'type(v:val) == 3 ? v:val : [v:val, default]')
|
||||
let args = map(range(1, len(list)), 'call("tlib#arg#Get", [v:val] + list[v:val - 1])')
|
||||
return join(args, ' | ')
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#arg#StringAsKeyArgs(string, ?keys=[], ?evaluate=0, ?sep=':', ?booleans=0)
|
||||
function! tlib#arg#StringAsKeyArgs(string, ...) "{{{1
|
||||
TVarArg ['keys', {}], ['evaluate', 0], ['sep', ':'], ['booleans', 0]
|
||||
let keyargs = {}
|
||||
let args = split(a:string, '\\\@<! ')
|
||||
let key_rx = booleans ? '\([-+]\?\w\+\)' : '\(\w\+\)'
|
||||
let arglist = map(args, 'matchlist(v:val, ''^\%('. key_rx . sep .'\(.*\)\|\(.*\)\)$'')')
|
||||
" TLogVAR a:string, args, arglist
|
||||
let pos = -1
|
||||
for matchlist in arglist
|
||||
if !empty(matchlist[3])
|
||||
if booleans && matchlist[3] =~ '^[-+]'
|
||||
let key = substitute(matchlist[3], '^[-+]', '', '')
|
||||
let val = matchstr(matchlist[3], '^[-+]')
|
||||
let keyargs[key] = val ==# '+'
|
||||
else
|
||||
let pos += 1
|
||||
let keyargs[pos] = matchlist[3]
|
||||
endif
|
||||
else
|
||||
let [match, key, val; rest] = matchlist
|
||||
if empty(keys) || has_key(keys, key)
|
||||
let val = substitute(val, '\\\\', '\\', 'g')
|
||||
if evaluate
|
||||
let val = eval(val)
|
||||
endif
|
||||
let keyargs[key] = val
|
||||
else
|
||||
echom 'Unknown key: '. key .'='. val
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
if pos >= 0
|
||||
let keyargs['__posargs__'] = range(0, pos)
|
||||
endif
|
||||
return keyargs
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#arg#StringAsKeyArgsEqual(string) "{{{1
|
||||
return tlib#arg#StringAsKeyArgs(a:string, [], 0, '=', 1)
|
||||
endf
|
||||
|
||||
|
||||
" :display: tlib#arg#GetOpts(args, ?def={})
|
||||
" Convert a list of strings of command-line arguments into a dictonary.
|
||||
"
|
||||
" The main use case is to pass [<f-args>], i.e. the command-line
|
||||
" arguments of a command as list, from a command definition to this
|
||||
" function.
|
||||
"
|
||||
" Example:
|
||||
" ['-h']
|
||||
" => If def contains a 'help' key, invoke |:help| on its value.
|
||||
"
|
||||
" ['-ab', '--foo', '--bar=BAR', 'bla', bla']
|
||||
" => {'a': 1, 'b': 1, 'foo': 1, 'bar': 'BAR', '__rest__': ['bla', 'bla']}
|
||||
"
|
||||
" ['-ab', '--', '--foo', '--bar=BAR']
|
||||
" => {'a': 1, 'b': 1, '__rest__': ['--foo', '--bar=BAR']}
|
||||
function! tlib#arg#GetOpts(args, ...) abort "{{{3
|
||||
if type(a:args) == 4
|
||||
reutrn a:args
|
||||
else
|
||||
let throw = a:0 == 0
|
||||
TVarArg ['def', {}]
|
||||
" TLogVAR def
|
||||
let opts = {'__exit__': 0}
|
||||
for [key, vdef] in items(get(def, 'values', {}))
|
||||
if has_key(vdef, 'default')
|
||||
let opts[key] = vdef.default
|
||||
endif
|
||||
endfor
|
||||
let idx = 0
|
||||
for o in a:args
|
||||
let [break, idx] = s:SetOpt(def, opts, idx, o)
|
||||
if break == 1
|
||||
break
|
||||
elseif break == 2
|
||||
if throw
|
||||
throw 'tlib#arg#GetOpts: Show help'
|
||||
else
|
||||
let opts.__exit__ = 5
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
let opts.__rest__ = a:args[idx : -1]
|
||||
return opts
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! s:GetValueType(def) abort "{{{3
|
||||
return get(a:def, 'type', type(get(a:def, 'default', '')))
|
||||
endf
|
||||
|
||||
|
||||
function! s:SetOpt(def, opts, idx, opt) abort "{{{3
|
||||
" TLogVAR a:def
|
||||
let idx = a:idx + 1
|
||||
let break = 0
|
||||
let long = get(a:def, 'long', 1)
|
||||
let short = get(a:def, 'short', 1)
|
||||
if (short && a:opt =~# '^-[?h]$') || (long && a:opt ==# '--help')
|
||||
if has_key(a:def, 'help')
|
||||
exec 'help' a:def.help
|
||||
else
|
||||
" TLogVAR a:def
|
||||
let values = get(a:def, 'values', {})
|
||||
let flags = get(a:def, 'flags', {})
|
||||
if empty(values) && empty(flags)
|
||||
echom 'No help'
|
||||
else
|
||||
if !empty(values)
|
||||
echom 'Options:'
|
||||
for [key, vdef] in sort(items(values))
|
||||
let opt = key
|
||||
let default = get(vdef, 'default', '')
|
||||
let type = s:GetValueType(vdef)
|
||||
if default =~ '^-\?\d\+\%(\.\d\+\)$'
|
||||
if type == -1 || type == 6
|
||||
let opt .= ' (flag)'
|
||||
elseif type == 1
|
||||
let opt .= '=INT'
|
||||
else
|
||||
let opt .= '=INT or maybe BOOL'
|
||||
endif
|
||||
elseif type(default) == 1
|
||||
let opt .= '=STRING'
|
||||
elseif type(default) == 3
|
||||
let opt .= '=COMMA-LIST'
|
||||
endif
|
||||
echom printf(' --%20s (default: %s)', opt, string(default))
|
||||
endfor
|
||||
endif
|
||||
if !empty(flags)
|
||||
echom 'Short flags:'
|
||||
for [sflag, lflag] in sort(items(flags))
|
||||
echom printf(' -%s -> %s', sflag, lflag)
|
||||
endfor
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
let break = 2
|
||||
elseif long && a:opt =~# '^--\%(no-\)\?debug$'
|
||||
if has_key(a:def, 'trace')
|
||||
let mod = a:opt =~# '--no-' ? '-' : '+'
|
||||
exec 'Tlibtraceset' mod . a:def.trace
|
||||
endif
|
||||
elseif long && a:opt =~# '^--no-.\+'
|
||||
let key = matchstr(a:opt, '^--no-\zs.\+$')
|
||||
let a:opts[key] = s:Validate(a:def, key, 0)
|
||||
elseif long && a:opt =~# '^--\w\+$'
|
||||
let key = matchstr(a:opt, '^--\zs.\+$')
|
||||
let a:opts[key] = s:Validate(a:def, key, 1)
|
||||
elseif long && a:opt =~# '^--\w\+='
|
||||
let ml = matchlist(a:opt, '^--\(\w\+\)=\(.*\)$')
|
||||
if empty(ml)
|
||||
throw 'tlib#arg#GetOpts: Cannot parse: '. a:opt
|
||||
else
|
||||
let values = get(a:def, 'values', {})
|
||||
if has_key(values, ml[1])
|
||||
let vdef = values[ml[1]]
|
||||
let type = s:GetValueType(vdef)
|
||||
if type == -1
|
||||
let opt_value = !!str2nr(ml[2])
|
||||
elseif type == 0
|
||||
let opt_value = str2nr(ml[2])
|
||||
elseif type == 1
|
||||
let opt_value = ml[2]
|
||||
elseif type == 2
|
||||
let opt_value = function(ml[2])
|
||||
elseif type == 3
|
||||
let opt_value = tlib#string#SplitCommaList(ml[2])
|
||||
elseif type == 4
|
||||
throw 'tlib#arg#GetOpts: Unsupported type conversion for '. ml[1]
|
||||
elseif type == 5
|
||||
let opt_value = str2float(ml[2])
|
||||
endif
|
||||
else
|
||||
let opt_value = ml[2]
|
||||
endif
|
||||
let a:opts[ml[1]] = s:Validate(a:def, ml[1], opt_value)
|
||||
unlet opt_value
|
||||
endif
|
||||
elseif short && a:opt =~# '^-\w='
|
||||
let flagdefs = get(a:def, 'flags', {})
|
||||
let flag = matchstr(a:opt, '^-\zs\w')
|
||||
let rest = matchstr(a:opt, '^-\w\zs.*$')
|
||||
call s:SetFlag(a:def, a:opts, idx, flag, rest, flagdefs)
|
||||
elseif short && a:opt =~# '^-\w\+$'
|
||||
let flagdefs = get(a:def, 'flags', {})
|
||||
for flag in split(substitute(a:opt, '^-', '', ''), '\zs')
|
||||
call s:SetFlag(a:def, a:opts, idx, flag, '', flagdefs)
|
||||
endfor
|
||||
else
|
||||
let break = 1
|
||||
if a:opt !=# '--'
|
||||
let idx -= 1
|
||||
endif
|
||||
endif
|
||||
return [break, idx]
|
||||
endf
|
||||
|
||||
|
||||
function! s:SetFlag(def, opts, idx, flag, rest, flagdefs) abort "{{{3
|
||||
" TLogVAR a:def
|
||||
if has_key(a:flagdefs, a:flag)
|
||||
call s:SetOpt(a:def, a:opts, a:idx, a:flagdefs[a:flag] . a:rest)
|
||||
else
|
||||
let a:opts[a:flag] = s:Validate(a:def, a:flag, 1)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! s:Validate(def, name, value) abort "{{{3
|
||||
let values = get(a:def, 'values', {})
|
||||
if has_key(values, a:name)
|
||||
let vdef = values[a:name]
|
||||
if has_key(vdef, 'validate')
|
||||
if !call(vdef.validate, [a:value])
|
||||
throw printf('tlib#arg: %s has invalid value: %s', string(a:name), string(a:value))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return a:value
|
||||
endf
|
||||
|
||||
|
||||
":nodoc:
|
||||
function! tlib#arg#CComplete(def, ArgLead) abort "{{{3
|
||||
let values = get(a:def, 'values', {})
|
||||
let opt = matchstr(a:ArgLead, '^--\zs\w\+\ze=')
|
||||
if has_key(values, opt)
|
||||
let words = []
|
||||
let vals = values[opt]
|
||||
let complete_customlist = get(vals, 'complete_customlist', '')
|
||||
if !empty(complete_customlist)
|
||||
let words = eval(complete_customlist)
|
||||
" else
|
||||
" let complete = get(vals, 'complete', '')
|
||||
" if !empty(complete)
|
||||
" endif
|
||||
endif
|
||||
if !empty(words)
|
||||
let prefix = matchstr(a:ArgLead, '^--\w\+=\%([^,]\+,\s*\)*')
|
||||
let lead = substitute(a:ArgLead, '^--\w\+=\%([^,]\+,\s*\)*', '', '')
|
||||
" TLogVAR a:ArgLead, lead
|
||||
if !empty(lead)
|
||||
let nchar = len(lead)
|
||||
call filter(words, 'tlib#string#Strcharpart(v:val, 0, nchar) ==# lead')
|
||||
endif
|
||||
let words = map(words, 'prefix . v:val')
|
||||
return sort(words)
|
||||
endif
|
||||
endif
|
||||
let cs = {'-h': 1, '--help': 1}
|
||||
for [name, vdef] in items(values)
|
||||
let type = s:GetValueType(vdef)
|
||||
if type >= 0
|
||||
let name .= '='
|
||||
else
|
||||
let cs['--no-'. name] = 1
|
||||
endif
|
||||
let cs['--'. name] = 1
|
||||
endfor
|
||||
for [name, subst] in items(get(a:def, 'flags', {}))
|
||||
let ldef = get(values, substitute(subst, '^--', '', ''), {})
|
||||
let type = s:GetValueType(ldef)
|
||||
if type >= 0
|
||||
let name .= '='
|
||||
endif
|
||||
let cs['-'. name] = 1
|
||||
endfor
|
||||
if has_key(a:def, 'trace')
|
||||
let cs['--debug'] = 1
|
||||
endif
|
||||
let nchar = len(a:ArgLead)
|
||||
if nchar > 0
|
||||
call filter(cs, 'tlib#string#Strcharpart(v:key, 0, nchar) ==# a:ArgLead')
|
||||
endif
|
||||
return sort(keys(cs))
|
||||
endf
|
||||
|
||||
|
||||
|
||||
""" Command line {{{1
|
||||
|
||||
" :def: function! tlib#arg#Ex(arg, ?chars='%#! ')
|
||||
" Escape some characters in a string.
|
||||
"
|
||||
" Use |fnamescape()| if available.
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" exec 'edit '. tlib#arg#Ex('foo%#bar.txt')
|
||||
function! tlib#arg#Ex(arg, ...) "{{{3
|
||||
if exists('*fnameescape') && a:0 == 0
|
||||
return fnameescape(a:arg)
|
||||
else
|
||||
" let chars = '%# \'
|
||||
let chars = '%#! '
|
||||
if a:0 >= 1
|
||||
let chars .= a:1
|
||||
endif
|
||||
return escape(a:arg, chars)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: https://github.com/tomtom
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2017-02-22
|
||||
" @Revision: 42
|
||||
|
||||
|
||||
" Enable tracing via |:Tlibassert|.
|
||||
function! tlib#assert#Enable() abort "{{{3
|
||||
" :nodoc:
|
||||
command! -nargs=+ -bang Tlibassert call tlib#assert#Assert(expand('<sfile>'), <q-args>, [<args>])
|
||||
endf
|
||||
|
||||
|
||||
" Disable tracing via |:Tlibassert|.
|
||||
function! tlib#assert#Disable() abort "{{{3
|
||||
" :nodoc:
|
||||
command! -nargs=+ -bang Tlibassert :
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#assert#Assert(caller, check, vals) abort "{{{3
|
||||
for val in a:vals
|
||||
" TLogVAR val
|
||||
if type(val) == 3
|
||||
call tlib#assert#Assert(a:caller, a:check, val)
|
||||
elseif !val
|
||||
throw 'Tlibassert: '. tlib#trace#Backtrace(a:caller) .': '. a:check
|
||||
endif
|
||||
endfor
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#assert#Map(vals, expr) abort "{{{3
|
||||
return tlib#assert#All(map(a:vals, a:expr))
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#assert#All(vals) abort "{{{3
|
||||
" TLogVAR a:vals, empty(filter(a:vals, '!v:val'))
|
||||
return empty(filter(a:vals, '!v:val'))
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
" autocmdgroup.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 7
|
||||
|
||||
augroup TLib
|
||||
autocmd!
|
||||
augroup END
|
||||
|
||||
|
||||
function! tlib#autocmdgroup#Init() "{{{3
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @GIT: http://github.com/tomtom/tlib_vim/
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2010-08-30.
|
||||
" @Last Change: 2015-11-23.
|
||||
" @Revision: 48
|
||||
|
||||
|
||||
function! tlib#balloon#Register(expr) "{{{3
|
||||
if !has('balloon_eval')
|
||||
return
|
||||
endif
|
||||
if !exists('b:tlib_balloons')
|
||||
let b:tlib_balloons = []
|
||||
endif
|
||||
if !&ballooneval
|
||||
setlocal ballooneval
|
||||
endif
|
||||
if &balloonexpr != 'tlib#balloon#Expr()'
|
||||
if !empty(&balloonexpr)
|
||||
call add(b:tlib_balloons, &balloonexpr)
|
||||
endif
|
||||
setlocal ballooneval balloonexpr=tlib#balloon#Expr()
|
||||
endif
|
||||
if index(b:tlib_balloons, a:expr) == -1
|
||||
call add(b:tlib_balloons, a:expr)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#balloon#Remove(expr) "{{{3
|
||||
if exists('b:tlib_balloons')
|
||||
call filter(b:tlib_balloons, 'v:val != a:expr')
|
||||
if empty(b:tlib_balloons)
|
||||
setlocal ballooneval&
|
||||
setlocal balloonexpr&
|
||||
unlet b:tlib_balloons
|
||||
endif
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#balloon#Expr() "{{{3
|
||||
" TLogVAR exists('b:tlib_balloons')
|
||||
if !exists('b:tlib_balloons')
|
||||
return ''
|
||||
endif
|
||||
let text = map(copy(b:tlib_balloons), 'eval(v:val)')
|
||||
" TLogVAR b:tlib_balloons, text
|
||||
call filter(text, '!empty(v:val)')
|
||||
if has('balloon_multiline')
|
||||
return join(text, "\n----------------------------------\n")
|
||||
else
|
||||
return get(text, 0, '')
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#balloon#Expand(expr) abort "{{{3
|
||||
if v:beval_bufnr != bufnr('%')
|
||||
" TLogVAR v:beval_bufnr, bufnr('%')
|
||||
return ''
|
||||
endif
|
||||
let win = winsaveview()
|
||||
try
|
||||
call setpos('.', [v:beval_bufnr, v:beval_lnum, v:beval_col, 0])
|
||||
return expand(a:expr)
|
||||
finally
|
||||
call winrestview(win)
|
||||
endtry
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 124
|
||||
|
||||
|
||||
function! tlib#bitwise#Num2Bits(num) "{{{3
|
||||
if type(a:num) <= 1 || type(a:num) == 5
|
||||
let bits = reverse(tlib#number#ConvertBase(a:num, 2, 'list'))
|
||||
elseif type(a:num) == 3
|
||||
let bits = copy(a:num)
|
||||
else
|
||||
throw "tlib#bitwise#Num2Bits: Must be number of list: ". string(a:num)
|
||||
endif
|
||||
return bits
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#Bits2Num(bits, ...) "{{{3
|
||||
let base = a:0 >= 1 ? a:1 : 10
|
||||
" TLogVAR a:bits
|
||||
let num = 0.0
|
||||
for i in range(len(a:bits))
|
||||
if get(a:bits, i, 0)
|
||||
let num += pow(2, i)
|
||||
endif
|
||||
endfor
|
||||
" TLogVAR num
|
||||
if base == 10
|
||||
if type(base) == 5
|
||||
return num
|
||||
else
|
||||
return float2nr(num)
|
||||
endif
|
||||
else
|
||||
return tlib#number#ConvertBase(num, base)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#AND(num1, num2, ...) "{{{3
|
||||
let rtype = a:0 >= 1 ? a:1 : 'num'
|
||||
return s:BitwiseComparison(a:num1, a:num2, rtype,
|
||||
\ 'get(bits1, v:val) && get(bits2, v:val)')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#OR(num1, num2, ...) "{{{3
|
||||
let rtype = a:0 >= 1 ? a:1 : 'num'
|
||||
return s:BitwiseComparison(a:num1, a:num2, rtype,
|
||||
\ 'get(bits1, v:val) || get(bits2, v:val)')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#XOR(num1, num2, ...) "{{{3
|
||||
let rtype = a:0 >= 1 ? a:1 : 'num'
|
||||
return s:BitwiseComparison(a:num1, a:num2, rtype,
|
||||
\ 'get(bits1, v:val) ? !get(bits2, v:val) : get(bits2, v:val)')
|
||||
endf
|
||||
|
||||
|
||||
function! s:BitwiseComparison(num1, num2, rtype, expr) "{{{3
|
||||
let bits1 = tlib#bitwise#Num2Bits(a:num1)
|
||||
let bits2 = tlib#bitwise#Num2Bits(a:num2)
|
||||
let range = range(max([len(bits1), len(bits2)]))
|
||||
let bits = map(range, a:expr)
|
||||
if a:rtype == 'num' || (a:rtype == 'auto' && type(a:num1) <= 1)
|
||||
return tlib#bitwise#Bits2Num(bits)
|
||||
else
|
||||
return bits
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#ShiftRight(bits, n) "{{{3
|
||||
let bits = a:bits[a:n : -1]
|
||||
if empty(bits)
|
||||
let bits = [0]
|
||||
endif
|
||||
return bits
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#ShiftLeft(bits, n) "{{{3
|
||||
let bits = repeat([0], a:n) + a:bits
|
||||
return bits
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#Add(num1, num2, ...) "{{{3
|
||||
let rtype = a:0 >= 1 ? a:1 : 'num'
|
||||
let bits1 = tlib#bitwise#Num2Bits(a:num1)
|
||||
let bits2 = tlib#bitwise#Num2Bits(a:num2)
|
||||
let range = range(max([len(bits1), len(bits2)]))
|
||||
" TLogVAR bits1, bits2, range
|
||||
let carry = 0
|
||||
let bits = []
|
||||
for i in range
|
||||
let sum = get(bits1, i) + get(bits2, i) + carry
|
||||
if sum == 3
|
||||
let bit = 1
|
||||
let carry = 1
|
||||
elseif sum == 2
|
||||
let bit = 0
|
||||
let carry = 1
|
||||
elseif sum == 1
|
||||
let bit = 1
|
||||
let carry = 0
|
||||
elseif sum == 0
|
||||
let bit = 0
|
||||
let carry = 0
|
||||
endif
|
||||
call add(bits, bit)
|
||||
" TLogVAR i, bits, bit
|
||||
endfor
|
||||
if carry == 1
|
||||
call add(bits, carry)
|
||||
endif
|
||||
if rtype == 'num' || (rtype == 'auto' && type(a:num1) <= 1)
|
||||
return tlib#bitwise#Bits2Num(bits)
|
||||
else
|
||||
return bits
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#bitwise#Sub(num1, num2, ...) "{{{3
|
||||
let rtype = a:0 >= 1 ? a:1 : 'num'
|
||||
let bits1 = tlib#bitwise#Num2Bits(a:num1)
|
||||
let bits2 = tlib#bitwise#Num2Bits(a:num2)
|
||||
let range = range(max([len(bits1), len(bits2)]))
|
||||
let bits2 = map(range, '!get(bits2, v:val)')
|
||||
let bits2 = tlib#bitwise#Add(bits2, [1], 'bits')
|
||||
let bits3 = tlib#bitwise#Add(bits1, bits2, 'bits')
|
||||
let bits = bits3[0 : -2]
|
||||
if rtype == 'num' || (rtype == 'auto' && type(a:num1) <= 1)
|
||||
return tlib#bitwise#Bits2Num(bits)
|
||||
else
|
||||
return bits
|
||||
endif
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,401 @@
|
||||
" buffer.vim
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2007-06-30.
|
||||
" @Last Change: 2017-09-28.
|
||||
" @Revision: 12.1.352
|
||||
|
||||
|
||||
" Where to display the line when using |tlib#buffer#ViewLine|.
|
||||
" For possible values for position see |scroll-cursor|.
|
||||
TLet g:tlib_viewline_position = 'zz'
|
||||
|
||||
|
||||
let s:bmru = []
|
||||
|
||||
|
||||
function! tlib#buffer#EnableMRU() abort "{{{3
|
||||
call tlib#autocmdgroup#Init()
|
||||
autocmd TLib BufEnter * call s:BMRU_Push(bufnr('%'))
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#buffer#DisableMRU() abort "{{{3
|
||||
call tlib#autocmdgroup#Init()
|
||||
autocmd! TLib BufEnter
|
||||
endf
|
||||
|
||||
|
||||
function! s:BMRU_Push(bnr) abort "{{{3
|
||||
let i = index(s:bmru, a:bnr)
|
||||
if i >= 0
|
||||
call remove(s:bmru, i)
|
||||
endif
|
||||
call insert(s:bmru, a:bnr)
|
||||
endf
|
||||
|
||||
|
||||
function! s:CompareBuffernameByBasename(a, b) abort "{{{3
|
||||
let rx = '"\zs.\{-}\ze" \+\S\+ \+\d\+$'
|
||||
let an = matchstr(a:a, rx)
|
||||
let an = fnamemodify(an, ':t')
|
||||
let bn = matchstr(a:b, rx)
|
||||
let bn = fnamemodify(bn, ':t')
|
||||
let rv = an == bn ? 0 : an > bn ? 1 : -1
|
||||
return rv
|
||||
endf
|
||||
|
||||
|
||||
function! s:CompareBufferNrByMRU(a, b) abort "{{{3
|
||||
let an = matchstr(a:a, '\s*\zs\d\+\ze')
|
||||
let bn = matchstr(a:b, '\s*\zs\d\+\ze')
|
||||
let ai = index(s:bmru, 0 + an)
|
||||
if ai == -1
|
||||
return 1
|
||||
else
|
||||
let bi = index(s:bmru, 0 + bn)
|
||||
if bi == -1
|
||||
return -1
|
||||
else
|
||||
return ai == bi ? 0 : ai > bi ? 1 : -1
|
||||
endif
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" Set the buffer to buffer and return a command as string that can be
|
||||
" evaluated by |:execute| in order to restore the original view.
|
||||
function! tlib#buffer#Set(buffer) abort "{{{3
|
||||
let lazyredraw = &lazyredraw
|
||||
set lazyredraw
|
||||
try
|
||||
let cb = bufnr('%')
|
||||
let sn = bufnr(a:buffer)
|
||||
if sn != cb
|
||||
let ws = bufwinnr(sn)
|
||||
if ws != -1
|
||||
let wb = bufwinnr('%')
|
||||
exec ws.'wincmd w'
|
||||
return wb.'wincmd w'
|
||||
else
|
||||
silent exec 'sbuffer! '. sn
|
||||
return 'wincmd c'
|
||||
endif
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
finally
|
||||
let &lazyredraw = lazyredraw
|
||||
endtry
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#buffer#Eval(buffer, code) abort
|
||||
" Evaluate CODE in BUFFER.
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" call tlib#buffer#Eval('foo.txt', 'echo b:bar')
|
||||
function! tlib#buffer#Eval(buffer, code) abort "{{{3
|
||||
" let cb = bufnr('%')
|
||||
" let wb = bufwinnr('%')
|
||||
" " TLogVAR cb
|
||||
" let sn = bufnr(a:buffer)
|
||||
" let sb = sn != cb
|
||||
let lazyredraw = &lazyredraw
|
||||
set lazyredraw
|
||||
let restore = tlib#buffer#Set(a:buffer)
|
||||
try
|
||||
exec a:code
|
||||
" if sb
|
||||
" let ws = bufwinnr(sn)
|
||||
" if ws != -1
|
||||
" try
|
||||
" exec ws.'wincmd w'
|
||||
" exec a:code
|
||||
" finally
|
||||
" exec wb.'wincmd w'
|
||||
" endtry
|
||||
" else
|
||||
" try
|
||||
" silent exec 'sbuffer! '. sn
|
||||
" exec a:code
|
||||
" finally
|
||||
" wincmd c
|
||||
" endtry
|
||||
" endif
|
||||
" else
|
||||
" exec a:code
|
||||
" endif
|
||||
finally
|
||||
exec restore
|
||||
let &lazyredraw = lazyredraw
|
||||
endtry
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#buffer#GetList(?show_hidden=0, ?show_number=0, " ?order='bufnr') abort
|
||||
" Possible values for the "order" argument:
|
||||
" bufnr :: Default behaviour
|
||||
" mru :: Sort buffers according to most recent use
|
||||
" basename :: Sort by the file's basename (last component)
|
||||
"
|
||||
" NOTE: MRU order works on second invocation only. If you want to always
|
||||
" use MRU order, call tlib#buffer#EnableMRU() in your ~/.vimrc file.
|
||||
function! tlib#buffer#GetList(...) abort
|
||||
TVarArg ['show_hidden', 0], ['show_number', 0], ['order', '']
|
||||
" TLogVAR show_hidden, show_number, order
|
||||
let ls_bang = show_hidden ? '!' : ''
|
||||
redir => bfs
|
||||
exec 'silent ls'. ls_bang
|
||||
redir END
|
||||
let buffer_list = split(bfs, '\n')
|
||||
if order ==# 'mru'
|
||||
if empty(s:bmru)
|
||||
call tlib#buffer#EnableMRU()
|
||||
echom 'tlib: Installed Buffer MRU logger; disable with: call tlib#buffer#DisableMRU()'
|
||||
else
|
||||
call sort(buffer_list, function('s:CompareBufferNrByMRU'))
|
||||
endif
|
||||
elseif order ==# 'basename'
|
||||
call sort(buffer_list, function('s:CompareBuffernameByBasename'))
|
||||
endif
|
||||
let buffer_nr = map(copy(buffer_list), 'str2nr(matchstr(v:val, ''\s*\zs\d\+\ze''))')
|
||||
" TLogVAR buffer_list, buffer_nr
|
||||
if show_number
|
||||
call map(buffer_list, 'matchstr(v:val, ''^\s*\d\+.\{-}\ze\s\+\S\+ \d\+\s*$'')')
|
||||
else
|
||||
call map(buffer_list, 'matchstr(v:val, ''^\s*\d\+\zs.\{-}\ze\s\+\S\+ \d\+\s*$'')')
|
||||
endif
|
||||
" TLogVAR buffer_list
|
||||
" call map(buffer_list, 'matchstr(v:val, ''^.\{-}\ze\s\+line \d\+\s*$'')')
|
||||
" TLogVAR buffer_list
|
||||
call map(buffer_list, 'matchstr(v:val, ''^[^"]\+''). printf("%-20s %s", fnamemodify(matchstr(v:val, ''"\zs.\{-}\ze"$''), ":t"), fnamemodify(matchstr(v:val, ''"\zs.\{-}\ze"$''), ":h"))')
|
||||
" TLogVAR buffer_list
|
||||
return [buffer_nr, buffer_list]
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#buffer#ViewLine(line, ?position='z') abort
|
||||
" line is either a number or a string that begins with a number.
|
||||
" For possible values for position see |scroll-cursor|.
|
||||
" See also |g:tlib_viewline_position|.
|
||||
function! tlib#buffer#ViewLine(line, ...) abort "{{{3
|
||||
if a:line
|
||||
TVarArg 'pos'
|
||||
let ln = matchstr(a:line, '^\d\+')
|
||||
let lt = matchstr(a:line, '^\d\+: \zs.*')
|
||||
" TLogVAR pos, ln, lt
|
||||
exec ln
|
||||
if empty(pos)
|
||||
let pos = tlib#var#Get('tlib_viewline_position', 'wbg')
|
||||
endif
|
||||
" TLogVAR pos
|
||||
if !empty(pos)
|
||||
exec 'norm! '. pos
|
||||
endif
|
||||
call tlib#buffer#HighlightLine(ln)
|
||||
" let @/ = '\%'. ln .'l.*'
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! s:UndoHighlightLine() abort "{{{3
|
||||
2match none
|
||||
autocmd! TLib CursorMoved,CursorMovedI <buffer>
|
||||
autocmd! TLib CursorHold,CursorHoldI <buffer>
|
||||
autocmd! TLib InsertEnter,InsertChange,InsertLeave <buffer>
|
||||
autocmd! TLib BufLeave,BufWinLeave,WinLeave,BufHidden <buffer>
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#buffer#HighlightLine(...) abort "{{{3
|
||||
TVarArg ['line', line('.')]
|
||||
" exec '2match MatchParen /^\%'. a:line .'l.*/'
|
||||
exec '2match Search /^\%'. line .'l.*/'
|
||||
call tlib#autocmdgroup#Init()
|
||||
exec 'autocmd TLib CursorMoved,CursorMovedI <buffer> if line(".") != '. line .' | call s:UndoHighlightLine() | endif'
|
||||
autocmd TLib CursorHold,CursorHoldI <buffer> call s:UndoHighlightLine()
|
||||
autocmd TLib InsertEnter <buffer> call s:UndoHighlightLine()
|
||||
" autocmd TLib BufLeave,BufWinLeave,WinLeave,BufHidden <buffer> call s:UndoHighlightLine()
|
||||
endf
|
||||
|
||||
|
||||
" Delete the lines in the current buffer. Wrapper for |:delete|.
|
||||
function! tlib#buffer#DeleteRange(line1, line2) abort "{{{3
|
||||
let r = @t
|
||||
try
|
||||
exec a:line1.','.a:line2.'delete t'
|
||||
finally
|
||||
let @t = r
|
||||
endtry
|
||||
endf
|
||||
|
||||
|
||||
" Replace a range of lines.
|
||||
function! tlib#buffer#ReplaceRange(line1, line2, lines) abort
|
||||
call tlib#buffer#DeleteRange(a:line1, a:line2)
|
||||
call append(a:line1 - 1, a:lines)
|
||||
endf
|
||||
|
||||
|
||||
" Initialize some scratch area at the bottom of the current buffer.
|
||||
function! tlib#buffer#ScratchStart() abort "{{{3
|
||||
norm! Go
|
||||
let b:tlib_inbuffer_scratch = line('$')
|
||||
return b:tlib_inbuffer_scratch
|
||||
endf
|
||||
|
||||
|
||||
" Remove the in-buffer scratch area.
|
||||
function! tlib#buffer#ScratchEnd() abort "{{{3
|
||||
if !exists('b:tlib_inbuffer_scratch')
|
||||
echoerr 'tlib: In-buffer scratch not initalized'
|
||||
endif
|
||||
call tlib#buffer#DeleteRange(b:tlib_inbuffer_scratch, line('$'))
|
||||
unlet b:tlib_inbuffer_scratch
|
||||
endf
|
||||
|
||||
|
||||
" Run exec on all buffers via bufdo and return to the original buffer.
|
||||
function! tlib#buffer#BufDo(exec) abort "{{{3
|
||||
let bn = bufnr('%')
|
||||
exec 'bufdo '. a:exec
|
||||
exec 'buffer! '. bn
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#buffer#InsertText(text, keyargs) abort
|
||||
" Keyargs:
|
||||
" 'shift': 0|N
|
||||
" 'col': col('.')|N
|
||||
" 'lineno': line('.')|N
|
||||
" 'indent': 0|1
|
||||
" 'pos': 'e'|'s' ... Where to locate the cursor (somewhat like s and e in {offset})
|
||||
" Insert text (a string) in the buffer.
|
||||
function! tlib#buffer#InsertText(text, ...) abort "{{{3
|
||||
TVarArg ['keyargs', {}]
|
||||
" TLogVAR a:text, keyargs
|
||||
let keyargs = extend({
|
||||
\ 'shift': 0, 'col': col('.'), 'lineno': line('.'), 'pos': 'e', 'indent': 0
|
||||
\ }, keyargs)
|
||||
" TLogVAR keyargs
|
||||
let grow = 0
|
||||
let post_del_last_line = line('$') == 1
|
||||
let line = getline(keyargs.lineno)
|
||||
if keyargs.col + keyargs.shift > 0
|
||||
let pre = line[0 : (keyargs.col - 1 + keyargs.shift)]
|
||||
let post = line[(keyargs.col + keyargs.shift): -1]
|
||||
else
|
||||
let pre = ''
|
||||
let post = line
|
||||
endif
|
||||
" TLogVAR keyargs.lineno, line, pre, post
|
||||
let text0 = pre . a:text . post
|
||||
let text = split(text0, '\n', 1)
|
||||
" TLogVAR text
|
||||
let icol = len(pre)
|
||||
" exec 'norm! '. keyargs.lineno .'G'
|
||||
call cursor(keyargs.lineno, keyargs.col)
|
||||
if keyargs.indent && keyargs.col > 1
|
||||
if &formatoptions =~# '[or]'
|
||||
" FIXME: Is the simple version sufficient?
|
||||
" VERSION 1
|
||||
" " This doesn't work because it's not guaranteed that the
|
||||
" " cursor is set.
|
||||
" let cline = getline('.')
|
||||
" norm! a
|
||||
" "norm! o
|
||||
" " TAssertExec redraw | sleep 3
|
||||
" let idt = tlib#string#Strcharpart(getline('.'), 0, keyargs.col('.') + keyargs.shift)
|
||||
" " TLogVAR idt
|
||||
" let idtl = len(idt)
|
||||
" -1,.delete
|
||||
" " TAssertExec redraw | sleep 3
|
||||
" call append(keyargs.lineno - 1, cline)
|
||||
" call cursor(keyargs.lineno, keyargs.col)
|
||||
" " TAssertExec redraw | sleep 3
|
||||
" if idtl == 0 && icol != 0
|
||||
" let idt = matchstr(pre, '^\s\+')
|
||||
" let idtl = len(idt)
|
||||
" endif
|
||||
" VERSION 2
|
||||
let idt = matchstr(pre, '^\s\+')
|
||||
let idtl = len(idt)
|
||||
else
|
||||
let [m_0, idt, iline; rest] = matchlist(pre, '^\(\s*\)\(.*\)$')
|
||||
let idtl = len(idt)
|
||||
endif
|
||||
if idtl < icol
|
||||
let idt .= repeat(' ', icol - idtl)
|
||||
endif
|
||||
" TLogVAR idt
|
||||
let idtl1 = len(idt)
|
||||
for i in range(1, len(text) - 1)
|
||||
let text[i] = idt . text[i]
|
||||
let grow += idtl1
|
||||
endfor
|
||||
endif
|
||||
" TLogVAR text
|
||||
" exec 'norm! '. keyargs.lineno .'Gdd'
|
||||
call tlib#normal#WithRegister('"tdd', 't')
|
||||
call append(keyargs.lineno - 1, text)
|
||||
if post_del_last_line
|
||||
call tlib#buffer#KeepCursorPosition('$delete')
|
||||
endif
|
||||
let tlen = len(text)
|
||||
let posshift = matchstr(keyargs.pos, '\d\+')
|
||||
" TLogVAR keyargs.pos
|
||||
if keyargs.pos =~# '^e'
|
||||
exec keyargs.lineno + tlen - 1
|
||||
exec 'norm! 0'. (len(text[-1]) - len(post) + posshift - 1) .'l'
|
||||
elseif keyargs.pos =~# '^s'
|
||||
" TLogVAR keyargs.lineno, pre, posshift
|
||||
exec keyargs.lineno
|
||||
exec 'norm! '. len(pre) .'|'
|
||||
if !empty(posshift)
|
||||
exec 'norm! '. posshift .'h'
|
||||
endif
|
||||
endif
|
||||
" TLogDBG getline(keyargs.lineno)
|
||||
" TLogDBG string(getline(1, '$'))
|
||||
return grow
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#buffer#InsertText0(text, ...) abort "{{{3
|
||||
TVarArg ['keyargs', {}]
|
||||
let mode = get(keyargs, 'mode', 'i')
|
||||
" TLogVAR mode
|
||||
if !has_key(keyargs, 'shift')
|
||||
let col = col('.')
|
||||
" if mode =~ 'i'
|
||||
" let col += 1
|
||||
" endif
|
||||
let keyargs.shift = col >= col('$') ? 0 : -1
|
||||
" let keyargs.shift = col('.') >= col('$') ? 0 : -1
|
||||
" TLogVAR col
|
||||
" TLogDBG col('.') .'-'. col('$') .': '. string(getline('.'))
|
||||
endif
|
||||
" TLogVAR keyargs.shift
|
||||
return tlib#buffer#InsertText(a:text, keyargs)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#buffer#CurrentByte() abort "{{{3
|
||||
return line2byte(line('.')) + col('.')
|
||||
endf
|
||||
|
||||
|
||||
" Evaluate cmd while maintaining the cursor position and jump registers.
|
||||
function! tlib#buffer#KeepCursorPosition(cmd) abort "{{{3
|
||||
" let pos = getpos('.')
|
||||
let view = winsaveview()
|
||||
try
|
||||
keepjumps exec a:cmd
|
||||
finally
|
||||
" call setpos('.', pos)
|
||||
call winrestview(view)
|
||||
endtry
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,464 @@
|
||||
" cache.vim
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2007-06-30.
|
||||
" @Last Change: 2019-01-02.
|
||||
" @Revision: 125.1.243
|
||||
|
||||
|
||||
" The cache directory. If empty, use |tlib#dir#MyRuntime|.'/cache'.
|
||||
" You might want to delete old files from this directory from time to
|
||||
" time with a command like: >
|
||||
" find ~/vimfiles/cache/ -atime +31 -type f -print -delete
|
||||
TLet g:tlib_cache = ''
|
||||
|
||||
" |tlib#cache#Purge()|: Remove cache files older than N days.
|
||||
TLet g:tlib#cache#purge_days = 31
|
||||
|
||||
" Purge the cache every N days. Disable automatic purging by setting
|
||||
" this value to a negative value.
|
||||
TLet g:tlib#cache#purge_every_days = 31
|
||||
|
||||
" The encoding used for the purge-cache script.
|
||||
" Default: 'enc'
|
||||
TLet g:tlib#cache#script_encoding = &enc
|
||||
|
||||
" Whether to run the directory removal script:
|
||||
" 0 ... No
|
||||
" 1 ... Query user
|
||||
" 2 ... Yes
|
||||
TLet g:tlib#cache#run_script = 1
|
||||
|
||||
" Verbosity level:
|
||||
" 0 ... Be quiet
|
||||
" 1 ... Display informative message
|
||||
" 2 ... Display detailed messages
|
||||
TLet g:tlib#cache#verbosity = 1
|
||||
|
||||
" A list of regexps that are matched against partial filenames of the
|
||||
" cached files. If a regexp matches, the file won't be removed by
|
||||
" |tlib#cache#Purge()|.
|
||||
TLet g:tlib#cache#dont_purge = ['[\/]\.last_purge$']
|
||||
|
||||
" If the cache filename is longer than N characters, use
|
||||
" |pathshorten()|.
|
||||
TLet g:tlib#cache#max_filename = 200
|
||||
|
||||
TLet g:tlib#cache#use_json = 0
|
||||
|
||||
TLet g:tlib#cache#use_encoding = ''
|
||||
|
||||
|
||||
let s:cache = {}
|
||||
|
||||
|
||||
" :display: tlib#cache#Dir(?mode = 'bg', ?ensure_dir = true)
|
||||
" The default cache directory.
|
||||
function! tlib#cache#Dir(...) "{{{3
|
||||
TVarArg ['mode', 'bg'], ['ensure_dir', 1]
|
||||
let dir = tlib#var#Get('tlib_cache', mode)
|
||||
if empty(dir)
|
||||
let dir = tlib#file#Join([tlib#dir#MyRuntime(), 'cache'])
|
||||
endif
|
||||
if ensure_dir
|
||||
call tlib#dir#Ensure(dir)
|
||||
endif
|
||||
return dir
|
||||
endf
|
||||
|
||||
|
||||
" :display: tlib#cache#EncodedFilename(type, file, ?mkdir=0, ?dir='')
|
||||
" Encode `file` and call |tlib#cache#Filename()|.
|
||||
function! tlib#cache#EncodedFilename(type, file, ...) "{{{3
|
||||
let file = tlib#url#Encode(a:file)
|
||||
return call(function('tlib#cache#Filename'), [a:type, file] + a:000)
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#cache#Filename(type, ?file=%, ?mkdir=0, ?dir='')
|
||||
function! tlib#cache#Filename(type, ...) "{{{3
|
||||
" TLogDBG 'bufname='. bufname('.')
|
||||
let dir0 = a:0 >= 3 && !empty(a:3) ? a:3 : tlib#cache#Dir()
|
||||
let dir = dir0
|
||||
if a:0 >= 1 && !empty(a:1)
|
||||
let file = a:1
|
||||
else
|
||||
if empty(expand('%:t'))
|
||||
return ''
|
||||
endif
|
||||
let file = expand('%:p')
|
||||
let file = tlib#file#Relative(file, tlib#file#Join([dir, '..']))
|
||||
endif
|
||||
" TLogVAR file, dir
|
||||
let mkdir = a:0 >= 2 ? a:2 : 0
|
||||
let file = substitute(file, '\.\.\|[:&<>]\|//\+\|\\\\\+', '_', 'g')
|
||||
let dirs = [dir, a:type]
|
||||
let dirf = fnamemodify(file, ':h')
|
||||
if dirf != '.'
|
||||
call add(dirs, dirf)
|
||||
endif
|
||||
let dir = tlib#file#Join(dirs)
|
||||
" TLogVAR dir
|
||||
let dir = tlib#dir#PlainName(dir)
|
||||
" TLogVAR dir
|
||||
let file = fnamemodify(file, ':t')
|
||||
" TLogVAR file, dir, mkdir
|
||||
let cache_file = tlib#file#Join([dir, file])
|
||||
if len(cache_file) > g:tlib#cache#max_filename
|
||||
" echom "DBG long filename" cache_file
|
||||
" echom "DBG long filename" dir
|
||||
if v:version >= 704
|
||||
let shortfilename = sha256(file)
|
||||
else
|
||||
let shortfilename = tlib#hash#Adler32(file)
|
||||
endif
|
||||
" let cache_file = tlib#cache#Filename(a:type, shortfilename, mkdir, dir0)
|
||||
let cache_file = tlib#file#Join([dir, shortfilename])
|
||||
else
|
||||
if mkdir && !isdirectory(dir)
|
||||
try
|
||||
call mkdir(dir, 'p')
|
||||
catch /^Vim\%((\a\+)\)\=:E739:/
|
||||
if filereadable(dir) && !isdirectory(dir)
|
||||
echoerr 'TLib: Cannot create directory for cache file because a file with the same name exists (please delete it):' dir
|
||||
" call delete(dir)
|
||||
" call mkdir(dir, 'p')
|
||||
endif
|
||||
endtry
|
||||
endif
|
||||
endif
|
||||
" TLogVAR cache_file
|
||||
return cache_file
|
||||
endf
|
||||
|
||||
|
||||
let s:timestamps = {}
|
||||
|
||||
|
||||
function! s:SetTimestamp(cfile, type) "{{{3
|
||||
if !has_key(s:timestamps, a:cfile)
|
||||
let s:timestamps[a:cfile] = {}
|
||||
endif
|
||||
let s:timestamps[a:cfile].atime = getftime(a:cfile)
|
||||
let s:timestamps[a:cfile][a:type] = s:timestamps[a:cfile].atime
|
||||
endf
|
||||
|
||||
|
||||
function! s:PutValue(cfile, value) abort "{{{3
|
||||
let s:cache[a:cfile] = {'mtime': localtime(), 'data': a:value}
|
||||
endf
|
||||
|
||||
|
||||
function! s:GetValue(cfile, default) abort "{{{3
|
||||
return get(get(s:cache, a:cfile, {}), 'data', a:default)
|
||||
endf
|
||||
|
||||
|
||||
function! s:GetCacheTime(cfile) abort "{{{3
|
||||
let not_found = !has_key(s:cache, a:cfile)
|
||||
let cftime = not_found ? -1 : s:cache[a:cfile].mtime
|
||||
return cftime
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#cache#Save(cfile, value, ...) "{{{3
|
||||
TVarArg ['options', {}]
|
||||
let in_memory = get(options, 'in_memory', 0)
|
||||
if in_memory
|
||||
" TLogVAR in_memory, a:cfile, localtime()
|
||||
call s:PutValue(a:cfile, a:value)
|
||||
elseif !empty(a:cfile)
|
||||
" TLogVAR a:value
|
||||
let cfile = a:cfile
|
||||
if g:tlib#cache#use_json && exists('*json_encode')
|
||||
try
|
||||
let value = json_encode(a:value)
|
||||
let cfile .= '.json'
|
||||
catch
|
||||
echoerr v:exception
|
||||
let value = string(a:value)
|
||||
endtry
|
||||
else
|
||||
let value = string(a:value)
|
||||
endif
|
||||
Tlibtrace 'tlib', cfile, value
|
||||
call writefile([value], cfile, 'b')
|
||||
call s:SetTimestamp(a:cfile, 'write')
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#cache#MTime(cfile) "{{{3
|
||||
let mtime = {'mtime': getftime(a:cfile)}
|
||||
let mtime = extend(mtime, get(s:timestamps, a:cfile, {}))
|
||||
return mtime
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#cache#Get(cfile, ...) "{{{3
|
||||
TVarArg ['default', {}], ['options', {}]
|
||||
let in_memory = get(options, 'in_memory', 0)
|
||||
if in_memory
|
||||
" TLogVAR in_memory, a:cfile
|
||||
return s:GetValue(a:cfile, default)
|
||||
else
|
||||
call tlib#cache#MaybePurge()
|
||||
if !empty(a:cfile)
|
||||
let jsonfile = a:cfile .'.json'
|
||||
let use_json = g:tlib#cache#use_json && exists('*json_decode') && exists('v:none') && filereadable(jsonfile)
|
||||
if use_json
|
||||
let use_json = 1
|
||||
let cfile = jsonfile
|
||||
else
|
||||
let cfile = a:cfile
|
||||
endif
|
||||
let mt = s:GetCacheTime(cfile)
|
||||
let ft = getftime(cfile)
|
||||
if mt != -1 && mt >= ft
|
||||
return s:GetValue(cfile, default)
|
||||
elseif ft != -1
|
||||
call s:SetTimestamp(cfile, 'read')
|
||||
let val = join(readfile(cfile, 'b'), '\n')
|
||||
try
|
||||
if use_json
|
||||
" NOTE: Copy result of json_decode() in order to
|
||||
" avoid "E741: value is locked" error in vim8.
|
||||
let value = json_decode(val)
|
||||
if value is v:none
|
||||
let value = default
|
||||
else
|
||||
let value = copy(value)
|
||||
endif
|
||||
else
|
||||
let value = eval(val)
|
||||
endif
|
||||
call s:PutValue(cfile, value)
|
||||
return value
|
||||
catch
|
||||
echohl ErrorMsg
|
||||
echom v:exception
|
||||
echom 'tlib#cache#Get: Invalid value in:' cfile
|
||||
echom 'Value:' string(val)
|
||||
echom 'Please review the file and delete it if necessary'
|
||||
echom 'Will use default value:' string(default)
|
||||
echohl NONE
|
||||
if g:tlib#debug
|
||||
let @* = string(val)
|
||||
endif
|
||||
" call s:PutValue(cfile, default)
|
||||
return default
|
||||
endtry
|
||||
endif
|
||||
endif
|
||||
return default
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" :display: tlib#cache#Value(cfile, generator, ftime, ?generator_args=[], ?options={})
|
||||
" Get a cached value from cfile. If it is outdated (compared to ftime)
|
||||
" or does not exist, create it calling a generator function.
|
||||
function! tlib#cache#Value(cfile, generator, ftime, ...) "{{{3
|
||||
TVarArg ['args', []], ['options', {}]
|
||||
let in_memory = get(options, 'in_memory', 0)
|
||||
if in_memory
|
||||
let cftime = s:GetCacheTime(a:cfile)
|
||||
else
|
||||
let cftime = getftime(a:cfile)
|
||||
endif
|
||||
let ftime = a:ftime
|
||||
" TLogVAR in_memory, cftime
|
||||
if cftime == -1 || ftime == -1 || (ftime != 0 && cftime < ftime)
|
||||
" TLogVAR a:generator, args
|
||||
let val = call(a:generator, args)
|
||||
" TLogVAR val
|
||||
let cval = {'val': val}
|
||||
" TLogVAR cval
|
||||
call tlib#cache#Save(a:cfile, cval, options)
|
||||
return val
|
||||
else
|
||||
let val = tlib#cache#Get(a:cfile, {}, options)
|
||||
if !has_key(val, 'val')
|
||||
throw 'tlib#cache#Value: Internal error: '. a:cfile
|
||||
else
|
||||
return val.val
|
||||
endif
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#cache#ValueFromName(type, name, ...) abort "{{{3
|
||||
let cfile = tlib#cache#Filename(a:type, tlib#url#Encode(a:name), 1)
|
||||
return call(function('tlib#cache#Value'), [cfile] + a:000)
|
||||
endf
|
||||
|
||||
|
||||
" Call |tlib#cache#Purge()| if the last purge was done before
|
||||
" |g:tlib#cache#purge_every_days|.
|
||||
function! tlib#cache#MaybePurge() "{{{3
|
||||
if g:tlib#cache#purge_every_days < 0
|
||||
return
|
||||
endif
|
||||
let dir = tlib#cache#Dir('g')
|
||||
let last_purge = tlib#file#Join([dir, '.last_purge'])
|
||||
let last_purge_exists = filereadable(last_purge)
|
||||
if last_purge_exists
|
||||
let threshold = localtime() - g:tlib#cache#purge_every_days * g:tlib#date#dayshift
|
||||
let should_purge = getftime(last_purge) < threshold
|
||||
else
|
||||
let should_purge = 0 " should ignore empty dirs, like the tmru one: !empty(glob(tlib#file#Join([dir, '**'])))
|
||||
endif
|
||||
if should_purge
|
||||
if last_purge_exists
|
||||
let yn = 'y'
|
||||
else
|
||||
let txt = "TLib: The cache directory '". dir ."' should be purged of old files.\nDelete files older than ". g:tlib#cache#purge_days ." days now?"
|
||||
let yn = tlib#input#Dialog(txt, ['yes', 'no'], 'no')
|
||||
endif
|
||||
if yn =~ '^y\%[es]$'
|
||||
call tlib#cache#Purge()
|
||||
else
|
||||
let g:tlib#cache#purge_every_days = -1
|
||||
if !last_purge_exists
|
||||
call s:PurgeTimestamp(dir)
|
||||
endif
|
||||
echohl WarningMsg
|
||||
echom "TLib: Please run :call tlib#cache#Purge() to clean up ". dir
|
||||
echohl NONE
|
||||
endif
|
||||
elseif !last_purge_exists
|
||||
call s:PurgeTimestamp(dir)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" Delete old files.
|
||||
function! tlib#cache#Purge() "{{{3
|
||||
let threshold = localtime() - g:tlib#cache#purge_days * g:tlib#date#dayshift
|
||||
let dir = tlib#cache#Dir('g')
|
||||
if g:tlib#cache#verbosity >= 1
|
||||
echohl WarningMsg
|
||||
echom "TLib: Delete files older than ". g:tlib#cache#purge_days ." days from ". dir
|
||||
echohl NONE
|
||||
endif
|
||||
let files = tlib#cache#ListFilesInCache()
|
||||
let deldir = []
|
||||
let newer = []
|
||||
let msg = []
|
||||
let more = &more
|
||||
set nomore
|
||||
try
|
||||
for file in files
|
||||
if isdirectory(file)
|
||||
if empty(filter(copy(newer), 'tlib#string#Strcharpart(v:val, 0, len(file)) ==# file'))
|
||||
call add(deldir, file)
|
||||
endif
|
||||
else
|
||||
if getftime(file) < threshold
|
||||
call s:Delete(msg, file, '')
|
||||
else
|
||||
call add(newer, file)
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
finally
|
||||
let &more = more
|
||||
endtry
|
||||
if !empty(msg) && g:tlib#cache#verbosity >= 1
|
||||
echo join(msg, "\n")
|
||||
endif
|
||||
if !empty(deldir)
|
||||
let deldir = filter(reverse(sort(deldir)), 's:Delete(msg, v:val, "d")')
|
||||
if !empty(deldir)
|
||||
if &shell =~ 'sh\(\.exe\)\?$'
|
||||
let scriptfile = 'deldir.sh'
|
||||
let rmdir = 'rm -rf %s'
|
||||
else
|
||||
let scriptfile = 'deldir.bat'
|
||||
let rmdir = 'rmdir /S /Q %s'
|
||||
endif
|
||||
let enc = g:tlib#cache#script_encoding
|
||||
if has('multi_byte') && enc != &enc
|
||||
call map(deldir, 'iconv(v:val, &enc, enc)')
|
||||
endif
|
||||
let scriptfile = tlib#file#Join([dir, scriptfile])
|
||||
if filereadable(scriptfile)
|
||||
let script = readfile(scriptfile)
|
||||
else
|
||||
let script = []
|
||||
endif
|
||||
let script += map(copy(deldir), 'printf(rmdir, shellescape(v:val, 1))')
|
||||
let script = tlib#list#Uniq(script)
|
||||
call writefile(script, scriptfile)
|
||||
call inputsave()
|
||||
if g:tlib#cache#run_script == 0
|
||||
if g:tlib#cache#verbosity >= 1
|
||||
echohl WarningMsg
|
||||
if g:tlib#cache#verbosity >= 2
|
||||
echom "TLib: Purged cache. Need to run script to delete directories"
|
||||
endif
|
||||
echom "TLib: Please review and execute: ". scriptfile
|
||||
echohl NONE
|
||||
endif
|
||||
else
|
||||
try
|
||||
let yn = g:tlib#cache#run_script == 2 ? 'y' : tlib#input#Dialog("TLib: About to delete directories by means of a shell script.\nDirectory removal script: ". scriptfile ."\nRun script to delete directories now?", ['yes', 'no', 'edit'], 'no')
|
||||
if yn =~ '^y\%[es]$'
|
||||
exec 'silent cd '. fnameescape(dir)
|
||||
exec '! ' &shell shellescape(scriptfile, 1)
|
||||
exec 'silent cd -'
|
||||
call delete(scriptfile)
|
||||
elseif yn =~ '^e\%[dit]$'
|
||||
exec 'edit '. fnameescape(scriptfile)
|
||||
endif
|
||||
finally
|
||||
call inputrestore()
|
||||
endtry
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
call s:PurgeTimestamp(dir)
|
||||
endf
|
||||
|
||||
|
||||
function! s:Delete(msg, file, flags) abort "{{{3
|
||||
let rv = delete(a:file, a:flags)
|
||||
if !rv && g:tlib#cache#verbosity >= 2
|
||||
call add(a:msg, "TLib#cache: Delete ". file)
|
||||
endif
|
||||
return rv
|
||||
endf
|
||||
|
||||
|
||||
function! s:PurgeTimestamp(dir) "{{{3
|
||||
let last_purge = tlib#file#Join([a:dir, '.last_purge'])
|
||||
" TLogVAR last_purge
|
||||
call writefile([" "], last_purge)
|
||||
endf
|
||||
|
||||
function! tlib#cache#ListFilesInCache(...) "{{{3
|
||||
let dir = a:0 >= 1 ? a:1 : tlib#cache#Dir('g')
|
||||
if v:version > 702 || (v:version == 702 && has('patch51'))
|
||||
let filess = glob(tlib#file#Join([dir, '**']), 1)
|
||||
else
|
||||
let filess = glob(tlib#file#Join([dir, '**']))
|
||||
endif
|
||||
let files = reverse(split(filess, '\n'))
|
||||
let pos0 = len(tlib#dir#CanonicName(dir))
|
||||
call filter(files, 's:ShouldPurge(tlib#string#Strcharpart(v:val, pos0))')
|
||||
return files
|
||||
endf
|
||||
|
||||
|
||||
function! s:ShouldPurge(partial_filename) "{{{3
|
||||
" TLogVAR a:partial_filename
|
||||
for rx in g:tlib#cache#dont_purge
|
||||
if a:partial_filename =~ rx
|
||||
" TLogVAR a:partial_filename, rx
|
||||
return 0
|
||||
endif
|
||||
endfor
|
||||
return 1
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 38
|
||||
|
||||
|
||||
" :def: function! tlib#char#Get(?timeout=0)
|
||||
" Get a character.
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" echo tlib#char#Get()
|
||||
" echo tlib#char#Get(5)
|
||||
function! tlib#char#Get(...) "{{{3
|
||||
TVarArg ['timeout', 0], ['resolution', 0], ['getmod', 0]
|
||||
let char = -1
|
||||
let mode = 0
|
||||
if timeout == 0 || !has('reltime')
|
||||
let char = getchar()
|
||||
else
|
||||
let char = tlib#char#GetWithTimeout(timeout, resolution)
|
||||
endif
|
||||
if getmod
|
||||
if char != -1
|
||||
let mode = getcharmod()
|
||||
endif
|
||||
return [char, mode]
|
||||
else
|
||||
return char
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#char#IsAvailable() "{{{3
|
||||
let ch = getchar(1)
|
||||
return type(ch) == 0 && ch != 0
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#char#GetWithTimeout(timeout, ...) "{{{3
|
||||
TVarArg ['resolution', 2]
|
||||
" TLogVAR a:timeout, resolution
|
||||
let start = tlib#time#MSecs()
|
||||
while 1
|
||||
let c = getchar(0)
|
||||
if type(c) != 0 || c != 0
|
||||
return c
|
||||
else
|
||||
let now = tlib#time#MSecs()
|
||||
let diff = tlib#time#DiffMSecs(now, start, resolution)
|
||||
" TLogVAR diff
|
||||
if diff > a:timeout
|
||||
return -1
|
||||
endif
|
||||
endif
|
||||
endwh
|
||||
return -1
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 58
|
||||
|
||||
|
||||
let g:tlib#cmd#last_output = []
|
||||
|
||||
|
||||
function! tlib#cmd#OutputAsList(command) "{{{3
|
||||
" TLogVAR a:command
|
||||
if exists('s:redir_lines')
|
||||
redir END
|
||||
let cache = s:redir_lines
|
||||
endif
|
||||
let s:redir_lines = ''
|
||||
redir =>> s:redir_lines
|
||||
silent! exec a:command
|
||||
redir END
|
||||
let g:tlib#cmd#last_output = split(s:redir_lines, '\n')
|
||||
unlet s:redir_lines
|
||||
if exists('cache')
|
||||
let s:redir_lines = cache
|
||||
redir =>> s:redir_lines
|
||||
endif
|
||||
return g:tlib#cmd#last_output
|
||||
endf
|
||||
|
||||
|
||||
" See |:TBrowseOutput|.
|
||||
function! tlib#cmd#BrowseOutput(command) "{{{3
|
||||
call tlib#cmd#BrowseOutputWithCallback("tlib#cmd#DefaultBrowseOutput", a:command)
|
||||
endf
|
||||
|
||||
" :def: function! tlib#cmd#BrowseOutputWithCallback(callback, command)
|
||||
" Execute COMMAND and present its output in a |tlib#input#List()|;
|
||||
" when a line is selected, execute the function named as the CALLBACK
|
||||
" and pass in that line as an argument.
|
||||
"
|
||||
" The CALLBACK function gives you an opportunity to massage the COMMAND output
|
||||
" and possibly act on it in a meaningful way. For example, if COMMAND listed
|
||||
" all URIs found in the current buffer, CALLBACK could validate and then open
|
||||
" the selected URI in the system's default browser.
|
||||
"
|
||||
" This function is meant to be a tool to help compose the implementations of
|
||||
" powerful commands that use |tlib#input#List()| as a common interface. See
|
||||
" |TBrowseScriptnames| as an example.
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" call tlib#cmd#BrowseOutputWithCallback('tlib#cmd#ParseScriptname', 'scriptnames')
|
||||
function! tlib#cmd#BrowseOutputWithCallback(callback, command) "{{{3
|
||||
let list = tlib#cmd#OutputAsList(a:command)
|
||||
let cmds = tlib#input#List('m', 'Output of: '. a:command, list)
|
||||
if !empty(cmds)
|
||||
for cmd in cmds
|
||||
let Callback = function(a:callback)
|
||||
call call(Callback, [cmd])
|
||||
endfor
|
||||
endif
|
||||
endf
|
||||
|
||||
function! tlib#cmd#DefaultBrowseOutput(cmd) "{{{3
|
||||
call feedkeys(':'. a:cmd)
|
||||
endf
|
||||
|
||||
function! tlib#cmd#ParseScriptname(line) "{{{3
|
||||
" let parsedValue = substitute(a:line, '^.\{-}\/', '/', '')
|
||||
let parsedValue = matchstr(a:line, '^\s*\d\+:\s*\zs.*$')
|
||||
exe 'drop '. fnameescape(parsedValue)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#cmd#TBrowseScriptnames() abort "{{{3
|
||||
call tlib#cmd#BrowseOutputWithCallback("tlib#cmd#ParseScriptname", "scriptnames")
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#cmd#UseVertical(?rx='')
|
||||
" Look at the history whether the command was called with vertical. If
|
||||
" an rx is provided check first if the last entry in the history matches
|
||||
" this rx.
|
||||
function! tlib#cmd#UseVertical(...) "{{{3
|
||||
TVarArg ['rx']
|
||||
let h0 = histget(':')
|
||||
let rx0 = '\C\<vert\%[ical]\>\s\+'
|
||||
if !empty(rx)
|
||||
let rx0 .= '.\{-}'.rx
|
||||
endif
|
||||
" TLogVAR h0, rx0
|
||||
return h0 =~ rx0
|
||||
endf
|
||||
|
||||
|
||||
" Print the time in seconds or milliseconds (if your version of VIM
|
||||
" has |+reltime|) a command takes.
|
||||
function! tlib#cmd#Time(cmd) "{{{3
|
||||
if has('reltime')
|
||||
let start = tlib#time#Now()
|
||||
exec a:cmd
|
||||
let end = tlib#time#Now()
|
||||
let diff = string(tlib#time#Diff(end, start)) .'ms'
|
||||
else
|
||||
let start = localtime()
|
||||
exec a:cmd
|
||||
let diff = (localtime() - start) .'s'
|
||||
endif
|
||||
echom 'Time: '. diff .': '. a:cmd
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#cmd#Capture(cmd) "{{{3
|
||||
redir => s
|
||||
silent exec a:cmd
|
||||
redir END
|
||||
return s
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 25
|
||||
|
||||
|
||||
" function! tlib#comments#Comments(?rx='')
|
||||
function! tlib#comments#Comments(...)
|
||||
TVarArg ['rx', '']
|
||||
let comments = {}
|
||||
let co = &comments
|
||||
while !empty(co)
|
||||
" TLogVAR co
|
||||
let [m_0, m_key, m_val, m_val1, co0, co; rest] = matchlist(co, '^\([^:]*\):\(\(\\.\|[^,]*\)\+\)\(,\(.*\)$\|$\)')
|
||||
" TLogVAR m_key, m_val, co
|
||||
if empty(m_key)
|
||||
let m_key = ':'
|
||||
endif
|
||||
if empty(rx) || m_key =~ rx
|
||||
let comments[m_key] = m_val
|
||||
endif
|
||||
endwh
|
||||
return comments
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
" date.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2010-03-25.
|
||||
" @Last Change: 2017-09-06.
|
||||
" @Revision: 44.0.34
|
||||
|
||||
|
||||
if !exists('g:tlib#date#ShortDatePrefix') | let g:tlib#date#ShortDatePrefix = '20' | endif "{{{2
|
||||
if !exists('g:tlib#date#TimeZoneShift') | let g:tlib#date#TimeZoneShift = 0 | endif "{{{2
|
||||
|
||||
let g:tlib#date#dayshift = 60 * 60 * 24
|
||||
" let g:tlib#date#date_rx = '\<\(\d\{4}\)-\(\d\d\)-\(\d\d\)\%(\s\+\(\(\d\d\):\(\d\d\)\)\)\?\>'
|
||||
let g:tlib#date#date_rx = '\<\(\d\{4}\)-\(\d\d\)-\(\d\d\)\>'
|
||||
let g:tlib#date#date_format = '%Y-%m-%d'
|
||||
|
||||
|
||||
function! tlib#date#IsDate(text) abort "{{{3
|
||||
return a:text =~# '^'. g:tlib#date#date_rx .'$' &&
|
||||
\ !empty(tlib#date#Parse(a:text, 0, 1))
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#date#Format(...) abort "{{{3
|
||||
let secs1970 = a:0 >= 1 ? a:1 : localtime()
|
||||
return strftime(g:tlib#date#date_format, secs1970)
|
||||
endf
|
||||
|
||||
|
||||
" :display: tlib#date#DiffInDays(date1, ?date2=localtime(), ?allow_zero=0)
|
||||
function! tlib#date#DiffInDays(date, ...)
|
||||
let allow_zero = a:0 >= 2 ? a:2 : 0
|
||||
let s0 = tlib#date#SecondsSince1970(a:date, 0, allow_zero)
|
||||
let s1 = a:0 >= 1 ? tlib#date#SecondsSince1970(a:1, 0, allow_zero) : localtime()
|
||||
let dd = (s0 - s1) / g:tlib#date#dayshift
|
||||
" TLogVAR dd
|
||||
return dd
|
||||
endf
|
||||
|
||||
|
||||
" :display: tlib#date#Parse(date, ?allow_zero=0, ?silent=0) "{{{3
|
||||
function! tlib#date#Parse(date, ...) "{{{3
|
||||
let min = a:0 >= 1 && a:1 ? 0 : 1
|
||||
let silent = a:0 >= 2 ? a:2 : 0
|
||||
Tlibtype 'tlib', a:date, min, silent
|
||||
let m = matchlist(a:date, '^\(\d\{2}\|\d\{4}\)-\(\d\{1,2}\)-\(\d\{1,2}\)$')
|
||||
Tlibtype 'tlib', m
|
||||
let year = ''
|
||||
let month = ''
|
||||
let days = ''
|
||||
if !empty(m)
|
||||
let year = m[1]
|
||||
let month = m[2]
|
||||
let days = m[3]
|
||||
else
|
||||
let m = matchlist(a:date, '^\(\d\+\)/\(\d\{1,2}\)/\(\d\{1,2}\)$')
|
||||
if !empty(m)
|
||||
let year = m[1]
|
||||
let month = m[3]
|
||||
let days = m[2]
|
||||
else
|
||||
let m = matchlist(a:date, '^\(\d\{1,2}\)\.\s*\(\d\{1,2}\)\.\s*\(\d\d\{2}\|\d\{4}\)$')
|
||||
if !empty(m)
|
||||
let year = m[3]
|
||||
let month = m[2]
|
||||
let days = m[1]
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
Tlibtype 'tlib', year, month, days
|
||||
if empty(m) || year == '' || month == '' || days == '' ||
|
||||
\ month < min || month > 12 || days < min || days > 31
|
||||
if !silent
|
||||
echoerr 'TLib: Invalid date: '. a:date
|
||||
endif
|
||||
return []
|
||||
endif
|
||||
if strlen(year) == 2
|
||||
let year = g:tlib#date#ShortDatePrefix . year
|
||||
Tlibtype 'tlib', year
|
||||
endif
|
||||
return [0 + year, 0 + month, 0 + days]
|
||||
endf
|
||||
|
||||
|
||||
" tlib#date#SecondsSince1970(date, ?daysshift=0, ?allow_zero=0)
|
||||
function! tlib#date#SecondsSince1970(date, ...) "{{{3
|
||||
let allow_zero = a:0 >= 2 ? a:2 : 0
|
||||
" TLogVAR a:date, allow_zero
|
||||
let date = tlib#date#Parse(a:date, allow_zero)
|
||||
if empty(date)
|
||||
return 0
|
||||
endif
|
||||
let [year, month, days] = date
|
||||
if a:0 >= 1 && a:1 > 0
|
||||
let days = days + a:1
|
||||
end
|
||||
let days_passed = days
|
||||
let i = 1970
|
||||
while i < year
|
||||
let days_passed = days_passed + 365
|
||||
if i % 4 == 0 || i == 2000
|
||||
let days_passed = days_passed + 1
|
||||
endif
|
||||
let i = i + 1
|
||||
endwh
|
||||
let i = 1
|
||||
while i < month
|
||||
if i == 1
|
||||
let days_passed = days_passed + 31
|
||||
elseif i == 2
|
||||
let days_passed = days_passed + 28
|
||||
if year % 4 == 0 || year == 2000
|
||||
let days_passed = days_passed + 1
|
||||
endif
|
||||
elseif i == 3
|
||||
let days_passed = days_passed + 31
|
||||
elseif i == 4
|
||||
let days_passed = days_passed + 30
|
||||
elseif i == 5
|
||||
let days_passed = days_passed + 31
|
||||
elseif i == 6
|
||||
let days_passed = days_passed + 30
|
||||
elseif i == 7
|
||||
let days_passed = days_passed + 31
|
||||
elseif i == 8
|
||||
let days_passed = days_passed + 31
|
||||
elseif i == 9
|
||||
let days_passed = days_passed + 30
|
||||
elseif i == 10
|
||||
let days_passed = days_passed + 31
|
||||
elseif i == 11
|
||||
let days_passed = days_passed + 30
|
||||
endif
|
||||
let i = i + 1
|
||||
endwh
|
||||
let seconds = (days_passed - 1) * 24 * 60 * 60
|
||||
let seconds = seconds + (strftime('%H') + g:tlib#date#TimeZoneShift) * 60 * 60
|
||||
let seconds = seconds + strftime('%M') * 60
|
||||
let seconds = seconds + strftime('%S')
|
||||
return seconds
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#date#Shift(date, shift) abort "{{{3
|
||||
let n = str2nr(matchstr(a:shift, '\d\+'))
|
||||
let ml = matchlist(a:date, g:tlib#date#date_rx)
|
||||
" TLogVAR a:date, a:shift, n, ml
|
||||
if a:shift =~ 'd$'
|
||||
let date = tlib#date#AddDays(a:date, n)
|
||||
elseif a:shift =~ 'b$'
|
||||
let n1 = n
|
||||
let secs = tlib#date#SecondsSince1970(a:date)
|
||||
while n1 > 0
|
||||
let n1 -= 1
|
||||
let secs += g:tlib#date#dayshift
|
||||
let uday = strftime('%u', secs)
|
||||
if uday == 6
|
||||
let secs += g:tlib#date#dayshift * 2
|
||||
elseif uday == 7
|
||||
let secs += g:tlib#date#dayshift
|
||||
endif
|
||||
endwh
|
||||
let date = tlib#date#Format(secs)
|
||||
elseif a:shift =~ 'w$'
|
||||
let date = tlib#date#AddDays(a:date, n * 7)
|
||||
elseif a:shift =~ 'm$'
|
||||
let d = str2nr(ml[3])
|
||||
let ms = str2nr(ml[2]) + n
|
||||
let m = (ms - 1) % 12 + 1
|
||||
let yr = str2nr(ml[1]) + (ms - 1) / 12
|
||||
let date = printf('%04d-%02d-%02d', yr, m, d)
|
||||
" TLogVAR d, ms, m, yr, date
|
||||
elseif a:shift =~ 'y$'
|
||||
let yr = str2nr(ml[1]) + n
|
||||
let date = substitute(a:date, '^\d\{4}', yr, '')
|
||||
else
|
||||
throw 'tlib#date#Shift: Unsupported arguments: '. string(a:shift)
|
||||
endif
|
||||
" if !empty(ml[4]) && date !~ '\s'. ml[4] .'$'
|
||||
" let date .= ' '. ml[4]
|
||||
" endif
|
||||
" TLogVAR date
|
||||
return date
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#date#AddDays(date, n) abort "{{{3
|
||||
let secs = tlib#date#SecondsSince1970(a:date) + g:tlib#date#dayshift * a:n
|
||||
" TLogVAR secs
|
||||
let date = tlib#date#Format(secs)
|
||||
return date
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: https://github.com/tomtom
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2016-04-06
|
||||
" @Revision: 22
|
||||
|
||||
|
||||
" :display: tlib#dictionary#Rev(dict, ?opts = {}) abort "{{{3
|
||||
function! tlib#dictionary#Rev(dict, ...) abort "{{{3
|
||||
let opts = a:0 >= 1 ? a:1 : {}
|
||||
Tlibtype a:dict, 'dict', opts, 'dict'
|
||||
let rev = {}
|
||||
let use_string = get(opts, 'use_string', 0)
|
||||
let use_eval = get(opts, 'use_eval', 0)
|
||||
let values_as_list = get(opts, 'values_as_list', 0)
|
||||
for [m, f] in items(a:dict)
|
||||
if use_string
|
||||
let k = string(f)
|
||||
else
|
||||
let k = type(f) == 1 ? f : string(f)
|
||||
if k ==# ''
|
||||
let k = get(opts, 'empty', '')
|
||||
if empty(k)
|
||||
continue
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
if use_eval
|
||||
let v = eval(m)
|
||||
else
|
||||
let v = m
|
||||
endif
|
||||
if values_as_list
|
||||
if has_key(rev, k)
|
||||
call add(rev[k], v)
|
||||
else
|
||||
let rev[k] = [v]
|
||||
endif
|
||||
else
|
||||
let rev[k] = v
|
||||
endif
|
||||
endfor
|
||||
return rev
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 43
|
||||
|
||||
" TLet g:tlib#dir#sep = '/'
|
||||
TLet g:tlib#dir#sep = exists('+shellslash') && !&shellslash ? '\' : '/'
|
||||
|
||||
|
||||
let s:dir_stack = []
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#dir#CanonicName('foo/bar')
|
||||
" => 'foo/bar/'
|
||||
function! tlib#dir#CanonicName(dirname) "{{{3
|
||||
let dirname = tlib#file#Canonic(a:dirname)
|
||||
if dirname !~ '[/\\]$'
|
||||
return dirname . g:tlib#dir#sep
|
||||
endif
|
||||
return dirname
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#dir#NativeName('foo/bar/')
|
||||
" On Windows:
|
||||
" => 'foo\bar\'
|
||||
" On Linux:
|
||||
" => 'foo/bar/'
|
||||
function! tlib#dir#NativeName(dirname) "{{{3
|
||||
let sep = tlib#rx#EscapeReplace(g:tlib#dir#sep)
|
||||
let dirname = substitute(a:dirname, '[\/]', sep, 'g')
|
||||
return dirname
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#dir#PlainName('foo/bar/')
|
||||
" => 'foo/bar'
|
||||
function! tlib#dir#PlainName(dirname) "{{{3
|
||||
let dirname = a:dirname
|
||||
while index(['/', '\'], dirname[-1 : -1]) != -1
|
||||
let dirname = dirname[0 : -2]
|
||||
endwh
|
||||
return dirname
|
||||
" return substitute(a:dirname, tlib#rx#Escape(g:tlib#dir#sep).'\+$', '', '')
|
||||
endf
|
||||
|
||||
|
||||
" Create a directory if it doesn't already exist.
|
||||
function! tlib#dir#Ensure(dir) "{{{3
|
||||
if !isdirectory(a:dir)
|
||||
let dir = tlib#dir#PlainName(a:dir)
|
||||
return mkdir(dir, 'p')
|
||||
endif
|
||||
return 1
|
||||
endf
|
||||
|
||||
|
||||
" Return the first directory in &rtp.
|
||||
function! tlib#dir#MyRuntime() "{{{3
|
||||
return get(split(&rtp, ','), 0)
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#dir#CD(dir, ?locally=0) => CWD
|
||||
function! tlib#dir#CD(dir, ...) "{{{3
|
||||
TVarArg ['locally', haslocaldir()]
|
||||
let cmd = locally ? 'lcd! ' : 'cd! '
|
||||
" let cwd = getcwd()
|
||||
let cmd .= tlib#arg#Ex(a:dir)
|
||||
" TLogVAR a:dir, locally, cmd
|
||||
exec 'silent' cmd
|
||||
" return cwd
|
||||
return getcwd()
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#dir#Push(dir, ?locally=0) => CWD
|
||||
function! tlib#dir#Push(dir, ...) "{{{3
|
||||
TVarArg ['locally', haslocaldir()]
|
||||
call add(s:dir_stack, [getcwd(), locally])
|
||||
return tlib#dir#CD(a:dir, locally)
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#dir#Pop() => CWD
|
||||
function! tlib#dir#Pop() "{{{3
|
||||
let [dir, locally] = remove(s:dir_stack, -1)
|
||||
return tlib#dir#CD(dir, locally)
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 56
|
||||
|
||||
|
||||
function! tlib#eval#FormatValue(value, ...) "{{{3
|
||||
TVarArg ['indent', 0]
|
||||
" TLogVAR a:value, indent
|
||||
let indent1 = indent + 1
|
||||
let indenti = repeat(' ', &sw)
|
||||
let type = type(a:value)
|
||||
let acc = []
|
||||
if type == 0 || type == 1 || type == 2
|
||||
" TLogDBG 'Use string() for type='. type
|
||||
call add(acc, string(a:value))
|
||||
elseif type == 3 "List
|
||||
" TLogDBG 'List'
|
||||
call add(acc, '[')
|
||||
for e in a:value
|
||||
call add(acc, printf('%s%s,', indenti, tlib#eval#FormatValue(e, indent1)))
|
||||
unlet e
|
||||
endfor
|
||||
call add(acc, ']')
|
||||
elseif type == 4 "Dictionary
|
||||
" TLogDBG 'Dictionary'
|
||||
call add(acc, '{')
|
||||
let indent1 = indent + 1
|
||||
for [k, v] in items(a:value)
|
||||
call add(acc, printf("%s%s: %s,", indenti, string(k), tlib#eval#FormatValue(v, indent1)))
|
||||
unlet k v
|
||||
endfor
|
||||
call add(acc, '}')
|
||||
else
|
||||
" TLogDBG 'Unknown type: '. string(a:value)
|
||||
call add(acc, string(a:value))
|
||||
endif
|
||||
if indent > 0
|
||||
let is = repeat(' ', indent * &sw)
|
||||
for i in range(1,len(acc) - 1)
|
||||
let acc[i] = is . acc[i]
|
||||
endfor
|
||||
endif
|
||||
return join(acc, "\n")
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#eval#Extend(a, b, ...) abort "{{{3
|
||||
let mode = a:0 >= 1 ? a:1 : 'force'
|
||||
if type(a:a) != type(a:b)
|
||||
throw 'tlib#eval#Extend: Incompatible types: a='. string(a:a) .' b='. string(a:b)
|
||||
elseif type(a:a) == 3 " list
|
||||
return extend(a:a, a:b, mode)
|
||||
elseif type(a:a) == 4 " dict
|
||||
for k in keys(a:b)
|
||||
if has_key(a:a, k)
|
||||
if mode == 'force'
|
||||
let a:a[k] = tlib#eval#Extend(copy(a:a[k]), a:b[k], mode)
|
||||
elseif mode == 'error'
|
||||
throw 'tlib#eval#Extend: Key already exists: '. k
|
||||
endif
|
||||
else
|
||||
let a:a[k] = a:b[k]
|
||||
endif
|
||||
unlet! k
|
||||
endfor
|
||||
return a:a
|
||||
else
|
||||
return a:b
|
||||
endif
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 225
|
||||
|
||||
|
||||
if !exists('g:tlib#file#drop')
|
||||
" If true, use |:drop| to edit loaded buffers (only available with GUI).
|
||||
let g:tlib#file#drop = has('gui') "{{{2
|
||||
endif
|
||||
|
||||
|
||||
if !exists('g:tlib#file#use_tabs')
|
||||
let g:tlib#file#use_tabs = 0 "{{{2
|
||||
endif
|
||||
|
||||
|
||||
if !exists('g:tlib#file#edit_cmds')
|
||||
let g:tlib#file#edit_cmds = g:tlib#file#use_tabs ? {'buffer': 'tab split | buffer', 'edit': 'tabedit'} : {} "{{{2
|
||||
endif
|
||||
|
||||
|
||||
if !exists('g:tlib#file#absolute_filename_rx')
|
||||
let g:tlib#file#absolute_filename_rx = '^\~\?[\/]' "{{{2
|
||||
endif
|
||||
|
||||
|
||||
if !exists('g:tlib#file#reject_rx')
|
||||
let g:tlib#file#reject_rx = '\%(^\|[\/]\)\%(tags\|Thumbs\.db\)$' "{{{2
|
||||
endif
|
||||
|
||||
|
||||
""" File related {{{1
|
||||
" For the following functions please see ../../test/tlib.vim for examples.
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#file#Split('foo/bar/filename.txt')
|
||||
" => ['foo', 'bar', 'filename.txt']
|
||||
function! tlib#file#Split(filename) abort "{{{3
|
||||
let prefix = matchstr(a:filename, '^\(\w\+:\)\?/\+')
|
||||
Tlibtrace 'tlib', prefix
|
||||
if !empty(prefix)
|
||||
let filename = a:filename[len(prefix) : -1]
|
||||
else
|
||||
let filename = a:filename
|
||||
endif
|
||||
let rv = split(filename, '[\/]')
|
||||
" let rv = split(filename, '[\/]', 1)
|
||||
if !empty(prefix)
|
||||
call insert(rv, prefix[0:-2])
|
||||
endif
|
||||
return rv
|
||||
endf
|
||||
|
||||
|
||||
" :display: tlib#file#Join(filename_parts, ?strip_slashes=1, ?maybe_absolute=0)
|
||||
" EXAMPLES: >
|
||||
" tlib#file#Join(['foo', 'bar', 'filename.txt'])
|
||||
" => 'foo/bar/filename.txt'
|
||||
function! tlib#file#Join(filename_parts, ...) abort "{{{3
|
||||
TVarArg ['strip_slashes', 1], 'maybe_absolute'
|
||||
Tlibtrace 'tlib', a:filename_parts, strip_slashes
|
||||
if maybe_absolute
|
||||
let filename_parts = []
|
||||
for part in a:filename_parts
|
||||
if part =~ g:tlib#file#absolute_filename_rx
|
||||
let filename_parts = []
|
||||
endif
|
||||
call add(filename_parts, part)
|
||||
endfor
|
||||
else
|
||||
let filename_parts = a:filename_parts
|
||||
endif
|
||||
if strip_slashes
|
||||
" let rx = tlib#rx#Escape(g:tlib#dir#sep) .'$'
|
||||
let rx = '[/\\]\+$'
|
||||
let parts = map(copy(filename_parts), 'substitute(v:val, rx, "", "")')
|
||||
Tlibtrace 'tlib', parts
|
||||
return join(parts, g:tlib#dir#sep)
|
||||
else
|
||||
return join(filename_parts, g:tlib#dir#sep)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#file#Relative('foo/bar/filename.txt', 'foo')
|
||||
" => 'bar/filename.txt'
|
||||
function! tlib#file#Relative(filename, basedir) abort "{{{3
|
||||
Tlibtrace 'tlib', a:filename, a:basedir
|
||||
" TLogDBG getcwd()
|
||||
" TLogDBG expand('%:p')
|
||||
let b0 = tlib#file#Absolute(a:basedir)
|
||||
let b = tlib#file#Split(b0)
|
||||
Tlibtrace 'tlib', b
|
||||
let f0 = tlib#file#Absolute(a:filename)
|
||||
let fn = fnamemodify(f0, ':t')
|
||||
let fd = fnamemodify(f0, ':h')
|
||||
let f = tlib#file#Split(fd)
|
||||
Tlibtrace 'tlib', f0, fn, fd, f
|
||||
if f[0] != b[0]
|
||||
let rv = f0
|
||||
else
|
||||
while !empty(f) && !empty(b)
|
||||
if f[0] != b[0]
|
||||
break
|
||||
endif
|
||||
call remove(f, 0)
|
||||
call remove(b, 0)
|
||||
endwh
|
||||
Tlibtrace 'tlib', f, b
|
||||
let rv = tlib#file#Join(repeat(['..'], len(b)) + f + [fn])
|
||||
endif
|
||||
Tlibtrace 'tlib', rv
|
||||
return rv
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#file#IsAbsolute(filename) abort "{{{3
|
||||
return a:filename =~? '^\%(/\|\w\+:/\)'
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#file#Absolute(filename, ...) abort "{{{3
|
||||
if filereadable(a:filename)
|
||||
let filename = fnamemodify(a:filename, ':p')
|
||||
elseif a:filename =~# '^\(/\|[^\/]\+:\)'
|
||||
let filename = a:filename
|
||||
else
|
||||
let cwd = a:0 >= 1 ? a:1 : getcwd()
|
||||
let filename = tlib#file#Join([cwd, a:filename])
|
||||
endif
|
||||
let filename = substitute(filename, '\(^\|[\/]\)\zs\.[\/]', '', 'g')
|
||||
let filename = substitute(filename, '[\/]\zs[^\/]\+[\/]\.\.[\/]', '', 'g')
|
||||
return filename
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#file#Canonic(filename, ...) abort "{{{3
|
||||
TVarArg ['mode', '']
|
||||
if empty(mode)
|
||||
if a:filename =~# '^\\\\'
|
||||
let mode = 'windows'
|
||||
elseif a:filename =~# '^\(file\|ftp\|http\)s\?:'
|
||||
let mode = 'url'
|
||||
elseif (empty(mode) && g:tlib#sys#windows)
|
||||
let mode = 'windows'
|
||||
endif
|
||||
endif
|
||||
let filename = a:filename
|
||||
if mode ==# 'windows'
|
||||
let filename = substitute(filename, '/', '\\', 'g')
|
||||
else
|
||||
let filename = substitute(filename, '\\', '/', 'g')
|
||||
endif
|
||||
return filename
|
||||
endf
|
||||
|
||||
|
||||
function! s:SetScrollBind(world) abort "{{{3
|
||||
let sb = get(a:world, 'scrollbind', &scrollbind)
|
||||
if sb != &scrollbind
|
||||
let &scrollbind = sb
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#file#With(fcmd, bcmd, files, ?world={}) abort
|
||||
function! tlib#file#With(fcmd, bcmd, files, ...) abort "{{{3
|
||||
Tlibtrace 'tlib', a:fcmd, a:bcmd, a:files
|
||||
let world = a:0 >= 1 ? a:1 : {}
|
||||
let unset_switchbuf = a:0 >= 2 ? a:2 : 0
|
||||
exec tlib#arg#Let([['world', {}]])
|
||||
call tlib#autocmdgroup#Init()
|
||||
augroup TLibFileRead
|
||||
autocmd!
|
||||
augroup END
|
||||
if unset_switchbuf
|
||||
let switchbuf = &switchbuf
|
||||
set switchbuf&
|
||||
endif
|
||||
try
|
||||
for f in a:files
|
||||
try
|
||||
let bn = bufnr('^'.f.'$')
|
||||
Tlibtrace 'tlib', f, bn
|
||||
let bufloaded = bufloaded(bn)
|
||||
let ok = 0
|
||||
let s:bufread = ""
|
||||
if bn != -1 && buflisted(bn)
|
||||
if !empty(a:bcmd)
|
||||
let bcmd = a:bcmd .' '. bn
|
||||
Tlibtrace 'tlib', bcmd
|
||||
exec bcmd
|
||||
let ok = 1
|
||||
call s:SetScrollBind(world)
|
||||
endif
|
||||
else
|
||||
if filereadable(f)
|
||||
if !empty(a:fcmd)
|
||||
" TLogDBG a:fcmd .' '. tlib#arg#Ex(f)
|
||||
exec 'autocmd TLibFileRead BufRead' escape(f, '\ ') 'let s:bufread=expand("<afile>:p")'
|
||||
try
|
||||
let fcmd = a:fcmd .' '. tlib#arg#Ex(f)
|
||||
Tlibtrace 'tlib', fcmd
|
||||
exec fcmd
|
||||
finally
|
||||
exec 'autocmd! TLibFileRead BufRead'
|
||||
endtry
|
||||
let ok = 1
|
||||
call s:SetScrollBind(world)
|
||||
endif
|
||||
else
|
||||
echohl error
|
||||
echom 'File not readable: '. f
|
||||
echohl NONE
|
||||
endif
|
||||
endif
|
||||
Tlibtrace 'tlib', ok, bufloaded, &filetype
|
||||
if empty(s:bufread) && ok && !bufloaded && empty(&filetype)
|
||||
doautocmd BufRead
|
||||
endif
|
||||
catch /^Vim\%((\a\+)\)\=:E325/
|
||||
echohl ErrorMsg
|
||||
echom v:exception
|
||||
echohl NONE
|
||||
endtry
|
||||
endfor
|
||||
finally
|
||||
augroup! TLibFileRead
|
||||
if unset_switchbuf
|
||||
let &switchbuf = switchbuf
|
||||
endif
|
||||
unlet! s:bufread
|
||||
endtry
|
||||
" TLogDBG "done"
|
||||
endf
|
||||
|
||||
|
||||
" Return 0 if the file isn't readable/doesn't exist.
|
||||
" Otherwise return 1.
|
||||
function! tlib#file#Edit(fileid) abort "{{{3
|
||||
if type(a:fileid) == 0
|
||||
let bn = a:fileid
|
||||
let filename = fnamemodify(bufname(bn), ':p')
|
||||
else
|
||||
let filename = fnamemodify(a:fileid, ':p')
|
||||
let bn = bufnr(filename)
|
||||
endif
|
||||
if filename == expand('%:p')
|
||||
return 1
|
||||
else
|
||||
Tlibtrace 'tlib', a:fileid, bn, filename, g:tlib#file#drop, filereadable(filename), bufnr('%')
|
||||
if bn != -1 && buflisted(bn)
|
||||
if g:tlib#file#drop
|
||||
" echom "DBG" get(g:tlib#file#edit_cmds, 'drop', 'drop') fnameescape(filename)
|
||||
exec get(g:tlib#file#edit_cmds, 'drop', 'drop') fnameescape(filename)
|
||||
" echom "DBG" bufnr('%')
|
||||
else
|
||||
" echom "DBG" get(g:tlib#file#edit_cmds, 'buffer', 'buffer') bn
|
||||
exec get(g:tlib#file#edit_cmds, 'buffer', 'buffer') bn
|
||||
" echom "DBG" bufnr('%')
|
||||
endif
|
||||
return 1
|
||||
endif
|
||||
if !filereadable(filename) && exists('#TLibPrepareFile#User')
|
||||
exec 'doautocmd TLibPrepareFile User' filename
|
||||
endif
|
||||
if filereadable(filename)
|
||||
try
|
||||
" let file = tlib#arg#Ex(filename)
|
||||
" Tlibtrace 'tlib', file
|
||||
" echom "DBG" get(g:tlib#file#edit_cmds, 'edit', 'edit') fnameescape(filename)
|
||||
exec get(g:tlib#file#edit_cmds, 'edit', 'edit') fnameescape(filename)
|
||||
catch /E325/
|
||||
" swap file exists, let the user handle it
|
||||
catch
|
||||
echohl error
|
||||
echom v:exception
|
||||
echohl NONE
|
||||
endtry
|
||||
return 1
|
||||
else
|
||||
echom "TLIB: File not readable: " . filename
|
||||
if filename != a:fileid
|
||||
echom "TLIB: original filename: " . a:fileid
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
return 0
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#file#FilterFiles(files, options) abort "{{{3
|
||||
Tlibtrace 'tlib', a:files, a:options, g:tlib#file#reject_rx
|
||||
if !get(a:options, 'all', 0)
|
||||
call filter(a:files, 'v:val !~# g:tlib#file#reject_rx')
|
||||
endif
|
||||
Tlibtrace 'tlib', a:files
|
||||
let type = get(a:options, 'type', 'fd')
|
||||
Tlibtrace 'tlib', type
|
||||
if type !~# 'd' || type !~# 'f'
|
||||
call filter(a:files, 'isdirectory(v:val) ? type =~# "d" : type =~# "f"')
|
||||
endif
|
||||
Tlibtrace 'tlib', a:files
|
||||
return a:files
|
||||
endf
|
||||
|
||||
|
||||
if v:version > 704 || (v:version == 704 && has('patch279'))
|
||||
|
||||
function! tlib#file#Glob(pattern, ...) abort "{{{3
|
||||
let all = a:0 >= 1 ? a:1 : 0
|
||||
let nosuf = a:0 >= 2 ? a:2 : 0
|
||||
return tlib#file#FilterFiles(glob(a:pattern, nosuf, 1), {'all': all})
|
||||
endf
|
||||
|
||||
function! tlib#file#Globpath(path, pattern, ...) abort "{{{3
|
||||
let all = a:0 >= 1 ? a:1 : 0
|
||||
let nosuf = a:0 >= 2 ? a:2 : 0
|
||||
return tlib#file#FilterFiles(globpath(a:path, a:pattern, nosuf, 1), {'all': all})
|
||||
endf
|
||||
|
||||
else
|
||||
|
||||
" :nodoc:
|
||||
function! tlib#file#Glob(pattern, ...) abort "{{{3
|
||||
let all = a:0 >= 1 ? a:1 : 0
|
||||
let nosuf = a:0 >= 2 ? a:2 : 0
|
||||
return tlib#file#FilterFiles(split(glob(a:pattern, nosuf), '\n'), {'all': all})
|
||||
endf
|
||||
|
||||
" :nodoc:
|
||||
function! tlib#file#Globpath(path, pattern, ...) abort "{{{3
|
||||
let all = a:0 >= 1 ? a:1 : 0
|
||||
let nosuf = a:0 >= 2 ? a:2 : 0
|
||||
return tlib#file#FilterFiles(split(globpath(a:path, a:pattern), '\n'), {'all': all})
|
||||
endf
|
||||
|
||||
endif
|
||||
|
||||
|
||||
let s:filereadable = {}
|
||||
|
||||
augroup TLib
|
||||
autocmd BufWritePost,FileWritePost,FocusLost * let s:filereadable = {}
|
||||
augroup end
|
||||
|
||||
function! tlib#file#Filereadable(filename) abort "{{{3
|
||||
if !has_key(s:filereadable, a:filename)
|
||||
let s:filereadable[a:filename] = filereadable(a:filename)
|
||||
endif
|
||||
return s:filereadable[a:filename]
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2013-02-22.
|
||||
" @Revision: 3
|
||||
|
||||
|
||||
function! tlib#fixes#Winpos() "{{{3
|
||||
if has('gui_win32')
|
||||
return 'winpos '. getwinposx() .' '. getwinposy()
|
||||
else
|
||||
return ''
|
||||
endif
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2013-10-16.
|
||||
" @Revision: 31
|
||||
|
||||
|
||||
function! tlib#grep#Do(cmd, rx, files) "{{{3
|
||||
" TLogVAR a:cmd, a:rx, a:files
|
||||
let files = join(map(copy(a:files), 'tlib#arg#Ex(v:val, "")'), ' ')
|
||||
let rx = '/'. escape(a:rx, '/') .'/j'
|
||||
" TLogVAR rx, files
|
||||
silent exec a:cmd rx files
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#grep#LocList(rx, files) "{{{3
|
||||
return tlib#grep#Do('noautocmd lvimgrep', a:rx, a:files)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#grep#QuickFixList(rx, files) "{{{3
|
||||
return tlib#grep#Do('noautocmd vimgrep', a:rx, a:files)
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#grep#List(rx, files) "{{{3
|
||||
call setqflist([])
|
||||
call tlib#grep#Do('noautocmd vimgrepadd', a:rx, a:files)
|
||||
let qfl = getqflist()
|
||||
" TLogVAR qfl
|
||||
" try
|
||||
silent! colder
|
||||
" catch
|
||||
" call setqflist([], 'r')
|
||||
" endtry
|
||||
return qfl
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 276
|
||||
|
||||
|
||||
if !exists('g:tlib#hash#use_crc32')
|
||||
let g:tlib#hash#use_crc32 = '' "{{{2
|
||||
endif
|
||||
|
||||
|
||||
if !exists('g:tlib#hash#use_adler32')
|
||||
let g:tlib#hash#use_adler32 = '' "{{{2
|
||||
endif
|
||||
|
||||
|
||||
function! tlib#hash#CRC32B(chars) "{{{3
|
||||
if !empty(g:tlib#hash#use_crc32)
|
||||
let use = g:tlib#hash#use_crc32
|
||||
elseif has('ruby')
|
||||
let use = 'ruby'
|
||||
else
|
||||
let use = 'vim'
|
||||
endif
|
||||
if exists('*tlib#hash#CRC32B_'. use)
|
||||
return tlib#hash#CRC32B_{use}(a:chars)
|
||||
else
|
||||
throw "Unknown version of tlib#hash#CRC32B: ". use
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#hash#CRC32B_ruby(chars) "{{{3
|
||||
if has('ruby')
|
||||
let rv = ''
|
||||
if !exists('s:loaded_ruby_zlib')
|
||||
ruby require 'zlib'
|
||||
let s:loaded_ruby_zlib = 1
|
||||
endif
|
||||
ruby VIM::command('let rv = "%08X"' % Zlib.crc32(VIM::evaluate("a:chars")))
|
||||
return rv
|
||||
else
|
||||
throw "tlib#hash#CRC32B_ruby not supported in this version of vim"
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#hash#CRC32B_vim(chars) "{{{3
|
||||
if !exists('s:crc_table')
|
||||
let cfile = tlib#persistent#Filename('tlib', 'crc_table', 1)
|
||||
let s:crc_table = tlib#persistent#Value(cfile, 'tlib#hash#CreateCrcTable', 0)
|
||||
endif
|
||||
let xFFFF_FFFF = repeat([1], 32)
|
||||
let crc = tlib#bitwise#XOR([0], xFFFF_FFFF, 'bits')
|
||||
for char in split(a:chars, '\zs')
|
||||
let octet = char2nr(char)
|
||||
let r1 = tlib#bitwise#ShiftRight(crc, 8)
|
||||
let i0 = tlib#bitwise#AND(crc, xFFFF_FFFF, 'bits')
|
||||
let i1 = tlib#bitwise#XOR(i0, octet, 'bits')
|
||||
let i2 = tlib#bitwise#Bits2Num(tlib#bitwise#AND(i1, 0xff, 'bits'))
|
||||
let r2 = s:crc_table[i2]
|
||||
let crc = tlib#bitwise#XOR(r1, r2, 'bits')
|
||||
endfor
|
||||
let crc = tlib#bitwise#XOR(crc, xFFFF_FFFF, 'bits')
|
||||
let rv = tlib#bitwise#Bits2Num(crc, 16)
|
||||
if len(rv) < 8
|
||||
let rv = repeat('0', 8 - len(rv)) . rv
|
||||
endif
|
||||
return rv
|
||||
endf
|
||||
|
||||
|
||||
" :nodoc:
|
||||
function! tlib#hash#CreateCrcTable() "{{{3
|
||||
let sum = 0.0
|
||||
for exponent in [0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26, 32]
|
||||
let exp = tlib#bitwise#Bits2Num(repeat([0], 32 - exponent) + [1], 10.0)
|
||||
let sum += exp
|
||||
endfor
|
||||
let divisor = tlib#bitwise#Num2Bits(sum)
|
||||
let crc_table = []
|
||||
for octet in range(256)
|
||||
let remainder = tlib#bitwise#Num2Bits(octet)
|
||||
for i in range(8)
|
||||
if get(remainder, i) != 0
|
||||
let remainder = tlib#bitwise#XOR(remainder, tlib#bitwise#ShiftLeft(divisor, i), "bits")
|
||||
endif
|
||||
endfor
|
||||
let remainder = tlib#bitwise#ShiftRight(remainder, 8)
|
||||
call add(crc_table, remainder)
|
||||
endfor
|
||||
return crc_table
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#hash#Adler32(chars) "{{{3
|
||||
if !empty(g:tlib#hash#use_adler32)
|
||||
let use = g:tlib#hash#use_adler32
|
||||
elseif exists('*or')
|
||||
let use = 'vim'
|
||||
else
|
||||
let use = 'tlib'
|
||||
endif
|
||||
if exists('*tlib#hash#Adler32_'. use)
|
||||
return tlib#hash#Adler32_{use}(a:chars)
|
||||
else
|
||||
throw "Unknown version of tlib#hash#Adler32_: ". use
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#hash#Adler32_vim(chars) "{{{3
|
||||
if exists('*or')
|
||||
let mod_adler = 65521
|
||||
let a = 1
|
||||
let b = 0
|
||||
for index in range(len(a:chars))
|
||||
let c = char2nr(a:chars[index])
|
||||
let a = (a + c) % mod_adler
|
||||
let b = (b + a) % mod_adler
|
||||
endfor
|
||||
let bb = b * float2nr(pow(2, 16))
|
||||
let checksum = or(bb, a)
|
||||
" TLogVAR checksum, a, b, bb
|
||||
return printf("%08X", checksum)
|
||||
else
|
||||
throw "TLIB: Vim version doesn't support bitwise or()"
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#hash#Adler32_tlib(chars) "{{{3
|
||||
let mod_adler = 65521
|
||||
let a = 1
|
||||
let b = 0
|
||||
for index in range(len(a:chars))
|
||||
let c = char2nr(a:chars[index])
|
||||
let a = (a + c) % mod_adler
|
||||
let b = (b + a) % mod_adler
|
||||
endfor
|
||||
let bb = tlib#bitwise#ShiftLeft(tlib#bitwise#Num2Bits(b), 16)
|
||||
let checksum = tlib#bitwise#OR(bb, a, "bits")
|
||||
return printf('%08s', tlib#bitwise#Bits2Num(checksum, 16))
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 11
|
||||
|
||||
|
||||
" :def: function! tlib#hook#Run(hook, ?dict={})
|
||||
" Execute dict[hook], w:{hook}, b:{hook}, or g:{hook} if existent.
|
||||
function! tlib#hook#Run(hook, ...) "{{{3
|
||||
TVarArg ['dict', {}]
|
||||
if has_key(dict, a:hook)
|
||||
let hook = dict[a:hook]
|
||||
else
|
||||
let hook = tlib#var#Get(a:hook, 'wbg')
|
||||
endif
|
||||
if empty(hook)
|
||||
return 0
|
||||
else
|
||||
let world = dict
|
||||
exec hook
|
||||
return 1
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,194 @@
|
||||
" list.vim
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2007-06-30.
|
||||
" @Last Change: 2017-03-26.
|
||||
" @Revision: 71
|
||||
|
||||
|
||||
""" List related functions {{{1
|
||||
" For the following functions please see ../../test/tlib.vim for examples.
|
||||
|
||||
" :def: function! tlib#list#Inject(list, initial_value, funcref) abort
|
||||
" EXAMPLES: >
|
||||
" echo tlib#list#Inject([1,2,3], 0, function('Add')
|
||||
" => 6
|
||||
function! tlib#list#Inject(list, value, Function) abort "{{{3
|
||||
if empty(a:list)
|
||||
return a:value
|
||||
else
|
||||
let item = a:list[0]
|
||||
let rest = a:list[1:-1]
|
||||
let value = call(a:Function, [a:value, item])
|
||||
return tlib#list#Inject(rest, value, a:Function)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#list#Compact([0,1,2,3,[], {}, ""])
|
||||
" => [1,2,3]
|
||||
function! tlib#list#Compact(list) abort "{{{3
|
||||
return filter(copy(a:list), '!empty(v:val)')
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#list#Flatten([0,[1,2,[3,""]]])
|
||||
" => [0,1,2,3,""]
|
||||
function! tlib#list#Flatten(list) abort "{{{3
|
||||
let acc = []
|
||||
for e in a:list
|
||||
if type(e) == 3
|
||||
let acc += tlib#list#Flatten(e)
|
||||
else
|
||||
call add(acc, e)
|
||||
endif
|
||||
unlet e
|
||||
endfor
|
||||
return acc
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#list#FindAll(list, filter, ?process_expr="") abort
|
||||
" Basically the same as filter()
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" tlib#list#FindAll([1,2,3], 'v:val >= 2')
|
||||
" => [2, 3]
|
||||
function! tlib#list#FindAll(list, filter, ...) abort "{{{3
|
||||
let rv = filter(copy(a:list), a:filter)
|
||||
if a:0 >= 1 && !empty(a:1)
|
||||
let rv = map(rv, a:1)
|
||||
endif
|
||||
return rv
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#list#Find(list, filter, ?default="", ?process_expr="") abort
|
||||
"
|
||||
" EXAMPLES: >
|
||||
" tlib#list#Find([1,2,3], 'v:val >= 2')
|
||||
" => 2
|
||||
function! tlib#list#Find(list, filter, ...) abort "{{{3
|
||||
let default = a:0 >= 1 ? a:1 : ''
|
||||
let expr = a:0 >= 2 ? a:2 : ''
|
||||
return get(tlib#list#FindAll(a:list, a:filter, expr), 0, default)
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#list#Any([1,2,3], 'v:val >= 2')
|
||||
" => 1
|
||||
function! tlib#list#Any(list, expr) abort "{{{3
|
||||
return !empty(tlib#list#FindAll(a:list, a:expr))
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#list#All([1,2,3], 'v:val >= 2')
|
||||
" => 0
|
||||
function! tlib#list#All(list, expr) abort "{{{3
|
||||
return len(tlib#list#FindAll(a:list, a:expr)) == len(a:list)
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#list#Remove([1,2,1,2], 2)
|
||||
" => [1,1,2]
|
||||
function! tlib#list#Remove(list, element) abort "{{{3
|
||||
let idx = index(a:list, a:element)
|
||||
if idx != -1
|
||||
call remove(a:list, idx)
|
||||
endif
|
||||
return a:list
|
||||
endf
|
||||
|
||||
|
||||
" EXAMPLES: >
|
||||
" tlib#list#RemoveAll([1,2,1,2], 2)
|
||||
" => [1,1]
|
||||
function! tlib#list#RemoveAll(list, element) abort "{{{3
|
||||
call filter(a:list, 'v:val != a:element')
|
||||
return a:list
|
||||
endf
|
||||
|
||||
|
||||
" :def: function! tlib#list#Zip(lists, ?default='') abort
|
||||
" EXAMPLES: >
|
||||
" tlib#list#Zip([[1,2,3], [4,5,6]])
|
||||
" => [[1,4], [2,5], [3,6]]
|
||||
function! tlib#list#Zip(lists, ...) abort "{{{3
|
||||
TVarArg 'default'
|
||||
let lists = copy(a:lists)
|
||||
let max = 0
|
||||
for l in lists
|
||||
let ll = len(l)
|
||||
if ll > max
|
||||
let max = ll
|
||||
endif
|
||||
endfor
|
||||
" TLogVAR default, max
|
||||
return map(range(0, max - 1), 's:GetNthElement(v:val, lists, default)')
|
||||
endf
|
||||
|
||||
function! s:GetNthElement(n, lists, default) abort "{{{3
|
||||
" TLogVAR a:n, a:lists, a:default
|
||||
return map(copy(a:lists), 'get(v:val, a:n, a:default)')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#list#Uniq(list, ...) abort "{{{3
|
||||
" TLogVAR a:list
|
||||
TVarArg ['get_value', ''], ['remove_empty', 0]
|
||||
if remove_empty
|
||||
call filter(a:list, 'type(v:val) == 0 || !empty(v:val)')
|
||||
endif
|
||||
" CREDITS: Based on syntastic#util#unique(list) by scrooloose
|
||||
let emptystring = 0
|
||||
let seen = {}
|
||||
let uniques = []
|
||||
if empty(get_value)
|
||||
for e in a:list
|
||||
if empty(e)
|
||||
if !emptystring
|
||||
let emptystring = 1
|
||||
call add(uniques, e)
|
||||
endif
|
||||
elseif !has_key(seen, e)
|
||||
let seen[e] = 1
|
||||
call add(uniques, e)
|
||||
endif
|
||||
unlet e
|
||||
endfor
|
||||
else
|
||||
for e in a:list
|
||||
let v = eval(printf(get_value, string(e)))
|
||||
if empty(v)
|
||||
if !emptystring
|
||||
let emptystring = 1
|
||||
call add(uniques, v)
|
||||
endif
|
||||
elseif !has_key(seen, v)
|
||||
let seen[v] = 1
|
||||
call add(uniques, v)
|
||||
endif
|
||||
unlet e v
|
||||
endfor
|
||||
endif
|
||||
return uniques
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#list#ToDictionary(list, default, ...) abort "{{{3
|
||||
TVarArg ['generator', '']
|
||||
let dict = {}
|
||||
for item in a:list
|
||||
if !empty(item)
|
||||
let dict[item] = empty(generator) ? a:default : call(generator, [item, a:default])
|
||||
endif
|
||||
endfor
|
||||
return dict
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2015-10-24
|
||||
" @Revision: 2
|
||||
|
||||
|
||||
function! tlib#loclist#Browse(...) abort "{{{3
|
||||
let list = getloclist(0)
|
||||
return call(function('tlib#qfl#QflList'), [list] + a:000)
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
" map.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2009-08-23.
|
||||
" @Last Change: 2009-08-23.
|
||||
" @Revision: 0.0.4
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
|
||||
" If |pumvisible()| is true, return "\<c-y>". Otherwise return a:key.
|
||||
" For use in maps like: >
|
||||
" imap <expr> <cr> tlib#map#PumAccept("\<cr>")
|
||||
function! tlib#map#PumAccept(key) "{{{3
|
||||
return pumvisible() ? "\<c-y>" : a:key
|
||||
endf
|
||||
|
||||
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
@@ -0,0 +1,34 @@
|
||||
" normal.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2008-10-06.
|
||||
" @Last Change: 2010-09-22.
|
||||
" @Revision: 28
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
|
||||
" :display: tlib#normal#WithRegister(cmd, ?register='t', ?norm_cmd='norm!')
|
||||
" Execute a normal command while maintaining all registers.
|
||||
function! tlib#normal#WithRegister(cmd, ...) "{{{3
|
||||
TVarArg ['register', 't'], ['norm_cmd', 'norm!']
|
||||
let registers = {}
|
||||
for reg in split('123456789'. register, '\zs')
|
||||
exec 'let registers[reg] = @'. reg
|
||||
endfor
|
||||
exec 'let reg = @'. register
|
||||
try
|
||||
exec norm_cmd .' '. a:cmd
|
||||
exec 'return @'. register
|
||||
finally
|
||||
for [reg, value] in items(registers)
|
||||
exec 'let @'. reg .' = value'
|
||||
endfor
|
||||
endtry
|
||||
endf
|
||||
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
@@ -0,0 +1,113 @@
|
||||
" notify.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2008-09-19.
|
||||
" @Last Change: 2017-09-28.
|
||||
" @Revision: 3.3.19
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
|
||||
" :display: tlib#notify#Echo(text, ?style='')
|
||||
" Print text in the echo area. Temporarily disable 'ruler' and 'showcmd'
|
||||
" in order to prevent |press-enter| messages.
|
||||
function! tlib#notify#Echo(text, ...)
|
||||
TVarArg 'style'
|
||||
let ruler = &ruler
|
||||
let showcmd = &showcmd
|
||||
let text = substitute(a:text, '\n', '|', 'g')
|
||||
try
|
||||
set noruler
|
||||
set noshowcmd
|
||||
if !empty(style)
|
||||
exec 'echohl' style
|
||||
endif
|
||||
echo tlib#string#Strcharpart(text, 0, &columns - 1)
|
||||
finally
|
||||
if !empty(style)
|
||||
echohl None
|
||||
endif
|
||||
let &ruler = ruler
|
||||
let &showcmd = showcmd
|
||||
endtry
|
||||
endf
|
||||
|
||||
|
||||
" Contributed by Erik Falor:
|
||||
" If the line containing the message is too long, echoing it will cause
|
||||
" a 'Hit ENTER' prompt to appear. This function cleans up the line so
|
||||
" that does not happen.
|
||||
" The echoed line is too long if it is wider than the width of the
|
||||
" window, minus cmdline space taken up by the ruler and showcmd
|
||||
" features.
|
||||
function! tlib#notify#TrimMessage(message) "{{{3
|
||||
let filler = '...'
|
||||
|
||||
" If length of message with tabs converted into spaces + length of
|
||||
" line number + 2 (for the ': ' that follows the line number) is
|
||||
" greater than the width of the screen, truncate in the middle
|
||||
let to_fill = &columns
|
||||
" TLogVAR to_fill
|
||||
|
||||
" Account for space used by elements in the command-line to avoid
|
||||
" 'Hit ENTER' prompts.
|
||||
" If showcmd is on, it will take up 12 columns.
|
||||
" If the ruler is enabled, but not displayed in the statusline, it
|
||||
" will in its default form take 17 columns. If the user defines a
|
||||
" custom &rulerformat, they will need to specify how wide it is.
|
||||
if has('cmdline_info')
|
||||
if &showcmd
|
||||
let to_fill -= 12
|
||||
else
|
||||
let to_fill -= 1
|
||||
endif
|
||||
" TLogVAR &showcmd, to_fill
|
||||
|
||||
" TLogVAR &laststatus, &ruler, &rulerformat
|
||||
if &ruler
|
||||
if &laststatus == 0 || winnr('$') == 1
|
||||
if has('statusline')
|
||||
if &rulerformat == ''
|
||||
" default ruler is 17 chars wide
|
||||
let to_fill -= 17
|
||||
elseif exists('g:MP_rulerwidth')
|
||||
let to_fill -= g:MP_rulerwidth
|
||||
else
|
||||
" tml: fallback: guess length
|
||||
let to_fill -= strlen(&rulerformat)
|
||||
endif
|
||||
else
|
||||
endif
|
||||
endif
|
||||
else
|
||||
endif
|
||||
else
|
||||
let to_fill -= 1
|
||||
endif
|
||||
|
||||
" TLogVAR to_fill
|
||||
" TLogDBG strlen(a:message)
|
||||
if strlen(a:message) > to_fill
|
||||
let front = to_fill / 2 - 1
|
||||
let back = front
|
||||
if to_fill % 2 == 0 | let back -= 1 | endif
|
||||
return tlib#string#Strcharpart(a:message, 0, front) . filler .
|
||||
\ tlib#string#Strcharpart(a:message, strlen(a:message) - back)
|
||||
else
|
||||
return a:message
|
||||
endif
|
||||
endfunction
|
||||
|
||||
|
||||
function! tlib#notify#PrintError() abort "{{{3
|
||||
echohl ErrorMsg
|
||||
echom v:exception
|
||||
echom v:throwpoint
|
||||
echohl NONE
|
||||
endf
|
||||
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
@@ -0,0 +1,29 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 18
|
||||
|
||||
|
||||
function! tlib#number#ConvertBase(num, base, ...) "{{{3
|
||||
let rtype = a:0 >= 1 ? a:1 : 'string'
|
||||
if a:base > 36
|
||||
throw 'tlib#number#ConvertBase: base > 36 is not supported'
|
||||
endif
|
||||
" TLogVAR a:num, a:base, rtype
|
||||
let rv = []
|
||||
let num = 0.0 + a:num
|
||||
let chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
while floor(num) > 0.0
|
||||
let div = floor(num / a:base)
|
||||
let num1 = float2nr(num - a:base * div)
|
||||
call insert(rv, chars[num1])
|
||||
let num = num / a:base
|
||||
endwh
|
||||
" TLogVAR rv
|
||||
if rtype == 'list'
|
||||
return rv
|
||||
else
|
||||
return join(rv, '')
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
" paragraph.vim
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2009-10-26.
|
||||
" @Last Change: 2011-04-03.
|
||||
" @Revision: 62
|
||||
|
||||
let s:save_cpo = &cpo
|
||||
set cpo&vim
|
||||
|
||||
|
||||
" Return an object describing a |paragraph|.
|
||||
function! tlib#paragraph#GetMetric() "{{{3
|
||||
let sp = {'text_start': line("'{") + 1}
|
||||
if line("'}") == line("$")
|
||||
let sp.last = 1
|
||||
let sp.text_end = line("'}")
|
||||
if line("'{") == 1
|
||||
let sp.ws_start = 0
|
||||
let sp.ws_end = 0
|
||||
let sp.top = sp.text_start
|
||||
let sp.bottom = sp.text_end
|
||||
else
|
||||
let sp.ws_start = prevnonblank(line("'{")) + 1
|
||||
let sp.ws_end = line("'{")
|
||||
let sp.top = sp.ws_start
|
||||
let sp.bottom = sp.text_end
|
||||
endif
|
||||
else
|
||||
let sp.last = 0
|
||||
let sp.text_end = line("'}") - 1
|
||||
let sp.ws_start = line("'}")
|
||||
for i in range(line("'}"), line('$'))
|
||||
if getline(i) =~ '\w'
|
||||
let sp.ws_end = i - 1
|
||||
break
|
||||
elseif i == line("$")
|
||||
let sp.ws_end = i
|
||||
endif
|
||||
endfor
|
||||
let sp.top = sp.text_start
|
||||
let sp.bottom = sp.ws_end
|
||||
endif
|
||||
return sp
|
||||
endf
|
||||
|
||||
|
||||
" This function can be used with the tinymode plugin to move around
|
||||
" paragraphs.
|
||||
"
|
||||
" Example configuration: >
|
||||
"
|
||||
" call tinymode#EnterMap("para_move", "gp")
|
||||
" call tinymode#ModeMsg("para_move", "Move paragraph: j/k")
|
||||
" call tinymode#Map("para_move", "j", "silent call tlib#paragraph#Move('Down', '[N]')")
|
||||
" call tinymode#Map("para_move", "k", "silent call tlib#paragraph#Move('Up', '[N]')")
|
||||
" call tinymode#ModeArg("para_move", "owncount", 1)
|
||||
function! tlib#paragraph#Move(direction, count)
|
||||
" TLogVAR a:direction, a:count
|
||||
let mycount = empty(a:count) ? 1 : a:count
|
||||
for i in range(1, mycount)
|
||||
let para = tlib#paragraph#GetMetric()
|
||||
" TLogVAR para
|
||||
let text = getline(para.text_start, para.text_end)
|
||||
let ws = getline(para.ws_start, para.ws_end)
|
||||
" TLogVAR text, ws
|
||||
exec para.top .','. para.bottom .'delete'
|
||||
if a:direction == "Down"
|
||||
let other = tlib#paragraph#GetMetric()
|
||||
let target = other.bottom + 1
|
||||
if other.last
|
||||
let lines = ws + text
|
||||
let pos = target + len(ws)
|
||||
else
|
||||
let lines = text + ws
|
||||
let pos = target
|
||||
endif
|
||||
elseif a:direction == "Up"
|
||||
if !para.last
|
||||
norm! {
|
||||
endif
|
||||
let other = tlib#paragraph#GetMetric()
|
||||
let target = other.text_start
|
||||
let lines = text + ws
|
||||
let pos = target
|
||||
endif
|
||||
" TLogVAR other, target
|
||||
" TLogVAR lines
|
||||
call append(target - 1, lines)
|
||||
exec pos
|
||||
endfor
|
||||
endf
|
||||
|
||||
|
||||
let &cpo = s:save_cpo
|
||||
unlet s:save_cpo
|
||||
@@ -0,0 +1,54 @@
|
||||
" persistent.vim -- Persistent data
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Created: 2012-05-11.
|
||||
" @Last Change: 2017-03-29.
|
||||
" @Revision: 15
|
||||
|
||||
" The directory for persistent data files. If empty, use
|
||||
" |tlib#dir#MyRuntime|.'/share'.
|
||||
TLet g:tlib_persistent = ''
|
||||
|
||||
|
||||
" :display: tlib#persistent#Dir(?mode = 'bg')
|
||||
" Return the full directory name for persistent data files.
|
||||
function! tlib#persistent#Dir() "{{{3
|
||||
TVarArg ['mode', 'bg']
|
||||
let dir = tlib#var#Get('tlib_persistent', mode)
|
||||
if empty(dir)
|
||||
let dir = tlib#file#Join([tlib#dir#MyRuntime(), 'share'])
|
||||
endif
|
||||
return dir
|
||||
endf
|
||||
|
||||
" :display: tlib#persistent#EncodedFilename(type, file, ?mkdir=0, ?dir='')
|
||||
" Encode `file` and call |tlib#persistent#Filename()|.
|
||||
function! tlib#persistent#EncodedFilename(type, file, ...) "{{{3
|
||||
let file = tlib#url#Encode(a:file)
|
||||
return call(function('tlib#persistent#Filename'), [a:type, file] + a:000)
|
||||
endf
|
||||
|
||||
" :def: function! tlib#persistent#Filename(type, ?file=%, ?mkdir=0)
|
||||
function! tlib#persistent#Filename(type, ...) "{{{3
|
||||
" TLogDBG 'bufname='. bufname('.')
|
||||
let file = a:0 >= 1 ? a:1 : ''
|
||||
let mkdir = a:0 >= 2 ? a:2 : 0
|
||||
return tlib#cache#Filename(a:type, file, mkdir, tlib#persistent#Dir())
|
||||
endf
|
||||
|
||||
function! tlib#persistent#Get(...) "{{{3
|
||||
return call('tlib#cache#Get', a:000)
|
||||
endf
|
||||
|
||||
function! tlib#persistent#MTime(cfile) "{{{3
|
||||
return tlib#cache#MTime(a:cfile)
|
||||
endf
|
||||
|
||||
function! tlib#persistent#Value(...) "{{{3
|
||||
return call('tlib#cache#Value', a:000)
|
||||
endf
|
||||
|
||||
function! tlib#persistent#Save(...) "{{{3
|
||||
call call(function('tlib#cache#Save'), a:000)
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 86
|
||||
|
||||
let s:id = 0
|
||||
let s:ids = []
|
||||
let s:statusline = []
|
||||
let s:laststatus = []
|
||||
let s:max = []
|
||||
let s:format = []
|
||||
let s:width = []
|
||||
let s:value = []
|
||||
let s:timestamp = -1
|
||||
|
||||
" EXAMPLE: >
|
||||
" call tlib#progressbar#Init(20)
|
||||
" try
|
||||
" for i in range(20)
|
||||
" call tlib#progressbar#Display(i)
|
||||
" call DoSomethingThatTakesSomeTime(i)
|
||||
" endfor
|
||||
" finally
|
||||
" call tlib#progressbar#Restore()
|
||||
" endtry
|
||||
function! tlib#progressbar#Init(max, ...) "{{{3
|
||||
TVarArg ['format', '%s'], ['width', 10]
|
||||
let s:id += 1
|
||||
call insert(s:ids, s:id)
|
||||
call insert(s:statusline, &statusline)
|
||||
call insert(s:laststatus, &laststatus)
|
||||
call insert(s:max, a:max)
|
||||
call insert(s:format, format)
|
||||
call insert(s:width, width)
|
||||
call insert(s:value, -1)
|
||||
let sl = {
|
||||
\ 'id': s:id,
|
||||
\ 'statusline': &statusline,
|
||||
\ 'laststatus': &laststatus,
|
||||
\ 'max': a:max,
|
||||
\ 'format': format,
|
||||
\ 'width': width,
|
||||
\ 'value': -1
|
||||
\ }
|
||||
let &laststatus = 2
|
||||
let s:timestamp = localtime()
|
||||
return sl
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#progressbar#Restore(...) "{{{3
|
||||
if a:0 >= 1
|
||||
let sl = a:1
|
||||
let idx = index(s:ids, sl.id)
|
||||
let &statusline = sl.statusline
|
||||
let &laststatus = sl.laststatus
|
||||
else
|
||||
let idx = 0
|
||||
let &statusline = remove(s:statusline, idx)
|
||||
let &laststatus = remove(s:laststatus, idx)
|
||||
endif
|
||||
call remove(s:ids, idx)
|
||||
call remove(s:max, idx)
|
||||
call remove(s:format, idx)
|
||||
call remove(s:width, idx)
|
||||
call remove(s:value, idx)
|
||||
redrawstatus
|
||||
" redraw
|
||||
" echo
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#progressbar#Display(value, ...) "{{{3
|
||||
TVarArg 'extra', ['always', 0]
|
||||
let ts = localtime()
|
||||
if !always && ts == s:timestamp
|
||||
return
|
||||
else
|
||||
let s:timestamp = ts
|
||||
endif
|
||||
let val = a:value * s:width[0] / s:max[0]
|
||||
if always || val != s:value[0]
|
||||
let s:value[0] = val
|
||||
let pbl = repeat('#', val)
|
||||
let pbr = repeat('.', s:width[0] - val)
|
||||
let txt = printf(s:format[0], '['.pbl.pbr.']') . extra
|
||||
let &statusline = txt
|
||||
" TLogDBG txt
|
||||
redrawstatus
|
||||
" redraw
|
||||
" call tlib#notify#Echo(txt)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: https://github.com/tomtom
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2018-02-08
|
||||
" @Revision: 69
|
||||
|
||||
" :nodoc:
|
||||
TLet g:tlib#qfl#world = {
|
||||
\ 'type': 'mi',
|
||||
\ 'query': 'Select entry',
|
||||
\ 'pick_last_item': 0,
|
||||
\ 'resize_vertical': 0,
|
||||
\ 'resize': 20,
|
||||
\ 'scratch': '__TLibQFL__',
|
||||
\ 'tlib_UseInputListScratch': 'call tlib#qfl#InitListBuffer(world)',
|
||||
\ 'key_handlers': [
|
||||
\ {'key': 5, 'agent': 'tlib#qfl#AgentWithSelected', 'key_name': '<c-e>', 'help': 'Run a command on selected lines'},
|
||||
\ {'key': 16, 'agent': 'tlib#qfl#AgentPreviewQFE', 'key_name': '<c-p>', 'help': 'Preview'},
|
||||
\ {'key': 60, 'agent': 'tlib#qfl#AgentGotoQFE', 'key_name': '<', 'help': 'Jump (don''t close the list)'},
|
||||
\ {'key': 19, 'agent': 'tlib#qfl#AgentSplitBuffer', 'key_name': '<c-s>', 'help': 'Show in split buffer'},
|
||||
\ {'key': 20, 'agent': 'tlib#qfl#AgentTabBuffer', 'key_name': '<c-t>', 'help': 'Show in tab'},
|
||||
\ {'key': 22, 'agent': 'tlib#qfl#AgentVSplitBuffer', 'key_name': '<c-v>', 'help': 'Show in vsplit buffer'},
|
||||
\ {'key': 12, 'agent': 'tlib#qfl#AgentEditLine', 'key_name': '<c-l>', 'help': 'Edit selected line(s)'},
|
||||
\ {'key': "\<c-insert>", 'agent': 'tlib#qfl#SetFollowCursor', 'key_name': '<c-ins>', 'help': 'Toggle trace cursor'},
|
||||
\ ],
|
||||
\ 'return_agent': 'tlib#qfl#AgentEditQFE',
|
||||
\ }
|
||||
|
||||
|
||||
function! tlib#qfl#FormatQFLE(qfe) dict abort "{{{3
|
||||
let filename = tlib#qfl#QfeFilename(a:qfe)
|
||||
let short_filename = get(self, 'qfl_short_filename', '')
|
||||
if short_filename ==# 'basename'
|
||||
let filename = matchstr(filename, '[^\\/]\+$')
|
||||
elseif !empty(short_filename)
|
||||
let filename = pathshorten(filename)
|
||||
endif
|
||||
return printf("%s|%d| %s", filename, a:qfe.lnum, get(a:qfe, "text"))
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#QfeFilename(qfe) abort "{{{3
|
||||
let filename = get(a:qfe, 'filename')
|
||||
if empty(filename)
|
||||
let filename = bufname(get(a:qfe, 'bufnr'))
|
||||
endif
|
||||
return filename
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#InitListBuffer(world) "{{{3
|
||||
let set_syntax = get(a:world, 'set_syntax', 'tlib#qfl#SetSyntax')
|
||||
call call(set_syntax, [], a:world)
|
||||
if has('balloon_eval')
|
||||
setlocal ballooneval balloonexpr=tlib#qfl#Balloon()
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#SetSyntax() dict abort "{{{3
|
||||
let syntax = get(self, 'qfl_list_syntax', '')
|
||||
let nextgroup = get(self, 'qfl_list_syntax_nextgroup', '')
|
||||
" TLogVAR syntax, nextgroup
|
||||
if !empty(syntax)
|
||||
exec printf('runtime syntax/%s.vim', syntax)
|
||||
endif
|
||||
syn match TTagedFilesFilename /\%(\f\+\| \)\+\ze|\d\+| / nextgroup=TTagedFilesLNum
|
||||
if !empty(nextgroup)
|
||||
exec 'syn match TTagedFilesLNum /|\d\+|\s\+/ nextgroup='. nextgroup
|
||||
else
|
||||
syn match TTagedFilesLNum /|\d\+|/
|
||||
endif
|
||||
hi def link TTagedFilesFilename Directory
|
||||
hi def link TTagedFilesLNum LineNr
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#Balloon() "{{{3
|
||||
let world = getbufvar(v:beval_bufnr, 'tlibDisplayListWorld')
|
||||
let current = max([1, world.offset]) + v:beval_lnum - 1
|
||||
if current > len(world.table)
|
||||
let current = len(world.table)
|
||||
endif
|
||||
let baseidx = world.GetBaseIdx0(current)
|
||||
" TLogVAR world.offset, v:beval_lnum, current, baseidx
|
||||
let item = world.data[baseidx]
|
||||
let bufnr = get(item, 'bufnr', 0)
|
||||
let bufname = get(item, 'filename', '')
|
||||
if bufnr == 0 && !empty(bufname)
|
||||
let bufnr = bufnr(bufname)
|
||||
endif
|
||||
if empty(bufname) && bufnr > 0
|
||||
let bufname = bufname(bufnr)
|
||||
endif
|
||||
" TLogVAR item
|
||||
if bufnr == 0
|
||||
return ''
|
||||
else
|
||||
let lines = [printf("%d#%d: %s", bufnr, item.lnum, bufname)]
|
||||
if has('balloon_multiline')
|
||||
let desc = {'nr': 'Error number', 'type': 'Error type', 'text': ''}
|
||||
for key in ['nr', 'type', 'text']
|
||||
if has_key(item, key) && !empty(item[key])
|
||||
let keydesc = get(desc, key, key)
|
||||
if empty(keydesc)
|
||||
let text = item[key]
|
||||
else
|
||||
let text = printf("%s: %s", key, item[key])
|
||||
endif
|
||||
call add(lines, text)
|
||||
endif
|
||||
endfor
|
||||
endif
|
||||
return join(lines, "\n")
|
||||
endif
|
||||
" v:beval_bufnr number of the buffer in which balloon is going to show
|
||||
" v:beval_winnr number of the window
|
||||
" v:beval_lnum line number
|
||||
" v:beval_col column number (byte index)
|
||||
" v:beval_text word under or after the mouse pointer
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentEditQFE(world, selected, ...) "{{{3
|
||||
TVarArg ['cmd_edit', ''], ['cmd_buffer', ''], ['set_origin', 1]
|
||||
" TVarArg ['cmd_edit', 'edit'], ['cmd_buffer', 'buffer']
|
||||
" TLogVAR a:selected
|
||||
if empty(a:selected)
|
||||
" call a:world.RestoreOrigin()
|
||||
" call a:world.ResetSelected()
|
||||
else
|
||||
call a:world.RestoreOrigin()
|
||||
for idx in a:selected
|
||||
let idx -= 1
|
||||
" TLogVAR idx
|
||||
if idx >= 0
|
||||
" TLogVAR a:world.data
|
||||
" call tlog#Debug(string(map(copy(a:world.data), 'v:val.bufnr')))
|
||||
" TLogVAR idx, a:world.data[idx]
|
||||
let qfe = a:world.data[idx]
|
||||
" let back = a:world.SwitchWindow('win')
|
||||
" TLogVAR cmd_edit, cmd_buffer, qfe
|
||||
let fn = tlib#qfl#QfeFilename(qfe)
|
||||
" TLogVAR cmd_edit, cmd_buffer, fn
|
||||
if empty(cmd_edit) && empty(cmd_buffer)
|
||||
if tlib#file#Edit(fn)
|
||||
call tlib#buffer#ViewLine(qfe.lnum)
|
||||
endif
|
||||
else
|
||||
call tlib#file#With(cmd_edit, cmd_buffer, [fn], a:world)
|
||||
" TLogDBG bufname('%')
|
||||
" TLogVAR &filetype
|
||||
call tlib#buffer#ViewLine(qfe.lnum)
|
||||
" exec back
|
||||
endif
|
||||
endif
|
||||
endfor
|
||||
if set_origin
|
||||
call a:world.SetOrigin()
|
||||
endif
|
||||
endif
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentPreviewQFE(world, selected) "{{{3
|
||||
" TLogVAR a:selected
|
||||
let back = a:world.SwitchWindow('win')
|
||||
call tlib#qfl#AgentEditQFE(a:world, a:selected[0:0], '', '', 0)
|
||||
exec back
|
||||
redraw
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentGotoQFE(world, selected) "{{{3
|
||||
let world = a:world
|
||||
if !empty(a:selected)
|
||||
let world = tlib#agent#Suspend(world, a:selected)
|
||||
call tlib#qfl#AgentEditQFE(world, a:selected[0:0])
|
||||
endif
|
||||
return world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentWithSelected(world, selected, ...) "{{{3
|
||||
let cmd = a:0 >= 1 ? a:1 : input('Ex command: ', '', 'command')
|
||||
let world = a:world
|
||||
if !empty(cmd)
|
||||
let world = tlib#qfl#RunCmdOnSelected(world, a:selected, cmd)
|
||||
else
|
||||
let world.state = 'redisplay'
|
||||
endif
|
||||
return world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#RunCmdOnSelected(world, selected, cmd, ...) "{{{3
|
||||
let close_scratch = a:0 >= 1 ? a:1 : 1
|
||||
if close_scratch
|
||||
call a:world.CloseScratch()
|
||||
endif
|
||||
" TLogVAR a:cmd
|
||||
for entry in a:selected
|
||||
" TLogVAR entry, a:world.GetBaseItem(entry)
|
||||
call tlib#qfl#AgentEditQFE(a:world, [entry], '', '', 0)
|
||||
" TLogDBG bufname('%')
|
||||
exec a:cmd
|
||||
" let item = a:world.data[a:world.GetBaseIdx(entry - 1)]
|
||||
" <+TODO+>
|
||||
let item = a:world.data[entry - 1]
|
||||
" TLogVAR entry, item, getline('.')
|
||||
if has_key(a:world, 'GetBufferLines')
|
||||
let lines = a:world.GetBufferLines('.', '.')
|
||||
else
|
||||
let lines = getline('.', '.')
|
||||
endif
|
||||
let item['text'] = tlib#string#Strip(lines[0])
|
||||
endfor
|
||||
if has_key(a:world, 'AfterRunCmd')
|
||||
if bufnr('%') == a:world.bufnr
|
||||
call a:world.AfterRunCmd()
|
||||
else
|
||||
" <+TODO+> Run in other buffer
|
||||
endif
|
||||
endif
|
||||
" call s:FormatBase(a:world)
|
||||
call a:world.RestoreOrigin()
|
||||
let a:world.state = 'reset'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentSplitBuffer(world, selected) "{{{3
|
||||
call a:world.CloseScratch()
|
||||
return tlib#qfl#AgentEditQFE(a:world, a:selected, 'split', 'sbuffer')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentTabBuffer(world, selected) "{{{3
|
||||
call a:world.CloseScratch()
|
||||
return tlib#qfl#AgentEditQFE(a:world, a:selected, 'tabedit', 'tab sbuffer')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentVSplitBuffer(world, selected) "{{{3
|
||||
call a:world.CloseScratch()
|
||||
return tlib#qfl#AgentEditQFE(a:world, a:selected, 'vertical split', 'vertical sbuffer')
|
||||
endf
|
||||
|
||||
|
||||
" function! tlib#qfl#AgentOpenBuffer(world, selected) "{{{3
|
||||
" endf
|
||||
|
||||
|
||||
function! tlib#qfl#AgentEditLine(world, selected) "{{{3
|
||||
call a:world.CloseScratch()
|
||||
let cmd = 'call tlib#qfl#EditLine(".")'
|
||||
return tlib#qfl#RunCmdOnSelected(a:world, a:selected, cmd)
|
||||
let a:world.state = 'reset'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#EditLine(lnum) "{{{3
|
||||
call inputsave()
|
||||
let line = input('', getline(a:lnum))
|
||||
call inputrestore()
|
||||
if !empty(line)
|
||||
call setline(line(a:lnum), line)
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#SetFollowCursor(world, selected) "{{{3
|
||||
if empty(a:world.follow_cursor)
|
||||
let a:world.follow_cursor = 'tlib#qfl#AgentPreviewQFE'
|
||||
else
|
||||
let a:world.follow_cursor = ''
|
||||
endif
|
||||
let a:world.state = 'redisplay'
|
||||
return a:world
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#QflList(list, ...) abort "{{{3
|
||||
TVarArg ['world_dict', {}], ['anyway', 0], ['suspended', 0]
|
||||
Tlibtrace 'tlib', world_dict, anyway, suspended
|
||||
" TLogVAR a:list, world_dict, anyway, suspended
|
||||
if !anyway && empty(a:list)
|
||||
return
|
||||
endif
|
||||
let world = copy(g:tlib#qfl#world)
|
||||
if !empty(world_dict)
|
||||
let world = tlib#eval#Extend(world, world_dict)
|
||||
endif
|
||||
" TLogVAR world
|
||||
let world = tlib#World#New(world)
|
||||
" echom "DBG world" string(sort(keys(world)))
|
||||
let world.data = copy(a:list)
|
||||
if !has_key(world, 'format_data')
|
||||
let world.format_data = 'tlib#qfl#FormatQFLE'
|
||||
endif
|
||||
" TLogVAR world
|
||||
" TLogVAR world.data
|
||||
" call s:FormatBase(world)
|
||||
" TLogVAR world.base
|
||||
return tlib#input#ListW(world, suspended ? 'hibernate' : '')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#qfl#Browse(...) abort "{{{3
|
||||
let list = getqflist()
|
||||
return call(function('tlib#qfl#QflList'), [list] + a:000)
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 114
|
||||
|
||||
|
||||
" :def: function! tlib#rx#Escape(text, ?magic='m')
|
||||
" magic can be one of: m, M, v, V
|
||||
" See :help 'magic'
|
||||
function! tlib#rx#Escape(text, ...) "{{{3
|
||||
TVarArg 'magic'
|
||||
if empty(magic)
|
||||
let magic = 'm'
|
||||
endif
|
||||
if magic =~# '^\\\?m$'
|
||||
return escape(a:text, '^$.*\[]~')
|
||||
elseif magic =~# '^\\\?M$'
|
||||
return escape(a:text, '^$\')
|
||||
elseif magic =~# '^\\\?V$'
|
||||
return escape(a:text, '\')
|
||||
elseif magic =~# '^\\\?v$'
|
||||
return substitute(a:text, '[^0-9a-zA-Z_]', '\\&', 'g')
|
||||
else
|
||||
echoerr 'tlib: Unsupported magic type'
|
||||
return a:text
|
||||
endif
|
||||
endf
|
||||
|
||||
" :def: function! tlib#rx#EscapeReplace(text, ?magic='m')
|
||||
" Escape return |sub-replace-special|.
|
||||
function! tlib#rx#EscapeReplace(text, ...) "{{{3
|
||||
TVarArg ['magic', 'm']
|
||||
return escape(a:text, '\&~')
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#rx#Suffixes(...) "{{{3
|
||||
TVarArg ['magic', 'm']
|
||||
let sfx = split(&suffixes, ',')
|
||||
call map(sfx, 'tlib#rx#Escape(v:val, magic)')
|
||||
if magic ==# 'v'
|
||||
return '('. join(sfx, '|') .')$'
|
||||
elseif magic ==# 'V'
|
||||
return '\('. join(sfx, '\|') .'\)\$'
|
||||
else
|
||||
return '\('. join(sfx, '\|') .'\)$'
|
||||
endif
|
||||
endf
|
||||
|
||||
|
||||
function! tlib#rx#LooksLikeRegexp(text) abort "{{{3
|
||||
return a:text =~ '[.?*+{}\[\]]'
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
" @Author: Tom Link (micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Revision: 255
|
||||
|
||||
|
||||
" Scratch window position. By default the list window is opened on the
|
||||
" bottom. Set this variable to 'topleft' or '' to change this behaviour.
|
||||
" See |tlib#input#List()|.
|
||||
TLet g:tlib_scratch_pos = 'botright'
|
||||
|
||||
" If you want the scratch buffer to be fully removed, you might want to
|
||||
" set this variable to 'wipe'.
|
||||
" See also https://github.com/tomtom/tlib_vim/pull/16
|
||||
TLet g:tlib#scratch#hidden = 'hide'
|
||||
|
||||
|
||||
" :def: function! tlib#scratch#UseScratch(?keyargs={})
|
||||
" Display a scratch buffer (a buffer with no file). See :TScratch for an
|
||||
" example.
|
||||
" Return the scratch buffer's number.
|
||||
" Values for keyargs:
|
||||
" scratch_split ... 1: split, 0: window, -1: tab
|
||||
function! tlib#scratch#UseScratch(...) "{{{3
|
||||
exec tlib#arg#Let([['keyargs', {}]])
|
||||
" TLogDBG string(keys(keyargs))
|
||||
let id = get(keyargs, 'scratch', '__Scratch__')
|
||||
" TLogVAR id, bufwinnr(id)
|
||||
" TLogVAR bufnr(id), bufname(id)
|
||||
" TLogVAR 1, winnr(), bufnr('%'), bufname("%")
|
||||
if bufwinnr(id) != -1
|
||||
" echom 'DBG noautocmd keepalt keepj' bufwinnr(id) 'wincmd w'
|
||||
exec 'noautocmd keepalt keepj' bufwinnr(id) 'wincmd w'
|
||||
" TLogVAR "reuse", bufnr("%"), bufname("%")
|
||||
else
|
||||
let winpos = ''
|
||||
let bn = bufnr(id)
|
||||
let wpos = get(keyargs, 'scratch_pos', g:tlib_scratch_pos)
|
||||
" TLogVAR keyargs.scratch_vertical
|
||||
if get(keyargs, 'scratch_vertical')
|
||||
let wpos .= ' vertical'
|
||||
let winpos = tlib#fixes#Winpos()
|
||||
endif
|
||||
" TLogVAR wpos
|
||||
let scratch_split = get(keyargs, 'scratch_split', 1)
|
||||
if bn != -1
|
||||
" TLogVAR bn
|
||||
let wn = bufwinnr(bn)
|
||||
if wn != -1
|
||||
" TLogVAR wn
|
||||
exec 'noautocmd keepalt keepj' (wn .'wincmd w')
|
||||
else
|
||||
if scratch_split == 1
|
||||
let cmd = wpos.' sbuffer!'
|
||||
elseif scratch_split == -1
|
||||
let cmd = wpos.' tab sbuffer!'
|
||||
else
|
||||
let cmd = 'buffer!'
|
||||
endif
|
||||
" TLogVAR cmd, bn
|
||||
silent exec 'noautocmd keepalt keepj' cmd bn
|
||||
endif
|
||||
else
|
||||
" TLogVAR id
|
||||
if scratch_split == 1
|
||||
let cmd = wpos.' split'
|
||||
elseif scratch_split == -1
|
||||
let cmd = wpos.' tab split'
|
||||
else
|
||||
let cmd = 'edit'
|
||||
endif
|
||||
" TLogVAR cmd, id
|
||||
silent exec 'noautocmd keepalt keepj' cmd escape(id, '%#\ ')
|
||||
" silent exec 'split '. id
|
||||
endif
|
||||
let ft = get(keyargs, 'scratch_filetype', '')
|
||||
" TLogVAR ft, winpos
|
||||
if !empty(winpos)
|
||||
exec winpos
|
||||
endif
|
||||
setlocal buftype=nofile
|
||||
let &l:bufhidden = get(keyargs, 'scratch_hidden', g:tlib#scratch#hidden)
|
||||
setlocal noswapfile
|
||||
setlocal nobuflisted
|
||||
setlocal foldmethod=manual
|
||||
setlocal foldcolumn=0
|
||||
setlocal nospell
|
||||
setlocal modifiable
|
||||
setlocal noreadonly
|
||||
" TLogVAR &ft, ft
|
||||
if !empty(ft)
|
||||
let &l:ft = ft
|
||||
endif
|
||||
endif
|
||||
let keyargs.scratch = bufnr('%')
|
||||
let keyargs.scratch_tabpagenr = tabpagenr()
|
||||
let keyargs.scratch_winnr = winnr()
|
||||
" TLogVAR 2, winnr(), bufnr('%'), bufname("%"), keyargs.scratch
|
||||
return keyargs.scratch
|
||||
endf
|
||||
|
||||
|
||||
" Close a scratch buffer as defined in keyargs (usually a World).
|
||||
" Return 1 if the scratch buffer is closed (or if it already was
|
||||
" closed).
|
||||
function! tlib#scratch#CloseScratch(keyargs, ...) "{{{3
|
||||
TVarArg ['reset_scratch', 1]
|
||||
let scratch = get(a:keyargs, 'scratch', '')
|
||||
" TLogVAR scratch, reset_scratch
|
||||
" TLogDBG string(tlib#win#List())
|
||||
if !empty(scratch) && winnr('$') > 1
|
||||
let wn = bufwinnr(scratch)
|
||||
" TLogVAR wn
|
||||
try
|
||||
if wn != -1
|
||||
" TLogDBG winnr()
|
||||
let wb = tlib#win#Set(wn)
|
||||
let winpos = tlib#fixes#Winpos()
|
||||
wincmd c
|
||||
if get(a:keyargs, 'scratch_vertical') && !empty(winpos)
|
||||
exec winpos
|
||||
endif
|
||||
" exec wb
|
||||
" redraw
|
||||
" TLogVAR winnr()
|
||||
endif
|
||||
return 1
|
||||
finally
|
||||
if reset_scratch
|
||||
let a:keyargs.scratch = ''
|
||||
endif
|
||||
endtry
|
||||
endif
|
||||
return 0
|
||||
endf
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
" @Author: Tom Link (mailto:micathom AT gmail com?subject=[vim])
|
||||
" @Website: http://www.vim.org/account/profile.php?user_id=4037
|
||||
" @License: GPL (see http://www.gnu.org/licenses/gpl.txt)
|
||||
" @Last Change: 2017-09-28
|
||||
" @Revision: 4
|
||||
|
||||
|
||||
" :display: tlib#selection#GetSelection(mode, ?mbeg="'<", ?mend="'>", ?opmode='selection')
|
||||
" mode can be one of: selection, lines, block
|
||||
function! tlib#selection#GetSelection(mode, ...) range "{{{3
|
||||
if a:0 >= 2
|
||||
let mbeg = a:1
|
||||
let mend = a:2
|
||||
else
|
||||
let mbeg = "'<"
|
||||
let mend = "'>"
|
||||
endif
|
||||
let opmode = a:0 >= 3 ? a:3 : 'selection'
|
||||
let l0 = line(mbeg)
|
||||
let l1 = line(mend)
|
||||
let text = getline(l0, l1)
|
||||
let c0 = col(mbeg)
|
||||
let c1 = col(mend)
|
||||
" TLogVAR mbeg, mend, opmode, l0, l1, c0, c1
|
||||
" TLogVAR text[-1]
|
||||
" TLogVAR len(text[-1])
|
||||
if opmode == 'block'
|
||||
let clen = c1 - c0
|
||||
call map(text, 'tlib#string#Strcharpart(v:val, c0, clen)')
|
||||
elseif opmode == 'selection'
|
||||
if c1 > 1
|
||||
let text[-1] = tlib#string#Strcharpart(text[-1], 0, c1 - (a:mode == 'o' || c1 > len(text[-1]) ? 0 : 1))
|
||||
endif
|
||||
if c0 > 1
|
||||
let text[0] = tlib#string#Strcharpart(text[0], c0 - 1)
|
||||
endif
|
||||
endif
|
||||
return text
|
||||
endf
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user