Repository: mhinz/vim-mix-format Branch: master Commit: 01a31ef82aa5 Files: 4 Total size: 12.1 KB Directory structure: gitextract_2r40t88n/ ├── LICENSE ├── README.md ├── doc/ │ └── mix-format.txt └── ftplugin/ └── elixir.vim ================================================ FILE CONTENTS ================================================ ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2017-present, Marco Hinz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # vim-mix-format Elixir 1.6 introduced the formatter: `mix format`. This plugin makes it easy to run the formatter asynchronously from within Vim 8 and Neovim. ![demo](demo.gif) ## Installation Use your [favorite plugin manager](https://github.com/mhinz/vim-galore#managing-plugins), e.g. [vim-plug](https://github.com/junegunn/vim-plug): Plug 'mhinz/vim-mix-format' ## Commands * To format the current file, use `:MixFormat`. Use `:verb MixFormat` to see the exact shell command used. * The formatter is not perfect yet, so `:MixFormatDiff` will open a diff window that can be used for previewing the changes or picking only those that seem reasonable. `dp` pushes changes from the diff window to the source file. `q` closes the diff window. `]c` and `[c` jump between the changes. If you're not used to Vim's diff mode, [watch this screencast](http://vimcasts.org/episodes/comparing-buffers-with-vimdiff). ## Options * Automatically format on saving. ```vim let g:mix_format_on_save = 1 ``` * Set options for the formatter. See `mix help format` in the shell. ```vim let g:mix_format_options = '--check-equivalent' ``` * By default this plugin opens a window containing the stacktrace on errors. With this option enabled, there will be just a short message in the command-line bar. The stacktrace can still be looked up via `:messages`. ```vim let g:mix_format_silent_errors = 1 ``` * If you're not using Elixir 1.6 in your project, but want to use the formatter anyway, you can specify the bin directory of an alternative Elixir installation: ```vim let g:mix_format_elixir_bin_path = '~/repo/elixir/bin' ``` ## Customization When using `:MixFormatDiff`, a new diff window will be opened and an user event is emitted. It can be used to set different settings or switch back to the source window: ```vim autocmd User MixFormatDiff wincmd p ``` ## Feedback If you like this plugin, star it! It helps me deciding which projects to spend more time on. ================================================ FILE: doc/mix-format.txt ================================================ *mix-format.txt* Elixir formatter integration. *mix-format* by Marco Hinz~ Twitter: https://twitter.com/_mhinz_ Github: http://github.com/mhinz > If you use any of my plugins, please star them on github. It's a great way of getting feedback and gives me the kick to put more time into their development. < ============================================================================== COMMANDS *mix-format-commands* * To format the current file, use `:MixFormat`. * The formatter is not perfect yet, so `:MixFormatDiff` will open a diff window that can be used for previewing the changes or picking only those that seem reasonable. |dp| pushes changes from the diff window to the source file. `q` closes the diff window. |]c| and |[c| jump between the changes. If you're not used to Vim's diff mode, watch this screencast: http://vimcasts.org/episodes/comparing-buffers-with-vimdiff ============================================================================== OPTIONS *mix-format-options* * Automatically format on saving. > let g:mix_format_on_save = 1 < * Set options for the formatter. See `mix help format` in the shell. > let g:mix_format_options = '--check-equivalent' < * By default this plugin creates a new |quickfix| list on errors. With this option enabled, there will be just a short message in the command-line bar. The stacktrace can still be looked up via `:messages`. > let g:mix_format_silent_errors = 1 < * If you're not using Elixir 1.6 in your project, but want to use the formatter anyway, you can specify the bin directory of an alternative Elixir installation: > let g:mix_format_elixir_bin_path = '~/repo/elixir/bin' < ============================================================================== CUSTOMIZATION *mix-format-customization* When using `:MixFormatDiff`, a new diff window will be opened and an user event is emitted. It can be used to set different settings or switch back to the source window: > autocmd User MixFormatDiff wincmd p < ============================================================================== vim: tw=78 ================================================ FILE: ftplugin/elixir.vim ================================================ if exists('b:loaded_mix_format') \ || &filetype != 'elixir' \ || &compatible finish endif " Is 'cwd' key for job_start() options available? let s:has_cwd = has('nvim') || has('patch-8.0.902') if !exists('g:mix_format_env_cmd') " Workaround for https://github.com/mhinz/vim-mix-format/issues/15 let g:mix_format_env_cmd = executable('env') ? ['env', '-u', 'MIX_ENV'] : [] endif function! s:msg(show, msg) abort if a:show echomsg 'MixFormat: '. a:msg endif endfunction function! s:on_stdout_nvim(_job, data, _event) dict abort if empty(a:data[-1]) " Second-last item is the last complete line in a:data. let self.stdout += self.stdoutbuf + a:data[:-2] let self.stdoutbuf = [] else if empty(self.stdoutbuf) " Last item in a:data is an incomplete line. Put into buffer. let self.stdoutbuf = [remove(a:data, -1)] let self.stdout += a:data else " Last item in a:data is an incomplete line. Append to buffer. let self.stdoutbuf = self.stdoutbuf[:-2] \ + [self.stdoutbuf[-1] . get(a:data, 0, '')] \ + a:data[1:] endif endif endfunction function! s:on_stdout_vim(_job, data) dict abort let self.stdout += [a:data] endfunction function! s:on_exit(_job, exitval, ...) dict abort let source_win_id = win_getid() call win_gotoid(self.win_id) if !s:has_cwd call s:msg(self.verbose, 'Changing to: '. self.origdir) execute 'cd' fnameescape(self.origdir) endif if filereadable(self.undofile) execute 'silent rundo' self.undofile call s:msg(self.verbose, 'Deleting undo file: '. self.undofile) call delete(self.undofile) endif if a:exitval && get(g:, 'mix_format_silent_errors') for line in self.stdout echomsg line endfor redraw | echohl ErrorMsg | echo 'Formatting failed. Check :messages.' | echohl NONE return end let old_efm = &errorformat let &errorformat = '%-Gmix format failed%.%#' let &errorformat .= ',** (%.%#) %f:%l: %m' lgetexpr self.stdout let &errorformat = old_efm lwindow if &buftype == 'quickfix' let w:quickfix_title = s:build_cmd(fnamemodify(self.origfile, ':.')) endif if a:exitval redraw | echohl ErrorMsg | echo 'Formatting failed.' | echohl NONE return endif if self.diffmode call system(printf('diff %s %s', self.origfile, self.difffile)) if !v:shell_error echomsg 'No formatting issues found.' if +get(g:, 'mix_format_diff_win_id') let winnr = win_id2win(g:mix_format_diff_win_id) if winnr execute winnr 'close' endif endif return endif else let [sol, ur] = [&startofline, &undoreload] let [&startofline, &undoreload] = [0, 10000] mkview try silent edit! finally let [&startofline, &undoreload] = [sol, ur] loadview endtry call win_gotoid(source_win_id) return end diffthis if +get(g:, 'mix_format_diff_win_id') && win_gotoid(g:mix_format_diff_win_id) %delete else rightbelow vnew let g:mix_format_diff_win_id = win_getid() set buftype=nofile nobuflisted bufhidden=wipe runtime syntax/elixir.vim endif execute 'silent read' fnameescape(self.difffile) call s:msg(self.verbose, 'Deleting diff file: '. self.difffile) silent! call delete(self.difffile) silent 0delete _ diffthis normal! ]c nnoremap q :close augroup mix_format_diff autocmd! autocmd BufWipeout silent diffoff! augroup END if exists('#User#MixFormatDiff') doautocmd User MixFormatDiff endif endfunction function! s:get_cmd_from_file(filename) abort let cmd = s:build_cmd(a:filename) if has('win32') && &shell =~ 'cmd' return 'cmd /c '. cmd endif return g:mix_format_env_cmd + ['sh', '-c', cmd] endfunction function! s:build_cmd(filename) abort let elixir_bin_path = get(g:, 'mix_format_elixir_bin_path') let options = get(g:, 'mix_format_options', '--check-equivalent') let [shellslash, &shellslash] = [&shellslash, 0] let dot_formatter = findfile('.formatter.exs', expand('%:p:h').';') if !empty(dot_formatter) let options .= ' --dot-formatter '. shellescape(fnamemodify(dot_formatter, ':p')) endif let filename = shellescape(a:filename) let &shellslash = shellslash if empty(elixir_bin_path) return printf('mix format %s %s', options, filename) endif return printf('%s %s %s %s', \ elixir_bin_path .'/elixir', \ elixir_bin_path .'/mix format', \ options, \ filename) endfunction function! s:mix_format(diffmode) abort if &modified redraw | echohl WarningMsg | echo 'Unsaved buffer. Quitting.' | echohl NONE return endif let origdir = getcwd() let mixfile = findfile('mix.exs', expand('%:p:h').';') if empty(mixfile) call s:msg(&verbose, 'No mix project found.') else let mixroot = fnamemodify(mixfile, ':h') if !s:has_cwd call s:msg(&verbose, 'Changing to: '. mixroot) execute 'cd' fnameescape(mixroot) endif endif let origfile = expand('%:p') if a:diffmode let difffile = tempname() call s:msg(&verbose, 'Creating diff file: '. difffile) execute 'silent write' fnameescape(difffile) else let difffile = origfile endif let cmd = s:get_cmd_from_file(difffile) let undofile = tempname() call s:msg(&verbose, 'Creating undo file: '. undofile) execute 'silent wundo!' undofile let options = { \ 'cmd': type(cmd) == type([]) ? join(cmd) : cmd, \ 'diffmode': a:diffmode, \ 'origdir': origdir, \ 'origfile': origfile, \ 'difffile': difffile, \ 'undofile': undofile, \ 'win_id': win_getid(), \ 'verbose': &verbose, \ 'stdout': [], \ 'stdoutbuf': [], \ } if s:has_cwd && exists('mixroot') let options.cwd = mixroot endif call s:msg(&verbose, type(cmd) == type([]) ? string(cmd) : cmd) if has('nvim') silent! call jobstop(s:id) let s:id = jobstart(cmd, extend(options, { \ 'on_stdout': function('s:on_stdout_nvim'), \ 'on_stderr': function('s:on_stdout_nvim'), \ 'on_exit': function('s:on_exit'), \ 'detach': !has('nvim-0.3.6'), \ })) else silent! call job_stop(s:id) let s:id = job_start(cmd, extend({ \ 'in_io': 'null', \ 'err_io': 'out', \ 'out_cb': function('s:on_stdout_vim', options), \ 'exit_cb': function('s:on_exit', options), \ }, has_key(options, 'cwd') ? {'cwd': options.cwd} : {})) endif endfunction command! -buffer -bar MixFormat call mix_format(0+'diffmode') command! -buffer -bar MixFormatDiff call mix_format(1+'diffmode') if get(g:, 'mix_format_on_save') augroup mix_format autocmd BufWritePre noautocmd silent update | call s:mix_format(0+'diffmode') augroup END endif let b:loaded_mix_format = 1