diff --git a/doc/json_formatter.txt b/doc/json_formatter.txt new file mode 100644 index 0000000..7b745ae --- /dev/null +++ b/doc/json_formatter.txt @@ -0,0 +1,181 @@ +json-formatter.txt* For Vim version 7.0. + +Author: Kaidi Zhu October 10, 2015 +Version: 2.0.0 + +For instructions on installing this file, type + :help add-local-help |add-local-help| inside Vim. + +Homepage: http://vim.sourceforge.net/script.php?script_id=5010 + + +============================================================================== +1. Contents *json_formatter* *json_formatter-contents* + + 1. Contents...............................: |json_formatter-contents| + 2. Description............................: |json_formatter-description| + 3. Installation...........................: |json_formatter-installation| + 4. Configuration..........................: |json_formatter-configure| + 3.1 Global Variables...................: |json_formatter-globals| + 3.2 Default Keys.......................: |json_formatter-mappings| + 4. Commands...............................: |json_formatter-commands| + JSONFormatter..........................: |:JSONFormatter| + +============================================================================== +2. Description *json_formatter-description* + +A Vim plugin for formatting JSON. + +JSONLint is used to first check the validity of the JSON. +If JSONLint reports error a Vim buffer is open (similar to the |quickfix| +window) which will display the error and the line information. +Clicking on that line will take you to the error in the buffer +which contains the JSON. + +If there are no errors, the selected text is replaced with the formatted +text. + +The json-formatter Vim plugin calls the NodeJS jjson module to perform +the formatting. + +============================================================================== +3. Installation *json_formatter-installation* + +If using Vundle: + Add this `repo` to your Vundle configuration: + Bundle "XadillaX/json-formatter.vim" + +No package manager: + If you are not using a Vim package manager, simply unzip the + jjson-formatter.zip file into your .vim or vimfiles directory. + There are 2 files: + plugin/json-formatter.vim + doc/json-formatter.txt + +Node.js + A Node.js module is required which performs the actual formatting + and syntax checking. You must first install Node.js from here: + https://nodejs.org/ + + Once installed, you must install the jjson package. Using a + terminal or command prompt, you can run the following: + $ npm install jjson -g + + To verify the package is installed correctly, from the terminal + or command prompt you can run: + jjson -h + + You should get output similar to this: > + Usage: jjson [options] + + Options: + -f, --file JSON filename. + -e, --encoding JSON file encoding. [utf8] + -i, --indent Number of indent for each line. [2] + -v, --vim-plugin-mode Whether it's in VIM plugin mode. + +============================================================================== +3. Configuration *json_formatter-configure* + +3.1 Global Variables *json_formatter-globals* + +You can customize the json_formatter by setting various global variables in +your |.vimrc|. + +Running the Node.js package to format the JSON can be modified using +some additional options (if necessary): > + + json_formatter_command +< Default: jjson + You can include a full path to the script if necessary using: > + let g:json_formatter_command = 'C:\Program Files\nodejs\node_modules\.bin\jjson.cmd' + json_formatter_command_encoding +< Default: + This will pass an encoding value using the -e parameter. > + let g:json_formatter_command_encoding = 'utf8' + json_formatter_command_indent +< Default: + This will pass an indent value using the -i parameter. > + let g:json_formatter_command_indent = '4' + +The jjson-formatter error window is displayed if there is +a problem with the JSON. The following settings allow you to decide +where this window is opened and it's size. +> + json_formatter_window_use_horiz +< Default: 1 + When the json_formatter window is opened, it uses a horizontal split at the + bottom of the Vim window. It can optionally use a vertical split by + setting this option to 0. > + let g:json_formatter_window_use_horiz = 0 " Use vertical split + json_formatter_window_height +< Default: 8 + If using a horizontal split, this option controls how high to make + the window. > + let g:json_formatter_window_height = 8 + json_formatter_window_width +< Default: 30 + If using a vertical split, this option controls how wide to make the + window. > + let g:json_formatter_window_width = 30 + json_formatter_window_use_bottom +< Default: 1 + If using a horizontal split, this option control whether the window is + opened at the top or bottom of the Vim window. Setting this option to + 0 forces the window to open at the top of the Vim window. > + let g:json_formatter_window_use_bottom = 1 + json_formatter_window_use_right +< Default: 1 + If using a vertical split, this option control whether the window is + opened on the left or right side of the Vim window. To force the + window to open on the left side, set this option to 0. > + let g:json_formatter_window_use_right = 1 + json_formatter_window_increment +< Default: 1 + If using a vertical split the default width of the vertical window may + be too narrow to view enough of the elements. Pressing [] will + increase the size of the window by this number of columns. Pressing + [] again will toggle it back to the original size. > + let g:json_formatter_window_increment = 50 + +< +3.2 Buffer Variables *json_formatter-buffer* + +You can customize the json_formatter by setting various buffer local variables in +your buffer to allow you to format the JSON differently for each buffer. +For example, if you are working on different projects and one specifies +and indent standard of 4 and the other 2, then you can define a buffer +local variable to override the jjson command to pass the correct values +to Node.js. The let statements below differ from the globals with a +"b:" at the start, rather than a "g:". > + + json_formatter_command +< Default: jjson + You can include a full path to the script if necessary using: > + let b:json_formatter_command = 'C:\Program Files\nodejs\node_modules\.bin\jjson.cmd' + json_formatter_command_encoding +< Default: + This will pass an encoding value using the -e parameter. > + let b:json_formatter_command_encoding = 'latin1' + json_formatter_command_indent +< Default: + This will pass an indent value using the -i parameter. > + let b:json_formatter_command_indent = '8' + +============================================================================== +4. Commands: *json_formatter-commands* + +JSONFormatter *:JSONFormatter* + The JSONFormatter command will either format the JSON supplied + or open the |quickfix| window and show any errors reported + by the tools. Clicking or hitting on any of the lines + reported in the quickfix window will take you directly to + that location. + + Examples: > + :JSONFormatter + :1,100JSONFormatter + :'<,'>JSONFormatter +< + +vim: ts=4 ft=help tw=78 diff --git a/plugin/json_formatter.vim b/plugin/json_formatter.vim index 49b522b..05d2b12 100644 --- a/plugin/json_formatter.vim +++ b/plugin/json_formatter.vim @@ -1,10 +1,255 @@ -if exists("loaded_json_formatter") - finish +" json-formatter: A VIM plugin for formatting JSON +" Author: David Fishburn +" Last Changed: 2017 Feb 15 +" Version: 2.0.0 +" Script: http://www.vim.org/script.php?script_id=5010 +" License: GPL (http://www.gnu.org/licenses/gpl.html) +" +" Documentation: +" :h json-formatter.txt +" +if exists("g:loaded_json_formatter") + finish endif -function! JsonFormatter() - execute "%!jjson --vim-plugin-mode -i 4 -f %" +let g:loaded_json_formatter = 2 + +let s:json_formatter_buffer_errors = 0 +let s:json_formatter_buffer_last = 0 +let s:json_formatter_buffer_last_winnr = 0 + +" Get the name of a temporary file for the system +let s:json_formatter_tempfile = fnamemodify(tempname(), ":h") +let s:json_formatter_tempfile = s:json_formatter_tempfile.(s:json_formatter_tempfile =~ '^/' ? '/' : '\').'json_formatter.json' + +" define shell command +if !exists('g:json_formatter_command') + let g:json_formatter_command = 'jjson' +endif + +" Parameters to the shell command +if !exists('g:json_formatter_command_encoding') + let g:json_formatter_command_encoding = '' +endif +if !exists('g:json_formatter_command_indent') + let g:json_formatter_command_indent = '' +endif + +" Error window position and size +if !exists('g:json_formatter_window_title') + let g:json_formatter_window_title = 'JSON Formatter Errors' +endif +if !exists('g:json_formatter_window_use_horiz') + let g:json_formatter_window_use_horiz = 1 +endif +if !exists('g:json_formatter_window_use_bottom') + let g:json_formatter_window_use_bottom = 1 +endif +if !exists('g:json_formatter_window_use_right') + let g:json_formatter_window_use_right = 0 +endif +if !exists('g:json_formatter_window_width') + let g:json_formatter_window_width = 80 +endif +if !exists('g:json_formatter_window_increment') + let g:json_formatter_window_increment = 50 +endif + +function! s:JSONFormatter(...) range + let default_register = 'a' + let default_register_type = 'V' + let save_reg = getreg(default_register) + let save_reg_type = getregtype(default_register) + let linenum = 1 + let colnum = 1 + + " Default command mode to normal mode 'n' + let cmd_mode = 'n' + if a:0 > 0 + " Change to visual mode, if command executed via a visual map + let cmd_mode = ((a:1 == 'v') ? 'v' : 'n') + endif + + if cmd_mode == 'v' + " We are yanking either an entire line, or a range. + " Reselect the visual range and yank the text + " into our register. + silent! exec 'normal! gv"' . default_register . 'y' + let default_register_type = getregtype(default_register) + let orig_linenum = line("'<") + let orig_colnum = colnum("'<") + let end_linenum = line("'>") + let linenum = line("'<") + let colnum = colnum("'<") + else + " In normal mode, always yank the complete line, since this + " command is for a range. + silent! exec a:firstline . ',' . a:lastline . 'yank '. default_register + let orig_linenum = a:firstline + let orig_colnum = 1 + let end_linenum = a:lastline + let linenum = a:firstline + let colnum = 1 + endif + + " Populate the temporary file with the yanked text + let rc = writefile(split(getreg(default_register), "\n"), s:json_formatter_tempfile) + if rc == -1 + echohl Warning + echo 'JSONFormatter - Failed to write to temporary file[' . s:json_formatter_tempfile . ']' + echohl None + return + endif + + " Store buffer information to return to for the error list + let s:json_formatter_buffer_last = bufnr('%') + let s:json_formatter_buffer_last_winnr = winnr() + + let encoding = g:json_formatter_command_encoding + if exists("b:json_formatter_command_encoding") + let encoding = b:json_formatter_command_encoding + endif + + let indent = g:json_formatter_command_indent + if exists("b:json_formatter_command_indent") + let indent = b:json_formatter_command_indent + endif + + let json_cmd = g:json_formatter_command + if exists("b:json_formatter_command") + let json_cmd = b:json_formatter_command + endif + + " Use nodejs to format the JSON + let cmd = shellescape(json_cmd) + if encoding != '' + let cmd = cmd . " -e " . encoding + endif + if indent != '' + let cmd = cmd . " -i " . indent + endif + let cmd = cmd . " -f " . s:json_formatter_tempfile + + let result = system( cmd ) + + " echomsg result + " If the formatting failed, the result always starts with "Error occurred" + " so check for this text. + if result =~ '^Error occurred while' + " Handle strings like this: + " Error occurred while: + " D:\WINDOW~1\json_formatter.json,3,130,found: '}' - expected: 'STRING' + let matches = matchlist(result, '^Error occurred while.\{-}file:\s\+\zs\([^,]\+\),\(\d\+\),\(\d\+\),\(.*\)', '', '') + + let MATCH_ALL = 0 + let MATCH_FILENAME = 1 + let MATCH_LINENUM = 2 + let MATCH_COLNUM = 3 + let MATCH_ERROR = 4 + + " Open the quick fix window with an errorformat specified. + setlocal errorformat=%E%f,%l,%c,%Z%m + + if len(matches) > 3 && matches[MATCH_COLNUM] != '' + + let linenum = linenum + matches[MATCH_LINENUM] - 1 + + for line in getbufline('', orig_linenum, linenum) + " Empty lines are not picked up by the JSON parser + " so manually adjust the linenum. + " Abort at the first non-empty line. + if line =~ '^$' + let linenum = linenum + 1 + else + break + endif + endfor + + if 1 == matches[MATCH_LINENUM] && colnum != 1 + " A range of lines was selected so we need to correct the + " offset to the errorline so the quickfix window will take + " us to the correct column. + let colnum = colnum + matches[MATCH_COLNUM] - 1 + else + let colnum = matches[MATCH_COLNUM] + endif + + let rc = setqflist([ + \{ + \ 'bufnr': '' + \, 'filename': bufname(s:json_formatter_buffer_last) + \, 'lnum': linenum + \, 'pattern': '' + \, 'col': colnum + \, 'vcol': 0 + \, 'nr': 0 + \, 'text': matches[MATCH_ERROR] + \, 'type': 'E' + \} + \,] + \) + else + let linenum = orig_linenum + + for line in getbufline('', orig_linenum, end_linenum) + " Blank lines are not picked up by the JSON parser + " so manually adjust the linenum. + if line =~ '^\s*$' + let linenum = linenum + 1 + else + break + endif + endfor + + " Either JSONLint hasn't been installed or JSONLint passed + " but JSON.parse() has failed. So no line and column information + " is provided. Just show the error message. + let rc = setqflist([ + \{ + \ 'bufnr': '' + \, 'filename': bufname(s:json_formatter_buffer_last) + \, 'lnum': linenum + \, 'pattern': '' + \, 'col': colnum + \, 'vcol': 0 + \, 'nr': -1 + \, 'text': matchstr(result, '^Error occurred while.\{-}file: \zs.*', '', '') + \, 'type': 'E' + \} + \,] + \) + endif + + copen + else + " Put the formatted JSON into our register. + call setreg(default_register, result, default_register_type) + + " The formatting was successful, replace the selected text + " with the formatted text. + if cmd_mode == 'v' + " Reselect the visual selection and paste the newly + " formatted text + silent! exec 'normal! gv"' . default_register . 'p' + else + " In normal mode, always yank the complete line, since this + " command is for a range. + silent! exec a:firstline . ',' . a:lastline . 'delete' + " Replaced selected area with reformatted JSON from the default + " register. + " Subtract 1 from the firstline of the range since we just + " deleted those lines, so we need to put from the previous line. + silent! exec (a:firstline - 1) . 'put ' . default_register + endif + endif + + call setreg(default_register, save_reg, save_reg_type) endfunction -nnoremap json :call JsonFormatter() +command! -nargs=? -range=% JSONFormatter ,call s:JSONFormatter() + +"exec 'xnoremap '.g:yankring_v_key." :JSONFormatter 'v'" + +"xmap