Skip to content

Instantly share code, notes, and snippets.

@yzdann
Created September 9, 2020 06:32
Show Gist options
  • Select an option

  • Save yzdann/45ab0175bdca7524e6059cde7f1a68c8 to your computer and use it in GitHub Desktop.

Select an option

Save yzdann/45ab0175bdca7524e6059cde7f1a68c8 to your computer and use it in GitHub Desktop.

Revisions

  1. @adembudak adembudak revised this gist Sep 4, 2020. 1 changed file with 26 additions and 24 deletions.
    50 changes: 26 additions & 24 deletions VimForCppDevelopment.md
    Original file line number Diff line number Diff line change
    @@ -1,9 +1,10 @@

    - [Intro](#intro)
    * [Problem](#problem)
    * [Solution](#solution)
    - [Setup](#setup)
    * [Server](#server)
    * [Client](#client)
    * [A server](#a-server)
    * [A client](#a-client)
    * [compile_commands.json file generation](#compile-commandsjson-file-generation)
    - [Linting](#linting)
    - [Code formatting](#code-formatting)
    @@ -13,8 +14,8 @@
    ## Intro

    I want to share how I use Vim as C++ development environment, adding things like
    code completion, linting, formatting, snippet. If you come from the IDE land and
    have been set your options with the checks box on a GUI, you might need mental shift to use
    code completion, linting, formatting and snippet support. If you come from the IDE land and
    have been set your options with the checkbox on a GUI, you might need a mental shift to use
    text based configuration tools, like Vim.

    ### Problem
    @@ -24,7 +25,7 @@ successful, some others evolved, yet others deprecated. I tried plugins like
    YouCompleteMe, they were great but the process that making them work wasn't a
    pleasant experience.

    Creating a completion engine admittedly hard, porting those code other editors
    Creating a completion engine admittedly hard, porting those code to other editors
    without touching implementation details is virtually impossible.

    ### Solution
    @@ -71,7 +72,7 @@ apt-get install -qq clang-11 clang-tools-11 clang-11-doc libclang-common-11-dev
    ```
    ... and that's it. Now along with the clangd, I have the latest stable C++
    compiler, standard library implementation (that I can enjoy latest features
    added to language), a linter and a code formatter. We got the server, what
    added to the language), a linter and a code formatter. We got the server, what
    about the client?

    ### A client
    @@ -88,7 +89,7 @@ apt-get install npm
    To add the coc.nvim and other plugins in easy way, a plugin manager required. Again, various
    options are available, I'll use [vim-plug](https://github.com/junegunn/vim-plug):

    `.vimrc`:
    `.vim/vimrc`:
    ```
    call plug#begin('~/.vim/plugged')
    @@ -100,9 +101,9 @@ Plug 'neoclide/coc.nvim', {'for':['zig','cmake','rust',
    call plug#end()
    ```

    This is from my .vimrc file. Plugins are listed between `plug#begin` and
    This is from my vimrc file. Plugins are listed between `plug#begin` and
    `plug#end` as `Plug 'Github_URI_path'`. It allows plugins work with certain filetype, which listed after
    `for`. I don't need and want this plugin to work other filetypes, like .txt, .md etc.
    `for`. I don't need and want this plugin to work other with filetypes, like .txt, .md etc.

    `:PlugInstall` will install and `:PlugUpdate` update the plugins. A common
    ritual among the vimmers, once plugin installed, reading its doc. Usually available with `:help pluginName`.
    @@ -133,14 +134,13 @@ now, I'll just register language server and leave others default:
    "--all-scopes-completion",
    "--background-index",
    "--clang-tidy",
    "--cross-file-rename",
    "--completion-parse=always",
    "--completion-style=detailed",
    "--cross-file-rename",
    "--function-arg-placeholders",
    "--header-insertion-decorators",
    "--query-driver=/usr/bin/**/clang-*,/home/adem/GCC-10/bin/g++*",
    "--header-insertion=never",
    "--cross-file-rename",
    "--limit-results=0",
    "-j=6",
    "--pch-storage=memory",
    @@ -152,7 +152,7 @@ now, I'll just register language server and leave others default:

    This calls clangd with the parameters listed on args array. Check out all options of clangd with `clangd --help`.

    You can add any number of server to `languageserver` object, that way you can
    You can add any number of server to `languageserver` object. That way you can
    have same editing experience, mapping, theme, etc for different languages on the same editor:
    ```
    {
    @@ -194,20 +194,20 @@ command.

    ## Linting

    The [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) linting tool can be
    called via clangd. A linter is a tool that shout out the fishy parts of
    The [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) linter can be
    called via clangd. A linter is a tool that shouts out the fishy parts of
    the code. Make sure passed `--clang-tidy` arg to clangd on coc-setting.json file.

    You can enable some family of checks, and dump it into a file:
    ```
    clang-tidy --checks='-*,bugprone-*' --dump-config > .clang-tidy;
    clang-tidy --checks='-*,bugprone-*' --dump-config > .clang-tidy
    ```
    Clangd will detect this file and lint your code based on some criteria. See all
    checks with: `clang-tidy --list-checks`

    ## Code formatting

    People used [aspell](http://aspell.net) and some other tools to format their code, As a millennial, my
    People used [AStyle](http://astyle.sourceforge.net) and some other tools to format their code. As a millennial, my
    first encounter with such a tool happen with
    [clang-format](https://clang.llvm.org/docs/ClangFormat.html). It's fairly easy
    to use:
    @@ -218,7 +218,7 @@ clang-format -i source.cpp
    [vim-clang-format](https://github.com/rhysd/vim-clang-format) plugin allows us to use clang-format
    in automatized way, like formatting on every save:

    `vimrc`:
    `.vim/vimrc`:
    ```
    " between plug#begin/plug#end
    Plug 'rhysd/vim-clang-format', {'for' : ['c', 'cpp']}
    @@ -232,12 +232,13 @@ Snippets are kind of underappreciated helpers. They reduce repetitive,
    no-brainer jobs. Install coc.nvim snippet extension: `:CocInstall coc-snippets`

    Let extension know where to find snippets:
    `coc-settings.json`:

    `.vim/coc-settings.json`:
    ```shell
    "snippets.textmateSnippetsRoots": ["/home/adem/.config/snippets"],
    ```

    On daily configurations when I type `cmake` it extends to:
    On daily coding, when I type `cmake`, it extends to:
    ```
    cmake_minimum_required(VERSION |)
    @@ -249,7 +250,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    |
    ```
    where each `|` waiting to be typed. Writing such a snippet is pretty easy. Just
    like in VSCode, it's JSON file:
    like in VSCode, it's a JSON file:

    `/home/adem/.config/snippets/cmake.json`:
    ```
    @@ -284,14 +285,15 @@ this. Here is an example mapping:
    ```
    nnoremap <F5> :SCCompileRunAF -g -Wall -Wextra -std=c++2a<cr>
    ```
    When I press <F5>, it compiles and run the executable. More on `:h SingleCompile`
    When I press `<F5>`, it compiles and run the executable. More on `:h SingleCompile`

    ---

    This client-server architecture in mind, you can use similar setup on other
    platforms. In Windows, you can install get Windows binaries from
    LLVM and use clangd with VSCode with [clangd extension](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd). On Emacs, there is
    a [lsp mode](https://github.com/emacs-lsp/lsp-mode) support.
    platforms. In Windows, you can get Windows binaries of LLVM and use clangd on
    VSCode with [clangd
    extension](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd).
    On Emacs, there is a [lsp mode](https://github.com/emacs-lsp/lsp-mode) support.

    Feel free to embarrass me what I made with this post :) Thanks for reading.

  2. @adembudak adembudak created this gist Sep 3, 2020.
    298 changes: 298 additions & 0 deletions VimForCppDevelopment.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,298 @@
    - [Intro](#intro)
    * [Problem](#problem)
    * [Solution](#solution)
    - [Setup](#setup)
    * [Server](#server)
    * [Client](#client)
    * [compile_commands.json file generation](#compile-commandsjson-file-generation)
    - [Linting](#linting)
    - [Code formatting](#code-formatting)
    - [Snippets](#snippets)
    - [One shot compilations](#one-shot-compilations)

    ## Intro

    I want to share how I use Vim as C++ development environment, adding things like
    code completion, linting, formatting, snippet. If you come from the IDE land and
    have been set your options with the checks box on a GUI, you might need mental shift to use
    text based configuration tools, like Vim.

    ### Problem

    There has been plugins to provide IDE-like features to Vim. Some of them were
    successful, some others evolved, yet others deprecated. I tried plugins like
    YouCompleteMe, they were great but the process that making them work wasn't a
    pleasant experience.

    Creating a completion engine admittedly hard, porting those code other editors
    without touching implementation details is virtually impossible.

    ### Solution

    [The language server protocol](https://microsoft.github.io/language-server-protocol) developed solve
    this problem. The idea is, create a set of rule and implement a server and a
    client that follows the rules, then communicate over the protocol and provide
    functionalities like auto complete, go-to definition, search function calls,
    diagnostics.

    Quoting from its [website](https://langserver.org):

    > LSP creates the opportunity to reduce the m-times-n complexity problem of
    > providing a high level of support for any programming language in any editor,
    > IDE, or client endpoint to a simpler m-plus-n problem.
    ## Setup

    The *server* needs to installed on the host system, and *client* needs to provided
    by the editor, either as a plugin or build-in. In Vim, it must be a plugin, NeoVim has
    an [experimental support](https://github.com/neovim/nvim-lspconfig). Some IDEs,
    like CLion, ship both out of package... with a price.

    ### A server

    There are two actively developed language servers for C++:
    [clangd](https://clangd.llvm.org/) and [ccls](https://github.com/MaskRay/ccls).
    Both are great. I found clangd is somewhat easier to
    install. Precompiled binaries are available in
    [here](https://releases.llvm.org/download.html). APT packages also available at
    [https://apt.llvm.org](https://apt.llvm.org). On my fresh installed Debian
    10, I just use:

    ```bash
    apt-add-repository 'deb http://apt.llvm.org/buster/ llvm-toolchain-buster-11 main'

    wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -

    apt-get update

    apt-get install -qq clang-11 clang-tools-11 clang-11-doc libclang-common-11-dev \
    libclang-11-dev libclang1-11 clang-format-11 clangd-11 clang-tidy-11 \
    libc++-11-dev libc++abi-11-dev
    ```
    ... and that's it. Now along with the clangd, I have the latest stable C++
    compiler, standard library implementation (that I can enjoy latest features
    added to language), a linter and a code formatter. We got the server, what
    about the client?

    ### A client

    To make use of clangd, we'll need a language client.
    [Various](https://langserver.org) implementations are available, I'll use
    [coc.nvim](https://github.com/neoclide/coc.nvim/). It's written in
    [TypeScript](https://www.typescriptlang.org) needs
    [Node.js](https://nodejs.org/en) runtime:
    ```
    apt-get install npm
    ```

    To add the coc.nvim and other plugins in easy way, a plugin manager required. Again, various
    options are available, I'll use [vim-plug](https://github.com/junegunn/vim-plug):

    `.vimrc`:
    ```
    call plug#begin('~/.vim/plugged')
    Plug 'neoclide/coc.nvim', {'for':['zig','cmake','rust',
    \'java','json', 'haskell', 'ts','sh', 'cs',
    \'yaml', 'c', 'cpp', 'd', 'go',
    \'python', 'dart', 'javascript', 'vim'], 'branch': 'release'}
    call plug#end()
    ```

    This is from my .vimrc file. Plugins are listed between `plug#begin` and
    `plug#end` as `Plug 'Github_URI_path'`. It allows plugins work with certain filetype, which listed after
    `for`. I don't need and want this plugin to work other filetypes, like .txt, .md etc.

    `:PlugInstall` will install and `:PlugUpdate` update the plugins. A common
    ritual among the vimmers, once plugin installed, reading its doc. Usually available with `:help pluginName`.

    coc.nvim holds server configurations in a JSON file called `coc-settings.json`
    (with `:CocConfig`). You can customize almost everything the way server behave.
    Check out full scheme from
    [here](https://github.com/neoclide/coc.nvim/blob/master/data/schema.json). For
    now, I'll just register language server and leave others default:

    `.vim/coc-settings.json`:
    ```
    {
    "languageserver":{
    "clangd":{
    "command":"clangd",
    "filetypes":[
    "c",
    "cpp"
    ],
    "rootPatterns":[
    "compile_commands.json",
    ".git"
    ],
    "args":[
    "--compile-commands-dir=build",
    "--compile_args_from=filesystem",
    "--all-scopes-completion",
    "--background-index",
    "--clang-tidy",
    "--completion-parse=always",
    "--completion-style=detailed",
    "--cross-file-rename",
    "--function-arg-placeholders",
    "--header-insertion-decorators",
    "--query-driver=/usr/bin/**/clang-*,/home/adem/GCC-10/bin/g++*",
    "--header-insertion=never",
    "--cross-file-rename",
    "--limit-results=0",
    "-j=6",
    "--pch-storage=memory",
    ]
    }
    }
    }
    ```

    This calls clangd with the parameters listed on args array. Check out all options of clangd with `clangd --help`.

    You can add any number of server to `languageserver` object, that way you can
    have same editing experience, mapping, theme, etc for different languages on the same editor:
    ```
    {
    "languageserver":{
    "clangd":{
    // clangd options
    },
    "rls" {
    // rls options
    },
    "bash-lsp" {
    // bash-lsp options
    }
    }
    }
    ```
    For mappings (a term used for reassignable shortcuts in Vim), begin with the [example
    configuration](https://github.com/neoclide/coc.nvim/#example-vim-configuration).
    If you want to take a look, this idiot holds [his configurations](https://github.com/p1v0t/dotfiles) on
    Github.

    Now got the server and client, but need one more thing.

    ## compile_commands.json file generation

    The last part of the ceremony involves using [CMake](https://cmake.org).
    All we need is, adding a single line definition on toplevel CMakeLists.txt:
    ```
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    ```
    This generates a file called
    [compile_commands.json](https://clang.llvm.org/docs/JSONCompilationDatabase.html)
    on build directory. It contains include paths, compiler command and options.
    These helps clangd to figure out what is where.

    If the project don't use CMake, but make, you can use
    [Bear](https://github.com/rizsotto/Bear) to generate this file with `bear make`
    command.

    ## Linting

    The [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) linting tool can be
    called via clangd. A linter is a tool that shout out the fishy parts of
    the code. Make sure passed `--clang-tidy` arg to clangd on coc-setting.json file.

    You can enable some family of checks, and dump it into a file:
    ```
    clang-tidy --checks='-*,bugprone-*' --dump-config > .clang-tidy;
    ```
    Clangd will detect this file and lint your code based on some criteria. See all
    checks with: `clang-tidy --list-checks`

    ## Code formatting

    People used [aspell](http://aspell.net) and some other tools to format their code, As a millennial, my
    first encounter with such a tool happen with
    [clang-format](https://clang.llvm.org/docs/ClangFormat.html). It's fairly easy
    to use:
    ```
    clang-format -i source.cpp
    ```

    [vim-clang-format](https://github.com/rhysd/vim-clang-format) plugin allows us to use clang-format
    in automatized way, like formatting on every save:

    `vimrc`:
    ```
    " between plug#begin/plug#end
    Plug 'rhysd/vim-clang-format', {'for' : ['c', 'cpp']}
    let g:clang_format#auto_format=1
    ```

    ## Snippets

    Snippets are kind of underappreciated helpers. They reduce repetitive,
    no-brainer jobs. Install coc.nvim snippet extension: `:CocInstall coc-snippets`

    Let extension know where to find snippets:
    `coc-settings.json`:
    ```shell
    "snippets.textmateSnippetsRoots": ["/home/adem/.config/snippets"],
    ```

    On daily configurations when I type `cmake` it extends to:
    ```
    cmake_minimum_required(VERSION |)
    DESCRIPTION "|"
    HOMEPAGE_URL https://github.com/p1v0t/ |
    LANGUAGES CXX)
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    |
    ```
    where each `|` waiting to be typed. Writing such a snippet is pretty easy. Just
    like in VSCode, it's JSON file:

    `/home/adem/.config/snippets/cmake.json`:
    ```
    {
    "cmake": {
    "prefix": [
    "cmake"
    ],
    "body": [
    "cmake_minimum_required(VERSION ${1:version})",
    "",
    "project(${2:projname}",
    "DESCRIPTION \"${3:description}\"",
    "HOMEPAGE_URL https://github.com/p1v0t/${4:reponame}",
    "LANGUAGES CXX)",
    "",
    "set(CMAKE_EXPORT_COMPILE_COMMANDS ON)",
    "${0}"
    ]
    }
    }
    ```

    There is also [an extension](https://github.com/voldikss/coc-cmake) for CMake which
    provides basic completion. See list of extensions in [here](https://github.com/neoclide).

    ## One shot compilations

    If you like to write small programs and don't need to build,
    [SingleCompile](https://github.com/vim-scripts/SingleCompile) plugin is just for
    this. Here is an example mapping:
    ```
    nnoremap <F5> :SCCompileRunAF -g -Wall -Wextra -std=c++2a<cr>
    ```
    When I press <F5>, it compiles and run the executable. More on `:h SingleCompile`

    ---

    This client-server architecture in mind, you can use similar setup on other
    platforms. In Windows, you can install get Windows binaries from
    LLVM and use clangd with VSCode with [clangd extension](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.vscode-clangd). On Emacs, there is
    a [lsp mode](https://github.com/emacs-lsp/lsp-mode) support.

    Feel free to embarrass me what I made with this post :) Thanks for reading.

    ---