Skip to content

Commit 9c88fb5

Browse files
committed
Clean up and use a CodeCell to render and execute the code
1 parent dce59aa commit 9c88fb5

15 files changed

+184
-45
lines changed

.eslintrc.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ module.exports = {
1515
'@typescript-eslint/naming-convention': [
1616
'error',
1717
{
18-
'selector': 'interface',
19-
'format': ['PascalCase'],
20-
'custom': {
21-
'regex': '^I[A-Z]',
22-
'match': true
18+
selector: 'interface',
19+
format: ['PascalCase'],
20+
custom: {
21+
regex: '^I[A-Z]',
22+
match: true
2323
}
2424
}
2525
],

.github/workflows/binder-on-pr.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Reference https://mybinder.readthedocs.io/en/latest/howto/gh-actions-badges.html
2+
name: Binder Badge
3+
on:
4+
pull_request_target:
5+
types: [opened]
6+
7+
permissions:
8+
pull-requests: write
9+
jobs:
10+
binder:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: comment on PR with Binder link
14+
uses: actions/github-script@v3
15+
with:
16+
github-token: ${{secrets.GITHUB_TOKEN}}
17+
script: |
18+
var PR_HEAD_USERREPO = process.env.PR_HEAD_USERREPO;
19+
var PR_HEAD_REF = process.env.PR_HEAD_REF;
20+
github.issues.createComment({
21+
issue_number: context.issue.number,
22+
owner: context.repo.owner,
23+
repo: context.repo.repo,
24+
body: `[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/${PR_HEAD_USERREPO}/${PR_HEAD_REF}?urlpath=lab) :point_left: Launch a Binder on branch _${PR_HEAD_USERREPO}/${PR_HEAD_REF}_`
25+
})
26+
env:
27+
PR_HEAD_REF: ${{ github.event.pull_request.head.ref }}
28+
PR_HEAD_USERREPO: ${{ github.event.pull_request.head.repo.full_name }}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
- repo: https://github.com/pre-commit/mirrors-prettier
2+
rev: "" # Use the sha or tag you want to point at
3+
hooks:
4+
- id: prettier
5+

.prettierrc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"singleQuote": true,
33
"trailingComma": "none",
4-
"arrowParens": "avoid"
5-
}
4+
"arrowParens": "avoid",
5+
"endOfLine": "auto"
6+
}

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,33 @@
55
Blockly extension for JupyterLab.
66

77
## Blockly
8+
89
Blockly is a library from Google for building beginner-friendly block-based programming languages.
910

1011
Docs: https://developers.google.com/blockly/guides/overview
1112
Repo: https://github.com/google/blockly
1213

13-
1414
## Requirements
1515

16-
* JupyterLab == 3.4
16+
- JupyterLab == 3.4
1717

1818
## Install
1919

2020
To install the extension, execute:
2121

2222
```bash
23-
micromamba create -n blockly -c conda-forge python ipykernel xeus-python xeus-lua
23+
micromamba create -n blockly -c conda-forge python jupyterlab==3.4 ipykernel xeus-python xeus-lua jupyterlab-language-pack-es-ES jupyterlab-language-pack-fr-FR
2424
micromamba activate blockly
2525
pip install jupyterlab_blockly
2626
```
2727

