ChimeHQ / LanguageClient

Language Server Protocol (LSP) client for Swift
BSD 3-Clause "New" or "Revised" License
93 stars 10 forks source link

Shall I contribute support for user script servers? #7

Closed mchakravarty closed 10 months ago

mchakravarty commented 11 months ago

I wrote a variant of localProcessChannel that allows running LSP servers via a script in the user script directory of an app. This is useful if you want the functionality of localProcessChannel for a sandboxed app (that can be distributed via the App Store).

If you think that this is useful functionality that you are willing to include in the package, I'll send a PR.

mattmassicotte commented 11 months ago

This sounds really interesting! And I'd love the contribution! But, I do not understand the mechanism. Don't all child processes inherent the parent's sandbox?

I've experimented with a few different ways of handling sandboxing, including with this. And while that approach works, it does not pass app review without special permissions that only a few apps will ever get.

mchakravarty commented 11 months ago

A sandboxed app can execute scripts in the application scripts directory using the NSUserUnixTask class — these scripts will execute outside of the sandbox. A sandboxed app can read, but not write to that directory.

By default, this directory is empty and, as the app cannot write to it, it cannot escape its sandbox entirely on its own. However, an app can ask the user to install something in that location (typically a script) that allows it, then, to access other system functionality, such as the command line dev toolchain.

This approach is fine by Apple. I have got an app using it for many years in the App Store: https://apps.apple.com/nl/app/haskell/id841285201?mt=12

Other apps, like BBEdit, use it, too.

However, there are some caveats. The app needs to be useful without the extra user script functionality and you cannot advertise this functionality strongly in the App Store description. For example, BBEdit just states that it supports user script functionality and my app's description says that you can extend it and points to the app website for further details.

You also need to be careful how you expose the functionality to download user scripts in your app's UI. In my case, I have got the script plus extra executables in an installer package on my website. In the first version that I submitted, when the user clicked a particular button, the app directly downloaded this installer. App review didn't like that. I had to change my app so that the button takes you to the website, where you need to click a download link on the website to get the installer.

Does that clarify my proposal?

mattmassicotte commented 11 months ago

Ok wow this is kind of mind-blowing. I had no idea this functionality existed. And, I've even been in touch with the author of BBEdit about these kinds of things.

This is incredible, and I would greatly appreciate the contribution!

mchakravarty commented 11 months ago

Great — glad to hear that! I'll prepare a PR in the next days.

mchakravarty commented 10 months ago

Here you go: https://github.com/ChimeHQ/LanguageClient/pull/8

I tried to follow your style, but I am of course happy to change things around if you have got any suggestions.

To use a Swift language server, I am, e.g., using a script with the following contents:

#!/bin/sh

exec sourcekit-lsp "$@"

I put it into ~/Library/Application\ Scripts/<app-bundle-id>/swift-language-server-runner and pass "swift-language-server-runner" as the first argument to DataChannel.userScriptChannel(scriptPath:arguments:terminationHandler:).

mattmassicotte commented 10 months ago

Ok, this is really fantastic! Thank you!!

mchakravarty commented 10 months ago

Well, thank you for writing this package (and LanguageServerProtocol) in the first place!

mattmassicotte commented 10 months ago

I’m so happy you find it useful! Please let me know about any features/bugs you find along the way.