diff --git a/localtypings/pxteditor.d.ts b/localtypings/pxteditor.d.ts index 26dd274455a3..6ac5336fd374 100644 --- a/localtypings/pxteditor.d.ts +++ b/localtypings/pxteditor.d.ts @@ -1,6 +1,7 @@ /// /// /// +/// declare namespace pxt.editor { export interface EditorMessage { @@ -1155,6 +1156,7 @@ declare namespace pxt.editor { onCodeStop?: () => void; experiments?: Experiment[]; + monacoFieldEditors?: MonacoFieldEditorDefinition[]; } export interface Experiment { @@ -1368,6 +1370,47 @@ declare namespace pxt.editor { } type AssetEditorEvent = AssetEditorRequestSaveEvent | AssetEditorReadyEvent; + + export interface TextEdit { + range: monaco.Range; + replacement: string; + } + + export interface MonacoFieldEditorHost { + contentDiv(): HTMLDivElement; + getText(range: monaco.Range): string; + blocksInfo(): pxtc.BlocksInfo; + + package(): pxt.MainPackage; + writeFileAsync(filename: string, content: string): Promise; + readFile(filename: string): string; + } + + export interface MonacoFieldEditor { + getId(): string; + showEditorAsync(fileType: pxt.editor.FileType, editrange: monaco.Range, host: MonacoFieldEditorHost): Promise; + onClosed(): void; + dispose(): void; + } + + export interface MonacoFieldEditorDefinition { + id: string; + matcher: MonacoFindArguments; + foldMatches?: boolean; + alwaysBuildOnClose?: boolean; + glyphCssClass?: string; + weight?: number; // higher weight will override lower weight when on same line + proto: { new(): MonacoFieldEditor }; + heightInPixels?: number; + } + + export interface MonacoFindArguments { + searchString: string; + isRegex: boolean; + matchWholeWord: boolean; + matchCase: boolean; + validateRange?: (range: monaco.Range, model: monaco.editor.ITextModel) => monaco.Range; + } } declare namespace pxt.workspace { diff --git a/pxteditor/monaco-fields/field_musiceditor.ts b/pxteditor/monaco-fields/field_musiceditor.ts index 6306a1179c88..5b87b73fcdf9 100644 --- a/pxteditor/monaco-fields/field_musiceditor.ts +++ b/pxteditor/monaco-fields/field_musiceditor.ts @@ -1,5 +1,5 @@ import { MonacoReactFieldEditor } from "./field_react"; -import { MonacoFieldEditorDefinition, registerMonacoFieldEditor } from "./monacoFieldEditor"; +import { registerMonacoFieldEditor } from "./monacoFieldEditor"; const fieldEditorId = "music-editor"; @@ -91,7 +91,7 @@ function createFakeAsset(song: pxt.assets.music.Song): pxt.Song { } } -export const songEditorDefinition: MonacoFieldEditorDefinition = { +export const songEditorDefinition: pxt.editor.MonacoFieldEditorDefinition = { id: fieldEditorId, foldMatches: true, glyphCssClass: "fas fa-music sprite-focus-hover", diff --git a/pxteditor/monaco-fields/field_react.ts b/pxteditor/monaco-fields/field_react.ts index 9bb9049af571..a155501f0419 100644 --- a/pxteditor/monaco-fields/field_react.ts +++ b/pxteditor/monaco-fields/field_react.ts @@ -1,21 +1,19 @@ -import { MonacoFieldEditor, TextEdit, MonacoFieldEditorHost } from "./monacoFieldEditor"; - const fieldEditorId = "image-editor"; -export class MonacoReactFieldEditor implements MonacoFieldEditor { - private resolver: (edit: TextEdit) => void; +export class MonacoReactFieldEditor implements pxt.editor.MonacoFieldEditor { + private resolver: (edit: pxt.editor.TextEdit) => void; private rejecter: (err?: any) => void; protected fileType: pxt.editor.FileType; protected editrange: monaco.Range; - protected host: MonacoFieldEditorHost; + protected host: pxt.editor.MonacoFieldEditorHost; protected fv: pxt.react.FieldEditorView; getId() { return fieldEditorId; } - showEditorAsync(fileType: pxt.editor.FileType, editrange: monaco.Range, host: MonacoFieldEditorHost): Promise { + showEditorAsync(fileType: pxt.editor.FileType, editrange: monaco.Range, host: pxt.editor.MonacoFieldEditorHost): Promise { this.fileType = fileType; this.editrange = editrange; this.host = host; diff --git a/pxteditor/monaco-fields/field_soundEffect.ts b/pxteditor/monaco-fields/field_soundEffect.ts index 4b6bdc1bd7b0..cd746a2cb839 100644 --- a/pxteditor/monaco-fields/field_soundEffect.ts +++ b/pxteditor/monaco-fields/field_soundEffect.ts @@ -1,5 +1,5 @@ import { MonacoReactFieldEditor } from "./field_react"; -import { MonacoFieldEditorDefinition, registerMonacoFieldEditor } from "./monacoFieldEditor"; +import { registerMonacoFieldEditor } from "./monacoFieldEditor"; const fieldEditorId = "soundeffect-editor"; @@ -205,7 +205,7 @@ function defaultSound(): pxt.assets.Sound { } } -export const soundEditorDefinition: MonacoFieldEditorDefinition = { +export const soundEditorDefinition: pxt.editor.MonacoFieldEditorDefinition = { id: fieldEditorId, foldMatches: true, glyphCssClass: "fas fa-music sprite-focus-hover", diff --git a/pxteditor/monaco-fields/field_sprite.ts b/pxteditor/monaco-fields/field_sprite.ts index 3cd8be6ac4f9..e3f172aee639 100644 --- a/pxteditor/monaco-fields/field_sprite.ts +++ b/pxteditor/monaco-fields/field_sprite.ts @@ -1,5 +1,5 @@ import { MonacoReactFieldEditor } from "./field_react"; -import { MonacoFieldEditorDefinition, registerMonacoFieldEditor } from "./monacoFieldEditor"; +import { registerMonacoFieldEditor } from "./monacoFieldEditor"; const fieldEditorId = "image-editor"; @@ -76,7 +76,7 @@ function createFakeAsset(bitmap: pxt.sprite.Bitmap): pxt.ProjectImage { } } -export const spriteEditorDefinition: MonacoFieldEditorDefinition = { +export const spriteEditorDefinition: pxt.editor.MonacoFieldEditorDefinition = { id: fieldEditorId, foldMatches: true, glyphCssClass: "sprite-editor-glyph sprite-focus-hover", diff --git a/pxteditor/monaco-fields/field_tilemap.ts b/pxteditor/monaco-fields/field_tilemap.ts index a207108be603..85b74758c75e 100644 --- a/pxteditor/monaco-fields/field_tilemap.ts +++ b/pxteditor/monaco-fields/field_tilemap.ts @@ -1,5 +1,5 @@ import { MonacoReactFieldEditor } from "./field_react"; -import { MonacoFieldEditorDefinition, registerMonacoFieldEditor } from "./monacoFieldEditor"; +import { registerMonacoFieldEditor } from "./monacoFieldEditor"; const fieldEditorId = "tilemap-editor"; @@ -139,7 +139,7 @@ function createFakeAsset(data: pxt.sprite.TilemapData): pxt.ProjectTilemap { } } -export const tilemapEditorDefinition: MonacoFieldEditorDefinition = { +export const tilemapEditorDefinition: pxt.editor.MonacoFieldEditorDefinition = { id: fieldEditorId, foldMatches: true, alwaysBuildOnClose: true, diff --git a/pxteditor/monaco-fields/monacoFieldEditor.ts b/pxteditor/monaco-fields/monacoFieldEditor.ts index 981935d83b35..fb52900e267b 100644 --- a/pxteditor/monaco-fields/monacoFieldEditor.ts +++ b/pxteditor/monaco-fields/monacoFieldEditor.ts @@ -1,49 +1,9 @@ /// -export interface TextEdit { - range: monaco.Range; - replacement: string; -} - -export interface MonacoFieldEditorHost { - contentDiv(): HTMLDivElement; - getText(range: monaco.Range): string; - blocksInfo(): pxtc.BlocksInfo; - - package(): pxt.MainPackage; - writeFileAsync(filename: string, content: string): Promise; - readFile(filename: string): string; -} - -export interface MonacoFieldEditor { - getId(): string; - showEditorAsync(fileType: pxt.editor.FileType, editrange: monaco.Range, host: MonacoFieldEditorHost): Promise; - onClosed(): void; - dispose(): void; -} - -export interface MonacoFieldEditorDefinition { - id: string; - matcher: MonacoFindArguments; - foldMatches?: boolean; - alwaysBuildOnClose?: boolean; - glyphCssClass?: string; - weight?: number; // higher weight will override lower weight when on same line - proto: { new(): MonacoFieldEditor }; - heightInPixels?: number; -} - -export interface MonacoFindArguments { - searchString: string; - isRegex: boolean; - matchWholeWord: boolean; - matchCase: boolean; - validateRange?: (range: monaco.Range, model: monaco.editor.ITextModel) => monaco.Range; -} -const definitions: pxt.Map = {}; +const definitions: pxt.Map = {}; -export function registerMonacoFieldEditor(name: string, definition: MonacoFieldEditorDefinition) { +export function registerMonacoFieldEditor(name: string, definition: pxt.editor.MonacoFieldEditorDefinition) { definitions[name] = definition; } diff --git a/webapp/src/cmds.ts b/webapp/src/cmds.ts index 273c714b031b..c2c8c95421f7 100644 --- a/webapp/src/cmds.ts +++ b/webapp/src/cmds.ts @@ -13,6 +13,7 @@ import * as pxtblockly from "../../pxtblocks"; import ExtensionResult = pxt.editor.ExtensionResult; import NativeHostMessage = pxt.editor.NativeHostMessage; import { setEditorExtensionExperiments } from "../../pxteditor/experiments"; +import { registerMonacoFieldEditor } from "../../pxteditor"; function log(msg: string) { @@ -401,6 +402,11 @@ function applyExtensionResult() { if (res.experiments) { setEditorExtensionExperiments(res.experiments); } + if (res.monacoFieldEditors) { + for (const def of res.monacoFieldEditors) { + registerMonacoFieldEditor(def.id, def); + } + } } export async function initAsync() { diff --git a/webapp/src/monaco.tsx b/webapp/src/monaco.tsx index 01177842f525..1db2e5f10040 100644 --- a/webapp/src/monaco.tsx +++ b/webapp/src/monaco.tsx @@ -1606,7 +1606,7 @@ export class Editor extends toolboxeditor.ToolboxEditor { } } - showFieldEditor(range: monaco.Range, fe: pxteditor.MonacoFieldEditor, viewZoneHeight: number, buildAfter: boolean) { + showFieldEditor(range: monaco.Range, fe: pxt.editor.MonacoFieldEditor, viewZoneHeight: number, buildAfter: boolean) { if (this.feWidget) { this.feWidget.close(); } diff --git a/webapp/src/monacoFieldEditorHost.ts b/webapp/src/monacoFieldEditorHost.ts index ec38bda8ccd5..21e26787efec 100644 --- a/webapp/src/monacoFieldEditorHost.ts +++ b/webapp/src/monacoFieldEditorHost.ts @@ -1,6 +1,5 @@ /// -import { MonacoFieldEditor, MonacoFieldEditorDefinition, MonacoFieldEditorHost, TextEdit } from "../../pxteditor"; import * as compiler from "./compiler"; import * as pkg from "./package"; @@ -11,7 +10,7 @@ interface OwnedRange { id: number; } -export class ViewZoneEditorHost implements MonacoFieldEditorHost, monaco.editor.IViewZone { +export class ViewZoneEditorHost implements pxt.editor.MonacoFieldEditorHost, monaco.editor.IViewZone { domNode: HTMLDivElement; afterLineNumber: number; heightInPx = 520; @@ -26,7 +25,7 @@ export class ViewZoneEditorHost implements MonacoFieldEditorHost, monaco.editor. suppressMouseDown = false; - constructor(protected fe: MonacoFieldEditor, protected range: monaco.Range, protected model: monaco.editor.IModel) { + constructor(protected fe: pxt.editor.MonacoFieldEditor, protected range: monaco.Range, protected model: monaco.editor.IModel) { this.afterLineNumber = range.endLineNumber; const outer = document.createElement("div"); @@ -52,7 +51,7 @@ export class ViewZoneEditorHost implements MonacoFieldEditorHost, monaco.editor. return this.content; } - showAsync(fileType: pxt.editor.FileType, editor: monaco.editor.IStandaloneCodeEditor): Promise { + showAsync(fileType: pxt.editor.FileType, editor: monaco.editor.IStandaloneCodeEditor): Promise { this.fileType = fileType; this.editor = editor; return compiler.getBlocksAsync() @@ -132,10 +131,10 @@ export class ViewZoneEditorHost implements MonacoFieldEditorHost, monaco.editor. } } -export class ModalEditorHost implements MonacoFieldEditorHost { +export class ModalEditorHost implements pxt.editor.MonacoFieldEditorHost { protected blocks: pxtc.BlocksInfo; - constructor(protected fe: MonacoFieldEditor, protected range: monaco.Range, protected model: monaco.editor.IModel) { + constructor(protected fe: pxt.editor.MonacoFieldEditor, protected range: monaco.Range, protected model: monaco.editor.IModel) { } contentDiv(): HTMLDivElement { @@ -164,7 +163,7 @@ export class ModalEditorHost implements MonacoFieldEditorHost { return this.package().host().readFile(pkg.mainPkg, filename); } - showAsync(fileType: pxt.editor.FileType, editor: monaco.editor.IStandaloneCodeEditor): Promise { + showAsync(fileType: pxt.editor.FileType, editor: monaco.editor.IStandaloneCodeEditor): Promise { return compiler.getBlocksAsync() .then(bi => { this.blocks = bi; @@ -179,7 +178,7 @@ export class ModalEditorHost implements MonacoFieldEditorHost { } export class FieldEditorManager implements monaco.languages.FoldingRangeProvider { - protected fieldEditors: MonacoFieldEditorDefinition[] = []; + protected fieldEditors: pxt.editor.MonacoFieldEditorDefinition[] = []; protected decorations: pxt.Map = {}; protected liveRanges: OwnedRange[] = []; protected fieldEditorsEnabled = true; @@ -213,7 +212,7 @@ export class FieldEditorManager implements monaco.languages.FoldingRangeProvider } } - addFieldEditor(definition: MonacoFieldEditorDefinition) { + addFieldEditor(definition: pxt.editor.MonacoFieldEditorDefinition) { for (const f of this.fieldEditors) { if (f.id === definition.id) return; }