【发布时间】:2014-11-30 14:10:03
【问题描述】:
说实话go 宠坏了我。通过go,我已经习惯了由我的编辑器 (vim) 强制执行的严格格式标准,并且几乎被团队中和世界各地的其他人所接受和遵循。
我想以相同的方式在保存时格式化 JSON 文件。
问题:如何在 vim 中保存时自动格式化/缩进/lint json 文件。
【问题讨论】:
说实话go 宠坏了我。通过go,我已经习惯了由我的编辑器 (vim) 强制执行的严格格式标准,并且几乎被团队中和世界各地的其他人所接受和遵循。
我想以相同的方式在保存时格式化 JSON 文件。
问题:如何在 vim 中保存时自动格式化/缩进/lint json 文件。
【问题讨论】:
在 vim.org 上搜索 JSON 插件返回以下内容:
jdaddy.vim : JSON manipulation and pretty printing
描述如下:
gqaj“漂亮的打印”(换行/缩进/排序键/否则清理) 光标下的 JSON 结构。
如果它符合您期望的格式,那么您可以创建一个autocmd BufWritePre 以在保存时进行格式化。
【讨论】:
在一个命令中,试试这个:
execute '%!python -m json.tool' | w
然后您可以添加自己的键绑定,使其更简单的击键。当然,要让它工作,你需要在你的机器上安装 Python。
【讨论】:
| w 这里的目的是什么?为什么不只是::%!python -m json.tool?
|w 只是保存缓冲区,没有它,您将获得 json 格式,但更改将不会保存。这取决于我猜你想要什么。
:write 是有道理的。干杯!
Error occured at line 1,但是当我在命令行将同一个文件放入 json.tool 时,它可以工作。我不明白为什么。
感谢 mMontu 和 Jose B,这就是我最终要做的:
警告这将覆盖您的缓冲区。因此,如果您打开一个已经存在语法错误的 json 文件,您将丢失整个文件(或可能会丢失)。
将此行添加到您的~/.vimrc
" Ali: to indent json files on save
autocmd FileType json autocmd BufWritePre <buffer> %!python -m json.tool
当然,你需要在你的机器上安装 python。
编辑:如果你的 json 有错误,下一个不应该覆盖你的缓冲区。这使它成为正确的答案,但由于我对 Vim 脚本或 shell 没有很好的掌握,所以我将它作为一个实验性的东西来呈现,如果你感到幸运,你可以尝试一下。它也可能取决于您的外壳。你被警告了。
" Ali: to indent json files on save
autocmd FileType json autocmd BufWritePre <buffer> %!python -m json.tool 2>/dev/null || echo <buffer>
【讨论】:
如果您热衷于使用外部工具并且正在使用 json 进行一些工作,我建议您使用 jq:
https://stedolan.github.io/jq/
然后,您可以在 vim 中执行:%!jq .,它将用 jq 的输出替换当前缓冲区。
【讨论】:
:%!jq "." 假设您下载了 jq 的 windows 版本,并将其从 jq-win64.exe 重命名为 jq.exe (类似 32 位版本)。另外,请确保它在您的路径中。
.、:%! jq . 为我工作或:%! jq --indent 4 . 周围加上引号
jq 而不是 python 命令,因为 python 可能会根据编码更改内容。例如。 {"test": "ü"} 其中"ü" 在:%!python -m json.tool 之后变为"\u00fc"
Vim 自动格式化
https://github.com/Chiel92/vim-autoformat
有这个 Vim 插件支持多种自动格式和缩进方案,以及使用每个文件类型的自定义格式化程序进行扩展。
https://github.com/Chiel92/vim-autoformat#default-formatprograms
注意:
您需要安装nodejs 和js-beautify,因为vim-autoformat 使用它们作为默认的外部工具。
npm install -g js-beautify
【讨论】:
你可以搜索'vim-json-line-format'插件,在Normal mode打开一个文件,将光标移到json行,使用<leader>pj打印格式化的json,使用<leader>wj可以将文本更改为格式化的 json。
无效的json无法格式化!
【讨论】:
%!python -m json.tool
或
%!python -c "import json, sys, collections; print json.dumps(json.load(sys.stdin, object_pairs_hook=collections.OrderedDict), ensure_ascii=False, indent=4)"
你可以把它添加到你的 vimrc 中:
com! FormatJSON %!python -m json.tool
你可以使用:FormatJson格式的json文件
【讨论】:
ensure_ascii或者使用你自己的indent,你可以使用com! FormatJSON %!python -m json.tool --no-ensure-ascii --indent 4。正如python -m json.tool --help 建议的那样。
这是我的解决方案。它没有完全解决“保存时”的问题部分,但如果您在保存之前执行此操作,它将输出错误,您可以在保存之前修复。
另外,它只依赖于一个外部工具——jq——它已经成为了 unix shell JSON 处理工具的黄金标准。并且您可能已经安装了(仅限 macOS 和 Linux/Unix;想知道这在 Windows 中会如何表现)
基本上就是:
ggVG!jq '.'
这将突出显示整个 JSON 文档,然后通过 jq 运行它,它将解析它的正确性,重新格式化它(例如修复任何缩进等),并将输出返回到 Vim 编辑器。
如果您只想解析文档的一部分,可以通过按v 或V 手动突出显示该部分,然后运行
!jq '.'
这样做的好处是您可以通过这种方式修复文档的小节。
【讨论】:
:%!jq '.'
我做了一些整理(虽然其中一些与 vim 无关)并自己在neovim上编写脚本!
Neovim 允许通过将 Python 文件或包放在 rplugin/python3/ 中的 runtimepath 文件夹中来定义 Python3 插件)
就我而言
- init.vim
- rplugin/python3/[your_py_file_set].py
- rplugin/python3/fmt_file.py
fmt_file.py 如下
# rplugin/python3/fmt_file.py
import pynvim
import json
@pynvim.plugin
class Plugin:
__slots__ = ('vim',)
def __init__(self, vim):
self.vim = vim
@pynvim.command('FormatJson', nargs='*', range='')
def format_json(self, args, rg):
"""
USAGE::
:FormatJson
"""
try:
buf = self.vim.current.buffer
json_content: str = '\n'.join(buf[:])
dict_content: dict = json.loads(json_content)
new_content: str = json.dumps(dict_content, indent=4, sort_keys=True)
buf[:] = new_content.split('\n')
except Exception as e:
self.vim.current.line = str(e)
然后在Nvim 内运行一次::UpdateRemotePlugins,以生成必要的 Vimscript 以使您的插件可用。 (你最好重启 neovim)
然后,您打开要格式化的 JSON 文件并在命令中键入::FormatJson。全部完成。
别忘了告诉 vim 你的 python 在哪里
" init.vim
let g:python3_host_prog = '...\python.exe''
和pip install pynvim
tool.py 位于Lib/json/tool.py 上的位置
:%!python -m json.tool
如果你已经安装了python,可以打开命令行:
python -m json.tool "test.json" >> "output.json"
我为这些事情写了一个简单的脚本。
"""
USAGE::
python fmt_file.py fmt-json "C:\test\test.json"
python fmt_file.py fmt-json "C:\test\test.json" --out_path="abc.json"
python fmt_file.py fmt-json "test.json" --out_path="abc.json"
"""
import click # pip install click
from click.types import File
import json
from pathlib import Path
@click.group('json')
def gj():
...
@gj.command('fmt-json')
@click.argument('file_obj', type=click.File('r', encoding='utf-8'))
@click.option('--out_path', default=None, type=Path, help='output path')
def format_json(file_obj: File, out_path: Path):
new_content = ''
with file_obj as f:
buf_list = [_ for _ in f]
if buf_list:
json_content: str = '\n'.join(buf_list)
dict_content: dict = json.loads(json_content)
new_content: str = json.dumps(dict_content, indent=4, sort_keys=True)
if new_content:
with open(out_path if out_path else Path('./temp.temp_temp.json'),
'w', encoding='utf-8') as f:
f.write(new_content)
def main():
for register_group in (gj,):
register_group()
if __name__ == '__main__':
main()
【讨论】:
另一种解决方案是使用coc-format-json。
【讨论】: