vim-textobj-function-javascript
vim-textobj-function-javascript copied to clipboard
Support arrow functions
var foo = [1, 2, 3];
var bar = foo.map(x => x * x);
It would be nice if ES6 arrow functions (like the one above) were supported.
Object literal methods would be lovely too:
{
test() {
}
}
Added pull request for fat arrow functions - #4
Just tested, it looks like arrorw functions are working, but not object literal methods. Would be amazing if someone could add that!
I there any update? Can anybody fix it?
It can select es5 functions which starting from function
.
the fat arrow functions work as a charm - I think the issue might be with functions using new destructuring operators, or ...
and generator functions, async functions and so on. Practically this extension does not help at all, 80% of modern javascript is not supported.
@alex-shamshurin instead of complaining we should fix it :)
unfortunately I'm not good at vimscript
@alex-shamshurin I think its enough to understand a bit of regex to fix it - lets make a deal - I will try to provide a fix for it and you will tell me what is missing/not working. Good idea?
Anyone, could you please try this?
diff --git a/autoload/textobj/function/javascript.vim b/autoload/textobj/function/javascript.vim
index d60b209..c2ab901 100644
--- a/autoload/textobj/function/javascript.vim
+++ b/autoload/textobj/function/javascript.vim
@@ -88,7 +88,7 @@ endfunction
function! s:function_range()
let start = getpos('.')
" look backward for function definition or fat arrow
- while search('\v<function>|(\(%(\k|,|\s)*\)|\k+)\s*\=\>\s*', 'bcW') != 0
+ while search('\v<function>|(\(%(\k|\.\.\.|,|\s)*\)|\k+)\s*\=\>\s*', 'bcW') != 0
let b = getpos('.')
" go to either the start of the function argument list or right after the fat arrow
And I noticed that goes endless loop in sometimes.
diff --git a/autoload/textobj/function/javascript.vim b/autoload/textobj/function/javascript.vim
index d60b209..48101c9 100644
--- a/autoload/textobj/function/javascript.vim
+++ b/autoload/textobj/function/javascript.vim
@@ -88,8 +88,13 @@ endfunction
function! s:function_range()
let start = getpos('.')
" look backward for function definition or fat arrow
- while search('\v<function>|(\(%(\k|,|\s)*\)|\k+)\s*\=\>\s*', 'bcW') != 0
+ let prev = start
+ while search('\v<function>|(\(%(\k|\.\.\.|,|\s)*\)|\k+)\s*\=\>\s*', 'bcW') != 0
let b = getpos('.')
+ if b ==# prev
+ break
+ endif
+ let prev = b
" go to either the start of the function argument list or right after the fat arrow
if (search('\v<function>\s*\k*\s*\(|\=\>\s*', 'ceW'))
@mattn What should I be testing?
As far as I can see, my patch fixes problems you mentioned.
But, there may still be unknown cases.
@mattn I think its better to provide a PR in your own fork.
As a sidenote - I looked at the code and as @alex-shamshurin pointed out about himself I always have a hard time reading vimml :). But my first takeaway about this, is that I would branch out on function
or =>
(nearer wins) and then delegate to specific functions - that would make code and regexes clearer.
I may not fully understand what the case you want. Could you please show me the code? (to reproduce)
@mattn Excellent work! I think the only one I can see missing there are class methods/object methods:
class {
someMethod() {
}
}
{
test() {
}
}
Is that tricky to add?
Ah, I understand the case. Hmm, it's hard to implement without syntax-contained feature of vim.
diff --git a/autoload/textobj/function/javascript.vim b/autoload/textobj/function/javascript.vim
index d60b209..d31f11c 100644
--- a/autoload/textobj/function/javascript.vim
+++ b/autoload/textobj/function/javascript.vim
@@ -88,11 +88,16 @@ endfunction
function! s:function_range()
let start = getpos('.')
" look backward for function definition or fat arrow
- while search('\v<function>|(\(%(\k|,|\s)*\)|\k+)\s*\=\>\s*', 'bcW') != 0
+ let prev = start
+ while search('\v<function>|(\(%(\k|\.\.\.|,|\s)*\)|\k+)\s*\=\>\s*', 'bcW') != 0
let b = getpos('.')
+ if b ==# prev
+ break
+ endif
+ let prev = b
" go to either the start of the function argument list or right after the fat arrow
- if (search('\v<function>\s*\k*\s*\(|\=\>\s*', 'ceW'))
+ if (search('\v<function>\s*\k*\s*\(|\k\+|\=\>\s*', 'ceW'))
" if we're on the start of a normal function argument list - skip it
if s:cursor_char() == '('
call s:jump_to_pair()
@@ -130,7 +135,34 @@ function! s:function_range()
endif
return [b, e]
endwhile
- return 0
+
+ call setpos('.', start)
+
+ " handle ES6 class method. back to something like "foo("
+ if !search('\v\k+\s*\(', 'bcW')
+ return 0
+ endif
+ let b = getpos('.')
+ call s:left()
+ " in left side back, syntax have Class identifier
+ if s:cursor_syn() !~ 'Class'
+ return 0
+ endif
+ " move forward to the end of block
+ if !search('(', 'ceW')
+ return 0
+ endif
+ call s:jump_to_pair()
+
+ while search('\S', 'W') != 0 && s:cursor_syn() ==# 'Comment'
+ endwhile
+ if s:cursor_char() != '{'
+ return 0
+ endif
+ call s:jump_to_pair()
+
+ let e = getpos('.')
+ return [b, e]
endfunction
function! s:jump_to_pair()
If you install syntax plugin that support ES6, and it have syntax identifier contains Class
, this may work well. But this have some ugly workaround.