Plain text paste from Bike into iMessage?

I use Bike as my plain text editor because it’s so fast, but I noticed recently that I can’t paste plain text into iMessage. It turns into a file attachment, even if I use “Paste and Match Style”. Is there a way around this?

I don’t know whether there’s something that needs to be adjusted on the Bike end, but one option is the application “Pure Paste” (from Mac App Store). I have it set so when I paste using a defined hotkey, it “guarantees” it will come through as plain text. So far it works with every application I’ve tried, including Bike-to-iMessage.

When you copy in an application, it typically places pasteboard items of various types in the clipboard, but the choice which of these to use is made by the pasting application – in this case iMessage.

The simplest thing is probably to reduce the choices available to iMessage – I personally paste into it with a script assigned it ⌘⇧V in Keyboard Maestro, which strips the clipboard back to one type of content:

public.utf8-plain-text

I use the same script in a number of other contexts when I just want to paste plain text (copied from any source – not just Bike) but the receiving application is trying to be too clever.

Here is a Keyboard Maestro wrapping of it:

Paste as plain text.kmmacros.zip (1.8 KB)

and here is the script part, which retains the public.utf8-plain-text pasteboard item in the clipboard, discarding all others:

(To test in Script Editor, choose JavaScript from the language selector at top left)

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

    // Recopy any plain UTF8 in the clipboard,
    // dropping other formats.

    ObjC.import("AppKit");

    const main = () =>
        either(
            alert("Reduce clipboard to plain text only")
        )(
            text => text
        )(
            fmapLR(copyText)(
                clipTextLR()
            )
        );

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

    // alert :: String => String -> IO String
    const alert = title =>
        s => {
            const sa = Object.assign(
                Application("System Events"), {
                    includeStandardAdditions: true
                });

            return (
                sa.activate(),
                sa.displayDialog(s, {
                    withTitle: title,
                    buttons: ["OK"],
                    defaultButton: "OK"
                }),
                s
            );
        };


    // clipTextLR :: () -> Either String String
    const clipTextLR = () => {
    // Either a message, or the plain text
    // content of the clipboard.
        const
            v = ObjC.unwrap(
                $.NSPasteboard.generalPasteboard
                .stringForType($.NSPasteboardTypeString)
            );

        return Boolean(v) && 0 < v.length ? (
            Right(v)
        ) : Left("No utf8-plain-text found in clipboard.");
    };


    // copyText :: String -> IO String
    const copyText = s => {
        // ObjC.import("AppKit");
        const pb = $.NSPasteboard.generalPasteboard;

        return (
            pb.clearContents,
            pb.setStringForType(
                $(s),
                $.NSPasteboardTypeString
            ),
            s
        );
    };

    // --------------------- GENERIC ---------------------

    // Left :: a -> Either a b
    const Left = x => ({
        type: "Either",
        Left: x
    });

    // Right :: b -> Either a b
    const Right = x => ({
        type: "Either",
        Right: x
    });


    // either :: (a -> c) -> (b -> c) -> Either a b -> c
    const either = fl =>
    // Application of the function fl to the
    // contents of any Left value in e, or
    // the application of fr to its Right value.
        fr => e => "Left" in e ? (
            fl(e.Left)
        ) : fr(e.Right);


    // fmapLR (<$>) :: (b -> c) -> Either a b -> Either a c
    const fmapLR = f =>
    // Either f mapped into the contents of any Right
    // value in e, or e unchanged if is a Left value.
        e => "Left" in e ? (
            e
        ) : Right(f(e.Right));

    return main();
})();
1 Like

This has bothered me, but I couldn’t find a good workaround. I’m putting string types on the pasteboard, but for some reason Messages always want to make file attachment. Anyway, playing more with it this morning and it seems if I add RTF to pasteboard messages will take that first. I’ll try to fix this by including RTF in upcoming release.

1 Like

What about a Copy As option?
Then we can customize the shortcut keys to meet different needs.


screenshot from Bear.

3 Likes

I’d like this too. The only struggle I’m having with Bike so far is that in order to use its formatting I have to use its file-format. I like storing plain txt. But if I could have a way to:

  1. copy-as multiple formats (rich text & markdown especially)

  2. convert a batch of .bike files to txt with markdown formatting

…I’d feel more “safe” about using the .bike format.

I’ve got this implemented for next release:

Just working on a few other things too, so haven’t released it yet.

4 Likes

