Kappa plugins allow you to transform C code by visiting and modifying AST nodes. This guide will help you create your own plugin.
For examples and templates, check out the example-kappa-plugins directory.
Every Kappa plugin follows this basic structure:
export default class MyPlugin {
get testsSpec() {
return [];
}
async visit{NodeKind}(node, visitor, context) {
// Your transformation logic here
}
}A plugin uses the visitor pattern to traverse the AST. You can implement methods the following methods:
visit{NodeKind}(node, visitor, context)- Called when a node of kind{NodeKind}is encounteredvisitAny(node, visitor, context)- Called for every node (useful for debugging)
Finding Node Kinds: The are two easy ways to to discover available node kinds:
- using the
visitAny(node, visitor, context)method and printingnode.kind()during traversal - by exploring the
ast-grepplayground
Example:
async visitBinaryOperator(node, visitor) {
// Handle binary operations like +, -, *, /
}
async visitRecord(node, visitor) {
// Handle the `struct` statement
}Use these methods to transform the source code:
Replace an AST node with the provided raw code string.
Example:
visitor.updateDocumentNodeWithRawCode(integerNode, `Q(${value})`);Update the document after modifying a node's properties in-place.
Example:
integerNode.detail = `${Number(integerNode.detail) * 2}`;
visitor.updateDocumentFromNode(integerNode);Add a comment at the beginning of the line containing the specified node.
Example:
visitor.addLeadingComment(node, 'Example');Add a trailing comment after the specified node. When atEndOfLine is true, the comment will always be placed at the end of the line.
Example:
visitor.addTrailingComment(node, 'Example', true);Insert a new line of text before the specified node. When keepIdentation is true, the inserted text will maintain the same indentation as the node's line.
Example:
visitor.insertLineBeforeNode(node, 'printf("Debug: entering function");');Insert a new line of text after the specified node. When keepIdentation is true, the inserted text will maintain the same indentation as the node's line.
Example:
visitor.insertLineAfterNode(node, 'printf("Debug: exiting function");');Apply a regular expression replacement to the text content of the specified node's range.
Example:
visitor.applyRegexReplace(node, /\bint\b/g, 'int32_t');The testsSpec getter defines test cases for your plugin:
get testsSpec(): Array<{
name: string;
description: string;
given: string;
then: string;
}>Properties:
name- Short test case namedescription- What the plugin should dogiven- Input C code with a cursor position markerthen- Expected output after transformation
Cursor Position: Mark where the plugin should run using a comment with a single asterisk:
// *The plugin will execute at the column position of the asterisk on the following line.