Skip to content

Commit 9860f96

Browse files
authored
Merge pull request #24 from Tbusk/feature/lsp-settings
[FEATURE]: LSP Configuration via Settings, LSP Docs
2 parents 74feb91 + 65cb915 commit 9860f96

File tree

10 files changed

+534
-32
lines changed

10 files changed

+534
-32
lines changed

README.md

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,16 @@ This plugin provides syntax highlighting, code completion, and other features fo
1313
This currently is in an early stage of development. Most luxuries of JetBrain IDEs are not implemented yet or are limited.
1414

1515
A Language Server Protocol (LSP) is used to provide many features, including documentation, code completion, syntax checking, etc.
16-
The supported LSP is required to be installed separately, and is found [here](https://github.com/vala-lang/vala-language-server).
1716

18-
Currently, the project expects the download location to be in `/usr/bin/vala-language-server` and is ran with `vala-language-server`.
19-
The path and command to run can be configured in `src/main/java/com/tbusk/vala_plugin/lsp/ValaLanguageServer.java`.
20-
Support for in-settings configuration is planned.
21-
22-
Largely, the LSP can be installed in a command or two. It likely is already installed if you are using other IDEs like VSCode or Neovim with the Vala plugin.
17+
The supported LSP is required to be installed separately for now. More details for the LSP are available [here](https://github.com/Tbusk/vala-jetbrains-plugin/blob/main/docs/LanguageServer.md).
2318

2419
If you want to support this project or encounter any problems, please consider opening issues (features requests, bug fixes, etc.) or pull requests on our GitHub repository [here](https://github.com/Tbusk/vala-jetbrains-plugin).
2520

2621
<!-- Plugin description end -->
2722

2823
## Project Development Phases
29-
30-
1. Improve syntax highlighting and enhance compatability with themes and color customization with the language.
31-
2. Add support for LSP to be at default download positions based on OS, and then further customized in settings.
24+
1. Add support for LSP to be at default download positions based on OS, and then further customized in settings.
25+
2. Improve syntax highlighting and enhance compatability with themes and color customization with the language.
3226
3. Add additional feature support, including most refactor methods to improve development experience.
3327
4. Add runnability support to make files executable.
3428
5. Add installation capabilities if the LSP is not found so it can be installed and downloaded.

docs/LanguageServer.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
## Language Server Configuration
2+
3+
The current supported language server is `vala-language-server`, which is an official language server for Vala available
4+
at https://github.com/vala-lang/vala-language-server.
5+
6+
It provides features like code completion, syntax checking, and more, enhancing the development experience. It is used
7+
with other Vala IDE plugins like Zed, VSCode, and NeoVim.
8+
9+
Other language servers like https://gitlab.gnome.org/esodan/gvls can be supported provided you specify the path to the
10+
executable in the plugin settings. That LSP has not been tested, so it may not work as expected.
11+
12+
To configure the path of the LSP or command used,
13+
<kbd>⚙️</kbd> > <kbd>Settings</kbd> > <kbd>Tools</kbd> > <kbd>Vala Plugin Settings</kbd> >
14+
`Specify path` > <kbd>Apply</kbd>
15+
16+
### Language Server Manager
17+
The plugin uses the RedHat LSP4IJ manager to handle the language server, which is available at
18+
https://github.com/redhat-developer/lsp4ij and https://plugins.jetbrains.com/plugin/23257-lsp4ij. This allows for easy
19+
management of the language server. While not supported by JetBrains, it is a community plugin that is actively
20+
maintained and provides a good experience for Vala development.
21+
22+
The JetBrains supported LSP configuration is restricted to paid versions of the IDE, so it is not used.
23+
24+
The docs for LSP4IJ can be found at https://github.com/redhat-developer/lsp4ij/tree/main/docs.
25+
26+
### Installation
27+
28+
To get the most up-to-date instructions, go to https://github.com/vala-lang/vala-language-server.
29+
30+
Automated installation is possible with RedHat LSP4IJ, the LSP manager for the plugin, but will be worked on at a later date.
31+
32+
#### Installation Commands
33+
_Arch Linux (via AUR)_: `yay -S vala-language-server` or `yay -S vala-language-server-git`
34+
35+
_Ubuntu, Fedora, Debian, openSUSE, and Mageia_: install from the OBS repo build result
36+
37+
_Fedora (official)_: `sudo dnf install vala-language-server`
38+
39+
_elementaryOS_: `sudo apt install vala-language-server`
40+
41+
_Alpine Linux_: `apk add vala-language-server`
42+
43+
_Guix_: `guix install vala-language-server`
44+
45+
_Void Linux_: `xbps-install vala-language-server`
46+
47+
_Windows (via MSYS2)_: `pacman -S mingw-w64-x86_64-vala-language-server`
48+
49+
50+
### Windows
51+
The easiest way to configure the language server on Windows is to locate the path to the `vala-language-server` executable
52+
and set the `PATH` environment variable in your settings.
53+
If you do this, then you can use `language-server-protocol` instead of having to specify the path to it.
54+
55+
**Note**: developing with Windows does require you to manually install each dependency used in a project, which needs to be
56+
satisfied for the language server to work properly.
57+
58+
### Linux
59+
The default path for the language server is `/usr/bin/vala-language-server`.
60+
61+
You also should be able to get away with using `language-server-protocol` as the path instead assuming you can run it
62+
in your terminal with that command.
63+
64+
### macOS
65+
The default path for the language server is `/usr/local/bin/vala-language-server`.
66+
67+
You also should be able to get away with using `language-server-protocol` as the path instead assuming you can run it
68+
in your terminal with that command.
69+
70+
## Development
71+
All LSP functionality is implemented in the `lsp` package, which is set up for `lsp4ij` from RedHat.
72+
73+
There is also an additional configuration area in `plugin.xml` for managing the plugin and language server settings.
74+
75+
There also is an area in `settings` package which is used for managing the lsp path settings.
76+
77+
A developer guide for `lsp4ij` can be found at https://github.com/redhat-developer/lsp4ij/blob/main/docs/DeveloperGuide.md.

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pluginGroup = com.tbusk.vala_plugin
44
pluginName = Vala Language
55
pluginRepositoryUrl = https://github.com/Tbusk/vala-jetbrains-plugin
66
# SemVer format -> https://semver.org
7-
pluginVersion = 1.0.0-ALPHA
7+
pluginVersion = 1.1.0-ALPHA
88

99
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
1010
pluginSinceBuild = 251
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.tbusk.vala_plugin.lsp;
2+
3+
/**
4+
* DefaultLanguageServerPathProvider is a singleton class that provides the command line configuration
5+
* for the Vala Language Server based on the operating system.
6+
* <br/>
7+
* It determines the appropriate command path for the language server depending on whether
8+
* the application is running on Windows, macOS, or Linux.
9+
*/
10+
public final class DefaultLanguageServerPathProvider {
11+
12+
private static DefaultLanguageServerPathProvider INSTANCE;
13+
14+
// Default command paths for different operating systems
15+
private static final String DEFAULT_WINDOWS_COMMAND_PATH = "vala-language-server";
16+
private static final String DEFAULT_MAC_COMMAND_PATH = "/usr/local/bin/vala-language-server";
17+
private static final String DEFAULT_LINUX_COMMAND_PATH = "/usr/bin/vala-language-server";
18+
19+
/**
20+
* Private constructor to prevent instantiation.
21+
* Use getInstance() to obtain the singleton instance.
22+
*/
23+
private DefaultLanguageServerPathProvider() {
24+
}
25+
26+
/**
27+
* Returns the singleton instance of DefaultLanguageServerPathProvider.
28+
*
29+
* @return The singleton instance of DefaultLanguageServerPathProvider.
30+
*/
31+
public static DefaultLanguageServerPathProvider getInstance() {
32+
if (INSTANCE == null) {
33+
INSTANCE = new DefaultLanguageServerPathProvider();
34+
}
35+
36+
return INSTANCE;
37+
}
38+
39+
40+
/**
41+
* Returns the command line configuration for the Vala Language Server based on the operating system.
42+
*
43+
* @return The command line path for the Vala Language Server.
44+
* @throws UnsupportedOperationException if the operating system is not supported.
45+
*/
46+
public String getCommandLineOSConfiguration() {
47+
String osNameLowercase = System.getProperty("os.name").toLowerCase();
48+
49+
if(osNameLowercase.contains("windows")) {
50+
return DEFAULT_WINDOWS_COMMAND_PATH;
51+
} else if (osNameLowercase.contains("mac")) {
52+
return DEFAULT_MAC_COMMAND_PATH;
53+
} else if (osNameLowercase.contains("linux")) {
54+
return DEFAULT_LINUX_COMMAND_PATH;
55+
}
56+
57+
throw new UnsupportedOperationException("Unsupported operating system: " + System.getProperty("os.name"));
58+
59+
}
60+
}
Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package com.tbusk.vala_plugin.lsp;
22

33
import com.intellij.execution.configurations.GeneralCommandLine;
4+
import com.intellij.openapi.application.ApplicationManager;
5+
import com.intellij.openapi.application.ex.ApplicationEx;
6+
import com.intellij.openapi.ui.Messages;
47
import com.redhat.devtools.lsp4ij.server.OSProcessStreamConnectionProvider;
8+
import com.tbusk.vala_plugin.settings.PluginSettings;
59

610
/**
711
* ValaLanguageServer is a class that extends OSProcessStreamConnectionProvider.
@@ -10,35 +14,80 @@
1014
* <br/>
1115
* The command line is set in the constructor and can be used to start the language server process.
1216
*/
13-
public class ValaLanguageServer extends OSProcessStreamConnectionProvider {
17+
public final class ValaLanguageServer extends OSProcessStreamConnectionProvider {
1418

15-
// Default command paths for different operating systems
16-
private static final String DEFAULT_WINDOWS_COMMAND_PATH = "vala-language-server";
17-
private static final String DEFAULT_MAC_COMMAND_PATH = "/usr/local/bin/vala-language-server";
18-
private static final String DEFAULT_LINUX_COMMAND_PATH = "/usr/bin/vala-language-server";
19+
private static ValaLanguageServer INSTANCE;
1920

20-
public ValaLanguageServer() {
21-
super.setCommandLine(getCommandLineOSConfiguration());
21+
/**
22+
* Private constructor to ensure singleton instance.
23+
* Initializes the command line with the path to the Vala Language Server.
24+
*/
25+
private ValaLanguageServer() {
26+
27+
String path = PluginSettings.getInstance().getState().lspServerPath;
28+
29+
super.setCommandLine(new GeneralCommandLine(path));
2230
}
2331

2432
/**
25-
* Returns a command line based on the operating system.
26-
* This method checks the OS name and returns the appropriate command line for the Vala Language Server.
33+
* Returns the singleton instance of the ValaLanguageServer.
34+
* <br/>
35+
* If the instance is null, it creates a new instance lazily.
2736
*
28-
* @return GeneralCommandLine configured for the current OS
37+
* @return ValaLanguageServer - the singleton instance of the ValaLanguageServer
2938
*/
30-
public GeneralCommandLine getCommandLineOSConfiguration() {
31-
String osName = System.getProperty("os.name").toLowerCase();
32-
33-
if(osName.contains("windows")) {
34-
return new GeneralCommandLine(DEFAULT_WINDOWS_COMMAND_PATH);
35-
} else if (osName.contains("mac")) {
36-
return new GeneralCommandLine(DEFAULT_MAC_COMMAND_PATH);
37-
} else if (osName.contains("linux")) {
38-
return new GeneralCommandLine(DEFAULT_LINUX_COMMAND_PATH);
39+
public static ValaLanguageServer getInstance() {
40+
if (INSTANCE == null) {
41+
INSTANCE = new ValaLanguageServer();
3942
}
4043

41-
throw new UnsupportedOperationException("Unsupported operating system: " + System.getProperty("os.name"));
44+
return INSTANCE;
45+
}
46+
47+
/**
48+
* Updates the command line configuration for the Vala Language Server.
49+
* <br/>
50+
* This method sets a new command path for the language server and prompts the user to restart the IDE.
51+
* The restart is necessary because LSP4IJ doesn't provide any way to reliably restart the language server
52+
* outside the UI.
53+
* @param commandPath - the new command path to set for the language server
54+
*/
55+
public void updateCommandLineConfiguration(String commandPath) {
56+
57+
setCommandLine(new GeneralCommandLine(commandPath));
58+
59+
int userChoice = showRestartPopup();
60+
61+
if(userChoice == Messages.YES) {
62+
restartIDE();
63+
}
64+
}
65+
66+
/**
67+
* Displays a popup dialog to the user asking if they want to restart the IDE.
68+
* <br/>
69+
* This dialog is shown when the language server configuration is changed and a restart is required.
70+
*
71+
* @return int - the user's choice (YES or NO)
72+
*/
73+
public int showRestartPopup() {
74+
return Messages.showYesNoDialog(
75+
"A restart is required for the changes to take affect. Do you want to restart now?",
76+
"Restart Required",
77+
Messages.getQuestionIcon()
78+
);
79+
}
80+
81+
/**
82+
* Restarts the IDE.
83+
* <br/>
84+
* This method uses the ApplicationEx class to restart the IDE with the current state.
85+
* <br/>
86+
* <a href="https://intellij-support.jetbrains.com/hc/en-us/community/posts/206105709-How-do-you-make-a-plugin-setting-change-require-a-restart">view forum q/a...</a>
87+
*/
88+
public void restartIDE() {
89+
ApplicationEx app = (ApplicationEx)ApplicationManager.getApplication();
4290

91+
app.restart(true);
4392
}
4493
}

src/main/java/com/tbusk/vala_plugin/lsp/ValaLanguageServerFactory.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,43 @@
77
import org.eclipse.lsp4j.services.LanguageServer;
88
import org.jetbrains.annotations.NotNull;
99

10+
/**
11+
* Factory for creating the Vala Language Server.
12+
* <br/>
13+
* This class implements the LanguageServerFactory interface to provide
14+
* the necessary server-related functionality.
15+
*/
1016
public class ValaLanguageServerFactory implements LanguageServerFactory {
1117

12-
18+
/**
19+
* Creates a connection provider for the Vala Language Server.
20+
*
21+
* @param project - the current project
22+
* @return a StreamConnectionProvider for the Vala Language Server
23+
*/
1324
@Override
1425
public @NotNull StreamConnectionProvider createConnectionProvider(@NotNull Project project) {
15-
return new ValaLanguageServer();
26+
return ValaLanguageServer.getInstance();
1627
}
1728

29+
/**
30+
* Creates a language client for the Vala Language Server.
31+
* This is useful for providing client specific features.
32+
*
33+
* @param project - the current project
34+
* @return LanguageClientImpl - for the Vala Language Server
35+
*/
1836
@Override
1937
public @NotNull LanguageClientImpl createLanguageClient(@NotNull Project project) {
2038
return LanguageServerFactory.super.createLanguageClient(project);
2139
}
2240

41+
/**
42+
* Returns the interface class for the Vala Language Server.
43+
* This method is used to expose custom server API.
44+
*
45+
* @return Class<? extends LanguageServer> - the Vala Language Server API interface
46+
*/
2347
@Override
2448
public @NotNull Class<? extends LanguageServer> getServerInterface() {
2549
return ValaLanguageServerAPI.class;
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.tbusk.vala_plugin.settings;
2+
3+
import com.intellij.openapi.application.ApplicationManager;
4+
import com.intellij.openapi.components.PersistentStateComponent;
5+
import com.intellij.openapi.components.State;
6+
import com.intellij.openapi.components.Storage;
7+
import com.tbusk.vala_plugin.lsp.DefaultLanguageServerPathProvider;
8+
import org.jetbrains.annotations.NonNls;
9+
import org.jetbrains.annotations.NotNull;
10+
import org.jetbrains.annotations.Nullable;
11+
12+
/**
13+
* This class holds the settings for the Vala plugin.
14+
* It is used to store and retrieve persistent data for the plugin.
15+
* Currently only the path to the Vala Language Server is stored.
16+
* <br/>
17+
* <a href="https://plugins.jetbrains.com/docs/intellij/settings-tutorial.html#the-appsettings-class">view plugin docs...</a>
18+
*/
19+
@State(
20+
name = "com.tbusk.vala_plugin.settings.PluginSettings",
21+
storages = @Storage("ValaPluginSettings.xml")
22+
)
23+
public final class PluginSettings implements PersistentStateComponent<PluginSettings.State> {
24+
25+
/**
26+
* This class holds the state of the plugin settings.
27+
* It contains the path to the Vala Language Server.
28+
*/
29+
public static class State {
30+
private DefaultLanguageServerPathProvider defaultLanguageServerPathProvider = DefaultLanguageServerPathProvider.getInstance();
31+
@NonNls
32+
public String lspServerPath = defaultLanguageServerPathProvider.getCommandLineOSConfiguration();
33+
}
34+
35+
private State pluginState = new State();
36+
37+
/**
38+
* Retrieves the singleton instance of PluginSettings.
39+
*
40+
* @return the instance of PluginSettings
41+
*/
42+
public static PluginSettings getInstance() {
43+
return ApplicationManager.getApplication().getService(PluginSettings.class);
44+
}
45+
46+
/**
47+
* Returns the current state of the plugin settings.
48+
*
49+
* @return the current state of the plugin settings, or null if not set
50+
*/
51+
@Override
52+
public @Nullable PluginSettings.State getState() {
53+
return pluginState;
54+
}
55+
56+
/**
57+
* Loads the state of the plugin settings from the provided state.
58+
* @param state the state to load
59+
*/
60+
@Override
61+
public void loadState(@NotNull State state) {
62+
pluginState = state;
63+
}
64+
}

0 commit comments

Comments
 (0)