Mimsy Were the Borogoves

Hacks: Articles about programming in Python, Perl, Swift, BASIC, and whatever else I happen to feel like hacking at.

Save clipboard text to the current folder

Jerry Stratton, June 9, 2021

Save clipboard text: Example of saving clipboard text to the Finder’s currently-displayed folder, with the default filename taken from the first paragraph.; AppleScript; clipboard; pasteboard

The script gets the default filename from the first line of text—often, a Markdown headline.

One scripting option that is often overlooked on the Mac is the Finder toolbar. You can drag any application into the toolbar and it will then be available for clicking in any open Finder window—or for dragging and dropping files from an open Finder window onto the icon.

You can use this as a simple shortcut for items that would normally go under the Services menu, but it is especially useful for doing file-related things that don’t involve selecting files. There is no Services menu in Finder windows if nothing’s selected, but there is a toolbar.

I often have text in the clipboard that I want to save to a file. Very often I can see the folder I want that file in, open in the Finder. It’s annoying to see it right there and still have to go into Terminal to type pbpaste then into the Finder to drag the folder’s drag icon onto the Terminal then back into Terminal to press return. Or, in the case of iA Writer, to have to create the document, paste it in, rename it, drag the title bar icon of the correct location to the Move dialog1 and then approve a move out of iCloud.

It would be a lot easier to have an icon in the Finder toolbar that would automatically dump clipboard text to a text file right there.

Often the text I’ve copied is a subset of a Markdown file. I’ve decided to make one collection of subthoughts in a post be, instead, the main thought in another post. It would be great if this hypothetical script could shift headlines to the left as necessary to make the top line be a top-level headline.

This script will do both of those tasks. It will prompt for a filename to save the clipboard text to, using the folder displayed in the current Finder window as the default location; and it will modify Markdown headlines, shifting them left appropriately to make the first paragraph be a top-level headline.

Open Script Editor on your Mac, and paste this in:

[toggle code]

  • on run
    • --get the clipboard text
    • set clipboardText to the clipboard as text
    • --take a wild guess at an appropriate filename
    • set defaultFilename to the first paragraph of clipboardText
    • --if this is markdown, shift headlines to the left as appropriate
    • if defaultFilename starts with "#" then
      • --remove extra pounds from the filename, keeping track of each
      • copy defaultFilename to markdownCheck
      • copy "" to headlineShift
      • repeat while markdownCheck starts with "##"
        • set headlineShift to headlineShift & "#"
        • set markdownCheck to the rest of the characters of markdownCheck as string
      • end repeat
      • --if the line begins with a pound, a space, and some text, it is probably Markdown
      • if markdownCheck starts with "# " and the length of markdownCheck is greater than 3 then
        • --first, clear the headline marker from the default filename
        • copy characters 3 thru -1 of markdownCheck as string to defaultFilename
        • --then, shift all headlines left so that the top headline is a top-level headline
        • copy markdownCheck & linefeed to newText
        • copy the (length of headlineShift) + 1 to poundsToShift
        • repeat with rawParagraph in the rest of the paragraphs of clipboardText
          • --this makes it easier to work with the characters of the paragraph
          • set rawParagraph to rawParagraph as string
          • if rawParagraph starts with headlineShift then
            • copy characters poundsToShift thru -1 of rawParagraph as string to newParagraph
            • set newText to newText & newParagraph & linefeed
          • else
            • set newText to newText & rawParagraph & linefeed
          • end if
        • end repeat
        • set clipboardText to newText
      • end if
    • end if
    • --ensure a reasonable filename length
    • if the number of characters of defaultFilename is greater than 32 then
      • set defaultFilename to characters 1 thru 32 of defaultFilename as string
    • end if
    • --make sure the default filename ends with .txt
    • if defaultFilename ends with "." then
      • set defaultFilename to defaultFilename & "txt"
    • else if defaultFilename does not end with ".txt" then
      • set defaultFilename to defaultFilename & ".txt"
    • end if
    • --get the current folder
    • tell application "Finder"
      • set currentPath to (POSIX path of (target of front window as alias))
    • end tell
    • --ask for a filename, defaulting to the current folder
    • set theFile to choose file name default name defaultFilename default location currentPath
    • --write the clipboard to the file
    • set destination to open for access theFile with write permission
    • write clipboardText to destination as "utf8"
    • close access destination
  • end run
Save script as application: Save the script as an application from Script Editor.; AppleScript

Save the script as an application from Script Editor. You can put it wherever you want, preferably a folder under Documents where you save all of your AppleScript files.

