1

I am new to Neovim, having moved from Emacs. One of the features I really liked and got used to in Emacs was automatic indentation and formatting while in different modes such as C++. I knew how to do this in Emacs and it was through the following added to my .emacs:

defun linux-c-mode ()
  "C mode with adjusted defaults for use with the Linux kernel."
  (interactive)
  (c-mode)
  (c-set-style "K&R")
  (setq tab-width 8)
  (setq indent-tabs-mode t)
  (setq c-basic-offset 8))

It worked beautifully when I was editing any file with a .c extension: with the code text moving according to the C syntax. Similarly, for other kinds of files.

As an illustration, here is an animated gif of what I am looking for (in Emacs). Pardon my lack of typing skills that make it more painful to watch, but note that the indentation and formatting as happening automagically as I type in Emacs.

enter image description here

Is there similar code that I can put in my .config/nvim/init.vim or some other file like that?

So, if you see, what is happening in the animated gif is that as I am typing with Emacs, I write for (, the automatic indentation happens the moment I press the ( and then when the brace opens next {, the indentation for the next line is automatic when I hit return key. Note that I am not actually having to press any key combination and formatting is happening according to the "Kernighan and Ritchie" style of C programming (as asked for in the style setting). This really helps in making fewer errors while writing code.

I looked into formatter.nvim at https://github.com/mhartington/formatter.nvim but I am not sure it is possible to do what I am looking for automagically. Being new to nvim, it is also quite confusing, and difficult to easily find suggestions because I am not sure what to search on.

For C bindings, I have found that adding the following to my `.config/nvim/init.vim' works fairly well:

autocmd BufEnter  *.c,*.h,*.C set cindent formatoptions=croq
autocmd BufLeave  *.c,*.h,*.C set nocindent formatoptions=tcq

However, I am still looking for better solutions.

Thanks for all the suggestions and the help, and my best wishes!

5
  • 1
    Try :help :filetype and follow the links to different things like per-filetype indent settings. This is also introduced at some point in the user guide.
    – D. Ben Knoble
    Nov 18, 2023 at 15:44
  • Thanks @D. Ben Knoble, so automatic formatting of C/python etc files is possible in nvim, too? Nov 18, 2023 at 20:01
  • Yes; I don’t have time to provide a full answer (or search for dupes) at the moment.
    – D. Ben Knoble
    Nov 19, 2023 at 1:00
  • Thanks, @D.BenKnoble for your pointers and your help. I understand. Perhaps someone else can also help me out! Nov 19, 2023 at 4:47
  • Regarding tabs, what's the expected behavior: should tabs turn into 8 spaces or should tabs remain \t characters that are 8 characters wide?
    – Friedrich
    Nov 20, 2023 at 15:08

2 Answers 2

2

1. Auto-Indenting

Auto-indentation is a vast topic and I have no intention to cover it all but I can give some indication about the default automatic indentation for cpp filetype.

More information about C indentation with :help C-indenting.

By default for the cpp filetype the cindent option is on.

This ensure that automatic indentation is triggered by the key specified in the cinkeys option (more information with :help 'cinkeys') following the cinoptions auto-indentation style (more information with :help 'cinoptions')

By default this means that auto-indentation will be triggered by:

  • New line
  • Closing bracket on empty lines
  • Ctrl-f
  • ...

2. Indentation Correction

The indentation of a line can be corrected in normal mode with ==

The indentation of a range of line can be corrected using the = operator (e.g. gg=G for the entire program, = for the selected lines, =a{ for the current scope, method or function, ...)

3. Formatting

For the formatting there are multiple solutions:

  1. Based on external program and Vim filtering
  2. Based on formatting plugins
  3. Based on LSP engine

3.a External Program

A popular choice for formatting cpp program is clang-format.

It reads from standard input and, based on the formatting option set in ~/.clang-format, writes formatted output to the standard output.

You can format your cpp code using the following Vim/Neovim command:

:%!clang-format

The clang-format documentation as a Vim Integration section to provide partial formatting (when you want to format only a part of your code)

For Python a popular choice for formatting is black.

You can format your python code using the following Vim/Neovim commnand:

:%!black -q -

For partial Python formatting there is a black-machiato plugin that provides it (I wrote some pull requests to solve some small problems with black-macchiato).

3.a.1. The gq Command

The formatting command of Vim is gq, among other things it allows you to associate a program to the command via the formatprg option (more information with :help 'formatprg').

For cpp you could do:

set formatprg=clangformat

With that set:

  • gggqG will format your entire cpp file,
  • gqa{ will format the current scope (function or method).
  • ...

3.b Formatting Plugins

Under the hood they will use the same filtering technique but they will provide you with minimal configuration:

  • A common command to format the code for several languages
  • The possibility to automatically format on save

Some popular example of such plugins are:

3.c LSP engine

Some of the LSP engine, that are known to provide source completion, also offers code formatting. If you install a plugin that bridge Vim/Neovim with a LSP engine they will come with formatting command.

The coc-nvim comes with the Format option.

The lsp-formatting plugin offer formatting based on the builtin LSP bridge of Neovim

10
  • Thank you very much for this, @VivianDeSmedt! This is great and very helpful, but I also wonder it it is possible to have the formatting happen automatically as I type specific keywords (in C in the above emacs example). All these formatting tools require some action (save file, for example) while pressing a key. I have been looking for something that does this automagically as some keyword is typed. Nov 19, 2023 at 13:16
  • I don't know much the solution in Emacs and in the example you posted the formatting I see is more what we call auto indentation. Could you give us an example of what you expect (correction of indentation, correction of the white space, correction of the return value, addition/removal of brace {, ...)? Nov 19, 2023 at 13:26
  • 1
    THank you again, @VivianDeSmedt, your suggestions above have provided me with a wealth of references to check out. I will also look at auto-indentation, though I feel it should be possible to do what emacs is doing. Thanks again! Nov 19, 2023 at 14:33
  • 1
    Thanks, @Vivian De Smedt, I am looking into it. I alos found a simple way to handle this in C files. But let me understand the rest. And yes, I will accept the best answer. Thanks again! Nov 20, 2023 at 0:38
  • 1
    You might also mention formatprg to make gq run the program of your choice. I also like to include (for example) =a{ to show more interesting uses of operators beyond gg<op>G and visual mode.
    – D. Ben Knoble
    Nov 20, 2023 at 15:40
1

If I read the emacs code correctly, what you want are the three options:

set cindent       " use indentation for C code
set shiftwidth=8  " indent is 8 spaces
set noexpandtab   " keep tabs as tabs, don't expand to spaces

See :help cindent, :help shiftwidth and :help expandtab respectively to see what these options do.

Vim's automatic filetype detection will enable cindent for C files (among other things). So you should switch it on (in NeoVim, it's on by default) and override the other two options e.g. by adding the following file or an autocommand that triggers when filetype=c is set.

In after/ftplugin/c.vim:

setlocal shiftwidth=8
setlocal noexpandtab

Alternatively, define an autocmd in init.vim:

filetype plugin indent on
augroup linux_kernel_indentation
    autocmd!
    autocmd FileType c setlocal shiftwidth=8 noexpandtab
augroup END

Again, refer to :help :filetype and help for the respective commands.

The lines above are for a classic vimrc so you need to translate them into Lua if you want them in an init.lua.

BTW, Linux Kernel Coding Style mandates to use spaces instead of tabs, that would mean set expandtab. I may have simply misread the emacs code.

8
  • Adding the above to my .config/nvim/init.vim does not appear to do anything. Nov 20, 2023 at 14:19
  • @user3236841 does it work if you set the options manually?
    – Friedrich
    Nov 20, 2023 at 14:47
  • 1
    Yes, it does. Interesting! Nov 20, 2023 at 14:53
  • 1
    Might as well use after/indent/c.vim if you’re turning on indent scripts; no need for the extra autocommand.
    – D. Ben Knoble
    Nov 20, 2023 at 15:41
  • 1
    They should use the same rtp files for ftplugins and such.
    – D. Ben Knoble
    Nov 20, 2023 at 19:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.