Ah! That’s fantastic!

  1. I there a beta list I can sign up for?

  2. What about the concern about having a folder of .bike files vs a folder of .txt files? Any thoughts on that? My (possibly irrational) thought is that 10 years down the road a folder of txt files will still feel like my data is safe and accessible to me, while a folder of hundreds of .bike files may or may not.

  3. It would be nice to search for file-content (inside text, not filename) across multiple notes in a folder. I believe my Mac can do this with a folder of txt files, but I don’t think it will do it for a folder of .bike files. Thoughts?

See this page in user’s guide “To include preview release updates”

I also post in these forums for each beta release.

Not sure if you already know, but .bike files are just a subset of HTML, so it’s a pretty standard and readable format. You can rename you Bike file to have a .html file extension, and then open it in web browser to view (if for example Bike isn’t available).

It should be fairly easy (using Bike, or other tools) to transform those .bike files to plain text. Of course you would loos formatting information… though with a bit for work you might encode that using Markdown formatting.

Mac Spotlight searches should already work for .bike files… since Bike files are a subset of HTML Mac OS can understand and index them for search automatically.

Okay, I’ll look into some of this. Thank you!

Yes, I know about the HTML formatting. Just not as straight-forward as a plain txt file.

I’m curious if you considered storing formatting as Markdown instead of HTML. Were there functions MD just couldn’t handle?

I can’t speak for Jesse’s design thinking, but,

speaking as a user – a few things that have become indispensible to me in Bike:

  • Nodes with ids (stored in the attribute layer of HTML, and enabling URLs which point to particular parts of a document)
  • Custom attributes generally
  • Highlighting (encoded with ==Somestring== in iaWriter for example, but not part of CommonMark)
  • Clean formatting without clutter,

and, perhaps above all, a simple and coherent nesting structure – FoldingText worked hard to use Markdown as an outline format, but the nesting relationship between headings, paragraphs, and bullet-nests turns out to be more complex and harder to pin down and outline with consistently than it looks.

1 Like

For when you do want, for any reason, to export a Bike file to Markdown, one route, which could be packaged in utilties like Keyboard Maestro etc, is through a Pandoc command line like:

pandoc -f html -t commonmark someFile.bike --lua-filter=noGap.lua

Where the contents of noGap.lua (pruning empty bullets, dropping inline Div or Span tags, converting highlighting to inline == markup, converting strikethrough to inline ~~ markup) might be something like:

Expand disclosure triangle to view Lua source
function BulletList(x)
    return pandoc.BulletList(
        x.content:filter(
            function(xs) return nil ~= next(xs) end
        )
    )
end

function Div(x)
    return x.content
end

function Span(x)
    if "mark" == x.classes[1] then
        if FORMAT:match 'docx' then
            x.attributes['custom-style'] = 'MarkYellow'
        elseif FORMAT:match '^.*mark' then
            return {
                pandoc.Str(
                    "==" .. pandoc.utils.stringify(
                        x.content
                    ) .. "=="
                )
            }
        else
            print("FORMAT unhandled for highlight: '" .. FORMAT .. "'. Ask.")
        end
    end

    return x
end

function Strikeout(x)
    -- This is just an alternative to flanking MD text
    -- with <s> .. </s> (See, for example iAWriter MD)
    if FORMAT:match '^.*mark' then
        return pandoc.Str(
            "~~" .. pandoc.utils.stringify(
                x.content
            ) .. "~~"
        )
    else
        return x
    end
end

See also sketches like:

Draft demos: Copy As Markdown & Save As Markdown - Bike - Hog Bay Software Support

1 Like

No, not as Bike’s most native file format. I wanted HTML because I want (and eventually plugins too) to be able to add arbitrary metadata to the format. Also I think that HTML is likely to be more readable in 50 years (with formatting, etc) than Markdown.

But I do expect to eventually add support for Markdown, much as I now support OPML and Plain text formats. I don’t know exactly how it will work, bold text will likely be encoded as Markdown. bold formatting… but other outline data (such as persistent unique id for each row) isn’t likely to get saved. Anyway, this is something that I do expect to add, but no timeline other then it’s not what I’m working on now or next.

Interesting. I can see that. Good thing for me to consider…

This is great. Keep up the great work. Enjoying this app more every day. Excited for 1.6!

1 Like

I’ve added more copy options in Bike 1.6 Preview (88)

Normal copy still has the same behavior … provides the outline data in all supported formats. But for cases where the pasted into app doesn’t choose the type you want you can now put copy Bike outline in a specific format through the Copy As menu.

5 Likes