Allow freeform extension for document types in NSSavePanel - swift

I have a document-based application with 3 document types (Type A, Type B, Type C) configured as editor in the info.plist. How can I make it so that Type A will allow the user to set whatever file name they want when saving, without forcing any particular extension, while still being able to choose from the 3 different formats?
What I’ve tried:
Setting the NSSavePanel’s allowsOtherFileTypes to true in my NSDocument’s prepareSavePanel() function. This isn’t sufficient because it only works if the user enters an extension that isn’t currently known by the system (e.g. “My document.foo” will still save as “My Document.foo.typea”).
Not setting a type identifier on the document type in the info.plist. This actually worked reasonably well up until macOS 13, where it logs an error about a UTI that wasn't exported and won't offer that type in the save panel.
Setting a blank extension on the exported type in the info.plist. This almost works but if the user enters a known extension it shows a prompt like this:
You have used the extension “.txt” at the end of the name. The standard extension is “.”.
Not setting any extension on the exported type in the info.plist. This seemed to work great on macOS 13, but on macOS 12 it would show a prompt similar to the above but with “.(null)” rather than “.”.
So, without completely overriding the entire save process, I'm now out of ideas.

I had another idea which seems to be working on both macOS 12 and 13:
Set the type identifier of the document type to public.data in the info.plist.
On macOS 12 this logs a warning about not having a valid extension, but it doesn't show any confusing prompts to the user. I'm still open to other solutions though, if anyone has any.

Related

Opening the VSC settings window from code

I'm working on a Visual Studio Code extension, where some settings are required for it to work properly. Right now, in case the user has forgotten something, I'm showing a warning message indicating this, and telling them to fix this property in the settings. I would, however, like to add a button that opens the settings page of that property.
However, after looking around for over an hour, I can't seem to find any support for this in the Api, or anyone else asking this question (which I find a bit weird?). If it really doesn't exist, I'd still expect at least 1 other person asking this somewhere, but as far as I can see there's absolutely nothing.
Is it possible to open the settings window (preferably even filtering them down to only my extension's properties/the one property that has to be filled in) from code?
Thanks in advance
I found it out myself after digging through the keybinds window. You can use the following to open the settings:
vscode.commands.executeCommand("workbench.action.openSettings2");
I did not, however, find how to pass a search query into it to open a specific place in the settings.
EDIT: You can use openSettings & add the search query as an extra argument to executeCommand. For example - if your property is defined as my.extension.property in package.json, you can use this:
vscode.commands.executeCommand("workbench.action.openSettings", "my.extension.property");

manifest.json display property has invalid option of browser

The documentation seems to state that there are four options for the "display" property within a manifest.json: fullscreen, standalone, minimal-ui and browser
I decided upon 'browser' for one of my apps, but the message from Chrome (Version 76) says "Manifest 'display' property must be one of 'standalone', 'fullscreen' or 'minimal-ui'". The message also appears if I leave 'display' undefined.
Is 'browser' an obsolete option or has it just not made it into the latest Chrome version yet?
(I probably should mention that the message appears in Chrome DevTools>application>manifest).
Valid options for display are fullscreen, standalone, minimal-ui and browser according to https://developer.mozilla.org/en-US/docs/Web/Manifest/display.
In order to show the Add to Home Screen Prompt, display must be set to must be one of: fullscreen, standalone, or minimal-ui, see https://developers.google.com/web/fundamentals/app-install-banners/
browser display option is like leaving the field empty.
When you use standalone it looks like native app. When you use fullscreen there is no status bar etc. Probably you want to use standalone, because fullscreen has very specific use-case (e.g. gaming).
I finally got around to reporting it as a bug.
https://bugs.chromium.org/p/chromium/issues/detail?id=1330323
The immediate response was...
The behaviour is seen from M-85.This is is a non regression issue
hence marking it as untriaged and requesting some one from dev team to
look into the issue.

Cocoa invoke Service, do not overwrite Pasteboard

I have created a Service in Cocoa which grabs the selected Text and sends the result back to my Main App, so i can handle it there ( Couldn't find any other way to get current selection), now that the Service works and appears in the Service Menu, i tried to invoke the Service from my parent App to get current selection, after some goggling around i found this snippet:
NSPasteboard *pboard = [NSPasteboard pasteboardWithUniqueName];
[pboard declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
NSPerformService(#"PCB", pboard);
This one works as far as it triggers my Service, the Problem here is it redefines the NSPasteboard, so my service doesn't get the selected text, but a NIL Value Pasteboard which is blank, how can i prevent this?
And does someone know how to convert a .service bundle into an .app bundle that performs itself and sends the data and kills itself after finish?
thx for help
You want to get the text that is selected in another application, right? Probably in the front application, while your app is in the background.
For this to work, you'd have to have the Service be invoked by the front application. If you invoke it from your app in the background, it can't access the front app's text field that contains the selected text. Instead, it'll try to find a text field in your own app's responder chain (I believe – someone correct me if I'm wrong on this detail).
But for your code to run in the app's process, you'll have to inject it somehow, which is - out of security concerns - mostly prohibited by OS X, and especially with sandboxed apps.
There are ways to accomplish code injection, one that 1Password and other popular tools use it through an osax extension. But that's an entirely different topic.
Once you have your code running inside the other app's process, you should be able to copy the selected text (provided it's a Cocoa app) with [NSTextView writeSelectionToPasteboard:types:]. I haven't tested this myself, though, so this is just an assumption.

UIPasteboard is stubbornly persistent, no matter what I do

I am creating a application UIPasteboard with my app's identifier as a name (e.g. com.example.app.pboard) as suggested in the docs.
All the copying and pasting works, but the damn thing never goes away. I set its persistent property explicitly to NO every time I access it to copy something onto it, and I even call UIPasteboard's +removePasteboardWithName: every time my app starts.
But every time I look at it, the most recent thing I copied onto it is always there, despite app restarts.
What gives?
No idea why what you are trying isn't working, here are two guesses and a possible solution:
Removing the paste board may be expected to be executed on exit from the app, so it doesn't execute until the app is terminated or backgrounded?
Calling remove and then asking for the items may be recreating it again in the same "place" so the items still remain.
You could perhaps solve this by setting the pasteboard's items to nil when leaving or entering the app.
You can set UIPasteboard to persistent. Accord to Apple's document,
setPersistent:
A Boolean value that indicates whether the pasteboard is persistent.
When a pasteboard is persistent, it continues to exist past app terminations and across system reboots. App pasteboards that are not persistent only last until the owning (creating) app quits. The system wide general pasteboard is persistent. Named, app-specific pasteboards are not persistent.
Update: For iOS 10, UIPasteboard set persistence automatically.
Note
Starting in iOS 10, the system sets pasteboard persistence automatically. If you try to set the setPersistent: property on a pasteboard, Xcode issues a deprecation warning.
Instead of named persistent pasteboards, use shared containers, as described in the Overview section of this document.

Register for all file types (CFBundleDocumentTypes)

Programs like Drop Box, or Airsharing don't handle or edit documents but store them. In this case it would seem that they have to register as being a valid choice for any type of file. Is there a way to register your application as a handler for all files? '.*' ? Or is the only solution to register for any type of file that you can think of?
Registering for the public.data type accepts EVERYTHING. If you want specific actions for certain types of files you will need to check when it gets passed to your app. See this apple doc for the hierarchy: Apple
Edit for clarification: public.data allows for your app to accept any kind of data type. (image/text/etc..)..the very base UTI is public.item (includes public.data and public.content and public.archive). As i'm not sure what you are really trying to do, it could be that you want the other stuff as well.