How do you get Vim to highlight C++ syntax errors like Visual Studio?

19,903

Solution 1

Short answer: Yes, but it won't be so smooth / immediate as in IDEs.

Long answer: Whereas IDEs have built-in support (and parsers, etc.) for a (usually very limited) set of programming languages, Vim is a general-purpose editor, and therefore has to rely on external tools to do the syntax checking. The built-in way is to execute :make and receive a list of (syntax or compiler) errors in the quickfix list. There are plugins to automate that; Syntastic is a very popular one with support for many languages.

But still, because Vim has to invoke an external executable and has little support for running tasks asynchronously, there will be more delay until you see the errors. If you can't do without the features of an IDE, it's fine to use both according to their strengths: Vim for super-efficient text editing, and the IDE for code navigation, debugging, and compilation.

Solution 2

VIM was good for years for me, but I moved to Sublime Text 3 when I realized how useful this editor is and how easy it is to extend this editor with more functionalities.

Now, I edit in Sublime Text and compile in the same application. I have made a syntax highlighter that shows the error in a nicer way, and if you click on the error it takes you to the place where the error happened.

Follow these steps and coding in c++ would be much simpler than before for you.

So after installing sublime_text and running it once you get a folder ~/HOME/.config/sublime-text-3/. If you aren't familiar with sublime_text it suffices to say that you can add your modifications into this folder ~/HOME/.config/sublime-text-3/Packages/User. Let's call this folder $SUBLIME_CONFIG_DIR from now on. What I am going to show you in here is how to add a build system for C++ and how to syntax highlight the output.

Setting Up the Build System

Create your build system by adding a file named c++build.sublime-build to $SUBLIME_CONFIG_DIR with the following contents:

{
  "shell" : true,
  "cmd": ["make $file_base_name"],
  "file_regex": "^(..[^:]*):([0-9]+):?([0-9]+)?:? (.*)$",
  "selector": "source.c++",
  "working_dir": "${file_path}",
  "syntax" : "Packages/User/c++output.tmLanguage"
}

I will explain what each line does. 1. "shell":true simply says that sublime should run a shell command if you call build on a file. 2. cmd will be executed when build is invoked. You can use g++ or anything else instead of make. This build configuration that I have put here is a starting point, you can modify it and make it do what you want. 3. selector tells sublime which files will automatically use this build (in this case all c++ files) 4. workig_dir I set it to current directory to make it easier 5. syntax when you build your file the output will be shown in the output view as plain text with no syntax highlighting. In here I am going to use C++output.tmLanguage file which I will explain later which helps you obtain a better highlighted output for easier debugging. 6. file_regex matches the error lines in the output and if there is an error, and you double-click on the error it takes you to the corresponding file.

Adding a New Syntax

There are various ways of adding new syntax highlighter to sublime. You can use JSON and then convert it to PList, you can use PList directly. For simplicity just copy the following in a file called c++output.tmLanguage. tmLanguage files are picked automatically by Sublime Text at startup of the application to highlight files.

the content should be as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>fileTypes</key>
  <array>
    <string>ssraw</string>
  </array>
  <key>name</key>
  <string>Mazanin</string>
  <key>patterns</key>
  <array>
    <dict>
      <key>match</key>
      <string>\b(error)\b</string>
      <key>name</key>
      <string>invalid.illegal</string>
    </dict>
    <dict>
      <key>match</key>
      <string>(warning|instantiation|note|required|candidate)</string>
      <key>name</key>
      <string>markup.quote</string>
    </dict>
    <dict>
      <key>match</key>
      <string>^.*:[0-9]+</string>
      <key>name</key>
      <string>support.variable.mazanin</string>
    </dict>
    <dict>
      <key>begin</key>
      <string>\[</string>
      <key>beginCaptures</key>
      <dict>
        <key>0</key>
        <dict>
          <key>name</key>
          <string>punctuation.definition.mazanin</string>
        </dict>
      </dict>
      <key>end</key>
      <string>\]</string>
      <key>endCaptures</key>
      <dict>
        <key>0</key>
        <dict>
          <key>name</key>
          <string>punctuation.definition.mazanin</string>
        </dict>
      </dict>
      <key>name</key>
      <string>comment.mazanin</string>
      <key>patterns</key>
      <array>
        <dict>
          <key>match</key>
          <string>\\.</string>
          <key>name</key>
          <string>source.mazanin</string>
        </dict>
      </array>
    </dict>
    <dict>
      <key>begin</key>
      <string>\(</string>
      <key>beginCaptures</key>
      <dict>
        <key>0</key>
        <dict>
          <key>name</key>
          <string>punctuation.definition.mazanin</string>
        </dict>
      </dict>
      <key>end</key>
      <string>\)</string>
      <key>endCaptures</key>
      <dict>
        <key>0</key>
        <dict>
          <key>name</key>
          <string>punctuation.definition.mazanin</string>
        </dict>
      </dict>
      <key>name</key>
      <string>storage.mazanin</string>
      <key>patterns</key>
      <array>
        <dict>
          <key>match</key>
          <string>\\.</string>
          <key>name</key>
          <string>source.mazanin</string>
        </dict>
      </array>
    </dict>
  </array>
  <key>scopeName</key>
  <string>source.cerr</string>
  <key>uuid</key>
  <string>ca03e751-04ef-4330-9a6b-9b99aae1c418</string>
