vscode#CustomTextEditorProvider TypeScript Examples
The following examples show how to use
vscode#CustomTextEditorProvider.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: extension.ts From markmap-vscode with MIT License | 4 votes |
class MarkmapEditor implements CustomTextEditorProvider {
constructor(private context: ExtensionContext) {}
private resolveAssetPath(relPath: string) {
return Utils.joinPath(this.context.extensionUri, relPath);
}
private async loadAsset(relPath: string) {
const bytes = await workspace.fs.readFile(this.resolveAssetPath(relPath))
const decoder = new TextDecoder();
const data = decoder.decode(bytes);
return data;
}
public async resolveCustomTextEditor(
document: TextDocument,
webviewPanel: WebviewPanel,
token: CancellationToken,
): Promise<void> {
webviewPanel.webview.options = {
enableScripts: true,
};
const jsUri = webviewPanel.webview.asWebviewUri(this.resolveAssetPath(LOCAL_ASSETS.js.app));
const cssUri = webviewPanel.webview.asWebviewUri(this.resolveAssetPath(LOCAL_ASSETS.css.app));
const toolbarJs = webviewPanel.webview.asWebviewUri(this.resolveAssetPath(LOCAL_ASSETS.js.toolbar));
const toolbarCss = webviewPanel.webview.asWebviewUri(this.resolveAssetPath(LOCAL_ASSETS.css.toolbar));
const baseJs: JSItem[] = [
webviewPanel.webview.asWebviewUri(this.resolveAssetPath(LOCAL_ASSETS.js.d3)),
webviewPanel.webview.asWebviewUri(this.resolveAssetPath(LOCAL_ASSETS.js.markmapView)),
].map(uri => ({ type: 'script', data: { src: uri.toString() } }));
let allAssets = transformer.getAssets();
allAssets = {
styles: [
...allAssets.styles || [],
{
type: 'stylesheet',
data: {
href: toolbarCss.toString(),
},
},
{
type: 'stylesheet',
data: {
href: cssUri.toString(),
},
},
],
scripts: [
...allAssets.scripts || [],
{
type: 'script',
data: {
src: toolbarJs.toString(),
},
},
{
type: 'script',
data: {
src: jsUri.toString(),
},
},
],
};
webviewPanel.webview.html = fillTemplate(undefined, allAssets, {
baseJs,
});
const updateCursor = () => {
const editor = vscodeWindow.activeTextEditor;
if (editor?.document === document) {
webviewPanel.webview.postMessage({
type: 'setCursor',
data: editor.selection.active.line,
});
}
};
let defaultOptions: IMarkmapJSONOptions;
let customCSS: string;
const updateOptions = () => {
const raw = workspace.getConfiguration('markmap').get<string>('defaultOptions');
try {
defaultOptions = raw && JSON.parse(raw);
} catch {
defaultOptions = null;
}
update();
};
const updateCSS = () => {
customCSS = workspace.getConfiguration('markmap').get<string>('customCSS');
webviewPanel.webview.postMessage({
type: 'setCSS',
data: customCSS,
});
};
const update = () => {
const md = document.getText();
const { root, frontmatter } = transformer.transform(md);
webviewPanel.webview.postMessage({
type: 'setData',
data: {
root,
jsonOptions: {
...defaultOptions,
...(frontmatter as any)?.markmap,
},
},
});
updateCursor();
};
const debouncedUpdateCursor = debounce(updateCursor, 300);
const debouncedUpdate = debounce(update, 300);
const messageHandlers: { [key: string]: (data?: any) => void } = {
refresh: update,
editAsText: () => {
vscodeWindow.showTextDocument(document, {
viewColumn: ViewColumn.Beside,
});
},
exportAsHtml: async () => {
const targetUri = await vscodeWindow.showSaveDialog({
saveLabel: 'Export',
filters: {
HTML: ['html'],
},
});
if (!targetUri) return;
const md = document.getText();
const { root, features, frontmatter } = transformer.transform(md);
const jsonOptions = {
...defaultOptions,
...(frontmatter as any)?.markmap,
};
const { embedAssets } = jsonOptions as { embedAssets?: boolean };
let assets = transformer.getUsedAssets(features);
assets = {
styles: [
...assets.styles || [],
embedAssets ? {
type: 'style',
data: await this.loadAsset(LOCAL_ASSETS.css.toolbar),
} : {
type: 'stylesheet',
data: {
href: TOOLBAR_CSS,
},
},
...customCSS ? [
{
type: 'style',
data: customCSS,
} as CSSItem,
] : [],
],
scripts: [
...assets.scripts || [],
{
type: 'script',
data: embedAssets ? {
textContent: await this.loadAsset(LOCAL_ASSETS.js.toolbar),
} : {
src: TOOLBAR_JS,
},
},
{
type: 'iife',
data: {
fn: (r: typeof renderToolbar) => {
setTimeout(r);
},
getParams: () => [renderToolbar],
},
},
],
};
const extra = {
jsonOptions,
} as Parameters<typeof fillTemplate>[2];
if (embedAssets) {
extra.baseJs = (await Promise.all([
this.loadAsset(LOCAL_ASSETS.js.d3),
this.loadAsset(LOCAL_ASSETS.js.markmapView),
])).map(textContent => ({
type: 'script',
data: {
textContent,
},
}));
}
const html = fillTemplate(root, assets, extra);
const encoder = new TextEncoder();
const data = encoder.encode(html);
try {
await workspace.fs.writeFile(targetUri, data);
} catch (e) {
vscodeWindow.showErrorMessage(`Cannot write file "${targetUri.toString()}"!`);
}
},
openFile(relPath: string) {
const filePath = Utils.joinPath(Utils.dirname(document.uri), relPath);
commands.executeCommand(
'vscode.open',
filePath,
);
},
};
// const logger = vscodeWindow.createOutputChannel('Markmap');
// messageHandlers.log = (data: string) => {
// logger.appendLine(data);
// };
webviewPanel.webview.onDidReceiveMessage(e => {
const handler = messageHandlers[e.type];
handler?.(e.data);
});
workspace.onDidChangeTextDocument(e => {
if (e.document === document) {
debouncedUpdate();
}
});
vscodeWindow.onDidChangeTextEditorSelection(() => {
debouncedUpdateCursor();
});
updateOptions();
updateCSS();
workspace.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('markmap.defaultOptions')) updateOptions();
if (e.affectsConfiguration('markmap.customCSS')) updateCSS();
});
}
}
Example #2
Source File: DrawioEditorProviderText.ts From vscode-drawio with GNU General Public License v3.0 | 4 votes |
export class DrawioEditorProviderText implements CustomTextEditorProvider {
constructor(private readonly drawioEditorService: DrawioEditorService) {}
public async resolveCustomTextEditor(
document: TextDocument,
webviewPanel: WebviewPanel,
token: CancellationToken
): Promise<void> {
try {
const readonlySchemes = new Set(["git", "conflictResolution"]);
const isReadOnly = readonlySchemes.has(document.uri.scheme);
const editor =
await this.drawioEditorService.createDrawioEditorInWebview(
webviewPanel,
{
kind: "text",
document,
},
{ isReadOnly }
);
const drawioClient = editor.drawioClient;
interface NormalizedDocument {
equals(other: this): boolean;
}
function getNormalizedDocument(src: string): NormalizedDocument {
const result = {
src,
equals: (o: any) => o.src === src,
};
return result;
}
let lastDocument = getNormalizedDocument(document.getText());
let isThisEditorSaving = false;
workspace.onDidChangeTextDocument(async (evt) => {
if (evt.document !== document) {
return;
}
if (isThisEditorSaving) {
// We don't want to process our own changes.
return;
}
if (evt.contentChanges.length === 0) {
// Sometimes VS Code reports a document change without a change.
return;
}
const newText = evt.document.getText();
const newDocument = getNormalizedDocument(newText);
if (newDocument.equals(lastDocument)) {
return;
}
lastDocument = newDocument;
await drawioClient.mergeXmlLike(newText);
});
drawioClient.onChange.sub(async ({ oldXml, newXml }) => {
// We format the xml so that it can be easily edited in a second text editor.
async function getOutput(): Promise<string> {
if (document.uri.path.endsWith(".svg")) {
const svg =
await drawioClient.exportAsSvgWithEmbeddedXml();
newXml = svg.toString("utf-8");
// This adds a host to track which files are created by this extension and which by draw.io desktop.
newXml = newXml.replace(
/^<svg /,
() => `<svg host="65bd71144e" `
);
return formatter(newXml);
} else {
if (newXml.startsWith('<mxfile host="')) {
newXml = newXml.replace(
/^<mxfile host="(.*?)"/,
() => `<mxfile host="65bd71144e"`
);
} else {
// in case there is no host attribute
newXml = newXml
.replace(
/^<mxfile /,
() => `<mxfile host="65bd71144e"`
)
.replace(
/^<mxfile>/,
() => `<mxfile host="65bd71144e">`
);
}
return formatter(
// This normalizes the host
newXml
);
}
}
const output = await getOutput();
const newDocument = getNormalizedDocument(output);
if (newDocument.equals(lastDocument)) {
return;
}
lastDocument = newDocument;
const workspaceEdit = new WorkspaceEdit();
// TODO diff the new document with the old document and only edit the changes.
workspaceEdit.replace(
document.uri,
new Range(0, 0, document.lineCount, 0),
output
);
isThisEditorSaving = true;
try {
if (!(await workspace.applyEdit(workspaceEdit))) {
window.showErrorMessage(
"Could not apply Draw.io document changes to the underlying document. Try to save again!"
);
}
} finally {
isThisEditorSaving = false;
}
});
drawioClient.onSave.sub(async () => {
await document.save();
});
drawioClient.onInit.sub(async () => {
drawioClient.loadXmlLike(document.getText());
});
} catch (e) {
window.showErrorMessage(`Failed to open diagram: ${e}`);
throw e;
}
}
}