@jupyterlab/fileeditor 4.0.0-alpha.8 → 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.
Files changed (49) hide show
  1. package/lib/fileeditorlspadapter.d.ts +96 -0
  2. package/lib/fileeditorlspadapter.js +175 -0
  3. package/lib/fileeditorlspadapter.js.map +1 -0
  4. package/lib/index.d.ts +4 -0
  5. package/lib/index.js +4 -0
  6. package/lib/index.js.map +1 -1
  7. package/lib/searchprovider.d.ts +60 -0
  8. package/lib/searchprovider.js +80 -0
  9. package/lib/searchprovider.js.map +1 -0
  10. package/lib/syntaxstatus.d.ts +74 -0
  11. package/lib/syntaxstatus.js +151 -0
  12. package/lib/syntaxstatus.js.map +1 -0
  13. package/lib/tabspacestatus.d.ts +8 -12
  14. package/lib/tabspacestatus.js +23 -27
  15. package/lib/tabspacestatus.js.map +1 -1
  16. package/lib/toc/factory.d.ts +25 -0
  17. package/lib/toc/factory.js +32 -0
  18. package/lib/toc/factory.js.map +1 -0
  19. package/lib/toc/index.d.ts +4 -0
  20. package/lib/toc/index.js +7 -0
  21. package/lib/toc/index.js.map +1 -0
  22. package/lib/toc/latex.d.ts +48 -0
  23. package/lib/toc/latex.js +117 -0
  24. package/lib/toc/latex.js.map +1 -0
  25. package/lib/toc/markdown.d.ts +44 -0
  26. package/lib/toc/markdown.js +68 -0
  27. package/lib/toc/markdown.js.map +1 -0
  28. package/lib/toc/python.d.ts +44 -0
  29. package/lib/toc/python.js +116 -0
  30. package/lib/toc/python.js.map +1 -0
  31. package/lib/widget.d.ts +12 -35
  32. package/lib/widget.js +45 -105
  33. package/lib/widget.js.map +1 -1
  34. package/package.json +26 -21
  35. package/src/fileeditorlspadapter.ts +225 -0
  36. package/src/index.ts +14 -0
  37. package/src/searchprovider.ts +115 -0
  38. package/src/syntaxstatus.tsx +217 -0
  39. package/src/tabspacestatus.tsx +166 -0
  40. package/src/toc/factory.ts +72 -0
  41. package/src/toc/index.ts +7 -0
  42. package/src/toc/latex.ts +145 -0
  43. package/src/toc/markdown.ts +90 -0
  44. package/src/toc/python.ts +143 -0
  45. package/src/tokens.ts +20 -0
  46. package/src/widget.ts +267 -0
  47. package/style/base.css +8 -0
  48. package/style/index.css +4 -0
  49. package/style/index.js +4 -0
