Skip to content

Commit

Permalink
Merge branch 'unpack'
Browse files Browse the repository at this point in the history
* unpack:
  Documentation
  Reverse an :Unpack with :Inline
  Repeat.vim support for :Unpack
  Initial work on :Unpack
  • Loading branch information
AndrewRadev committed Aug 22, 2016
2 parents 57da5a9 + 0394ca7 commit 0c1ab4a
Show file tree
Hide file tree
Showing 5 changed files with 385 additions and 0 deletions.
3 changes: 3 additions & 0 deletions autoload/ember_tools.vim
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ function! ember_tools#Init()

setlocal includeexpr=ember_tools#Includeexpr()
command! -count=0 -nargs=1 -buffer Extract call ember_tools#extract#Run(<line1>, <line2>, <f-args>)

command! -buffer Unpack call ember_tools#unpack#Run()
command! -buffer Inline call ember_tools#unpack#Reverse()
endfunction

function! ember_tools#Includeexpr()
Expand Down
101 changes: 101 additions & 0 deletions autoload/ember_tools/unpack.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
function! ember_tools#unpack#Run()
" TODO (2016-08-07) Multiline imports (look for the closing ; of the line?)
" TODO (2016-07-06) Nested unpacking:
" const { computed, Controller, inject: { service }, observer } = Ember;

let saved_view = winsaveview()

if !search('\%(\k\|\.\)\+', 'bc', line('.'))
return
endif

let namespace = expand('<cword>')
normal! "_df.
let member = expand('<cword>')

" Look for an existing unpacking
if search('const {.*'.member.'.*}\s\+=\s\+'.namespace, 'n')
" this member of the namespace is already unpacked, nothing to do
return
endif

if search('const {.*}\s\+=\s\+'.namespace)
" we found an existing unpacking without this member, unpack it here
let unpacking = getline('.')
let unpacking = substitute(unpacking,
\ '\s*}\(\s\+=\s\+'.namespace.'\)',
\ ', '.member.' } = '.namespace,
\ 'g')
call setline('.', unpacking)

call winrestview(saved_view)
silent! call repeat#set(":call ember_tools#unpack#Run(0)\<cr>")
return
endif

" if we're here, there's no existing unpacking
if search('^const {', 'bW')
" we can add it after the last unpacking
call append(line('.'), [''])
normal! j
elseif search('^import', 'bW')
" we can add it after the last import
call append(line('.'), ['', ''])
normal! jj
else
" just add it at the top of the file
call append(0, ['', ''])
normal! gg
endif

call setline('.', 'const { '.member.' } = '.namespace.';')
call winrestview(saved_view)
silent! call repeat#set(":call ember_tools#unpack#Run()\<cr>")
endfunction

function! ember_tools#unpack#Reverse()
let saved_view = winsaveview()
let variable = expand('<cword>')

if searchpair('const {', '', '}\s*=\s*\zs\k\+', 'W') <= 0
return
endif

let prefix = expand('<cword>')

call search('\<'.variable.'\>', 'bW')

" Remove variable from const line
exe 's/,\s*\%#'.variable.'//e'
exe 's/\%#'.variable.',\=\s*\ze\%(\k\| }\)//e'

" Handle empty const blocks
if getline('.') =~ '^const {\s*} ='
let next_lineno = nextnonblank(line('.') + 1)

if getline(next_lineno) !~ '^const'
" it's something other than another const line, let's delete all the
" whitespace up until that point
exe line('.').','.(next_lineno - 1).'delete _'
else
" just delete this line
delete _
endif
endif

" Add prefix everywhere
normal! G$
let search_flags = "w"
let variable_pattern = '\%('.prefix.'\.\)\@<!\<'.variable.'\>'

while search(variable_pattern, search_flags) > 0
if synIDattr(synID(line('.'), col('.'), 1), 'name') !~ 'String\|Comment'
exe 'normal! i'.prefix.'.'
" go back to the search
call search(variable_pattern)
endif
let search_flags = "W"
endwhile

