Skip to content

Commit f77567b

Browse files
Shushant SinghPrabhakar Kumar
authored andcommitted
Adds feature to LabExtension to highlight valid MAGIC commands.
1 parent 1a1ced6 commit f77567b

File tree

6 files changed

+126
-30
lines changed

6 files changed

+126
-30
lines changed

src/jupyter_matlab_labextension/src/lezer-matlab/src/highlight.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export const matlabHighlighting = styleTags({
1111
MultilineComment: t.comment,
1212
SystemCommand: t.meta,
1313
String: t.string,
14+
Magic: t.monospace,
1415
'( )': t.paren,
1516
'[ ]': t.squareBracket,
1617
'{ }': t.brace

src/jupyter_matlab_labextension/src/lezer-matlab/src/matlab.grammar

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,15 @@ expression {
88
MultilineComment |
99
keyword |
1010
Symbol |
11-
SystemCommand
11+
SystemCommand |
12+
Magic
1213
}
1314

15+
@external propSource matlabHighlighting from "./highlight"
16+
17+
// Call out to comment parser. Since this is above the tokens block in this grammar, it takes precedence.
18+
@external tokens parseComments from "./parse_comments" { MultilineComment, LineComment, Magic }
19+
1420
// See https://lezer.codemirror.net/docs/guide/ for documentation on syntax
1521
// specific to @tokens blocks, and how it differs from regular expression syntax.
1622
@tokens {
@@ -38,9 +44,4 @@ keyword {
3844

3945
@skip { space | LineComment }
4046

41-
@external propSource matlabHighlighting from "./highlight"
42-
43-
// Call out to comment parser.
44-
@external tokens parseComments from "./parse_comments" { MultilineComment, LineComment }
45-
4647
@detectDelim

src/jupyter_matlab_labextension/src/lezer-matlab/src/parse_comments.js

Lines changed: 68 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { ExternalTokenizer } from '@lezer/lr';
44
// This file is created by lezer-generator during the build.
5-
import { MultilineComment, LineComment } from './parser.terms.js';
5+
import { MultilineComment, LineComment, Magic } from './parser.terms.js';
66

77
const percent = '%'.charCodeAt(0);
88
const openBrace = '{'.charCodeAt(0);
@@ -12,6 +12,8 @@ const fileEnd = -1;
1212
const newline = '\n'.charCodeAt(0);
1313
const carriageReturn = '\r'.charCodeAt(0);
1414

15+
const isAlphabetical = (char) => /^[a-zA-Z]$/.test(String.fromCharCode(char));
16+
1517
const lineEndArray = [newline, carriageReturn, fileEnd, fileStart];
1618

1719
const isWhitespace = (char) => /\s/.test(char);
@@ -84,33 +86,75 @@ const validMultiLineCommentEnd = (input) => {
8486
return true;
8587
};
8688

87-
export const parseComments = new ExternalTokenizer(input => {
88-
// First, check if it's just a line comment.
89+
const validMagic = (input) => {
90+
if (input.notMagic !== undefined) {
91+
return false;
92+
}
93+
var isMagic = false;
94+
if (
95+
input.peek(0) === percent &&
96+
input.peek(1) === percent &&
97+
isAlphabetical(input.peek(2))
98+
) {
99+
isMagic = true;
100+
}
101+
return isMagic;
102+
};
103+
104+
export const parseComments = new ExternalTokenizer((input) => {
105+
// Tokenize only if the line is a comment, multiline comment
106+
// or a magic and starts with a percentage.
89107
if (input.peek(0) !== percent) {
108+
// If the line starts with anything other than a percentage then it is MATLAB Code.
109+
// If the input.input.string exists then check it's length otherwise ignore the keys by returning true.
110+
if (
111+
input.peek(0) !== fileStart && input.peek(0) !== newline &&
112+
(
113+
!('input' in input) ||
114+
!('string' in input.input) ||
115+
input.input.string.length !== 0
116+
)
117+
) {
118+
input.notMagic = true;
119+
}
90120
return;
91-
} else if (!validMultiLineCommentStart(input)) {
92-
while (!lineEndArray.includes(input.peek(0))) { input.advance(1); }
93-
input.acceptToken(LineComment);
121+
} else if (validMagic(input)) {
122+
while (!lineEndArray.includes(input.peek(0))) {
123+
input.advance(1);
124+
}
125+
input.acceptToken(Magic);
94126
return;
95-
}
96-
// Consume the %{
97-
input.advance(2);
127+
} else if (validMultiLineCommentStart(input)) {
128+
// Consume the %{
129+
input.advance(2);
130+
// Multiline comments are treated as MATLAB Code.
131+
input.notMagic = true;
132+
// Now we know we've started a multiline comment, so
133+
// continue until the end of the input or until the comment is closed.
134+
// We need to keep track of the depth of nested multiline comments.
135+
let depth = 1;
136+
while (input.peek(0) !== fileEnd) {
137+
if (validMultiLineCommentEnd(input)) {
138+
input.advance(2);
139+
depth--;
140+
if (depth === 0) {
141+
break;
142+
}
143+
} else if (validMultiLineCommentStart(input)) {
144+
depth++;
145+
}
146+
input.advance(1);
147+
}
98148

99-
// Now we know we've started a multiline comment, so
100-
// continue until the end of the input or until the comment is closed.
101-
// We need to keep track of the depth of nested multiline comments.
102-
let depth = 1;
103-
while (input.peek(0) !== fileEnd) {
104-
if (validMultiLineCommentEnd(input)) {
105-
input.advance(2);
106-
depth--;
107-
if (depth === 0) { break; }
108-
} else if (validMultiLineCommentStart(input)) {
109-
depth++;
149+
// Emit the token for the entire multiline comment
150+
input.acceptToken(MultilineComment);
151+
} else {
152+
// Comments are also treated as MATLAB Code.
153+
input.notMagic = true;
154+
while (!lineEndArray.includes(input.peek(0))) {
155+
input.advance(1);
110156
}
111-
input.advance(1);
157+
input.acceptToken(LineComment);
158+
return;
112159
}
113-
114-
// Emit the token for the entire multiline comment
115-
input.acceptToken(MultilineComment);
116160
});

src/jupyter_matlab_labextension/src/lezer-matlab/test/additional_cases.txt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,34 @@ test!test
5656
==>
5757

5858
Script(Identifier,SystemCommand)
59+
60+
# Magic command after a Line Comment is treated as a Line Comment
61+
62+
%%magic command
63+
% A comment
64+
%%magic now treated as comment
65+
66+
==>
67+
68+
Script(Magic, LineComment, LineComment)
69+
70+
# Magic command after a MultilineComment is treated as a LineComment
71+
72+
%{
73+
A MultilineComment
74+
%}
75+
%%magic now treated as comment
76+
77+
==>
78+
79+
Script(MultilineComment, LineComment)
80+
81+
# Magic command after a MATLAB Code should be treated as a Line Comment
82+
83+
%%magic command1
84+
peaks
85+
%%magic command2
86+
87+
==>
88+
89+
Script(Magic, Identifier, LineComment)

src/jupyter_matlab_labextension/src/lezer-matlab/test/basic_terms.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,11 @@ test ! echo "Test system command"
7171
==>
7272

7373
Script(Identifier,SystemCommand)
74+
75+
# Magic command
76+
77+
%%magic command
78+
79+
==>
80+
81+
Script(Magic)

src/jupyter_matlab_labextension/src/lezer-matlab/test/nested_terms.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,14 @@ Script(LineComment,MultilineComment)
6868
==>
6969

7070
Script(String,Symbol,String,Symbol)
71+
72+
# Nested Magic commands
73+
74+
%%magic command 1
75+
%%magic command 2
76+
77+
%%magic command 3
78+
79+
==>
80+
81+
Script(Magic, Magic, Magic)

0 commit comments

Comments
 (0)