Skip to content

Commit d0e82a7

Browse files
benmiller-googlemarijnh
authored andcommitted
[powershell mode] Improve
corrected angle bracket matching in operators (fixes block comments) corrected digit matching regex corrected spelling of 'identifier' in grammar dictionary notCharacterOrDash explicitly includes lowercase characters improved variable matching splatted variables now match bare '$' and '@' are errors, not variables moved single-quoted string processing into tokenSingleQuoteString incomplete strings are errors now empty strings are no longer errors added support for here-string interpolation with nesting support added highlighting for splatted vars removed arbitrary stream advancement prior to default error in tokenBase enabled folding braces
1 parent 20641be commit d0e82a7

File tree

1 file changed

+80
-24
lines changed

1 file changed

+80
-24
lines changed

mode/powershell/powershell.js

Lines changed: 80 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
// Initially based on CodeMirror Python mode, copyright (c) by Marijn Haverbeke and others
2-
// PowerShell mode, copyright (c) Andrey Shchekin, VapidWorx and others
3-
// Distributed under an MIT license: http://codemirror.net/LICENSE
1+
/**
2+
* @license
3+
* Initially based on CodeMirror Python mode, copyright (c) by Marijn Haverbeke and others
4+
* PowerShell mode, copyright (c) Andrey Shchekin, VapidWorx and others
5+
* Distributed under an MIT license: http://codemirror.net/LICENSE
6+
*/
47

58
(function(mod) {
69
'use strict';
@@ -31,7 +34,8 @@ CodeMirror.defineMode('powershell', function() {
3134
return new RegExp(prefix + '(' + patterns.join('|') + ')' + suffix, 'i');
3235
}
3336

34-
var notCharacterOrDash = '(?=[^A-Z\\d\\-_]|$)';
37+
var notCharacterOrDash = '(?=[^A-Za-z\\d\\-_]|$)';
38+
var varNames = /[\w\-:]/
3539
var keywords = buildRegexp([
3640
/begin|break|catch|continue|data|default|do|dynamicparam/,
3741
/else|elseif|end|exit|filter|finally|for|foreach|from|function|if|in/,
@@ -49,10 +53,10 @@ CodeMirror.defineMode('powershell', function() {
4953
/[ic]?replace/,
5054
/b?(and|or|xor)/
5155
], { prefix: '-' });
52-
var symbolOperators = /[+\-*\/%]=|\+\+|--|\.\.|[+\-*&^%:=<>!|\/]/;
56+
var symbolOperators = /[+\-*\/%]=|\+\+|--|\.\.|[+\-*&^%:=!|\/]|<(?!#)|(?!#)>/;
5357
var operators = buildRegexp([wordOperators, symbolOperators], { suffix: '' });
5458

55-
var numbers = /^[+-]?(0x[\da-f]+|(\d+(\.\d+)?|\.\d*)(e[\+\-]?\d+)?)[ld]?([kmgtp]b)?/i;
59+
var numbers = /^[+-]?((0x[\da-f]+)|((\d+\.\d+|\d\.|\.\d+|\d+)(e[\+\-]?\d+)?))[ld]?([kmgtp]b)?/i;
5660

5761
var identifiers = /^[A-Za-z\_][A-Za-z\-\_\d]*\b/;
5862

@@ -106,8 +110,8 @@ CodeMirror.defineMode('powershell', function() {
106110
/Save-Help/,
107111
/Select-(Object|String|Xml)/,
108112
/Send-MailMessage/,
109-
new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug'
110-
+ '|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'),
113+
new RegExp('Set-(Acl|Alias|AuthenticodeSignature|Content|Date|ExecutionPolicy|Item(Property)?|Location|PSBreakpoint|PSDebug' +
114+
'|PSSessionConfiguration|Service|StrictMode|TraceSource|Variable|WmiInstance)'),
111115
/Show-(Command|ControlPanelItem|EventLog)/,
112116
/Sort-Object/,
113117
/Split-Path/,
@@ -132,7 +136,7 @@ CodeMirror.defineMode('powershell', function() {
132136
/group|gsn|gsnp|gsv|gu|gv|gwmi|h|history|icm|iex|ihy|ii|ipal|ipcsv|ipmo|ipsn|irm|ise|iwmi|iwr|kill|lp|ls|man|md/,
133137
/measure|mi|mount|move|mp|mv|nal|ndr|ni|nmo|npssc|nsn|nv|ogv|oh|popd|ps|pushd|pwd|r|rbp|rcjb|rcsn|rd|rdr|ren|ri/,
134138
/rjb|rm|rmdir|rmo|rni|rnp|rp|rsn|rsnp|rujb|rv|rvpa|rwmi|sajb|sal|saps|sasv|sbp|sc|select|set|shcm|si|sl|sleep|sls/,
135-
/sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/,
139+
/sort|sp|spjb|spps|spsv|start|sujb|sv|swmi|tee|trcm|type|where|wjb|write/
136140
], { prefix: '', suffix: '' });
137141
var variableBuiltins = buildRegexp([
138142
/[$?^_]|Args|ConfirmPreference|ConsoleFileName|DebugPreference|Error|ErrorActionPreference|ErrorView|ExecutionContext/,
@@ -147,15 +151,15 @@ CodeMirror.defineMode('powershell', function() {
147151
/true|false|null/
148152
], { prefix: '\\$', suffix: '' });
149153

150-
var builtins = buildRegexp([ symbolBuiltins, namedBuiltins, variableBuiltins ], { suffix: notCharacterOrDash });
154+
var builtins = buildRegexp([symbolBuiltins, namedBuiltins, variableBuiltins], { suffix: notCharacterOrDash });
151155

152156
var grammar = {
153157
keyword: keywords,
154158
number: numbers,
155159
operator: operators,
156160
builtin: builtins,
157161
punctuation: punctuation,
158-
indetifier: identifiers
162+
identifier: identifiers
159163
};
160164

161165
// tokenizers
@@ -190,12 +194,13 @@ CodeMirror.defineMode('powershell', function() {
190194
}
191195
}
192196

197+
var ch = stream.next();
198+
193199
// single-quote string
194-
if (stream.match(/'([^']|'')+'/)) {
195-
return 'string';
200+
if (ch === "'") {
201+
return tokenSingleQuoteString(stream, state);
196202
}
197203

198-
var ch = stream.next();
199204
if (ch === '$') {
200205
return tokenVariable(stream, state);
201206
}
@@ -221,18 +226,35 @@ CodeMirror.defineMode('powershell', function() {
221226
state.tokenize = tokenMultiString;
222227
state.startQuote = quoteMatch[0];
223228
return tokenMultiString(stream, state);
229+
} else if (stream.peek().match(/[({]/)) {
230+
return 'punctuation';
231+
} else if (stream.match(varNames)) {
232+
// splatted variable
233+
return tokenVariable(stream, state);
234+
}
235+
}
236+
return 'error';
237+
}
238+
239+
function tokenSingleQuoteString(stream, state) {
240+
var ch;
241+
while ((ch = stream.peek()) != null) {
242+
stream.next();
243+
244+
if (ch === "'" && !stream.eat("'")) {
245+
state.tokenize = tokenBase;
246+
return 'string';
224247
}
225248
}
226249

227-
stream.next();
228250
return 'error';
229251
}
230252

231253
function tokenDoubleQuoteString(stream, state) {
232254
var ch;
233-
while((ch = stream.peek()) != null) {
255+
while ((ch = stream.peek()) != null) {
234256
if (ch === '$') {
235-
state.tokenize = tokenInterpolation;
257+
state.tokenize = tokenStringInterpolation;
236258
return 'string';
237259
}
238260

@@ -251,15 +273,30 @@ CodeMirror.defineMode('powershell', function() {
251273
return 'error';
252274
}
253275

254-
function tokenInterpolation(stream, state) {
276+
function tokenStringInterpolation(stream, state) {
277+
return tokenInterpolation(stream, state, tokenDoubleQuoteString);
278+
}
279+
280+
function tokenMultiStringReturn(stream, state) {
281+
state.tokenize = tokenMultiString;
282+
state.startQuote = '"'
283+
return tokenMultiString(stream, state);
284+
}
285+
286+
function tokenHereStringInterpolation(stream, state) {
287+
var saved;
288+
return tokenInterpolation(stream, state, tokenMultiStringReturn);
289+
}
290+
291+
function tokenInterpolation(stream, state, parentTokenize) {
255292
if (stream.match('$(')) {
256293
var savedBracketNesting = state.bracketNesting;
257294
state.returnStack.push({
258295
/*jshint loopfunc:true */
259296
shouldReturnFrom: function(state) {
260297
return state.bracketNesting === savedBracketNesting;
261298
},
262-
tokenize: tokenDoubleQuoteString
299+
tokenize: parentTokenize
263300
});
264301
state.tokenize = tokenBase;
265302
state.bracketNesting += 1;
@@ -268,7 +305,7 @@ CodeMirror.defineMode('powershell', function() {
268305
stream.next();
269306
state.returnStack.push({
270307
shouldReturnFrom: function() { return true; },
271-
tokenize: tokenDoubleQuoteString
308+
tokenize: parentTokenize
272309
});
273310
state.tokenize = tokenVariable;
274311
return state.tokenize(stream, state);
@@ -288,13 +325,17 @@ CodeMirror.defineMode('powershell', function() {
288325
}
289326

290327
function tokenVariable(stream, state) {
328+
var ch = stream.peek();
291329
if (stream.eat('{')) {
292330
state.tokenize = tokenVariableWithBraces;
293331
return tokenVariableWithBraces(stream, state);
294-
} else {
295-
stream.eatWhile(/[\w\\\-:]/);
332+
} else if (ch != undefined && ch.match(varNames)) {
333+
stream.eatWhile(varNames);
296334
state.tokenize = tokenBase;
297335
return 'variable-2';
336+
} else {
337+
state.tokenize = tokenBase;
338+
return 'error';
298339
}
299340
}
300341

@@ -314,6 +355,20 @@ CodeMirror.defineMode('powershell', function() {
314355
if (stream.sol() && stream.match(new RegExp(quote + '@'))) {
315356
state.tokenize = tokenBase;
316357
}
358+
else if (quote === '"') {
359+
while (!stream.eol()) {
360+
var ch = stream.peek();
361+
if (ch === '$') {
362+
state.tokenize = tokenHereStringInterpolation;
363+
return 'string';
364+
}
365+
366+
stream.next();
367+
if (ch === '`') {
368+
stream.next();
369+
}
370+
}
371+
}
317372
else {
318373
stream.skipToEnd();
319374
}
@@ -336,10 +391,11 @@ CodeMirror.defineMode('powershell', function() {
336391

337392
blockCommentStart: '<#',
338393
blockCommentEnd: '#>',
339-
lineComment: '#'
394+
lineComment: '#',
395+
fold: 'brace'
340396
};
341397
return external;
342398
});
343399

344400
CodeMirror.defineMIME('text/x-powershell', 'powershell');
345-
});
401+
});

0 commit comments

Comments
 (0)