Skip to content
This repository

Execute commands consistently #699

Merged
merged 6 commits into from about 2 years ago

2 participants

Rob McBroom Patrick Robertson
Rob McBroom
Owner

This contains fixes for #623 and #670.

Long story short, you couldn’t have a trigger for something like “Finder Selection → Compress”. Now you can.

The problem was that there were different places that could execute an action and they didn’t all behave the same way. Rather than duplicate code, I’ve attempted to move things around so the same code is used no matter how an action is run.

I initially didn’t like QSommand doing so much with the interface controller, but I’ve talked myself into it. I can go into more detail if anyone is similarly uneasy.

I’ve tried executing things every way I can think of (using the interface, triggers, droplets, encapsulated commands, commands saved to disk, commands run after delay) and they all seem to function correctly.

added some commits January 31, 2012
Rob McBroom group similar functionality together so it can be modified more easily
`executePartialCommand:` and `performOnDirectObject:indirectObject:` were each being called in two different places
b4fea8d
Rob McBroom add a missing method declaration cd0e212
Rob McBroom handle actions that return results when commands are executed
Previously, these actions would only work correctly if run by the user from the interface. Now they should work in other contexts.

fixes #623
8e6113a
Rob McBroom remove objects selected by the comma trick for triggers that ask for …
…input - fixes #670
f2d98df
Rob McBroom quiet an NSLog() when not debugging ce3fe60
Patrick Robertson
Owner

Funny I should only stumble upon this now after years of QS use, just as you've open this...

Seems like #670 also applies to objects grabbed with ⌘⎋. Would it be possible to fix that? Should be pretty easy I imagine. The ⌘⎋ command runs the receiveObject method in QSController.m. I came across it when fixing the getSelectionJump pull #643

Rob McBroom
Owner

Seems like #670 also applies to objects grabbed with ⌘⎋. Would it be possible to fix that?

Same goes for things opened with the qs command-line tool. I’ll see if I can fix them both.

Rob McBroom skurfer referenced this pull request in quicksilver/CommandLineTool-qsplugin February 20, 2012
Merged

General updates #2

Rob McBroom
Owner

I’ll see if I can fix them both.

Done. :-)

Patrick Robertson
Owner

Oooh the command line tool. Never actually used that. Any good?

This all looks good. i'll keep playing

Rob McBroom
Owner

Oooh the command line tool. Never actually used that. Any good?

Yeah, I forget it’s there most of the time, but I’ve rediscovered it in the past couple of weeks. It’s pretty cool. One time I love having it is when I’m in a plug-in’s directory doing git stuff and I want to open the Xcode project. There are lots of ways to do it, but the fastest I’ve found is to just run qs ., then hit / to go into the folder, at which point it’s pretty easy to find the project file.

Patrick Robertson

You can put this line and the next into one, to save doing the test twice, but some thing it's more difficult to read:

