sublimelsp / LSP-OmniSharp

Convenience plugin to install/update OmniSharp for LSP
MIT License
20 stars 9 forks source link

Question: How to use in combination with Godot? ("The type or namespace name 'Godot' could not be found") #39

Open pineapplemachine opened 2 months ago

pineapplemachine commented 2 months ago

I installed this plugin hoping to use it with C# code for Godot. I think I must be missing some setup step, though, because the line using Godot; is currently producing an error. The same source file shows as having no errors when viewed in JetBrains Rider, configured for Godot C#.

image

Here are my LSP-OmniSharp settings:

// Settings in here override those in "LSP-OmniSharp/LSP-OmniSharp.sublime-settings"
{
    "settings": {
        "csharp.format.enable": false,
        "csharp.maxProjectFileCountForDiagnosticAnalysis": 100,
        "omnisharp.useEditorFormattingSettings": false,
        "razor.format.enable": false,
    },
}

I have not added any C#-specific settings to my LSP plugin settings, since this wasn't mentioned in the LSP-OmniSharp readme?

deathaxe commented 2 months ago

Omnisharp requires a proper *.csproj file with references to all used assemblies.

A minimal project with a Godot reference would look like...

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <Reference Include="Godot">
      <HintPath>%ProgramFiles%\Godot\GodotSharp\Api\Release\GodotSharp.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>
pineapplemachine commented 2 months ago

@deathaxe I do have a csproj file in my project directory. It didn't originally have the Reference portion you gave an example of. But even after adding one, I am still having the same issue.

image

The contents of my [myproject].csproj file (the reference HintPath is correct on my system):

<Project Sdk="Godot.NET.Sdk/4.2.2">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
    <EnableDynamicLoading>true</EnableDynamicLoading>
    <RootNamespace>Monster</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="cmstar.Serialization.Json" Version="1.0.0" />
    <PackageReference Include="YamlDotNet" Version="13.7.1" />
  </ItemGroup>
  <ItemGroup>
    <Compile Remove="scratch\**" />
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Remove="scratch\**" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="src\cs\" />
    <Folder Include="addons\Gui\src\" />
  </ItemGroup>
  <ItemGroup>
    <Reference Include="Godot">
      <HintPath>C:\apps\godot-4.2.2\GodotSharp\Api\Release\GodotSharp.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>
deathaxe commented 2 months ago

Downloading Godot, adding the reference and restarting Omnisharp was the only steps I needed to do to fix it on my end.

pineapplemachine commented 2 months ago

I have tried restarting OmniSharp, after making the change to the csproj file, but that hasn't resolved the issue for me.

It seems unlikely to be related, but I have noticed that after adding this line to my plugin settings:

"csharp.referencesCodeLens.enabled": false,

