Most operating systems provide support for sending files to the "trash can" (or sometimes "recycle bin"). Inspired by a python project called "send2trash", I thought Factor should have a similar cross-platform library for trashing files.
trash
First, we are going to define a trash
vocabulary, and use a HOOK: that dispatches to the proper implementation, depending on which operating system you are running.
USING: combinators system vocabs.loader ; IN: trash HOOK: send-to-trash os ( path -- ) { { [ os macosx? ] [ "trash.macosx" ] } { [ os unix? ] [ "trash.unix" ] } { [ os winnt? ] [ "trash.windows" ] } } cond require
trash.macosx
Next, we will create the trash.macosx
vocabulary.
USING: alien.c-types alien.strings alien.syntax classes.struct core-foundation io.encodings.utf8 kernel system trash ; IN: trash.macosx
On the Mac OS, there are several methods of moving files to the trash. A good discussion on CocoaDev lists some of them. We are going to use the alien vocabulary to make calls into the File Manager in the CarbonCore.framework
. Some functions will return an OSStatus
flag (a signed 32-bit integer) to indicate if the operation succeeded. We will add a TYPEDEF: for it, and then define the GetMacOSStatusCommentString
function that converts the status flag into a human readable error.
TYPEDEF: SInt32 OSStatus FUNCTION: char* GetMacOSStatusCommentString ( OSStatus err ) ; : check-err ( err -- ) [ GetMacOSStatusCommentString utf8 alien>string throw ] unless-zero ;
Many of the file operations act on an FSRef
structure which represents a path within the file system. We will define the FSPathMakeRefWithOptions
function which will allow us to create these references:
STRUCT: FSRef { hidden UInt8[80] } ; TYPEDEF: UInt32 OptionBits FUNCTION: OSStatus FSPathMakeRefWithOptions ( UInt8* path, OptionBits options, FSRef* ref, Boolean* isDirectory ) ;
We can then make a <fs-ref>
word for creating references, given a path to a file (or directory).
CONSTANT: kFSPathMakeRefDoNotFollowLeafSymlink HEX: 01 : <fs-ref> ( path -- fs-ref ) utf8 string>alien kFSPathMakeRefDoNotFollowLeafSymlink FSRef <struct> [ f FSPathMakeRefWithOptions check-err ] keep ;
There are several ways of "trashing" files, but one recommended way is implemented by the FSMoveObjectToTrashSync
function:
FUNCTION: OSStatus FSMoveObjectToTrashSync ( FSRef* source, FSRef* target, OptionBits options ) ;
Implementing the send-to-trash
word is now pretty straightforward:
CONSTANT: kFSFileOperationDefaultOptions HEX: 00 M: macosx send-to-trash ( path -- ) <fs-ref> f kFSFileOperationDefaultOptions FSMoveObjectToTrashSync check-err ;
You can test this by creating a temporary file (e.g., /tmp/foo
), sending it to the trash, and then verifying that it exists by looking in the Finder's Trash.
( scratchpad ) USING: trash io.encodings.ascii io.files ; ( scratchpad ) "" "/tmp/foo" ascii set-file-contents ( scratchpad ) "/tmp/foo" send-to-trash
Note: This method does not appear to support the "Put Back" functionality (to "undo" the trash operation). Perhaps there is some metadata that we can add (or a different function we can call) that will track the original file location so that the Finder knows where it should be restored to.
The code for this is on my Github.
No comments:
Post a Comment