Skip to content

Commit

Permalink
Added option to format visual selection
Browse files Browse the repository at this point in the history
Works the same as plain :Neoformat when you are formatter a selection in a buffer

When you are formatting a subregion in a markdown file for example, then
you must use the following syntax.

:Neoformat! python

Note: the ! and filetype of the selection are required

Added tests for visual selection.
Using fstrings so travis config can be simplified.

#30
  • Loading branch information
sbdchd committed Jan 10, 2017
1 parent 3be20a1 commit 4c454b3
Show file tree
Hide file tree
Showing 9 changed files with 136 additions and 66 deletions.
8 changes: 5 additions & 3 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
[*.vim]
[*]
indent_style = space
indent_size = 4
tab_width = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[*.vim]
indent_size = 4
tab_width = 4

[*.vader]
indent_size = 2
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ cache:

node_js:
- "5.11.1"

python:
- "2.7"
- "3.5"
- "3.6"

install:
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ via stdin.

## Basic Usage

Format the current file using its filetype
Format the entire buffer, or visual selection of the buffer

```viml
:Neoformat
Expand All @@ -29,6 +29,14 @@ Or specify a certain formatter (must be defined for the current filetype)
:Neoformat js-beautify
```

Or format a visual selection of code in a different filetype

__Note:__ you must use a ! and pass the filetype of the selection

```viml
:Neoformat! python
```

Or perhaps run a formatter on save

```viml
Expand Down
105 changes: 59 additions & 46 deletions autoload/neoformat.vim
Original file line number Diff line number Diff line change
@@ -1,12 +1,34 @@
function! neoformat#Neoformat(user_formatter) abort
function! neoformat#Neoformat(bang, user_input, start_line, end_line) abort
let search = @/
let view = winsaveview()
let original_filetype = &filetype

call s:neoformat(a:bang, a:user_input, a:start_line, a:end_line)

let @/ = search
call winrestview(view)
let &filetype = original_filetype
endfunction

function! s:neoformat(bang, user_input, start_line, end_line) abort

if !&modifiable
return neoformat#utils#warn('buffer not modifiable')
endif

let using_visual_selection = a:start_line != 1 || a:end_line != line('$')

if a:bang
let &filetype = a:user_input
endif

let filetype = s:split_filetypes(&filetype)

if !empty(a:user_formatter)
let formatters = [a:user_formatter]
let using_user_passed_formatter = !empty(a:user_input) && !a:bang

if using_user_passed_formatter
" user passed a formatter
let formatters = [a:user_input]
else
let formatters = s:get_enabled_formatters(filetype)
if formatters == []
Expand All @@ -23,25 +45,32 @@ function! neoformat#Neoformat(user_formatter) abort
let definition = neoformat#formatters#{filetype}#{formatter}()
else
call neoformat#utils#log('definition not found for formatter: ' . formatter)
if !empty(a:user_formatter)
call neoformat#utils#msg('formatter definition for ' . a:user_formatter . ' not found')
if using_user_passed_formatter
call neoformat#utils#msg('formatter definition for ' . a:user_input . ' not found')

return s:basic_format()
endif
continue
endif

let cmd = s:generate_cmd(definition, filetype)
if cmd == {}
if !empty(a:user_formatter)
return neoformat#utils#warn('formatter ' . a:user_formatter . ' failed')
if using_user_passed_formatter
return neoformat#utils#warn('formatter ' . a:user_input . ' failed')
endif
continue
endif

let stdin = getbufline(bufnr('%'), 1, '$')
let stdin = getbufline(bufnr('%'), a:start_line, a:end_line)
let original_buffer = getbufline(bufnr('%'), 1, '$')

call neoformat#utils#log(stdin)

if cmd.stdin
let stdout = systemlist(cmd.exe, stdin)
else
call mkdir('/tmp/neoformat', 'p')
call writefile(stdin, cmd.tmp_file_path)
let stdout = systemlist(cmd.exe)
endif

Expand All @@ -50,39 +79,30 @@ function! neoformat#Neoformat(user_formatter) abort
let stdout = readfile(cmd.tmp_file_path)
endif

call neoformat#utils#log(stdin)
call neoformat#utils#log(stdout)
if !v:shell_error
if stdout != stdin
" 1. set lines to '' aka \n from end of file when new data < old data
let datalen = len(stdout)

while datalen <= line('$')
call setline(datalen, '')
let datalen += 1
endwhile

" 2. remove extra newlines at the end of the file
let search = @/
let view = winsaveview()
" http://stackoverflow.com/a/7496112/3720597
" vint: -ProhibitCommandRelyOnUser -ProhibitCommandWithUnintendedSideEffect
silent! %s#\($\n\)\+\%$##
" vint: +ProhibitCommandRelyOnUser +ProhibitCommandWithUnintendedSideEffect
let @/=search
call winrestview(view)

" 3. write new data to buffer
call setline(1, stdout)
call neoformat#utils#msg(cmd.name . ' formatted buffer')
" 1. append the lines that are before and after the formatterd content
let lines_after = getbufline(bufnr('%'), a:end_line + 1, '$')
let lines_before = getbufline(bufnr('%'), 1, a:start_line - 1)

let new_buffer = lines_before + stdout + lines_after
if new_buffer != original_buffer

call s:deletelines(len(new_buffer), line('$'))

call setline(1, new_buffer)

return neoformat#utils#msg(cmd.name . ' formatted buffer')
else
call neoformat#utils#msg('no change necessary with ' . cmd.name)

return neoformat#utils#msg('no change necessary with ' . cmd.name)
endif
else
call neoformat#utils#log(v:shell_error)
continue
call neoformat#utils#log('trying next formatter')
endif
endfor
call neoformat#utils#msg('attempted all formatters for current filetype')
endfunction

function! s:get_enabled_formatters(filetype) abort
Expand All @@ -94,6 +114,10 @@ function! s:get_enabled_formatters(filetype) abort
return []
endfunction

function! s:deletelines(start, end) abort
silent! execute a:start . ',' . a:end . 'delete'
endfunction

function! neoformat#CompleteFormatters(ArgLead, CmdLine, CursorPos) abort
if a:ArgLead =~ '[^A-Za-z0-9]'
return []
Expand Down Expand Up @@ -139,19 +163,8 @@ function! s:generate_cmd(definition, filetype) abort
let no_append = get(a:definition, 'no_append', 0)
let using_stdin = get(a:definition, 'stdin', 0)

" Write buffer data to /tmp/ file if formatter doesn't use stdin
if !using_stdin
let base_tmp_path = '/tmp/neoformat/'
call mkdir(base_tmp_path, 'p')

" get the last path component, the filename
let filename = expand('%:t')
let path = base_tmp_path . fnameescape(filename)
let data = getbufline(bufnr('%'), 1, '$')
call writefile(data, path)
else
let path = ''
endif
let filename = expand('%:t')
let path = !using_stdin ? '/tmp/neoformat/' . fnameescape(filename) : ''

let _fullcmd = executable . ' ' . join(args_expanded) . ' ' . (no_append ? '' : path)
" make sure there aren't any double spaces in the cmd
Expand Down
10 changes: 9 additions & 1 deletion doc/neoformat.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,22 @@ Install with [vim-plug](https://github.com/junegunn/vim-plug)
==============================================================================
USAGE *neoformat-usage*

Format the current file using its filetype
Format the entire buffer, or visual selection of the buffer
>
:Neoformat
<Or specify a certain formatter (must be defined for the current filetype)
>
:Neoformat js-beautify
Or format a visual selection of code in a different filetype

*Note:* you must use a ! and pass the filetype of the selection

>
:Neoformat! python
>
Or perhaps run a formatter on save

>
Expand Down
4 changes: 2 additions & 2 deletions plugin/neoformat.vim
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
command! -nargs=? -bar -complete=customlist,neoformat#CompleteFormatters Neoformat
\ call neoformat#Neoformat(<q-args>)
command! -nargs=? -bar -range=% -bang -complete=customlist,neoformat#CompleteFormatters Neoformat
\ call neoformat#Neoformat(<bang>0, <q-args>, <line1>, <line2>)
32 changes: 21 additions & 11 deletions test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,36 @@

def run_formatter(filename):
formatter = filename.split('.')[0]
cmd = 'nvim -u vimrc -c "set verbose=1 | Neoformat {formatter} | wq " --headless ./before/{filename}'.format(
filename=filename, formatter=formatter)
output = subprocess.check_output(cmd, shell=True)
print(output.decode('utf-8'))
cmd = f'nvim -u vimrc -c "set verbose=1 | Neoformat {formatter} | wq " --headless ./before/{filename}'
print(subprocess.check_output(cmd, shell=True).decode('utf-8'))


def compare_files(filename):
with open('./before/' + filename) as f_before:
with open('./after/' + filename) as f_after:
before = f_before.readlines()
after = f_after.readlines()
def run_formatter_with_visual(filename, filetype, start_line, end_line):
cmd = f'nvim -u vimrc -c "set verbose=1 | {start_line},{end_line}Neoformat! {filetype} | wq " --headless {filename}'
print(subprocess.check_output(cmd, shell=True).decode('utf-8'))

assert before == after

def readlines(filename):
with open(filename) as f:
return f.readlines()


def test_formatters():
for f in listdir('before'):
run_formatter(f)
compare_files(f)
before = readlines('./before/' + f)
after = readlines('./after/' + f)
assert before == after


def test_visualselection():
filename_before = 'visual_selection_before.txt'
for test in [('python', 4, 7), ('css', 9, 9), ('css', 14, 15)]:
run_formatter_with_visual(filename_before, *test)

before = readlines(filename_before)
after = readlines('visual_selection_after.txt')
assert before == after

if __name__ == '__main__':
test_formatters()
16 changes: 16 additions & 0 deletions test/visual_selection_after.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@



def main():

pass


.body {
color: red;
}


.textleft {
text-align: left;
}
14 changes: 14 additions & 0 deletions test/visual_selection_before.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@



def main():


pass


.body{color:red;}


.textleft{
text-align:left;}

0 comments on commit 4c454b3

Please sign in to comment.