call winrestview(saved_view)
endfunction
75 changes: 75 additions & 0 deletions doc/ember_tools.txt
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,81 @@ emblem template, but if you'd like to specify explicitly what templates you
prefer, set the |g:ember_tools_default_logic_filetype| and/or
|g:ember_tools_default_template_filetype| configuration variables.

*ember_tools-:Unpack*
:Unpack ~

The `:Unpack` command helps you unpack an imported variable into its component
pieces. An example might looks something like this:

>
import Ember from 'ember';
export default Ember.Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
<
Running the `:Unpack` command with the cursor on "Ember.Controller" would lead
to the following result:
>
import Ember from 'ember';
const { Controller } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
<
The command creates a `const { ... } = ` line that unpacks the `Ember`
variable's `Controller` component into its own variable.

You can continue to run `:Unpack` on, for instance, "Ember.computed.equal",
and then once again on the remaining "computed.equal" (if you have repeat.vim
installed, you can just trigger the |.| mapping) to get:
>
import Ember from 'ember';
const { Controller, computed } = Ember;
const { equal } = computed;
export default Controller.extend({
foo: equal('bar', 'baz')
});
<
The command adds new entries to the end of the list. If you'd like to sort
them in some way afterwards, you can try using a different plugin of mine,
sideways (https://github.com/AndrewRadev/sideways.vim).

*ember_tools-:Inline*
:Inline ~

The `:Inline` command inlines an "unpacked" variable. If you have code like
this:
>
import Ember from 'ember';
const { computed, Controller } = Ember;
export default Controller.extend({
foo: computed.equal('bar', 'baz')
bar: computed.equal('baz', 'qux')
});
<
Running `:Inline` on "computed" within the `const { ... }` definition will
remove it from that list and replace it across the file (ignoring strings and
comments) with "Ember.computed".
>
import Ember from 'ember';
const { Controller } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
bar: Ember.computed.equal('baz', 'qux')
});
<
For now, this is simply a reversal of the `:Unpack` command. In the future,
the `:Inline` command might also inline other kinds of constructs, like local
variables or properties.


==============================================================================
Expand Down
118 changes: 118 additions & 0 deletions spec/plugin/inline_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
require 'spec_helper'

describe ":Inline" do
describe "const unpacking" do
specify "deletes a const line if nothing is left of it after inlining" do
edit_file 'test.js', <<-EOF
const { Controller } = Ember;
export default Controller.extend({});
EOF

vim.search 'const { \zsController'
vim.command 'Inline'
vim.write

expect_file_contents current_file, <<-EOF
export default Ember.Controller.extend({});
EOF
end

specify "deletes an const line with another const line following" do
edit_file 'test.js', <<-EOF
const { Controller } = Ember;
const { foo } = bar;
export default Controller.extend({});
EOF

vim.search 'const { \zsController'
vim.command 'Inline'
vim.write

expect_file_contents current_file, <<-EOF
const { foo } = bar;
export default Ember.Controller.extend({});
EOF
end

specify "inlines entries from the beginning" do
edit_file 'test.js', <<-EOF
import Ember from 'ember';
const { computed, Controller, isPresent } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
EOF

vim.search 'const.*\zscomputed'
vim.command 'Inline'
vim.write

expect_file_contents current_file, <<-EOF
import Ember from 'ember';
const { Controller, isPresent } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
EOF
end

specify "inlines entries in the middle" do
edit_file 'test.js', <<-EOF
import Ember from 'ember';
const { computed, Controller, isPresent } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
EOF

vim.search 'const.*\zsController'
vim.command 'Inline'
vim.write

expect_file_contents current_file, <<-EOF
import Ember from 'ember';
const { computed, isPresent } = Ember;
export default Ember.Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
EOF
end

specify "inlines entries at the end" do
edit_file 'test.js', <<-EOF
import Ember from 'ember';
const { computed, Controller, isPresent } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
EOF

vim.search 'const.*\zsisPresent'
vim.command 'Inline'
vim.write

expect_file_contents current_file, <<-EOF
import Ember from 'ember';
const { computed, Controller } = Ember;
export default Controller.extend({
foo: Ember.computed.equal('bar', 'baz')
});
EOF
end
end
end
Loading

0 comments on commit 0c1ab4a

Please sign in to comment.