Skip to content

Commit

Permalink
Fix R code cell parser and add # %% support (#3858)
Browse files Browse the repository at this point in the history
Addresses #3709.

Changes:
- R parser would end cells after first blank line; this is now removed
- `# %%` is now recognized as a valid cell demarcation in R
- cellDecorationSetting now matches python (only highlights currently
active cell). Note that before the whole program is highlighted a gray
color, so the information was meaningless.
- Tests added to test for these changes

---------

Signed-off-by: Kyle F Butts <[email protected]>
Co-authored-by: Wasim Lorgat <[email protected]>
  • Loading branch information
kylebutts and seeM authored Jul 8, 2024
1 parent 2039581 commit 6363fe6
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 54 deletions.
14 changes: 8 additions & 6 deletions extensions/positron-code-cells/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,10 @@ function getJupyterMarkdownCellText(cell: Cell, document: vscode.TextDocument):
return `%%markdown\n${text}\n\n`;
}

const pythonIsCellStartRegExp = new RegExp(/^\s*#\s*%%/);
const pythonMarkdownRegExp = new RegExp(/^\s*#\s*%%[^[]*\[markdown\]/);
// Spaces can not occur before #
const pythonIsCellStartRegExp = new RegExp(/^#\s*%%/);
const pythonMarkdownRegExp = new RegExp(/^#\s*%%[^[]*\[markdown\]/);
const rIsCellStartRegExp = new RegExp(/^#\s*(%%|\+)/);

// TODO: Expose an API to let extensions register parsers
const pythonCellParser: CellParser = {
Expand All @@ -81,12 +83,12 @@ const pythonCellParser: CellParser = {
};

const rCellParser: CellParser = {
isCellStart: (line) => line.startsWith('#+'),
isCellEnd: (line) => line.trim() === '',
isCellStart: (line) => rIsCellStartRegExp.test(line),
isCellEnd: (_line) => false,
getCellType: (_line) => CellType.Code,
getCellText: getCellText,
newCell: () => '\n\n#+',
cellDecorationSetting: () => CellDecorationSetting.All,
newCell: () => '\n#+\n',
cellDecorationSetting: () => CellDecorationSetting.Current,
};

const parsers: Map<string, CellParser> = new Map([
Expand Down
52 changes: 31 additions & 21 deletions extensions/positron-code-cells/src/test/codeLenses.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,55 @@ import { closeAllEditors } from './utils';
suite('CodeLenses', () => {
teardown(closeAllEditors);

test('Provides Python cell code lenses', async () => {
const language = 'python';
const content = `#%%
const content = `# %%
testing1
#%%
testing2
#%%
testing3`;
const document = await vscode.workspace.openTextDocument({ language, content });
# %%
testing3
# %%
testing4`;
const content_with_plus = content.replaceAll("# %%", "#+");

test('Provides Python cell code lenses', async () => {
const provider = new CellCodeLensProvider();

const language = 'python';
const document = await vscode.workspace.openTextDocument({ language: language, content: content });
const codeLenses = await provider.provideCodeLenses(document);

assert.ok(codeLenses, 'No code lenses provided');
verifyCodeLenses(codeLenses, [
new vscode.Range(0, 0, 1, 8),
new vscode.Range(2, 0, 3, 8),
new vscode.Range(4, 0, 5, 8)
new vscode.Range(0, 0, 4, 0),
new vscode.Range(5, 0, 7, 0),
new vscode.Range(8, 0, 9, 8)
]);
});

test('Provides R cell code lenses', async () => {
const language = 'r';
const content = `#+
testing1
#+
testing2
#+
testing3`;
const document = await vscode.workspace.openTextDocument({ language, content });
const provider = new CellCodeLensProvider();

const language = 'r';
const document = await vscode.workspace.openTextDocument({ language: language, content: content });
const codeLenses = await provider.provideCodeLenses(document);

assert.ok(codeLenses, 'No code lenses provided');
verifyCodeLenses(codeLenses, [
new vscode.Range(0, 0, 1, 8),
new vscode.Range(2, 0, 3, 8),
new vscode.Range(4, 0, 5, 8)
new vscode.Range(0, 0, 4, 0),
new vscode.Range(5, 0, 7, 0),
new vscode.Range(8, 0, 9, 8)
]);

const document2 = await vscode.workspace.openTextDocument({ language: language, content: content_with_plus });
const codeLenses2 = await provider.provideCodeLenses(document2);

assert.ok(codeLenses2, 'No code lenses provided');
verifyCodeLenses(codeLenses2, [
new vscode.Range(0, 0, 4, 0),
new vscode.Range(5, 0, 7, 0),
new vscode.Range(8, 0, 9, 8)
]);
});
});
Expand Down
53 changes: 32 additions & 21 deletions extensions/positron-code-cells/src/test/folding.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,56 @@ import { closeAllEditors } from './utils';
suite('Folding', () => {
teardown(closeAllEditors);

test('Provides Python cell folding ranges', async () => {
const language = 'python';
const content = `#%%
const content = `# %%
testing1
#%%
testing2
#%%
testing3`;
const document = await vscode.workspace.openTextDocument({ language, content });
# %%
testing3
# %%
testing4`;
const content_with_plus = content.replaceAll("# %%", "#+");


test('Provides Python cell folding ranges', async () => {
const provider = new CellFoldingRangeProvider();

const language = 'python';
const document = await vscode.workspace.openTextDocument({ language, content });
const foldingRanges = await provider.provideFoldingRanges(document);

assert.ok(foldingRanges, 'No folding ranges provided');
assert.deepStrictEqual(foldingRanges, [
new vscode.FoldingRange(0, 1),
new vscode.FoldingRange(2, 3),
new vscode.FoldingRange(4, 5),
new vscode.FoldingRange(0, 4),
new vscode.FoldingRange(5, 7),
new vscode.FoldingRange(8, 9),
], 'Incorrect folding ranges');
});

test('Provides R cell folding ranges', async () => {
const language = 'r';
const content = `#+
testing1
#+
testing2
#+
testing3`;
const document = await vscode.workspace.openTextDocument({ language, content });
const provider = new CellFoldingRangeProvider();

const language = 'r';
const document = await vscode.workspace.openTextDocument({ language: language, content: content });
const foldingRanges = await provider.provideFoldingRanges(document);

assert.ok(foldingRanges, 'No folding ranges provided');
assert.deepStrictEqual(foldingRanges, [
new vscode.FoldingRange(0, 1),
new vscode.FoldingRange(2, 3),
new vscode.FoldingRange(4, 5),
new vscode.FoldingRange(0, 4),
new vscode.FoldingRange(5, 7),
new vscode.FoldingRange(8, 9),
], 'Incorrect folding ranges');

const document2 = await vscode.workspace.openTextDocument({ language: language, content: content_with_plus });
const foldingRanges2 = await provider.provideFoldingRanges(document2);

assert.ok(foldingRanges2, 'No folding ranges provided');
assert.deepStrictEqual(foldingRanges2, [
new vscode.FoldingRange(0, 4),
new vscode.FoldingRange(5, 7),
new vscode.FoldingRange(8, 9),
], 'Incorrect folding ranges');
});
});
12 changes: 6 additions & 6 deletions extensions/positron-code-cells/src/test/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,9 @@ And a [link](target)`;

suite('R Parser', () => {
const language = 'r';
const codeCellBody = '123\n456';
const codeCellBody = '\n123\n456';
const codeCell1 = `#+\n${codeCellBody}`;
const codeCell2 = `#+\n789\n012`;
const codeCell2 = `# %%\n789\n\n012`;

const parser = getParser(language);

Expand All @@ -123,8 +123,8 @@ And a [link](target)`;
const content = [codeCell1, codeCell2].join('\n\n');
const document = await vscode.workspace.openTextDocument({ language, content });
assert.deepStrictEqual(parseCells(document), [
{ range: new vscode.Range(0, 0, 2, 3), type: CellType.Code },
{ range: new vscode.Range(4, 0, 6, 3), type: CellType.Code }
{ range: new vscode.Range(0, 0, 4, 0), type: CellType.Code },
{ range: new vscode.Range(5, 0, 8, 3), type: CellType.Code }
]);
});

Expand All @@ -150,11 +150,11 @@ And a [link](target)`;
});

test('New cell', async () => {
assert.strictEqual(parser?.newCell(), '\n\n#+');
assert.strictEqual(parser?.newCell(), '\n#+\n');
});

test('Cell decoration setting', async () => {
assert.strictEqual(parser?.cellDecorationSetting(), CellDecorationSetting.All);
assert.strictEqual(parser?.cellDecorationSetting(), CellDecorationSetting.Current);
});
});
});
Expand Down

0 comments on commit 6363fe6

Please sign in to comment.