Skip to content

Instantly share code, notes, and snippets.

@Velro
Created August 18, 2018 03:39
Show Gist options
  • Save Velro/b27723f07b2b12351108251f5b1baf38 to your computer and use it in GitHub Desktop.
Save Velro/b27723f07b2b12351108251f5b1baf38 to your computer and use it in GitHub Desktop.
Go to next error CLI setup for C++
REM This is the file where I compile my whole project
REM This outputs the errors into clang_output.log and the terminal. We are forcing clang to output color and with absolute file paths.
REM -fcolor-diagnostics and -fansi-escape-codes forces clang to output color codes, which is nice for the console output
clang-cl -ferror-limit=10 ^
-fdiagnostics-absolute-paths ^
-fcolor-diagnostics ^
-fansi-escape-codes ^
-fuse-ld=lld-link ^
-o my_program.exe ^
my_program.cpp 2>&1 | tee clang_output.log
REM helper batch file I keep at the top-level of my project
@echo off
compiler/build/project/clang/build.bat
REM Reset error indexing util program
SET COMPILATION_ERROR_INDEX=0
REM top level batch to call to open vim to the next error in your project
@echo off
vim_clang_next_error.exe ^
clang_output.log ^
%COMPILATION_ERROR_INDEX%
SET /A COMPILATION_ERROR_INDEX += 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char * argv[])
{
if (argc < 3) /*no command specified*/
{
fprintf(stderr, "Usage: clang_vim_next_error clang_output.log error_number\n");
exit(EXIT_FAILURE);
}
else
{
FILE * fileStream;
errno_t fileError = fopen_s(&fileStream, argv[1], "r");
if (fileError != 0) {
fprintf(stderr, "Couldn't open file\n");
return 1;
}
int requestedErrorIndex = atoi(argv[2]);
//printf("Requested error index: %d\n", requestedErrorIndex);
// obtain file size
fseek(fileStream, 0, SEEK_END);
long fileSize = ftell(fileStream);
rewind(fileStream);
// dump file to memory
char * file = (char *)calloc(1, sizeof(char)*fileSize);
fread(file, 1, fileSize, fileStream);
fclose(fileStream);
/* An example error with clang-cl.
*C:\projects\zah\compiler\code\source\zah_parser.cpp(440,18): error: use of undeclared identifier 'decl'
* TokenToType(&decl->type, typeTok);
*
* A clang error has a slightly different format, the numbers are given like Ex. file.cpp:440:18: ....
*/
//
// backslash to forward slash
//
for (char * ptr = file; ptr < file + fileSize; ++ptr) {
if (*ptr == '\\') {
*ptr = '/';
}
}
//
// count number of errors
//
char * errorLocations[512] = {};
int errorCount = 0;
char * lastErrorLoc = file;
while (true) {
char * duh = lastErrorLoc;
lastErrorLoc = strstr(duh, "error: ");
if (!lastErrorLoc) {
break;
}
errorLocations[errorCount++] = lastErrorLoc;
// eat forward so we don't get the same result again
lastErrorLoc++;
}
//printf("Error count: %d", errorCount);
// loop to first error if requested index is over count
requestedErrorIndex = requestedErrorIndex % errorCount;
//
// Find requested error and extract info
//
char * errorLoc = errorLocations[requestedErrorIndex];
char * errorLineNumberStart = nullptr;
char * errorColumnNumberStart = nullptr;
char filename[512] = {};
// search backwards for line and column number
for (char * ptr = errorLoc; errorLoc > file; ptr--) {
if (*ptr == ',' && !errorColumnNumberStart) {
errorColumnNumberStart = ptr + 1;
}
if (*ptr == '(' && !errorLineNumberStart) {
errorLineNumberStart = ptr + 1;
}
if (*ptr == '\n') {
bool found = false;
char * localPtr = ptr + 1;
for (localPtr = ptr + 1; localPtr < file + fileSize; ++localPtr) {
// sometimes there's a second escape?
if (*localPtr == '\x6D' && *(localPtr + 4) != '\x6D') {
localPtr++; // eat past escape character
char * filenameStart = localPtr;
int filenameLength = errorLineNumberStart - filenameStart - 1;
memcpy(&filename[0], filenameStart, filenameLength);
found = true;
break; // inner loop
}
}
if (found) {
break; // outer loop
}
printf("Trouble parsing error\n");
break;
}
if (ptr == file + 1) {
printf("Trouble parsing error\n");
break;
}
}
if (!errorLoc || !errorLineNumberStart || !errorColumnNumberStart) {
fprintf(stderr, "Trouble parsing error\n");
return 1;
}
//
// Build vim command
//
int lineNumber = atoi(errorLineNumberStart);
int columnNumber = atoi(errorColumnNumberStart);
char buf[512] = {};
snprintf(buf, 512, "gvim --remote-silent \"+call cursor(%d, %d)\" %s",
lineNumber,
columnNumber,
&filename[0]);
//puts(buf);
// call shell
system(buf);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment