I’m trying to add support for copying from VS code and pasting in ProseMirror. VS code adds a special vscode-editor-data section in the clipboard that specifies things like language (e.g. typescript.)
Example, copying test from VS code, results in this from Clipboard Inspector (evercoder.github.io)
I tried looking at handlePaste, transformPastedText, transformPastedHTML, however all of those are called after ProseMirror determines whether to process the clipboard contents as text or HTML in the internal-only parseFromClipboard function.
I’d really like to be able to direct the clipboard parsing in case of VS Code to a) get the text and b) insert it either as plain text or <code lang=SomeLanguageFromVsCode> slice.
Perhaps making parseFromClipboard an extensibility point would provide that control.
Is this the right approach or am I missing something important?
Thanks both for the help!
handlePaste works, however I didn’t like that some processing occurs before it in doPaste that is later discarded. For this specific case, handlePaste will work. There’s a hypothetical case (that I was assuming was my case as well, until now) where one might want to have logic to choose “text/plain” and run it through the default pipeline of text parsers, etc. in ProseMirror - for example, I was trying to paste [[date]] from VS code in my custom editor that has a parser to create a “date node”. I’m no longer trying to do that, just mentioning to illustrate the case I had in mind before I decided to “just paste as code”.
I will use @philippkuehn’s plugin since I’m using tiptap. Here’s some code I was just testing for “raw ProseMirror” users. After a bit of digging I found handleDOMEvents which gets called before all the internal doPaste code.
handleDOMEvents: {
paste(view: EditorView<any>, event: ClipboardEvent): boolean {
const vsCodeData: string | undefined = event.clipboardData?.getData("vscode-editor-data");
if (typeof vsCodeData !== "string" || vsCodeData === "") { // if not VS code
return false; // default processing
}
const text = event.clipboardData?.getData("text/plain");
if (!text) {
return false;
}
// VS code processing:
// TODO: in the future, make this get the language mode from metadata.mode, etc.
// see ClipboardStoredMetadata from https://github.com/microsoft/vscode/blob/main/src/vs/editor/browser/controller/textAreaInput.ts#L51
// and paste from VS code into https://evercoder.github.io/clipboard-inspector/ to check the format
const $context = view.state.selection.$from;
const isInCode = $context.parent.type.name === "codeBlock";
const schema = view.state.schema;
const textNode = schema.text(text.replace(/\r\n?/g, "\n"));
const resultSlice: Slice<any> = new Slice(Fragment.from(isInCode ? textNode : schema.nodes.codeBlock.create(null, textNode, null)), 0, 0);
const tr = view.state.tr.replaceSelection(resultSlice);
view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"));
event.preventDefault();
return true;
},
},