thinca / vim-textobj-function-javascript

Text objects for functions in javascript.
31 stars 8 forks source link

Support arrow functions #3

Open cpixl opened 9 years ago

cpixl commented 9 years ago
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.

simonsmith commented 8 years ago

Object literal methods would be lovely too:

{
  test() {

  }
}
yasen-atanasov commented 8 years ago

Added pull request for fat arrow functions - #4

bag-man commented 7 years ago

Just tested, it looks like arrorw functions are working, but not object literal methods. Would be amazing if someone could add that!

alex-shamshurin commented 7 years ago

I there any update? Can anybody fix it?

alex-shamshurin commented 6 years ago

It can select es5 functions which starting from function.

kubek2k commented 6 years ago

the fat arrow functions work as a charm - I think the issue might be with functions using new destructuring operators, or ...

alex-shamshurin commented 6 years ago

and generator functions, async functions and so on. Practically this extension does not help at all, 80% of modern javascript is not supported.

kubek2k commented 6 years ago

@alex-shamshurin instead of complaining we should fix it :)

alex-shamshurin commented 6 years ago

unfortunately I'm not good at vimscript

kubek2k commented 6 years ago

@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?

mattn commented 6 years ago

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
mattn commented 6 years ago

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'))
simonsmith commented 6 years ago

@mattn What should I be testing?

mattn commented 6 years ago

As far as I can see, my patch fixes problems you mentioned.

tests

But, there may still be unknown cases.

kubek2k commented 6 years ago

@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.

mattn commented 6 years ago

I may not fully understand what the case you want. Could you please show me the code? (to reproduce)

simonsmith commented 6 years ago

@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?

mattn commented 6 years ago

Ah, I understand the case. Hmm, it's hard to implement without syntax-contained feature of vim.

mattn commented 6 years ago
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.