if ([actionObject isKindOfClass:[QSRankedObject class]] && QSAction * rankedAction = [(QSRankedObject *)actionObject object]) {

You might have to declare rankedAction before though. I really don't think this would affect the performance of QS though!

Patrick Robertson
Owner

I see the problem with the current command line tool. I'm assuming your change over there fixes it.

Other than that, everything looks good.

P.S. I use a different method to you for getting e.g. the current folder/file/whatever in terminal/whatever.
With the User Interface Access module install, I have a trigger for Current DocumentSelect in Command Window.

I think this is probably my most used thing in Quicksilver since neurolepsy introduced it a year or so ago. You can use it on practically anything: Safari URLs, Terminal Windows, non-cocoa apps (MS Word etc.), Preview...

Patrick Robertson pjrobertson merged commit e6ae4d6 into from February 23, 2012
Patrick Robertson pjrobertson closed this February 23, 2012
Rob McBroom
Owner

I see the problem with the current command line tool. I'm assuming your change over there fixes it.

Yep.

You can use it on practically anything: Safari URLs, Terminal Windows, non-cocoa apps (MS Word etc.), Preview...

Wow. I knew it was good, but I didn’t know it worked on Terminal’s current directory. I wonder if it’s only because we have it in the title bar? Anyway, cool.

BTW, my favorite new trigger (now that this is merged): Finder Selection → Get Path (scoped to Finder only)

Patrick Robertson
Owner
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 6 unique commits by 1 author.

Jan 31, 2012
Rob McBroom group similar functionality together so it can be modified more easily
`executePartialCommand:` and `performOnDirectObject:indirectObject:` were each being called in two different places
b4fea8d
Rob McBroom add a missing method declaration cd0e212
Rob McBroom handle actions that return results when commands are executed
Previously, these actions would only work correctly if run by the user from the interface. Now they should work in other contexts.

fixes #623
8e6113a
Rob McBroom remove objects selected by the comma trick for triggers that ask for …
…input - fixes #670
f2d98df
Feb 03, 2012
Rob McBroom quiet an NSLog() when not debugging ce3fe60
Feb 20, 2012
Rob McBroom remove objects selected by the comma trick when getting new object(s)…
… from services
b59feb1
This page is out of date. Refresh to see the latest.
1  Quicksilver/Code-App/QSController.m
@@ -500,6 +500,7 @@ - (BOOL)readSelectionFromPasteboard:(NSPasteboard *)pboard {
500 500
 }
501 501
 
502 502
 - (void)receiveObject:(QSObject *)object {
  503
+	[[self interfaceController] clearObjectView:[[self interfaceController] dSelector]];
503 504
 	[[self interfaceController] selectObject:object];
504 505
     [[self interfaceController] actionActivate:nil];
505 506
 }
68  Quicksilver/Code-QuickStepCore/QSCommand.m
@@ -102,7 +102,9 @@ - (QSObject *)saveCommand:(QSObject *)dObject toPath:(QSObject *)iObject {
102 102
 	id commandObject = [(QSCommand*)dObject dObject];
103 103
 	BOOL asDroplet = [[commandObject identifier] isEqualToString:@"QSDropletItemProxy"];
104 104
     
  105
+#ifdef DEBUG
105 106
 	NSLog(@"droplet %d", asDroplet);
  107
+#endif
106 108
 	NSString *destination = [[[[iObject singleFilePath] stringByAppendingPathComponent:[dObject name]] stringByAppendingPathExtension:asDroplet?@"app":@"qscommand"] firstUnusedFilePath];
107 109
 	if (asDroplet) {
108 110
 		[[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] pathForResource:@"QSDroplet" ofType:@"app"] toPath:destination error:nil];
@@ -398,34 +400,58 @@ - (QSObject *)execute {
398 400
 #ifdef DEBUG
399 401
 	if (VERBOSE) NSLog(@"Execute Command: %@", self);
400 402
 #endif
  403
+	QSInterfaceController *controller = [(QSController *)[NSApp delegate] interfaceController];
401 404
 	int argumentCount = [(QSAction *)actionObject argumentCount];
402  
-	if (argumentCount<2) {
403  
-		return [actionObject performOnDirectObject:directObject indirectObject:indirectObject];
404  
-	} else if (argumentCount == 2) {
405  
-		if ([indirectObject objectForType:QSTextProxyType]) {
406  
-			[[(QSController *)[NSApp delegate] interfaceController] executePartialCommand:[NSArray arrayWithObjects:directObject, actionObject, indirectObject, nil]];
407  
-		} else if (indirectObject) {
408  
-			return [aObject performOnDirectObject:directObject indirectObject:indirectObject];
409  
-		} else {
410  
-			if (!indirectObject) {
411  
-				NSString *selectClass = [[NSUserDefaults standardUserDefaults] stringForKey:@"QSUnidentifiedObjectSelector"];
412  
-				id handler = [QSReg getClassInstance:selectClass];
413  
-				NSLog(@"handler %@ %@", selectClass, handler);
414  
-				if (handler && [handler respondsToSelector:@selector(completeAndExecuteCommand:)]) {
415  
-					[handler completeAndExecuteCommand:self];
416  
-					return nil;
  405
+	if (argumentCount == 2 && (!indirectObject || [[indirectObject primaryType] isEqualToString:QSTextProxyType])) {
  406
+		// indirect object required, but is either missing or asking for text input
  407
+		if (!indirectObject) {
  408
+			// attempt to use the Missing Object Selector
  409
+			NSString *selectClass = [[NSUserDefaults standardUserDefaults] stringForKey:@"QSUnidentifiedObjectSelector"];
  410
+			id handler = [QSReg getClassInstance:selectClass];
  411
+#ifdef DEBUG
  412
+			NSLog(@"handler %@ %@", selectClass, handler);
  413
+#endif
  414
+			if (handler && [handler respondsToSelector:@selector(completeAndExecuteCommand:)]) {
  415
+				[handler completeAndExecuteCommand:self];
  416
+				return nil;
  417
+			}
  418
+		}
  419
+		// use Quicksilver's interface to get the missing object
  420
+		[controller executePartialCommand:[NSArray arrayWithObjects:directObject, actionObject, indirectObject, nil]];
  421
+	} else {
  422
+		// indirect object is either present, or unnecessary - run the action
  423
+		QSObject *returnValue = [actionObject performOnDirectObject:directObject indirectObject:indirectObject];
  424
+		if (returnValue) {
  425
+			// if the action returns something, wipe out the first pane
  426
+			/* (The main object would get replaced anyway. This is only done to
  427
+			 remove objects selected by the comma trick before the action was run.) */
  428
+			[controller clearObjectView:[controller dSelector]];
  429
+			// put the result in the first pane and in the results list
  430
+			[[controller dSelector] performSelectorOnMainThread:@selector(setObjectValue:) withObject:returnValue waitUntilDone:YES];
  431
+			if (actionObject) {
  432
+				if ([actionObject isKindOfClass:[QSRankedObject class]] && [(QSRankedObject *)actionObject object]) {
  433
+					QSAction* rankedAction = [(QSRankedObject *)actionObject object];
  434
+					if (rankedAction != actionObject) {
  435
+						[rankedAction retain];
  436
+						[actionObject release];
  437
+						actionObject = rankedAction;
  438
+					}
  439
+				}
  440
+				// bring the interface back to show the result
  441
+				if ([actionObject displaysResult]) {
  442
+					// send focus to the second pane if the user has set the preference
  443
+					if ([[NSUserDefaults standardUserDefaults] boolForKey:@"QSJumpToActionOnResult"]) {
  444
+						[controller actionActivate:nil];
  445
+					}
  446
+					[controller showMainWindow:controller];
417 447
 				}
418 448
 			}
419  
-			[[(QSController *)[NSApp delegate] interfaceController] executePartialCommand:[NSArray arrayWithObjects:directObject, actionObject, indirectObject, nil]];
  449
+			return returnValue;
420 450
 		}
421  
-		return nil;
422 451
 	}
423 452
 	return nil;
424  
-//		NS_DURING
425  
-//	NS_HANDLER
426  
-//		;
427  
-//	NS_ENDHANDLER
428 453
 }
  454
+
429 455
 - (void)executeFromMenu:(id)sender {
430 456
 	//NSLog(@"sender %@", NSStringFromClass([sender class]) );
431 457
 	QSObject *object = [self execute];
1  Quicksilver/Code-QuickStepInterface/QSInterfaceController.h
@@ -96,4 +96,5 @@
96 96
 - (BOOL)preview;
97 97
 - (void)setPreview:(BOOL)flag;
98 98
 
  99
+- (void)clearObjectView:(QSSearchObjectView *)view;
99 100
 @end
27  Quicksilver/Code-QuickStepInterface/QSInterfaceController.m
@@ -515,29 +515,8 @@ - (void)executeCommandThreaded {
515 515
         dObject = [(QSRankedObject*)dObject object];
516 516
     if( [iObject isKindOfClass:[QSRankedObject class]] )
517 517
         iObject = [(QSRankedObject*)iObject object];
518  
-	QSObject *returnValue = [action performOnDirectObject:dObject indirectObject:iObject];
519  
-	if (returnValue) {
520  
-        // if the action returns something, wipe out the first pane
521  
-        /* (The main object would get replaced anyway. This is only done to
522  
-           remove objects selected by the comma trick before the action was run.) */
523  
-        [self clearObjectView:dSelector];
524  
-        // put the result in the first pane and in the results list
525  
-        [dSelector performSelectorOnMainThread:@selector(setObjectValue:) withObject:returnValue waitUntilDone:YES];
526  
-		if (action) {
527  
-            if ([action isKindOfClass:[QSRankedObject class]] && [(QSRankedObject *)action object]) {
528  
-                QSAction* rankedAction = [(QSRankedObject *)action object];
529  
-                if (rankedAction != action) {
530  
-                    [rankedAction retain];
531  
-                    [action release];
532  
-                    action = rankedAction;
533  
-                }
534  
-            }
535  
-            // bring the interface back to show the result
536  
-            if ([action displaysResult]) {
537  
-                [self actionActivate:nil];
538  
-            }
539  
-        }
540  
-	}
  518
+	QSCommand *command = [QSCommand commandWithDirectObject:dObject actionObject:action indirectObject:iObject];
  519
+	[command execute];
541 520
 #ifdef DEBUG
542 521
 	if (VERBOSE) NSLog(@"Command executed (%dms) ", (int)(-[startDate timeIntervalSinceNow] *1000));
543 522
 #endif
@@ -546,6 +525,8 @@ - (void)executeCommandThreaded {
546 525
 }
547 526
 
548 527
 - (void)executePartialCommand:(NSArray *)array {
  528
+	// remove objects previously selected by the comma trick
  529
+	[self clearObjectView:dSelector];
549 530
 	[dSelector setObjectValue:[array objectAtIndex:0]];
550 531
 	if ([array count] == 1) {
551 532
 		[self updateActionsNow];
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.