├── .python-version ├── messages.json ├── .gitattributes ├── messages └── 1.2.0.txt ├── LSP-OmniSharp.sublime-commands ├── LICENSE ├── README.md ├── LSP-OmniSharp.sublime-settings ├── sublime-package.json └── plugin.py /.python-version: -------------------------------------------------------------------------------- 1 | 3.8 2 | -------------------------------------------------------------------------------- /messages.json: -------------------------------------------------------------------------------- 1 | { 2 | "1.2.0": "messages/1.2.0.txt" 3 | } 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | .github/ export-ignore 2 | pyproject.toml export-ignore 3 | renovate.json export-ignore 4 | -------------------------------------------------------------------------------- /messages/1.2.0.txt: -------------------------------------------------------------------------------- 1 | LSP-OmniSharp's underlying language server has been upgraded to v1.39.12. 2 | 3 | See: https://github.com/OmniSharp/omnisharp-roslyn/releases/tag/v1.39.12 4 | 5 | This enables support for .NET 6. 6 | 7 | If you encounter any problems, you may want to open a new Github issue 8 | at https://github.com/sublimelsp/LSP-OmniSharp/issues. 9 | -------------------------------------------------------------------------------- /LSP-OmniSharp.sublime-commands: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "caption": "Preferences: LSP-OmniSharp Settings", 4 | "command": "edit_settings", 5 | "args": { 6 | "base_file": "${packages}/LSP-OmniSharp/LSP-OmniSharp.sublime-settings", 7 | "default": "// Settings in here override those in \"LSP-OmniSharp/LSP-OmniSharp.sublime-settings\"\n{\n\t$0\n}\n" 8 | } 9 | } 10 | ] 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Raoul Wols 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LSP-OmniSharp 2 | 3 | This is a helper package that automatically installs and updates 4 | [OmniSharp](https://github.com/OmniSharp/omnisharp-roslyn) for you. 5 | 6 | To use this package, you must have: 7 | 8 | - The [LSP](https://packagecontrol.io/packages/LSP) package. 9 | - The [.NET SDK 6 or higher](https://dotnet.microsoft.com/download). 10 | - (Optional but recommended) Install the [LSP-file-watcher-chokidar](https://github.com/sublimelsp/LSP-file-watcher-chokidar) via Package Control to enable functionality to notify the server about new files. 11 | 12 | 13 | ## Applicable Selectors 14 | 15 | This language server operates on views with the `source.cs` base scope. 16 | 17 | ## Installation Location 18 | 19 | The server is installed in the $DATA/Package Storage/LSP-OmniSharp directory, where $DATA is the base data path of Sublime Text. 20 | For instance, $DATA is `~/.config/sublime-text` on a Linux system. If you want to force a re-installation of the server, 21 | you can delete the entire $DATA/Cache/LSP-OmniSharp directory. 22 | 23 | Like any helper package, installation starts when you open a view that is suitable for this language server. In this 24 | case, that means that when you open a view with the `source.cs` base scope, installation commences. 25 | 26 | ## Configuration 27 | 28 | Configure OmniSharp by running `Preferences: LSP-OmniSharp Settings` from the Command Palette. 29 | 30 | ## Capabilities 31 | 32 | OmniSharp can do a lot of cool things, like 33 | 34 | - code completion 35 | - signature help 36 | - hover info 37 | - some quality code actions 38 | - formatting 39 | - find references 40 | - goto def 41 | -------------------------------------------------------------------------------- /LSP-OmniSharp.sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "selector": "source.cs | source.cake", 3 | "settings": { 4 | // The name of the default solution used at start up if the repo has multiple solutions. 5 | // e.g.'MyAwesomeSolution.sln'. Default value is `null` which will cause the first in 6 | // alphabetical order to be chosen. 7 | "omnisharp.defaultLaunchSolution": null, 8 | // Enables support for decompiling external references instead of viewing metadata. 9 | "omnisharp.enableDecompilationSupport": false, 10 | // Enables support for reading code style, naming convention and analyzer settings from 11 | // .editorconfig. 12 | "omnisharp.enableEditorConfigSupport": true, 13 | // Enables support for showing unimported types and unimported extension methods in 14 | // completion lists. When committed, the appropriate using directive will be added at the 15 | // top of the current file. This option can have a negative impact on initial completion 16 | // responsiveness, particularly for the first few completion sessions after opening a 17 | // solution. 18 | "omnisharp.enableImportCompletion": false, 19 | // If true, MSBuild project system will only load projects for files that were opened in the 20 | // editor. This setting is useful for big C# codebases and allows for faster initialization 21 | // of code navigation features only for projects that are relevant to code that is being 22 | // edited. With this setting enabled OmniSharp may load fewer projects and may thus display 23 | // incomplete reference lists for symbols. 24 | "omnisharp.enableMsBuildLoadProjectsOnDemand": false, 25 | // Enables support for roslyn analyzers, code fixes and rulesets. 26 | "omnisharp.enableRoslynAnalyzers": false, 27 | // Specifies the level of logging output from the OmniSharp server. 28 | // possible values: trace, debug, information, warning, error, critical 29 | "omnisharp.loggingLevel": "information", 30 | // The maximum number of items that 'Go to Symbol in Workspace' operation can show. The 31 | // limit is applied only when a positive number is specified here. 32 | "omnisharp.maxFindSymbolsItems": 1000, 33 | // The maximum number of projects to be shown in the 'Select Project' dropdown (maximum 34 | // 250). 35 | "omnisharp.maxProjectResults": 250, 36 | // The minimum number of characters to enter before 'Go to Symbol in Workspace' operation 37 | // shows any results. 38 | "omnisharp.minFindSymbolsFilterLength": 0, 39 | // Specifies whether 'using' directives should be grouped and sorted during document 40 | // formatting. 41 | "omnisharp.organizeImportsOnFormat": false, 42 | // Specifes whether OmniSharp should use VS Code editor settings for C# code formatting (use 43 | // of tabs, indentation size). 44 | "omnisharp.useEditorFormattingSettings": true, 45 | // Enable/disable default Razor formatter. 46 | "razor.format.enable": true, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /sublime-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "contributions": { 3 | "settings": [ 4 | { 5 | "file_patterns": [ 6 | "/LSP-OmniSharp.sublime-settings" 7 | ], 8 | "schema": { 9 | "$id": "sublime://settings/LSP-OmniSharp", 10 | "allOf": [ 11 | { 12 | "$ref": "sublime://settings/LSP-plugin-base" 13 | }, 14 | { 15 | "$ref": "sublime://settings/LSP-OmniSharp#/definitions/PluginConfig" 16 | } 17 | ], 18 | "definitions": { 19 | "PluginConfig": { 20 | "properties": { 21 | "settings": { 22 | "additionalProperties": false, 23 | "properties": { 24 | "omnisharp.defaultLaunchSolution": { 25 | "default": null, 26 | "description": "The name of the default solution used at start up if the repo has multiple solutions. e.g.'MyAwesomeSolution.sln'. Default value is `null` which will cause the first in alphabetical order to be chosen.", 27 | "type": ["string", "null"] 28 | }, 29 | "omnisharp.enableDecompilationSupport": { 30 | "default": false, 31 | "description": "Enables support for decompiling external references instead of viewing metadata.", 32 | "type": "boolean" 33 | }, 34 | "omnisharp.enableEditorConfigSupport": { 35 | "default": true, 36 | "description": "Enables support for reading code style, naming convention and analyzer settings from .editorconfig.", 37 | "type": "boolean" 38 | }, 39 | "omnisharp.enableImportCompletion": { 40 | "default": false, 41 | "description": "Enables support for showing unimported types and unimported extension methods in completion lists. When committed, the appropriate using directive will be added at the top of the current file. This option can have a negative impact on initial completion responsiveness, particularly for the first few completion sessions after opening a solution.", 42 | "type": "boolean" 43 | }, 44 | "omnisharp.enableMsBuildLoadProjectsOnDemand": { 45 | "default": false, 46 | "description": "If true, MSBuild project system will only load projects for files that were opened in the editor. This setting is useful for big C# codebases and allows for faster initialization of code navigation features only for projects that are relevant to code that is being edited. With this setting enabled OmniSharp may load fewer projects and may thus display incomplete reference lists for symbols.", 47 | "type": "boolean" 48 | }, 49 | "omnisharp.enableRoslynAnalyzers": { 50 | "default": false, 51 | "description": "Enables support for roslyn analyzers, code fixes and rulesets.", 52 | "type": "boolean" 53 | }, 54 | "omnisharp.loggingLevel": { 55 | "default": "information", 56 | "description": "Specifies the level of logging output from the OmniSharp server.", 57 | "enum": [ 58 | "trace", 59 | "debug", 60 | "information", 61 | "warning", 62 | "error", 63 | "critical" 64 | ], 65 | "type": "string" 66 | }, 67 | "omnisharp.maxFindSymbolsItems": { 68 | "default": 1000, 69 | "description": "The maximum number of items that 'Go to Symbol in Workspace' operation can show. The limit is applied only when a positive number is specified here.", 70 | "type": "number" 71 | }, 72 | "omnisharp.maxProjectResults": { 73 | "default": 250, 74 | "description": "The maximum number of projects to be shown in the 'Select Project' dropdown (maximum 250).", 75 | "type": "number" 76 | }, 77 | "omnisharp.minFindSymbolsFilterLength": { 78 | "default": 0, 79 | "description": "The minimum number of characters to enter before 'Go to Symbol in Workspace' operation shows any results.", 80 | "type": "number" 81 | }, 82 | "omnisharp.organizeImportsOnFormat": { 83 | "default": false, 84 | "description": "Specifies whether 'using' directives should be grouped and sorted during document formatting.", 85 | "type": "boolean" 86 | }, 87 | "omnisharp.useEditorFormattingSettings": { 88 | "default": true, 89 | "description": "Specifes whether OmniSharp should use Sublime Text editor settings for C# code formatting (use of tabs, indentation size).", 90 | "type": "boolean" 91 | }, 92 | "razor.format.enable": { 93 | "default": true, 94 | "description": "Enable/disable default Razor formatter.", 95 | "type": "boolean" 96 | } 97 | } 98 | } 99 | } 100 | } 101 | } 102 | } 103 | }, 104 | { 105 | "file_patterns": [ 106 | "/*.sublime-project" 107 | ], 108 | "schema": { 109 | "properties": { 110 | "settings": { 111 | "properties": { 112 | "LSP": { 113 | "properties": { 114 | "OmniSharp": { 115 | "$ref": "sublime://settings/LSP-OmniSharp#/definitions/PluginConfig" 116 | } 117 | } 118 | } 119 | } 120 | } 121 | } 122 | } 123 | } 124 | ] 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /plugin.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import os 4 | import shutil 5 | import sublime 6 | 7 | from pathlib import Path 8 | 9 | from typing import TYPE_CHECKING 10 | if TYPE_CHECKING: 11 | from typing import Any, Callable, Optional 12 | 13 | from urllib.request import urlretrieve 14 | from zipfile import ZipFile 15 | 16 | from LSP.plugin import AbstractPlugin 17 | from LSP.plugin import ClientConfig 18 | from LSP.plugin import register_plugin 19 | from LSP.plugin import unregister_plugin 20 | from LSP.plugin import WorkspaceFolder 21 | from LSP.plugin.core.views import range_to_region # TODO: not public API :( 22 | 23 | VERSION = "1.39.12" 24 | URL = "https://github.com/OmniSharp/omnisharp-roslyn/releases/download/v{}/omnisharp-{}.zip" # noqa: E501 25 | 26 | 27 | def _platform_str() -> str: 28 | return { 29 | "osx": { 30 | "arm64": "osx-arm64-net6.0", 31 | "x64": "osx-x64-net6.0", 32 | "x32": "osx", 33 | }, 34 | "linux": { 35 | "arm64": "linux-arm64-net6.0", 36 | "x64": "linux-x64-net6.0", 37 | "x32": "linux-x86-net6.0", 38 | }, 39 | "windows": { 40 | "arm64": "win-arm64-net6.0", 41 | "x64": "win-x64-net6.0", 42 | "x32": "win-x86-net6.0", 43 | } 44 | }[sublime.platform()][sublime.arch()] 45 | 46 | 47 | class OmniSharp(AbstractPlugin): 48 | @classmethod 49 | def name(cls) -> str: 50 | return cls.__name__ 51 | 52 | @classmethod 53 | def get_settings(cls) -> sublime.Settings: 54 | return sublime.load_settings(f"LSP-{cls.name()}.sublime-settings") 55 | 56 | @classmethod 57 | def version_str(cls) -> str: 58 | return VERSION 59 | 60 | @classmethod 61 | def installed_version_str(cls) -> str: 62 | with open(cls.basedir() / "VERSION", "r") as f: 63 | version = f.readline().strip() 64 | return version 65 | 66 | @classmethod 67 | def basedir(cls) -> Path: 68 | return Path(cls.storage_path()) / f"LSP-{cls.name()}" 69 | 70 | @classmethod 71 | def binary_path(cls) -> Path: 72 | if sublime.platform() == "windows": 73 | return cls.basedir() / "OmniSharp.exe" 74 | else: 75 | return cls.basedir() / "OmniSharp" 76 | 77 | @classmethod 78 | def get_command(cls) -> list[str]: 79 | settings = cls.get_settings() 80 | cmd = settings.get("command") 81 | if isinstance(cmd, list): 82 | return cmd 83 | return [ 84 | str(cls.binary_path()), 85 | "--languageserver", 86 | "--encoding", "utf-8", 87 | "--hostPID", str(os.getpid()), 88 | ] 89 | 90 | @classmethod 91 | def needs_update_or_installation(cls) -> bool: 92 | try: 93 | if cls.version_str() == cls.installed_version_str(): 94 | return False 95 | except Exception: 96 | pass 97 | return True 98 | 99 | @classmethod 100 | def install_or_update(cls) -> None: 101 | basedir = cls.basedir() 102 | shutil.rmtree(basedir, ignore_errors=True) 103 | basedir.mkdir(parents=True, exist_ok=True) 104 | zipfile = basedir / "omnisharp.zip" 105 | try: 106 | version = cls.version_str() 107 | urlretrieve(URL.format(version, _platform_str()), zipfile) 108 | with ZipFile(zipfile, "r") as f: 109 | f.extractall(basedir) 110 | zipfile.unlink() 111 | if sublime.platform() != "windows": 112 | cls.binary_path().chmod(0o744) 113 | with open(basedir / "VERSION", "w") as fp: 114 | fp.write(version) 115 | except Exception: 116 | shutil.rmtree(basedir, ignore_errors=True) 117 | raise 118 | 119 | @classmethod 120 | def on_pre_start( 121 | cls, 122 | window: sublime.Window, 123 | initiating_view: sublime.View, 124 | workspace_folders: list[WorkspaceFolder], 125 | configuration: ClientConfig 126 | ) -> Optional[str]: 127 | configuration.command = cls.get_command() 128 | return None 129 | 130 | # -- commands from the server that should be handled client-side ---------- 131 | 132 | def on_pre_server_command( 133 | self, 134 | command: dict[str, Any], 135 | done_callback: Callable[[], None] 136 | ) -> bool: 137 | name = command["command"] 138 | if name == "omnisharp/client/findReferences": 139 | return self._handle_quick_references(command["arguments"], done_callback) 140 | return False 141 | 142 | def _handle_quick_references(self, arguments: list[Any], done_callback: Callable[[], None]) -> bool: 143 | session = self.weaksession() 144 | if not session: 145 | return True 146 | sb = session.get_session_buffer_for_uri_async(arguments[0]["uri"]) 147 | if not sb: 148 | return True 149 | for sv in sb.session_views: 150 | if not sv.view.is_valid(): 151 | continue 152 | region = range_to_region(arguments[0]["range"], sv.view) 153 | args = {"point": region.a} 154 | sv.view.run_command("lsp_symbol_references", args) 155 | done_callback() 156 | return True 157 | return True 158 | 159 | # --- custom notification handlers ---------------------------------------- 160 | 161 | def _print(self, sticky: bool, fmt: str, *args: Any) -> None: 162 | session = self.weaksession() 163 | if session: 164 | message = fmt.format(*args) 165 | if sticky: 166 | session.set_config_status_async(message) 167 | else: 168 | session.set_config_status_async("") 169 | session.window.status_message(message) 170 | 171 | def m_o__msbuildprojectdiagnostics(self, params: Any) -> None: 172 | self._print(True, "Compiled {}", params["FileName"]) 173 | 174 | def m_o__projectconfiguration(self, params: Any) -> None: 175 | self._print(False, "Project configured") 176 | 177 | def m_o__unresolveddependencies(self, params: Any) -> None: 178 | self._print(False, "{} has unresolved dependencies", params["FileName"]) 179 | 180 | def _get_assembly_name(self, params: Any) -> Optional[str]: 181 | project = params.get("MsBuildProject") 182 | if project: 183 | assembly_name = project.get("AssemblyName") 184 | if isinstance(assembly_name, str): 185 | return assembly_name 186 | return None 187 | 188 | def m_o__projectadded(self, params: Any) -> None: 189 | assembly_name = self._get_assembly_name(params) 190 | if assembly_name: 191 | self._print(False, "Project added: {}", assembly_name) 192 | 193 | def m_o__projectchanged(self, params: Any) -> None: 194 | assembly_name = self._get_assembly_name(params) 195 | if assembly_name: 196 | self._print(False, "Project changed: {}", assembly_name) 197 | 198 | 199 | def plugin_loaded() -> None: 200 | register_plugin(OmniSharp) 201 | 202 | 203 | def plugin_unloaded() -> None: 204 | unregister_plugin(OmniSharp) 205 | --------------------------------------------------------------------------------