|
| 1 | +// CodeMirror mode for C++ Mode for Processing |
| 2 | +// Matches Processing Java IDE keyword coloring: |
| 3 | +// FUNCTION1 = entry points / constructors (bold dark blue, paren-sensitive) |
| 4 | +// FUNCTION2 = API functions (light blue, always paren-sensitive) |
| 5 | +// KEYWORD3 = control flow (green) |
| 6 | +// KEYWORD4 = constants / variables (pink) |
| 7 | +// KEYWORD5 = types (orange) |
| 8 | +// KEYWORD6 = language keywords (teal) |
| 9 | + |
| 10 | +(function(mod) { |
| 11 | + if (typeof exports == "object" && typeof module == "object") mod(require("codemirror")); |
| 12 | + else if (typeof define == "function" && define.amd) define(["codemirror"], mod); |
| 13 | + else mod(CodeMirror); |
| 14 | +})(function(CodeMirror) { |
| 15 | + |
| 16 | +// ── Keyword tables ──────────────────────────────────────────────────────────── |
| 17 | +// FUNCTION1: colored only when followed by ( -- entry points and color/PVector constructors |
| 18 | +const FUNCTION1_PAREN = new Set([ |
| 19 | + "color","PVector","PImage","PGraphics","PFont","PShape", |
| 20 | + "ArrayList","IntList","FloatList","StringList", |
| 21 | + "HashMap","HashSet", |
| 22 | +]); |
| 23 | +// FUNCTION1: always colored (setup/draw/event handlers) |
| 24 | +const FUNCTION1_ALWAYS = new Set([ |
| 25 | + "setup","draw","mousePressed","mouseReleased","mouseClicked", |
| 26 | + "mouseMoved","mouseDragged","mouseWheel", |
| 27 | + "keyPressed","keyReleased","keyTyped", |
| 28 | + "settings", |
| 29 | +]); |
| 30 | +// FUNCTION2: API functions -- colored only when followed by ( |
| 31 | +const FUNCTION2 = new Set([ |
| 32 | + "size","fullScreen","smooth","noSmooth","frameRate","cursor","noCursor","exit", |
| 33 | + "background","fill","noFill","stroke","noStroke","strokeWeight","strokeCap","strokeJoin", |
| 34 | + "colorMode","lerpColor","red","green","blue","alpha","hue","saturation","brightness", |
| 35 | + "rect","ellipse","circle","square","line","point","triangle","quad","arc", |
| 36 | + "bezier","bezierVertex","bezierPoint","bezierTangent", |
| 37 | + "curve","curveVertex","curvePoint","curveTangent","curveTightness", |
| 38 | + "beginShape","endShape","vertex","curveVertex","bezierVertex","quadraticVertex", |
| 39 | + "pushMatrix","popMatrix","translate","rotate","rotateX","rotateY","rotateZ", |
| 40 | + "scale","shearX","shearY","resetMatrix","applyMatrix","printMatrix", |
| 41 | + "pushStyle","popStyle","push","pop", |
| 42 | + "image","imageMode","tint","noTint","texture","textureMode","textureWrap", |
| 43 | + "text","textSize","textAlign","textLeading","textWidth","textAscent","textDescent", |
| 44 | + "textFont","loadFont","createFont", |
| 45 | + "loadImage","requestImage","saveFrame","save", |
| 46 | + "loadPixels","updatePixels","get","set","copy","mask","filter","blend", |
| 47 | + "createGraphics","createImage","createShape", |
| 48 | + "lights","noLights","ambientLight","directionalLight","pointLight","spotLight", |
| 49 | + "lightFalloff","lightSpecular","normal","shininess","specular","emissive","ambient", |
| 50 | + "camera","perspective","ortho","frustum","printCamera","printProjection", |
| 51 | + "box","sphere","sphereDetail","beginCamera","endCamera", |
| 52 | + "noise","noiseDetail","noiseSeed","random","randomSeed","randomGaussian", |
| 53 | + "abs","ceil","floor","round","constrain","dist","lerp","mag","map","max","min","norm","sq","sqrt", |
| 54 | + "acos","asin","atan","atan2","cos","degrees","exp","log","pow","radians","sin","tan", |
| 55 | + "nf","nfc","nfp","nfs","hex","unhex","binary","unbinary", |
| 56 | + "str","int","float","boolean","byte","char","join","split","splitTokens","trim","toLowerCase","toUpperCase", |
| 57 | + "append","concat","expand","reverse","shorten","sort","splice","subset", |
| 58 | + "year","month","day","hour","minute","second","millis", |
| 59 | + "delay","print","println", |
| 60 | + "rectMode","ellipseMode","imageMode", |
| 61 | + "hint","blendMode","clip","noClip", |
| 62 | + "selectInput","selectOutput","selectFolder", |
| 63 | + "loadStrings","saveStrings","loadBytes","saveBytes", |
| 64 | + "loadJSON","saveJSON","loadXML","saveXML","loadTable","saveTable", |
| 65 | + "selectInput","selectOutput", |
| 66 | +]); |
| 67 | +// KEYWORD3: control flow -- always colored |
| 68 | +const KEYWORD3 = new Set([ |
| 69 | + "if","else","for","while","do","switch","case","break","continue","return", |
| 70 | + "default","goto","try","catch","throw","finally", |
| 71 | +]); |
| 72 | +// KEYWORD4: constants and built-in variables -- always colored |
| 73 | +const KEYWORD4 = new Set([ |
| 74 | + "PI","HALF_PI","QUARTER_PI","TWO_PI","TAU","E","DEG_TO_RAD","RAD_TO_DEG", |
| 75 | + "mouseX","mouseY","pmouseX","pmouseY","mouseDX","mouseDY", |
| 76 | + "mouseButton","mousePressed","keyPressed","keyCode","key", |
| 77 | + "width","height","frameCount","frameRate","displayWidth","displayHeight", |
| 78 | + "focused","_frameRate","deltaTime", |
| 79 | + "LEFT","RIGHT","CENTER","TOP","BOTTOM","BASELINE", |
| 80 | + "CORNER","CORNERS","RADIUS","CENTER", |
| 81 | + "POINTS","LINES","TRIANGLES","TRIANGLE_FAN","TRIANGLE_STRIP", |
| 82 | + "QUADS","QUAD_STRIP","CLOSE", |
| 83 | + "RGB","HSB","HSL","ARGB","ALPHA", |
| 84 | + "BLEND","ADD","SUBTRACT","DARKEST","LIGHTEST","DIFFERENCE", |
| 85 | + "EXCLUSION","MULTIPLY","SCREEN","OVERLAY","HARD_LIGHT","SOFT_LIGHT", |
| 86 | + "DODGE","BURN","REPLACE","REMOVE", |
| 87 | + "THRESHOLD","GRAY","INVERT","POSTERIZE","BLUR","OPAQUE","ERODE","DILATE", |
| 88 | + "OPEN","CHORD","PIE", |
| 89 | + "ROUND","SQUARE","PROJECT","MITER","BEVEL", |
| 90 | + "UP","DOWN","ALT","CONTROL","SHIFT","BACKSPACE","TAB","ENTER","RETURN", |
| 91 | + "ESC","DELETE","CODED","ARROW_LEFT","ARROW_RIGHT","ARROW_UP","ARROW_DOWN", |
| 92 | + "P2D","P3D","JAVA2D","PDF","SVG","DXF","FX2D", |
| 93 | + "ENABLE_DEPTH_TEST","DISABLE_DEPTH_TEST", |
| 94 | + "ENABLE_DEPTH_MASK","DISABLE_DEPTH_MASK", |
| 95 | + "true","false","null","nullptr","NULL", |
| 96 | + "WHITE","BLACK","RED","GREEN","BLUE","YELLOW","CYAN","MAGENTA", |
| 97 | +]); |
| 98 | +// KEYWORD5: types -- always colored |
| 99 | +const KEYWORD5 = new Set([ |
| 100 | + "color","PVector","PImage","PGraphics","PFont","PShape","PApplet", |
| 101 | + "ArrayList","IntList","FloatList","StringList","HashMap","HashSet", |
| 102 | + "int","float","double","boolean","bool","byte","char","long","short", |
| 103 | + "void","String","string","auto","size_t","uint32_t","uint8_t", |
| 104 | +]); |
| 105 | +// KEYWORD6: language keywords -- always colored |
| 106 | +const KEYWORD6 = new Set([ |
| 107 | + "class","struct","public","private","protected","virtual","override","final", |
| 108 | + "static","const","constexpr","inline","explicit","friend","operator", |
| 109 | + "new","delete","this","super","extends","implements","import","package", |
| 110 | + "namespace","using","typedef","typename","template","sizeof","alignof", |
| 111 | + "noexcept","decltype","nullptr","true","false", |
| 112 | + "include","define","ifdef","ifndef","endif","pragma", |
| 113 | +]); |
| 114 | + |
| 115 | +// ── Token class → CSS class mapping ────────────────────────────────────────── |
| 116 | +// We emit custom token names that map to CSS via CodeMirror's token naming |
| 117 | +// cm-keyword1 etc aren't standard; we use cm-def for FUNCTION1, etc. |
| 118 | + |
| 119 | +CodeMirror.defineMode("cppmode", function(config) { |
| 120 | + var clikeMode = CodeMirror.getMode(config, "text/x-c++src"); |
| 121 | + |
| 122 | + return { |
| 123 | + startState: function() { |
| 124 | + return { |
| 125 | + clike: CodeMirror.startState(clikeMode), |
| 126 | + lastToken: null, |
| 127 | + lastWord: null, |
| 128 | + parenNext: false, // true if we just emitted a paren-sensitive word |
| 129 | + pendingWord: null, // word waiting to see if ( follows |
| 130 | + pendingType: null, |
| 131 | + }; |
| 132 | + }, |
| 133 | + |
| 134 | + copyState: function(state) { |
| 135 | + return { |
| 136 | + clike: CodeMirror.copyState(clikeMode, state.clike), |
| 137 | + lastToken: state.lastToken, |
| 138 | + lastWord: state.lastWord, |
| 139 | + parenNext: state.parenNext, |
| 140 | + pendingWord: state.pendingWord, |
| 141 | + pendingType: state.pendingType, |
| 142 | + }; |
| 143 | + }, |
| 144 | + |
| 145 | + token: function(stream, state) { |
| 146 | + // Skip whitespace |
| 147 | + if (stream.eatSpace()) { |
| 148 | + return null; |
| 149 | + } |
| 150 | + |
| 151 | + // Check for pending word -- did ( follow? |
| 152 | + if (state.pendingWord) { |
| 153 | + var ch = stream.peek(); |
| 154 | + var word = state.pendingWord; |
| 155 | + var type = state.pendingType; |
| 156 | + state.pendingWord = null; |
| 157 | + state.pendingType = null; |
| 158 | + |
| 159 | + if (ch === '(') { |
| 160 | + // Yes -- emit as function |
| 161 | + return type === 'f1' ? 'cppmode-f1' : 'cppmode-f2'; |
| 162 | + } else { |
| 163 | + // No paren -- if it's a dual type/function word, emit as type |
| 164 | + if (KEYWORD5.has(word)) return 'cppmode-k5'; |
| 165 | + return null; |
| 166 | + } |
| 167 | + } |
| 168 | + |
| 169 | + var start = stream.pos; |
| 170 | + |
| 171 | + // Identifiers / keywords |
| 172 | + if (stream.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) { |
| 173 | + var word = stream.current(); |
| 174 | + |
| 175 | + // KEYWORD3: control flow -- always |
| 176 | + if (KEYWORD3.has(word)) return 'cppmode-k3'; |
| 177 | + |
| 178 | + // KEYWORD6: language keywords -- always |
| 179 | + if (KEYWORD6.has(word)) return 'cppmode-k6'; |
| 180 | + |
| 181 | + // KEYWORD4: constants -- always |
| 182 | + if (KEYWORD4.has(word)) return 'cppmode-k4'; |
| 183 | + |
| 184 | + // FUNCTION1 always (entry points) |
| 185 | + if (FUNCTION1_ALWAYS.has(word)) return 'cppmode-f1'; |
| 186 | + |
| 187 | + // FUNCTION1 paren-sensitive (constructors) |
| 188 | + if (FUNCTION1_PAREN.has(word)) { |
| 189 | + // Peek ahead -- but we need to skip whitespace |
| 190 | + // Use pending mechanism |
| 191 | + state.pendingWord = word; |
| 192 | + state.pendingType = 'f1'; |
| 193 | + // Consume this token now but defer color decision |
| 194 | + // We'll decide next token call |
| 195 | + return null; // temporarily uncolored -- will be resolved next call |
| 196 | + } |
| 197 | + |
| 198 | + // FUNCTION2: paren-sensitive API |
| 199 | + if (FUNCTION2.has(word)) { |
| 200 | + state.pendingWord = word; |
| 201 | + state.pendingType = 'f2'; |
| 202 | + return null; |
| 203 | + } |
| 204 | + |
| 205 | + // KEYWORD5: types -- always (for things not in FUNCTION1_PAREN) |
| 206 | + if (KEYWORD5.has(word)) return 'cppmode-k5'; |
| 207 | + |
| 208 | + // Fall through to clike for other identifiers |
| 209 | + stream.backUp(stream.current().length); |
| 210 | + } |
| 211 | + |
| 212 | + // Delegate to clike for everything else (strings, numbers, operators, etc.) |
| 213 | + var tok = clikeMode.token(stream, state.clike); |
| 214 | + return tok; |
| 215 | + }, |
| 216 | + |
| 217 | + indent: function(state, textAfter) { |
| 218 | + return clikeMode.indent(state.clike, textAfter); |
| 219 | + }, |
| 220 | + |
| 221 | + electricChars: clikeMode.electricChars, |
| 222 | + lineComment: clikeMode.lineComment, |
| 223 | + blockCommentStart: clikeMode.blockCommentStart, |
| 224 | + blockCommentEnd: clikeMode.blockCommentEnd, |
| 225 | + blockCommentContinue: clikeMode.blockCommentContinue, |
| 226 | + fold: "brace", |
| 227 | + }; |
| 228 | +}); |
| 229 | + |
| 230 | +CodeMirror.defineMIME("text/x-cppmode", "cppmode"); |
| 231 | + |
| 232 | +}); // end module |
0 commit comments