Copy and paste with list structure preserved

First off, thanks a lot for building Bike! It’s a great tool to structure one’s thoughts.

This is a feature request. When you copy an outline from Bike and paste it in a rich-text formatting input (e.g. Slack or Google Docs), the list structure isn’t preserved and it is pasted as plain text with indentation.

Can we introduce a way to copy the text with the list structure intact? The same is needed while pasting formatted lists in Bike. Currently they aren’t automatically formatted as an outline. This could either be the default behaviour on copying and pasting, or it could be added as separate option in the menu preferably with keyboard shortcuts.

I know that we can rename the .bike extension to .html and copy that, but it’s cumbersome if you’re doing this frequently, and it adds blank lines after every line when you paste the content somewhere.

Could you tell us more about the distinction that you are drawing between:

  1. list structure, and
  2. indentation


What I am seeing here is that if I copy a Bike outline, and paste it into Google docs,

  • the indentation structure is preserved, and
  • I can apply bullets by selecting the pasted outline and clicking the Google Docs Bulleted List button (⌘⇧8)

Bike places three kinds of outline in the clipboard – plain tab-indented text, OPML, and XML (HTML)

Note that the choice between those, and what is done with the chosen outline type, is up to the receiving application, e.g. up to Google Docs, rather than Bike.

If you simply want to be able to paste directly into Google docs in a bulleted format, we can help Google to understand by relabelling the XML pasteboard item as public.html.

To do that, you can copy from Bike using this script:

