From 27a7cac20253d96af5e3801055d417a1ad473fa8 Mon Sep 17 00:00:00 2001 From: Ludovic Chabant Date: Fri, 17 Feb 2017 17:18:34 -0800 Subject: [PATCH 1/2] Improve error reporting and Windows support. --- autoload/pymatcher.py | 36 ++++++++++++++++++++++++++++++--- autoload/pymatcher.vim | 46 +++++++++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/autoload/pymatcher.py b/autoload/pymatcher.py index 57a2e3c..d3608b1 100644 --- a/autoload/pymatcher.py +++ b/autoload/pymatcher.py @@ -1,10 +1,27 @@ +import os import vim, re import heapq _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')) @@ -17,7 +34,7 @@ def CtrlPPyMatch(): items.remove(crfile) rez = vim.eval('s:rez') - + sep = vim.eval('s:slashsep') regex = '' if aregex == 1: @@ -43,7 +60,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:] @@ -88,3 +105,16 @@ def path_score(line): 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: + val = 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 + diff --git a/autoload/pymatcher.vim b/autoload/pymatcher.vim index fc5f0ec..8eb68c3 100644 --- a/autoload/pymatcher.vim +++ b/autoload/pymatcher.vim @@ -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(':p:h'), '\') @@ -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 From 2f6947480203b734b069e5d9f69ba440db6b4698 Mon Sep 17 00:00:00 2001 From: Ludovic Chabant Date: Wed, 21 Jun 2017 10:56:39 -0700 Subject: [PATCH 2/2] pep8 compliance, and fix a typo. --- autoload/pymatcher.py | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/autoload/pymatcher.py b/autoload/pymatcher.py index d3608b1..4b1e08c 100644 --- a/autoload/pymatcher.py +++ b/autoload/pymatcher.py @@ -1,8 +1,10 @@ -import os -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(): try: @@ -27,10 +29,11 @@ def _doCtrlPPyMatch(): 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') @@ -47,11 +50,13 @@ def _doCtrlPPyMatch(): # 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() @@ -69,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 @@ -80,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 @@ -97,10 +102,12 @@ 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)) @@ -110,11 +117,10 @@ def _troubleshootUnicodeInputError(): count = vim.eval('len(a:items)') for i in range(int(count)): try: - val = vim.eval('a:items[%d]' % i) + 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 -