SuperCollider VSCode / Language Server Protocol support

This is an easy fix, I’m setting the log level from the environment:
Log('LanguageServer.quark').level = settings[\logLevel];
but not converting to a Symbol first. If you do:

Log('LanguageServer.quark').level = \debug;

at the beginning of your startup, it should fix for now. I’ll push a proper fix this evening.

Oops, sorry, I was wrong - I am converting to a Symbol. Possibly you are setting an incorrect log level i your vscode settings, or possibly I’m somehow sending a blank/wrong value. Either way, I’ll fix - but the interim solution is to set in your startup or make sure your VSCode settings have a level from Log.levels

1 Like

I wanted to add a post-mortem on teaching SC using Visual Studio Code as the class IDE. I did this during the spring semester at Peabody and it went far better than I expected.

My main reason for teaching with VSCode is that I wanted to show students how learning SC is part of a larger goal of techno-fluency. What I see in the younger students is a desire to be part of technology in general and music-technology in particular. Coming from DAWs, they want to make VST plugins. It is what they know. They also have maybe programmed in python or javascript and want to learn c++ or rust. Knowing that they can write all of those languages in VSCode and seeing that SC works in VSCode opens their mind to learning SC and pushes them to work harder at it. I saw this first hand in my class this term. The “buy-in” was palpable.

So, though I fully understand the desire by others to avoid the dark side, I do hope this community continues to support this LSP quark. I actually think our continued relevancy/survival depends on it.

Sam

4 Likes

I’ve got a couple small but interesting quark updates. I’ll post them as I can clean them up, but the first is a small but useful 1.0.4 to the Require.quark has more granular caching, and an easier way to require multiple files.

Formerly, files evaluated by Require were only evaluated once per code execution (e.g. hitting Cmd+Enter), and would otherwise be cached. This is required so that, in a tree of files requiring each other, a file is only executed once even if 5 other files Require it. I’ve added more specific cache keys - \serverBoot, \serverTree, \cmdPeriod, \content, \evaluate, \never - that can be specified to control whena. specific file needs to be re-evaluated.

For example, suppose you have a file that set up some buffers: these will be destroyed when the server is rebooted, so you’ll want to re-execute this ONLY after a server boot. You can specify this by calling Require.cache(\serverBoot) anywhere in your file:

(  // buffers.scd
Require.cache(\serverBoot);
(
  bufferA: Buffer.read(...),
  bufferB: Buffer.read(...),
  bufferC: Buffer.read(...),
)
)

// elsewhere....
Require.with("buffers") {
  |buffers|
  buffers.bufferA.play;
}

The latter will only be executed ONCE and cached thereafter - but the cache is reset if the server is rebooted. Note that it does not automatically re-evaluate your file, it only allows it to be re-evaluated if you run code that requires it.

The second feature is a better way of requiring multiple files, using the with method:

Require.with("fileA", "fileB") {
  |a, b|
  a.postln; b.postln;
}

This is equivalent to doing e.g. var a = Require("fileA"), though the syntax is a bit more clear. I’m working toward allowing require to be async (if they contain e.g. lots of buffer loading) - in the long run, these requires would happen in parallel, which should improve the speed of loading complex projects. But, for now, theyre synchronous for various reasons related to complexity :slight_smile:

thanks for the reaction and the possible fix!
I managed to get it running by setting log levels in the initclass file (Startup did not wirk because it hangs in initfile)

It seems that I did not set the Supercollider: Language Server Log Level to anything which resulted in the mentioned error. Now that I put it to error, everything works as expected :slight_smile:

I switched this to a list you can pick from rather than an open text field, and also made the Log class handle failure cases a bit better. I’ll push those things soon, but I’m glad the fix was easy.

1 Like

Hello :slight_smile:

I noticed in VSCode that the SuperCollider binding starts in workspaces that I do not want it to start, probably because I accidentally pressed <cmd>-. at some point and this started the server (which is now somehow saved in SCCode preferences).
Is there any way around this behaviour and would it be possible to add a SuperCollider: stop sclang command for those accidents?

thanks for reading!

I think it’s probably a mistake that the cmd+period keybinding doesn’t have "when": "editorLangId == 'supercollider'" - but I’m not sure this would cause your problem?

