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.
2.1 - The Data Capture Section
2.1.1 - Specifying single line text input
2.1.2 - Specifying checkbox input
2.1.3 - Specifying radio button input
2.1.4 - Specifying expression pseudo-input
2.1.5 - Specifying map pseudo-input
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.
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
.
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 requiredcreates a checkbox control named
want_more
, with the label More explanation required
and being checked when initially displayed.
To specify single line text input, set the type of control to text
, for example:
text.user_name: User nameor:
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
To specify checkbox input, set the type of control to checkbox
, for example:
checkbox.is_const: Method is constor:
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
.
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
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$
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
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.
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.
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.
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
.
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."