@jupyterlab/fileeditor 4.0.0-alpha.9 → 4.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/fileeditorlspadapter.d.ts +96 -0
- package/lib/fileeditorlspadapter.js +175 -0
- package/lib/fileeditorlspadapter.js.map +1 -0
- package/lib/index.d.ts +4 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -1
- package/lib/searchprovider.d.ts +60 -0
- package/lib/searchprovider.js +80 -0
- package/lib/searchprovider.js.map +1 -0
- package/lib/syntaxstatus.d.ts +74 -0
- package/lib/syntaxstatus.js +151 -0
- package/lib/syntaxstatus.js.map +1 -0
- package/lib/tabspacestatus.d.ts +8 -12
- package/lib/tabspacestatus.js +23 -27
- package/lib/tabspacestatus.js.map +1 -1
- package/lib/toc/factory.d.ts +25 -0
- package/lib/toc/factory.js +32 -0
- package/lib/toc/factory.js.map +1 -0
- package/lib/toc/index.d.ts +4 -0
- package/lib/toc/index.js +7 -0
- package/lib/toc/index.js.map +1 -0
- package/lib/toc/latex.d.ts +48 -0
- package/lib/toc/latex.js +117 -0
- package/lib/toc/latex.js.map +1 -0
- package/lib/toc/markdown.d.ts +44 -0
- package/lib/toc/markdown.js +68 -0
- package/lib/toc/markdown.js.map +1 -0
- package/lib/toc/python.d.ts +44 -0
- package/lib/toc/python.js +116 -0
- package/lib/toc/python.js.map +1 -0
- package/lib/widget.d.ts +4 -0
- package/lib/widget.js +21 -4
- package/lib/widget.js.map +1 -1
- package/package.json +26 -21
- package/src/fileeditorlspadapter.ts +225 -0
- package/src/index.ts +14 -0
- package/src/searchprovider.ts +115 -0
- package/src/syntaxstatus.tsx +217 -0
- package/src/tabspacestatus.tsx +166 -0
- package/src/toc/factory.ts +72 -0
- package/src/toc/index.ts +7 -0
- package/src/toc/latex.ts +145 -0
- package/src/toc/markdown.ts +90 -0
- package/src/toc/python.ts +143 -0
- package/src/tokens.ts +20 -0
- package/src/widget.ts +267 -0
- package/style/base.css +8 -0
- package/style/index.css +4 -0
- package/style/index.js +4 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
import { TableOfContentsModel } from '@jupyterlab/toc';
|
|
4
|
+
import { EditorTableOfContentsFactory } from './factory';
|
|
5
|
+
/**
|
|
6
|
+
* Regular expression to create the outline
|
|
7
|
+
*/
|
|
8
|
+
let KEYWORDS;
|
|
9
|
+
try {
|
|
10
|
+
// https://github.com/tc39/proposal-regexp-match-indices was accepted
|
|
11
|
+
// in May 2021 (https://github.com/tc39/proposals/blob/main/finished-proposals.md)
|
|
12
|
+
// So we will fallback to the polyfill regexp-match-indices if not available
|
|
13
|
+
KEYWORDS = new RegExp('^\\s*(class |def |from |import )', 'd');
|
|
14
|
+
}
|
|
15
|
+
catch (_a) {
|
|
16
|
+
KEYWORDS = new RegExp('^\\s*(class |def |from |import )');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Table of content model for Python files.
|
|
20
|
+
*/
|
|
21
|
+
export class PythonTableOfContentsModel extends TableOfContentsModel {
|
|
22
|
+
/**
|
|
23
|
+
* Type of document supported by the model.
|
|
24
|
+
*
|
|
25
|
+
* #### Notes
|
|
26
|
+
* A `data-document-type` attribute with this value will be set
|
|
27
|
+
* on the tree view `.jp-TableOfContents-content[data-document-type="..."]`
|
|
28
|
+
*/
|
|
29
|
+
get documentType() {
|
|
30
|
+
return 'python';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Produce the headings for a document.
|
|
34
|
+
*
|
|
35
|
+
* @returns The list of new headings or `null` if nothing needs to be updated.
|
|
36
|
+
*/
|
|
37
|
+
async getHeadings() {
|
|
38
|
+
if (!this.isActive) {
|
|
39
|
+
return Promise.resolve(null);
|
|
40
|
+
}
|
|
41
|
+
// Split the text into lines:
|
|
42
|
+
const lines = this.widget.content.model.sharedModel
|
|
43
|
+
.getSource()
|
|
44
|
+
.split('\n');
|
|
45
|
+
// Iterate over the lines to get the heading level and text for each line:
|
|
46
|
+
let headings = new Array();
|
|
47
|
+
let processingImports = false;
|
|
48
|
+
let indent = 1;
|
|
49
|
+
let lineIdx = -1;
|
|
50
|
+
for (const line of lines) {
|
|
51
|
+
lineIdx++;
|
|
52
|
+
let hasKeyword;
|
|
53
|
+
if (KEYWORDS.flags.includes('d')) {
|
|
54
|
+
hasKeyword = KEYWORDS.exec(line);
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const { default: execWithIndices } = await import('regexp-match-indices');
|
|
58
|
+
hasKeyword = execWithIndices(KEYWORDS, line);
|
|
59
|
+
}
|
|
60
|
+
if (hasKeyword) {
|
|
61
|
+
// Index 0 contains the spaces, index 1 is the keyword group
|
|
62
|
+
const [start] = hasKeyword.indices[1];
|
|
63
|
+
if (indent === 1 && start > 0) {
|
|
64
|
+
indent = start;
|
|
65
|
+
}
|
|
66
|
+
const isImport = ['from ', 'import '].includes(hasKeyword[1]);
|
|
67
|
+
if (isImport && processingImports) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
processingImports = isImport;
|
|
71
|
+
const level = 1 + start / indent;
|
|
72
|
+
if (level > this.configuration.maximalDepth) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
headings.push({
|
|
76
|
+
text: line.slice(start),
|
|
77
|
+
level,
|
|
78
|
+
line: lineIdx
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return Promise.resolve(headings);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Table of content model factory for Python files.
|
|
87
|
+
*/
|
|
88
|
+
export class PythonTableOfContentsFactory extends EditorTableOfContentsFactory {
|
|
89
|
+
/**
|
|
90
|
+
* Whether the factory can handle the widget or not.
|
|
91
|
+
*
|
|
92
|
+
* @param widget - widget
|
|
93
|
+
* @returns boolean indicating a ToC can be generated
|
|
94
|
+
*/
|
|
95
|
+
isApplicable(widget) {
|
|
96
|
+
var _a, _b;
|
|
97
|
+
const isApplicable = super.isApplicable(widget);
|
|
98
|
+
if (isApplicable) {
|
|
99
|
+
let mime = (_b = (_a = widget.content) === null || _a === void 0 ? void 0 : _a.model) === null || _b === void 0 ? void 0 : _b.mimeType;
|
|
100
|
+
return (mime &&
|
|
101
|
+
(mime === 'application/x-python-code' || mime === 'text/x-python'));
|
|
102
|
+
}
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Create a new table of contents model for the widget
|
|
107
|
+
*
|
|
108
|
+
* @param widget - widget
|
|
109
|
+
* @param configuration - Table of contents configuration
|
|
110
|
+
* @returns The table of contents model
|
|
111
|
+
*/
|
|
112
|
+
_createNew(widget, configuration) {
|
|
113
|
+
return new PythonTableOfContentsModel(widget, configuration);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=python.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"python.js","sourceRoot":"","sources":["../../src/toc/python.ts"],"names":[],"mappings":"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"}
|
package/lib/widget.d.ts
CHANGED
package/lib/widget.js
CHANGED
|
@@ -28,7 +28,10 @@ export class FileEditor extends Widget {
|
|
|
28
28
|
this._mimeTypeService = options.mimeTypeService;
|
|
29
29
|
const editorWidget = (this._editorWidget = new CodeEditorWrapper({
|
|
30
30
|
factory: options.factory,
|
|
31
|
-
model: context.model
|
|
31
|
+
model: context.model,
|
|
32
|
+
editorOptions: {
|
|
33
|
+
config: FileEditor.defaultEditorConfig
|
|
34
|
+
}
|
|
32
35
|
}));
|
|
33
36
|
this._editorWidget.addClass('jp-FileEditorCodeWrapper');
|
|
34
37
|
this._editorWidget.node.dataset[CODE_RUNNER] = 'true';
|
|
@@ -39,8 +42,8 @@ export class FileEditor extends Widget {
|
|
|
39
42
|
this._onContextReady();
|
|
40
43
|
});
|
|
41
44
|
// Listen for changes to the path.
|
|
42
|
-
context.pathChanged.connect(this._onPathChanged, this);
|
|
43
45
|
this._onPathChanged();
|
|
46
|
+
context.pathChanged.connect(this._onPathChanged, this);
|
|
44
47
|
const layout = (this.layout = new StackedLayout());
|
|
45
48
|
layout.addWidget(editorWidget);
|
|
46
49
|
}
|
|
@@ -54,7 +57,7 @@ export class FileEditor extends Widget {
|
|
|
54
57
|
* A promise that resolves when the file editor is ready.
|
|
55
58
|
*/
|
|
56
59
|
get ready() {
|
|
57
|
-
return this.
|
|
60
|
+
return this._ready.promise;
|
|
58
61
|
}
|
|
59
62
|
/**
|
|
60
63
|
* Handle the DOM events for the widget.
|
|
@@ -125,9 +128,22 @@ export class FileEditor extends Widget {
|
|
|
125
128
|
_onPathChanged() {
|
|
126
129
|
const editor = this.editor;
|
|
127
130
|
const localPath = this._context.localPath;
|
|
128
|
-
editor.model.mimeType =
|
|
131
|
+
editor.model.mimeType =
|
|
132
|
+
this._mimeTypeService.getMimeTypeByFilePath(localPath);
|
|
129
133
|
}
|
|
130
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* The namespace for editor widget statics.
|
|
137
|
+
*/
|
|
138
|
+
(function (FileEditor) {
|
|
139
|
+
/**
|
|
140
|
+
* File editor default configuration.
|
|
141
|
+
*/
|
|
142
|
+
FileEditor.defaultEditorConfig = {
|
|
143
|
+
lineNumbers: true,
|
|
144
|
+
scrollPastEnd: true
|
|
145
|
+
};
|
|
146
|
+
})(FileEditor || (FileEditor = {}));
|
|
131
147
|
/**
|
|
132
148
|
* A widget factory for editors.
|
|
133
149
|
*/
|
|
@@ -145,6 +161,7 @@ export class FileEditorFactory extends ABCWidgetFactory {
|
|
|
145
161
|
createNewWidget(context) {
|
|
146
162
|
const func = this._services.factoryService.newDocumentEditor;
|
|
147
163
|
const factory = options => {
|
|
164
|
+
// Use same id as document factory
|
|
148
165
|
return func(options);
|
|
149
166
|
};
|
|
150
167
|
const content = new FileEditor({
|
package/lib/widget.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"AAAA,0CAA0C;AAC1C,2DAA2D;AAE3D,OAAO,EAEL,iBAAiB,EAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,gBAAgB,EAEhB,cAAc,EAEf,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAExD;;GAEG;AACH,MAAM,WAAW,GAAG,cAAc,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,GAAG,UAAU,CAAC;AAE1B;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,MAAM;IACpC;;OAEG;IACH,YAAY,OAA4B;QACtC,KAAK,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"widget.js","sourceRoot":"","sources":["../src/widget.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyterlab/fileeditor",
|
|
3
|
-
"version": "4.0.0-
|
|
3
|
+
"version": "4.0.0-beta.0",
|
|
4
4
|
"description": "JupyterLab - Editor Widget",
|
|
5
5
|
"homepage": "https://github.com/jupyterlab/jupyterlab",
|
|
6
6
|
"bugs": {
|
|
@@ -23,11 +23,10 @@
|
|
|
23
23
|
"lib": "lib/"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
|
-
"lib
|
|
27
|
-
"lib/*.js.map",
|
|
28
|
-
"lib/*.js",
|
|
26
|
+
"lib/**/*.{d.ts,js,js.map}",
|
|
29
27
|
"style/*.css",
|
|
30
|
-
"style/index.js"
|
|
28
|
+
"style/index.js",
|
|
29
|
+
"src/**/*.{ts,tsx}"
|
|
31
30
|
],
|
|
32
31
|
"scripts": {
|
|
33
32
|
"build": "tsc -b",
|
|
@@ -41,25 +40,31 @@
|
|
|
41
40
|
"watch": "tsc -b --watch"
|
|
42
41
|
},
|
|
43
42
|
"dependencies": {
|
|
44
|
-
"@jupyterlab/apputils": "^4.0.0-
|
|
45
|
-
"@jupyterlab/codeeditor": "^4.0.0-
|
|
46
|
-
"@jupyterlab/
|
|
47
|
-
"@jupyterlab/
|
|
48
|
-
"@jupyterlab/
|
|
49
|
-
"@jupyterlab/
|
|
50
|
-
"@
|
|
51
|
-
"@
|
|
52
|
-
"@
|
|
53
|
-
"
|
|
43
|
+
"@jupyterlab/apputils": "^4.0.0-beta.0",
|
|
44
|
+
"@jupyterlab/codeeditor": "^4.0.0-beta.0",
|
|
45
|
+
"@jupyterlab/codemirror": "^4.0.0-beta.0",
|
|
46
|
+
"@jupyterlab/coreutils": "^6.0.0-beta.0",
|
|
47
|
+
"@jupyterlab/docregistry": "^4.0.0-beta.0",
|
|
48
|
+
"@jupyterlab/documentsearch": "^4.0.0-beta.0",
|
|
49
|
+
"@jupyterlab/lsp": "^4.0.0-beta.0",
|
|
50
|
+
"@jupyterlab/statusbar": "^4.0.0-beta.0",
|
|
51
|
+
"@jupyterlab/toc": "^6.0.0-beta.0",
|
|
52
|
+
"@jupyterlab/translation": "^4.0.0-beta.0",
|
|
53
|
+
"@jupyterlab/ui-components": "^4.0.0-beta.0",
|
|
54
|
+
"@lumino/commands": "^2.0.0",
|
|
55
|
+
"@lumino/coreutils": "^2.0.0",
|
|
56
|
+
"@lumino/messaging": "^2.0.0",
|
|
57
|
+
"@lumino/widgets": "^2.0.0",
|
|
58
|
+
"react": "^18.2.0",
|
|
59
|
+
"regexp-match-indices": "^1.0.2"
|
|
54
60
|
},
|
|
55
61
|
"devDependencies": {
|
|
56
|
-
"@jupyterlab/
|
|
57
|
-
"@types/jest": "^
|
|
58
|
-
"jest": "^
|
|
62
|
+
"@jupyterlab/testing": "^4.0.0-beta.0",
|
|
63
|
+
"@types/jest": "^29.2.0",
|
|
64
|
+
"jest": "^29.2.0",
|
|
59
65
|
"rimraf": "~3.0.0",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"typescript": "~4.6.3"
|
|
66
|
+
"typedoc": "~0.23.25",
|
|
67
|
+
"typescript": "~5.0.2"
|
|
63
68
|
},
|
|
64
69
|
"publishConfig": {
|
|
65
70
|
"access": "public"
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { CodeMirrorEditor } from '@jupyterlab/codemirror';
|
|
5
|
+
import { DocumentRegistry, IDocumentWidget } from '@jupyterlab/docregistry';
|
|
6
|
+
import {
|
|
7
|
+
Document,
|
|
8
|
+
IAdapterOptions,
|
|
9
|
+
IVirtualPosition,
|
|
10
|
+
VirtualDocument,
|
|
11
|
+
WidgetLSPAdapter
|
|
12
|
+
} from '@jupyterlab/lsp';
|
|
13
|
+
import { PromiseDelegate } from '@lumino/coreutils';
|
|
14
|
+
|
|
15
|
+
import { FileEditor } from './widget';
|
|
16
|
+
|
|
17
|
+
export interface IFileEditorAdapterOptions extends IAdapterOptions {
|
|
18
|
+
/**
|
|
19
|
+
* The document registry instance.
|
|
20
|
+
*/
|
|
21
|
+
docRegistry: DocumentRegistry;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class FileEditorAdapter extends WidgetLSPAdapter<
|
|
25
|
+
IDocumentWidget<FileEditor>
|
|
26
|
+
> {
|
|
27
|
+
constructor(
|
|
28
|
+
editorWidget: IDocumentWidget<FileEditor>,
|
|
29
|
+
options: IFileEditorAdapterOptions
|
|
30
|
+
) {
|
|
31
|
+
const { docRegistry, ...others } = options;
|
|
32
|
+
super(editorWidget, others);
|
|
33
|
+
this.editor = editorWidget.content;
|
|
34
|
+
this._docRegistry = docRegistry;
|
|
35
|
+
|
|
36
|
+
// Ensure editor uniqueness
|
|
37
|
+
this._virtualEditor = Object.freeze({
|
|
38
|
+
getEditor: () => this.editor.editor,
|
|
39
|
+
ready: () => Promise.resolve(this.editor.editor),
|
|
40
|
+
reveal: () => Promise.resolve(this.editor.editor)
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
Promise.all([this.editor.context.ready, this.connectionManager.ready])
|
|
44
|
+
.then(async () => {
|
|
45
|
+
await this.initOnceReady();
|
|
46
|
+
this._readyDelegate.resolve();
|
|
47
|
+
})
|
|
48
|
+
.catch(console.error);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The wrapped `FileEditor` widget.
|
|
53
|
+
*/
|
|
54
|
+
readonly editor: FileEditor;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Promise that resolves once the adapter is initialized
|
|
58
|
+
*/
|
|
59
|
+
get ready(): Promise<void> {
|
|
60
|
+
return this._readyDelegate.promise;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get current path of the document.
|
|
65
|
+
*/
|
|
66
|
+
get documentPath(): string {
|
|
67
|
+
return this.widget.context.path;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Get the mime type of the document.
|
|
72
|
+
*/
|
|
73
|
+
get mimeType(): string {
|
|
74
|
+
const mimeTypeFromModel = this.editor.model.mimeType;
|
|
75
|
+
const codeMirrorMimeType: string = Array.isArray(mimeTypeFromModel)
|
|
76
|
+
? mimeTypeFromModel[0] ?? 'text/plain'
|
|
77
|
+
: mimeTypeFromModel;
|
|
78
|
+
const contentsModel = this.editor.context.contentsModel;
|
|
79
|
+
|
|
80
|
+
// when MIME type is not known it defaults to 'text/plain',
|
|
81
|
+
// so if it is different we can accept it as it is
|
|
82
|
+
if (codeMirrorMimeType != 'text/plain') {
|
|
83
|
+
return codeMirrorMimeType;
|
|
84
|
+
} else if (contentsModel) {
|
|
85
|
+
// a script that does not have a MIME type known by the editor
|
|
86
|
+
// (no syntax highlight mode), can still be known by the document
|
|
87
|
+
// registry (and this is arguably easier to extend).
|
|
88
|
+
let fileType = this._docRegistry.getFileTypeForModel(contentsModel);
|
|
89
|
+
return fileType.mimeTypes[0];
|
|
90
|
+
} else {
|
|
91
|
+
// "text/plain" this is
|
|
92
|
+
return codeMirrorMimeType;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get the file extension of the document.
|
|
98
|
+
*/
|
|
99
|
+
get languageFileExtension(): string {
|
|
100
|
+
let parts = this.documentPath.split('.');
|
|
101
|
+
return parts[parts.length - 1];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get the CM editor
|
|
106
|
+
*/
|
|
107
|
+
get ceEditor(): CodeMirrorEditor {
|
|
108
|
+
return this.editor.editor as CodeMirrorEditor;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get the activated CM editor.
|
|
113
|
+
*/
|
|
114
|
+
get activeEditor(): Document.IEditor {
|
|
115
|
+
return this._virtualEditor;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get the inner HTMLElement of the document widget.
|
|
120
|
+
*/
|
|
121
|
+
get wrapperElement(): HTMLElement {
|
|
122
|
+
return this.widget.node;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get current path of the document.
|
|
127
|
+
*/
|
|
128
|
+
get path(): string {
|
|
129
|
+
return this.widget.context.path;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get the list of CM editors in the document, there is only one editor
|
|
134
|
+
* in the case of file editor.
|
|
135
|
+
*/
|
|
136
|
+
get editors(): Document.ICodeBlockOptions[] {
|
|
137
|
+
return [
|
|
138
|
+
{
|
|
139
|
+
ceEditor: this._virtualEditor,
|
|
140
|
+
type: 'code',
|
|
141
|
+
value: this.editor?.model.sharedModel.getSource() ?? ''
|
|
142
|
+
}
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Dispose the widget.
|
|
148
|
+
*/
|
|
149
|
+
dispose(): void {
|
|
150
|
+
if (this.isDisposed) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.editor.model.mimeTypeChanged.disconnect(this.reloadConnection);
|
|
154
|
+
super.dispose();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Generate the virtual document associated with the document.
|
|
159
|
+
*/
|
|
160
|
+
createVirtualDocument(): VirtualDocument {
|
|
161
|
+
return new VirtualDocument({
|
|
162
|
+
language: this.language,
|
|
163
|
+
foreignCodeExtractors: this.options.foreignCodeExtractorsManager,
|
|
164
|
+
path: this.documentPath,
|
|
165
|
+
fileExtension: this.languageFileExtension,
|
|
166
|
+
// notebooks are continuous, each cell is dependent on the previous one
|
|
167
|
+
standalone: true,
|
|
168
|
+
// notebooks are not supported by LSP servers
|
|
169
|
+
hasLspSupportedFile: true
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Get the index of editor from the cursor position in the virtual
|
|
175
|
+
* document. Since there is only one editor, this method always return
|
|
176
|
+
* 0
|
|
177
|
+
*
|
|
178
|
+
* @param position - the position of cursor in the virtual document.
|
|
179
|
+
* @return {number} - index of the virtual editor
|
|
180
|
+
*/
|
|
181
|
+
getEditorIndexAt(position: IVirtualPosition): number {
|
|
182
|
+
return 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Get the index of input editor
|
|
187
|
+
*
|
|
188
|
+
* @param ceEditor - instance of the code editor
|
|
189
|
+
*/
|
|
190
|
+
getEditorIndex(ceEditor: Document.IEditor): number {
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get the wrapper of input editor.
|
|
196
|
+
*
|
|
197
|
+
* @param ceEditor
|
|
198
|
+
* @return {HTMLElement}
|
|
199
|
+
*/
|
|
200
|
+
getEditorWrapper(ceEditor: Document.IEditor): HTMLElement {
|
|
201
|
+
return this.wrapperElement;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Initialization function called once the editor and the LSP connection
|
|
206
|
+
* manager is ready. This function will create the virtual document and
|
|
207
|
+
* connect various signals.
|
|
208
|
+
*/
|
|
209
|
+
protected async initOnceReady(): Promise<void> {
|
|
210
|
+
this.initVirtual();
|
|
211
|
+
|
|
212
|
+
// connect the document, but do not open it as the adapter will handle this
|
|
213
|
+
// after registering all features
|
|
214
|
+
await this.connectDocument(this.virtualDocument!, false);
|
|
215
|
+
|
|
216
|
+
this.editor.model.mimeTypeChanged.connect(this.reloadConnection, this);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* The document registry instance.
|
|
221
|
+
*/
|
|
222
|
+
private readonly _docRegistry: DocumentRegistry;
|
|
223
|
+
private readonly _virtualEditor: Document.IEditor;
|
|
224
|
+
private _readyDelegate = new PromiseDelegate<void>();
|
|
225
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
/**
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
* @module fileeditor
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export * from './fileeditorlspadapter';
|
|
9
|
+
export * from './searchprovider';
|
|
10
|
+
export * from './syntaxstatus';
|
|
11
|
+
export * from './tabspacestatus';
|
|
12
|
+
export * from './toc';
|
|
13
|
+
export * from './tokens';
|
|
14
|
+
export * from './widget';
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
// Copyright (c) Jupyter Development Team.
|
|
2
|
+
// Distributed under the terms of the Modified BSD License.
|
|
3
|
+
|
|
4
|
+
import { MainAreaWidget } from '@jupyterlab/apputils';
|
|
5
|
+
import { CodeMirrorEditor, EditorSearchProvider } from '@jupyterlab/codemirror';
|
|
6
|
+
import { CodeEditor } from '@jupyterlab/codeeditor';
|
|
7
|
+
import {
|
|
8
|
+
IFilters,
|
|
9
|
+
IReplaceOptionsSupport,
|
|
10
|
+
ISearchProvider
|
|
11
|
+
} from '@jupyterlab/documentsearch';
|
|
12
|
+
import { ITranslator } from '@jupyterlab/translation';
|
|
13
|
+
import { Widget } from '@lumino/widgets';
|
|
14
|
+
import { FileEditor } from './widget';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Helper type
|
|
18
|
+
*/
|
|
19
|
+
export type FileEditorPanel = MainAreaWidget<FileEditor>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* File editor search provider
|
|
23
|
+
*/
|
|
24
|
+
export class FileEditorSearchProvider
|
|
25
|
+
extends EditorSearchProvider<CodeEditor.IModel>
|
|
26
|
+
implements ISearchProvider
|
|
27
|
+
{
|
|
28
|
+
/**
|
|
29
|
+
* Constructor
|
|
30
|
+
* @param widget File editor panel
|
|
31
|
+
*/
|
|
32
|
+
constructor(protected widget: FileEditorPanel) {
|
|
33
|
+
super();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get isReadOnly(): boolean {
|
|
37
|
+
return this.editor.getOption('readOnly') as boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Support for options adjusting replacement behavior.
|
|
42
|
+
*/
|
|
43
|
+
get replaceOptionsSupport(): IReplaceOptionsSupport {
|
|
44
|
+
return {
|
|
45
|
+
preserveCase: true
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Text editor
|
|
51
|
+
*/
|
|
52
|
+
get editor() {
|
|
53
|
+
return this.widget.content.editor as CodeMirrorEditor;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Editor content model
|
|
58
|
+
*/
|
|
59
|
+
get model(): CodeEditor.IModel {
|
|
60
|
+
return this.widget.content.model;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async startQuery(
|
|
64
|
+
query: RegExp,
|
|
65
|
+
filters: IFilters | undefined
|
|
66
|
+
): Promise<void> {
|
|
67
|
+
await super.startQuery(query, filters);
|
|
68
|
+
await this.highlightNext(false, true);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Instantiate a search provider for the widget.
|
|
73
|
+
*
|
|
74
|
+
* #### Notes
|
|
75
|
+
* The widget provided is always checked using `isApplicable` before calling
|
|
76
|
+
* this factory.
|
|
77
|
+
*
|
|
78
|
+
* @param widget The widget to search on
|
|
79
|
+
* @param translator [optional] The translator object
|
|
80
|
+
*
|
|
81
|
+
* @returns The search provider on the widget
|
|
82
|
+
*/
|
|
83
|
+
static createNew(
|
|
84
|
+
widget: FileEditorPanel,
|
|
85
|
+
translator?: ITranslator
|
|
86
|
+
): ISearchProvider {
|
|
87
|
+
return new FileEditorSearchProvider(widget);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Report whether or not this provider has the ability to search on the given object
|
|
92
|
+
*/
|
|
93
|
+
static isApplicable(domain: Widget): domain is FileEditorPanel {
|
|
94
|
+
return (
|
|
95
|
+
domain instanceof MainAreaWidget &&
|
|
96
|
+
domain.content instanceof FileEditor &&
|
|
97
|
+
domain.content.editor instanceof CodeMirrorEditor
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get an initial query value if applicable so that it can be entered
|
|
103
|
+
* into the search box as an initial query
|
|
104
|
+
*
|
|
105
|
+
* @returns Initial value used to populate the search box.
|
|
106
|
+
*/
|
|
107
|
+
getInitialQuery(): string {
|
|
108
|
+
const cm = this.editor as CodeMirrorEditor;
|
|
109
|
+
const selection = cm.state.sliceDoc(
|
|
110
|
+
cm.state.selection.main.from,
|
|
111
|
+
cm.state.selection.main.to
|
|
112
|
+
);
|
|
113
|
+
return selection;
|
|
114
|
+
}
|
|
115
|
+
}
|