Использование Vim в качестве C/C++ IDE
Привет, Хабрахабр. Меня зовут Алексей и я занимаюсь тем, что разрабатываю встраиваемые операционные системы.
Сегодня я хочу рассказать, как я использую Vim в качестве IDE для C/C++ проектов.
Несмотря на то, что я использую Vim для C/C++, многие из рекоммендаций довольно общие и могут использоваться в любом проекте.
Первый шаг
Для начала, мы хотим иметь место, где можно будет сохранять настройки для своего проекта. Глобальный .vimrc нам не подходит, так как проектов много и они разные, а значит, каждый из них имеет свои специфические настройки.
В Vim есть подходящая для нас опция — exrc. Она говорит vim’у искать дополнительный .vimrc в текущей рабочей директории. Таким образом, мы можем иметь один файлик в корне каждого проекта с его специфическими настройками.
Так как vim будет подключать .vimrc из любой директории, из которой вы его запустите, желательно предпринять некоторые меры защиты и установить опцию secure. В основном, она запрещает внешним .vimrc писать что-то в файлы, выполнять комманды шелла и отображает маппинги, которые создаются.
В общем, нам нужно добавить следующие две строчки в наш главный .vimrc:
set exrc set secure
Настройки конкретного проекта
После того, как мы получили возможность сохранять опции для каждого проекта в отдельности, почему бы нам этим не заняться.
У всех проектов есть какие-то свои правила касательно тех же отступов, так что просто пеместите нужные настройки в .vimrc в корне вашего проекта:
set tabstop=4 set softtabstop=4 set shiftwidth=4 set noexpandtab
Кроме этого, я стараюсь держать свои строки в пределах 110 символов. Но так как это очень специфично и сильно зависит от контекста, я не могу доверить такое важное дело как разбиение строк какому-либо редактору (даже vim). Но vim может помочь мне просто подсветив нужный столбец.
set colorcolumn=110 highlight ColorColumn ctermbg=darkgray
Определений типов файлов
По умолчанию, Vim предпологает, что все .h файлы это C++. Однако, часть моих проектов написаны на чистом C. Поэтому я хочу, чтобы тип файла был C. Кроме того, в моих проектах используется doxygen, так что я не против включить очень клевую подсветку doxygen в vim.
Для того, нужно добавить пару строк в локальный .vimrc:
augroup project autocmd! autocmd BufRead,BufNewFile *.h,*.c set filetype=c.doxygen augroup END
Установка переменной path
В vim есть чудесная комманда gf (и родственные к ней), которая открывает файл, чье имя находится под курсором. Это неимоверно полезно при навигации по заголовочным файлам.
По умолчанию, vim смотрит файлы в текущей папке, а так же в /usr/include. Однако почти все проекты имеют заголовочные файлы, которые хранятся в других папках. Поэтому, нужно установить переменную path, которая содержит список папок для поиска, разделенный запятыми.
let &path.="src/include,/usr/include/AL,"
Заметка
Джавистам следует обратить внимание на опцию includeexpr. Она содержит выражение, которое будет использовано для преобразования строки в имя файла. Следующая строка заменяет все точки на слеши для gf. Таким образом, можно прыгать по import’ам.
set includeexpr=substitute(v:fname,'\\.','/','g')
Автодополнение
Лучший(Устарело. Сейчас я использую YouCompleteMe. Обратитесь к моему посту за деталями) Хороший плагин для автодополнения C/C++ кода, который я нашел, это clang_complete (инструкции для установки смотри на страничке плагина).
Он использует clang для того, чтобы сгенерировать список дополнений. И работает отлично для C и C++ (а так же еще пары языков).
Для того, чтобы clang знал о ваших папках с заголовочными файлами, нужно добавить -I и -D флаги в файл .clang_complete в корне вашего проекта. После этого, clang_complete будет автоматически вызываться при нажатии «.» или «->».
Подсказка
Если path опция уже заполнена, то можно легко вставить список I-флагов с помощью следующей нехитрой комбинации клавиш
"='-I'.substitute(&path, ',', '\n-I', 'g')p
Другие clang плагины
Clang не просто компилятор, а еще и набор полезных библиотек для анализа и манипуляций с кодом. Таким образом, это очень хорошая основа для разнообразных плагинов. Так что в ближайшем будующем можно ожидать множество основаных на нем плагинов.
Навигатор
Для того чтобы отображать дерево проекта можно воспользоваться либо отдельными плагинами (NERD Tree например), либо встроеным netrw.
Я не использую ни один из способов, так как мне вполне комфортно выбирать файлы прямо из коммандного режима vim. (если установить wildmode в longest:list,full , то vim показывает подходящие файлы как нормальный шелл)
Настройка системы сборки
После того, как мы разобрались с редактированием и навигацией по файлам, можно собирать проект. В vim есть комманда make. По умолчанию, она запускает make в текущей директории и парсит вывод на наличие ошибок.
Фактическая комманда для выполнения хранится в makeprg. Если проект собирается в другой папке, использует другие параметры make или вообще использует другую систему сборки, нужно просто изменить makeprg чтобы отобразить это:
set makeprg=make\ -C\ ../build\ -j9
После этого, можно собирать проект просто напечатав :make .
Но так как нам этого мало, можно повесить эту комманду на одну из ненужных кнопок. Например:
nnoremap :make!
(«!» предотвращает от прыгания на первую ошибку)
Настройки системы запуска
После того, как проект собран, вполне логично запустить его. Vim может запускать любую программу, для этого всего лишь нужно добавить восклицательный знак перед ее именем в коммандном режиме. Так, чтобы запустить мою супер-пупер программу, нужно набрать . /my_great_program .
Конечно, это тоже нужно упростить!
nnoremap . /my_great_program
Система контроля версий
Так как vim предоставляет прямой доступ к коммандной строке, я не использую какой-либо специальный плагин для этих задач и просто управляю своим git-деревом прямо из шелла.
Но я должен отметить, что есть множество отличных vim плагинов для работы с разными системами контроля версий.
Например, fugitive. Если вы работаете с git, вы абсолютно должны посмотреть вимкасты fugitive.
Забытый пункт: отладка
Так как я чувствую себя комфортно в command-line gdb, да и специфика операционных систем делает почти невозможным отладку их отладчиками, за прошедший год я запускал gdb лишь однажды. В основном, все мои проекты я отлаживаю обычными print’ами и капелькой мозгов. Так что в моем vim нет ничего, чтобы напоминало отладчик.
Однако, я должен сказать, что существуют несколько плагинов для интеграции gdb и vim. Например, clewn, gdbvim.
Итог
После серии несложных оперций, vim превратился в вполне себе сносную IDE. Буду рад услышать о дополнительных настройках, которые облегчили вашу жизнь в vim и позволили лучше интегрировать его с окружающими инструментами.
Blogs » Use Vim as a C/C++ IDE
This is a general guide for using SpaceVim as a C/C++ IDE, including layer configuration and usage. Each of the following sections will be covered:
- Enable language layer
- Syntax highlighting
- code completion
- alternate file jumping
- code running
- Syntax lint
- code format
- REPL support
Enable language layer
To add C/C++ language support in SpaceVim, you need to enable the lang#c layer. Press SPC f v d to open SpaceVim configuration file, and add following configuration:
[[layers]] name = "lang#c"
for more info, you can read the lang#c layer documentation.
Syntax highlighting
The basic syntax highlighting is based on regular expression, If you want clang based syntax highlighting. Enable enable_clang_syntax_highlight layer option:
[[layers]] name = 'lang#c' enable_clang_syntax_highlight = true
This option requires +python or +python3 enabled and libclang has been installed.
code completion
By default the autocomplete layer has been enabled, so after loading lang#c layer, the code completion for C/C++ language should works well.
If the autocomplete_method is deoplete , then Shougo/deoplete-clangx will be loaded in lang#c layer.
If the autocomplete_method is asyncomplete , then wsdjeg/asyncomplete-clang.vim will be loaded.
If the autocomplete_method is neocomplete , Then Rip-Rip/clang_complete will be loaded.
You can check the value of autocomplete_method via :SPSet autocomplete_method .
alternate file jumping
To manage alternate files for a project, you may need to create a .project_alt.json file in the root of your project.
For example, add the following content into the .project_alt.json file:
"*.c": "alternate": "<>.h">, "*.h": "alternate": "<>.c"> >
With this configuration, you can jump between alternate files via command :A
code running
The default code running key binding is SPC l r . It will compile and run current file asynchronously. And the stdout will be shown on a runner buffer.
The default runner compile option is defineded in clang_std and clang_flag option. If you want to use c11 , you can change clang_std option to:
[[layers]] name = "lang#c" [layers.clang_std] cpp = "c11"
You can also create a .clang file in the root directory of you project. Within this file, all compile option should be defineded in it. for example:
-I/home/test -I/user/std/include
Syntax lint
The checker layer provides syntax checking for many programming languages. Including C/C++, and the default plugin is neomake. The default lint for C/C++ is gcc / g++ . These commands also read configuration in .clang file.
code format
In order to be able to format C/C++ files, you need to install uncrustify , clangformat or astyle . The key binding SPC b f is defineded in format layer which is loaded by default. In this layer, the default format engine is neoformat .
REPL support
Start a igcc inferior REPL process with SPC l s i . After the REPL process being started, you can send code to inferior process, all key bindings prefix with SPC l s , including sending line, sending selection or even send whole buffer.
Make Vim as your C/C++ IDE
This procedure can be very similar for VSCode and Fleet editors. In this case, you should only create the compile_commands.json file, and this procedure is illustrated in the bear subsection, but I suggest you read the whole post.
It happened to me in the past that I had to configure Vim to manage C projects with some external library, and after lots of useless attempts, I gave up setting it up. I am currently attending a university course called Advanced in Operating Systems. I am using a STM32 microcontroller and ST provides an “Eclipse 2010 based” IDE with lots of proprietary libraries, but as a Vim programmer writing even 10 lines of code on this IDE made me frustrated. So, I decided to try again, and as you can imagine if you are reading this blog post, I succeeded!
Requirements
- Make sure use Vim >= 8.1.1719 or Neovim >= 0.4.0 and make
- Install nodejs >= 14.14:
curl -sL install-node.vercel.app/lts | bash
Configuration
coc
Firstly, you should have a coc.nvim plug-in installed. I am currently using vim-plug as plug-in manager, but you can use any other.
In my case, I added it to my .vimrc file
Plug 'https://github.com/neoclide/coc.nvim'
and run :PlugInstall
After that restart Vimand make sure you have installed two important extensions, which are coc-json and coc-tsserver using :CocList extensions , if not run :CocInstall coc-json coc-tsserver
coc-clangd
As you can imagine, coc-clangd is an extension of coc.nvim like the previous two, and you can install it just by running :CocInstall coc-clangd , after that coc-clangd will try to find clangd from your $PATH , if not found, you can run :CocCommand clangd.install to install the latest release from GitHub.
At this point, you should be able to create ~/.vim/coc-settings.json file and add the code below to it
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
< "languageserver": < "ccls": < "command": "ccls", "args": ["--log-file=/tmp/ccls.log", "-v=1"], "filetypes": ["c", "cc", "cpp", "c++", "objc", "objcpp"], "rootPatterns": [".ccls", "compile_commands.json"], "initializationOptions": < "cache": < "directory": "/tmp/ccls" >, "client": < "snippetSupport": true > > > >, "clangd.path": "~/.config/coc/extensions/coc-clangd-data/install/15.0.6/clangd_15.0.6/bin/clangd", >
Obviusly, you should change the value of the “clangd.path” field with your version, it may be something like «clangd.path»: «~/.config/coc/extensions/coc-clangd-data/install//clangd_/bin/clangd» (note on the string).
I do not want to bore you by explaining whole fields of the json file, the only thing I would like to say to you is that this code is used to specify the type of language server ( ccls in this case) and its behavior.
ccls
Basically, ccls , which originates from cquery , is a C/C++/Objective-C language server.
- code completition (with both signature help and snippets)
- definition/reference, and other cross references
- diagnostics and code actions
- semantic highlighting and preprocessor skipped regions
- diagnostics and code actions
- semantic highlighting and preprocessor skipped regions
and the other many usefull things.
You must install it because, as you can see in the coc-settings.json , the language server specified is ccls .
You can do it using your package manager, in my case
sudo apt-get install ccls
Setup
Typically, ccls indexes an entire project. In order for this to work properly, ccls needs to be able to obtain the source file list and their compilation command lines.
How ccls obtains sources and compilation commands
There are two main ways this happens:
- Provide compile_commands.json at the project root
- Provide a .ccls file.
If neither exists, then when ccls starts it will not index anything: instead it will wait for LSP clients to open files and index only those files.
I prefer use the first one, and to do that if you are using Makefile as build system for your C/C++ project you can generate compile_commands.json automatically with bear command, I will explain in detail how in the next paragraph.
If you are not using Makefile as build system, there are lots of ways to generate this file, for example with CMake , compiledb , scan-build and so on. I suggest you to take a look here.
bear
Bear is a tool that generates a compilation database for clang tooling. The compilation database is our compile_commands.json , a simple json file.
The JSON compilation database is used in the clang project to provide information on how a single compilation unit is processed. With this, it is easy to re-run the compilation with alternate programs.
Some build system natively supports the generation of JSON compilation database. For projects which does not use such build tool, Bear generates the JSON file during the build process.
You can install it using your package manager, in my case
sudo apt-get install bear
Use case
Consider this simple C project, but it can be extended to much larger projects.
I assure you that it works exactly as in the case I am going to illustrate now, the only important thing is to write your makefile correctly, but this is also obvious because otherwise your project would not compile. 😀
1 2 3 4 5 6
. ├── inc/ │ └── main.h ├── src/ │ └── main.c └── Makefile
1 2 3
Vim как ide c
— insertion of various types of comments (file prologue, function descriptions, file section headers
keyword comments, date, time, . )
— insertion of empty control statements (if-else, while, do-while, switch, . )
— insertion of various preprocessor directives
— insertion of C-idioms (enum+typedef, loops, complete main, empty function, file open dialogs, . )
— insertion of C++ -idioms ( frames for simple classes and template classes, try-catch blocks,
file open dialogs, output manipulators, ios flags, . )
— use and organize your own collection of code snippets
— compile / link / run support for one-file projects (without a makefile)
— run buffer through splint
— personalization of comments (name, email, . )
— menus can be switched on and off (via the Tools menu)
DOCUMENTATION
———————————————————
This plug-in comes with a help file (csupport.txt). Read it with
** PLEASE READ THE DOCUMENTATION **
Editing actions differ for different modes! There are a lot of features which
can be configured or customized to match your needs.
(Please help us keep track of all the issues and name your report/request «C-Support: «)
To enable the tools for cmake or doxygen, add these lines to ~/.vimrc :
let g:C_UseTool_cmake = ‘yes’
let g:C_UseTool_doxygen = ‘yes’
For how to enable the Doxygen templates, see Chapter 1.10.1 of the documentation:
Click on the package to download.
— New template system (many thanks to Wolfgang Mehner)
— A few new hotkeys and menu item.
— A few hotkeys and menu items renamed.