Codalogic Code Scrapbook
Version 0.2
Document Revision 1
Copyright © 2011 Codalogic Ltd.

Introduction

Codalogic Code Scrapbook is a simple app designed to improve programmer productivity by acting as a repository for commonly used snippets of code that can be easily pasted into a program.

Code Scrapbook has a macro expansion feature so that code snippets can be easily customized for a particular usage; for example, capturing the name of a class, or a file. Templates for snippets are defined by the user, and can be added, deleted, modified and organised as the user requires.

Contents

[Top] [Contents]

1 - Screen Layout

On the left side of the Code Scrapbook app is a tree view which allows selection, addition and removal of snippet templates. Addition and removal of snippet templates is achieved via the right-click context menu associated with the tree view. (Note that each snippet template is stored in its own file and users my find it easier to edit snippet templates directly using their preferred editor rather that using the editor in Code Scrapbook.)

Below the tree view on the left-hand side is a button to set options for Code Scrapbook; such as the directories where the snippet templates are stored and whether auto-copying of generated code is enabled. Multiple directories can be specified for storing snippet templates. This enables, for example, for a centralized corporate set of templates to be specified, plus general personal templates, and perhaps project specific templates.

The right side of the app allows you to interact with the selected snippet template. This is a tabbed window which allows you to either edit the template, or run the template.

When a template is being run, the top part of the screen displays controls that capture information from the user. The information that is captured is specified in the template, and can be text, checkbox results, and/or radio button results. Below this is displayed the expanded snippet with the relevant information captured from the user displayed in it.

Code Scrapbook can automatically copy the generated snippet to the clipboard (ready for pasting into another application) when it loses focus, hence there is normally no need to press the "Copy Generated Code" button when you have entered all the required information. The generated snippet can also be saved to a file using the "Save to file..." button. If only part of the generated code is wanted, select that part in the generated code text window before doing a copy or save to file operation.

[Top] [Contents]

2 - Defining Templates

Code Scrapbook uses templates (also known as snippet templates) to define the code to be generated. A template is used to generate a snippet, which can be pasted into another application.

A template has two sections; a data capture section and a snippet format section. The data capture section allows a user to specify the data the template needs the user to enter in order to create the snippet. For example, the data capture section may specify that the user needs to enter the name of a class, or whether a class method should be constant. The snippet format section describes the format of the snippet and where the data captured from the user should be placed.

The data capture section appears at the start of a template file. The end of the data capture section and the beginning of the snippet format section is marked by a line containing a single dot character ('.'). The snippet format section forms the remainder of the file. For example, in the following:

	text.user_name: What is your name
	.
	Hello ^user_name$

the text text.user_name: What is your name forms the data capture section and the text Hello ^user_name$ forms the snippet format section.

[Top] [Contents]

2.1 - The Data Capture Section

The data capture section specifies the data needed to be captured from the user for the snippet to be generated. The data capture section may contain blank lines. Anything after a '#' character until the end of a line is treated as a comment.

	# This is a comment

	# The blank line above is ignored
	text.user_name: What is your name	# This is also a comment

The data capture section can specify single line text input, checkbox input and radio button input. The section can also specify expression and map pseudo-input, which allows common sub-expressions to be defined that rely on the values of the other inputs.

Each input specification is defined on its own line and generally has the format:

	{type of control}.{name of control}:{question}
or:
	{type of control}.{name of control}[{default value}]:{question}
For example:
	checkbox.want_more[yes]: More explanation required
creates a checkbox control named want_more, with the label More explanation required and being checked when initially displayed.

[Top] [Contents]

2.1.1 - Specifying single line text input

To specify single line text input, set the type of control to text, for example:

	text.user_name: User name
or:
	text.user_name[Super User]: User name

The latter creates a text box named user_name, has the initial value set to Super User and the label User name.

Text input is actually displayed as a combo box with a history of recently used values associated with the name of the control included in the pull-down. As a special case for text input, a default value of .. will initialise the text field to the value previously associated with the name of the control. Thus, by using consistent naming in templates, information such as a class name can be automatically inserted into a text input field without any typing. An example usage of this feature is:

	text.class[..]: Class name

[Top] [Contents]

2.1.2 - Specifying checkbox input

To specify checkbox input, set the type of control to checkbox, for example:

	checkbox.is_const: Method is const
or:
	checkbox.is_const[on]: Method is const

These examples create a checkbox that is named is_const and has the label Method is const.

By default checkboxes are created unchecked. The latter case above shows how to create a checkbox that is initially checked. Setting the default to any value that resolves to true will result in the checkbox being initially checked. See 5 - True or False Values for what values correspond to true.

[Top] [Contents]

2.1.3 - Specifying radio button input

Creating radio buttons is slightly more complex than creating text input or checkbox input. Firstly you need to define a radiogroup and then within that define multiple radio buttons.