2828
#### Kernels
29-
* ipykernel
30-
* xeus-python
31-
* xeus-lua
32-
* [JavaScript](https://github.com/n-riesco/ijavascript#installation)
33-
* [JavaScript](https://github.com/yunabe/tslab)
29+
30+
- ipykernel
31+
- xeus-python
32+
- xeus-lua
33+
- [JavaScript](https://github.com/n-riesco/ijavascript#installation)
34+
- [JavaScript](https://github.com/yunabe/tslab)
3435

3536
## Uninstall
3637

@@ -40,7 +41,6 @@ To remove the extension, execute:
4041
pip uninstall jupyterlab_blockly
4142
```
4243

43-
4444
## Contributing
4545

4646
### Development install
@@ -52,7 +52,7 @@ The `jlpm` command is JupyterLab's pinned version of
5252
`yarn` or `npm` in lieu of `jlpm` below.
5353

5454
```bash
55-
micromamba create -n blockly -c conda-forge python nodejs yarn jupyterlab==3.4 jupyter-packaging
55+
micromamba create -n blockly -c conda-forge python nodejs yarn jupyterlab==3.4 jupyter-packaging jupyterlab-language-pack-es-ES jupyterlab-language-pack-fr-FR ipykernel xeus-python xeus-lua
5656
micromamba activate blockly
5757
# Clone the repo to your local environment
5858
# Change directory to the jupyterlab_blockly directory

RELEASE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Python package. Before generating a package, we first need to install `build`.
1515
pip install build twine
1616
```
1717

18-
To create a Python source package (``.tar.gz``) and the binary package (`.whl`) in the `dist/` directory, do:
18+
To create a Python source package (`.tar.gz`) and the binary package (`.whl`) in the `dist/` directory, do:
1919

2020
```bash
2121
python -m build

package.json

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,14 @@
3737
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
3838
"clean:labextension": "rimraf jupyterlab_blockly/labextension",
3939
"clean:all": "jlpm run clean:lib && jlpm run clean:labextension",
40-
"eslint": "eslint . --ext .ts,.tsx --fix",
41-
"eslint:check": "eslint . --ext .ts,.tsx",
40+
"eslint": "jlpm eslint:check --fix",
41+
"eslint:check": "eslint . --cache --ext .ts,.tsx",
4242
"install:extension": "jlpm run build",
43+
"lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
44+
"lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
45+
"prettier": "jlpm prettier:base --write --list-different",
46+
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
47+
"prettier:check": "jlpm prettier:base --check",
4348
"watch": "run-p watch:src watch:labextension",
4449
"watch:src": "tsc -w",
4550
"watch:labextension": "jupyter labextension watch .",
@@ -48,6 +53,8 @@
4853
"dependencies": {
4954
"@jupyterlab/application": "^3.4",
5055
"@jupyterlab/apputils": "^3.4",
56+
"@jupyterlab/cells": "^3.4",
57+
"@jupyterlab/codeeditor": "^3.4",
5158
"@jupyterlab/coreutils": "^5.4",
5259
"@jupyterlab/docregistry": "^3.4",
5360
"@jupyterlab/filebrowser": "^3.4",

src/factory.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
DocumentModel
55
} from '@jupyterlab/docregistry';
66
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
7+
import { IEditorMimeTypeService } from '@jupyterlab/codeeditor';
78

89
import { BlocklyEditor, BlocklyPanel } from './widget';
910
import { BlocklyRegistry } from './registry';
@@ -18,6 +19,7 @@ export class BlocklyEditorFactory extends ABCWidgetFactory<
1819
> {
1920
private _registry: BlocklyRegistry;
2021
private _rendermime: IRenderMimeRegistry;
22+
private _mimetypeService: IEditorMimeTypeService;
2123

2224
/**
2325
* Constructor of BlocklyEditorFactory.
@@ -28,6 +30,7 @@ export class BlocklyEditorFactory extends ABCWidgetFactory<
2830
super(options);
2931
this._registry = new BlocklyRegistry();
3032
this._rendermime = options.rendermime;
33+
this._mimetypeService = options.mimetypeService;
3134
}
3235

3336
get registry(): BlocklyRegistry {
@@ -43,7 +46,11 @@ export class BlocklyEditorFactory extends ABCWidgetFactory<
4346
protected createNewWidget(
4447
context: DocumentRegistry.IContext<DocumentModel>
4548
): BlocklyEditor {
46-
const manager = new BlocklyManager(this._registry, context.sessionContext);
49+
const manager = new BlocklyManager(
50+
this._registry,
51+
context.sessionContext,
52+
this._mimetypeService
53+
);
4754
const content = new BlocklyPanel(context, manager, this._rendermime);
4855
return new BlocklyEditor({ context, content, manager });
4956
}
@@ -55,5 +62,9 @@ export namespace BlocklyEditorFactory {
5562
* A rendermime instance.
5663
*/
5764
rendermime: IRenderMimeRegistry;
65+
/*
66+
* A mimeType service instance.
67+
*/
68+
mimetypeService: IEditorMimeTypeService;
5869
}
5970
}

src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { jsonIcon } from '@jupyterlab/ui-components';
77
import { WidgetTracker } from '@jupyterlab/apputils';
88
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
9+
import { IEditorServices } from '@jupyterlab/codeeditor';
910
import { ICommandPalette } from '@jupyterlab/apputils';
1011
import { IFileBrowserFactory } from '@jupyterlab/filebrowser';
1112
import { ILauncher } from '@jupyterlab/launcher';
@@ -43,6 +44,7 @@ const plugin: JupyterFrontEndPlugin<IBlocklyRegisty> = {
4344
requires: [
4445
ILayoutRestorer,
4546
IRenderMimeRegistry,
47+
IEditorServices,
4648
IFileBrowserFactory,
4749
ISettingRegistry,
4850
ITranslator
@@ -53,6 +55,7 @@ const plugin: JupyterFrontEndPlugin<IBlocklyRegisty> = {
5355
app: JupyterFrontEnd,
5456
restorer: ILayoutRestorer,
5557
rendermime: IRenderMimeRegistry,
58+
editorServices: IEditorServices,
5659
browserFactory: IFileBrowserFactory,
5760
settings: ISettingRegistry,
5861
translator: ITranslator,
@@ -97,8 +100,10 @@ const plugin: JupyterFrontEndPlugin<IBlocklyRegisty> = {
97100
shutdownOnClose: true,
98101

99102
// The rendermime instance, necessary to render the outputs
100-
// after a code execution.
103+
// after a code execution. And the mimeType service to get the
104+
// mimeType from the kernel language
101105
rendermime: rendermime,
106+
mimetypeService: editorServices.mimeTypeService,
102107

103108
// The translator instance, used for the internalization of the plugin.
104109
translator: translator

src/layout.ts

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { SimplifiedOutputArea, OutputAreaModel } from '@jupyterlab/outputarea';
21
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
32
import { ISessionContext, showErrorMessage } from '@jupyterlab/apputils';
3+
import { CodeCell, CodeCellModel } from '@jupyterlab/cells';
44

55
import { Message } from '@lumino/messaging';
66
import { PartialJSONValue } from '@lumino/coreutils';
@@ -21,7 +21,7 @@ export class BlocklyLayout extends PanelLayout {
2121
private _manager: BlocklyManager;
2222
private _workspace: Blockly.WorkspaceSvg;
2323
private _sessionContext: ISessionContext;
24-
private _outputArea: SimplifiedOutputArea;
24+
private _cell: CodeCell;
2525

2626
/**
2727
* Construct a `BlocklyLayout`.
@@ -40,12 +40,18 @@ export class BlocklyLayout extends PanelLayout {
4040
// and the output area to render the execution replies.
4141
this._host = document.createElement('div');
4242

43-
// Creating a SimplifiedOutputArea widget to render the
43+
// Creating a CodeCell widget to render the code and
4444
// outputs from the execution reply.
45-
this._outputArea = new SimplifiedOutputArea({
46-
model: new OutputAreaModel({ trusted: true }),
45+
this._cell = new CodeCell({
46+
model: new CodeCellModel({}),
4747
rendermime
4848
});
49+
// Trust the outputs and set the mimeType for the code
50+
this._cell.readOnly = true;
51+
this._cell.model.trusted = true;
52+
this._cell.model.mimeType = this._manager.mimeType;
53+
54+
this._manager.changed.connect(this._onManagerChanged, this);
4955
}
5056

5157
get workspace(): PartialJSONValue {
@@ -99,6 +105,9 @@ export class BlocklyLayout extends PanelLayout {
99105
run(): void {
100106
// Serializing our workspace into the chosen language generator.
101107
const code = this._manager.generator.workspaceToCode(this._workspace);
108+
this._cell.model.sharedModel.setSource(code);
109+
this.addWidget(this._cell);
110+
this._resizeWorkspace();
102111

103112
// Execute the code using the kernel, by using a static method from the
104113
// same class to make an execution request.
@@ -111,11 +120,8 @@ export class BlocklyLayout extends PanelLayout {
111120
`
112121
);
113122
} else {
114-
SimplifiedOutputArea.execute(code, this._outputArea, this._sessionContext)
115-
.then(resp => {
116-
this.addWidget(this._outputArea);
117-
this._resizeWorkspace();
118-
})
123+
CodeCell.execute(this._cell, this._sessionContext)
124+
.then(() => this._resizeWorkspace())
119125
.catch(e => console.error(e));
120126
}
121127
}
@@ -155,19 +161,30 @@ export class BlocklyLayout extends PanelLayout {
155161
private _resizeWorkspace(): void {
156162
//Resize logic.
157163
const rect = this.parent.node.getBoundingClientRect();
158-
const { height } = this._outputArea.node.getBoundingClientRect();
159-
this._host.style.width = rect.width + 'px';
164+
const { height } = this._cell.node.getBoundingClientRect();
160165
const margin = rect.height / 3;
161166

162167
if (height > margin) {
163168
this._host.style.height = rect.height - margin + 'px';
164-
this._outputArea.node.style.height = margin + 'px';
165-
this._outputArea.node.style.overflowY = 'scroll';
169+
this._cell.node.style.height = margin + 'px';
170+
this._cell.node.style.overflowY = 'scroll';
166171
} else {
167172
this._host.style.height = rect.height - height + 'px';
168-
this._outputArea.node.style.overflowY = 'hidden';
173+
this._cell.node.style.overflowY = 'scroll';
169174
}
170175

171176
Blockly.svgResize(this._workspace);
172177
}
178+
179+
private _onManagerChanged(
180+
sender: BlocklyManager,
181+
change: BlocklyManager.Change
182+
) {
183+
if (change === 'kernel') {
184+
// Serializing our workspace into the chosen language generator.
185+
const code = this._manager.generator.workspaceToCode(this._workspace);
186+
this._cell.model.sharedModel.setSource(code);
187+
this._cell.model.mimeType = this._manager.mimeType;
188+
}
189+
}
173190
}

src/manager.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ISessionContext } from '@jupyterlab/apputils';
2+
import { IEditorMimeTypeService } from '@jupyterlab/codeeditor';
23
import { KernelSpec, KernelConnection } from '@jupyterlab/services';
34
import { IChangedArgs } from '@jupyterlab/coreutils';
45

@@ -20,14 +21,20 @@ export class BlocklyManager {
2021
private _registry: BlocklyRegistry;
2122
private _selectedKernel: KernelSpec.ISpecModel;
2223
private _sessionContext: ISessionContext;
24+
private _mimetypeService: IEditorMimeTypeService;
2325
private _changed: Signal<this, BlocklyManager.Change>;
2426

2527
/**
2628
* Constructor of BlocklyManager.
2729
*/
28-
constructor(registry: BlocklyRegistry, sessionContext: ISessionContext) {
30+
constructor(
31+
registry: BlocklyRegistry,
32+
sessionContext: ISessionContext,
33+
mimetypeService: IEditorMimeTypeService
34+
) {
2935
this._registry = registry;
3036
this._sessionContext = sessionContext;
37+
this._mimetypeService = mimetypeService;
3138

3239
this._toolbox = this._registry.toolboxes.get('default');
3340
this._generator = this._registry.generators.get('python');
@@ -43,6 +50,22 @@ export class BlocklyManager {
4350
return this._toolbox;
4451
}
4552

53+
/**
54+
* Returns the mimeType for the selected kernel.
55+
*
56+
* Note: We need the mimeType for the syntax highlighting
57+
* when rendering the code.
58+
*/
59+
get mimeType(): string {
60+
if (this._selectedKernel) {
61+
return this._mimetypeService.getMimeTypeByLanguage({
62+
name: this._selectedKernel.language
63+
});
64+
} else {
65+
return 'text/plain';
66+
}
67+
}
68+
4669
/**
4770
* Returns the name of the selected kernel.
4871
*/

0 commit comments

Comments
 (0)