fzy

terminal fuzzy finder picker

git clone https://9o.is/git/fzy.git

commit a0267abc51586b531ab37a7951c211d43c0c4044
parent 321f016ee9f387fa91709f7f1ceba4e667d018ec
Author: John Hawthorn <john.hawthorn@gmail.com>
Date:   Sat, 12 Jul 2014 15:07:22 -0700

Add tests and split matching into match.c

Diffstat:
M.gitignore | 1+
MMakefile | 17+++++++++++------
Mfzy.c | 11++---------
Amatch.c | 12++++++++++++
Atest.rb | 41+++++++++++++++++++++++++++++++++++++++++
Atestscore.c | 20++++++++++++++++++++
6 files changed, 87 insertions(+), 15 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,2 +1,3 @@ fzy +testscore *.o diff --git a/Makefile b/Makefile @@ -1,10 +1,15 @@ -LIBS= CFLAGS+=-Wall -Wextra -g -TARGET=fzy -OBJECTS=fzy.o -$(TARGET): $(OBJECTS) - $(CC) $(CCFLAGS) -o $@ $^ $(LIBS) +all: fzy testscore + +testscore: testscore.o match.o + $(CC) $(CCFLAGS) -o $@ $^ + +test: testscore + ruby test.rb + +fzy: fzy.o match.o + $(CC) $(CCFLAGS) -o $@ $^ clean: - $(RM) $(TARGET) *.o + $(RM) fzy testscore *.o diff --git a/fzy.c b/fzy.c @@ -7,15 +7,8 @@ #include <fcntl.h> #include <ctype.h> -double match(const char *needle, const char *haystack){ - while(*needle){ - if(!*haystack) - return 0.0; - while(tolower(*needle) == tolower(*haystack++)) - needle++; - } - return 1.0; -} +/* from match.c */ +double match(const char *needle, const char *haystack); #define INITIAL_CAPACITY 1 int choices_capacity = 0; diff --git a/match.c b/match.c @@ -0,0 +1,12 @@ +#include <ctype.h> + +double match(const char *needle, const char *haystack){ + while(*needle){ + if(!*haystack) + return 0.0; + while(*haystack && tolower(*needle) == tolower(*haystack++)){ + needle++; + } + } + return 1.0; +} diff --git a/test.rb b/test.rb @@ -0,0 +1,41 @@ +require "minitest/autorun" + +# Largely borrowed from selecta +describe "score" do + def score(candidate, query) + # FIXME: should escape this properly + `./testscore '#{query}' '#{candidate}'`.to_f + end + + it "scores 1 when the query is empty" do + assert_equal 1, score("a", "") + end + + it "scores 0 when the choice is empty" do + assert_equal 0, score("", "a") + end + + it "scores 1 when exact match" do + assert_equal 1, score("a", "a") + end + + it "scores 0 when the query is longer than the choice" do + assert_equal 0, score("short", "longer") + end + + it "scores 0 when the query doesn't match at all" do + assert_equal 0, score("a", "b") + end + + it "scores 0 when only a prefix of the query matches" do + assert_equal 0, score("ab", "ac") + end + + it "scores greater than 0 when it matches" do + assert_operator 0, :<, score("a", "a") + assert_operator 0, :<, score("ab", "a") + assert_operator 0, :<, score("ba", "a") + assert_operator 0, :<, score("bab", "a") + assert_operator 0, :<, score("babababab", "aaaa") + end +end diff --git a/testscore.c b/testscore.c @@ -0,0 +1,20 @@ +#include <stdlib.h> +#include <stdio.h> + +/* from match.c */ +double match(const char *needle, const char *haystack); + +void usage(const char *argv0){ + fprintf(stderr, "USAGE: %s QUERY CANDIDATE\n", argv0); +} + +int main(int argc, char *argv[]){ + if(argc != 3){ + usage(argv[0]); + } + + double result = match(argv[1], argv[2]); + printf("%f\n", result); + + return 0; +}