</dict>
</plist>

Remember to replace the uuid (string) above with a unique uuid. But how do you get one. Open sublime-console and type in the followings:

import uuid
uuid.uuid4()

Now you are basically done. Open your c++ file, call build on that and you should be able to see the error highlighted and clickable as follows (I use Dawn theme).

This is the sample output for a simple program that fails with the error line wrapped

I personally prefer to wrap the lines of the output error and unwrap them fast so I have added this shortcut in my keymappings in $SUBLIME_CONFIG_DIR/Default (Linux).sublime-keymap which says:

[
  {
    "keys": ["ctrl+shift+l"], "command": "toggle_setting", "args": {"setting": "word_wrap"}
  }
]

Now if you prese ctrl+shift+l you can simply wrap/unwrap the output This is more useful in most of the cases when the errors are long and the information is not helpful. The above example without wrapping would look like:

With the error lines not wrapped

Using YAML

You can also use YAML to describe your syntax highlighting rules which is more concise and easier to modify. However, you need to have PackageDev installed on your sublime to be able to use the YAML language. Put the following file in your $HOME/.config/sublime-text-3/Packages/User and open it with sublime. Press F7 and the syntax file will be generated for you.

# [PackageDev] target_format: plist, ext: tmLanguage
---
name: C++ Error Output
scopeName: source.boo
fileTypes: [boo]
uuid: 45319b4d-90f8-4ff1-9a66-c56ed5c408a4

patterns:
- include: '#pars'
- include: '#bracs'
- include: '#anglebracs'
- include: '#quotes'
- include: '#curlies'
- match: \b((e|E)rror)\b
  name: invalid.illegal
- match: (warning|instantiation|note|required|candidate)
  name: markup.quote
- match: ^[^\:\s]*(?=:)
  name: support.variable
- match: (?<=:)[0-9]+
  name: keyword.control

repository:
  bracs:
    name: markup.quote
    begin: \[
    beginCaptures:
      '0': {name: keyword}
    end: \]
    endCaptures:
      '0': {name: keyword}
    patterns:
    - include: $self
    - include: anglebracs
    - include: pars
  pars:
    name: variable.parameter
    begin: \(
    beginCaptures:
      '0': {name: keyword}
    end: (\)|$)
    endCaptures:
      '0': {name: keyword}
    patterns:
    - include: $self
    - include: anglebracs
  anglebracs:
    name: markup.raw
    begin: (?<!<)\<(?!\<)
    beginCaptures:
      '0': {name: keyword}
    end: \>
    endCaptures:
      '0': {name: keyword}
    patterns:
    - include: $self
    - include: pars
  quotes:
    name: markup.heading
    begin: ‘
    beginCaptures:
      '0': {name: keyword}
    end: ’
    endCaptures:
      '0': {name: keyword}
    patterns:
    - include: $self
    - include: anglebracs
    - include: pars
    - include: bracs
  curlies:
    name: markup.list
    begin: \{
    beginCaptures:
      '0': {name: keyword}
    end: \}
    endCaptures:
      '0': {name: keyword}
    patterns:
    - include: $self
    - include: anglebracs
    - include: pars
    - include: bracs
...

You can find a list of color names in here

Share:
19,903

Related videos on Youtube

teknix
Author by

teknix

Updated on June 12, 2022

Comments

  • teknix
    teknix almost 2 years

    Is it possible to get gVim to highlight C++ syntax errors (the red squiggles underneath) in real-time like Visual Studio?

  • Michael Younkin
    Michael Younkin almost 10 years
    This doesn't answer the question, which was specifically about Vim.
  • THC
    THC over 7 years
    Whilst this answer is instructive, I agree it doesn't answer the question - at all.
  • edwinc
    edwinc about 3 years
    vim provides similar build and error highlights