本文是 cc-mode 缩进的设置,所有继承自 cc-modemajor mode 都可以参考,如 c++

缩进的设置主要是两个方面的设置:

  1. tab 的设置
  2. 代码中各个地方的缩进设置

tab 设置

tab 的设置主要是两方面:

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

下面是全局默认设置

1
2
(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 定义了默认使用的缩进风格,不进行任何配置的情况下,默认值为:

1
2
3
((java-mode . "java")
 (awk-mode . "awk")
 (other . "gnu"))

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

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

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

定义自己的缩进风格

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

emacs 的缩进风格格式如下:

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

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

1
2
3
(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 效果就是下面这样的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
namespace test {
    namespace {
        int a = 0;
    }

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

}

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

1
2
3
4
5
6
(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 的值是 4 ,=innamespace= 的缩进就是 0 ,即 c-basic-offset + (-1 * c-basic-offset)

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
namespace test {
namespace {
int a = 0;
}

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

}

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

1
2
3
4
5
6
7
(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` 看哪些语法元素可以定义缩进

相关文档:https://www.gnu.org/software/emacs/manual/html_mono/ccmode.html#c_002doffsets_002dalist

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(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"))