@@ -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
+ }
@@ -0,0 +1,217 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import { CodeEditor, IEditorMimeTypeService } from '@jupyterlab/codeeditor';
7
+ import { IEditorLanguageRegistry } from '@jupyterlab/codemirror';
8
+ import { IChangedArgs } from '@jupyterlab/coreutils';
9
+ import { Popup, showPopup, TextItem } from '@jupyterlab/statusbar';
10
+ import { ITranslator, nullTranslator } from '@jupyterlab/translation';
11
+ import { VDomModel, VDomRenderer } from '@jupyterlab/ui-components';
12
+ import { CommandRegistry } from '@lumino/commands';
13
+ import { JSONObject } from '@lumino/coreutils';
14
+ import { Menu } from '@lumino/widgets';
15
+ import React from 'react';
16
+
17
+ /**
18
+ * A namespace for `EditorSyntaxComponentStatics`.
19
+ */
20
+ namespace EditorSyntaxComponent {
21
+ /**
22
+ * The props for the `EditorSyntaxComponent`.
23
+ */
24
+ export interface IProps {
25
+ /**
26
+ * The current CodeMirror language for an editor.
27
+ */
28
+ language: string;
29
+
30
+ /**
31
+ * A function to execute on clicking the component.
32
+ * By default we provide a function that opens a menu
33
+ * for CodeMirror language selection.
34
+ */
35
+ handleClick: () => void;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * A pure function that returns a tsx component for an editor syntax item.
41
+ *
42
+ * @param props: the props for the component.
43
+ *
44
+ * @returns an editor syntax component.
45
+ */
46
+ function EditorSyntaxComponent(
47
+ props: EditorSyntaxComponent.IProps
48
+ ): React.ReactElement<EditorSyntaxComponent.IProps> {
49
+ return <TextItem source={props.language} onClick={props.handleClick} />;
50
+ }
51
+
52
+ /**
53
+ * StatusBar item to change the language syntax highlighting of the file editor.
54
+ */
55
+ export class EditorSyntaxStatus extends VDomRenderer<EditorSyntaxStatus.Model> {
56
+ /**
57
+ * Construct a new VDomRenderer for the status item.
58
+ */
59
+ constructor(options: EditorSyntaxStatus.IOptions) {
60
+ super(new EditorSyntaxStatus.Model(options.languages));
61
+ this._commands = options.commands;
62
+ this.translator = options.translator ?? nullTranslator;
63
+ const trans = this.translator.load('jupyterlab');
64
+
65
+ this.addClass('jp-mod-highlighted');
66
+ this.title.caption = trans.__('Change text editor syntax highlighting');
67
+ }
68
+
69
+ /**
70
+ * Render the status item.
71
+ */
72
+ render(): JSX.Element | null {
73
+ if (!this.model) {
74
+ return null;
75
+ }
76
+ return (
77
+ <EditorSyntaxComponent
78
+ language={this.model.language}
79
+ handleClick={this._handleClick}
80
+ />
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Create a menu for selecting the language of the editor.
86
+ */
87
+ private _handleClick = () => {
88
+ const languageMenu = new Menu({ commands: this._commands });
89
+ const command = 'fileeditor:change-language';
90
+ if (this._popup) {
91
+ this._popup.dispose();
92
+ }
93
+ this.model.languages
94
+ .getLanguages()
95
+ .sort((a, b) => {
96
+ const aName = a.displayName ?? a.name;
97
+ const bName = b.displayName ?? b.name;
98
+ return aName.localeCompare(bName);
99
+ })
100
+ .forEach(spec => {
101
+ if (spec.name.toLowerCase().indexOf('brainf') === 0) {
102
+ return;
103
+ }
104
+
105
+ const args: JSONObject = {
106
+ name: spec.name,
107
+ displayName: spec.displayName ?? spec.name
108
+ };
109
+
110
+ languageMenu.addItem({
111
+ command,
112
+ args
113
+ });
114
+ });
115
+ this._popup = showPopup({
116
+ body: languageMenu,
117
+ anchor: this,
118
+ align: 'left'
119
+ });
120
+ };
121
+
122
+ protected translator: ITranslator;
123
+ private _commands: CommandRegistry;
124
+ private _popup: Popup | null = null;
125
+ }
126
+
127
+ /**
128
+ * A namespace for EditorSyntax statics.
129
+ */
130
+ export namespace EditorSyntaxStatus {
131
+ /**
132
+ * A VDomModel for the current editor/mode combination.
133
+ */
134
+ export class Model extends VDomModel {
135
+ constructor(public languages: IEditorLanguageRegistry) {
136
+ super();
137
+ }
138
+ /**
139
+ * The current editor language. If no editor is present,
140
+ * returns the empty string.
141
+ */
142
+ get language(): string {
143
+ return this._language;
144
+ }
145
+
146
+ /**
147
+ * The current editor for the application editor tracker.
148
+ */
149
+ get editor(): CodeEditor.IEditor | null {
150
+ return this._editor;
151
+ }
152
+ set editor(editor: CodeEditor.IEditor | null) {
153
+ const oldEditor = this._editor;
154
+ if (oldEditor !== null) {
155
+ oldEditor.model.mimeTypeChanged.disconnect(this._onMIMETypeChange);
156
+ }
157
+ const oldLanguage = this._language;
158
+ this._editor = editor;
159
+ if (this._editor === null) {
160
+ this._language = '';
161
+ } else {
162
+ const spec = this.languages.findByMIME(this._editor.model.mimeType);
163
+ this._language = spec?.name ?? IEditorMimeTypeService.defaultMimeType;
164
+
165
+ this._editor.model.mimeTypeChanged.connect(this._onMIMETypeChange);
166
+ }
167
+
168
+ this._triggerChange(oldLanguage, this._language);
169
+ }
170
+
171
+ /**
172
+ * If the editor mode changes, update the model.
173
+ */
174
+ private _onMIMETypeChange = (
175
+ mode: CodeEditor.IModel,
176
+ change: IChangedArgs<string>
177
+ ) => {
178
+ const oldLanguage = this._language;
179
+ const spec = this.languages.findByMIME(change.newValue);
180
+ this._language = spec?.name ?? IEditorMimeTypeService.defaultMimeType;
181
+
182
+ this._triggerChange(oldLanguage, this._language);
183
+ };
184
+
185
+ /**
186
+ * Trigger a rerender of the model.
187
+ */
188
+ private _triggerChange(oldState: string, newState: string) {
189
+ if (oldState !== newState) {
190
+ this.stateChanged.emit(void 0);
191
+ }
192
+ }
193
+
194
+ private _language: string = '';
195
+ private _editor: CodeEditor.IEditor | null = null;
196
+ }
197
+
198
+ /**
199
+ * Options for the EditorSyntax status item.
200
+ */
201
+ export interface IOptions {
202
+ /**
203
+ * The application command registry.
204
+ */
205
+ commands: CommandRegistry;
206
+
207
+ /**
208
+ * Editor languages.
209
+ */
210
+ languages: IEditorLanguageRegistry;
211
+
212
+ /**
213
+ * The language translator.
214
+ */
215
+ translator?: ITranslator;
216
+ }
217
+ }