From bb87bedd350ff3a418141499f5db4b9af4c02b75 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Tue, 6 Sep 2016 22:40:17 +0200 Subject: [PATCH 01/22] Add a start of a gq implementation that does not split strings halfway through --- indent/python.vim | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/indent/python.vim b/indent/python.vim index befc60a..5c39f1c 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -27,6 +27,7 @@ setlocal expandtab setlocal nolisp setlocal autoindent setlocal indentexpr=GetPythonPEPIndent(v:lnum) +setlocal formatexpr=GetPythonPEPFormat(v:lnum,v:count) setlocal indentkeys=!^F,o,O,<:>,0),0],0},=elif,=except setlocal tabstop=4 setlocal softtabstop=4 @@ -59,6 +60,8 @@ let s:stop_statement = '^\s*\(break\|continue\|raise\|return\|pass\)\>' let s:skip_special_chars = 'synIDattr(synID(line("."), col("."), 0), "name") ' . \ '=~? "\\vstring|comment|jedi\\S"' +let s:skip_string = 'synIDattr(synID(line("."), col("."), 0), "name") ' . + \ '=~? "String"' let s:skip_after_opening_paren = 'synIDattr(synID(line("."), col("."), 0), "name") ' . \ '=~? "\\vcomment|jedi\\S"' @@ -421,3 +424,123 @@ function! GetPythonPEPIndent(lnum) return s:indent_like_previous_line(a:lnum) endfunction + +function s:SearchPosWithSkip(pattern, flags, skip, stopline) + " + " Returns true if a match is found for {pattern}, but ignores matches + " where {skip} evaluates to false. This allows you to do nifty things + " like, say, only matching outside comments, only on odd-numbered lines, + " or whatever else you like. + " + " Mimics the built-in search() function, but adds a {skip} expression + " like that available in searchpair() and searchpairpos(). + " (See the Vim help on search() for details of the other parameters.) + " + " Note the current position, so that if there are no unskipped + " matches, the cursor can be restored to this location. + " + let l:flags = a:flags + let l:movepos = getpos('.') + let l:firstmatch = [] + let l:pos = [0, 0, 0, 0] + + " Loop as long as {pattern} continues to be found. + " + while search(a:pattern, l:flags, a:stopline) > 0 + if l:firstmatch == [] + let l:firstmatch = getpos('.') + let l:flags = substitute(l:flags, 'c', '', '') + elseif l:firstmatch == getpos('.') + break + endif + + " If {skip} is true, ignore this match and continue searching. + " + if eval(a:skip) + continue + endif + + " If we get here, {pattern} was found and {skip} is false, + " so this is a match we don't want to ignore. Update the + " match position and stop searching. + " + let l:pos = getpos('.') + let l:movepos = getpos('.') + break + + endwhile + + " Jump to the position of the unskipped match, or to the original + " position if there wasn't one. + " + + call setpos('.', l:movepos) + return [l:pos[1], l:pos[2]] + +endfunction + +function s:IsInComment(lnum, col) + echom synIDattr(synID(a:lnum, a:col, 1), 'name') + return synIDattr(synID(a:lnum, a:col, 1), 'name') =~? 'comment' +endfunction + +function! GetPythonPEPFormat(lnum, count) + let l:tw = &textwidth ? &textwidth : 79 + + let l:winview = winsaveview() + + let l:count = a:count + let l:first_char = indent(a:lnum) + 1 + + if mode() ==? 'i' " gq was not pressed, but tw was set + return 1 + endif + + " This gq is only meant to do code with strings, not comments. + if s:IsInComment(a:lnum, l:first_char) + return 1 + endif + + if len(getline(a:lnum)) <= l:tw && l:count == 1 " No need for gq + return 1 + endif + + " Put all the lines on one line and do normal splitting after that. + if l:count > 1 + while l:count > 1 + let l:count -= 1 + normal! J + endwhile + endif + + call cursor(a:lnum, l:tw + 1) + let l:orig_breakpoint = searchpos(' ', 'bcW', a:lnum) + call cursor(a:lnum, l:tw + 1) + call cursor(a:lnum, l:tw + 1) + let l:breakpoint = s:SearchPosWithSkip(' ', 'bcW', s:skip_string, a:lnum) + + echom 'normal' + echom l:orig_breakpoint[1] + echom 'new' + echom l:breakpoint[1] + " No need for special treatment, normal gq handles edgecases better + if l:breakpoint[1] == l:orig_breakpoint[1] + call winrestview(l:winview) + return 1 + endif + + " If the match is at the indent level try breaking after string as last + " resort + if l:breakpoint[1] <= indent(a:lnum) + call cursor(a:lnum, l:tw + 1) + let l:breakpoint = s:SearchPosWithSkip(' ', 'cW', s:skip_special_chars, a:lnum) + endif + + + if l:breakpoint[1] == 0 + call winrestview(l:winview) + else + call feedkeys("r\") + call feedkeys('gqq') + endif +endfunction From 630fdc7f855073dc56cb0b502a6182a2126b13d5 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Sun, 11 Sep 2016 20:29:57 +0200 Subject: [PATCH 02/22] Remove extra cursor call --- indent/python.vim | 1 - 1 file changed, 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 5c39f1c..c84b118 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -516,7 +516,6 @@ function! GetPythonPEPFormat(lnum, count) call cursor(a:lnum, l:tw + 1) let l:orig_breakpoint = searchpos(' ', 'bcW', a:lnum) call cursor(a:lnum, l:tw + 1) - call cursor(a:lnum, l:tw + 1) let l:breakpoint = s:SearchPosWithSkip(' ', 'bcW', s:skip_string, a:lnum) echom 'normal' From a9ff2d9e4cfe18b68c4eea600d8f6823c7b5388c Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Sun, 11 Sep 2016 20:31:42 +0200 Subject: [PATCH 03/22] Fallback to normal gq when no better solution is found --- indent/python.vim | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index c84b118..14ff2a4 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -536,10 +536,12 @@ function! GetPythonPEPFormat(lnum, count) endif + "" Fallback to old behaviour when nothing is found if l:breakpoint[1] == 0 call winrestview(l:winview) - else - call feedkeys("r\") - call feedkeys('gqq') + return 1 endif + + call feedkeys("r\") + call feedkeys('gqq') endfunction From 0f0eeb81926f2836db13b07a830a1ca65559aae2 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Sun, 11 Sep 2016 20:38:27 +0200 Subject: [PATCH 04/22] Fix trailing whitespace break --- indent/python.vim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 14ff2a4..d6e199f 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -532,7 +532,8 @@ function! GetPythonPEPFormat(lnum, count) " resort if l:breakpoint[1] <= indent(a:lnum) call cursor(a:lnum, l:tw + 1) - let l:breakpoint = s:SearchPosWithSkip(' ', 'cW', s:skip_special_chars, a:lnum) + "Search for a space that is not trailing whitespace + let l:breakpoint = s:SearchPosWithSkip(' [^ ]', 'cW', s:skip_string, a:lnum) endif From ed8ce61aa492e5cb8d2caa1b9cacf33737424be2 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Sun, 11 Sep 2016 20:41:40 +0200 Subject: [PATCH 05/22] Add normal mode to feedkeys --- indent/python.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index d6e199f..9243772 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -543,6 +543,6 @@ function! GetPythonPEPFormat(lnum, count) return 1 endif - call feedkeys("r\") - call feedkeys('gqq') + call feedkeys("r\", 'n') + call feedkeys('gqq', 'n') endfunction From 1259823059deb24d93499364ebe26a5c7bf1d5b8 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Sun, 11 Sep 2016 22:24:33 +0200 Subject: [PATCH 06/22] Remove echom calls --- indent/python.vim | 5 ----- 1 file changed, 5 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 9243772..6b7c70b 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -480,7 +480,6 @@ function s:SearchPosWithSkip(pattern, flags, skip, stopline) endfunction function s:IsInComment(lnum, col) - echom synIDattr(synID(a:lnum, a:col, 1), 'name') return synIDattr(synID(a:lnum, a:col, 1), 'name') =~? 'comment' endfunction @@ -518,10 +517,6 @@ function! GetPythonPEPFormat(lnum, count) call cursor(a:lnum, l:tw + 1) let l:breakpoint = s:SearchPosWithSkip(' ', 'bcW', s:skip_string, a:lnum) - echom 'normal' - echom l:orig_breakpoint[1] - echom 'new' - echom l:breakpoint[1] " No need for special treatment, normal gq handles edgecases better if l:breakpoint[1] == l:orig_breakpoint[1] call winrestview(l:winview) From ea4f96d75f20160e282a0243aa68e8621714788a Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Sun, 11 Sep 2016 22:25:13 +0200 Subject: [PATCH 07/22] Add check to see if space is inside brackets and add a "\" accordingly --- indent/python.vim | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 6b7c70b..13a388b 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -538,6 +538,21 @@ function! GetPythonPEPFormat(lnum, count) return 1 endif - call feedkeys("r\", 'n') + let l:winview = winsaveview() + + " Check if match is inside brackets + let l:bracket = searchpairpos('(', '', ')', 'bW', s:skip_string) + call winrestview(l:winview) + let l:curly = searchpairpos('{', '', '}', 'bW', s:skip_string) + call winrestview(l:winview) + let l:square = searchpairpos('\[', '', '\]', 'bW', s:skip_string) + call winrestview(l:winview) + + if l:bracket[0] == 0 && l:curly[0] == 0 && l:square[0] == 0 + call feedkeys("a\\\\", 'n') + else + call feedkeys("r\", 'n') + endif + call feedkeys('gqq', 'n') endfunction From 7b21d1087b45c744b5b844c31051d8769e5cacfc Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Tue, 20 Sep 2016 22:16:17 +0200 Subject: [PATCH 08/22] Add support for breaking inside strings --- indent/python.vim | 96 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 13a388b..076c2ff 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -514,45 +514,95 @@ function! GetPythonPEPFormat(lnum, count) call cursor(a:lnum, l:tw + 1) let l:orig_breakpoint = searchpos(' ', 'bcW', a:lnum) + let l:orig_breakpointview = winsaveview() + " If breaking inside string extra space is needed for the space and quote + call cursor(a:lnum, l:tw - 1) + let l:better_orig_breakpoint = searchpos(' ', 'bcW', a:lnum) + let l:better_orig_breakpointview = winsaveview() call cursor(a:lnum, l:tw + 1) let l:breakpoint = s:SearchPosWithSkip(' ', 'bcW', s:skip_string, a:lnum) + let l:breakpointview = winsaveview() - " No need for special treatment, normal gq handles edgecases better + " No need for special treatment, normal gq handles normal cases just fine if l:breakpoint[1] == l:orig_breakpoint[1] + \ || s:isMultilineString(l:orig_breakpointview) call winrestview(l:winview) return 1 endif " If the match is at the indent level try breaking after string as last " resort - if l:breakpoint[1] <= indent(a:lnum) - call cursor(a:lnum, l:tw + 1) - "Search for a space that is not trailing whitespace - let l:breakpoint = s:SearchPosWithSkip(' [^ ]', 'cW', s:skip_string, a:lnum) - endif + " if l:breakpoint[1] <= indent(a:lnum) + " call cursor(a:lnum, l:tw + 1) + " "Search for a space that is not trailing whitespace + " let l:breakpoint = s:SearchPosWithSkip(' [^ ]', 'cW', s:skip_string, a:lnum) + " endif "" Fallback to old behaviour when nothing is found - if l:breakpoint[1] == 0 - call winrestview(l:winview) - return 1 + " if l:breakpoint[1] == 0 + " call winrestview(l:winview) + " return 1 + " endif + " let l:breakpoint_brackets = s:isBetweenBrackets(l:breakpointview) + " let l:orig_breakpoint_brackets = s:isBetweenBrackets(l:orig_breakpointview) + + "echom s:isBetweenPair('(', ')', l:breakpointview, s:skip_string) + "echom s:isBetweenPair('{', '}', l:breakpointview, s:skip_string) + "echom s:isBetweenPair('\[', '\]', l:breakpointview, s:skip_string) + "echom s:isBetweenPair('(', ')', l:orig_breakpointview, s:skip_string) + "echom s:isBetweenPair('{', '}', l:orig_breakpointview, s:skip_string) + "echom s:isBetweenPair('\[', '\]', l:orig_breakpointview, s:skip_string) + "echom 'new' + "echom l:breakpoint[1] + "echom 'orig' + "echom l:orig_breakpoint[1] + + "Order of breaking: + " 1. Only break on breakpoints that have actually been found + " 2. Breaking inside brackets is preferred (no backslash needed) + " 3. Breking outside a string is preferred (new breakpoint) + " 4. Possible future: breaking at space is preferred + if l:breakpoint[0] != 0 && s:isBetweenBrackets(l:breakpointview) + "echom 'between brackets' + call winrestview(l:breakpointview) + call feedkeys("r\", 'n') + else + "echom 'zooooi' + if l:better_orig_breakpoint[0] != 0 + \ && s:isBetweenBrackets(l:better_orig_breakpointview) + "echom 'doing the quotes' + call winrestview(l:better_orig_breakpointview) + call feedkeys("a'\'\", 'n') + elseif l:breakpoint[0] != 0 + "echom 'not doing the quotes' + call winrestview(l:breakpointview) + call feedkeys("a\\\\", 'n') + else + "echom 'fallling back to old method' + call winrestview(l:winview) + return 1 + endif endif - let l:winview = winsaveview() + call feedkeys('gqq', 'n') +endfunction +function s:isBetweenBrackets(winview) " Check if match is inside brackets - let l:bracket = searchpairpos('(', '', ')', 'bW', s:skip_string) - call winrestview(l:winview) - let l:curly = searchpairpos('{', '', '}', 'bW', s:skip_string) - call winrestview(l:winview) - let l:square = searchpairpos('\[', '', '\]', 'bW', s:skip_string) - call winrestview(l:winview) - - if l:bracket[0] == 0 && l:curly[0] == 0 && l:square[0] == 0 - call feedkeys("a\\\\", 'n') - else - call feedkeys("r\", 'n') - endif + let l:skip = s:skip_string + return s:isBetweenPair('(', ')', a:winview, l:skip) + \ || s:isBetweenPair('{', '}', a:winview, l:skip) + \ || s:isBetweenPair('\[', '\]', a:winview, l:skip) +endfunction - call feedkeys('gqq', 'n') +function s:isMultilineString(winview) + return s:isBetweenPair("'''", "'''", a:winview, '') + \ || s:isBetweenPair('"""', '"""', a:winview, '') +endfunction + +function s:isBetweenPair(left, right, winview, skip) + call winrestview(a:winview) + let l:bracket = searchpairpos(a:left, '', a:right, 'bW', a:skip) + return l:bracket[0] != 0 endfunction From 0d22c60be34329cc585663f1bae17f2bea259096 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Tue, 20 Sep 2016 22:43:26 +0200 Subject: [PATCH 09/22] Use custom gq more often --- indent/python.vim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 076c2ff..27cbd4c 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -523,9 +523,8 @@ function! GetPythonPEPFormat(lnum, count) let l:breakpoint = s:SearchPosWithSkip(' ', 'bcW', s:skip_string, a:lnum) let l:breakpointview = winsaveview() - " No need for special treatment, normal gq handles normal cases just fine - if l:breakpoint[1] == l:orig_breakpoint[1] - \ || s:isMultilineString(l:orig_breakpointview) + " No need for special treatment, normal gq handles docstrings fine + if s:isMultilineString(l:orig_breakpointview) call winrestview(l:winview) return 1 endif From c8de03f5ad535b34c7b3adbfc2ab756a001916f3 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Tue, 20 Sep 2016 22:44:57 +0200 Subject: [PATCH 10/22] Fix breaking in string for double quote strings --- indent/python.vim | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 27cbd4c..5a5336d 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -570,9 +570,17 @@ function! GetPythonPEPFormat(lnum, count) "echom 'zooooi' if l:better_orig_breakpoint[0] != 0 \ && s:isBetweenBrackets(l:better_orig_breakpointview) - "echom 'doing the quotes' + " echom 'doing the quotes' call winrestview(l:better_orig_breakpointview) - call feedkeys("a'\'\", 'n') + let l:pos_start_string = + \ s:SearchPosWithSkip('.', 'bcW', s:skip_string, a:lnum) + call winrestview(l:better_orig_breakpointview) + " Use single or double quote corresponding with start of string + if getline(a:lnum)[l:pos_start_string[1]] ==# '"' + call feedkeys("a\"\\"\", 'n') + else + call feedkeys("a'\'\", 'n') + endif elseif l:breakpoint[0] != 0 "echom 'not doing the quotes' call winrestview(l:breakpointview) From d4b530f377ae323e64bc0fddabd21260723b8e06 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 22:12:29 +0200 Subject: [PATCH 11/22] Fix multiline string detection by using syntax plugin --- indent/python.vim | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 5a5336d..da4f4eb 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -480,9 +480,14 @@ function s:SearchPosWithSkip(pattern, flags, skip, stopline) endfunction function s:IsInComment(lnum, col) - return synIDattr(synID(a:lnum, a:col, 1), 'name') =~? 'comment' + return synIDattr(synID(a:lnum, a:col, 0), 'name') =~? 'comment' endfunction +function s:IsInMultilineString(lnum, col) + return synIDattr(synID(a:lnum, a:col, 0), 'name') =~? 'multiline' +endfunction + + function! GetPythonPEPFormat(lnum, count) let l:tw = &textwidth ? &textwidth : 79 @@ -495,11 +500,6 @@ function! GetPythonPEPFormat(lnum, count) return 1 endif - " This gq is only meant to do code with strings, not comments. - if s:IsInComment(a:lnum, l:first_char) - return 1 - endif - if len(getline(a:lnum)) <= l:tw && l:count == 1 " No need for gq return 1 endif @@ -524,7 +524,8 @@ function! GetPythonPEPFormat(lnum, count) let l:breakpointview = winsaveview() " No need for special treatment, normal gq handles docstrings fine - if s:isMultilineString(l:orig_breakpointview) + if s:IsInMultilineString(l:orig_breakpoint[0], l:orig_breakpoint[1]) + \|| s:IsInComment(l:orig_breakpoint[0], l:orig_breakpoint[1]) call winrestview(l:winview) return 1 endif @@ -603,11 +604,6 @@ function s:isBetweenBrackets(winview) \ || s:isBetweenPair('\[', '\]', a:winview, l:skip) endfunction -function s:isMultilineString(winview) - return s:isBetweenPair("'''", "'''", a:winview, '') - \ || s:isBetweenPair('"""', '"""', a:winview, '') -endfunction - function s:isBetweenPair(left, right, winview, skip) call winrestview(a:winview) let l:bracket = searchpairpos(a:left, '', a:right, 'bW', a:skip) From 4f6697d2865b81a9098bdd50889d58c92b8ba87f Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 22:43:00 +0200 Subject: [PATCH 12/22] Fix some annoying bugs --- indent/python.vim | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index da4f4eb..761d9bf 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -582,14 +582,21 @@ function! GetPythonPEPFormat(lnum, count) else call feedkeys("a'\'\", 'n') endif - elseif l:breakpoint[0] != 0 - "echom 'not doing the quotes' + elseif l:breakpoint[1] > indent(a:lnum) call winrestview(l:breakpointview) call feedkeys("a\\\\", 'n') else - "echom 'fallling back to old method' - call winrestview(l:winview) - return 1 + call cursor(a:lnum, l:tw + 1) + "Search for a space that is not trailing whitespace + let l:afterbreakpoint = s:SearchPosWithSkip(' [^ ]', 'cW', s:skip_string, a:lnum) + + if l:afterbreakpoint[0] != 0 + call feedkeys("r\", 'n') + else + "echom 'fallling back to old method' + call winrestview(l:winview) + return 1 + endif endif endif From 8801fc9d8df281a1cde83d083cbbb3e75b527a90 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 23:00:59 +0200 Subject: [PATCH 13/22] Fix quote choosing for special strings (r/u/b) --- indent/python.vim | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 761d9bf..9f91441 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -576,8 +576,18 @@ function! GetPythonPEPFormat(lnum, count) let l:pos_start_string = \ s:SearchPosWithSkip('.', 'bcW', s:skip_string, a:lnum) call winrestview(l:better_orig_breakpointview) - " Use single or double quote corresponding with start of string - if getline(a:lnum)[l:pos_start_string[1]] ==# '"' + " Find the type of start quote of the string + " and skip charactars at the start of the string like b/u/r + let l:extra_chars = 0 + let l:cur_char = getline(a:lnum)[l:pos_start_string[1]] + while l:cur_char !=# '"' && l:cur_char !=# "'" + let l:extra_chars += 1 + let l:cur_char = getline(a:lnum)[l:pos_start_string[1] + \ + l:extra_chars] + endwhile + + + if l:cur_char ==# '"' call feedkeys("a\"\\"\", 'n') else call feedkeys("a'\'\", 'n') From d77a6cc82988096a3d80aa74731918d606d0b5c2 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 23:11:57 +0200 Subject: [PATCH 14/22] Fix string exclusion to include byte strings --- indent/python.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 9f91441..034d1b4 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -61,7 +61,7 @@ let s:skip_special_chars = 'synIDattr(synID(line("."), col("."), 0), "name") ' . \ '=~? "\\vstring|comment|jedi\\S"' let s:skip_string = 'synIDattr(synID(line("."), col("."), 0), "name") ' . - \ '=~? "String"' + \ '=~? "\\vstring|bytes\\S"' let s:skip_after_opening_paren = 'synIDattr(synID(line("."), col("."), 0), "name") ' . \ '=~? "\\vcomment|jedi\\S"' From 99d3c50a1fca708d3c2211866db94eddc1818f8c Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 23:28:28 +0200 Subject: [PATCH 15/22] Add a bracket intsead of backslash + newline when it can help --- indent/python.vim | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 034d1b4..ab45be1 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -594,7 +594,18 @@ function! GetPythonPEPFormat(lnum, count) endif elseif l:breakpoint[1] > indent(a:lnum) call winrestview(l:breakpointview) - call feedkeys("a\\\\", 'n') + + let l:next_char = getline(a:lnum)[l:breakpoint[1]] + if l:next_char !=# '{' && l:next_char !=# '(' && l:next_char !=# '[' + \ && !s:isBetweenBrackets(l:breakpointview) + "Add a bracket when this is not present yet + call winrestview(l:breakpointview) + call feedkeys("a(\", 'n') + else + "Otherwise fall back to a backslash + call winrestview(l:breakpointview) + call feedkeys("a\\\\", 'n') + endif else call cursor(a:lnum, l:tw + 1) "Search for a space that is not trailing whitespace From 85d31e26acf5617dcb912e239cc15f25459d6a7c Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 23:38:23 +0200 Subject: [PATCH 16/22] Try adding newline after bracket instead of using backslash --- indent/python.vim | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index ab45be1..0a422a3 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -563,13 +563,13 @@ function! GetPythonPEPFormat(lnum, count) " 2. Breaking inside brackets is preferred (no backslash needed) " 3. Breking outside a string is preferred (new breakpoint) " 4. Possible future: breaking at space is preferred - if l:breakpoint[0] != 0 && s:isBetweenBrackets(l:breakpointview) + if l:breakpoint[1] > indent(a:lnum) && s:isBetweenBrackets(l:breakpointview) "echom 'between brackets' call winrestview(l:breakpointview) call feedkeys("r\", 'n') else "echom 'zooooi' - if l:better_orig_breakpoint[0] != 0 + if l:better_orig_breakpoint[1] > indent(a:lnum) \ && s:isBetweenBrackets(l:better_orig_breakpointview) " echom 'doing the quotes' call winrestview(l:better_orig_breakpointview) @@ -596,8 +596,10 @@ function! GetPythonPEPFormat(lnum, count) call winrestview(l:breakpointview) let l:next_char = getline(a:lnum)[l:breakpoint[1]] - if l:next_char !=# '{' && l:next_char !=# '(' && l:next_char !=# '[' - \ && !s:isBetweenBrackets(l:breakpointview) + if l:next_char ==# '{' || l:next_char ==# '(' || l:next_char ==# '[' + "Add a newline after the bracket + call feedkeys("la\\", 'n') + elseif !s:isBetweenBrackets(l:breakpointview) "Add a bracket when this is not present yet call winrestview(l:breakpointview) call feedkeys("a(\", 'n') From 146ba032cdea3849a08a8315eb243b7da2c693b6 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 21 Sep 2016 23:55:56 +0200 Subject: [PATCH 17/22] Fix unicode support partially --- indent/python.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 0a422a3..8ceba7a 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -500,7 +500,7 @@ function! GetPythonPEPFormat(lnum, count) return 1 endif - if len(getline(a:lnum)) <= l:tw && l:count == 1 " No need for gq + if virtcol('$') <= l:tw + 1 && l:count == 1 " No need for gq return 1 endif From 58c534769e878f1d72db0690c834cca29ded551d Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Thu, 22 Sep 2016 00:13:53 +0200 Subject: [PATCH 18/22] Fix unicode related bugs by using virtcol --- indent/python.vim | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 8ceba7a..3e6cf20 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -512,14 +512,17 @@ function! GetPythonPEPFormat(lnum, count) endwhile endif - call cursor(a:lnum, l:tw + 1) + let l:twplus1 = s:VirtcolToCol(a:lnum, l:tw + 1) + let l:twminus1 = s:VirtcolToCol(a:lnum, l:tw - 1) + + call cursor(a:lnum, l:twplus1) let l:orig_breakpoint = searchpos(' ', 'bcW', a:lnum) let l:orig_breakpointview = winsaveview() " If breaking inside string extra space is needed for the space and quote - call cursor(a:lnum, l:tw - 1) + call cursor(a:lnum, l:twminus1) let l:better_orig_breakpoint = searchpos(' ', 'bcW', a:lnum) let l:better_orig_breakpointview = winsaveview() - call cursor(a:lnum, l:tw + 1) + call cursor(a:lnum, l:twplus1) let l:breakpoint = s:SearchPosWithSkip(' ', 'bcW', s:skip_string, a:lnum) let l:breakpointview = winsaveview() @@ -609,7 +612,7 @@ function! GetPythonPEPFormat(lnum, count) call feedkeys("a\\\\", 'n') endif else - call cursor(a:lnum, l:tw + 1) + call cursor(a:lnum, l:twplus1) "Search for a space that is not trailing whitespace let l:afterbreakpoint = s:SearchPosWithSkip(' [^ ]', 'cW', s:skip_string, a:lnum) @@ -639,3 +642,14 @@ function s:isBetweenPair(left, right, winview, skip) let l:bracket = searchpairpos(a:left, '', a:right, 'bW', a:skip) return l:bracket[0] != 0 endfunction + +function s:VirtcolToCol(lnum, cnum) + let l:last = virtcol([a:lnum, '$']) + let l:cnum = a:cnum + let l:vcol = virtcol([a:lnum, l:cnum]) + while l:vcol <= a:cnum && l:vcol < l:last + let l:cnum += 1 + let l:vcol = virtcol([a:lnum, l:cnum]) + endwhile + return l:cnum - 1 +endfunction From 5391f8d84bdfde640815eac86c472452070be827 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Thu, 22 Sep 2016 09:44:39 +0200 Subject: [PATCH 19/22] Add support for strings with strformat and doctests --- indent/python.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index 3e6cf20..f7a3f7d 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -61,7 +61,7 @@ let s:skip_special_chars = 'synIDattr(synID(line("."), col("."), 0), "name") ' . \ '=~? "\\vstring|comment|jedi\\S"' let s:skip_string = 'synIDattr(synID(line("."), col("."), 0), "name") ' . - \ '=~? "\\vstring|bytes\\S"' + \ '=~? "\\vstr|bytes|doc\\S"' let s:skip_after_opening_paren = 'synIDattr(synID(line("."), col("."), 0), "name") ' . \ '=~? "\\vcomment|jedi\\S"' From 05464ad6d8a66bec4e7da92d64f791d917094ead Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Thu, 22 Sep 2016 10:34:18 +0200 Subject: [PATCH 20/22] Use exclamation mark functions --- indent/python.vim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index f7a3f7d..7d28691 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -425,7 +425,7 @@ function! GetPythonPEPIndent(lnum) return s:indent_like_previous_line(a:lnum) endfunction -function s:SearchPosWithSkip(pattern, flags, skip, stopline) +function! s:SearchPosWithSkip(pattern, flags, skip, stopline) " " Returns true if a match is found for {pattern}, but ignores matches " where {skip} evaluates to false. This allows you to do nifty things @@ -479,11 +479,11 @@ function s:SearchPosWithSkip(pattern, flags, skip, stopline) endfunction -function s:IsInComment(lnum, col) +function! s:IsInComment(lnum, col) return synIDattr(synID(a:lnum, a:col, 0), 'name') =~? 'comment' endfunction -function s:IsInMultilineString(lnum, col) +function! s:IsInMultilineString(lnum, col) return synIDattr(synID(a:lnum, a:col, 0), 'name') =~? 'multiline' endfunction @@ -629,7 +629,7 @@ function! GetPythonPEPFormat(lnum, count) call feedkeys('gqq', 'n') endfunction -function s:isBetweenBrackets(winview) +function! s:isBetweenBrackets(winview) " Check if match is inside brackets let l:skip = s:skip_string return s:isBetweenPair('(', ')', a:winview, l:skip) @@ -637,13 +637,13 @@ function s:isBetweenBrackets(winview) \ || s:isBetweenPair('\[', '\]', a:winview, l:skip) endfunction -function s:isBetweenPair(left, right, winview, skip) +function! s:isBetweenPair(left, right, winview, skip) call winrestview(a:winview) let l:bracket = searchpairpos(a:left, '', a:right, 'bW', a:skip) return l:bracket[0] != 0 endfunction -function s:VirtcolToCol(lnum, cnum) +function! s:VirtcolToCol(lnum, cnum) let l:last = virtcol([a:lnum, '$']) let l:cnum = a:cnum let l:vcol = virtcol([a:lnum, l:cnum]) From 21ea58af75a9a759cf5f4516116fe489d6a2aaf2 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Thu, 6 Oct 2016 20:58:06 +0200 Subject: [PATCH 21/22] Remove gq code, it works fine without it --- indent/python.vim | 8 -------- 1 file changed, 8 deletions(-) diff --git a/indent/python.vim b/indent/python.vim index 7d28691..aae9c7e 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -504,14 +504,6 @@ function! GetPythonPEPFormat(lnum, count) return 1 endif - " Put all the lines on one line and do normal splitting after that. - if l:count > 1 - while l:count > 1 - let l:count -= 1 - normal! J - endwhile - endif - let l:twplus1 = s:VirtcolToCol(a:lnum, l:tw + 1) let l:twminus1 = s:VirtcolToCol(a:lnum, l:tw - 1) From 7445a127fc70e632399e6dfd78197720a53a6e56 Mon Sep 17 00:00:00 2001 From: Jelte Fennema Date: Wed, 19 Oct 2016 10:15:47 +0200 Subject: [PATCH 22/22] Fix bug after multiline removal --- indent/python.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indent/python.vim b/indent/python.vim index aae9c7e..cfd166e 100644 --- a/indent/python.vim +++ b/indent/python.vim @@ -500,7 +500,7 @@ function! GetPythonPEPFormat(lnum, count) return 1 endif - if virtcol('$') <= l:tw + 1 && l:count == 1 " No need for gq + if virtcol('$') <= l:tw + 1 " No need for gq return 1 endif