Skip to content

Copy and paste

This page shows how a d/Python program copies and pastes. You will publish something to the pasteboard, read what is on it, and learn the one habit that makes it reliable: keep the receipt. The code is real d/Python; it needs a pasteboard, which the macOS window host provides and this browser playground does not, so the samples here are for reading and for the macOS kit rather than for the Run button.

The pasteboard

On d/OS the clipboard is called the pasteboard, and it is a little more careful than the clipboards you know. An item on it is immutable: once published, its bytes never change. An item can carry several representations of one thing, in the order the sender prefers, so a spreadsheet range can offer a typed object, then styled text, then plain text, and a receiver takes the richest one it understands. And every publish and every read is a small transaction with a receipt, the host's record of exactly what happened, so a program can always find out whether an operation finished.

The representations have four-letter tags. TEXT is plain UTF-8 text, STYL styled text, DOBJ a typed object (see Typed Objects), and PATH and FILE are file references the host supervises. The same tags and the same pasteboard are used by d/BASIC, so the two languages copy and paste to each other freely.

Copy

# fragment: needs a mounted pasteboard (the macOS window host)
from dos import pasteboard

publication = pasteboard.Publication([(pasteboard.TEXT, "Hello from d/Python".encode())])
receipt = publication.publish()
receipt.ack()

A Publication is one item: a list of (tag, bytes) pairs, richest first. The constructor freezes those bytes before anything is sent. publish() runs the whole transaction (begin, write, commit) and returns the receipt; ack() acknowledges it, which tells the host you have seen the result and it may retire the record. The text is now on the pasteboard for any program on the machine, including a native macOS application, because the runtime bridges the d/OS pasteboard to the system clipboard.

If you would rather see the stages, begin(), write() and commit() are available individually. publish() never quietly publishes a replacement item: if it cannot finish, it says so.

Paste

# fragment: needs a mounted pasteboard (the macOS window host)
from dos import pasteboard

view = pasteboard.inspect()
choice = view.negotiate([pasteboard.TEXT])
payload = choice.read(limit=8192)

inspect() looks at the pasteboard as it is right now and remembers which version it saw. negotiate() takes the tags you can accept, in your order of preference, and picks the first one the item offers. read() fetches the bytes in bounded chunks and returns only when it has all of them; if someone replaced the item while you were reading, the read is declined instead of handing you half of one item and half of another. A single read returns at most 65,535 bytes in the current runtime.

view.listing(index) describes each representation the item carries, and pasteboard.capabilities() reports the host's limits: the largest item, the most representations, the chunk size.

Cut, and why the receipt matters

Copy never changes your program's data. Cut is copy plus a deletion, and d/OS is strict about the deletion: you may delete the source only after the host has confirmed that the destination has the bytes.

# fragment: cut = publish with allow_move, then delete only when authorized
publication = pasteboard.Publication([(pasteboard.TEXT, selected_bytes)], allow_move=True)
receipt = publication.publish()
receipt.ack()
if receipt.authorizes_cut(saved_revision, current_revision):
    # Now, and only now, apply your own delete and record it for undo.
    pass

authorizes_cut checks that your document has not changed since the selection was made (that is what the two revision numbers are for) and that the receipt was acknowledged. The helper never edits your document; that stays your program's job, with your own undo.

Keep the object while anything is uncertain

Networks fail, windows close, and a commit can succeed without its confirmation reaching you. The rule is simple: keep the Publication object until you know the outcome. publication.status() asks the host what became of that exact transaction and recovers a commit whose confirmation was lost. publication.phase tells you where it stands (new, committed, commit-uncertain and so on). A lost acknowledgement can be retried on the same receipt, and if the host reports it as stale, that is not permission to delete anything.

Everything that goes wrong on the host side raises RuntimeError in your program, with d/OS's status (class, rule and detail) inside it, so the message names the cause.

A complete window program

The interchange_window.py example in the macOS kit puts this together: press C to copy a card's text, V to paste whatever text is on the pasteboard into the destination area, and drag the card into another application. Run it with dpython run --native examples/interchange_window.py from the kit. The drag and drop page walks through its drag half.

Where it is proven

Nine pasteboard operations have the same test written in d/BASIC and d/Python, comparing every request and reply byte through the real macOS provider: publishing, receipts and acknowledgement, inspection, listing, negotiation and reading. The intent coverage page lists them. Not yet tested: physical keyboard shortcuts in a real macOS session, other platforms' clipboards, and the full failure matrix.