Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 45 additions & 56 deletions autoload/fuzzycomt.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,26 @@
#include "fuzzycomt.h"

// Forward declaration for ctrlp_get_line_matches
matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, char *mmode);
matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, mmode_t mmode);

mmode_t getMMode(char *mmode) {
mmode_t result = fullLine;
if (mmode[0] == 'f') {
if (mmode[1] == 'i') {
if (mmode[2] == 'l') {
result = filenameOnly;
} else {
result = firstNonTab;
}
} else {
result = fullLine;
}
} else {
result = untilLastTab;
}

return result;
}

void ctrlp_get_line_matches(PyObject* paths,
PyObject* abbrev,
Expand All @@ -35,12 +54,13 @@ void ctrlp_get_line_matches(PyObject* paths,
{
int i;
int max;

mmode_t mmodeEnum = getMMode(mmode);

// iterate over lines and get match score for every line
for (i = 0, max = PyList_Size(paths); i < max; i++) {
PyObject* path = PyList_GetItem(paths, i);
matchobj_t match;
match = ctrlp_find_match(path, abbrev, mmode);
matches[i] = match;
matches[i] = ctrlp_find_match(path, abbrev, mmodeEnum);
}
}

Expand All @@ -53,29 +73,18 @@ char *strduplicate(const char *s) {
}

char *slashsplit(char *line) {
char *pch, *linedup;
char *fname = "";

// we need to create a copy of input string because strtok() changes string
// while splitting. Need to call free() when linedup is not needed.
linedup = strduplicate(line);

pch = strtok(linedup, "/");

while (pch != NULL)
{
fname = pch;
pch = strtok(NULL, "/");
char *fname = line;
char *scan = fname;
while (scan != '\0')
Copy link

@ptzz ptzz Dec 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crashes for me. I think it should be while (*scan != '\0').

{
if (*scan == '/' || *scan == '\\') {
fname = ++scan;
} else {
++scan;
}
}

// We need to get a copy of a filename because fname is a pointer to the
// start of filename in linedup string which will be free'd. We need to
// call free() when return value of func will not be needed.
char *retval = strduplicate(fname);

free(linedup);

return retval;
return fname;
}

// comparison function for use with qsort
Expand Down Expand Up @@ -123,7 +132,8 @@ double ctrlp_recursive_match(matchinfo_t *m, // sharable meta-data
long haystack_idx, // where in the path string to start
long needle_idx, // where in the needle string to start
long last_idx, // location of last matched character
double score) // cumulative score so far
double score, // cumulative score so far
mmode_t mmode)
{
double seen_score = 0; // remember best score seen via recursion
long i, j, distance;
Expand Down Expand Up @@ -153,7 +163,9 @@ double ctrlp_recursive_match(matchinfo_t *m, // sharable meta-data
j++, haystack_idx++) {

char d = m->haystack_p[j];
if (d == '.') {
if (d == '\t' && mmode == firstNonTab) {
break;
} else if (d == '.') {
if (j == 0 || m->haystack_p[j - 1] == '/') {
m->dot_file = 1; // this is a dot-file
}
Expand Down Expand Up @@ -194,7 +206,7 @@ double ctrlp_recursive_match(matchinfo_t *m, // sharable meta-data
if (++j < m->haystack_len) {
// bump cursor one char to the right and
// use recursion to try and find a better match
double sub_score = ctrlp_recursive_match(m, j, i, last_idx, score);
double sub_score = ctrlp_recursive_match(m, j, i, last_idx, score, mmode);
if (sub_score > seen_score)
seen_score = sub_score;
}
Expand Down Expand Up @@ -350,34 +362,20 @@ PyObject* ctrlp_fuzzycomt_sorted_match_list(PyObject* self, PyObject* args) {
}


matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, char *mmode)
matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, mmode_t mmode)
{
long i, max;
double score;
matchobj_t returnobj;

// Make a copy of input string to replace all backslashes.
// We need to create a copy because PyString_AsString returns
// string that must not be changed.
// We will free() it later
char *temp_string;
temp_string = strduplicate(PyString_AsString(str));

// Replace all backslashes
for (i = 0; i < strlen(temp_string); i++) {
if (temp_string[i] == '\\') {
temp_string[i] = '/';
}
}

matchinfo_t m;
if (strcmp(mmode, "filename-only") == 0) {
if (mmode == filenameOnly) {
// get file name by splitting string on slashes
m.haystack_p = slashsplit(temp_string);
m.haystack_p = slashsplit(PyString_AsString(str));
m.haystack_len = strlen(m.haystack_p);
}
else {
m.haystack_p = temp_string;
m.haystack_p = PyString_AsString(str);
m.haystack_len = PyString_Size(str);
}
m.needle_p = PyString_AsString(abbrev);
Expand Down Expand Up @@ -407,18 +405,9 @@ matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, char *mmode)
memo[i] = DBL_MAX;
m.memo = memo;

score = ctrlp_recursive_match(&m, 0, 0, 0, 0.0);
score = ctrlp_recursive_match(&m, 0, 0, 0, 0.0, mmode);
}

// need to free memory because strdump() function in slashsplit() uses
// malloc to allocate memory, otherwise memory will leak
if (strcmp(mmode, "filename-only") == 0) {
free(m.haystack_p);
}

// Free memory after strdup()
free(temp_string);

returnobj.str = str;
returnobj.score = score;

Expand Down
11 changes: 10 additions & 1 deletion autoload/fuzzycomt.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@
#include <string.h>
#include <assert.h>



typedef enum mmode {
fullLine,
filenameOnly,
firstNonTab,
untilLastTab
} mmode_t;

typedef struct {
PyObject *str; // Python object with file path
double score; // score of string
Expand All @@ -43,7 +52,7 @@ typedef struct {
double *memo; // memoization
} matchinfo_t;

matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, char *mmode);
matchobj_t ctrlp_find_match(PyObject* str, PyObject* abbrev, mmode_t mmode);

void ctrlp_get_line_matches(PyObject* paths, PyObject* abbrev, matchobj_t matches[], char *mode);

Expand Down
34 changes: 18 additions & 16 deletions autoload/matcher.vim
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ else
endif

let s:script_folder_path = escape( expand( '<sfile>:p:h' ), '\' )
" -----
" PYTHON UNINDETED CODE BEGIN
" -----
python << ImportEOF
import sys, os, vim
sys.path.insert( 0, os.path.abspath( vim.eval('s:script_folder_path' ) ) )
import fuzzycomt
sys.path.pop(0)
ImportEOF
" -----
" PYTHON UNINDETED CODE END
" -----

fu! s:matchtabs(item, pat)
return match(split(a:item, '\t\+')[0], a:pat)
Expand All @@ -40,6 +46,9 @@ fu! s:matchfname(item, pat)
endf

fu! s:cmatcher(lines, input, limit, mmode, ispath, crfile)
" -----
" PYTHON UNINDETED CODE BEGIN
" -----
python << EOF
lines = vim.eval('a:lines')
searchinp = vim.eval('a:input')
Expand All @@ -60,7 +69,10 @@ try:
except:
matchlist = []
EOF
return s:pyeval("matchlist")
" -----
" PYTHON UNINDETED CODE END
" -----
return s:pyeval("matchlist")
endf

fu! s:escapechars(chars)
Expand Down Expand Up @@ -102,6 +114,11 @@ fu! s:highlight(input, mmode, regex)
let beginning = beginning.'\([^\/]*$\)\@='
end

if a:mmode == "first-non-tab"
" Make sure we stop at the tab
let ending = ending.'\t'
end

for i in range(len(a:input))
" Surround our current target letter with \zs and \ze so it only
" actually matches that one letter, but has all preceding and trailing
Expand Down Expand Up @@ -157,21 +174,6 @@ fu! matcher#cmatch(lines, input, limit, mmode, ispath, crfile, regex)
cal s:highlight(a:input, a:mmode, a:regex)
return array
endif
" use built-in matcher if mmode set to match until first tab ( in other case
" tag.vim doesnt work
if a:mmode == "first-non-tab"
let array = []
" call ctrlp.vim function to get proper input pattern
let pat = ctrlp#call('s:SplitPattern', a:input)
for item in a:lines
if call('s:matchtabs', [item, pat]) >= 0
cal add(array, item)
en
endfo
"TODO add highlight
cal sort(array, ctrlp#call('s:mixedsort'))
return array
en

let matchlist = s:cmatcher(a:lines, a:input, a:limit, a:mmode, a:ispath, a:crfile)
en
Expand Down