10000 method motions to include decorators by KamranMaharov · Pull Request #1015 · python-mode/python-mode · GitHub
[go: up one dir, main page]

Skip to content

method motions to include decorators #1015

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

Merged
Merged
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
22 changes: 11 additions & 11 deletions after/ftplugin/python.vim
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ if g:pymode_motion
vnoremap <buffer> ]M :call pymode#motion#vmove('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', '')<CR>
vnoremap <buffer> [M :call pymode#motion#vmove('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 'b')<CR>

onoremap <buffer> C :<C-U>call pymode#motion#select('^<Bslash>s*class<Bslash>s', 0)<CR>
onoremap <buffer> aC :<C-U>call pymode#motion#select('^<Bslash>s*class<Bslash>s', 0)<CR>
onoremap <buffer> iC :<C-U>call pymode#motion#select('^<Bslash>s*class<Bslash>s', 1)<CR>
vnoremap <buffer> aC :<C-U>call pymode#motion#select('^<Bslash>s*class<Bslash>s', 0)<CR>
vnoremap <buffer> iC :<C-U>call pymode#motion#select('^<Bslash>s*class<Bslash>s', 1)<CR>

onoremap <buffer> M :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 0)<CR>
onoremap <buffer> aM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 0)<CR>
onoremap <buffer> iM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 1)<CR>
vnoremap <buffer> aM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 0)<CR>
vnoremap <buffer> iM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 1)<CR>
onoremap <buffer> C :<C-U>call pymode#motion#select_c('^<Bslash>s*class<Bslash>s', 0)<CR>
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi @KamranMaharov
Why have you used select_c over here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good point. it could have been select(pattern, pattern)
to not duplicate pattern all over the script (that would be confusing), we call
select_c(pattern) and then select_c(pattern) calls select(pattern, pattern)

onoremap <buffer> aC :<C-U>call pymode#motion#select_c('^<Bslash>s*class<Bslash>s', 0)<CR>
onoremap <buffer> iC :<C-U>call pymode#motion#select_c('^<Bslash>s*class<Bslash>s', 1)<CR>
vnoremap <buffer> aC :<C-U>call pymode#motion#select_c('^<Bslash>s*class<Bslash>s', 0)<CR>
vnoremap <buffer> iC :<C-U>call pymode#motion#select_c('^<Bslash>s*class<Bslash>s', 1)<CR>

onoremap <buffer> M :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=@', '^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 0)<CR>
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't @ be an optional "group"?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, for a decorator, we don't use async before decorators right?
So this:

(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=@

have an extra async doesn't? [sorry if I didn't understand the regexes correctly].

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i'm not familiar with async keyword.
as far as i can tell, it was here before and we could use it for matching decorator pattern.

onoremap <buffer> aM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=@', '^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 0)<CR>
onoremap <buffer> iM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=@', '^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 1)<CR>
vnoremap <buffer> aM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=@', '^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 0)<CR>
vnoremap <buffer> iM :<C-U>call pymode#motion#select('^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=@', '^<Bslash>s*<Bslash>(async<Bslash>s<Bslash>+<Bslash>)<Bslash>=def<Bslash>s', 1)<CR>

endif

Expand Down
50 changes: 29 additions & 21 deletions autoload/pymode/motion.vim
Original file line number Diff line number Diff line change
Expand Up @@ -28,27 +28,26 @@ fun! pymode#motion#pos_le(pos1, pos2) "{{{
return ((a:pos1[0] < a:pos2[0]) || (a:pos1[0] == a:pos2[0] && a:pos1[1] <= a:pos2[1]))
endfunction "}}}


fun! pymode#motion#select(pattern, inner) "{{{
fun! pymode#motion#select(first_pattern, second_pattern, inner) "{{{
let cnt = v:count1 - 1
let orig = getpos('.')[1:2]
let snum = s:BlockStart(orig[0], a:pattern)
if getline(snum) !~ a:pattern
let posns = s:BlockStart(orig[0], a:first_pattern, a:second_pattern)
if getline(posns[0]) !~ a:first_pattern && getline(posns[0]) !~ a:second_pattern
return 0
endif
let enum = s:BlockEnd(snum, indent(snum))
let snum = posns[0]
let enum = s:BlockEnd(posns[1], indent(posns[1]))
while cnt
let lnum = search(a:pattern, 'nW')
let lnum = search(a:second_pattern, 'nW')
if lnum
let enum = s:BlockEnd(lnum, indent(lnum))
call cursor(enum, 1)
endif
let cnt = cnt - 1
endwhile
if pymode#motion#pos_le([snum, 0], orig) && pymode#motion#pos_le(orig, [enum, 1])
if pymode#motion#pos_le([snum, 0], orig) && pymode#motion#pos_le(orig, [enum+1, 0])
if a:inner
let snum = snum + 1
let enum = prevnonblank(enum)
let snum = posns[1] + 1
endif

call cursor(snum, 1)
Expand All @@ -57,28 +56,37 @@ fun! pymode#motion#select(pattern, inner) "{{{
endif
endfunction "}}}

fun! pymode#motion#select_c(pattern, inner) "{{{
call pymode#motion#select(a:pattern, a:pattern, a:inner)
endfunction "}}}

fun! s:BlockStart(lnum, ...) "{{{
let pattern = a:0 ? a:1 : '^\s*\(@\|class\s.*:\|def\s\)'
fun! s:BlockStart(lnum, first_pattern, second_pattern) "{{{
let lnum = a:lnum + 1
let indent = 100
while lnum
let lnum = prevnonblank(lnum - 1)
let test = indent(lnum)
let line = getline(lnum)
if line =~ '^\s*#' " Skip comments
continue
elseif !test " Zero-level regular line
return lnum
elseif test >= indent " Skip deeper or equal lines
" Skip comments, deeper or equal lines
if line =~ '^\s*#' || test >= indent
continue
" Indent is strictly less at this point: check for def/class
elseif line =~ pattern && line !~ '^\s*@'
return lnum
endif
let indent = indent(lnum)

" Indent is strictly less at this point: check for def/class/@
if line =~ a:first_pattern || line =~ a:second_pattern
while getline(lnum-1) =~ a:first_pattern
let lnum = lnum - 1
endwhile
let first_pos = lnum
while getline(lnum) !~ a:second_pattern
let lnum = lnum + 1
endwhile
let second_pos = lnum
return [first_pos, second_pos]
endif
endwhile
return 0
return [0, 0]
endfunction "}}}


Expand All @@ -89,7 +97,7 @@ fun! s:BlockEnd(lnum, ...) "{{{
let lnum = nextnonblank(lnum + 1)
if getline(lnum) =~ '^\s*#' | continue
elseif lnum && indent(lnum) <= indent
return lnum - 1
return prevnonblank(lnum - 1)
endif
endwhile
return line('$')
Expand Down
37 changes: 37 additions & 0 deletions tests/motion_decorator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!coding=utf-8
"""
to test pymode motions, please put cursor on each of the lines
and press "vaM" for selecting methods or
"vaC" for selection class.
"""

def a_decorator(func):
print("chamando func")
def wrapped(*args, **kw):
return func(*args, **kw)
print("Pós func")
return wrapped

def b_decorator(func):
print("second chamando func")
def wrapped(*args, **kw):
return func(*args, **kw)
print("second Pós func")
return wrapped

@b_decorator
@a_decorator
def teste():
print("Not Selecting Decorator")

class Teste:
@a_decorator
@b_decorator
def metodo(self):
print("Meu método")


teste()

testinho = Teste()
testinho.metodo()
0