summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hawthorn <john.hawthorn@gmail.com>2014-07-26 02:27:31 -0700
committerJohn Hawthorn <john.hawthorn@gmail.com>2014-07-26 20:01:04 -0700
commit5edec9a231541eaf06a7f87a92610b078a09dab9 (patch)
tree2e3203c26b7862e43a2dc7f0d4f72f32de921ae3
parent222b9882bcd5f704031424fdd21d260ce6f1a023 (diff)
Highlight matched characters
-rw-r--r--fzy.c26
-rw-r--r--match.c37
2 files changed, 57 insertions, 6 deletions
diff --git a/fzy.c b/fzy.c
index e3b5a28..ac3d938 100644
--- a/fzy.c
+++ b/fzy.c
@@ -10,6 +10,7 @@
/* from match.c */
double match(const char *needle, const char *haystack);
+double match_positions(const char *needle, const char *haystack, size_t *positions);
#define INITIAL_CAPACITY 1
int choices_capacity = 0;
@@ -136,6 +137,27 @@ void clear(){
fprintf(ttyout, "%c%c0G", 0x1b, '[');
}
+void draw_match(const char *choice, int selected){
+ int n = strlen(search);
+ size_t positions[n + 1];
+ for(int i = 0; i < n + 1; i++)
+ positions[i] = -1;
+
+ match_positions(search, choice, &positions[0]);
+
+ for(size_t i = 0, p = 0; choice[i] != '\0'; i++){
+ if(positions[p] == i){
+ fprintf(ttyout, "%c%c33m", 0x1b, '[');
+ p++;
+ }else{
+ fprintf(ttyout, "%c%c39;49m", 0x1b, '[');
+ }
+ fprintf(ttyout, "%c", choice[i]);
+ }
+ fprintf(ttyout, "\n");
+ fprintf(ttyout, "%c%c0m", 0x1b, '[');
+}
+
void draw(){
int line = 0;
const char *prompt = "> ";
@@ -144,9 +166,7 @@ void draw(){
for(size_t i = 0; line < 10 && i < choices_available; i++){
if(i == current_selection)
fprintf(ttyout, "%c%c7m", 0x1b, '[');
- else
- fprintf(ttyout, "%c%c0m", 0x1b, '[');
- fprintf(ttyout, "%s\n", choices[choices_sorted[i]]);
+ draw_match(choices[choices_sorted[i]], i == current_selection);
line++;
}
fprintf(ttyout, "%c%c%iA", 0x1b, '[', line + 1);
diff --git a/match.c b/match.c
index 7a6166e..3bf0e89 100644
--- a/match.c
+++ b/match.c
@@ -30,7 +30,7 @@ void mat_print(int *mat, int n, int m){
#define max(a, b) (((a) > (b)) ? (a) : (b))
typedef int score_t;
-double calculate_score(const char *needle, const char *haystack){
+double calculate_score(const char *needle, const char *haystack, size_t *positions){
if(!*haystack || !*needle)
return SCORE_MIN;
@@ -85,17 +85,48 @@ double calculate_score(const char *needle, const char *haystack){
}
}
+ /* backtrace to find the positions of optimal matching */
+ if(positions){
+ for(int i = n-1, j = m-1; i >= 0; i--){
+ int last = M[i][j];
+ for(; j >= 0 && M[i][j] == last; j--){
+ /*
+ * There may be multiple paths which result in
+ * the optimal weight.
+ *
+ * Since we don't exit the loop on the first
+ * match, positions[i] may be assigned to
+ * multiple times. Since we are decrementing i
+ * and j, this favours the optimal path
+ * occurring earlier in the string.
+ */
+ if(tolower(needle[i]) == tolower(haystack[j])){
+ positions[i] = j;
+ }
+ }
+ }
+ }
+
return (float)(M[n-1][m-1]) / (float)(n * 2 + 1);
}
-double match(const char *needle, const char *haystack){
+double match_positions(const char *needle, const char *haystack, size_t *positions){
if(!*needle){
return 1.0;
}else if(!is_subset(needle, haystack)){
return SCORE_MIN;
}else if(!strcasecmp(needle, haystack)){
+ if(positions){
+ int n = strlen(needle);
+ for(int i = 0; i < n; i++)
+ positions[i] = i;
+ }
return 1.0;
}else{
- return calculate_score(needle, haystack);
+ return calculate_score(needle, haystack, positions);
}
}
+
+double match(const char *needle, const char *haystack){
+ return match_positions(needle, haystack, NULL);
+}