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