Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ tasks:
dev:build:
desc: Build docker image for dev
cmds:
- docker compose -f docker-compose.dev.yml build
- BUILDKIT_PROGRESS=plain docker compose -f docker-compose.dev.yml build

dev:up:
desc: Spin up the docker compose stack for dev
cmds:
- docker compose -f docker-compose.dev.yml up -d
- docker exec -it jupyterlab_code_formatter-dev-1 jlpm install
- docker compose -f docker-compose.dev.yml up

dev:down:
Expand Down
1 change: 1 addition & 0 deletions dev.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,5 @@ RUN --mount=type=cache,target=/root/.cache/pip \
pip install -e ".[test]"
RUN jupyter labextension develop . --overwrite
RUN jupyter server extension enable jupyterlab_code_formatter
RUN jlpm install
RUN jlpm build
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@
"watch:labextension": "jupyter labextension watch ."
},
"dependencies": {
"@jupyterlab/application": "^3.6.0 || ~4.0.0",
"@jupyterlab/application": "^3.6.0",
"@jupyterlab/coreutils": "^5.1.0",
"@jupyterlab/fileeditor": "^3.6.0 || ~4.0.0",
"@jupyterlab/mainmenu": "^3.6.0 || ~4.0.0",
"@jupyterlab/fileeditor": "^3.6.0",
"@jupyterlab/mainmenu": "^3.6.0",
"@jupyterlab/services": "^6.1.0",
"@jupyterlab/settingregistry": "^3.6.0 || ~4.0.0"
"@jupyterlab/settingregistry": "^3.6.0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@jupyterlab/builder": "^3.6.0 || ~4.0.0",
"@jupyterlab/testutils": "^3.6.0 || ~4.0.0",
"@jupyterlab/builder": "^3.6.0",
"@jupyterlab/testutils": "^3.6.0",
"@types/jest": "^26.0.0",
"@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1",
Expand Down
145 changes: 118 additions & 27 deletions src/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -268,39 +268,130 @@ export class JupyterlabFileEditorCodeFormatter extends JupyterlabCodeFormatter {
}

formatAction(config: any, formatter: string) {
return this.formatEditor(config, { saving: false }, formatter);
}

public async formatEditor(
config: any,
context: Context,
formatter?: string,
) {
if (this.working) {
return;
}
const editorWidget = this.editorTracker.currentWidget;
this.working = true;
const editor = editorWidget!.content.editor;
const code = editor.model.sharedModel.source;
this.formatCode(
[code],
formatter,
config[formatter],
false,
config.cacheFormatters
)
.then(data => {
if (data.code[0].error) {
void showErrorMessage(
'Jupyterlab Code Formatter Error',
data.code[0].error
try {
this.working = true;

const formattersToUse = await this.getFormattersToUse(config, formatter);
await this.applyFormatters(
formattersToUse,
config,
context
);
} catch (error) {
await showErrorMessage('Jupyterlab Code Formatter Error', error);
}
this.working = false;
}

private getEditorType() {
if (!this.editorTracker.currentWidget) {
return null;
}

const mimeType =
this.editorTracker.currentWidget.content.model!.mimeType;

const mimeTypes = new Map([
['text/x-python', 'python'],
['application/x-rsrc', 'r'],
['application/x-scala', 'scala'],
['application/x-rustsrc', 'rust'],
['application/x-c++src', 'cpp'], // Not sure that this is right, whatever.
// Add more MIME types and corresponding programming languages here
]);

return mimeTypes.get(mimeType);
}

private getDefaultFormatters(config: any): Array<string> {
const editorType = this.getEditorType();
if (editorType) {
const defaultFormatter =
config.preferences.default_formatter[editorType];
if (defaultFormatter instanceof Array) {
return defaultFormatter;
} else if (defaultFormatter !== undefined) {
return [defaultFormatter];
}
}
return [];
}

private async getFormattersToUse(config: any, formatter?: string) {
const defaultFormatters = this.getDefaultFormatters(config);
const formattersToUse =
formatter !== undefined ? [formatter] : defaultFormatters;

if (formattersToUse.length === 0) {
await showErrorMessage(
'Jupyterlab Code Formatter Error',
'Unable to find default formatters to use, please file an issue on GitHub.'
);
}

return formattersToUse;
}

private async applyFormatters(
formattersToUse: string[],
config: any,
context: Context
) {
for (const formatterToUse of formattersToUse) {
if (formatterToUse === 'noop' || formatterToUse === 'skip') {
continue;
}
const showErrors =
!(config.suppressFormatterErrors ?? false) &&
!(
(config.suppressFormatterErrorsIFFAutoFormatOnSave ?? false) &&
context.saving
);
this.working = false;
return;
}
this.editorTracker.currentWidget!.content.editor.model.sharedModel.source =
data.code[0].code;
this.working = false;
})
.catch(error => {
this.working = false;
void showErrorMessage('Jupyterlab Code Formatter Error', error);
});

const editorWidget = this.editorTracker.currentWidget;
this.working = true;
const editor = editorWidget!.content.editor;
const code = editor.model.sharedModel.source;
this.formatCode(
[code],
formatterToUse,
config[formatterToUse],
false,
config.cacheFormatters
)
.then(data => {
if (data.code[0].error) {
if (showErrors) {
void showErrorMessage(
'Jupyterlab Code Formatter Error',
data.code[0].error
);
}
this.working = false;
return;
}
this.editorTracker.currentWidget!.content.editor.model.sharedModel.source =
data.code[0].code;
this.working = false;
})
.catch(error => {
void showErrorMessage('Jupyterlab Code Formatter Error', error);
});
}
}


applicable(formatter: string, currentWidget: Widget) {
const currentEditorWidget = this.editorTracker.currentWidget;
// TODO: Handle showing just the correct formatter for the language later
Expand Down
27 changes: 26 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DocumentRegistry } from '@jupyterlab/docregistry';
import { DocumentRegistry, DocumentWidget, DocumentModel } from '@jupyterlab/docregistry';
import {
INotebookModel,
INotebookTracker,
Expand Down Expand Up @@ -113,8 +113,33 @@ class JupyterLabCodeFormatter
}
}

private createNewEditor(widget: DocumentWidget, context: DocumentRegistry.IContext<DocumentModel>): IDisposable {
// Connect to save(State) signal, to be able to detect document save event
context.saveState.connect(this.onSaveEditor, this);
// Return an empty disposable, because we don't create any object
return new DisposableDelegate(() => { });
}

private async onSaveEditor(
context: DocumentRegistry.IContext<DocumentModel>,
state: DocumentRegistry.SaveState
) {
if (state === 'started' && this.config.formatOnSave) {
this.fileEditorCodeFormatter.formatEditor(
this.config,
{saving: true},
undefined,
)
}
}

private setupWidgetExtension() {
this.app.docRegistry.addWidgetExtension('Notebook', this);
this.app.docRegistry.addWidgetExtension('editor', {
createNew: (widget: DocumentWidget, context: DocumentRegistry.IContext<DocumentModel>): IDisposable => {
return this.createNewEditor(widget, context);
}
});
}

private setupContextMenu() {
Expand Down
3 changes: 2 additions & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"strict": true,
"strictNullChecks": true,
"target": "ES2018",
"types": ["jest"]
"types": ["jest"],
"skipLibCheck": true
},
"include": ["src/*"]
}
Loading