The radiogroup directive defines a labelled box that goes around the associated set of radio buttons. The format of a radiogroup specifier is:

	radiogroup.{name of radio group}:{label}
For example:
	radiogroup.color: Select a color

Within the radiogroup, each radio button is defined using the form:

	radio.{name of radio group}.{name of radio button}:{label}

or:

	radio.{name of radio group}.{name of radio button}[{default}]:{label}

For example:

	radio.color.red: Red

Each radio directive displays a radio button and results in a variable being defined that has the name: {name of radio group}.{name of radio button}. In the case of the latter example, the defined variable would be color.red.

One of the variables created by the radio button directives within a radio group will have a true value and all other radio button variables within the group will be set to false.

If a radio button named {name of radio group}.{name of radio button} has the value true, then a snippet format variable named {name of radio group} will be set to the value {name of radio button}.

A complete example for a radio group and associated radio buttons is:

	radiogroup.color: Select a color
	radio.color.red: Red
	radio.color.green: Green
	radio.color.blue: Blue

[Top] [Contents]

2.1.4 - Specifying expression pseudo-input

The expression pseudo-input allows you to define a repeatedly used expression in a variable rather than having to repeatedly copy and paste the expression within the snippet format section.

The format of an expression pseudo-input is:

	expr.{name of expression}: {expression}

For example:

	expr.full_name: ^first_name$ ^last_name$

[Top] [Contents]

2.1.5 - Specifying map pseudo-input

The map keyword is an alias of the expr keyword. Hence the map pseudo-input is identical to the expression pseudo-input, but in some use-cases calling the control a map rather than an expression makes more sense.

The format of an map pseudo-input is:

	map.{name of map}: {mapped text}

For example:

	radiogroup.control: Type of control
	radio.control.button: Button
	radio.control.text: Text control
	map.button_handler: EVT_BUTTON
	map.text_handler: EVT_TEXT

[Top] [Contents]

2.2 - The Snippet Format Section

The snippet format section defines the contents of the snippet and where the information captured by the data capture section should be placed.

The contents of the snippet format section are copied to the output character by character until a directive is found. On encountering a directive, the directive is resolved, it's value output, and then the parser returns to copying subsequent characters to the output.

The simplest directive has the form:

	^{variable or function name}$
The ^ character marks the beginning of the directive and the $ marks the end of the directive. (Hopefully these are easy to remember as they are the beginning and end anchors for regular expressions.) This form of directive would result in the value of the named variable being output. For example, if you had the following template:

	text.user_name: What is your name
	.
	Hello ^user_name$

and the user entered Alice in the What is your name text box, the generated output would be:

	Hello Alice

Functions will be described further later.

There are two other forms that a directive can take, these being:

	^{conditional}?{text if condition is true}$
and:
	^{conditional}?{text if condition is true}?{text if condition is false}$

Note the ? characters separating the various parts of the directive.

Within the conditional part of the directive whitespace is not significant. Whitespace is significant in the other parts of the directive.

The simplest form of conditional is the name of a variable. If, as per 5 - True or False Values, the variable has a true value, then the {text if condition is true} part of the directive will be output, otherwise, if present, the {text if condition is false} part of the directive will be output. For example, with the following directive:

	^color.red?You have selected Red?So you don't like Red!$

if color.red is true, the output would be:

	You have selected Red

The value of variables in the conditional section can be negated by preceding them with a ! character. Multiple variables can be combined in a conditional using | as an OR operator and & as an AND operator. Brackets may also be used to group sub-expressions together. For example:

	^ color.green | color.blue ?I like those colors too$
	^ ! color.red ?I like those colors too$

The {text if condition is true} and {text if condition is false} parts of the directive may contain additional nested directives.

Observe that there is no else if type construct (such as elif or elsif). To create such a construct you need to nest another conditional directive within the {text if condition is false} part of the directive. Both the outer and nested directives will need to be terminated by their own $ characters and so the combined expression will end with (at least) two $ characters, for example:

	You chose ^ color.red ?Red?^ color.green ?Green?Blue$$.
Here, the directive ^ color.green ?Green?Blue$ forms the {text if condition is false} part of the directive ^ color.red ?Red?...$. Naturally deeper nesting will require correspondingly more $ characters at the end of the directive.

Directives can be split across multiple lines. To aid formatting where the presence or absence of a set of code lines depends on the value of a conditional, the snippet template can be formatted as, for example:

	^ want_destructor ?
	~^ class $();
	$

Here the whitespace and carriage returns associated with lines beginning with a ^ character and ending with a ? character, or lines containing just $ characters will not be output.

It was mentioned earlier that functions could be used in directives. A directive using a function has the form:

	^ {name of function}[{comma separate list of arguments}] $

