Skip to content

Commit 7e19f2c

Browse files
Services: Add service to finder contextual menu. (#583)
* application: services provider has been added. * application: app delegate services provider has been registered. * application: services provider notes have been added. * application: info plist service have been added. * Fix spelling mistake * application: services provider check for existing repository has been added. * application: services provider imports have been fixed. Co-authored-by: Lucas Derraugh <[email protected]>
1 parent df72dc5 commit 7e19f2c

File tree

5 files changed

+133
-0
lines changed

5 files changed

+133
-0
lines changed

GitUp/Application/AppDelegate.m

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#import <GitUpKit/XLFacilityMacros.h>
2424

2525
#import "AppDelegate.h"
26+
#import "ServicesProvider.h"
2627
#import "DocumentController.h"
2728
#import "Document.h"
2829
#import "Common.h"
@@ -220,6 +221,9 @@ - (void)applicationDidFinishLaunching:(NSNotification*)notification {
220221
// Initialize user notification center
221222
[[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self];
222223

224+
// Register finder context menu services.
225+
[NSApplication sharedApplication].servicesProvider = [ServicesProvider new];
226+
223227
// Notify user in case app was updated since last launch
224228
NSString* currentVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];
225229
NSString* lastVersion = [[NSUserDefaults standardUserDefaults] objectForKey:kUserDefaultsKey_LastVersion];

GitUp/Application/Info.plist

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,5 +52,27 @@
5252
<string>MainMenu</string>
5353
<key>NSPrincipalClass</key>
5454
<string>NSApplication</string>
55+
<key>NSServices</key>
56+
<array>
57+
<dict>
58+
<key>NSMessage</key>
59+
<string>openRepository</string>
60+
<key>NSRequiredContext</key>
61+
<dict>
62+
<key>NSTextContent</key>
63+
<string>FilePath</string>
64+
</dict>
65+
<key>NSMenuItem</key>
66+
<dict>
67+
<key>default</key>
68+
<string>Open in GitUp</string>
69+
</dict>
70+
<key>NSSendTypes</key>
71+
<array>
72+
<string>NSURLPboardType</string>
73+
<string>NSFilenamesPboardType</string>
74+
</array>
75+
</dict>
76+
</array>
5577
</dict>
5678
</plist>

GitUp/Application/ServicesProvider.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//
2+
// ServicesProvider.h
3+
// Application
4+
//
5+
// Created by Dmitry Lobanov on 17/09/2019.
6+
//
7+
8+
#import <Foundation/Foundation.h>
9+
10+
NS_ASSUME_NONNULL_BEGIN
11+
12+
@interface ServicesProvider : NSObject
13+
14+
@end
15+
16+
NS_ASSUME_NONNULL_END

GitUp/Application/ServicesProvider.m

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//
2+
// ServicesProvider.m
3+
// Application
4+
//
5+
// Created by Dmitry Lobanov on 17/09/2019.
6+
//
7+
8+
#import "ServicesProvider.h"
9+
#import <AppKit/AppKit.h>
10+
#import "AppDelegate.h"
11+
#import "Document.h"
12+
#import <GitUpKit/GitUpKit.h>
13+
14+
@interface AppDelegate (ServicesProvider)
15+
- (void)_openRepositoryWithURL:(NSURL*)url withCloneMode:(CloneMode)cloneMode windowModeID:(WindowModeID)windowModeID;
16+
@end
17+
18+
@interface ServicesProvider ()
19+
@property (weak, nonatomic, readonly) AppDelegate *appDelegate;
20+
@end
21+
22+
@implementation ServicesProvider
23+
24+
#pragma mark - Handle Errors
25+
- (void)presentError:(NSError * __autoreleasing *)error {
26+
if (error && *error) {
27+
[[NSDocumentController sharedDocumentController] presentError:*error];
28+
}
29+
}
30+
#pragma mark - Accessors
31+
- (AppDelegate *)appDelegate {
32+
return [AppDelegate sharedDelegate];
33+
}
34+
35+
#pragma mark - Check pasteboard
36+
- (BOOL)canOpenItem:(NSPasteboard *)pasteboard {
37+
return [self items:pasteboard].count > 0;
38+
}
39+
40+
- (BOOL)isValidGitRepositoryAtURL:(NSURL *)url error:(NSError * __autoreleasing *)error {
41+
GCRepository *repository = [[GCRepository alloc] initWithExistingLocalRepository:url.path error:error];
42+
return repository != nil && (error == NULL || (*error) == nil);
43+
}
44+
45+
- (NSArray <NSURL *>*)items:(NSPasteboard *)pasteboard {
46+
return [pasteboard readObjectsForClasses:@[NSURL.class] options:nil];
47+
}
48+
49+
#pragma mark - Services Provider
50+
// the minimum method which consists of 3 parameters.
51+
// 1. methodName: NSPasteboard
52+
// 2. userData: NSString
53+
// 3. error: *NSError
54+
// methodName ( first part ) will be used in .plist to advertise service.
55+
56+
// NOTE:
57+
// To debug services functionailty.
58+
// 1. Be sure that methodName ( openRepository ) is used as instance method in plist.
59+
// 2. Set correct send types in plist. ( NSURLPboardType for urls. )
60+
// 3. Open Derived data and put .app into ~/Application directory. ( Or make a link to that app ).
61+
// 4. Rename app if necessary.
62+
// 5. Use pbs utility to refresh services.
63+
// 5.1. /System/Library/CoreServices/pbs -update
64+
// 5.2. /System/Library/CoreServices/pbs -flush
65+
// 5.3. /System/Library/CoreServices/pbs -dump_cache
66+
// 6. Be sure that your .app is appearing in dump_cache output.
67+
// 7. Check finder contextual menu.
68+
- (void)openRepository:(NSPasteboard *)pasteboard userData:(NSString *)userData error:(NSError * __autoreleasing *)error {
69+
if (![self canOpenItem:pasteboard]) {
70+
return;
71+
}
72+
73+
// check that we have a directory.
74+
75+
NSURL *url = [self items:pasteboard].firstObject;
76+
if ([self isValidGitRepositoryAtURL:url error:error]) {
77+
[self.appDelegate _openRepositoryWithURL:url withCloneMode:kCloneMode_None windowModeID:NSNotFound];
78+
}
79+
else {
80+
// item is not a valid git repository.
81+
[self presentError:error];
82+
}
83+
}
84+
85+
@end

GitUp/GitUp.xcodeproj/project.pbxproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
0A01676A2330CABD0069961E /* ServicesProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A0167692330CABD0069961E /* ServicesProvider.m */; };
1011
0A0C5ACB23720BAE000D84A1 /* KeychainAccessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A0C5ACA23720BAE000D84A1 /* KeychainAccessor.m */; };
1112
0A0D211B23579888003A2B5F /* AboutWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0A0D211723579887003A2B5F /* AboutWindowController.m */; };
1213
0A2BBECB235F9B2400912B65 /* AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0A2BBEC9235F9B2400912B65 /* AboutWindowController.xib */; };
@@ -119,6 +120,8 @@
119120
/* End PBXCopyFilesBuildPhase section */
120121

121122
/* Begin PBXFileReference section */
123+
0A0167682330CABD0069961E /* ServicesProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ServicesProvider.h; sourceTree = "<group>"; };
124+
0A0167692330CABD0069961E /* ServicesProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ServicesProvider.m; sourceTree = "<group>"; };
122125
0A0C5AC923720BAE000D84A1 /* KeychainAccessor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeychainAccessor.h; sourceTree = "<group>"; };
123126
0A0C5ACA23720BAE000D84A1 /* KeychainAccessor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KeychainAccessor.m; sourceTree = "<group>"; };
124127
0A0D211723579887003A2B5F /* AboutWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AboutWindowController.m; sourceTree = "<group>"; };
@@ -311,6 +314,8 @@
311314
E2C5672C1A6D98BC00ECFE07 /* WindowController.m */,
312315
31CD50E1203E2E2800360B3A /* ToolbarItemWrapperView.h */,
313316
31CD50E2203E2E2800360B3A /* ToolbarItemWrapperView.m */,
317+
0A0167682330CABD0069961E /* ServicesProvider.h */,
318+
0A0167692330CABD0069961E /* ServicesProvider.m */,
314319
0A0D211A23579887003A2B5F /* AboutWindowController.h */,
315320
0A0D211723579887003A2B5F /* AboutWindowController.m */,
316321
0A2BBEC9235F9B2400912B65 /* AboutWindowController.xib */,
@@ -482,6 +487,7 @@
482487
isa = PBXSourcesBuildPhase;
483488
buildActionMask = 2147483647;
484489
files = (
490+
0A01676A2330CABD0069961E /* ServicesProvider.m in Sources */,
485491
E21739F71A5080DD00EC6777 /* DocumentController.m in Sources */,
486492
E2E3C9A01D771E7600AA9A62 /* GARawTracker.m in Sources */,
487493
E2C338B419F8562F00063D95 /* main.m in Sources */,

0 commit comments

Comments
 (0)