├── .gitignore ├── AsciiDocQuickLook.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── AsciiDocQuickLook ├── AsciiDocManager.swift ├── AsciiDocQuickLook-Bridging-Header.h ├── GeneratePreviewForURL.m ├── GenerateThumbnailForURL.m ├── Info.plist └── main.c ├── LICENSE.txt └── README.adoc /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | # 3 | # Files to ignore for Xcode projects 4 | # 5 | # Based on Swift gitignore template in the github/gitignore repository at: 6 | # https://github.com/github/gitignore/blob/5f15ed83c7a3d5db29845edae5205ca2d795c3d8/Swift.gitignore 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | 12 | ## Various settings 13 | *.pbxuser 14 | !default.pbxuser 15 | *.mode1v3 16 | !default.mode1v3 17 | *.mode2v3 18 | !default.mode2v3 19 | *.perspectivev3 20 | !default.perspectivev3 21 | xcuserdata/ 22 | 23 | ## Other 24 | *.moved-aside 25 | *.xccheckout 26 | *.xcscmblueprint 27 | 28 | ## Obj-C/Swift specific 29 | *.hmap 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | # Package.resolved 44 | .build/ 45 | 46 | # CocoaPods 47 | # 48 | # We recommend against adding the Pods directory to your .gitignore. However 49 | # you should judge for yourself, the pros and cons are mentioned at: 50 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 51 | # 52 | # Pods/ 53 | 54 | # Carthage 55 | # 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # fastlane 62 | # 63 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 64 | # screenshots whenever they are needed. 65 | # For more information about the recommended setup visit: 66 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 67 | 68 | fastlane/report.xml 69 | fastlane/Preview.html 70 | fastlane/screenshots 71 | fastlane/test_output 72 | -------------------------------------------------------------------------------- /AsciiDocQuickLook.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C27DE3711FAF69F80057F054 /* README.adoc in Resources */ = {isa = PBXBuildFile; fileRef = C27DE3701FAF69F80057F054 /* README.adoc */; }; 11 | C2D158ED1D1B1AF2009BC66B /* GenerateThumbnailForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = C2D158EC1D1B1AF2009BC66B /* GenerateThumbnailForURL.m */; }; 12 | C2D158EF1D1B1AF2009BC66B /* GeneratePreviewForURL.m in Sources */ = {isa = PBXBuildFile; fileRef = C2D158EE1D1B1AF2009BC66B /* GeneratePreviewForURL.m */; }; 13 | C2D158F11D1B1AF2009BC66B /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = C2D158F01D1B1AF2009BC66B /* main.c */; }; 14 | C2D158FA1D1B1CFC009BC66B /* AsciiDocManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2D158F91D1B1CFC009BC66B /* AsciiDocManager.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | C27DE3701FAF69F80057F054 /* README.adoc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README.adoc; sourceTree = ""; }; 19 | C2D158E91D1B1AF2009BC66B /* AsciiDoc.qlgenerator */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AsciiDoc.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | C2D158EC1D1B1AF2009BC66B /* GenerateThumbnailForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GenerateThumbnailForURL.m; sourceTree = ""; }; 21 | C2D158EE1D1B1AF2009BC66B /* GeneratePreviewForURL.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = GeneratePreviewForURL.m; sourceTree = ""; }; 22 | C2D158F01D1B1AF2009BC66B /* main.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 23 | C2D158F21D1B1AF2009BC66B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 24 | C2D158F81D1B1CFC009BC66B /* AsciiDocQuickLook-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AsciiDocQuickLook-Bridging-Header.h"; sourceTree = ""; }; 25 | C2D158F91D1B1CFC009BC66B /* AsciiDocManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsciiDocManager.swift; sourceTree = ""; }; 26 | /* End PBXFileReference section */ 27 | 28 | /* Begin PBXFrameworksBuildPhase section */ 29 | C2D158E51D1B1AF2009BC66B /* Frameworks */ = { 30 | isa = PBXFrameworksBuildPhase; 31 | buildActionMask = 2147483647; 32 | files = ( 33 | ); 34 | runOnlyForDeploymentPostprocessing = 0; 35 | }; 36 | /* End PBXFrameworksBuildPhase section */ 37 | 38 | /* Begin PBXGroup section */ 39 | C2D158DF1D1B1AF2009BC66B = { 40 | isa = PBXGroup; 41 | children = ( 42 | C27DE3701FAF69F80057F054 /* README.adoc */, 43 | C2D158EB1D1B1AF2009BC66B /* AsciiDocQuickLook */, 44 | C2D158EA1D1B1AF2009BC66B /* Products */, 45 | ); 46 | sourceTree = ""; 47 | }; 48 | C2D158EA1D1B1AF2009BC66B /* Products */ = { 49 | isa = PBXGroup; 50 | children = ( 51 | C2D158E91D1B1AF2009BC66B /* AsciiDoc.qlgenerator */, 52 | ); 53 | name = Products; 54 | sourceTree = ""; 55 | }; 56 | C2D158EB1D1B1AF2009BC66B /* AsciiDocQuickLook */ = { 57 | isa = PBXGroup; 58 | children = ( 59 | C2D158EC1D1B1AF2009BC66B /* GenerateThumbnailForURL.m */, 60 | C2D158EE1D1B1AF2009BC66B /* GeneratePreviewForURL.m */, 61 | C2D158F91D1B1CFC009BC66B /* AsciiDocManager.swift */, 62 | C2D158F01D1B1AF2009BC66B /* main.c */, 63 | C2D158F21D1B1AF2009BC66B /* Info.plist */, 64 | C2D158F81D1B1CFC009BC66B /* AsciiDocQuickLook-Bridging-Header.h */, 65 | ); 66 | path = AsciiDocQuickLook; 67 | sourceTree = ""; 68 | }; 69 | /* End PBXGroup section */ 70 | 71 | /* Begin PBXHeadersBuildPhase section */ 72 | C2D158E61D1B1AF2009BC66B /* Headers */ = { 73 | isa = PBXHeadersBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | /* End PBXHeadersBuildPhase section */ 80 | 81 | /* Begin PBXNativeTarget section */ 82 | C2D158E81D1B1AF2009BC66B /* AsciiDoc */ = { 83 | isa = PBXNativeTarget; 84 | buildConfigurationList = C2D158F51D1B1AF2009BC66B /* Build configuration list for PBXNativeTarget "AsciiDoc" */; 85 | buildPhases = ( 86 | C2D158E41D1B1AF2009BC66B /* Sources */, 87 | C2D158E51D1B1AF2009BC66B /* Frameworks */, 88 | C2D158E61D1B1AF2009BC66B /* Headers */, 89 | C2D158E71D1B1AF2009BC66B /* Resources */, 90 | ); 91 | buildRules = ( 92 | ); 93 | dependencies = ( 94 | ); 95 | name = AsciiDoc; 96 | productName = AsciiDoc; 97 | productReference = C2D158E91D1B1AF2009BC66B /* AsciiDoc.qlgenerator */; 98 | productType = "com.apple.product-type.bundle"; 99 | }; 100 | /* End PBXNativeTarget section */ 101 | 102 | /* Begin PBXProject section */ 103 | C2D158E01D1B1AF2009BC66B /* Project object */ = { 104 | isa = PBXProject; 105 | attributes = { 106 | LastUpgradeCheck = 0820; 107 | ORGANIZATIONNAME = "Clyde Clements"; 108 | TargetAttributes = { 109 | C2D158E81D1B1AF2009BC66B = { 110 | CreatedOnToolsVersion = 7.3.1; 111 | DevelopmentTeam = LYJQR9E3B7; 112 | LastSwiftMigration = 0820; 113 | ProvisioningStyle = Automatic; 114 | }; 115 | }; 116 | }; 117 | buildConfigurationList = C2D158E31D1B1AF2009BC66B /* Build configuration list for PBXProject "AsciiDocQuickLook" */; 118 | compatibilityVersion = "Xcode 3.2"; 119 | developmentRegion = English; 120 | hasScannedForEncodings = 0; 121 | knownRegions = ( 122 | en, 123 | ); 124 | mainGroup = C2D158DF1D1B1AF2009BC66B; 125 | productRefGroup = C2D158EA1D1B1AF2009BC66B /* Products */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | C2D158E81D1B1AF2009BC66B /* AsciiDoc */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXResourcesBuildPhase section */ 135 | C2D158E71D1B1AF2009BC66B /* Resources */ = { 136 | isa = PBXResourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | C27DE3711FAF69F80057F054 /* README.adoc in Resources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXResourcesBuildPhase section */ 144 | 145 | /* Begin PBXSourcesBuildPhase section */ 146 | C2D158E41D1B1AF2009BC66B /* Sources */ = { 147 | isa = PBXSourcesBuildPhase; 148 | buildActionMask = 2147483647; 149 | files = ( 150 | C2D158ED1D1B1AF2009BC66B /* GenerateThumbnailForURL.m in Sources */, 151 | C2D158EF1D1B1AF2009BC66B /* GeneratePreviewForURL.m in Sources */, 152 | C2D158FA1D1B1CFC009BC66B /* AsciiDocManager.swift in Sources */, 153 | C2D158F11D1B1AF2009BC66B /* main.c in Sources */, 154 | ); 155 | runOnlyForDeploymentPostprocessing = 0; 156 | }; 157 | /* End PBXSourcesBuildPhase section */ 158 | 159 | /* Begin XCBuildConfiguration section */ 160 | C2D158F31D1B1AF2009BC66B /* Debug */ = { 161 | isa = XCBuildConfiguration; 162 | buildSettings = { 163 | ALWAYS_SEARCH_USER_PATHS = NO; 164 | CLANG_ANALYZER_NONNULL = YES; 165 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 166 | CLANG_CXX_LIBRARY = "libc++"; 167 | CLANG_ENABLE_MODULES = YES; 168 | CLANG_ENABLE_OBJC_ARC = YES; 169 | CLANG_WARN_BOOL_CONVERSION = YES; 170 | CLANG_WARN_CONSTANT_CONVERSION = YES; 171 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 172 | CLANG_WARN_EMPTY_BODY = YES; 173 | CLANG_WARN_ENUM_CONVERSION = YES; 174 | CLANG_WARN_INFINITE_RECURSION = YES; 175 | CLANG_WARN_INT_CONVERSION = YES; 176 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 177 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 178 | CLANG_WARN_UNREACHABLE_CODE = YES; 179 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 180 | CODE_SIGN_IDENTITY = "-"; 181 | COPY_PHASE_STRIP = NO; 182 | DEBUG_INFORMATION_FORMAT = dwarf; 183 | ENABLE_STRICT_OBJC_MSGSEND = YES; 184 | ENABLE_TESTABILITY = YES; 185 | GCC_C_LANGUAGE_STANDARD = gnu99; 186 | GCC_DYNAMIC_NO_PIC = NO; 187 | GCC_NO_COMMON_BLOCKS = YES; 188 | GCC_OPTIMIZATION_LEVEL = 0; 189 | GCC_PREPROCESSOR_DEFINITIONS = ( 190 | "DEBUG=1", 191 | "$(inherited)", 192 | ); 193 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 194 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 195 | GCC_WARN_UNDECLARED_SELECTOR = YES; 196 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 197 | GCC_WARN_UNUSED_FUNCTION = YES; 198 | GCC_WARN_UNUSED_VARIABLE = YES; 199 | MACOSX_DEPLOYMENT_TARGET = 10.11; 200 | MTL_ENABLE_DEBUG_INFO = YES; 201 | ONLY_ACTIVE_ARCH = YES; 202 | SDKROOT = macosx; 203 | }; 204 | name = Debug; 205 | }; 206 | C2D158F41D1B1AF2009BC66B /* Release */ = { 207 | isa = XCBuildConfiguration; 208 | buildSettings = { 209 | ALWAYS_SEARCH_USER_PATHS = NO; 210 | CLANG_ANALYZER_NONNULL = YES; 211 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 212 | CLANG_CXX_LIBRARY = "libc++"; 213 | CLANG_ENABLE_MODULES = YES; 214 | CLANG_ENABLE_OBJC_ARC = YES; 215 | CLANG_WARN_BOOL_CONVERSION = YES; 216 | CLANG_WARN_CONSTANT_CONVERSION = YES; 217 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 218 | CLANG_WARN_EMPTY_BODY = YES; 219 | CLANG_WARN_ENUM_CONVERSION = YES; 220 | CLANG_WARN_INFINITE_RECURSION = YES; 221 | CLANG_WARN_INT_CONVERSION = YES; 222 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 223 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 224 | CLANG_WARN_UNREACHABLE_CODE = YES; 225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 226 | CODE_SIGN_IDENTITY = "-"; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 229 | ENABLE_NS_ASSERTIONS = NO; 230 | ENABLE_STRICT_OBJC_MSGSEND = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu99; 232 | GCC_NO_COMMON_BLOCKS = YES; 233 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 234 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 235 | GCC_WARN_UNDECLARED_SELECTOR = YES; 236 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 237 | GCC_WARN_UNUSED_FUNCTION = YES; 238 | GCC_WARN_UNUSED_VARIABLE = YES; 239 | MACOSX_DEPLOYMENT_TARGET = 10.11; 240 | MTL_ENABLE_DEBUG_INFO = NO; 241 | SDKROOT = macosx; 242 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 243 | }; 244 | name = Release; 245 | }; 246 | C2D158F61D1B1AF2009BC66B /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 250 | CLANG_ENABLE_MODULES = YES; 251 | CODE_SIGN_IDENTITY = "Mac Developer"; 252 | COMBINE_HIDPI_IMAGES = YES; 253 | INFOPLIST_FILE = AsciiDocQuickLook/Info.plist; 254 | INSTALL_PATH = /Library/QuickLook; 255 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks"; 256 | PRODUCT_BUNDLE_IDENTIFIER = ca.bluemist2.AsciiDocQuickLook; 257 | PRODUCT_NAME = AsciiDoc; 258 | SWIFT_OBJC_BRIDGING_HEADER = "AsciiDocQuickLook/AsciiDocQuickLook-Bridging-Header.h"; 259 | SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)QuickLook-Swift.h"; 260 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 261 | SWIFT_VERSION = 3.0; 262 | WRAPPER_EXTENSION = qlgenerator; 263 | }; 264 | name = Debug; 265 | }; 266 | C2D158F71D1B1AF2009BC66B /* Release */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 270 | CLANG_ENABLE_MODULES = YES; 271 | CODE_SIGN_IDENTITY = "Mac Developer"; 272 | COMBINE_HIDPI_IMAGES = YES; 273 | INFOPLIST_FILE = AsciiDocQuickLook/Info.plist; 274 | INSTALL_PATH = /Library/QuickLook; 275 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @loader_path/../Frameworks"; 276 | PRODUCT_BUNDLE_IDENTIFIER = ca.bluemist2.AsciiDocQuickLook; 277 | PRODUCT_NAME = AsciiDoc; 278 | SWIFT_OBJC_BRIDGING_HEADER = "AsciiDocQuickLook/AsciiDocQuickLook-Bridging-Header.h"; 279 | SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)QuickLook-Swift.h"; 280 | SWIFT_VERSION = 3.0; 281 | WRAPPER_EXTENSION = qlgenerator; 282 | }; 283 | name = Release; 284 | }; 285 | /* End XCBuildConfiguration section */ 286 | 287 | /* Begin XCConfigurationList section */ 288 | C2D158E31D1B1AF2009BC66B /* Build configuration list for PBXProject "AsciiDocQuickLook" */ = { 289 | isa = XCConfigurationList; 290 | buildConfigurations = ( 291 | C2D158F31D1B1AF2009BC66B /* Debug */, 292 | C2D158F41D1B1AF2009BC66B /* Release */, 293 | ); 294 | defaultConfigurationIsVisible = 0; 295 | defaultConfigurationName = Release; 296 | }; 297 | C2D158F51D1B1AF2009BC66B /* Build configuration list for PBXNativeTarget "AsciiDoc" */ = { 298 | isa = XCConfigurationList; 299 | buildConfigurations = ( 300 | C2D158F61D1B1AF2009BC66B /* Debug */, 301 | C2D158F71D1B1AF2009BC66B /* Release */, 302 | ); 303 | defaultConfigurationIsVisible = 0; 304 | defaultConfigurationName = Release; 305 | }; 306 | /* End XCConfigurationList section */ 307 | }; 308 | rootObject = C2D158E01D1B1AF2009BC66B /* Project object */; 309 | } 310 | -------------------------------------------------------------------------------- /AsciiDocQuickLook.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AsciiDocQuickLook/AsciiDocManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AsciiDocManager.swift 3 | // AsciiDocQuickLook 4 | // 5 | // Created by Clyde Clements on 2016-06-22. 6 | // Copyright © 2016 Clyde Clements. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import QuickLook 11 | 12 | @objc open class AsciiDocManager: NSObject { 13 | fileprivate let url: URL 14 | 15 | public init(withUrl url: URL) { 16 | self.url = url 17 | } 18 | 19 | fileprivate func buildData(_ type: String) -> Data? { 20 | let task = Process() 21 | var useDefaultConverter = true 22 | if let prefs = UserDefaults.init(suiteName: "ca.bluemist2.AsciiDocQuickLook") { 23 | if let converter = prefs.string(forKey: "AsciiDocConverter") { 24 | let msg = "AsciiDoc Quick Look: using user-specified " + 25 | "converter \(converter)" 26 | NSLog(msg) 27 | task.launchPath = converter 28 | useDefaultConverter = false 29 | } 30 | } 31 | if useDefaultConverter { 32 | // The PATH setting must include /usr/local/bin in order for the 33 | // asciidoctor script to run with /usr/local/bin/ruby (if installed) 34 | // instead of /usr/bin/ruby. 35 | task.environment = [ 36 | "PATH": "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" 37 | ] 38 | task.launchPath = "/usr/local/bin/asciidoctor" 39 | task.arguments = [ 40 | "-b", "html5", "-a", "nofooter", "-o", "-", url.path 41 | ] 42 | } else { 43 | task.arguments = [url.path] 44 | } 45 | let pipe = Pipe() 46 | task.standardOutput = pipe 47 | var output = Data() 48 | let pipeOutputHandle = pipe.fileHandleForReading 49 | pipeOutputHandle.readabilityHandler = { pipe in 50 | output.append(pipe.availableData) 51 | } 52 | task.terminationHandler = { task in 53 | pipeOutputHandle.readabilityHandler = nil 54 | } 55 | task.launch() 56 | task.waitUntilExit() 57 | 58 | if (task.terminationStatus != 0) { 59 | let msg = "AsciiDoc Quick Look: " + 60 | "converter termination status \(task.terminationStatus); " + 61 | "unable to create data for \(type)" 62 | NSLog(msg) 63 | return nil 64 | } 65 | 66 | return output 67 | } 68 | 69 | open func buildPreview() -> Data? { 70 | return buildData("preview") 71 | } 72 | 73 | open func buildThumbnail() -> Data? { 74 | return buildData("thumbnail") 75 | } 76 | 77 | open func buildPreviewProperties() -> CFDictionary { 78 | return [ 79 | kQLPreviewPropertyTextEncodingNameKey as String : "UTF-8", 80 | kQLPreviewPropertyMIMETypeKey as String : "text/html" 81 | ] as CFDictionary 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /AsciiDocQuickLook/AsciiDocQuickLook-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | -------------------------------------------------------------------------------- /AsciiDocQuickLook/GeneratePreviewForURL.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import "AsciiDocQuickLook-Swift.h" 6 | 7 | OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); 8 | void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview); 9 | 10 | /* ----------------------------------------------------------------------------- 11 | Generate a preview for file 12 | This function's job is to create preview for designated file 13 | ----------------------------------------------------------------------------- */ 14 | 15 | OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options) 16 | { 17 | if (QLPreviewRequestIsCancelled(preview)) { 18 | return noErr; 19 | } 20 | 21 | AsciiDocManager* adManager = [[AsciiDocManager alloc] initWithUrl:(__bridge NSURL *)url]; 22 | 23 | CFDataRef data = (__bridge CFDataRef)[adManager buildPreview]; 24 | 25 | if (QLPreviewRequestIsCancelled(preview)) { 26 | return noErr; 27 | } 28 | 29 | CFDictionaryRef properties = [adManager buildPreviewProperties]; 30 | 31 | if (QLPreviewRequestIsCancelled(preview)) { 32 | return noErr; 33 | } 34 | 35 | QLPreviewRequestSetDataRepresentation(preview, data, kUTTypeHTML, properties); 36 | return noErr; 37 | } 38 | 39 | void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview) 40 | { 41 | // Implement only if supported 42 | } -------------------------------------------------------------------------------- /AsciiDocQuickLook/GenerateThumbnailForURL.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import 6 | #import "AsciiDocQuickLook-Swift.h" 7 | 8 | OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); 9 | void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail); 10 | 11 | /* ----------------------------------------------------------------------------- 12 | Generate a thumbnail for file 13 | 14 | This function's job is to create thumbnail for designated file as fast as possible 15 | ----------------------------------------------------------------------------- */ 16 | 17 | OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) 18 | { 19 | if (QLThumbnailRequestIsCancelled(thumbnail)) { 20 | return noErr; 21 | } 22 | 23 | AsciiDocManager* adManager = [[AsciiDocManager alloc] initWithUrl:(__bridge NSURL *)url]; 24 | CFDataRef data = (__bridge CFDataRef)[adManager buildThumbnail]; 25 | 26 | if (QLThumbnailRequestIsCancelled(thumbnail)) { 27 | return noErr; 28 | } 29 | 30 | NSRect viewRect = NSMakeRect(0.0, 0.0, 600.0, 800.0); 31 | float scale = maxSize.height / 800.0; 32 | NSSize scaleSize = NSMakeSize(scale, scale); 33 | CGSize thumbSize = NSSizeToCGSize(NSMakeSize((maxSize.width * (600.0/800.0)), maxSize.height)); 34 | 35 | WebView* webView = [[WebView alloc] initWithFrame: viewRect]; 36 | [webView scaleUnitSquareToSize: scaleSize]; 37 | [webView.mainFrame.frameView setAllowsScrolling:NO]; 38 | [webView.mainFrame loadData: (__bridge NSData *)(data) 39 | MIMEType: @"text/html" 40 | textEncodingName: @"utf-8" 41 | baseURL: (__bridge NSURL *)(url)]; 42 | 43 | while([webView isLoading]) { 44 | if (QLThumbnailRequestIsCancelled(thumbnail)) { 45 | return noErr; 46 | } 47 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); 48 | } 49 | 50 | [webView display]; 51 | 52 | CGContextRef context = QLThumbnailRequestCreateContext(thumbnail, thumbSize, false, NULL); 53 | 54 | if (context) { 55 | NSGraphicsContext *nsContext = [NSGraphicsContext graphicsContextWithGraphicsPort:(void *)context flipped:[webView isFlipped]]; 56 | [webView displayRectIgnoringOpacity:webView.bounds inContext:nsContext]; 57 | 58 | QLThumbnailRequestFlushContext(thumbnail, context); 59 | 60 | CFRelease(context); 61 | } 62 | 63 | return noErr; 64 | } 65 | 66 | void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail) 67 | { 68 | // Implement only if supported 69 | } 70 | -------------------------------------------------------------------------------- /AsciiDocQuickLook/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeRole 11 | QLGenerator 12 | LSItemContentTypes 13 | 14 | org.asciidoc 15 | 16 | 17 | 18 | CFBundleExecutable 19 | $(EXECUTABLE_NAME) 20 | CFBundleIdentifier 21 | $(PRODUCT_BUNDLE_IDENTIFIER) 22 | CFBundleInfoDictionaryVersion 23 | 6.0 24 | CFBundleName 25 | $(PRODUCT_NAME) 26 | CFBundleShortVersionString 27 | 1.0.1 28 | CFBundleSignature 29 | ???? 30 | CFBundleVersion 31 | 1 32 | CFPlugInDynamicRegisterFunction 33 | 34 | CFPlugInDynamicRegistration 35 | NO 36 | CFPlugInFactories 37 | 38 | D12D2AD4-0B90-47BD-8E2A-CEF2E6D083BF 39 | QuickLookGeneratorPluginFactory 40 | 41 | CFPlugInTypes 42 | 43 | 5E2D9680-5022-40FA-B806-43349622E5B9 44 | 45 | D12D2AD4-0B90-47BD-8E2A-CEF2E6D083BF 46 | 47 | 48 | CFPlugInUnloadFunction 49 | 50 | LSApplicationCategoryType 51 | 52 | NSHumanReadableCopyright 53 | Copyright © 2016 Clyde Clements. All rights reserved. 54 | QLNeedsToBeRunInMainThread 55 | 56 | QLPreviewHeight 57 | 600 58 | QLPreviewWidth 59 | 800 60 | QLSupportsConcurrentRequests 61 | 62 | QLThumbnailMinimumSize 63 | 17 64 | UTImportedTypeDeclarations 65 | 66 | 67 | UTTypeConformsTo 68 | 69 | public.plain-text 70 | 71 | UTTypeDescription 72 | AsciiDoc document 73 | UTTypeIconFile 74 | public.text.icns 75 | UTTypeIdentifier 76 | org.asciidoc 77 | UTTypeTagSpecification 78 | 79 | public.filename-extension 80 | 81 | ad 82 | adoc 83 | asciidoc 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /AsciiDocQuickLook/main.c: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // 3 | // DO NO MODIFY THE CONTENT OF THIS FILE 4 | // 5 | // This file contains the generic CFPlug-in code necessary for your generator 6 | // To complete your generator implement the function in GenerateThumbnailForURL/GeneratePreviewForURL.c 7 | // 8 | //============================================================================== 9 | 10 | 11 | 12 | 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | // ----------------------------------------------------------------------------- 21 | // constants 22 | // ----------------------------------------------------------------------------- 23 | 24 | // Don't modify this line 25 | #define PLUGIN_ID "D12D2AD4-0B90-47BD-8E2A-CEF2E6D083BF" 26 | 27 | // 28 | // Below is the generic glue code for all plug-ins. 29 | // 30 | // You should not have to modify this code aside from changing 31 | // names if you decide to change the names defined in the Info.plist 32 | // 33 | 34 | 35 | // ----------------------------------------------------------------------------- 36 | // typedefs 37 | // ----------------------------------------------------------------------------- 38 | 39 | // The thumbnail generation function to be implemented in GenerateThumbnailForURL.c 40 | OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); 41 | void CancelThumbnailGeneration(void* thisInterface, QLThumbnailRequestRef thumbnail); 42 | 43 | // The preview generation function to be implemented in GeneratePreviewForURL.c 44 | OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); 45 | void CancelPreviewGeneration(void *thisInterface, QLPreviewRequestRef preview); 46 | 47 | // The layout for an instance of QuickLookGeneratorPlugIn 48 | typedef struct __QuickLookGeneratorPluginType 49 | { 50 | void *conduitInterface; 51 | CFUUIDRef factoryID; 52 | UInt32 refCount; 53 | } QuickLookGeneratorPluginType; 54 | 55 | // ----------------------------------------------------------------------------- 56 | // prototypes 57 | // ----------------------------------------------------------------------------- 58 | // Forward declaration for the IUnknown implementation. 59 | // 60 | 61 | QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID); 62 | void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance); 63 | HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv); 64 | void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID); 65 | ULONG QuickLookGeneratorPluginAddRef(void *thisInstance); 66 | ULONG QuickLookGeneratorPluginRelease(void *thisInstance); 67 | 68 | // ----------------------------------------------------------------------------- 69 | // myInterfaceFtbl definition 70 | // ----------------------------------------------------------------------------- 71 | // The QLGeneratorInterfaceStruct function table. 72 | // 73 | static QLGeneratorInterfaceStruct myInterfaceFtbl = { 74 | NULL, 75 | QuickLookGeneratorQueryInterface, 76 | QuickLookGeneratorPluginAddRef, 77 | QuickLookGeneratorPluginRelease, 78 | NULL, 79 | NULL, 80 | NULL, 81 | NULL 82 | }; 83 | 84 | 85 | // ----------------------------------------------------------------------------- 86 | // AllocQuickLookGeneratorPluginType 87 | // ----------------------------------------------------------------------------- 88 | // Utility function that allocates a new instance. 89 | // You can do some initial setup for the generator here if you wish 90 | // like allocating globals etc... 91 | // 92 | QuickLookGeneratorPluginType *AllocQuickLookGeneratorPluginType(CFUUIDRef inFactoryID) 93 | { 94 | QuickLookGeneratorPluginType *theNewInstance; 95 | 96 | theNewInstance = (QuickLookGeneratorPluginType *)malloc(sizeof(QuickLookGeneratorPluginType)); 97 | memset(theNewInstance,0,sizeof(QuickLookGeneratorPluginType)); 98 | 99 | /* Point to the function table Malloc enough to store the stuff and copy the filler from myInterfaceFtbl over */ 100 | theNewInstance->conduitInterface = malloc(sizeof(QLGeneratorInterfaceStruct)); 101 | memcpy(theNewInstance->conduitInterface,&myInterfaceFtbl,sizeof(QLGeneratorInterfaceStruct)); 102 | 103 | /* Retain and keep an open instance refcount for each factory. */ 104 | theNewInstance->factoryID = CFRetain(inFactoryID); 105 | CFPlugInAddInstanceForFactory(inFactoryID); 106 | 107 | /* This function returns the IUnknown interface so set the refCount to one. */ 108 | theNewInstance->refCount = 1; 109 | return theNewInstance; 110 | } 111 | 112 | // ----------------------------------------------------------------------------- 113 | // DeallocQuickLookGeneratorPluginType 114 | // ----------------------------------------------------------------------------- 115 | // Utility function that deallocates the instance when 116 | // the refCount goes to zero. 117 | // In the current implementation generator interfaces are never deallocated 118 | // but implement this as this might change in the future 119 | // 120 | void DeallocQuickLookGeneratorPluginType(QuickLookGeneratorPluginType *thisInstance) 121 | { 122 | CFUUIDRef theFactoryID; 123 | 124 | theFactoryID = thisInstance->factoryID; 125 | /* Free the conduitInterface table up */ 126 | free(thisInstance->conduitInterface); 127 | 128 | /* Free the instance structure */ 129 | free(thisInstance); 130 | if (theFactoryID){ 131 | CFPlugInRemoveInstanceForFactory(theFactoryID); 132 | CFRelease(theFactoryID); 133 | } 134 | } 135 | 136 | // ----------------------------------------------------------------------------- 137 | // QuickLookGeneratorQueryInterface 138 | // ----------------------------------------------------------------------------- 139 | // Implementation of the IUnknown QueryInterface function. 140 | // 141 | HRESULT QuickLookGeneratorQueryInterface(void *thisInstance,REFIID iid,LPVOID *ppv) 142 | { 143 | CFUUIDRef interfaceID; 144 | 145 | interfaceID = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault,iid); 146 | 147 | if (CFEqual(interfaceID,kQLGeneratorCallbacksInterfaceID)){ 148 | /* If the Right interface was requested, bump the ref count, 149 | * set the ppv parameter equal to the instance, and 150 | * return good status. 151 | */ 152 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GenerateThumbnailForURL = GenerateThumbnailForURL; 153 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelThumbnailGeneration = CancelThumbnailGeneration; 154 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->GeneratePreviewForURL = GeneratePreviewForURL; 155 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType *)thisInstance)->conduitInterface)->CancelPreviewGeneration = CancelPreviewGeneration; 156 | ((QLGeneratorInterfaceStruct *)((QuickLookGeneratorPluginType*)thisInstance)->conduitInterface)->AddRef(thisInstance); 157 | *ppv = thisInstance; 158 | CFRelease(interfaceID); 159 | return S_OK; 160 | }else{ 161 | /* Requested interface unknown, bail with error. */ 162 | *ppv = NULL; 163 | CFRelease(interfaceID); 164 | return E_NOINTERFACE; 165 | } 166 | } 167 | 168 | // ----------------------------------------------------------------------------- 169 | // QuickLookGeneratorPluginAddRef 170 | // ----------------------------------------------------------------------------- 171 | // Implementation of reference counting for this type. Whenever an interface 172 | // is requested, bump the refCount for the instance. NOTE: returning the 173 | // refcount is a convention but is not required so don't rely on it. 174 | // 175 | ULONG QuickLookGeneratorPluginAddRef(void *thisInstance) 176 | { 177 | ((QuickLookGeneratorPluginType *)thisInstance )->refCount += 1; 178 | return ((QuickLookGeneratorPluginType*) thisInstance)->refCount; 179 | } 180 | 181 | // ----------------------------------------------------------------------------- 182 | // QuickLookGeneratorPluginRelease 183 | // ----------------------------------------------------------------------------- 184 | // When an interface is released, decrement the refCount. 185 | // If the refCount goes to zero, deallocate the instance. 186 | // 187 | ULONG QuickLookGeneratorPluginRelease(void *thisInstance) 188 | { 189 | ((QuickLookGeneratorPluginType*)thisInstance)->refCount -= 1; 190 | if (((QuickLookGeneratorPluginType*)thisInstance)->refCount == 0){ 191 | DeallocQuickLookGeneratorPluginType((QuickLookGeneratorPluginType*)thisInstance ); 192 | return 0; 193 | }else{ 194 | return ((QuickLookGeneratorPluginType*) thisInstance )->refCount; 195 | } 196 | } 197 | 198 | // ----------------------------------------------------------------------------- 199 | // QuickLookGeneratorPluginFactory 200 | // ----------------------------------------------------------------------------- 201 | void *QuickLookGeneratorPluginFactory(CFAllocatorRef allocator,CFUUIDRef typeID) 202 | { 203 | QuickLookGeneratorPluginType *result; 204 | CFUUIDRef uuid; 205 | 206 | /* If correct type is being requested, allocate an 207 | * instance of kQLGeneratorTypeID and return the IUnknown interface. 208 | */ 209 | if (CFEqual(typeID,kQLGeneratorTypeID)){ 210 | uuid = CFUUIDCreateFromString(kCFAllocatorDefault,CFSTR(PLUGIN_ID)); 211 | result = AllocQuickLookGeneratorPluginType(uuid); 212 | CFRelease(uuid); 213 | return result; 214 | } 215 | /* If the requested type is incorrect, return NULL. */ 216 | return NULL; 217 | } 218 | 219 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Clyde Clements 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = AsciiDoc Quick Look 2 | 3 | :url-releases: https://github.com/clydeclements/AsciiDocQuickLook/releases 4 | :url-what-is-asciidoc: http://asciidoctor.org/docs/what-is-asciidoc/ 5 | :url-asciidoctor: http://asciidoctor.org/ 6 | :url-terminating-processes: https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/Lifecycle.html#//apple_ref/doc/uid/10000172i-SW3-114794-BAJIBGGI 7 | :url-asciidoctorjs: http://asciidoctor.org/docs/install-and-use-asciidoctorjs 8 | :url-qlswift: https://github.com/lexrus/QLSwift 9 | 10 | 11 | == Introduction 12 | 13 | This is a Quick Look plug-in for {url-what-is-asciidoc}[AsciiDoc] format files. 14 | It renders a preview of an AsciiDoc file selected in the Finder by using 15 | {url-asciidoctor}[Asciidoctor]. 16 | 17 | == Installation 18 | 19 | * By default this plug-in uses Asciidoctor to render the preview. Therefore, 20 | first install that program via your preferred method. For example, to install 21 | via the system `gem` command, use: 22 | 23 | sudo gem install asciidoctor 24 | 25 | * Download a zipped {url-releases}[binary] of this plug-in. Unzip and move 26 | `AsciiDoc.qlgenerator` into `/Library/QuickLook`. Note the plug-in will not 27 | work if installed to a user directory `~/Library/QuickLook` due to restraints 28 | imposed by the sand-boxing of Quick Look plug-ins. 29 | 30 | * Lastly, open Terminal and run the command `qlmanage -r` to reset the Quick 31 | Look Server. 32 | 33 | == Customization 34 | 35 | The preview of an AsciiDoc file is generated by converting it to HTML via 36 | Asciidoctor and displaying the resultant HTML. This process can be customized 37 | by setting a preference to override the converter: 38 | 39 | defaults write ca.bluemist2.AsciiDocQuickLook AsciiDocConverter /path/to/my_converter 40 | 41 | The last part of the above command must give the full path to an executable 42 | that accepts one argument, the name of the AsciiDoc file to be previewed, and 43 | writes the corresponding HTML format on standard output. For example, create 44 | a shell script called `asciidoc_to_html` with content similar to the following: 45 | 46 | #!/bin/bash 47 | export PATH=/usr/local/bin:$PATH 48 | asciidoctor -b html5 -a nofooter -a icons=font -o - "$1" 49 | 50 | Ensure the script is executable (use `chmod +x asciidoc_to_html`) and place it 51 | in your `~/bin` folder (create the folder if it does not exist). Lastly, set 52 | the converter preference: 53 | 54 | defaults write ca.bluemist2.AsciiDocQuickLook AsciiDocConverter ~/bin/asciidoc_to_html 55 | 56 | == To Do 57 | 58 | * A process should support sudden termination for the best user experience; 59 | see {url-terminating-processes}[Terminating Processes]. This plug-in works by 60 | launching an Asciidoctor process. Could the handling of this process be 61 | improved? 62 | 63 | * Consider using {url-asciidoctorjs}[asciidoctor.js] to generate previews. 64 | Examine {url-qlswift}[QLSwift] to see how it generates previews using 65 | JavaScript. This method would not require the Asciidoctor program to be 66 | installed (though it would require distribution of `asciidoctor.js`) and it 67 | would not need to launch a separate process. 68 | 69 | == Release History 70 | 71 | * 1.0 (2017-11-06): Initial release 72 | 73 | == License 74 | 75 | Copyright (C) 2017 Clyde Clements 76 | 77 | The AsciiDoc Quick Look plug-in is distributed under the MIT license. See the 78 | link:LICENSE.txt[license] file for more information. 79 | --------------------------------------------------------------------------------