I still have references showing in Sublime Text (which I would rather they didn't), and also the counts often seem to be incorrect. I think what's happening is sometimes the counts are scrambled and not on the lines they should be?

image

deathaxe commented 2 months ago

Yes, settings actually don't work. See #28 for given code lense setting in particular or #44 for the reason why.

You can however control omnisharp settings by placing an omnisharp.json next to your project file. See https://github.com/OmniSharp/omnisharp-roslyn/wiki/Configuration-Options for details.


Is the project file located in the root of that folder, which is also added to sidebar in ST?

The only explanation I'd have for it not working is Omnisharp not having resolved or selected your project as the active one. It providing code lenses however indicates it basically working.

pineapplemachine commented 2 months ago

The csproj file is located in the project root directory, same as where Godot originally generated it.

Can you be more specific about what you mean by adding a project file to the sidebar? I don't use the sidebar. Mine is always set to hidden and I don't interact with it. (I use a *.sublime-project file and the Ctrl+P hotkey to navigate files.)

(And thank you for clarifying the configuration issue.)

deathaxe commented 2 months ago

sublime-project file is not important. Some language servers just require the main project folder to be the first folder in ST's sidebar. It may not be the case for Omnisharp, just wanted to rule out some possible reasons for file not being found.

You could try to override the "env" setting, which points to invalid path.

see https://github.com/sublimelsp/LSP-OmniSharp/commit/d5cea1febbcc0ba7175353610064c22ece5159b5

Maybe this helps finding required binaries.

pineapplemachine commented 2 months ago

Changing my plugin settings file to this does hide the references, but it doesn't change the behavior otherwise:

{
    "settings": {
        "csharp.format.enable": false,
        "omnisharp.useEditorFormattingSettings": false,
        "razor.format.enable": false,
        "csharp.referencesCodeLens.enabled": false,
    },
    "env": {},
    "disabled_capabilities": {
        "codeLensProvider": true,
    },
}

I also tried setting env like this, which also had no apparent effect:

    "env": {
        "FrameworkPathOverride": "C:/apps/godot-4.2.2/GodotSharp/Api/Release",
    },

Another thing I tried was navigating in the Sublime menu to "Project" -> "Add Folder to Project" and then selecting the Godot root project directory (the one containing the csproj file). This also didn't have any effect.

image

deathaxe commented 2 months ago

The only idea left is checking LSP Log Panel for some useful hints printed by OmniSharp language server. Maybe it tells us, what's missing.

Loading your project on my end causes various "invalid project file" messages, but I guess they are caused by godot not being properly installed and registerd. I don't have interest in learning godot or digging into that engine deeper though.

pineapplemachine commented 2 months ago

To be clear in advance of all this, I do have the .NET SDK installed, and Rider and Godot are both working and handling C# code without issue. So whatever is happening is seemingly a configuration issue specific to OmniSharp and shouldn't be a general issue with my .NET SDK installation.

Originally I was seeing this error in the LSP log panel:

:: [19:59:53.261] <-  OmniSharp window/logMessage: {'type': 1, 'message': "OmniSharp.MSBuild.ProjectManager: Failed to load project file 'F:\\Sync\\Monster24\\Godot\\monster24\\monster24.csproj'. - Microsoft.Build.Exceptions.InvalidProjectFileException: The SDK 'Microsoft.NET.Sdk' specified could not be found.  C:\\Users\\Sophie\\.nuget\\packages\\godot.net.sdk\\4.2.2\\Sdk\\Sdk.props\r\n   at Microsoft.Build.Shared.ProjectErrorUtilities.ThrowInvalidProject(String errorSubCategoryResourceName, IElementLocation elementLocation, String resourceName, Object[] args)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImportsFromUnescapedImportExpressionConditioned(String directoryOfImportingFile, ProjectImportElement importElement, List`1& projects, SdkResult& sdkResult)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImports(String directoryOfImportingFile, ProjectImportElement importElement, SdkResult& sdkResult)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.Evaluate()\r\n   at Microsoft.Build.Evaluation.Evaluator`4.Evaluate(IEvaluatorData`4 data, Project project, ProjectRootElement root, ProjectLoadSettings loadSettings, Int32 maxNodeCount, PropertyDictionary`1 environmentProperties, ILoggingService loggingService, IItemFactory`2 itemFactory, IToolsetProvider toolsetProvider, IDirectoryCacheFactory directoryCacheFactory, ProjectRootElementCacheBase projectRootElementCache, BuildEventContext buildEventContext, ISdkResolverService sdkResolverService, Int32 submissionId, EvaluationContext evaluationContext, Boolean interactive)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.Reevaluate(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(EvaluationContext evaluationContext)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.Initialize(IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext, Boolean interactive)\r\n   at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext, IDirectoryCacheFactory directoryCacheFactory, Boolean interactive)\r\n   at Microsoft.Build.Evaluation.ProjectCollection.LoadProject(String fileName, IDictionary`2 globalProperties, String toolsVersion)\r\n   at OmniSharp.MSBuild.ProjectLoader.EvaluateProjectFileCore(String filePath, IReadOnlyDictionary`2 projectConfigurationsInSolution, IList`1 loggers) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectLoader.cs:line 160\r\n   at OmniSharp.MSBuild.ProjectLoader.BuildProject(String filePath, IReadOnlyDictionary`2 configurationsInSolution) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectLoader.cs:line 84\r\n   at OmniSharp.MSBuild.ProjectFile.ProjectFileInfo.Load(String filePath, ProjectIdInfo projectIdInfo, ProjectLoader loader, Guid sessionId, DotNetInfo dotNetInfo) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectFile\\ProjectFileInfo.cs:line 117\r\n   at OmniSharp.MSBuild.ProjectManager.<>c__DisplayClass32_0.<LoadProject>b__0() in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectManager.cs:line 305\r\n   at OmniSharp.MSBuild.ProjectManager.LoadOrReloadProject(String projectFilePath, Func`1 loader) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectManager.cs:line 316 | "}

I followed a troubleshooting step I found here and added a new environment variable MSBuildSDKsPath and set it to C:\Program Files\dotnet\sdk\8.0.401\Sdks, where my .NET 8 SDK installation is located. https://stackoverflow.com/a/46339086

After that I got a different error regarding failing to load the project file, which seems to be the same as was encountered here https://github.com/dotnet/vscode-csharp/issues/5685:

:: [13:22:28.390] <-  OmniSharp window/logMessage: {'type': 1, 'message': "OmniSharp.MSBuild.ProjectManager: Failed to load project file 'F:\\Sync\\Monster24\\Godot\\monster24\\monster24.csproj'. - System.MissingMethodException: Method not found: 'System.ReadOnlySpan`1<Char> Microsoft.IO.Path.GetFileName(System.ReadOnlySpan`1<Char>)'.\r\n   at Microsoft.Build.Shared.FileMatcher.IsFileNameMatch(String path, String pattern)\r\n   at System.Linq.Enumerable.WhereListIterator`1.MoveNext()\r\n   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)\r\n   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)\r\n   at Microsoft.Build.Shared.FileMatcher.GetFilesForStep(RecursiveStepResult stepResult, RecursionState recursionState, String projectDirectory, Boolean stripProjectDirectory)\r\n   at Microsoft.Build.Shared.FileMatcher.GetFilesRecursive(ConcurrentStack`1 listOfFiles, RecursionState recursionState, String projectDirectory, Boolean stripProjectDirectory, IList`1 searchesToExclude, Dictionary`2 searchesToExcludeInSubdirs, TaskOptions taskOptions)\r\n   at Microsoft.Build.Shared.FileMatcher.GetFilesImplementation(String projectDirectoryUnescaped, String filespecUnescaped, List`1 excludeSpecsUnescaped)\r\n   at Microsoft.Build.Shared.FileMatcher.<>c__DisplayClass67_0.<GetFiles>b__1(String _)\r\n   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)\r\n   at Microsoft.Build.Shared.FileMatcher.GetFiles(String projectDirectoryUnescaped, String filespecUnescaped, List`1 excludeSpecsUnescaped)\r\n   at Microsoft.Build.Internal.EngineFileUtilities.GetFileList(String directoryEscaped, String filespecEscaped, Boolean returnEscaped, Boolean forceEvaluateWildCards, IEnumerable`1 excludeSpecsEscaped, FileMatcher fileMatcher, Object loggingMechanism, IElementLocation includeLocation, IElementLocation excludeLocation, IElementLocation importLocation, BuildEventContext buildEventContext, String buildEventFileInfoFullPath, Boolean disableExcludeDriveEnumerationWarning)\r\n   at Microsoft.Build.Internal.EngineFileUtilities.GetFileListEscaped(String directoryEscaped, String filespecEscaped, IEnumerable`1 excludeSpecsEscaped, Boolean forceEvaluate, FileMatcher fileMatcher, Object loggingMechanism, IElementLocation includeLocation, IElementLocation excludeLocation, IElementLocation importLocation, BuildEventContext buildEventContext, String buildEventFileInfoFullPath, Boolean disableExcludeDriveEnumerationWarning)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImportsFromUnescapedImportExpression(String directoryOfImportingFile, ProjectImportElement importElement, String unescapedExpression, Boolean throwOnFileNotExistsError, List`1& imports)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImportsFromUnescapedImportExpressionConditioned(String directoryOfImportingFile, ProjectImportElement importElement, List`1& projects, SdkResult& sdkResult)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.ExpandAndLoadImports(String directoryOfImportingFile, ProjectImportElement importElement, SdkResult& sdkResult)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.EvaluateImportElement(String directoryOfImportingFile, ProjectImportElement importElement)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.PerformDepthFirstPass(ProjectRootElement currentProjectOrImport)\r\n   at Microsoft.Build.Evaluation.Evaluator`4.Evaluate()\r\n   at Microsoft.Build.Evaluation.Evaluator`4.Evaluate(IEvaluatorData`4 data, Project project, ProjectRootElement root, ProjectLoadSettings loadSettings, Int32 maxNodeCount, PropertyDictionary`1 environmentProperties, ILoggingService loggingService, IItemFactory`2 itemFactory, IToolsetProvider toolsetProvider, IDirectoryCacheFactory directoryCacheFactory, ProjectRootElementCacheBase projectRootElementCache, BuildEventContext buildEventContext, ISdkResolverService sdkResolverService, Int32 submissionId, EvaluationContext evaluationContext, Boolean interactive)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.Reevaluate(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(ILoggingService loggingServiceForEvaluation, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.ReevaluateIfNecessary(EvaluationContext evaluationContext)\r\n   at Microsoft.Build.Evaluation.Project.ProjectImpl.Initialize(IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext, Boolean interactive)\r\n   at Microsoft.Build.Evaluation.Project..ctor(String projectFile, IDictionary`2 globalProperties, String toolsVersion, String subToolsetVersion, ProjectCollection projectCollection, ProjectLoadSettings loadSettings, EvaluationContext evaluationContext, IDirectoryCacheFactory directoryCacheFactory, Boolean interactive)\r\n   at Microsoft.Build.Evaluation.ProjectCollection.LoadProject(String fileName, IDictionary`2 globalProperties, String toolsVersion)\r\n   at OmniSharp.MSBuild.ProjectLoader.EvaluateProjectFileCore(String filePath, IReadOnlyDictionary`2 projectConfigurationsInSolution, IList`1 loggers) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectLoader.cs:line 160\r\n   at OmniSharp.MSBuild.ProjectLoader.BuildProject(String filePath, IReadOnlyDictionary`2 configurationsInSolution) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectLoader.cs:line 84\r\n   at OmniSharp.MSBuild.ProjectFile.ProjectFileInfo.Load(String filePath, ProjectIdInfo projectIdInfo, ProjectLoader loader, Guid sessionId, DotNetInfo dotNetInfo) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectFile\\ProjectFileInfo.cs:line 117\r\n   at OmniSharp.MSBuild.ProjectManager.<>c__DisplayClass32_0.<LoadProject>b__0() in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectManager.cs:line 305\r\n   at OmniSharp.MSBuild.ProjectManager.LoadOrReloadProject(String projectFilePath, Func`1 loader) in D:\\a\\1\\s\\src\\OmniSharp.MSBuild\\ProjectManager.cs:line 316 | "}

...And then as I was trying to troubleshoot further and restarted Sublime Text for the severalth time in this process, I got a package control message that LSP-OmniSharp has just been updated. And now it seems to be working?

Package Control Messages
========================

LSP-OmniSharp
-------------

  LSP-OmniSharp's underlying language server has been upgraded to v1.39.12.

  See: https://github.com/OmniSharp/omnisharp-roslyn/releases/tag/v1.39.12

  This enables support for .NET 6.

  If you encounter any problems, you may want to open a new Github issue
  at https://github.com/sublimelsp/LSP-OmniSharp/issues.

Here's the contents of my csproj file at the time that this seems to be working now:

<Project Sdk="Godot.NET.Sdk/4.2.2">
  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net7.0</TargetFramework>
    <TargetFramework Condition=" '$(GodotTargetPlatform)' == 'ios' ">net8.0</TargetFramework>
    <EnableDynamicLoading>true</EnableDynamicLoading>
    <RootNamespace>Monster</RootNamespace>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="cmstar.Serialization.Json" Version="1.0.0" />
    <PackageReference Include="YamlDotNet" Version="13.7.1" />
  </ItemGroup>
  <ItemGroup>
    <Compile Remove="scratch\**" />
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Remove="scratch\**" />
  </ItemGroup>
  <!-- <ItemGroup>
    <Folder Include="src\cs\" />
    <Folder Include="addons\Gui\src\" />
  </ItemGroup> -->
  <ItemGroup>
    <Reference Include="Godot">
      <HintPath>C:\apps\godot-4.2.2\GodotSharp\Api\Release\GodotSharp.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>
deathaxe commented 2 months ago

I assumed you got that update already. It may indeed make a difference as previous release shipped Omnisharp based on net471, which may not be fully compatible with .NET6+ and is known to suffer from various limitations with regards to resolving project/framework resources.

Maybe it now also runs without the explicit godot reference as - I guess - Sdk="Godot.NET.Sdk/4.2.2" already points to required assemblies.