Proper qlmanage debugging + dark mode with media query instead of NSAppearance

This commit is contained in:
relikd
2020-01-16 15:47:37 +01:00
parent ba4b94278b
commit bf38ca1442
7 changed files with 127 additions and 60 deletions

View File

@@ -8,18 +8,23 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */; }; 540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */; };
540A649E22EE78B200470937 /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = 540A649D22EE78B200470937 /* GeneratePreviewForURL.m */; }; 540A649E22EE78B200470937 /* GeneratePreviewForURL.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */; };
540A64A022EE78B200470937 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649F22EE78B200470937 /* main.c */; }; 540A64A022EE78B200470937 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 540A649F22EE78B200470937 /* main.c */; };
541EF8B322EEFBEA00C415AA /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = 541EF8B122EEFB2300C415AA /* style.css */; }; 541EF8B322EEFBEA00C415AA /* style.css in Resources */ = {isa = PBXBuildFile; fileRef = 541EF8B122EEFB2300C415AA /* style.css */; };
54BFFC1123D09E7300012FBB /* opml-lib.h in Headers */ = {isa = PBXBuildFile; fileRef = 54BFFC0F23D09E7300012FBB /* opml-lib.h */; };
54BFFC1223D09E7300012FBB /* opml-lib.m in Sources */ = {isa = PBXBuildFile; fileRef = 54BFFC1023D09E7300012FBB /* opml-lib.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
540A649822EE78B200470937 /* QLOPML.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QLOPML.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; }; 540A649822EE78B200470937 /* QLOPML.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QLOPML.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = "<group>"; }; 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GenerateThumbnailForURL.c; sourceTree = "<group>"; };
540A649D22EE78B200470937 /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = "<group>"; }; 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = GeneratePreviewForURL.c; sourceTree = "<group>"; };
540A649F22EE78B200470937 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; }; 540A649F22EE78B200470937 /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = "<group>"; };
540A64A122EE78B200470937 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 540A64A122EE78B200470937 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
541EF8B122EEFB2300C415AA /* style.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = style.css; sourceTree = "<group>"; }; 541EF8B122EEFB2300C415AA /* style.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = style.css; sourceTree = "<group>"; };
54BFFC0423D0988A00012FBB /* sample.opml */ = {isa = PBXFileReference; lastKnownFileType = file; path = sample.opml; sourceTree = SOURCE_ROOT; };
54BFFC0F23D09E7300012FBB /* opml-lib.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "opml-lib.h"; sourceTree = "<group>"; };
54BFFC1023D09E7300012FBB /* opml-lib.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "opml-lib.m"; sourceTree = "<group>"; };
54FB05D22305C8F400A088AD /* QLOPML.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLOPML.entitlements; sourceTree = "<group>"; }; 54FB05D22305C8F400A088AD /* QLOPML.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLOPML.entitlements; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@@ -54,11 +59,14 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
54FB05D22305C8F400A088AD /* QLOPML.entitlements */, 54FB05D22305C8F400A088AD /* QLOPML.entitlements */,
54BFFC0F23D09E7300012FBB /* opml-lib.h */,
54BFFC1023D09E7300012FBB /* opml-lib.m */,
540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */, 540A649B22EE78B200470937 /* GenerateThumbnailForURL.c */,
540A649D22EE78B200470937 /* GeneratePreviewForURL.m */, 540A649D22EE78B200470937 /* GeneratePreviewForURL.c */,
540A649F22EE78B200470937 /* main.c */, 540A649F22EE78B200470937 /* main.c */,
540A64A122EE78B200470937 /* Info.plist */, 540A64A122EE78B200470937 /* Info.plist */,
541EF8B122EEFB2300C415AA /* style.css */, 541EF8B122EEFB2300C415AA /* style.css */,
54BFFC0423D0988A00012FBB /* sample.opml */,
); );
path = QLOPML; path = QLOPML;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -70,6 +78,7 @@
isa = PBXHeadersBuildPhase; isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
54BFFC1123D09E7300012FBB /* opml-lib.h in Headers */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -150,7 +159,8 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */, 540A649C22EE78B200470937 /* GenerateThumbnailForURL.c in Sources */,
540A649E22EE78B200470937 /* GeneratePreviewForURL.m in Sources */, 54BFFC1223D09E7300012FBB /* opml-lib.m in Sources */,
540A649E22EE78B200470937 /* GeneratePreviewForURL.c in Sources */,
540A64A022EE78B200470937 /* main.c in Sources */, 540A64A022EE78B200470937 /* main.c in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -281,7 +291,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
INFOPLIST_FILE = QLOPML/Info.plist; INFOPLIST_FILE = QLOPML/Info.plist;
INSTALL_PATH = /Library/QuickLook;
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML; PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = qlgenerator; WRAPPER_EXTENSION = qlgenerator;
@@ -292,7 +301,6 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
INFOPLIST_FILE = QLOPML/Info.plist; INFOPLIST_FILE = QLOPML/Info.plist;
INSTALL_PATH = /Library/QuickLook;
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML; PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLOPML;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = qlgenerator; WRAPPER_EXTENSION = qlgenerator;

View File

@@ -29,8 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES"> shouldUseLaunchSchemeArgsEnv = "YES">
<Testables> <Testables>
</Testables> </Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug" buildConfiguration = "Debug"
@@ -42,6 +40,10 @@
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal" debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<PathRunnable
runnableDebuggingMode = "0"
FilePath = "/usr/bin/qlmanage">
</PathRunnable>
<MacroExpansion> <MacroExpansion>
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
@@ -51,8 +53,24 @@
ReferencedContainer = "container:QLOPML.xcodeproj"> ReferencedContainer = "container:QLOPML.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions> <CommandLineArguments>
</AdditionalOptions> <CommandLineArgument
argument = "-g &apos;${TARGET_BUILD_DIR}/${WRAPPER_NAME}&apos; -c &apos;org.opml.ompl&apos;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-p &apos;${PROJECT_DIR}/sample.opml&apos;"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
argument = "-t &apos;${PROJECT_DIR}/sample.opml&apos; -s 512"
isEnabled = "NO">
</CommandLineArgument>
<CommandLineArgument
argument = "-o &quot;$HOME/Downloads&quot;"
isEnabled = "NO">
</CommandLineArgument>
</CommandLineArguments>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release" buildConfiguration = "Release"

View File

@@ -0,0 +1,30 @@
#include <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>
#include "opml-lib.h"
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)
{
// qlmanage -r && qlmanage -p test.opml -o tmp/ && edit tmp/test.opml.qlpreview/Preview.html
CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview);
CFDataRef data = renderOPML(url, bundle);
if (data) {
QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeHTML, NULL);
CFRelease(data);
}
return noErr;
}
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview)
{
// Implement only if supported
}

6
QLOPML/opml-lib.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef opml_lib_h
#define opml_lib_h
CFDataRef renderOPML(CFURLRef url, CFBundleRef bundle);
#endif /* opml_lib_h */