Maybe I can sketch what the current intended behavior is (based on what I know about vscode extensions) - let me know if you’re seeing something different than this behavior NOW, and if there’s a change to the behavior that would be an improvement? I’m very open to workflow improvements here, I do feel some rough edges for myself and ofc there are lots of different ways of working that probably also need improvement.

  • The SuperCollider extension will be activated the first time you open an sc/scd file. It will stay alive for the lifetime of the workspace at that point.
  • You can explicitly disable the extension as a workspace setting (for e.g. a project with sc files that you don’t want to run).
  • I don’t THINK that disabling the extension in your workspace will actively unload it (and kill the interpreter), but I haven’t tested this.

IMO the best way to implement what you’re describing would be to simply make sure that disabling the extension for a workspace will immediately kills the interpreter - this lines up with existing vscode functionality and doesn’t require an “extra” layer of enable/disable state on top, which could get confusing But, I don’t know how vscode is supposed to work in this regard, nor whether this is working currently (my guess is no?)

Thanks for looking into this!

AFAICS this is indeed the behaviour that triggers it, yes.

Sounds good to me, this would require that SC will not start, especially not accidentally from files other than .sc(d).

A separate use case we might want to think about is editing SC files without wanting to evaluate anything… like, a large workspace (my obsidian vault) that contains sc files…
But this is optional for sure…

It indeed does not kill the server, even more, it seems that despite disabling it for a workspace, it still comes up when re-loading the workspace (or restarting VSCode).

this does not work atm with the SuperCollider extension, no.

kk I’ll take a look.

I guess we could have an option to never launch the language server - the result here would be that you would get syntax highlighting but all other functionality would be disabled? I can imagine some edge cases where this would be useful, I’ll consider adding an option like this if its simple.

In terms of more dynamic launching/killing/disabling the interpreter in a session: tbh there are a bunch of very subtle bugs / hiccups now with very ordinary sclang workflows like recompiling or recovering from crashes. These are a really high priority and tricky to solve - adding more complexity with extra options would only come after some of these other issues are solved. But, I would be very happy if anyone that had time and some deeper typescript skills wanted to look at some of these interpreter launch issues and try out some improvements.

1 Like

Hey there, I’m currently setting this up on macOS and I can’t see a way to load the startup.scd file as usual like with scIDE. Any clues? thanks

1 Like

Are you saying everything else works, but it doesn’t load the startup.scd? Or is it not working and not loading startup.scd?

The former, I have the vscode extension set up and working, but the startup.scd file doesn’t seem to get called when I run s.boot or the ‘boot server’ palette command. Have tried changing it to just “test”.postln; but I get no output in the console.

I also can no longer boot the server on regular supercollider app (not sure if related), so I can’t compare between the two.

would love some help with this if anyone has any ideas!

Well, startup.scd doesn’t get called when you boot the server, so that could be it. It it gets called when you start sclang. So, when sclang starts up in the output window or when you recompile the class library or when you open a new VSCode window with an scd file in it.

Good point, regardless the file doesn’t get called on starting/restarting sclang. Are there any other settings I need to change or something?

Console output after compile and starting sclang:

compile done
localhost : setting clientID to 0.
internal : setting clientID to 0.
MP3.lamepath automatically set to /opt/homebrew/bin/lame
WARNING: 'oggdec' executable not found. Please modify the MP3:oggdecpath class variable.
Class tree inited in 0.02 seconds
WARNING: Extension in '/Users/aelazary/Library/Application Support/SuperCollider/downloaded-quarks/LanguageServer/Providers/InitializeProvider.sc' overwrites Main:startup in main class library.
WARNING: Extension in '/Users/aelazary/Library/Application Support/SuperCollider/downloaded-quarks/LanguageServer/Providers/InitializeProvider.sc' overwrites Platform:startupFiles in main class library.
WARNING: Extension in '/Users/aelazary/Library/Application Support/SuperCollider/downloaded-quarks/LanguageServer/SystemOverrides/extServer.sc' overwrites Meta_Server:fromName in main class library.
WARNING: Extension in '/Users/aelazary/Library/Application Support/SuperCollider/downloaded-quarks/LanguageServer/SystemOverrides/extServer.sc' overwrites Server:addr_ in main class library.
Intentional overwrites must be put in a 'SystemOverwrites' subfolder.