Whitespace is significant in the {comma separate list of arguments}. Typically the value of a function's argument will be one or more variables or directives, but it could also be literal text.

The currently defined functions are uc (convert argument to upper case), lc (convert argument to lower case), u_to_h (convert underscores in argument to hyphens), h_to_u (convert hyphens in argument to underscores), lstrip (strip the value of the second argument from the left-hand side of the first argument), rstrip (strip the value of the second argument from the right-hand side of the first argument), date (output formatted date), save_file (specify name of save file), args_to_vars (convert function argument list to variable declarations), args_to_params (convert function argument list to variables that can be used in a function call) and map (output text mapped to the argument).

An example usage might be converting the name of a class into a suitable upper-case .h file include guard name, which could be done as:

	^ uc[^class$] $_H

Note: As in a template where this kind of directive is useful it would be used multiple times, this expression could be defined as an expression pseudo-input in the data capture section of the template, for example:

	expr.include_guard: ^ uc[^class$] $_H

and then used in the snippet format section as ^ include_guard $.

An example usage of a strip function is to remove the .h part of a file name before outputting a value:

	^ rstrip[^file_name$,.h] $

The map function evaluates its argument and then outputs the value it has been mapped to via a Data Capture Section's map or expr pseudo-input. For example, if the following has been defined:

	radiogroup.control: Type of control
	radio.control.button: Button
	radio.control.text: Text control
	map.button_handler: EVT_BUTTON
	map.button_event: wxCommandEvent
	map.text_handler: EVT_TEXT
	map.text_event: wxCommandEvent

and the user has selected the Text control radio button, then ^map[^control$_handler]$ will output EVT_TEXT, and ^map[^control$_event]$ will output wxCommandEvent.

To output a ^ character, insert ^^ into the template. To output ? and $ characters within the {text if condition is true} and {text if condition is false} parts of a directive, insert ^? and ^$ respectively.

[Top] [Contents]

3 - A Complete Template

Here are some examples of complete templates including a number of features described here.

A template to add a new method is an existing class:

	text.class[..]: Name of class owning method
	text.name: Name of method
	text.args: Method arguments
	text.return_type: Return type (leave empty for void)
	expr.return: ^ !return_type ?void?^ return_type $$
	checkbox.is_const: Is a const method
	.
	// For .h file
		^ return $ ^name$(^args? ^args$ $)^is_const? const$;

	// For .cpp file
	^ return $ ^class$::^name$(^args? ^args$ $)^is_const? const$
	{
	}

A template to add a new .h and .cpp file:

	text.name: Base name of file (without .h/.cpp ending)
	expr.inc_guard: ^ h_to_u[^uc[^name$]$] $_H
	.
	// For ^name$.h
	//----------------------------------------------------------------------
	//                                IN CONFIDENCE
	//                        Copyright (c) 2011 My Company. 
	//----------------------------------------------------------------------

	#ifndef ^ inc_guard $
	#define ^ inc_guard $

	#endif	// ^ inc_guard $

	//----------------------------------------------------------------------
	//                                IN CONFIDENCE
	//----------------------------------------------------------------------

	// For ^name$.cpp
	//----------------------------------------------------------------------
	//                                IN CONFIDENCE
	//                        Copyright (c) 2011 My Company. 
	//----------------------------------------------------------------------

	#include "^name$.h"

	//----------------------------------------------------------------------
	//                                IN CONFIDENCE
	//----------------------------------------------------------------------

One way to use this template is to copy a generated file name, then select the part generated for that file and click the "Save to File..." button, pasting the copied file name into the file save dialog, and then repeating the operation for the other portion of the generated code.

[Top] [Contents]

4 - Enhanced Drag and Drop

Code Scrapbook allows you to drag generated code and drop it into your code editor. When enabled, Code Scrapbook will automatically minimize itself when it detects the start of a drag operation, making it easier to drag code into your editor.

To further enhance the drag-and-drop experience, if no code has been selected and a drag operation is started with the ctrl key pressed (i.e. hold down ctrl key, press-and-hold mouse button then move mouse), then all of the generated code is automatically selected and dragged. Similarly if a section of generated code has been selected and the ctrl key is pressed when a drag operation starts, the selection is extended to the start of the first line and the end of the last line of the selected code.

Triple clicking the mouse button will select the whole line.

[Top] [Contents]

5 - True or False Values

The values false, no, off, the integer value 0 and the empty string resolve to false. The comparison is case-independent and leading and trailing whitespace is stripped. All other values resolve to true.

[Top] [Contents]

6 - Licensing

The specification of the Snippet Template is an open specification. If you wish to create your own application with similar functionality, we encourage you to base it on the Snippet Template format described here rather than define your own format. All that we ask is that you include in your application's About dialog, and on your application's web page text to the effect of "The template language used by this program is inspired by Codalogic's Code Scrapbook application."