> Use when adding a compiler or tool output parser for the Problems panel. Touches src/diagnostics/<name>.ts, src/diagnostics/build.ts, package.json "new diagnostic parser", "parse compiler output".
npx skills add https://github.com/microsoft/vscode-cmake-tools --skill add-diagnostic-parser
Recipe for adding a new compiler or tool output parser to CMake Tools. A parser extracts diagnostics (errors, warnings, notes) from build output and surfaces them in the VS Code Problems panel.
Adding a parser touches 4 files (plus tests and changelog):
| File | What to do |
|---|---|
| src/diagnostics/<name>.ts | Create the parser class |
| src/diagnostics/build.ts | Register the parser in Compilers |
| package.json | Add to cmake.enabledOutputParsers enum |
| package.nls.json | Update description if user-visible text changes |
Create src/diagnostics/<name>.ts. Every parser extends RawDiagnosticParser (defined in src/diagnostics/util.ts) and exports a class named Parser.
// src/diagnostics/util.ts (simplified)
export abstract class RawDiagnosticParser {
get diagnostics(): readonly RawDiagnostic[] { /* accumulated results */ }
/** Called by the build consumer for every line of output. */
handleLine(line: string): boolean {
const result = this.doHandleLine(line);
if (result === FeedLineResult.Ok) return true; // line consumed, no new diagnostic
if (result === FeedLineResult.NotMine) return false; // line not recognized
// Otherwise result is a RawDiagnostic — it gets stored automatically
this._diagnostics.push(result);
return true;
}
/** Implement this. Return a RawDiagnostic to emit, or a FeedLineResult. */
protected abstract doHandleLine(line: string): RawDiagnostic | FeedLineResult;
}
/**
* Module for parsing <ToolName> diagnostics
*/ /** */
import * as vscode from 'vscode';
import { oneLess, RawDiagnosticParser, FeedLineResult } from '@cmt/diagnostics/util';
// Regex that captures: file, line, severity, code (optional), message
export const REGEX = /^(.+):(\d+):\s+(error|warning|info)\s+(\w+):\s+(.*)$/;
export class Parser extends RawDiagnosticParser {
doHandleLine(line: string) {
const mat = REGEX.exec(line);
if (!mat) {
return FeedLineResult.NotMine;
}
const [full, file, lineStr, severity, code, message] = mat;
const lineno = oneLess(lineStr); // convert 1-based to 0-based
return {
full,
file,
location: new vscode.Range(lineno, 0, lineno, 999),
severity,
message,
code,
related: []
};
}
}
For tools whose diagnostics span multiple lines, use internal state:
import { RawDiagnosticParser, RawDiagnostic, FeedLineResult, oneLess } from '@cmt/diagnostics/util';
enum ParserState { init, pending_message }
export class Parser extends RawDiagnosticParser {
private state = ParserState.init;
private pending: RawDiagnostic | null = null;
doHandleLine(line: string): RawDiagnostic | FeedLineResult {
switch (this.state) {
case ParserState.init: {
const mat = FIRST_LINE_REGEX.exec(line);
if (!mat) return FeedLineResult.NotMine;
this.pending = { /* ... build partial diagnostic ... */ };
this.state = ParserState.pending_message;
return FeedLineResult.Ok; // consumed, but not complete yet
}
case ParserState.pending_message: {
if (/* line completes the diagnostic */) {
const diag = this.pending!;
this.reset();
return diag; // emits the diagnostic
}
return FeedLineResult.Ok; // still accumulating
}
}
return FeedLineResult.NotMine;
}
}
// src/diagnostics/util.ts
interface RawDiagnostic {
full: string; // the full matched line(s)
file: string; // source file path
location: vscode.Range; // 0-based range (use oneLess() for 1-based input)
severity: string; // 'error' | 'warning' | 'note' | 'info' | 'fatal error' | 'remark'
message: string;
code?: string; // optional diagnostic code (e.g. 'C4996', 'LNK2019')
related: RawRelated[]; // related diagnostics (notes, template backtraces)
}
enum FeedLineResult {
Ok, // line was consumed (but no new diagnostic produced yet)
NotMine, // line not recognized by this parser
}
diagnosticSeverity() in util.ts maps the severity string to vscode.DiagnosticSeverity. Recognized values: 'error', 'fatal error', 'catastrophic error', 'warning', 'note', 'info', 'remark'.
src/diagnostics/build.tsImport the new parser module and add an instance to the Compilers class. The property name becomes the parser identifier used in cmake.enabledOutputParsers.
// At the top — add import
import * as myparser from '@cmt/diagnostics/myparser';
// Inside the Compilers class — add property
export class Compilers {
[compiler: string]: RawDiagnosticParser;
gcc = new gcc.Parser();
gnuld = new gnu_ld.Parser();
ghs = new ghs.Parser();
diab = new diab.Parser();
msvc = new mvsc.Parser();
iar = new iar.Parser();
iwyu = new iwyu.Parser();
myparser = new myparser.Parser(); // ← new parser
}
The CompileOutputConsumer.error() method iterates over all Compilers properties in declaration order, calling parser.handleLine(line). The first parser to return true claims the line — order matters if your parser's regex could match lines from another compiler.
The resolveDiagnostics() method filters diagnostics by config.enableOutputParsers — only parsers whose name appears in that array will have their diagnostics shown in the Problems panel.
package.jsonAdd the parser name to the cmake.enabledOutputParsers enum. Decide whether it should be default-enabled or opt-in.
// package.json → contributes.configuration → cmake.enabledOutputParsers
"cmake.enabledOutputParsers": {
"type": "array",
"items": {
"type": "string",
"enum": [
"cmake",
"gcc",
"gnuld",
"msvc",
"ghs",
"diab",
"iar",
"iwyu",
"myparser" // ← add to enum
]
},
"default": [
"cmake",
"gcc",
"gnuld",
"msvc",
"ghs",
"diab"
// only add here if default-enabled
]
}
package.nls.jsonIf any user-visible setting descriptions changed, update the localization key in package.nls.json. The cmake.enabledOutputParsers description uses the key cmake-tools.configuration.cmake.enabledOutputParsers.description.
Add tests in test/unit-tests/diagnostics.test.ts. The test pattern:
test('Parse <tool> error', () => {
const build_consumer = new diags.CompileOutputConsumer(
new ConfigurationReader({} as ExtensionConfigurationSettings)
);
// Feed real compiler output lines
build_consumer.error('<tool-specific output line>');
// Verify diagnostics
const parser = build_consumer.compilers.myparser;
expect(parser.diagnostics).to.have.length(1);
expect(parser.diagnostics[0].severity).to.eq('error');
expect(parser.diagnostics[0].file).to.eq('expected/file.cpp');
});
CHANGELOG.mdAdd an entry under the current version:
Features:
- Add `myparser` diagnostic parser for <ToolName> compiler output. [PR #XXXX](https://github.com/microsoft/vscode-cmake-tools/pull/XXXX)
| Property in Compilers | Module file | Default-enabled |
|---|---|---|
| gcc | src/diagnostics/gcc.ts | ✅ |
| gnuld | src/diagnostics/gnu-ld.ts | ✅ |
| ghs | src/diagnostics/ghs.ts | ✅ |
| diab | src/diagnostics/diab.ts | ✅ |
| msvc | src/diagnostics/msvc.ts | ✅ |
| iar | src/diagnostics/iar.ts | ❌ opt-in |
| iwyu | src/diagnostics/iwyu.ts | ❌ opt-in |
The cmake parser (in src/diagnostics/cmake.ts) is separate — it handles CMake's own configure/generate output via CMakeOutputConsumer, not build compiler output. It is listed in the enabledOutputParsers default array but is not part of the Compilers class.
cmake, gcc, gnuld, msvc, ghs, diab) are included in the "default" array in package.json. Users get them automatically.iar, iwyu) are in the "enum" but not in "default". Users must add them to their cmake.enabledOutputParsers setting.RawDiagnosticParser and exports as ParserdoHandleLine() returns FeedLineResult.NotMine for unrecognized linesdoHandleLine() returns a RawDiagnostic (not FeedLineResult.Ok) when a diagnostic is completeoneLess()Compilers class in src/diagnostics/build.tscmake.enabledOutputParsers enum in package.jsontest/unit-tests/diagnostics.test.ts passyarn compile succeedsCHANGELOG.md entry addedSee also: .github/copilot-instructions.md for project-wide conventions.
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
Automatically creates user-facing changelogs from git commits by analyzing commit history, categorizing changes, and transforming technical commits into clear, customer-friendly release notes. Turns hours of manual changelog writing into minutes of automated generation.
Use when implementation is complete, all tests pass, and you need to decide how to integrate the work - guides completion of development work by presenting structured options for merge, PR, or cleanup
Guide for creating high-quality MCP (Model Context Protocol) servers that enable LLMs to interact with external services through well-designed tools. Use when building MCP servers to integrate external APIs or services, whether in Python (FastMCP) or Node/TypeScript (MCP SDK).
React Native and Expo best practices for building performant mobile apps. Use when building React Native components, optimizing list performance, implementing animations, or working with native modules. Triggers on tasks involving React Native, Expo, mobile performance, or native platform APIs.
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
Next.js best practices - file conventions, RSC boundaries, data patterns, async APIs, metadata, error handling, route handlers, image/font optimization, bundling
Use when starting feature work that needs isolation from current workspace or before executing implementation plans - creates isolated git worktrees with smart directory selection and safety verification
Take microsoft/add-diagnostic-parser from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.