我想了解下, emacs 下的缩进到底是怎么设置的...?😥

新手问题

我使用的是 doom emacs, 这是我自己的缩进设置(抄的别人的)

我想用空格代替 tab缩进, 然后C/C++ 是两个空格, Python 是 4 个空格,.

可是我写的时候用 lsp 补全生成的代码还是 4 个空格缩进,
image

format 一下又变成 2 个空格缩进了

能不能让它补全的时候也是两个空格的缩进?

关于 emacs 原本的缩进和 lsp 缩进设置有没有详细的参考资料呢?

各位大佬也可以给出你们的缩进设置方案, 让 emacs 在各种情况下都能有个自定义且合理的缩进设置.

Thanks♪(・ω・)ノ

1 个赞

我用editorconfig用来处理写的时候的缩进

format的问题是clang-format的原因,论坛里面有详细的clang-format设置

1 个赞

首先纠正一下:

  1. indent-tabs-mode 表示在按 TAB 的时候是否使用真实的 TAB
  2. tab-width 是用来表示一个 \t 显示成多少个空格

所以,即使 indent-tabs-mode 为 nil、tab-width 为 4,也不代表在按 TAB 的时候一定会插入 4 个空格。这两者没有必然关系。

在 C/C++ 中,是使用 c-basic-offset 来控制缩进的,当然与之相关的还有 c-offsets-alist 配置。不同的语言有不同的 offset 变量,在 C/C++ 中是 c-basic-offset, 而在 Python 里则是 python-indent-offset

关于详细的 cpp 缩进配置,可以参考我的

5 个赞

editorconfig 是个好主意

仔细看 editorconfig-mode 的代码, 实际上它做的事情就是针对常见的 mode 人工设置对应的 offset 变量,具体可以看

这个 alist.

1 个赞

c-basic-offset影响比如按回车后的缩进,但是不影响lsp server如ccls/clangd的format功能(用的是clang-format)。

所以一个可用的设置是保持editorconfig配置和.clang-format里的缩进一致。

首先抛开 lsp 这里面有两个问题:

  1. tab 的设置,
  2. cc-mode (c/c+±mode 继承自 cc-mode) 缩进的设置

tab 设置

tab 的设置主要是两方面:

  1. tab 字符的宽度
  2. 是否要将 tab 换成空格

下面是全局默认设置

(setq-default  tab-width 4) ;; 表示一个 tab 4个字符宽
(setq-default indent-tabs-mode nil) ;; nil 表示将 tab 替换成空格

cc-mode 的缩进设置

定义代码的各个部分如何缩进一般叫缩进风格 。

cc-mode 定义了一个缩进风格列表 c-style-alist ,里面预制了一些缩进风格,比如 gnu ,k&r 等 我们可以通过 M-x c-set-style 设置当前 buffer 的风格。

c-default-style 定义了默认使用的缩进风格,不进行任何配置的情况下,默认值为:

((java-mode . "java")
 (awk-mode . "awk")
 (other . "gnu"))

即 java-mode 用 java 风格,awk-mode 用 awk 风格,其它 mode(c/c++ 等) 用 gnu 风格。

如果我们想在 c/c++ 中默认用 k&r 风格,只需要修改这个变量

(add-to-list 'c-default-style '(c++-mode . "k&r"))
(add-to-list 'c-default-style '(c-mode . "k&r"))

如果预制的缩进风格不满足要求,我们可以定义自己的缩进风格,然后将它加到 c-style-alist 中。

emacs 的缩进风格格式如下:

  (STYLE-STRING [BASE-STYLE] (VARIABLE . VALUE) [(VARIABLE . VALUE) ...])

STYLE-STRING 是风格名称,BASE-STYLE 是可选的,表示继承某个已有的风格, 后面就是指定在这种风格下某个变量的值。如:

  (setq my-style '("my-style"
                   "stroustrup"
                   (indent-tabs-mode . nil)))

上面就是定义一个名为 my-style 的风格,继承自 stroustrup ,使用这个风格时 indent-tabs-modenil ,即将 tab 替换成空格。

有一个特殊的变量 c-offsets-alist ,这个列表定义了所有语法元素符号的缩进,如 class 缩进几个字符,public 缩进几个字符。

如果 my-style 只继承自 stroustrup 效果就是下面这样的:

  namespace test {
      namespace {
          int a = 0;
      }

      class Test final {
      public:
          void Hello();
      };

  }

如果我们想要内部 namespace 不缩进,我们就可以继承自 stroustrup 的基础上修改内部 namespace 的缩进

  (setq my-style '("my-style"
                   "stroustrup"
                   (indent-tabs-mode . nil)
                   (c-basic-offset . 4)
                   (c-offsets-alist
                    (innamespace . -))))

innamespace 就是控制内部 namespace ,- 表示 innamespace 的缩进是 c-basic-offset 的 -1 倍 c-basic-offset 的值是 4innamespace 的缩进就是 0c-basic-offset + (-1 * c-basic-offset)

设置后效果就从上面变成下面这样:

namespace test {
namespace {
int a = 0;
}

class Test final {
public:
    void Hello();
};

}

如果我们想让 public: 缩进两个字符

  (setq my-style '("my-style"
                   "stroustrup"
                   (indent-tabs-mode . nil)
                   (c-basic-offset . 4)
                   (c-offsets-alist
                    (innamespace . -)
                    (access-label . /)))

/ 代表 c-basic-offset的 -0.5 倍,即 c-basic-offset + (-0.5 * c-basic-offset)

可以通过 c-fallback-style 看哪些语法元素可以定义缩进

相关文档:CC Mode Manual

emacs 不推荐直接改 c-style-alist ,而是通过 c-add-style 增加缩进风格,所以最后的配置可以这样写:

  (c-add-style "my-style"
               '("stroustrup"
                 (indent-tabs-mode . nil)
                 (c-basic-offset . 4)
                 (c-offsets-alist
                  (innamespace . -))
                 ))

  (add-to-list 'c-default-style '(c++-mode . "my-style"))
  (add-to-list 'c-default-style '(c-mode . "my-style"))
6 个赞

这个回答真的值得每个新手收藏。哈哈哈

看到个搞笑的: https://www.reddit.com/r/emacs/comments/r3vipy/why_are_emacs_indents_so_fucking_awful/

我用的doom,可以M-x doom/set-indent-width设置

1 个赞

我也遇到个不能理解的问题,有的py文件缩进是4、有的是8。这个tab-width为8的文件,以前用别的编辑器写的,为4的是emacs里设置了indent-tabs-mode nil、tab-width之后写的。

我还是推荐使用 editorconfig 插件

我最后是用query-replace把缩进的tab替换成了4个空格。