如何使用 vim 作为 unix 过滤器来缩进源代码

How to use vim as a unix filter to indent source code

我想使用 vim 作为通用源代码压头。

这是我对 shell 函数的初步尝试,它包装了 vim 的调用,使 vim 根据文件类型和 shiftwidth 参数重新缩进 STDIN:

vim-indent () {
  local ext=
  local width=
  local file=$(mktemp --suffix=."$ext")
  cat >| "$file"
  vim -E +"set sw=$width|normal! gg=G" +'x' -- "$file" >/dev/null
  cat "$file"
}

测试 1:用 2 space 缩进

重新缩进 c 源代码
vim-indent c 2 << "EOF"
int main(int argc, char** argv) {
        char operator;
        printf("Enter an operator (+, -): ");
        scanf("%c", &operator);
        switch (operator) {
               case '+':
               case '-':
                   printf(operator);
                   break;
               default:
                   printf("Error! operator is not correct");
        }
        return 0;
}
EOF

成功。 c 源代码重新缩进了 2 space 缩进:

int main(int argc, char** argv) {
  char operator;
  printf("Enter an operator (+, -): ");
  scanf("%c", &operator);
  switch (operator) ​{
    case '+':
    case '-':
      printf(operator);
      break;
    default:
      printf("Error! operator is not correct");
  }
  return 0;
}

测试 2:使用 2 space 缩进 space 重新缩进 bash 源代码

vim-indent sh 2 << "EOF"
#!/usr/bin/bash
hello() {
        echo "Hello World"
}
if true; then
        echo "It is true"
fi
EOF

失败。函数体缩进正确,但 if 语句不缩进:

#!/usr/bin/bash
hello() {
  echo "Hello World"
}
if true; then
echo "It is true"
fi

测试 3:用 2 space 缩进 space 重新缩进 html 源代码

vim-indent html 2 << "EOF"
<html>
         <body>
                 <div>
                          <p>Hello</p>
                 </div>
         </body>
</html>
EOF

失败。完全没有缩进:

<html>
<body>
<div>
<p>Hello</p>
</div>
</body>
</html>

当我编辑 bashhtml 文件到 vim 时,我可以重新缩进它们。

为什么上面的测试对 c 源代码成功,但对 bashhtml 源代码失败?

结论

我结合了答案中的建议并创建了一个工作 shell 脚本(在下面作为答案提交),我可以将其用作通用源代码缩进器。

将此添加到 .vimrc:

filetype plugin indent on

根据您的 html 缩进首选项,您可能还需要将此行添加到 .vimrc

let g:html_indent_inctags="html,body,head" 

这一行是必需的,因为在某些 Vim 版本中,默认的 html 缩进文件(位于 :e $VIMRUNTIME/indent/html.vim)不会在 <html>、[=16] 中缩进行=] 和 <head> 标签。

由于 .vim/indent 文件夹,您还可以定义不同的缩进行为。然后在此文件夹中添加一个 html.vim 和一个 c.vim 文件。您可以描述每种语言的所有所需行为,并且您将能够像以前一样使用 = 快捷方式。

将此与 Sergio 之前的评论结合起来,您将获得一种合适的方法来缩进不同类型的文件。

这个 shell 脚本通过了我问题中描述的 3 个测试。

文件:vim-indent

#!/usr/bin/bash
filetype=${1:?"Usage: vim-indent FILETYPE [WIDTH]"}
shiftwidth=${2:-4} # default indent width is 4
file=$(mktemp) || { echo "Couldn't create temp file" >&2; exit 1; }
trap "rm $file" EXIT
cat > "$file"
/usr/bin/vim -u NONE -E \
  +'let g:html_indent_inctags = "p,html,body,head,tbody"' \
  +'filetype plugin indent on' \
  +"set filetype=$filetype" \
  +"syntax on" \
  +"set expandtab" \
  +"set shiftwidth=$shiftwidth|normal! gg=G" \
  +'x' -- "$file" >/dev/null
cat "$file"

与我最初的 shell 功能相比,我做了以下改进:

  • 将其设为 shell 脚本而不是 shell 函数
  • 采纳了 Sergio 关于使用 filetype plugin indent on
  • 的建议
  • 我把初始化文件设置为NONE。我直接在 vim 调用中执行初始化命令,以保持脚本独立。
  • 添加了一些额外的 HTML 标签以缩进
  • 在 EXIT 时添加了一个陷阱来清理临时文件

2020-07-02:添加了syntax onxml 文件和其他文件需要。