Paste and Match Style

This same question came up in this 2018 discussion, but I’d like to ask again, since this still seems to be an issue.

Mac has Cmd+Shift+V, and a corresponding menu item called “Paste and match style”. Windows has Ctrl+Shift+V, and a corresponding menu item called “Paste as plain text.” I have a couple of questions:

  1. ProseMirror does not seem to actually match the style. If I am in bold text and I do “paste and match style” (either via the keyboard or the menu), I would hope the pasted text would be bold. Would it be appropriate for me to file a GitHub issue for this?

  2. If we were to implement this ourselves in one of our plugins, what do you think might be the right approach (the right event handlers to define)?

As an aside, ProseMirror appears to have code that explicitly checks the state of the shift key in order to decide whether the paste is plaintext or not — e.g. see functions capturePaste() and doPaste() in prosemirror-view. But if the user uses one of the above-mentioned menu commands, the shift key is not down. From my tests on Mac, it seems that the only way for a JavaScript onpaste handler to “detect” paste and match style is to notice that only text/plain is on the clipboard, without text/html. Anyway, I’m not sure if this issue with the shift key actually has any material impact on how ProseMirror behaves, but I thought I would point it out.

  • Mike Morearty, Asana

Hm, hopefully this lends inspiration, but something hacky I’m doing to automatically transform links on regular paste is by defining a transformPasted which ‘linkifies’ the slice, along with Change transformPasted behaviour when shift key is pressed to detect if its a regular keyboard paste or plain text paste. If shift is detected, then we just return false in transformPasted.

Again this does not work if a person is using the context menu, as you brought up.

For the more general case of marks besides links, I would probably look at EditorState.storedMarks and EditorProps.handlePaste: storedMarks tells you which marks are “active” / “inclusive”, and handlePaste is more lower level than transformPasted but gives you access to the view and clipboard event.

Edit: In addition to storedMarks, for a TextSelection, there is also $cursor.marks().

ProseMirror itself only implements the concept of plain-text pasting, not a “match style” one. It could be argued that pasting plain text in text with a mark should apply the mark to the inserted text. Libreoffice and Google Docs seem to do this. But I feel this gets a bit dodgy when the text contains multiple blocks—should the library really go into the blocks and add marks to everything?

Overriding paste is indeed best done with the handlePaste hook. You could apply your own heuristics to determine whether marks should be inherited, and then process the slice to add them to all inline content where they are allowed via a recursive transformation function.

If we add this to the library, would it be enough for your use case to only do it when the content is entirely inline, or would you expect it to apply to multi-block pastes as well?

I think the Windows name for this feature, “Paste as plain text,” more clearly indicates how I think of it (even if “Paste and match style” might be a more user-friendly name.) To me as a software engineer, this command means “use the text/plain from the clipboard; ignore any rich text formats that may be there.” If you are pasting text/plain, then by definition you are pasting just characters with no formatting at all; so when it goes into a document, it makes sense to just put it in, using whatever formatting is at the cursor. It should be roughly equivalent to what would happen if you just typed the text.

In my experience, copying plain text and then pasting with Cmd+V is typically identical in behavior to copying rich text and then pasting with Cmd+Shift+V. E.g. since I am on Mac, to get just plain text on the clipboad, I use TextEdit and switch the document to plain text with Cmd+Shift+T.

If we add this to the library, would it be enough for your use case to only do it when the content is entirely inline, or would you expect it to apply to multi-block pastes as well?

I would expect it to apply to multi-block pastes as well. In my experience this is pretty standard behavior. The following all preserve formatting across all blocks (across newlines, in other words) when you do Paste and Match Style:

  • contenteditable div on every browser I tried
  • Mac TextEdit (which, I think, is just a wrapper around the standard macOS rich text editing components)
  • Microsoft Word (you can try it for free in the online version of Word at Microsoft Word - Work together on Word documents which has a slightly different UI: You just do Cmd+V and it pastes with formatting, but also shows a tiny menu you can use to switch to plain text)
  • Google Docs, as you mentioned (which calls this “Paste without formatting”)

Some editors don’t seem to support “Paste and Match Style” at all: Gmail editor (on some browsers), Dropbox Paper, Notion. I didn’t find any that apply formatting to the first paragraph and not the subsequent ones.

This patch applies the marks at the cursor to the inserted text when explicitly pasting as plain text.