What is the best way to format a localized string in AppleScript? - applescript

When a script is saved as a bundle, it can use the localized string command to find the appropriate string, e.g. in Contents/Resources/English.lproj/Localizable.strings. If this is a format string, what is the best way to fill in the placeholders? In other words, what is the AppleScript equivalent of +[NSString stringWithFormat:]?
One idea I had was to use do shell script with printf(1). Is there a better way?

Since OS X 10.10, it’s been possible for any AppleScript script to use Objective-C. There are a few ways to call Objective-C methods from within AppleScript, as detailed in this translation guide. An Objective-C developer like me would gravitate toward this syntax, which interpolates the method's parameters with their values:
use framework "Foundation"
tell the current application's NSWorkspace's sharedWorkspace to openFile:"/Users/me/Desktop/filter.png" withApplication:"Preview"
Result:
true
+[NSString stringWithFormat:] is a tricky case. It takes a vararg list as its first parameter, so you need some way to force both the format string and its arguments into the same method parameter. The following results in an error, because AppleScript ends up passing a single NSArray into the parameter that expects, conceptually, a C array of NSStrings:
use framework "Foundation"
the current application's NSString's stringWithFormat:{"%lu documents", 8}
Result:
error "-[__NSArrayM length]: unrecognized selector sent to instance 0x7fd8d59f3bf0" number -10000
Instead, you have to use an alternative syntax that looks more like an AppleScript handler call than an Objective-C message. You also need to coerce the return value (an NSString object) into a text:
use framework "Foundation"
the current application's NSString's stringWithFormat_("%lu documents", 8) as text
Result:
"2087 documents"
The “with parameters” syntax that #nlanza mentions points to the fact that AppleScript is using something akin to NSInvocation under the hood. In Objective-C, NSInvocation allows you to send a message to an object, along with an array of parameter values, without necessarily matching each value to a particular parameter. (See this article for some examples of using NSInvocation directly.)

As ugly as it is, calling out to printf(1) is the common solution.
A cleaner, though somewhat more complex, solution is to use AppleScript Studio, which allows you to call into Objective-C objects/classes from your AppleScript code with the call method syntax documented here.
With that, you'd be able to use something like this:
call method "stringWithFormat:" of class "NSString" with parameters {formatString, arguments}
The downside of this, of course, is that you need to write an AppleScript Studio app instead of just writing a simple script. You do get a good bit more flexibility in general with Studio apps, though, so it's not all together a terrible route to go.

Related

How can you tell what namespace constants have been put in in swift?