Save it as an Application. I named it “Save Clipboard”. You can save it wherever you want, since you'll be putting it in the toolbar. If you don’t have a place yet, make a folder called “AppleScripts” in your Documents folder.

Put Save Clipboard in the toolbar by holding down the COMMAND key and dragging the application into the toolbar on any open Finder window.

The script uses the first paragraph of the clipboard to create the suggested filename, adding .txt if, as is likely, the first paragraph doesn’t already end in .txt. This suggested filename is almost never exactly correct, but it does often contain appropriate words for the filename. This is especially true if the first paragraph is a Markdown headline.

Since I’ve put this into the Finder’s toolbar the front window is always the folder I want—it’s the folder on whose toolbar I clicked Save Clipboard. All I have to do is click “Save Clipboard” in the Finder’s toolbar, and up pops the query about the filename, defaulting to the folder that was open when I clicked the button (and is still open). Of course, I can change the folder from that dialog if I want to; the script won’t care.

And, boom! Whatever text is in the clipboard is saved in a text file in the current folder.

If you change your mind about saving, you can cancel the request for a filename; AppleScript automatically closes the application if the user cancels a display dialog or choose filename request.

There are a couple of tricks in here that you don’t normally see in AppleScripts. Both involve making sure that the text file is a generally useful text file in OS X. The first is that instead of using return as the line delimiter, it uses linefeed. The return character (ASCII 13) is the classic MacOS line feed, but nowadays macOS uses the linefeed character (ASCII 10).

The second is that the file must be saved as UTF-8. If you leave off the as "utf8" text editors such as Textastic and iA Writer won’t read it correctly. Textastic sees it as Mac Roman, but the characters are messed up. It’s possible that it’s saved as UTF-8 but marked as Mac Roman.

In any case, by saving as UTF-8 with linefeeds for breaking lines, it will be a normal macOS text file.

There are a couple of assumptions in the script that work for me but may or may not work for you. If the first paragraph indicates that this is Markdown text because it’s a Markdown headline, and the headline is marked by two or more pound signs, the script will attempt to shift all headlines left by the same amount that the first paragraph had to be shifted to make it a first-level Markdown headline.

Because AppleScript doesn’t have regular expressions, however, the easiest way to do this is to check whether each paragraph begins with at least as many pound signs as we’re shifting left. If it does, it removes those pound signs. It does not check that the pound signs are succeeded by a space, which is of course required for a Markdown headline.

The easiest way to do this would be with a regular expression, but AppleScript doesn’t have regular expressions built in. The next easiest would be one of three options:

  1. Use do shell script to call a scripting language that does have regular expressions.
  2. Check after shifting that the paragraph now starts with a succession of pound signs followed by a space.
  3. Write the app in Automator using various subscripts in each action.
  4. Or, more likely, look at using Foundation and NSString with AppleScript. This would allow the use of all of the methods included with NSString, including replace by regular expression.2

Any of these might end up being the best solution; my plan is to wait until I need the functionality—which may never happen—before trying to implement it.

Similarly, I make the assumption that I’m copying a valid outline-like set of Markdown headlines. Not only does it not check to see if there is a space after the remaining pound signs, it doesn’t even check that there are pound signs left over. If the first headline has, say, two pound signs, and there is another headline with only one pound sign later on, the script will remove all of the latter’s pound signs, making it no longer a headline at all. If this ever becomes a problem, I’ll need to look at what I would expect the script to do on that text. Right now, I can’t see why I would ever copy unbalanced headlines.

I could change if rawParagraph starts with headlineShift then to if rawParagraph starts with headlineShift and character (poundsToShift+1) of rawParagraph is "#" then and it would not remove the pound signs—but then any subsequent headlines would still be shifted. What I would probably have to do is stop at that point and not shift any more headlines. But since I can’t see why I’d be copying such text, I can’t be sure if that assumption is true.

There is an issue which doesn’t happen often, in which the Save dialog displays the wrong folder for saving to. I’ve verified that the default folder given to the dialog is the correct one, so this is likely some sort of residual memory in AppleScript’s call to the Finder. But it doesn’t happen often, and even when it does saving clipboard text this way is still faster than the alternative.

  1. An action which itself has become more time consuming in Big Sur, since there’s now a wait between moving the mouse to the title of a Finder window and seeing the folder icon for dragging.

  2. This would make it easier to really clean up the first line for use as a filename, such as by removing any HTML tags or Markup that happen to be in the text.

  1. <- Nisus index import
  2. AppleScript text backups ->