Compare commits

..

106 Commits
0.1.0 ... 0.6.0

Author SHA1 Message Date
Junegunn Choi
622c54f4a3 Update gem version (0.6.0)
- Smart-case pattern matching
- CTRL-Q
2013-12-22 16:00:06 +09:00
Junegunn Choi
e09993f919 Update README 2013-12-22 00:36:39 +09:00
Junegunn Choi
7ee6fd1f6d Make install script to add key bindings as well 2013-12-22 00:18:41 +09:00
Junegunn Choi
2dca6f0cb2 Update Last update 2013-12-20 16:13:38 +09:00
Junegunn Choi
159dd7f069 Implement smart-case match (#12) 2013-12-20 15:30:48 +09:00
Junegunn Choi
b30f21e074 CTRL-Q to terminate the finder (#11) 2013-12-20 14:01:28 +09:00
Junegunn Choi
636c86cf6f Update bash host completion for ssh and telnet commands 2013-12-20 11:18:28 +09:00
Junegunn Choi
5483e41b2a Update README 2013-12-14 22:30:09 +09:00
Junegunn Choi
1c89994c94 Suppress warnings on old version of Ruby 2013-12-11 01:03:47 +09:00
Junegunn Choi
e1bc4b983e Update gem version 2013-12-11 01:00:11 +09:00
Junegunn Choi
cb3645ea95 Fix ^.*$ pattern matching in extended-search mode (#9) 2013-12-09 14:46:06 +09:00
Junegunn Choi
04ebaddf5e 0.5.1 2013-12-08 02:09:50 +09:00
Junegunn Choi
45e1f1ae57 Last update: December 5, 2013 2013-12-05 13:29:52 +09:00
Junegunn Choi
c1d5f7cef7 Do not use 256-color if not supported (#8) 2013-12-05 12:17:21 +09:00
Junegunn Choi
df663c4e41 Improve bash completion
- kill completion: do not even start fzf on non-empty word
- host completion: start fzf with initial query
2013-11-29 23:42:00 +09:00
Junegunn Choi
d3742782f3 Fix a typo in README 2013-11-29 18:09:51 +09:00
Junegunn Choi
faff17b2a9 Hostname completion for ssh and telnet commands 2013-11-29 18:08:22 +09:00
Junegunn Choi
9a3cddc92e Apply FZF_COMPLETION_OPTS to kill completion 2013-11-29 17:53:30 +09:00
Junegunn Choi
bd2763d863 Add bash completion for kill command 2013-11-29 17:50:53 +09:00
Junegunn Choi
b2bb22d883 A minor update to install script 2013-11-29 13:42:13 +09:00
Junegunn Choi
ad8ec7f387 Encourage use of function instead of alias (exportability) 2013-11-29 13:40:31 +09:00
Junegunn Choi
cf0ca8578c Update bash key binding example 2013-11-27 10:20:27 +09:00
Junegunn Choi
07aee79bd8 Update examples and bash completion
- Use tput sc/rc instead of redraw-current-line
- Escape selected items with printf
2013-11-27 01:14:36 +09:00
Junegunn Choi
344b57fe33 grep -F 2013-11-26 19:05:20 +09:00
Junegunn Choi
18a2fbf54a Fix install script (use export-able function instead of alias) 2013-11-26 19:01:01 +09:00
Junegunn Choi
39af56cf8f Revert "Reduce the number of Curses.refresh calls"
This reverts commit 2d3a0a1034
(which doesn't make any noticeable difference)
2013-11-24 20:40:23 +09:00
Junegunn Choi
2d3a0a1034 Reduce the number of Curses.refresh calls 2013-11-24 13:40:02 +09:00
Junegunn Choi
655fa5d9aa Update query line after update_list call
This commit is the workaround for the curses issue where the query
string on the screen is truncated after the cursor when the list is
updated: e.g. `aaac|bbb`
2013-11-24 12:56:26 +09:00
Junegunn Choi
9a49a29c7f Fix bash completion (~/abc/def/ghi**)
~/abc/def/ghi** should match ghi under ~/abc/def/, not ~/abc/def*
2013-11-23 20:37:53 +09:00
Junegunn Choi
89ae45cda4 Merge branch 'master' of github.com:junegunn/fzf
Conflicts:
	fzf-completion.bash
2013-11-23 20:16:46 +09:00
Junegunn Choi
f660ad35b2 Improve bash completion: [DIRECTORY/][FUZZY_PATTERN]**<TAB> 2013-11-23 20:12:14 +09:00
Junegunn Choi
c61738ae43 Bump up gem version 2013-11-23 20:09:02 +09:00
Junegunn Choi
c4dec4d34b Add -q option (initial query) 2013-11-23 19:21:02 +09:00
Junegunn Choi
a797604255 -o default as well as -o bashdefault 2013-11-21 11:38:14 +09:00
Junegunn Choi
25840d3bc7 -o bashdefault instead of -o default 2013-11-21 10:49:23 +09:00
Junegunn Choi
4745d50931 Add CTRL-G and ESC (C-[) as abort key (#7) 2013-11-20 21:18:51 +09:00
Junegunn Choi
04bf3abe99 Fix bash completion example 2013-11-20 15:22:25 +09:00
Junegunn Choi
57f7963eee Remove obsolete lines 2013-11-20 14:02:29 +09:00
Junegunn Choi
2fa21e5dd6 Remove obsolete lines 2013-11-20 14:01:13 +09:00
Junegunn Choi
9c4c37aa36 Adjust completion types (all/file/dir) 2013-11-20 12:28:41 +09:00
Junegunn Choi
2540c9062f The last argument doesn't have to be a path 2013-11-20 10:46:53 +09:00
Junegunn Choi
f28274109f Update Vim plugin to take path argument 2013-11-20 10:31:33 +09:00
Junegunn Choi
724724bd8c Extend the list of commands for fzf-completion 2013-11-20 02:23:30 +09:00
Junegunn Choi
64541cb5f8 Fix install script (source ~/.xxxrc has no effect) 2013-11-20 02:10:19 +09:00
Junegunn Choi
179b00ed6c Reload .bashrc/.zshrc after installation 2013-11-20 01:57:24 +09:00
Junegunn Choi
a9fd496691 Merge pull request #6 from junegunn/completion
Prototype implementation of bash auto-completion
2013-11-19 08:44:30 -08:00
Junegunn Choi
b14c57e656 Update README 2013-11-20 01:42:57 +09:00
Junegunn Choi
fa5617e076 Implement bash auto-completion with fzf 2013-11-20 01:29:36 +09:00
Junegunn Choi
e52a1d5fad Update bash example 2013-11-18 17:36:54 +09:00
Junegunn Choi
423e26b0c9 Better handling of NFD chars 2013-11-17 12:32:38 +09:00
Junegunn Choi
84921df0e3 Fix extended-search on non-darwin env 2013-11-17 11:47:52 +09:00
Junegunn Choi
6a5e1de6f3 Fix missing NFD conversion in extended-search mode 2013-11-17 11:20:06 +09:00
Junegunn Choi
90adda73b0 Update Vim plugin
Changes:
- Rename g:fzf_command to g:fzf_source
- Support multi-select mode
- Add fzf#run(vim_command, fzf_args) function

Todo:
- Faster startup with --disable-gems option when available
2013-11-17 02:41:10 +09:00
Junegunn Choi
be3b948034 Fix Gem executable 2013-11-17 01:37:56 +09:00
Junegunn Choi
93dafff424 Implement ALT-B / ALT-F 2013-11-17 01:19:16 +09:00
Junegunn Choi
419bc17c0c Refactoring: separate renderer thread 2013-11-17 00:05:42 +09:00
Junegunn Choi
f0a5757244 Different color for selection-marker 2013-11-16 18:19:26 +09:00
Junegunn Choi
f0b2b98c5d Increase FZF_DEFAULT_SORT to 1000 2013-11-16 11:51:18 +09:00
Junegunn Choi
4530819539 Update README 2013-11-16 02:21:39 +09:00
Junegunn Choi
1825a73e2e "Extended-search mode" 2013-11-16 02:20:40 +09:00
Junegunn Choi
30d4974509 Update README 2013-11-16 01:55:33 +09:00
Junegunn Choi
e4a49dbb2a Add exact-match and invert-exact-match match types 2013-11-16 00:58:46 +09:00
Junegunn Choi
76c7f4f9c0 Do not include highlighted item when items chosen 2013-11-16 00:31:22 +09:00
Junegunn Choi
8ae604af67 Merge branch 'devel' 2013-11-16 00:13:04 +09:00
Junegunn Choi
6037e1e217 Ignore invalid UTF-8 sequences 2013-11-15 21:49:00 +09:00
Junegunn Choi
43acf5c8a4 Extended mode
- Implement prefix caching of extended mode
- Improved ranking algorithm for extended mode
- Fix nfc conversion bug
2013-11-15 20:40:57 +09:00
Junegunn Choi
545e8bfcee Prototype implementation of extended mode (#1) 2013-11-15 02:13:18 +09:00
Junegunn Choi
90ad6d50b8 Refactoring for test 2013-11-15 01:32:42 +09:00
Junegunn Choi
67bdc3a0ad Allow multiple highlighted regions 2013-11-14 20:04:46 +09:00
Junegunn Choi
ff34c6b272 Merge pull request #5 from Vifon/zsh-widgets
new zsh widgets
2013-11-10 16:11:29 -08:00
Wojciech Siewierski
b2ac52462c zsh widget fix
* fzf-cd-widget properly escapes the special characters
2013-11-10 18:57:47 +01:00
Wojciech Siewierski
a6f7caf20d new zsh widgets
+ new fzf-cd-widget for running cd

* fzf-file-widget now properly escapes the special characters and supports
  multi-selection

* fzf-history-widget replaces the current line instead of appending to it
2013-11-10 18:28:59 +01:00
Junegunn Choi
1e9e597837 Merge pull request #4 from Vifon/patch-1
superfluous backslash in zle widget removed
2013-11-10 06:34:21 -08:00
Wojciech Siewierski
0dc725d09c superfluous backslash in zle widget removed 2013-11-10 15:31:10 +01:00
Junegunn Choi
1eceb6a4b9 FZF_DEFAULT_SORT 2013-11-10 20:22:57 +09:00
Junegunn Choi
8777a495bc Shift-TAB on multi-select mode 2013-11-10 20:19:57 +09:00
Junegunn Choi
83825dbbd3 Add Tips section 2013-11-10 20:03:38 +09:00
Junegunn Choi
1ac19a2097 Update README 2013-11-10 11:53:13 +09:00
Junegunn Choi
833c6e1eeb Update example 2013-11-10 04:00:27 +09:00
Junegunn Choi
8a0a3f9bf5 Do not sort the result if query is empty 2013-11-10 03:57:10 +09:00
Junegunn Choi
ddf6e5ef1e Implement multi-select mode (#3) 2013-11-10 03:56:18 +09:00
Junegunn Choi
11a1010e9e Add zsh widget examples 2013-11-09 01:16:39 +09:00
Junegunn Choi
75b666bf54 Update README (replace backticks with $())
As reported in #2, backticks on oh-my-zsh (with TERM=xterm*)
makes fzf run twice. This should be a bug of oh-my-zsh,
but for now using $() seems to be a quick workaround.
2013-11-06 20:54:02 +09:00
Junegunn Choi
3f73554a9e Fix FZF_DEFAULT_COMMAND 2013-11-05 21:05:34 +09:00
Junegunn Choi
dc67420319 Make fzf.vim separately installable 2013-11-05 13:45:23 +09:00
Junegunn Choi
f2d8e7e3ee Update README 2013-11-05 00:11:06 +09:00
Junegunn Choi
de8116b1cf Fix error on Linux with Ruby 1.8 2013-11-04 10:38:16 +09:00
Junegunn Choi
1460e0a10b 0.2.0 2013-11-03 22:51:00 +09:00
Junegunn Choi
c46dad465f Fix invalid return when query string is empty 2013-11-03 22:49:12 +09:00
Junegunn Choi
0df647b2a7 Strip null bytes in the string 2013-11-03 22:15:52 +09:00
Junegunn Choi
69d6b58f88 Do not block on --no-sort 2013-11-03 22:01:25 +09:00
Junegunn Choi
8e305edcf2 Add --no-color (+c) option 2013-11-03 11:45:14 +09:00
Junegunn Choi
c326e363eb Premature optimization is root of all fun 2013-11-03 10:43:48 +09:00
Junegunn Choi
d1298b8fff Reduce memory footprint 2013-11-03 04:05:32 +09:00
Junegunn Choi
2a0e0ded2a Remove Gemfile 2013-11-03 01:11:36 +09:00
Junegunn Choi
7cecf648eb Optimize left/right trimming 2013-11-03 00:06:50 +09:00
Junegunn Choi
c3c94ea889 Fix long item display 2013-11-02 20:58:23 +09:00
Junegunn Choi
94f0c3d22b Bump up gem version to 0.1.3 2013-11-02 20:41:29 +09:00
Junegunn Choi
d717096ee3 Update README 2013-11-02 20:40:25 +09:00
Junegunn Choi
1629fe079a Improve display
- CJK wide character support
- Progress reporting for long-running queries (> 0.5sec)
2013-11-02 20:12:39 +09:00
Junegunn Choi
6a9970c98e FZF_DEFAULT_COMMAND 2013-11-02 12:56:43 +09:00
Junegunn Choi
682583e88f 0.1.1 2013-11-01 16:13:12 +09:00
Junegunn Choi
fd2472d11c Ignore empty file path 2013-11-01 16:07:46 +09:00
Junegunn Choi
311c4a36e2 Remove initial delay 2013-11-01 02:02:00 +09:00
Junegunn Choi
b98fba4cf1 Gradually increase delay upto 0.2 seconds 2013-11-01 01:59:23 +09:00
Junegunn Choi
a03b5c8c42 gem install fzf 2013-11-01 01:12:46 +09:00
10 changed files with 1819 additions and 531 deletions

View File

@@ -1,4 +0,0 @@
source 'https://rubygems.org'
# Specify your gem's dependencies in fzf.gemspec
gemspec

303
README.md
View File

@@ -16,37 +16,25 @@ fzf requires Ruby (>= 1.8.5).
Installation
------------
Download fzf executable and put it somewhere in your search $PATH.
```sh
mkdir -p ~/bin
wget https://raw.github.com/junegunn/fzf/master/fzf -O ~/bin/fzf
chmod +x ~/bin/fzf
```
Or you can just clone this repository and run
Clone this repository and run
[install](https://github.com/junegunn/fzf/blob/master/install) script.
```sh
git clone https://github.com/junegunn/fzf.git
fzf/install
git clone https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
```
Make sure that ~/bin is included in $PATH.
The script will generate `~/.fzf.bash` and `~/.fzf.zsh` and update your
`.bashrc` and `.zshrc` to load them.
```sh
export PATH=$PATH:~/bin
```
Or you can just download
[fzf executable](https://raw.github.com/junegunn/fzf/master/fzf) and put it
somewhere in your search $PATH.
Install as Vim plugin
---------------------
### Install as Vim plugin
fzf was not designed to be a Vim plugin, but you can use it as one. The only
reason one might consider using fzf in Vim is its speed. For a very large list
of files, fzf is significantly faster than native Vim plugins.
You can use any Vim plugin manager to install fzf as a Vim plugin. If you don't
use one, I recommend you try [vim-plug](https://github.com/junegunn/vim-plug).
You can use any Vim plugin manager to install fzf for Vim. If you don't use one,
I recommend you try [vim-plug](https://github.com/junegunn/vim-plug).
1. [Install vim-plug](https://github.com/junegunn/vim-plug#usage)
2. Edit your .vimrc
@@ -64,9 +52,14 @@ Usage
```
usage: fzf [options]
-s, --sort=MAX Maximum number of matched items to sort. Default: 500
+s, --no-sort Keep the sequence unchanged.
+i Case-sensitive match
-m, --multi Enable multi-select
-x, --extended Extended-search mode
-q, --query=STR Initial query
-s, --sort=MAX Maximum number of matched items to sort. Default: 1000
+s, --no-sort Do not sort the result. Keep the sequence unchanged.
-i Case-insensitive match (default: smart-case match)
+i Case-sensitive match
+c, --no-color Disable colors
```
fzf will launch curses-based finder, read the list from STDIN, and write the
@@ -77,10 +70,11 @@ find * -type f | fzf > selected
```
Without STDIN pipe, fzf will use find command to fetch the list of
files (excluding hidden ones).
files excluding hidden ones. (You can override the default command with
`FZF_DEFAULT_COMMAND`)
```sh
vim `fzf`
vim $(fzf)
```
If you want to preserve the exact sequence of the input, provide `--no-sort` (or
@@ -93,13 +87,33 @@ history | fzf +s
### Key binding
Use CTRL-J and CTRL-K (or CTRL-N and CTRL-P) to change the selection, press
enter key to select the item. CTRL-C will terminate the finder.
enter key to select the item. CTRL-C, CTRL-G, or ESC will terminate the finder.
The following readline key bindings should also work as expected.
- CTRL-A / CTRL-E
- CTRL-B / CTRL-F
- CTRL-W / CTRL-U
- ALT-B / ALT-F
If you enable multi-select mode with `-m` option, you can select multiple items
with TAB or Shift-TAB key.
### Extended-search mode
With `-x` or `--extended` option, fzf will start in "extended-search mode".
In this mode, you can specify multiple patterns delimited by spaces,
such as: `^music .mp3$ sbtrkt !rmx`
| Token | Description | Match type |
| -------- | -------------------------------- | -------------------- |
| `^music` | Items that start with `music` | prefix-exact-match |
| `.mp3$` | Items that end with `.mp3` | suffix-exact-match |
| `sbtrkt` | Items that match `sbtrkt` | fuzzy-match |
| `!rmx` | Items that do not match `rmx` | inverse-fuzzy-match |
| `'wild` | Items that include `wild` | exact-match (quoted) |
| `!'fire` | Items that do not include `fire` | inverse-exact-match |
Usage as Vim plugin
-------------------
@@ -107,33 +121,55 @@ Usage as Vim plugin
If you install fzf as a Vim plugin, `:FZF` command will be added.
```vim
" Look for files under current directory
:FZF
:FZF --no-sort
" Look for files under your home directory
:FZF ~
" With options
:FZF --no-sort -m /tmp
```
You can override the command which produces input to fzf.
You can override the source command which produces input to fzf.
```vim
let g:fzf_command = 'find . -type f'
let g:fzf_source = 'find . -type f'
```
Useful bash examples
--------------------
And you can predefine default options to fzf command.
```vim
let g:fzf_options = '--no-color --extended'
```
For more advanced uses, you can call `fzf#run` function as follows.
```vim
:call fzf#run('tabedit', '-m +c')
```
Most of the time, you will prefer native Vim plugins with better integration
with Vim. The only reason one might consider using fzf in Vim is its speed. For
a very large list of files, fzf is significantly faster and it does not block.
Useful examples
---------------
```sh
# vimf - Open selected file in Vim
vimf() {
FILE=`fzf` && vim "$FILE"
FILE=$(fzf) && vim "$FILE"
}
# fd - cd to selected directory
fd() {
DIR=`find ${1:-*} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf` && cd "$DIR"
DIR=$(find ${1:-*} -path '*/\.*' -prune -o -type d -print 2> /dev/null | fzf) && cd "$DIR"
}
# fda - including hidden directories
fda() {
DIR=`find ${1:-*} -type d 2> /dev/null | fzf` && cd "$DIR"
DIR=$(find ${1:-.} -type d 2> /dev/null | fzf) && cd "$DIR"
}
# fh - repeat history
@@ -143,12 +179,199 @@ fh() {
# fkill - kill process
fkill() {
ps -ef | sed 1d | fzf | awk '{print $2}' | xargs kill -${1:-9}
ps -ef | sed 1d | fzf -m | awk '{print $2}' | xargs kill -${1:-9}
}
```
# CTRL-T - Open fuzzy finder and paste the selected item to the command line
Key bindings for command line
-----------------------------
The install script will add the following key bindings to your configuration
files.
### bash
- `CTRL-T` - Paste the selected file path(s) into the command line
- `CTRL-R` - Paste the selected command from history into the command line
```sh
# Required to refresh the prompt after fzf
bind '"\er": redraw-current-line'
bind '"\C-t": " \C-u \C-a\C-k$(fzf)\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er"'
# CTRL-T - Paste the selected file path into the command line
fsel() {
find * -path '*/\.*' -prune \
-o -type f -print \
-o -type l -print 2> /dev/null | fzf -m | while read item; do
printf '%q ' "$item"
done
echo
}
bind '"\C-t": " \C-u \C-a\C-k$(fsel)\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er"'
# CTRL-R - Paste the selected command from history into the command line
bind '"\C-r": " \C-e\C-u$(history | fzf +s | sed \"s/ *[0-9]* *//\")\e\C-e\er"'
```
### zsh
- `CTRL-T` - Paste the selected file path(s) into the command line
- `CTRL-R` - Paste the selected command from history into the command line
- `ALT-C` - cd into the selected directory
```sh
# CTRL-T - Paste the selected file path(s) into the command line
fzf-file-widget() {
local FILES
local IFS="
"
FILES=($(
find * -path '*/\.*' -prune \
-o -type f -print \
-o -type l -print 2> /dev/null | fzf -m))
unset IFS
FILES=$FILES:q
LBUFFER="${LBUFFER%% #} $FILES"
zle redisplay
}
zle -N fzf-file-widget
bindkey '^T' fzf-file-widget
# ALT-C - cd into the selected directory
fzf-cd-widget() {
cd "${$(find * -path '*/\.*' -prune \
-o -type d -print 2> /dev/null | fzf):-.}"
zle reset-prompt
}
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() {
LBUFFER=$(history | fzf +s | sed "s/ *[0-9]* *//")
zle redisplay
}
zle -N fzf-history-widget
bindkey '^R' fzf-history-widget
```
Auto-completion
---------------
Disclaimer: *Auto-completion feature is currently experimental, it can change
over time*
### bash
#### 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 file.
```sh
ssh <TAB>
telnet <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'
```
### zsh
TODO :smiley:
(Pull requests are appreciated.)
Tips
----
### Faster startup with `--disable-gems` options
If you're running Ruby 1.9 or above, you can improve the startup time with
`--disable-gems` option to Ruby.
- `time ruby ~/bin/fzf -h`
- 0.077 sec
- `time ruby --disable-gems ~/bin/fzf -h`
- 0.025 sec
You can define fzf function with the option as follows:
```sh
fzf() {
ruby --disable-gems ~/bin/fzf "$@"
}
export -f fzf
```
However, this is automatically set up in your .bashrc and .zshrc if you use the
bundled [install](https://github.com/junegunn/fzf/blob/master/install) script.
### Incorrect display on Ruby 1.8
It is reported that the output of fzf can become unreadable on some terminals
when it's running on Ruby 1.8. If you experience the problem, upgrade your Ruby
to 1.9 or above. Ruby 1.9 or above is also required for displaying Unicode
characters.
### Ranking algorithm
fzf sorts the result first by the length of the matched substring, then by the
length of the whole string. However it only does so when the number of matches
is less than the limit which is by default 1000, in order to avoid the cost of
sorting a large list and limit the response time of the query.
This limit can be adjusted with `-s` option, or with the environment variable
`FZF_DEFAULT_SORT`.
```sh
export FZF_DEFAULT_SORT=10000
```
License

View File

@@ -1 +1,8 @@
require "bundler/gem_tasks"
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.pattern = 'test/**/test_*.rb'
test.verbose = true
end

1290
fzf

File diff suppressed because it is too large Load Diff

147
fzf-completion.bash Normal file
View File

@@ -0,0 +1,147 @@
#!/bin/bash
# ____ ____
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/-completion.bash
#
# - $FZF_COMPLETION_TRIGGER (default: '**')
# - $FZF_COMPLETION_OPTS (default: empty)
_fzf_opts_completion() {
local cur prev opts
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
opts="-m --multi -x --extended -s --sort +s +i +c --no-color"
case "${prev}" in
--sort|-s)
COMPREPLY=( $(compgen -W "$(seq 2000 1000 10000)" -- ${cur}) )
return 0
;;
esac
if [[ ${cur} =~ ^-|\+ ]]; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
return 0
}
_fzf_generic_completion() {
local cur base dir leftover matches
COMPREPLY=()
FZF_COMPLETION_TRIGGER=${FZF_COMPLETION_TRIGGER:-**}
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ ${cur} == *"$FZF_COMPLETION_TRIGGER" ]]; then
base=${cur:0:${#cur}-${#FZF_COMPLETION_TRIGGER}}
eval base=$base
dir="$base"
while [ 1 ]; do
if [ -z "$dir" -o -d "$dir" ]; then
leftover=${base/#"$dir"}
leftover=${leftover/#\/}
[ "$dir" = './' ] && dir=''
tput sc
matches=$(find "$dir"* $1 2> /dev/null | fzf $FZF_COMPLETION_OPTS $2 -q "$leftover" | while read item; do
printf '%q ' "$item"
done)
matches=${matches% }
if [ -n "$matches" ]; then
COMPREPLY=( "$matches" )
else
COMPREPLY=( "$cur" )
fi
tput rc
return 0
fi
dir=$(dirname "$dir")
[[ "$dir" =~ /$ ]] || dir="$dir"/
done
fi
}
_fzf_all_completion() {
_fzf_generic_completion \
"-name .git -prune -o -name .svn -prune -o -type d -print -o -type f -print -o -type l -print" \
"-m"
}
_fzf_file_completion() {
_fzf_generic_completion \
"-name .git -prune -o -name .svn -prune -o -type f -print -o -type l -print" \
"-m"
}
_fzf_dir_completion() {
_fzf_generic_completion \
"-name .git -prune -o -name .svn -prune -o -type d -print" \
""
}
_fzf_kill_completion() {
[ -n "${COMP_WORDS[COMP_CWORD]}" ] && return 1
local selected
tput sc
selected=$(ps -ef | sed 1d | fzf -m $FZF_COMPLETION_OPTS | awk '{print $2}' | tr '\n' ' ')
tput rc
if [ -n "$selected" ]; then
COMPREPLY=( "$selected" )
return 0
fi
}
_fzf_host_completion() {
local cur prev selected
cur="${COMP_WORDS[COMP_CWORD]}"
prev="${COMP_WORDS[COMP_CWORD-1]}"
[[ "$cur" =~ ^- || "$prev" =~ ^- ]] && return 1
tput sc
selected=$(grep -v '^\s*\(#\|$\)' /etc/hosts | awk '{print $2}' | sort -u | fzf $FZF_COMPLETION_OPTS -q "$cur")
tput rc
if [ -n "$selected" ]; then
COMPREPLY=("$selected")
return 0
fi
}
complete -F _fzf_opts_completion fzf
# Directory
for cmd in "cd pushd rmdir"; do
complete -F _fzf_dir_completion -o default -o bashdefault $cmd
done
# File
for cmd in "
awk cat diff diff3
emacs ex file ftp g++ gcc gvim head hg java
javac ld less more mvim patch perl python ruby
sed sftp sort source tail tee uniq vi view vim wc"; do
complete -F _fzf_file_completion -o default -o bashdefault $cmd
done
# Anything
for cmd in "
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"; do
complete -F _fzf_all_completion -o default -o bashdefault $cmd
done
# Kill completion
complete -F _fzf_kill_completion -o nospace -o default -o bashdefault kill
# Host completion
for cmd in "ssh telnet"; do
complete -F _fzf_host_completion -o default -o bashdefault $cmd
done

9
fzf-completion.zsh Normal file
View File

@@ -0,0 +1,9 @@
#!/bin/zsh
# ____ ____
# / __/___ / __/
# / /_/_ / / /_
# / __/ / /_/ __/
# /_/ /___/_/-completion.zsh
#
# TODO

View File

@@ -1,7 +1,7 @@
# coding: utf-8
Gem::Specification.new do |spec|
spec.name = 'fzf'
spec.version = '0.1.0'
spec.version = '0.6.0'
spec.authors = ['Junegunn Choi']
spec.email = ['junegunn.c@gmail.com']
spec.description = %q{Fuzzy finder for your shell}

162
install
View File

@@ -1,7 +1,163 @@
#!/bin/bash
cd `dirname $BASH_SOURCE`
mkdir -p ~/bin
ln -sf `pwd`/fzf ~/bin/fzf
chmod +x ~/bin/fzf
fzf_base=`pwd`
# ruby executable
echo -n "Checking Ruby executable ... "
ruby=`which ruby`
if [ $? -ne 0 ]; then
echo "ruby executable not found!"
exit 1
fi
echo "OK"
# Curses-support
echo -n "Checking Curses support ... "
/usr/bin/env ruby -e "begin; require 'curses'; rescue Exception; exit 1; end"
if [ $? -ne 0 ]; then
echo "Your ruby does not support 'curses'"
exit 1
fi
echo "OK"
# Ruby version
echo -n "Checking Ruby version ... "
/usr/bin/env ruby -e 'exit RUBY_VERSION >= "1.9"'
if [ $? -eq 0 ]; then
echo ">= 1.9"
fzf_cmd="$ruby --disable-gems $fzf_base/fzf"
else
echo "< 1.9"
fzf_cmd="$ruby $fzf_base/fzf"
fi
# Auto-completion
read -p "Do you want to add auto-completion support? ([y]/n) " -n 1 -r
echo
[[ ! $REPLY =~ ^[Nn]$ ]]
auto_completion=$?
# Key-bindings
read -p "Do you want to add key bindings? ([y]/n) " -n 1 -r
echo
[[ ! $REPLY =~ ^[Nn]$ ]]
key_bindings=$?
echo
for shell in bash zsh; do
echo -n "Generate ~/.fzf.$shell ... "
src=~/.fzf.${shell}
fzf_completion="source $fzf_base/fzf-completion.${shell}"
if [ $auto_completion -ne 0 ]; then
fzf_completion="# $fzf_completion"
fi
cat > $src << EOF
# Setup fzf function
# ------------------
unalias fzf 2> /dev/null
fzf() {
$fzf_cmd "\$@"
}
export -f fzf > /dev/null
# Auto-completion
# ---------------
$fzf_completion
EOF
if [ $key_bindings -eq 0 ]; then
if [ $shell = bash ]; then
cat >> $src << "EOF"
# Key bindings
# ------------
# Required to refresh the prompt after fzf
bind '"\er": redraw-current-line'
# CTRL-T - Paste the selected file path into the command line
fsel() {
find * -path '*/\.*' -prune \
-o -type f -print \
-o -type l -print 2> /dev/null | fzf -m | while read item; do
printf '%q ' "$item"
done
echo
}
bind '"\C-t": " \C-u \C-a\C-k$(fsel)\e\C-e\C-y\C-a\C-y\ey\C-h\C-e\er"'
# CTRL-R - Paste the selected command from history into the command line
bind '"\C-r": " \C-e\C-u$(history | fzf +s | sed \"s/ *[0-9]* *//\")\e\C-e\er"'
EOF
else
cat >> $src << "EOF"
# Key bindings
# ------------
# CTRL-T - Paste the selected file path(s) into the command line
fzf-file-widget() {
local FILES
local IFS="
"
FILES=($(
find * -path '*/\.*' -prune \
-o -type f -print \
-o -type l -print 2> /dev/null | fzf -m))
unset IFS
FILES=$FILES:q
LBUFFER="${LBUFFER%% #} $FILES"
zle redisplay
}
zle -N fzf-file-widget
bindkey '^T' fzf-file-widget
# ALT-C - cd into the selected directory
fzf-cd-widget() {
cd "${$(find * -path '*/\.*' -prune \
-o -type d -print 2> /dev/null | fzf):-.}"
zle reset-prompt
}
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() {
LBUFFER=$(history | fzf +s | sed "s/ *[0-9]* *//")
zle redisplay
}
zle -N fzf-history-widget
bindkey '^R' fzf-history-widget
EOF
fi
fi
echo "OK"
done
echo
for shell in bash zsh; do
rc=~/.${shell}rc
src="source ~/.fzf.${shell}"
echo "Update $rc:"
echo " - $src"
if [ $(grep -F "$src" $rc | wc -l) -gt 0 ]; then
echo " - Not added (already being sourced)"
else
echo $src >> $rc
echo " - Added"
fi
echo
done
cat << EOF
Finished. Reload your .bashrc or .zshrc to take effect.
source ~/.bashrc # bash"
source ~/.zshrc # zsh"
To uninstall fzf, simply remove the added line.
EOF

View File

@@ -23,19 +23,37 @@
let s:exec = expand('<sfile>:h:h').'/fzf'
function! s:fzf(args)
function! s:escape(path)
return substitute(a:path, ' ', '\\ ', 'g')
endfunction
function! fzf#run(command, ...)
let cwd = getcwd()
try
let tf = tempname()
let prefix = exists('g:fzf_command') ? g:fzf_command.'|' : ''
execute "silent !".prefix."/usr/bin/env ruby ".s:exec." ".a:args." > ".tf
let args = copy(a:000)
if len(args) > 0 && isdirectory(expand(args[-1]))
let dir = remove(args, -1)
execute 'chdir '.s:escape(dir)
endif
let argstr = join(args)
let tf = tempname()
let prefix = exists('g:fzf_source') ? g:fzf_source.'|' : ''
let fzf = executable(s:exec) ? s:exec : 'fzf'
let options = empty(argstr) ? get(g:, 'fzf_options', '') : argstr
execute "silent !".prefix.fzf.' '.options." > ".tf
if !v:shell_error
execute 'silent e '.join(readfile(tf), '')
for line in readfile(tf)
if !empty(line)
execute a:command.' '.s:escape(line)
endif
endfor
endif
finally
silent! call delete(tf)
execute 'chdir '.s:escape(cwd)
redraw!
silent! call delete(tf)
endtry
endfunction
command! -nargs=* FZF call s:fzf(<q-args>)
command! -nargs=* -complete=dir FZF call fzf#run('silent e', <f-args>)

394
test/test_fzf.rb Normal file
View File

@@ -0,0 +1,394 @@
#!/usr/bin/env ruby
# encoding: utf-8
require 'minitest/autorun'
$LOAD_PATH.unshift File.expand_path('../..', __FILE__)
ENV['FZF_EXECUTABLE'] = '0'
load 'fzf'
class TestFZF < MiniTest::Unit::TestCase
def test_default_options
fzf = FZF.new []
assert_equal 1000, fzf.sort
assert_equal false, fzf.multi
assert_equal true, fzf.color
assert_equal nil, fzf.rxflag
begin
ENV['FZF_DEFAULT_SORT'] = '1500'
fzf = FZF.new []
assert_equal 1500, fzf.sort
ensure
ENV.delete 'FZF_DEFAULT_SORT'
end
end
def test_option_parser
# Long opts
fzf = FZF.new %w[--sort=2000 --no-color --multi +i --query hello]
assert_equal 2000, fzf.sort
assert_equal true, fzf.multi
assert_equal false, fzf.color
assert_equal 0, fzf.rxflag
assert_equal 'hello', fzf.query.get
# Short opts
fzf = FZF.new %w[-s 2000 +c -m +i -qhello]
assert_equal 2000, fzf.sort
assert_equal true, fzf.multi
assert_equal false, fzf.color
assert_equal 0, fzf.rxflag
assert_equal 'hello', fzf.query.get
# Left-to-right
fzf = FZF.new %w[-qhello -s 2000 --no-sort -q world]
assert_equal nil, fzf.sort
assert_equal 'world', fzf.query.get
fzf = FZF.new %w[--query hello +s -s 2000 --query=world]
assert_equal 2000, fzf.sort
assert_equal 'world', fzf.query.get
rescue SystemExit => e
assert false, "Exited"
end
def test_invalid_option
[%w[--unknown], %w[yo dawg]].each do |argv|
assert_raises(SystemExit) do
fzf = FZF.new argv
end
end
end
# FIXME Only on 1.9 or above
def test_width
fzf = FZF.new []
assert_equal 5, fzf.width('abcde')
assert_equal 4, fzf.width('한글')
assert_equal 5, fzf.width('한글.')
end
def test_trim
fzf = FZF.new []
assert_equal ['사.', 6], fzf.trim('가나다라마바사.', 4, true)
assert_equal ['바사.', 5], fzf.trim('가나다라마바사.', 5, true)
assert_equal ['바사.', 5], fzf.trim('가나다라마바사.', 6, true)
assert_equal ['마바사.', 4], fzf.trim('가나다라마바사.', 7, true)
assert_equal ['가나', 6], fzf.trim('가나다라마바사.', 4, false)
assert_equal ['가나', 6], fzf.trim('가나다라마바사.', 5, false)
assert_equal ['가나a', 6], fzf.trim('가나ab라마바사.', 5, false)
assert_equal ['가나ab', 5], fzf.trim('가나ab라마바사.', 6, false)
assert_equal ['가나ab', 5], fzf.trim('가나ab라마바사.', 7, false)
end
def test_format
fzf = FZF.new []
assert_equal [['01234..', false]], fzf.format('0123456789', 7, [])
assert_equal [['012', false], ['34', true], ['..', false]],
fzf.format('0123456789', 7, [[3, 5]])
assert_equal [['..56', false], ['789', true]],
fzf.format('0123456789', 7, [[7, 10]])
assert_equal [['..56', false], ['78', true], ['9', false]],
fzf.format('0123456789', 7, [[7, 9]])
(3..5).each do |i|
assert_equal [['..', false], ['567', true], ['89', false]],
fzf.format('0123456789', 7, [[i, 8]])
end
assert_equal [['..', false], ['345', true], ['..', false]],
fzf.format('0123456789', 7, [[3, 6]])
assert_equal [['012', false], ['34', true], ['..', false]],
fzf.format('0123456789', 7, [[3, 5]])
# Multi-region
assert_equal [["0", true], ["1", false], ["2", true], ["34..", false]],
fzf.format('0123456789', 7, [[0, 1], [2, 3]])
assert_equal [["..", false], ["5", true], ["6", false], ["78", true], ["9", false]],
fzf.format('0123456789', 7, [[3, 6], [7, 9]])
assert_equal [["..", false], ["3", true], ["4", false], ["5", true], ["..", false]],
fzf.format('0123456789', 7, [[3, 4], [5, 6]])
# Multi-region Overlap
assert_equal [["..", false], ["345", true], ["..", false]],
fzf.format('0123456789', 7, [[4, 5], [3, 6]])
end
def test_fuzzy_matcher
matcher = FZF::FuzzyMatcher.new Regexp::IGNORECASE
list = %w[
juice
juiceful
juiceless
juicily
juiciness
juicy]
assert matcher.caches.empty?
assert_equal(
[["juice", [[0, 1]]],
["juiceful", [[0, 1]]],
["juiceless", [[0, 1]]],
["juicily", [[0, 1]]],
["juiciness", [[0, 1]]],
["juicy", [[0, 1]]]], matcher.match(list, 'j', '', '').sort)
assert !matcher.caches.empty?
assert_equal [list.object_id], matcher.caches.keys
assert_equal 1, matcher.caches[list.object_id].length
assert_equal 6, matcher.caches[list.object_id]['j'].length
assert_equal(
[["juicily", [[0, 5]]],
["juiciness", [[0, 5]]]], matcher.match(list, 'jii', '', '').sort)
assert_equal(
[["juicily", [[2, 5]]],
["juiciness", [[2, 5]]]], matcher.match(list, 'ii', '', '').sort)
assert_equal 3, matcher.caches[list.object_id].length
assert_equal 2, matcher.caches[list.object_id]['ii'].length
# TODO : partial_cache
end
def test_fuzzy_matcher_rxflag
assert_equal nil, FZF::FuzzyMatcher.new(nil).rxflag
assert_equal 0, FZF::FuzzyMatcher.new(0).rxflag
assert_equal 1, FZF::FuzzyMatcher.new(1).rxflag
assert_equal 1, FZF::FuzzyMatcher.new(nil).rxflag_for('abc')
assert_equal 0, FZF::FuzzyMatcher.new(nil).rxflag_for('Abc')
assert_equal 0, FZF::FuzzyMatcher.new(0).rxflag_for('abc')
assert_equal 0, FZF::FuzzyMatcher.new(0).rxflag_for('Abc')
assert_equal 1, FZF::FuzzyMatcher.new(1).rxflag_for('abc')
assert_equal 1, FZF::FuzzyMatcher.new(1).rxflag_for('Abc')
end
def test_fuzzy_matcher_case_sensitive
# Smart-case match (Uppercase found)
assert_equal [['Fruit', [[0, 5]]]],
FZF::FuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], 'Fruit', '', '').sort
# Smart-case match (Uppercase not-found)
assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
FZF::FuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], 'fruit', '', '').sort
# Case-sensitive match (-i)
assert_equal [['Fruit', [[0, 5]]]],
FZF::FuzzyMatcher.new(0).match(%w[Fruit Grapefruit], 'Fruit', '', '').sort
# Case-insensitive match (+i)
assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
FZF::FuzzyMatcher.new(Regexp::IGNORECASE).
match(%w[Fruit Grapefruit], 'Fruit', '', '').sort
end
def test_extended_fuzzy_matcher_case_sensitive
%w['Fruit Fruit$].each do |q|
# Smart-case match (Uppercase found)
assert_equal [['Fruit', [[0, 5]]]],
FZF::ExtendedFuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], q, '', '').sort
# Smart-case match (Uppercase not-found)
assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
FZF::ExtendedFuzzyMatcher.new(nil).match(%w[Fruit Grapefruit], q.downcase, '', '').sort
# Case-sensitive match (-i)
assert_equal [['Fruit', [[0, 5]]]],
FZF::ExtendedFuzzyMatcher.new(0).match(%w[Fruit Grapefruit], q, '', '').sort
# Case-insensitive match (+i)
assert_equal [["Fruit", [[0, 5]]], ["Grapefruit", [[5, 10]]]],
FZF::ExtendedFuzzyMatcher.new(Regexp::IGNORECASE).
match(%w[Fruit Grapefruit], q, '', '').sort
end
end
def test_extended_fuzzy_matcher
matcher = FZF::ExtendedFuzzyMatcher.new Regexp::IGNORECASE
list = %w[
juice
juiceful
juiceless
juicily
juiciness
juicy
_juice]
match = proc { |q, prefix|
matcher.match(list, q, prefix, '').sort.map { |p| [p.first, p.last.sort] }
}
assert matcher.caches.empty?
3.times do
['y j', 'j y'].each do |pat|
(0..pat.length - 1).each do |prefix_length|
prefix = pat[0, prefix_length]
assert_equal(
[["juicily", [[0, 1], [6, 7]]],
["juicy", [[0, 1], [4, 5]]]],
match.call(pat, prefix))
end
end
# $
assert_equal [["juiceful", [[7, 8]]]], match.call('l$', '')
assert_equal [["juiceful", [[7, 8]]],
["juiceless", [[5, 6]]],
["juicily", [[5, 6]]]], match.call('l', '')
# ^
assert_equal list.length, match.call('j', '').length
assert_equal list.length - 1, match.call('^j', '').length
# ^ + $
assert_equal 0, match.call('^juici$', '').length
assert_equal 1, match.call('^juice$', '').length
assert_equal 0, match.call('^.*$', '').length
# !
assert_equal 0, match.call('!j', '').length
# ! + ^
assert_equal [["_juice", []]], match.call('!^j', '')
# ! + $
assert_equal list.length - 1, match.call('!l$', '').length
# ! + f
assert_equal [["juicy", [[4, 5]]]], match.call('y !l', '')
# '
assert_equal %w[juiceful juiceless juicily],
match.call('il', '').map { |e| e.first }
assert_equal %w[juicily],
match.call("'il", '').map { |e| e.first }
assert_equal (list - %w[juicily]).sort,
match.call("!'il", '').map { |e| e.first }.sort
end
assert !matcher.caches.empty?
end
def test_xfuzzy_matcher_prefix_cache
matcher = FZF::ExtendedFuzzyMatcher.new Regexp::IGNORECASE
list = %w[
a.java
b.java
java.jive
c.java$
d.java
]
2.times do
assert_equal 5, matcher.match(list, 'java', 'java', '').length
assert_equal 3, matcher.match(list, 'java$', 'java$', '').length
assert_equal 1, matcher.match(list, 'java$$', 'java$$', '').length
assert_equal 0, matcher.match(list, '!java', '!java', '').length
assert_equal 4, matcher.match(list, '!^jav', '!^jav', '').length
assert_equal 4, matcher.match(list, '!^java', '!^java', '').length
assert_equal 2, matcher.match(list, '!^java !b !c', '!^java', '').length
end
end
def test_sort_by_rank
matcher = FZF::FuzzyMatcher.new Regexp::IGNORECASE
xmatcher = FZF::ExtendedFuzzyMatcher.new Regexp::IGNORECASE
list = %w[
0____1
0_____1
01
____0_1
01_
_01_
0______1
___01___
]
assert_equal(
[["01", [[0, 2]]],
["01_", [[0, 2]]],
["_01_", [[1, 3]]],
["___01___", [[3, 5]]],
["____0_1", [[4, 7]]],
["0____1", [[0, 6]]],
["0_____1", [[0, 7]]],
["0______1", [[0, 8]]]],
FZF.new([]).sort_by_rank(matcher.match(list, '01', '', '')))
assert_equal(
[["01", [[0, 1], [1, 2]]],
["01_", [[0, 1], [1, 2]]],
["_01_", [[1, 2], [2, 3]]],
["0____1", [[0, 1], [5, 6]]],
["0_____1", [[0, 1], [6, 7]]],
["____0_1", [[4, 5], [6, 7]]],
["0______1", [[0, 1], [7, 8]]],
["___01___", [[3, 4], [4, 5]]]],
FZF.new([]).sort_by_rank(xmatcher.match(list, '0 1', '', '')))
assert_equal(
[["_01_", [[1, 3], [0, 4]]],
["0____1", [[0, 6], [1, 3]]],
["0_____1", [[0, 7], [1, 3]]],
["0______1", [[0, 8], [1, 3]]],
["___01___", [[3, 5], [0, 2]]],
["____0_1", [[4, 7], [0, 2]]]],
FZF.new([]).sort_by_rank(xmatcher.match(list, '01 __', '', '')))
end
if RUBY_PLATFORM =~ /darwin/
NFD = '한글'
def test_nfc
assert_equal 6, NFD.length
assert_equal ["한글", [[0, 1], [1, 2]]],
FZF::UConv.nfc(NFD, [[0, 3], [3, 6]])
nfd2 = 'before' + NFD + 'after'
assert_equal 6 + 6 + 5, nfd2.length
nfc, offsets = FZF::UConv.nfc(nfd2, [[4, 14], [9, 13]])
o1, o2 = offsets
assert_equal 'before한글after', nfc
assert_equal 're한글af', nfc[(o1.first...o1.last)]
assert_equal '글a', nfc[(o2.first...o2.last)]
end
def test_nfd
nfc = '한글'
nfd = FZF::UConv.nfd(nfc)
assert_equal 2, nfd.length
assert_equal 6, nfd.join.length
assert_equal NFD, nfd.join
end
def test_nfd_fuzzy_matcher
matcher = FZF::FuzzyMatcher.new 0
assert_equal [], matcher.match([NFD + NFD], '할', '', '')
match = matcher.match([NFD + NFD], '글글', '', '')
assert_equal [[NFD + NFD, [[3, 12]]]], match
assert_equal ['한글한글', [[1, 4]]], FZF::UConv.nfc(*match.first)
end
def test_nfd_extended_fuzzy_matcher
matcher = FZF::ExtendedFuzzyMatcher.new 0
assert_equal [], matcher.match([NFD], "'글글", '', '')
match = matcher.match([NFD], "'한글", '', '')
assert_equal [[NFD, [[0, 6]]]], match
assert_equal ['한글', [[0, 2]]], FZF::UConv.nfc(*match.first)
end
end
def test_split
assert_equal ["a", "b", "c", "\xFF", "d", "e", "f"],
FZF::UConv.split("abc\xFFdef")
end
# ^$ -> matches empty item
def test_format_empty_item
fzf = FZF.new []
item = ['', [[0, 0]]]
line, offsets = fzf.convert_item item
tokens = fzf.format line, 80, offsets
assert_equal [], tokens
end
end