Skip to content

Commit abca128

Browse files
committed
Merge pull request #172 from macvim-dev/feature/quicklook
Import QLStephen to quick-look MacVim file types
2 parents 92dabee + 518ae71 commit abca128

File tree

15 files changed

+4045
-1
lines changed

15 files changed

+4045
-1
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,13 @@ src/MacVim/PSMTabBarControl/PSMTabBarControl.xcodeproj/*.mode1v3
9797
src/MacVim/PSMTabBarControl/PSMTabBarControl.xcodeproj/*.pbxuser
9898
src/MacVim/PSMTabBarControl/PSMTabBarControl.xcodeproj/xcuserdata
9999
src/MacVim/PSMTabBarControl/build
100-
src/MacVim/PSMTabBarControl/build
100+
src/MacVim/qlstephen/QuickLookStephen.xcodeproj/*.mode1
101+
src/MacVim/qlstephen/QuickLookStephen.xcodeproj/*.mode1v3
102+
src/MacVim/qlstephen/QuickLookStephen.xcodeproj/*.pbxuser
103+
src/MacVim/qlstephen/QuickLookStephen.xcodeproj/xcuserdata
104+
src/MacVim/qlstephen/build
101105
src/MacVim/build
106+
src/MacVim/DerivedData
102107
src/TAGS
103108
src/Vim
104109
src/auto/config.cache

src/MacVim/Credits.rtf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ Dmitry Vazhov\
4646
\
4747
Thank you to {\field{\*\fldinst{HYPERLINK "http://www.positivespinmedia.com"}}{\fldrslt Positive Spin Media}} for the PSMTabBarControl Framework.\
4848
\
49+
Thank you to {\field{\*\fldinst{HYPERLINK "https://whomwah.github.io/qlstephen/"}}{\fldrslt Duncan Robertson}} for the QLStephen QuickLook plugin.\
50+
\
4951
Toolbar icons by {\field{\*\fldinst{HYPERLINK "http://www.mattballdesign.com/"}}{\fldrslt Matt Ball}} (free Developer Icons), {\field{\*\fldinst{HYPERLINK "http://www.jonasraskdesign.com/"}}{\fldrslt Jonas Rask}} (Danish Royalty Free icon set), and {\field{\*\fldinst{HYPERLINK "http://www.everaldo.com"}}{\fldrslt Everaldo Coelho}} (Crystal Project Icons, released under LGPL license).\
5052
\
5153
Revamped MacVim icon by RIC.\

src/MacVim/MacVim.xcodeproj/project.pbxproj

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
1DE9B9500D341AB8008FEDD4 /* MMWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 1DE9B94E0D341AB8008FEDD4 /* MMWindow.m */; };
6666
1DED78600C6DE43D0079945F /* vimrc in Copy Vim Runtime Files */ = {isa = PBXBuildFile; fileRef = 1DED785F0C6DE43D0079945F /* vimrc */; };
6767
1DFE25A50C527BC4003000F7 /* PSMTabBarControl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D493DB90C52533B00AB718C /* PSMTabBarControl.framework */; };
68+
52818B031C1C08CE00F59085 /* QLStephen.qlgenerator in Copy QuickLookPlugin */ = {isa = PBXBuildFile; fileRef = 52818AFF1C1C075300F59085 /* QLStephen.qlgenerator */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
6869
8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; };
6970
8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; };
7071
8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
@@ -86,6 +87,20 @@
8687
remoteGlobalIDString = 53DF68FC067E5B5A0090B5B0;
8788
remoteInfo = PSMTabBarControlFramework;
8889
};
90+
52818AFE1C1C075300F59085 /* PBXContainerItemProxy */ = {
91+
isa = PBXContainerItemProxy;
92+
containerPortal = 52818AFA1C1C075300F59085 /* QuickLookStephen.xcodeproj */;
93+
proxyType = 2;
94+
remoteGlobalIDString = 8D576316048677EA00EA77CD;
95+
remoteInfo = QuickLookStephen;
96+
};
97+
52818B001C1C084100F59085 /* PBXContainerItemProxy */ = {
98+
isa = PBXContainerItemProxy;
99+
containerPortal = 52818AFA1C1C075300F59085 /* QuickLookStephen.xcodeproj */;
100+
proxyType = 1;
101+
remoteGlobalIDString = 8D57630D048677EA00EA77CD;
102+
remoteInfo = QuickLookStephen;
103+
};
89104
/* End PBXContainerItemProxy section */
90105