*** Welcome to SuperCollider 3.14.0-dev. *** For help type cmd-d.
***LSP READY***
[LANGUAGESERVER.QUARK] suggestedServerPortRange: [57630, 57640]
Using default server port: 57630 (allocated range: 57630-57639)
SCDoc: Indexing help-files...
SCDoc: Indexed 2816 documents in 0.47 seconds
Deferred(465303816)

And my startup, which should boot the server and load the synthdefs I use (idk if this is kosher usage but it worked fine on scIDE):

(
//server options
s.options.blockSize = 4;
s.options.hardwareBufferSize = 2048;
s.options.memSize = 8192 * 16;
s.options.numWireBufs = 8192*2048;

//remember to change clock
t = TempoClock.new(160/60).permanent_(true).schedAbs(0, {t.beatsPerBar_(4)});

s.waitForBoot {
	var startupPath = "/Users/aelazary/sc/music/startup";
	var instrumentsPath = startupPath ++ "/instruments";

	(startupPath ++ "/noiseFuncs.scd").load;
	(startupPath ++ "/patternFuncs.scd").load;
	(startupPath ++ "/flucomaFuncs.scd").load;

	(startupPath ++ "/FX.scd").load;
	(startupPath ++ "/spectral.scd").load;

	(instrumentsPath ++ "/droneSynths.scd").load;
	(instrumentsPath ++ "/fmSynths.scd").load;
	(instrumentsPath ++ "/microsoundSynths.scd").load;
	(instrumentsPath ++ "/percSynths.scd").load;
	(instrumentsPath ++ "/physmodSynths.scd").load;
	(instrumentsPath ++ "/slicerSynths.scd").load;
};
)

I really have no idea, but those Warnings say that

InitializeProvider.sc' overwrites Platform:startupFiles in main class library

That doesn’t look right. Did you update the Language Server Quark? The current version doesn’t have anything to do with startup.

Sam

Hmm - in the latest development version of the VSCode plugin / language server, there are two new options: useGlobalStartupFile and useWorkspaceStartupFile. Both should default to true, but it’s worth checking these first in the VSCode settings to see what their state is.

The first (useGlobalStartupFile) causes the “global” startup.scd file to be loaded, the one that I think @asher is expecting but is maybe not being loaded? The second will also load a file named startup.scd if it’s present at the root level of your VSCode workspace - this enables project-specific startup files.

It’s POSSIBLE that if you’ve updates the LanguageServer quark but NOT the vscode plugin, it could disrupt normal startup file loading - this is a good thing for me to check, I’ll see if I can protect against this kind of version mismatch in the future.

But for now - @asher, can you verify that useGlobalStartupFile is enabled in VSCode?

And, a general feature discussion:

In the newest develop versions of the LSP/VSCode plugin, there are several settings that make it easier to have project-specific configurations:

  • Supercollider › Sclang: Conf Yaml
    You can manually specify an sclang_conf.yaml file (the file that, among other things, specifies your include directories). You can set this globally if you want to use a different conf file (e.g. one that you keep in a git repository rather than an app support directory) - or, you can set this at the workspace level if you want a specific workspace to use a specific conf file.
  • Supercollider › Sclang: Load Workspace Conf Yaml
    If a file named sclang_conf.yaml is present at the root of your current workspace, use this instead of the global yaml file. This overrides the previous path, which is considered “global” for the purposes of the vscode plugin.
  • Supercollider › Sclang: Use Global Startup File / Supercollider › Sclang: Use Workspace Startup File:
    The global startup file is the standard startup.scd file. Enabling a workspace startup file will load a startup.scd in your local workspace. If both options are enabled, both startup files will be loaded (global first). This is useful if you have e.g. specific startup things you want to load for a specific project.

Isolated project workspaces
If you want to have a SuperCollider project that is entirely isolated from both the global includes (e.g. installed quarks) AND global startup file, you can disable “global” startup, and enable local sclang_conf (and create a yaml file for it) in the VSCode settings for that workspace (e.g. “Preferences: Open Workspace Settings”). This is very useful if you’re working on something that needs to be run on other machines / in collaboration, and don’t want to accidentally depend on quarks you’ve installed locally etc.

These work well for simple configurations, but in general these project management features of the VSCode plugin are a work in progress - there are still some things that are a little clunky with them.