My adventures in extending Visual Studio and general development on the GHC Haskell Compiler

Configurable Candy

Candy is a feature where you replace a selection of text with something else (usually also text), however this is done in view only and so not in the actual file. This is useful to replace things like “->” with an actual Unicode arrow while still allowing other text editors that can’t handle Unicode to display the file correctly.

Leksah implements this and allows you to configure it via a so called “Candy” file, So I “borrowed” their approach and extended it to suit my needs.

The general syntax of a Visual Haskell candy file (.vshc) is

-- "<token>" <unicode> <modifier> <enabled> <FIT|NONE>
-- the token has to be quoted
-- the supported modifiers are
-- CODE - Apply only to regions of code
-- COMMENT - Apply only inside comments
-- STRING - Apply only in string literals
-- ALL - Apply to all

the modifiers are self explanatory but the FIT or NONE modifiers take some explaining.

When using the FIT modifier, the Candy engine won’t try to keep the same width as the text it’s replacing. This means that you get a layout change. The actual file might have “alpha” but the view will show only “a”.

With some things, especially with keywords we don’t want this, this is where the NONE modifier comes in. When this is used the engine will always match the width of the text it’s replacing by making the Unicode text larger and adding horizontal whitespace. This means that “alpha” would be rendered as “ a “ and so preserving the layout.

A shot of this in action can is:

For reference, the full default candy file that will be shipping with VSH2010 is:

— Candy file

— Format

— "<token>" <unicode> <modifier> <enabled> <FIT|NONE>

— the token has to be quoted

— the supported modifiers are

— CODE – Apply only to regions of code

— COMMENT – Apply only inside comments

— STRING – Apply only in string literals

— ALL – Apply to all

—

— Note that the replacement block will always take up the exact same

— space as the tokens it’s replacing. e.g. "alpha" will be replaced by " a "

"->" 0x2192 CODE True NONE –RIGHTWARDS ARROW

"<-" 0x2190 CODE True NONE –LEFTWARDS ARROW

"=>" 0x21d2 CODE True NONE –RIGHTWARDS DOUBLE ARROW

">=" 0x2265 CODE False NONE –GREATER-THAN OR EQUAL TO

"<=" 0x2264 CODE False NONE –LESS-THAN OR EQUAL TO

"/=" 0x2260 CODE False NONE –NOT EQUAL TO

"&&" 0x2227 CODE False NONE –LOGICAL AND

"||" 0x2228 CODE False NONE –LOGICAL OR

"++" 0x2295 CODE False NONE –CIRCLED PLUS

"::" 0x2237 CODE False NONE –PROPORTION

".." 0x2025 CODE False NONE –TWO DOT LEADER

"^" 0x2191 COMMENT False NONE –UPWARDS ARROW

"==" 0x2261 CODE False NONE –IDENTICAL TO

" . " 0x2218 CODE True NONE –RING OPERATOR

"\\" 0x03bb CODE True NONE –GREEK SMALL LETTER LAMBDA

"=<<" 0x291e CODE False NONE —

">>=" 0x21a0 CODE False NONE —

"$" 0x25ca CODE False NONE —

">>" 0x226b CODE False NONE — MUCH GREATER THEN

"forall" 0x2200 CODE False NONE –FOR ALL

"exist" 0x2203 CODE False NONE –THERE EXISTS

"not" 0x00ac CODE False NONE –NOT SIGN

"alpha" 0x03b1 ALL True FIT –ALPHA

"beta" 0x03b2 ALL True FIT –BETA

"gamma" 0x03b3 ALL True FIT –GAMMA

"delta" 0x03b4 ALL True FIT –DELTA

"epsilon" 0x03b5 ALL True FIT –EPSILON

"zeta" 0x03b6 ALL True FIT –ZETA

"eta" 0x03b7 ALL True FIT –ETA

"theta" 0x03b8 ALL True FIT –THETA

— Because you can configure options inside the editor itself, don’t comment out