Expand disclosure triangle to view JS source
(() => {
    "use strict";


    // BIKE Outliner :: Copy As public.html
    // (Google docs, for example, makes better use of
    //  the Bike XML clipboard contents if it is labelled
    //  "public.html"

    // Rob Trew @2022
    // Ver 0.02

    const main = () => {
        const doc = Application("Bike");

        return doc.exists() ? (
                    from: doc.rows.where({
                        selected: true
                    as: "bike format",
                    all: false
        ) : "No documents open in Bike";

    // ----------------------- JXA -----------------------

    // setClipOfTextType :: String -> String -> IO String
    const setClipOfTextType = utiOrBundleID =>
        txt => {
            const pb = $.NSPasteboard.generalPasteboard;

            return (

    // MAIN
    return main();

Which can be tested in Script Editor (with the language selector at top left set to JavaScript)

See: Using Scripts - Bike

Or, if you have Keyboard Maestro, you can use this, which attaches the Copy as HTML script above to the keyboard shortcut ⌘^C

BIKE - Copy as (13.6 KB)

Script and macro updated to Ver 0.02
(to get the HTML directly from the Bike scripting interface)


The distinction is rich text formatting. Usually if you copy and paste formatted content between applications with a WYSIWYG kind of editor, the formatting is preserved. In this case Bike isn’t really a full-fledged rich text editor, but since outlines form the core of it I’d at least expect the outlines to be optionally copied with the structure (and not just indentation).

I tried this, but Google docs adds the bullets at the first level regardless of the nesting in the outlines. This gif demonstrates what I was trying to convey:


Thanks for sharing the script to copy html, appreciate it! However this also seems to be adding empty lines after each list item. Or maybe that’s an issue with Google docs.

As an aside, I use a variation of the script you shared to add and toggle checkboxes against rows and it is a lifesaver. Thanks for that!

1 Like

Yes, a Google issue, I’m afraid.

It’s the pasting application (not the copying application) that decides what use is made of the clipboard contents.

(Bike makes all of its formatting available in the clipboard in an XML/HTML format)

It might, at some point, be possible to write a script which converts the top N levels of a Bike outline in the clipboard from its native <ul> <li> bulleted structure to an H1 H2 H3 etc HTML content type.

(It sounds as if that may be what you are hoping for)

I’m still not 100% sure it depends on only the pasting application. Because with most applications supporting rich text most of the formatting is preserved on copying and pasting. So there must be a common subset of special handling they are doing while copying and pasting.

Yeah. It would be great if a menu option is added to copy as html instead of having to use scripts. Also, I noticed that if you copy as html, even then it doesn’t work flawlessly everywhere. For instance, it works with Google docs, but in Slack nothing gets pasted. That’s not the case when copying and pasting similar nested lists from other apps.

I actually don’t care for headings since Bike doesn’t have that concept currently. I’m only interested in the <ul> <li> unordered lists, with nested list structure preserved.

Also, could you share the previous version of your script again?

Remember that Bike’s format is not RTF – it’s semantic HTML markup, and there’s literally nothing that it holds back in the clipboard.

I’m only interested in the <ul> <li> unordered lists.

That’s what Google Docs, like browsers, represents as bulleted lists.

You would like it to make a special case of the first level, and suppress bullets there ?

Also, could you share the previous version of your script again?

Not sure that I kept a copy of that :slight_smile:

(It depended on GUI and clipboard, which risked timing glitches)

Was there something different which it did and which you found helpful ? It’s behaviour should be identical to the one above, I think – they vary only in how they fetch the HTML string.

I don’t know if its helpful to take a closer look at what kind of formatting a Bike file contains, but if we start with a file like:

and then drag its file icon into Safari, to see how a browser displays it, we get:

and the underlying XML/HTML (clipboard is identical to file content):

Expand disclosure triangle to view XML/HTML source
<?xml version="1.0" encoding="UTF-8"?>
    <meta charset="utf-8"/>
    <ul id="A_RwnvHn">
      <li id="Yi">
          <li id="i2">
          <li id="Ak">
              <li id="Sb">
              <li id="Qo">
              <li id="Qi">
          <li id="IW">
          <li id="NH">
      <li id="te">
          <li id="JS">
          <li id="1P">

As you can see, the top level Alpha and Iota are – like all the other lines – unordered list elements, and therefore displayed with bullets in a browser, and Google docs, and with triangle bullets in Bike.

If you would, however, prefer to paste into Google Docs and immediately see the top level rows without bullets, we might be able to write a script which transformed the clipboard contents, turning the top level rows into plain <p> paragraphs, rather than <ul> <li> ordered list elements.

PS this is what I see when I copy from Bike using the script above, and paste ito a blank Google Doc:

Screenshot 2022-09-15 at 10.02.45

In your video, what is happening is that Google docs doesn’t recognise the XML content of the clipboard as HTML, and chooses instead to use the tab-indented plain text.

We can get it to use the HTML by explicitly relabelling that part of the clipboard as public.html, and that’s all that the script does.

(I understand that a future build of Bike may include an additional pasteboard item, labelled public.html, by default, and I think that should enhance pasting into TextEdit and MS Word, as well as Google Docs)

1 Like

At @complexpoint 's suggestion I will also start writing same data that I’m writing for .bike, but also tagged as .html. This change makes it possible to paste into Google docs and keep formatting without requiring a separate script.


Note, incidentally that you are in Google Docs outline view there.

  1. You will getter better handling of pasted <ul> <li> if you switch off Show Outline before you apply the Google Docs bullets button.
  2. If you want the various levels of your Bike outline to show up in the Google Docs Outline panel, then we will need to write you a script which maps the top N Bike levels to HTML H1..6 Heading levels, as that’s what Google Docs uses for outline structure.

With Google Docs > Show Outline off:

Open disclosure triangle to see screen animation

Play button at bottom right:

@complexpoint :

Yeah, I understand and that’s great. The only minor gripe I had was that it’s not being recognized everywhere (e.g. Slack). I understand that receiving application also has a role in it, but I was wondering how the HTML pasteboard of Bike is different from Google Docs, which works fine in Slack.

If we can figure out this difference it would help ensure Bike’s copied HTML data works with most applications.

Yeah, I’m clear on that. And no, I’m not endorsing any special handling on the basis of levels, I’m perfectly content with the HTML Bike produces.

I’m still on the unlicensed version of Bike and the new script doesn’t work for me. But it’s not a big deal.

Thanks for going the extra mile and trying to help!


That would be great, thanks!

In addition to public.html, Bike could also include Apple HTML pasteboard type, which also seems to be getting added when copying HTML from other apps and has the same contents as public.html. It might help with better compatibility. // @jessegrosjean