Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve error reporting and Windows support. #35

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
64 changes: 50 additions & 14 deletions autoload/pymatcher.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,43 @@
import vim, re
import re
import vim
import heapq

_escape = dict((c , "\\" + c) for c in ['^','$','.','{','}','(',')','[',']','\\','/','+'])
_escape = dict((c, "\\" + c) for c in [
'^', '$', '.', '{', '}', '(', ')', '[', ']', '\\', '/', '+'])


def CtrlPPyMatch():
items = vim.eval('a:items')
try:
_doCtrlPPyMatch()
except Exception as ex:
import traceback
tb = traceback.format_exc()
vim.command(
'let s:rez = ["Unknown error in matcher", "%s", "%s"]' %
(str(ex), tb))


def _doCtrlPPyMatch():
try:
items = vim.eval('a:items')
except UnicodeDecodeError:
_troubleshootUnicodeInputError()
return

astr = vim.eval('a:str')
lowAstr = astr.lower()
limit = int(vim.eval('a:limit'))
mmode = vim.eval('a:mmode')
aregex = int(vim.eval('a:regex'))
spath = vim.eval('a:ispath')
ispath = vim.eval('a:ispath')
crfile = vim.eval('a:crfile')

if not vim.eval('exists("g:ctrlp_match_current_file")') and ispath and crfile:
if (not vim.eval('exists("g:ctrlp_match_current_file")') and
ispath and crfile):
items.remove(crfile)

rez = vim.eval('s:rez')

sep = vim.eval('s:slashsep')

regex = ''
if aregex == 1:
Expand All @@ -30,11 +50,13 @@ def CtrlPPyMatch():
# expression to each character (except the last).
if len(lowAstr) > 1:
mismatch = ["[^" + c + "]*" for c in escaped[:-1]]
regex = ''.join([c for pair in zip(escaped[:-1], mismatch) for c in pair])
regex = ''.join([c for pair in zip(escaped[:-1], mismatch)
for c in pair])

# Append the last character in the string to the regex
regex += escaped[-1]
# because this IGNORECASE flag is extremely expensive we are converting everything to lower case
# because this IGNORECASE flag is extremely expensive we are converting
# everything to lower case
# see https://github.com/FelikZ/ctrlp-py-matcher/issues/29
regex = regex.lower()

Expand All @@ -43,7 +65,7 @@ def CtrlPPyMatch():

def filename_score(line):
# get filename via reverse find to improve performance
slashPos = line.rfind('/')
slashPos = line.rfind(sep)

if slashPos != -1:
line = line[slashPos + 1:]
Expand All @@ -52,8 +74,8 @@ def filename_score(line):
result = prog.search(lineLower)
if result:
score = result.end() - result.start() + 1
score = score + ( len(lineLower) + 1 ) / 100.0
score = score + ( len(line) + 1 ) / 1000.0
score = score + (len(lineLower) + 1) / 100.0
score = score + (len(line) + 1) / 1000.0
return 1000.0 / score

return 0
Expand All @@ -63,7 +85,7 @@ def path_score(line):
result = prog.search(lineLower)
if result:
score = result.end() - result.start() + 1
score = score + ( len(lineLower) + 1 ) / 100.0
score = score + (len(lineLower) + 1) / 100.0
return 1000.0 / score

return 0
Expand All @@ -80,11 +102,25 @@ def path_score(line):
else:
res = [(path_score(line), line) for line in items]

rez.extend([line for score, line in heapq.nlargest(limit, res) if score != 0])
rez.extend([line for score, line in heapq.nlargest(limit, res)
if score != 0])

# Use double quoted vim strings and escape \
vimrez = ['"' + line.replace('\\', '\\\\').replace('"', '\\"') + '"' for line in rez]
vimrez = ['"' + line.replace('\\', '\\\\').replace('"', '\\"') + '"'
for line in rez]

vim.command("let s:regex = '%s'" % regex)
vim.command('let s:rez = [%s]' % ','.join(vimrez))


def _troubleshootUnicodeInputError():
count = vim.eval('len(a:items)')
for i in range(int(count)):
try:
vim.eval('a:items[%d]' % i)
except:
vim.command(
'let s:rez = ["Unicode error at item %d: ".a:items[%d],'
'"Line contains invalid characters."]' %
(i, i))
break
46 changes: 28 additions & 18 deletions autoload/pymatcher.vim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
" Python Matcher

if !has('python') && !has('python3')
echo 'In order to use pymatcher plugin, you need +python or +python3 compiled vim'
echo 'In order to use pymatcher plugin, you need +python or +python3 compiled vim'
endif

let s:plugin_path = escape(expand('<sfile>:p:h'), '\')
Expand All @@ -12,32 +12,42 @@ else
execute 'pyfile ' . s:plugin_path . '/pymatcher.py'
endif

function! pymatcher#PyMatch(items, str, limit, mmode, ispath, crfile, regex)
let s:slashsep = '/'
if has('win32') || has('win64')
if !has('+shellslash') || !&shellslash
let s:slashsep = '\'
endif
endif

call clearmatches()
function! pymatcher#PyMatch(items, str, limit, mmode, ispath, crfile, regex)
call clearmatches()

if a:str == ''
let arr = a:items[0:a:limit]
if !exists('g:ctrlp_match_current_file') && a:ispath && !empty(a:crfile)
call remove(arr, index(arr, a:crfile))
endif
return arr
if a:str == ''
let arr = a:items[0:a:limit]
if !exists('g:ctrlp_match_current_file') && a:ispath && !empty(a:crfile)
call remove(arr, index(arr, a:crfile))
endif
return arr
endif

let s:rez = []
let s:regex = ''
let s:rez = []
let s:regex = ''

try
execute 'python' . (has('python3') ? '3' : '') . ' CtrlPPyMatch()'
catch
return ['Error running matcher', str(v:exception)]
endtry

let s:matchregex = '\v\c'
let s:matchregex = '\v\c'

if a:mmode == 'filename-only'
let s:matchregex .= '[\^\/]*'
endif
if a:mmode == 'filename-only'
let s:matchregex .= '[\^\/\\]*'
endif

let s:matchregex .= s:regex
let s:matchregex .= s:regex

call matchadd('CtrlPMatch', s:matchregex)
call matchadd('CtrlPMatch', s:matchregex)

return s:rez
return s:rez
endfunction