91106
/* Begin PBXCopyFilesBuildPhase section */
@@ -124,6 +139,17 @@
124139
name = "Copy Vim Runtime Files";
125140
runOnlyForDeploymentPostprocessing = 0;
126141
};
142+
52818B021C1C088000F59085 /* Copy QuickLookPlugin */ = {
143+
isa = PBXCopyFilesBuildPhase;
144+
buildActionMask = 2147483647;
145+
dstPath = ../Library/QuickLook;
146+
dstSubfolderSpec = 6;
147+
files = (
148+
52818B031C1C08CE00F59085 /* QLStephen.qlgenerator in Copy QuickLookPlugin */,
149+
);
150+
name = "Copy QuickLookPlugin";
151+
runOnlyForDeploymentPostprocessing = 0;
152+
};
127153
/* End PBXCopyFilesBuildPhase section */
128154

129155
/* Begin PBXFileReference section */
@@ -209,6 +235,7 @@
209235
29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
210236
29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
211237
32CA4F630368D1EE00C91783 /* MacVim_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacVim_Prefix.pch; sourceTree = "<group>"; };
238+
52818AFA1C1C075300F59085 /* QuickLookStephen.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = QuickLookStephen.xcodeproj; path = qlstephen/QuickLookStephen.xcodeproj; sourceTree = "<group>"; };
212239
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
213240
8D1107320486CEB800E47090 /* MacVim.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacVim.app; sourceTree = BUILT_PRODUCTS_DIR; };
214241
/* End PBXFileReference section */
@@ -367,6 +394,7 @@
367394
29B97317FDCFA39411CA2CEA /* Resources */,
368395
1DE602460C587F760055263D /* Vim Resources */,
369396
29B97323FDCFA39411CA2CEA /* Frameworks */,
397+
52818AF81C1C073400F59085 /* QuickLook Plugin */,
370398
19C28FACFE9D520D11CA2CBB /* Products */,
371399
);
372400
name = MacVim;
@@ -406,6 +434,22 @@
406434
name = Frameworks;
407435
sourceTree = "<group>";
408436
};
437+
52818AF81C1C073400F59085 /* QuickLook Plugin */ = {
438+
isa = PBXGroup;
439+
children = (
440+
52818AFA1C1C075300F59085 /* QuickLookStephen.xcodeproj */,
441+
);
442+
name = "QuickLook Plugin";
443+
sourceTree = "<group>";
444+
};
445+
52818AFB1C1C075300F59085 /* Products */ = {
446+
isa = PBXGroup;
447+
children = (
448+
52818AFF1C1C075300F59085 /* QLStephen.qlgenerator */,
449+
);
450+
name = Products;
451+
sourceTree = "<group>";
452+
};
409453
/* End PBXGroup section */
410454

411455
/* Begin PBXNativeTarget section */
@@ -418,13 +462,15 @@
418462
8D11072E0486CEB800E47090 /* Frameworks */,
419463
1D0DCAD80BA3604D00B6CCFA /* Copy Executables */,
420464
1D9EB2840C366D7B0074B739 /* Copy Frameworks */,
465+
52818B021C1C088000F59085 /* Copy QuickLookPlugin */,
421466
1DE608B80C58807F0055263D /* Copy Vim Runtime Files */,
422467
1D1C31F00EFFBFD6003FE9A5 /* Make Document Icons */,
423468
);
424469
buildRules = (
425470
);
426471
dependencies = (
427472
1D493DCD0C5254A400AB718C /* PBXTargetDependency */,
473+
52818B011C1C084100F59085 /* PBXTargetDependency */,
428474
);
429475
name = MacVim;
430476
productInstallPath = "$(HOME)/Applications";
@@ -458,6 +504,10 @@
458504
ProductGroup = 1D493DB40C52533B00AB718C /* Products */;
459505
ProjectRef = 1D493DB30C52533B00AB718C /* PSMTabBarControl.xcodeproj */;
460506
},
507+
{
508+
ProductGroup = 52818AFB1C1C075300F59085 /* Products */;
509+
ProjectRef = 52818AFA1C1C075300F59085 /* QuickLookStephen.xcodeproj */;
510+
},
461511
);
462512
projectRoot = "";
463513
targets = (
@@ -474,6 +524,13 @@
474524
remoteRef = 1D493DB80C52533B00AB718C /* PBXContainerItemProxy */;
475525
sourceTree = BUILT_PRODUCTS_DIR;
476526
};
527+
52818AFF1C1C075300F59085 /* QLStephen.qlgenerator */ = {
528+
isa = PBXReferenceProxy;
529+
fileType = wrapper.cfbundle;
530+
path = QLStephen.qlgenerator;
531+
remoteRef = 52818AFE1C1C075300F59085 /* PBXContainerItemProxy */;
532+
sourceTree = BUILT_PRODUCTS_DIR;
533+
};
477534
/* End PBXReferenceProxy section */
478535

