diff --git a/QuickLookR.qlgenerator.zip b/QuickLookR.qlgenerator.zip new file mode 100644 index 0000000..e951de0 Binary files /dev/null and b/QuickLookR.qlgenerator.zip differ diff --git a/QuickLookR.xcodeproj/project.pbxproj b/QuickLookR.xcodeproj/project.pbxproj index d3d5277..27a7227 100644 --- a/QuickLookR.xcodeproj/project.pbxproj +++ b/QuickLookR.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ C4291BF11D552859001238D2 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = C4291BF01D552859001238D2 /* GeneratePreviewForURL.m */; }; C4291BF31D552859001238D2 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = C4291BF21D552859001238D2 /* main.c */; }; C4291BFB1D552C7A001238D2 /* QuickLookR.qlgenerator in CopyFiles */ = {isa = PBXBuildFile; fileRef = C4291BEB1D552859001238D2 /* QuickLookR.qlgenerator */; }; - C4291C171D552E27001238D2 /* rdata.h in Headers */ = {isa = PBXBuildFile; fileRef = C4291C161D552E27001238D2 /* rdata.h */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -33,7 +32,6 @@ C4291BF01D552859001238D2 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = ""; }; C4291BF21D552859001238D2 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; C4291BF41D552859001238D2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - C4291C161D552E27001238D2 /* rdata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = rdata.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -70,7 +68,6 @@ C4291BF01D552859001238D2 /* GeneratePreviewForURL.m */, C4291BF21D552859001238D2 /* main.c */, C4291BF41D552859001238D2 /* Info.plist */, - C4291C161D552E27001238D2 /* rdata.h */, ); path = QuickLookR; sourceTree = ""; @@ -82,7 +79,6 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - C4291C171D552E27001238D2 /* rdata.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/QuickLookR/GeneratePreviewForURL.m b/QuickLookR/GeneratePreviewForURL.m index ede9621..55fba28 100644 --- a/QuickLookR/GeneratePreviewForURL.m +++ b/QuickLookR/GeneratePreviewForURL.m @@ -4,61 +4,52 @@ #import -#include "rdata.h" +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, + CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); -OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview); -/* ----------------------------------------------------------------------------- - Generate a preview for file - - This function's job is to create preview for designated file - ----------------------------------------------------------------------------- */ - -OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) -{ +//' This does the hard work +OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, + CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) { @autoreleasepool { - NSURL *myURL = (__bridge NSURL *)url; + NSURL *myURL = (__bridge NSURL *)url ; - NSString *contents = [ myURL absoluteString ]; + NSString *contents = [ myURL absoluteString ] ; - NSLog(@"generate preview for %@", contents); + NSLog(@"Generating preview for %@", contents) ; - //int pid = [[NSProcessInfo processInfo] processIdentifier]; - NSPipe *pipe = [NSPipe pipe]; - NSFileHandle *file = pipe.fileHandleForReading; + NSPipe *pipe = [ NSPipe pipe ] ; + NSFileHandle *file = pipe.fileHandleForReading ; NSString *cmd = @"rdatainfo::get_info('" ; cmd = [ cmd stringByAppendingString: contents ] ; cmd = [ cmd stringByAppendingString: @"')" ] ; - NSTask *task = [[NSTask alloc] init]; + NSTask *task = [ [ NSTask alloc ] init] ; task.launchPath = @"/usr/local/bin/Rscript"; - task.arguments = @[@"-e", cmd]; + task.arguments = @[ @"-e", cmd ]; task.standardOutput = pipe; [task launch]; - NSData *data = [file readDataToEndOfFile]; - [file closeFile]; + NSData *data = [ file readDataToEndOfFile ] ; + [ file closeFile ]; - NSString *rOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; + NSString *rOutput = [ [ NSString alloc ] initWithData: data encoding: NSUTF8StringEncoding ] ; if (false == QLPreviewRequestIsCancelled(preview)) { QLPreviewRequestSetDataRepresentation(preview, - (__bridge CFDataRef)([rOutput dataUsingEncoding:NSUTF8StringEncoding]), - kUTTypePlainText, - NULL); + (__bridge CFDataRef)([ rOutput dataUsingEncoding:NSUTF8StringEncoding ]), + kUTTypePlainText, NULL) ; } } return noErr; + } -void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview) -{ - // Implement only if supported -} +void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview) { } diff --git a/QuickLookR/Info.plist b/QuickLookR/Info.plist index 13121bf..2967fe8 100644 --- a/QuickLookR/Info.plist +++ b/QuickLookR/Info.plist @@ -17,9 +17,9 @@ public.filename-extension - GGG - RData + rdata rda + rds @@ -38,9 +38,9 @@ public.filename-extension - GGG - RData + rdata rda + rds diff --git a/QuickLookR/rdata.h b/QuickLookR/rdata.h deleted file mode 100644 index ddd75e7..0000000 --- a/QuickLookR/rdata.h +++ /dev/null @@ -1,148 +0,0 @@ - -#include -#include -#include - -typedef enum rdata_type_e { - RDATA_TYPE_STRING, - RDATA_TYPE_INT32, - RDATA_TYPE_REAL, - RDATA_TYPE_LOGICAL, - RDATA_TYPE_TIMESTAMP -} rdata_type_t; - -typedef enum rdata_error_e { - RDATA_OK, - RDATA_ERROR_OPEN = 1, - RDATA_ERROR_SEEK, - RDATA_ERROR_READ, - RDATA_ERROR_MALLOC, - RDATA_ERROR_USER_ABORT, - RDATA_ERROR_PARSE, - RDATA_ERROR_WRITE, - RDATA_ERROR_FACTOR -} rdata_error_t; - -const char *rdata_error_message(rdata_error_t error_code); - -typedef int (*rdata_column_handler)(const char *name, rdata_type_t type, - void *data, long count, void *ctx); -typedef int (*rdata_table_handler)(const char *name, void *ctx); -typedef int (*rdata_text_value_handler)(const char *value, int index, void *ctx); -typedef int (*rdata_column_name_handler)(const char *value, int index, void *ctx); -typedef void (*rdata_error_handler)(const char *error_message, void *ctx); -typedef int (*rdata_progress_handler)(double progress, void *ctx); - -#if defined _WIN32 || defined __CYGWIN__ -typedef _off64_t rdata_off_t; -#elif defined _AIX -typedef off64_t rdata_off_t; -#else -typedef off_t rdata_off_t; -#endif - -typedef enum rdata_io_flags_e { - RDATA_SEEK_SET, - RDATA_SEEK_CUR, - RDATA_SEEK_END -} rdata_io_flags_t; - -typedef int (*rdata_open_handler)(const char *path, void *io_ctx); -typedef int (*rdata_close_handler)(void *io_ctx); -typedef rdata_off_t (*rdata_seek_handler)(rdata_off_t offset, rdata_io_flags_t whence, void *io_ctx); -typedef ssize_t (*rdata_read_handler)(void *buf, size_t nbyte, void *io_ctx); -typedef rdata_error_t (*rdata_update_handler)(long file_size, rdata_progress_handler progress_handler, void *user_ctx, void *io_ctx); - -typedef struct rdata_io_s { - rdata_open_handler open; - rdata_close_handler close; - rdata_seek_handler seek; - rdata_read_handler read; - rdata_update_handler update; - void *io_ctx; - int external_io; -} rdata_io_t; - -typedef struct rdata_parser_s { - rdata_table_handler table_handler; - rdata_column_handler column_handler; - rdata_column_name_handler column_name_handler; - rdata_text_value_handler text_value_handler; - rdata_text_value_handler value_label_handler; - rdata_error_handler error_handler; - rdata_io_t *io; -} rdata_parser_t; - -rdata_parser_t *rdata_parser_init(); -void rdata_parser_free(rdata_parser_t *parser); - -rdata_error_t rdata_set_table_handler(rdata_parser_t *parser, rdata_table_handler table_handler); -rdata_error_t rdata_set_column_handler(rdata_parser_t *parser, rdata_column_handler column_handler); -rdata_error_t rdata_set_column_name_handler(rdata_parser_t *parser, rdata_column_name_handler column_name_handler); -rdata_error_t rdata_set_text_value_handler(rdata_parser_t *parser, rdata_text_value_handler text_value_handler); -rdata_error_t rdata_set_value_label_handler(rdata_parser_t *parser, rdata_text_value_handler value_label_handler); -rdata_error_t rdata_set_error_handler(rdata_parser_t *parser, rdata_error_handler error_handler); -rdata_error_t rdata_set_open_handler(rdata_parser_t *parser, rdata_open_handler open_handler); -rdata_error_t rdata_set_close_handler(rdata_parser_t *parser, rdata_close_handler close_handler); -rdata_error_t rdata_set_seek_handler(rdata_parser_t *parser, rdata_seek_handler seek_handler); -rdata_error_t rdata_set_read_handler(rdata_parser_t *parser, rdata_read_handler read_handler); -rdata_error_t rdata_set_update_handler(rdata_parser_t *parser, rdata_update_handler update_handler); -rdata_error_t rdata_set_io_ctx(rdata_parser_t *parser, void *io_ctx); -/* rdata_parse works on RData and RDS. The table handler will be called once - * per data frame in RData files, and zero times on RDS files. */ -rdata_error_t rdata_parse(rdata_parser_t *parser, const char *filename, void *user_ctx); - - -// Write API -typedef ssize_t (*rdata_data_writer)(const void *data, size_t len, void *ctx); - -typedef struct rdata_column_s { - rdata_type_t type; - int index; - char name[256]; - char label[1024]; - - int32_t factor_count; - const char **factor; -} rdata_column_t; - -typedef struct rdata_writer_s { - rdata_data_writer data_writer; - size_t bytes_written; - - rdata_error_handler error_handler; - void *user_ctx; - - void *atom_table; - int bswap; - - rdata_column_t **columns; - int32_t columns_count; - int32_t columns_capacity; - - int32_t row_count; -} rdata_writer_t; - -rdata_writer_t *rdata_writer_init(rdata_data_writer write_callback); -void rdata_writer_free(rdata_writer_t *writer); - -rdata_column_t *rdata_add_column(rdata_writer_t *writer, const char *name, rdata_type_t type); - -rdata_error_t rdata_column_set_label(rdata_column_t *column, const char *label); -rdata_error_t rdata_column_add_factor(rdata_column_t *column, const char *factor); - -rdata_column_t *rdata_get_column(rdata_writer_t *writer, int32_t j); - -rdata_error_t rdata_begin_file(rdata_writer_t *writer, void *ctx); -rdata_error_t rdata_begin_table(rdata_writer_t *writer, const char *variable_name, int32_t row_count); -rdata_error_t rdata_begin_column(rdata_writer_t *writer, rdata_column_t *column); - -rdata_error_t rdata_append_real_value(rdata_writer_t *writer, double value); -rdata_error_t rdata_append_int32_value(rdata_writer_t *writer, int32_t value); -rdata_error_t rdata_append_timestamp_value(rdata_writer_t *writer, time_t value); -rdata_error_t rdata_append_logical_value(rdata_writer_t *writer, int value); -rdata_error_t rdata_append_string_value(rdata_writer_t *writer, const char *value); - -rdata_error_t rdata_end_column(rdata_writer_t *writer, rdata_column_t *column); -rdata_error_t rdata_end_table(rdata_writer_t *writer, const char *datalabel); -rdata_error_t rdata_end_file(rdata_writer_t *writer); diff --git a/README.md b/README.md new file mode 100644 index 0000000..1a6422c --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +This is a macOS QuickLook Plugin for R data files. + +That means if you install this plugin (download and unzip `QuickLookR.qlgenerator.zip` and put `QuickLookR.qlgenerator` into `~/Library/QuickLook`) you can hit the spacebar on an R Data or saved RDS file (`.rdata`, `.rda`, `.rds` are currently supported extensions) and get a `str()` preview without firing up R/RStudio. + +It looks for `Rscript` in `/usr/local/bin` and (for now) requires a helper package [`rdatainfo`](https://github.com/hrbrmstr/rdatainfo). `devtools::install_github("hrbrmstr/rdatainfo")` to install that. + +For the moment, the QuickLook preview is rather plain, but I hope to improve the output and switch to reading the data files at the C-level by linking directly to `R.framework`.