In swift, a lot of cocoa and framework constants have been put into namespaces. For example, NSCompositeSourceOver is now NSCompositingOperation.CompositeSourceOver.
This is generally a good thing. However, sometimes it's hard to work out where Apple have put certain constants. For example, I currently need kCGDesktopWindowLevel, and I can't find the damn thing. (There is kCGDesktopWindowLevelKey, but that's not the same thing.)
Is there a reference for this, or some set of files I can grep?
In the original CGWindowLevel.h, kCGDesktopWindowLevel is a macro defined to CGWindowLevelForKey(kCGDesktopWindowLevelKey). The macro was not imported, but the latter works fine in Swift as long as you add some type conversions: Int(CGWindowLevelForKey(CGWindowLevelKey(kCGDesktopWindowLevelKey))). (You might wish to file a bug since these type conversions are required.) You can see some of these things by ⌘-clicking on the CGWindowLevelForKey function, or using :print_module CoreGraphics from swift -integrated-repl.

How to adjust the Summary Format to expose a float** as a float[][]?

I'm using XCode to debug some code. Specifically, the code that I'm debugging exposes a float[][] as float**. I am unable to change this syntax, but I'm not certain it would help anyway.
After including a relevant breakpoint, I want to view the contents of the array in the Variables view of the debugger?
When I double-click on the variable in the list of Autos, I see that I can add a Summary Format which seems deceivingly like it might help, but for the life of me, I can't figure out how to use it!
In conclusion, how do I use the Variables View to see the contents of my array of arrays of this primitive type without resorting to typing commands directly to GDB (which, I believe, can also perform this function)?

Partial completions in Xcode?

Is it possible to have partial completions in Xcode? By that I mean if we were calling a method on a string
eg.
[string <some method here method>]
on XCode, currently if you type
[string
and hit escape, you'll see suggestions for methods you can call on the object. If I wanted to find the method which checks equality isEqualToString, I only get the suggestion if I start typing isE..., but is there a way code completion will still give isEqualToString as a suggestion if I type "equal" ie. it matches against any part of a method?
Thanks!
I'm sorry but there is no way, there aren't really any ways to change the way Xcode handles the code completion, all you can do is turn it on or off. Your best bet may be a feature request to Apple.

Code completion for multi-parameter method names in Xcode 4

In Xcode4, I'm finding that I can't get code completion to readily narrow for multi-parameter method names where the first part is common. For example, consider the following methods from UITableViewDelegate:
- tableView:viewForHeaderInSection:
- tableView:heightForHeaderInSection:
- tableView:accessoryTypeForRowWithIndexPath:
...
The list goes on; there are quite a few methods that start tableView. If I type "tableView", the list is long and not quickly navigated. If I type "tableView:", code completion is exited as soon as I type the colon (:). If I type a run-on such as "tableViewview", completion also exits, presumably as it no longer literally matches the first method name part.
Is there some way to complete via the keyboard on such a list without resorting to either mousing around or clattering out a random number of arrow key hits to navigate the long list? I'm having a hard time believing that code completion for multi-parameter Objective-C methods is so limited, but neither experimentation nor documentation have proved illuminating thus far.
Update for clarification:
Above I'm referring to completion of a method declaration (e.g. in a .m file), not of a method call. For method calls, Xcode 4.x does completion for each method parameter part independently; this works great. The problem above only applys to declarations, generally when starting to write a new method implementation in a .m file.
It does seems that the behavior you expect is (unfortunately) not implemented in Xcode. However, I've found a partial solution: code completion works when you specify the complete first part of the multi-parameter method, i.e. if you type this (with space at the end)
- tableView:(UITableView *)tableView
and press ESCAPE key then the code completion dialog will appear and you will be able to keep typing the rest of the method name.
You are probably wondering:
"Oh boy, do I really have to type in this long preamble just to get
my code completion?"
Code snippets to the rescue! You just have to type the preamble once and convert it into snippet. I found it's best to configure it the following way, don't forget to add space at the end of code part, it will make things easier.
How should you use the thing you've just created? In your .m file start typing tabl and Xcode will let you autocomplete the snippet for you. Once the preamble is placed press ESC to reveal the auto-completion list.
This solution is not very robust, since you have to create a snippet for every multi-part method you want to use, but it does save some time and there aren't that many multi-part method names that share the same prefix.
I'm annoyed by this problem for quite a long time. Now I can verify that there is no way to do even in the newest Xcode 5, I submitted a bug report:
Multi-parameter method declaration completion in Xcode
Please dup it if you also want it.
Oh sorry, it does not work that way I mentioned with protocol stubs like you wanted in your update.
I use Accessorizer for that, an app in the mac app store to fully implement the declaration of your delegate/protocol methods you want to implement. Hope that help a little bit.
Old post:
I use Tab ⇥ for this.
Example I often have:
You want one of many init methods in the code completion.
Then you don't want to scroll down or use to many keystrokes to get to the right method.
Hit i > hit Tab ⇥ > init is completed.
Hit Escape ⎋ and then w and then again Tab ⇥ for all these initWith methods.
You can even use Tab ⇥ / Escape ⎋ after the first parameter, when there is more than the method with only one parameter.
In your case hit t > Tab ⇥ > Escape ⎋ > a and Return ↩, there you got your third method.
You can also jump to the previous code completion argument with Shift ⇧ + Tab ⇥.

How to see multi-byte strings in Xcode

Is it possible to see strings that use 16 bits chars in Xcode debugger? I use a custom string class, not NSString. The strings are NULL terminated. The only way I can see the strings is if I see them as memory, but they are hard to read.
Thank you!
You'll need to write a data formatter bundle -- just writing the data formatter expressions inside the debugger isn't enough. Viewing strings in the Xcode debugger is a black art. Even once you've written the data formatter bundle, be prepared for them not to work at least 50% of the time. We've been fighting this issue for about 5 years now. Most of the time the debugger will tell you the variable is no longer in scope when it really is, and you'll still need to drill down into the members to view the raw memory anyway.
Something that may make it easier (I haven't tried this) is to write a method in the class that returns an NSString and then you may be able to get the data formatter expressions to display something useful.
Use Data Formatting in the XCode debugger
For custom classes I always found it helpful to implement description and debugDescription methods. Maybe this approach will be sufficient in your case too.

Resources