479536
/* Begin PBXResourcesBuildPhase section */
@@ -574,6 +631,11 @@
574631
name = PSMTabBarControlFramework;
575632
targetProxy = 1D493DCC0C5254A400AB718C /* PBXContainerItemProxy */;
576633
};
634+
52818B011C1C084100F59085 /* PBXTargetDependency */ = {
635+
isa = PBXTargetDependency;
636+
name = QuickLookStephen;
637+
targetProxy = 52818B001C1C084100F59085 /* PBXContainerItemProxy */;
638+
};
577639
/* End PBXTargetDependency section */
578640

579641
/* Begin PBXVariantGroup section */
90 Bytes
Binary file not shown.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include <CoreFoundation/CoreFoundation.h>
2+
#include <CoreServices/CoreServices.h>
3+
#include <QuickLook/QuickLook.h>
4+
5+
#import <Foundation/Foundation.h>
6+
7+
#import "QLSFileAttributes.h"
8+
9+
10+
// Generate a preview for the document with the given url
11+
OSStatus GeneratePreviewForURL(void *thisInterface,
12+
QLPreviewRequestRef request,
13+
CFURLRef url,
14+
CFStringRef contentTypeUTI,
15+
CFDictionaryRef options) {
16+
@autoreleasepool {
17+
if (QLPreviewRequestIsCancelled(request))
18+
return noErr;
19+
20+
QLSFileAttributes *magicAttributes =
21+
[QLSFileAttributes attributesForItemAtURL:(__bridge NSURL *)url];
22+
23+
if (!magicAttributes) {
24+
NSLog(@"QLStephen: Could not determine attribtues of file %@", url);
25+
return noErr;
26+
}
27+
28+
if (!magicAttributes.isTextFile) {
29+
return noErr;
30+
}
31+
32+
if (magicAttributes.fileEncoding == kCFStringEncodingInvalidId) {
33+
NSLog(@"QLStephen: Could not determine encoding of file %@", url);
34+
return noErr;
35+
}
36+
37+
NSDictionary *previewProperties = @{
38+
(NSString *)kQLPreviewPropertyStringEncodingKey : @( magicAttributes.fileEncoding ),
39+
(NSString *)kQLPreviewPropertyWidthKey : @700,
40+
(NSString *)kQLPreviewPropertyHeightKey : @800
41+
};
42+
43+
QLPreviewRequestSetURLRepresentation(
44+
request,
45+
url,
46+
kUTTypePlainText,
47+
(__bridge CFDictionaryRef)previewProperties);
48+
49+
return noErr;
50+
}
51+
}
52+
53+
void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) {
54+
// implement only if supported
55+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
#include <CoreFoundation/CoreFoundation.h>
2+
#include <CoreServices/CoreServices.h>
3+
#include <QuickLook/QuickLook.h>
4+
5+
#import <Foundation/Foundation.h>
6+
#import "RegexKitLite.h"
7+
8+
#import "QLSFileAttributes.h"
9+
10+
11+
/**
12+
* This dictionary is used for a file with no extension. It maps the MIME type
13+
* (as returned by file(1)) onto an appropriate thumbnail badge.
14+
*/
15+
static NSDictionary *mimeTypeToBadgeMap() {
16+
return @{
17+
@"application/xml": @"xml",
18+
@"text/x-c" : @"C",
19+
@"text/x-c++" : @"C++",
20+
@"text/x-shellscript" : @"shell",
21+
@"text/x-php" : @"php",
22+
@"text/x-python" : @"python",
23+
@"text/x-perl" : @"perl",
24+
@"text/x-ruby" : @"ruby"
25+
};
26+
}
27+
28+
/**
29+
* Some formats, e.g. Makefiles, have well-known names and no extension.
30+
*/
31+
static NSDictionary *filenameRegexToBadgeMap() {
32+
return @{
33+
@"Makefile" : @"make"
34+
};
35+
}
36+
37+
/**
38+
* @return the string that should be used to badge the thumbnail.
39+
*/
40+
static NSString *ThumbnailBadgeForItemWithAttributes(
41+
QLSFileAttributes *attributes) {
42+
43+
NSString *fileExtension = attributes.url.pathExtension;
44+
NSString *fileName = attributes.url.lastPathComponent;
45+
__block NSString *badge;
46+
47+
// Do we have a file extension? If so, use it as a badge if it's not too
48+
// long.
49+
if (![fileExtension isEqualToString:@""]) {
50+
badge = fileExtension;
51+
52+
// Is the file extension too long to be reasonably displayed in a
53+
// thumbnail? If so, fall back on the additional tests.
54+
55+
// FIXME: use some better test to determine an appropriate length.
56+
// FIXME: perhaps we should truncate the extension (at the end? in the
57+
// middle?) to fit as much in the thumbnail as possible.
58+
59+
if (badge.length >= 10)
60+
badge = nil;
61+
}
62+
63+
// Do we have a well-known MIME type? Note that we only do this test if we
64+
// have no file extension. file(1) might wrongly guess the MIME type, and it
65+
// would be annoying if the file extension were to say one thing and the
66+
// badge another.
67+
if (!badge && [fileExtension isEqualToString:@""]) {
68+
NSDictionary *map = mimeTypeToBadgeMap();
69+
badge = map[attributes.mimeType];
70+
}
71+
72+
// Does the filename match a known pattern? If so, use the appropriate badge.
73+
if (!badge && [fileExtension isEqualToString:@""]) {
74+
NSDictionary *map = filenameRegexToBadgeMap();
75+
76+
[map enumerateKeysAndObjectsUsingBlock:
77+
^(NSString *regex, NSString *candidateBadge, BOOL *stop) {
78+
if ([fileName rkl_isMatchedByRegex:regex]) {
79+
badge = candidateBadge;
80+
*stop = true;
81+
}
82+
}];
83+
}
84+
85+
// Do we have an executable text file? If so, assume it's a script of some
86+
// sort.
87+
if (!badge) {
88+
NSFileManager *fm = [NSFileManager new];
89+
BOOL isExecutable = [fm isExecutableFileAtPath:attributes.url.path];
90+
if (isExecutable)
91+
badge = @"script";
92+
}
93+
94+
// No other tests passed? Just badge it with "txt". I would use "text",
95+
// except that the OS X text QuickLook generator uses "txt", and we ought
96+
// to be consistent with it.
97+
if (!badge) {
98+
badge = @"txt";
99+
}
100+
101+
return [badge uppercaseString];
102+
}
103+
104+
105+
/* -----------------------------------------------------------------------------
106+
Generate a thumbnail for file
107+
108+
This function's job is to create thumbnail for designated file as fast as
109+
possible
110+
-------------------------------------------------------------------------- */
111+
OSStatus GenerateThumbnailForURL(void *thisInterface,
112+
QLThumbnailRequestRef request,
113+
CFURLRef url,
114+
CFStringRef contentTypeUTI,
115+
CFDictionaryRef options,
116+
CGSize maxSize) {
117+
@autoreleasepool {
118+
if (QLThumbnailRequestIsCancelled(request))
119+
return noErr;
120+
121+
QLSFileAttributes *magicAttributes
122+
= [QLSFileAttributes attributesForItemAtURL:(__bridge NSURL *)url];
123+
124+
if (!magicAttributes) {
125+
NSLog(@"QLStephen: Could not determine attribtues of file %@", url);
126+
return noErr;
127+
}
128+
129+
if (!magicAttributes.isTextFile) {
130+
// NSLog(@"QLStephen: I don't think %@ is a text file", url);
131+
return noErr;
132+
}
133+
134+
if (magicAttributes.fileEncoding == kCFStringEncodingInvalidId) {
135+
NSLog(@"QLStephen: Could not determine encoding of file %@", url);
136+
return noErr;
137+
}
138+
139+
NSDictionary *previewProperties = @{
140+
(NSString *)kQLPreviewPropertyStringEncodingKey : @( magicAttributes.fileEncoding )
141+
};
142+
143+
NSString *badge = ThumbnailBadgeForItemWithAttributes(magicAttributes);
144+
145+
NSDictionary *properties = @{
146+
(NSString *)kQLThumbnailPropertyExtensionKey : badge
147+
};
148+
149+
150+
QLThumbnailRequestSetThumbnailWithURLRepresentation(
151+
request,
152+
url,
153+
kUTTypePlainText,
154+
(__bridge CFDictionaryRef)previewProperties,
155+
(__bridge CFDictionaryRef)properties);
156+
157+
return noErr;
158+
}
159+
}
160+
161+
void CancelThumbnailGeneration(void* thisInterface,
162+
QLThumbnailRequestRef thumbnail) {
163+
// implement only if supported
164+
}

0 commit comments

Comments
 (0)