View File

@@ -1,36 +1,8 @@
#include <CoreFoundation/CoreFoundation.h> //#import <CoreFoundation/CoreFoundation.h>
#include <CoreServices/CoreServices.h> //#import <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h> //#import <QuickLook/QuickLook.h>
#include <Foundation/Foundation.h> #import <Foundation/Foundation.h>
#include <AppKit/AppKit.h> #import <AppKit/AppKit.h>
NSData* renderOPML(NSURL* url, CFBundleRef bundle);
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)
{
// qlmanage -r && qlmanage -p test.opml -o tmp/ && edit tmp/test.opml.qlpreview/Preview.html
CFBundleRef bundle = QLPreviewRequestGetGeneratorBundle(preview);
CFDataRef data = CFBridgingRetain(renderOPML((__bridge NSURL*)url, bundle));
if (data) {
QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeHTML, NULL);
}
return noErr;
}
void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview)
{
// Implement only if supported
}
// --------------------------------------------------------------- // ---------------------------------------------------------------
// | // |
@@ -52,7 +24,7 @@ void attribute(NSXMLElement *parent, NSString *key, NSString *value) {
NSXMLElement* section(NSString *title, NSString *container, NSXMLElement *parent) { NSXMLElement* section(NSString *title, NSString *container, NSXMLElement *parent) {
make(@"h3", title, parent); make(@"h3", title, parent);
NSXMLElement *div = make(container, nil, parent); NSXMLElement *div = make(container, nil, parent);
attribute(div, @"class", @"first"); attribute(div, @"class", @"section");
return div; return div;
} }
@@ -94,9 +66,9 @@ void appendNode(NSXMLElement *child, NSXMLElement *parent) {
} }
} }
NSData* renderOPML(NSURL* url, CFBundleRef bundle) { CFDataRef renderOPML(CFURLRef url, CFBundleRef bundle) {
NSError *err; NSError *err;
NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:&err]; NSXMLDocument *doc = [[NSXMLDocument alloc] initWithContentsOfURL:(__bridge NSURL*)url options:0 error:&err];
if (err || !doc) { if (err || !doc) {
printf("ERROR: %s\n", err.description.UTF8String); printf("ERROR: %s\n", err.description.UTF8String);
return nil; return nil;
@@ -112,16 +84,9 @@ NSData* renderOPML(NSURL* url, CFBundleRef bundle) {
NSXMLElement *body = make(@"body", nil, html); NSXMLElement *body = make(@"body", nil, html);
NSString *appearance = @"light";
if (@available(macOS 10.14, *)) {
if ([NSAppearance.currentAppearance.name isEqualToString:NSAppearanceNameDarkAqua])
appearance = @"dark";
}
attribute(body, @"class", appearance);
for (NSXMLElement *child in doc.children) { for (NSXMLElement *child in doc.children) {
appendNode(child, body); appendNode(child, body);
} }
NSXMLDocument *xml = [NSXMLDocument documentWithRootElement:html]; NSXMLDocument *xml = [NSXMLDocument documentWithRootElement:html];
return [xml XMLDataWithOptions:NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement]; return CFBridgingRetain([xml XMLDataWithOptions:NSXMLNodePrettyPrint | NSXMLNodeCompactEmptyElement]);
} }

View File

@@ -1,11 +1,12 @@
* { font-family: Courier; } * { font-family: Courier; }
body { padding: 30px; } body { padding: 30px; background-color: #AAA; color: black; }
dd, li, hr { font-weight: bold; line-height: 1.5em; } dd, li, hr { font-weight: bold; line-height: 1.5em; }
ul { list-style-type: none; padding-bottom: 1em; } ul { list-style-type: none; padding-bottom: 1em; }
a { font-size: 0.75em; color: #FBA43A; } a { font-size: 0.75em; color: #FBA43A; }
.light { background-color: #AAA; color: black; } .section { padding: 1em 1.5em; border-radius: 7px; background-color: #EEE; }
.dark { background-color: #555; color: white; }
.first { padding: 1em 1.5em; border-radius: 7px; } @media (prefers-color-scheme: dark) {
.light .first { background-color: #EEE; } body { background-color: #555; color: white; }
.dark .first { background-color: #222; } .section { background-color: #222; }
}

39
sample.opml Normal file
View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
<head>
<title>Sample OPML file for RSSReader</title>
</head>
<body>
<outline title="News" text="News">
<outline text="Big News Finland" title="Big News Finland" type="rss" xmlUrl="http://www.bignewsnetwork.com/?rss=37e8860164ce009a"/>
<outline text="Euronews" title="Euronews" type="rss" xmlUrl="http://feeds.feedburner.com/euronews/en/news/"/>
<outline text="Reuters Top News" title="Reuters Top News" type="rss" xmlUrl="http://feeds.reuters.com/reuters/topNews"/>
<outline text="Yahoo Europe" title="Yahoo Europe" type="rss" xmlUrl="http://rss.news.yahoo.com/rss/europe"/>
</outline>
<outline title="Leisure" text="Leisure">
<outline text="CNN Entertainment" title="CNN Entertainment" type="rss" xmlUrl="http://rss.cnn.com/rss/edition_entertainment.rss"/>
<outline text="E! News" title="E! News" type="rss" xmlUrl="http://uk.eonline.com/syndication/feeds/rssfeeds/topstories.xml"/>
<outline text="Hollywood Reporter" title="Hollywood Reporter" type="rss" xmlUrl="http://feeds.feedburner.com/thr/news"/>
<outline text="Reuters Entertainment" title="Reuters Entertainment" type="rss" xmlUrl="http://feeds.reuters.com/reuters/entertainment"/>
<outline text="Reuters Music News" title="Reuters Music News" type="rss" xmlUrl="http://feeds.reuters.com/reuters/musicNews"/>
<outline text="Yahoo Entertainment" title="Yahoo Entertainment" type="rss" xmlUrl="http://rss.news.yahoo.com/rss/entertainment"/>
</outline>
<outline title="Sports" text="Sports">
<outline text="Formula 1" title="Formula 1" type="rss" xmlUrl="http://www.formula1.com/rss/news/latest.rss"/>
<outline text="MotoGP" title="MotoGP" type="rss" xmlUrl="http://rss.crash.net/crash_motogp.xml"/>
<outline text="N.Y.Times Track And Field" title="N.Y.Times Track And Field" type="rss" xmlUrl="http://topics.nytimes.com/topics/reference/timestopics/subjects/t/track_and_field/index.html?rss=1"/>
<outline text="Reuters Sports" title="Reuters Sports" type="rss" xmlUrl="http://feeds.reuters.com/reuters/sportsNews"/>
<outline text="Yahoo Sports NHL" title="Yahoo Sports NHL" type="rss" xmlUrl="http://sports.yahoo.com/nhl/rss.xml"/>
<outline text="Yahoo Sports" title="Yahoo Sports" type="rss" xmlUrl="http://rss.news.yahoo.com/rss/sports"/>
</outline>
<outline title="Tech" text="Tech">
<outline text="Coding Horror" title="Coding Horror" type="rss" xmlUrl="http://feeds.feedburner.com/codinghorror/"/>
<outline text="Gadget Lab" title="Gadget Lab" type="rss" xmlUrl="http://www.wired.com/gadgetlab/feed/"/>
<outline text="Gizmodo" title="Gizmodo" type="rss" xmlUrl="http://gizmodo.com/index.xml"/>
<outline text="Reuters Technology" title="Reuters Technology" type="rss" xmlUrl="http://feeds.reuters.com/reuters/technologyNews"/>
</outline>
</body>
</opml>