Redirecting you to github in ... 3 seconds.
Cancel

Demo

--- DEMO VIDEO ---

Usages

How it works

C++ Snippet Assist parses c and c++ files and exposes the parsed data (Abstract Syntax Tree) to a scriptable environment. The code is then easily navigable and modifiable, similarly to how the Document Object Model(DOM) handles HTML and XML files.

C++ To AST Model Figure

To use, we simply run C++ snippet assist on a directory containing source files, after which we are ready to execute statements:

csa /path/to/cppdir

For example, we can find all nodes with the Time identifier:

csa> nodes('Time')
NodeCollection['class Time']

Considering our codebase containing the following class:

class Time{
private:
	unsigned char m_second;
	unsigned char m_minute;
	unsigned char m_hour;
};

we can use csa to scan all available fields:

csa> nodes('*', 'field')
NodeCollection['unsigned char m_second', 'unsigned char m_minute', 'unsigned char m_hour']

For each node we can apply a set of operations. The operations are available as custom plugins written in javascript and automatically loaded by csa. An already available plugin is the addGetter() method, which adds a getter method to each selected fields node:

csa> nodes('m_second').addGetter()

Which appends a getter method to our class:

class Time{
private:
	unsigned char m_second;
	unsigned char m_minute;
	unsigned char m_hour;

public:
    unsigned char second();
};
inline unsigned char Time::second(){
    return m_second;
}

Similar plugins can be created by simply manipulating the AST model. In the following example, we create a similar addInsideGetter() which adds the getter method inside the class:

function addInsideGetter(node){
    if ( node === null || typeof node === 'undefined' )
        throw new Error("Selected node is not of \'field'\ type.");

    // Get node name and extract getter name
    var nodeName = node.identifier();
    var getterName = (nodeName.indexOf('m_') === 0) ? nodeName.slice(2) : nodeName;

    // Create getter implementation
    var getterImplementation = node.prop('type') + ' ' + getterName + '(){ return ' + nodeName + ';}';

    // Get node parent, which is the class of the node
    var nodeClass = node.astParent()

    // Find the public section of the class
    var publicSection = nodeClass.lastChild('public', 'access');
    if ( publicSection )
        publicSection.after('\n    ' + getterImplementation);
    else
    // Create a public section if it doesn't exist
        classNode.append('\npublic:\n    ' + getterImplementation);
}

A prototype for the NodeCollection is also needed, where we apply call the global method on each selected node. The code is appended in the same file as the plugin:

NodeCollection.prototype.addInsideGetter = function(){
    this.nodes.forEach(function(v, i){
        addInsideGetter(v);
    });
    codeBase.save();
}

And then we use the csa interpreter to modify the previously open Time class:

csa> nodes('m_minute').addInsideGetter()

Which yields the following result:

class Time{
private:
	unsigned char m_second;
	unsigned char m_minute;
	unsigned char m_hour;

public:
    unsigned char minute(){ return m_minute;}
    unsigned char second();
};
inline unsigned char Time::second(){
    return m_second;
}