5

If you select some text in an app (e.g. Safari, Chrome or any other app which allows dragging text), and drag the selection to a Finder panel, then a file will be created in the panel with an invisible .textClipping extension. The extension might or might not be visible in Finder depending on your settings.

Originally I assumed that the file is plain text, and tried renaming it to add a .txt extension, yet double-clicking still opens it with Finder.

Then I checked the file type:

file 'some text.textClipping'
>> some text.textClipping: Apple binary property list

cat-ing it shows a header of bplist00?XUTI-Data? followed by readable text.

I tried:

mv 'some text.textClipping' 'some text.txt'

but even after this it still opens with Finder and not the associated app for the .txt files.

Another 'oddity' is that dragging a .textClipping file into the terminal — which I sometimes use as a way of inserting the full path — has the unexpected effect of inserting the contents of the file rather than its path.

I wish I could use .textClipping files to quickly create snippets from web pages and other apps, but for obvious reasons, I want to avoid the snippets being stored in some Apple proprietary binary format.

Is there a way to convert the snippets to a portable format, such as plain text? How come that this type of files behave differently from others? Is there is some extended file property? Then how to remove it so that the files stop being 'special'?

3 Answers 3

5

Futher googling about Apple's binary property lists lead me to try plutil -convert xml1 note.textClipping which produces an XML file with the readable text of the snippet as UTF-8 text, then base64-encoded versions of the same text in UTF-16, mac-plain, and HTML.

Even after converting the binary to XML format, Finder still opens the file in its own viewer no matter what extension is set (e.g. .plist or .xml).

Running /bin/ls -al in the folder shows a @ next to the file name which indicates the file has extended attributes so it looks that they are causing the 'special' behavour in Finder.

This answer lead me to try

xattr -l note.plist 

which reveals that some of the note's content is stored as an extended attribute key.

And finally, clearing all extended attributes turned the file into a 'normal' file, so now it opens with the associated app:

xattr -c note.plist 

The command above is for a single file, to strip extended attributes for all files in the current folder run:

xattr -rc .

Extended attributes might be useful in some cases — for example, if you downloaded a file with safari or chrome the original URL will be stored as an extended attribute which you can see with xattr -l myfile.zip or right-clicking a file in Finder and selecting Get Info > The URL will be displayed under More Info > Where from. (Another reason not to use wget when you want to keep track of the file's origin.)

3

A python3 snippet that can be added as a Quick Action in Finder with the help of the ootb Automator.app (New > Quick Action > find and drag Run Shell Script onto the right work panel).

import plistlib
import sys
from pathlib import Path

clippath = Path(sys.argv[1])

with clippath.open('rb') as fi:
    plist = plistlib.load(fi)
    data = plist.get('UTI-Data')
    utf8text = data.get('public.utf8-plain-text')
    html = data.get('public.html')

    utf8text and clippath.with_suffix(".txt").write_text(utf8text, encoding='utf-8')
    html and clippath.with_suffix(".html").write_bytes(html)

This is how the snippet must look in automator (assuming you have python3 installed in /usr/local/bin/python3):

enter image description here

Clicking Save in automator will ask for a name (e.g. Convert Clipping). Once saved, right-click a .textClipping file in Finder, then in the dropdown menu select Quick Actions > Convert Clipping. Two new files will be created, .txt and optionally, if the snippet was created from a web page .html. Clippings created from web pages will preserve formatting and links.

2

In the same vein as @ccpizza suggested with python, but this time using perl, you can create in Automator a new Quick Action workflow, and use the following script instead.

You will need to install RTF::Parser:

  1. Download it

  2. Open the archive and cd into it

  3. perl Makefile.PL

  4. make && make test

  5. sudo make install

The RTF::Parser module is marked as deprecated on CPAN, but still does the job.

#!/usr/local/bin/perl
use strict;
use warnings;
use IO::File;
use File::Basename ();
use File::Spec;
use Cwd ();
use RTF::TEXT::Converter;
our $DEBUG = 0;

{
    our $basedir = Cwd::getcwd;
    foreach my $f ( @ARGV )
    {
        if( $f !~ /\.(textClipping)$/ )
        {
            next;
        }
        if( &convert( File::Spec->rel2abs( $f, $basedir ) ) )
        {
            print( STDOUT "File $f has been successfully converted.\n" );
        }
        else
        {
            print( STDOUT "Failed to convert file $f.\n" );
        }
    }
    exit(0);
}

sub convert
{
    my $file = shift( @_ );
    my( $name, $path, $suffix ) = File::Basename::fileparse( $file, '.textClipping' );
    my $fh = IO::File->new( "${file}/..namedfork/rsrc" ) || do
    {
        print( STDERR "Failed to open resource for file $file: $!\n" );
        return;
    };
    my $data = do{ local $/ = undef; <$fh> };
    $fh->close;
    my $result = '';
    my $p = RTF::TEXT::Converter->new( output => \$result );
    $p->parse_string( $data );
    # Sometime, RTF::TEXT::Converter gets it right, and sometime there is some weird data mixed up, so we need to clean up.
    if( index( $result, "\0" ) != -1 )
    {
        # say "Data is:\n" . Devel::Hexdump::xd( $result );
        my @parts = split( /\0+/, $result );
        # say "Data is:\n" . Devel::Hexdump::xd( $parts[-1] );
        $result = $parts[-1];
        $result =~ s/^[\x01\xcb]+//;
    }
    print( STDOUT "Saving result to ${path}/${name}.txt\n" ) if( $DEBUG );
    my $out = IO::File->new( ">${path}/${name}.txt" ) || do
    {
        print( STDERR "Unable to open file ${path}/${name}.txt in write mode: $!\n" );
        return;
    };
    $out->autoflush(1);
    $out->print( $result ) || do
    {
        print( STDERR "Unable to write to file ${path}/${name}.txt: $!\n" );
        return;
    };
    $out->close;
    return(1);
}

__END__

MacOSX Automator screenshot

Then, you can select one or multiple files ending with the extension .textClipping and right-click, in the Services menu, select your workflow Convert textClipping to text and this will create files with the same base name, but with extension .txt.

You can also save this perl script in a file and call it from the command line, such as rtf2text.pl *.textClipping.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .