-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Try to get contextive definitions if not defined in the config #49
Conversation
Hi @erikjuhani, thanks so much for this contribution! You have the honour of being the first community code contribution to Contextive 😍! Unfortunately this means you are somewhat paving the path with me here - as I haven't yet properly setup community contribution guidelines or any automated pr checks - so I appreciate your support & patience as we work out together how to get this improvement into a release :) Also, well done working out this solution given the limited developer documentation! TestsThe good news is that although there are no pr checks setup yet, I have cloned your fork and run the tests locally and I'm happy that all existing tests are still passing. However, I have been using TDD to build contextive, and while I won't insist contributors use TDD, I would like to ensure all meaningful features/scenarios are represented in a test. In this case, I think a new test case in Could you please take a look at that and see if you can work out how to construct an equivalent situation in that test as to how the neovim lsp client will present to the server? Ideally the test should fail with the current official release and pass with your release. If it's not clear let me know and we can setup a pairing session to work through it together. DesignIt seems that this change makes contextive language server more resilient if the client does not provide the contextive.path configuration setting. In VsCode (which has been my focus so far), the setting is defined in the extension - with a default value. So the client has always provided a value, either this default or the user configured value. Now that I see how neovim is likely to work it makes me realise that the default value should be defined in the server (as you have done) but now we have a potential conflict between the server default and the vscode extension default. I will take a look at the vscode extension to see how best to ensure that the new server default is used consistently. How would this neovim configuration work if the repository had the definitions file NOT in the default location? In vscode there is a settings.json file that overrides the default config value for the path. This is helpful as it's in the repository so all devs on the team get the same setting. Is there a way to do something similar with neovim? Official Neovim supportDo you have a recommendation on how we can simplify life for other neovim users? A few questions come to mind:
Thanks!Thanks again, look forward to your thoughts on the above :) |
Thanks @chrissimon-au for the detailed answer! I hope I didn't split my answers too much, but I wanted to keep the context small.
You're welcome! I'm delighted to be the first community contributer to Contextive. 😊
I understand! I hope I can help you to setup the requirements and expectations. I agree that PR checks would be in order—firstly to ease the maintainer burden, but also give more confidence to the contributor itself.
Thanks! It was quite easy to setup. Probably due to
In hindsight, I should have mentioned that I ran all the tests, and they passed before opening this PR (sorry about that 🙁). I also conducted manual testing with my Neovim setup. Also I think it would be great to provide specific steps for setting up the development environment for the Contextive VSCode extension, as that is something I did not test locally.
Perhaps this is something worthwhile to mention in the upcoming contribution guidelines! 😉
I'll take a look at those tests and add this particular scenario, thank you for pointing this out!
Yes that was my idea, to make the Contextive language-server easier to use, so it would work with less configuration. For example I just couldn't get the
That is indeed true. I'd propose that the language server acts as the source of truth and the extension by default should use the default from the language server instead. That way we centralize the logic, which affects all the clients that use the Contextive language server.
In neovim there's a separate server settings that can be applied, as an example my gopls setup: lspconfig.gopls.setup {
on_attach = on_attach,
capabilities = capabilities,
cmd = { "gopls", "serve" },
settings = {
gopls = {
analyses = {
unusedparams = true,
},
staticcheck = true,
linksInHover = false,
codelenses = {
generate = true,
gc_details = false,
regenerate_cgo = true,
tidy = false,
upgrade_depdendency = true,
vendor = true,
},
usePlaceholders = true,
},
},
} For some reason I couldn't get this particular setting to work for Contextive, specifically the In my mind, in order for this to work with other editors. Contextive would need to provide a separate runtime configuration file ( As far as I know there is no similar option for neovim out of the box like the settings.json in vscode.
I obtained the language-server by building it on my own machine, as there's no artifacts available currently, and yeah I'd say having the github release artifacts for different operating systems and architectures would be a good starting point! After that I would consider including the language server in different package managers like brew, apt, nix, etc.
I would approach this in a tool agnostic way! So the setup could serve multiple different editors. I guess there could be some mention or example configuration for neovim, but maybe a focus for now could be to provide a way to easily setup the Contextive language server locally by building it youself and adding it to system path for example. Definitely I'd consider a contribution to nvim-lspconfig and also (mason-registry)[https://github.com/mason-org/mason-registry], which would make it a breeze to install in neovim, but before those contributions I think the language-server should be available as a separate artifact in the github releases! Example configuration from the mason registry: https://github.com/mason-org/mason-registry/blob/main/packages/arduino-language-server/package.yaml |
Hi @erikjuhani thanks for the thorough response! Based on this conversation I've setup the following issues:
I'll be taking a look at #50 later this week, but will wait until #49 is merged before doing #51. Then, if you're open to it, your assistance with #33 would be appreciated! Let me know how you go with adding tests, look forward to getting this merged :) |
Hey! Sorry there was a bit of delay in my answer. I did try to add these particular test cases however:
Unfortunately I can’t wrap my head around how those tests should be implemented, due to current ones being quite complex and my knowledge of dotnet and fsharp limited. I tried to make a proper end to end test for initializing by setting up a temporary path and definitions file. That however broke tests with errors that were hard for me to interpret. I have one idea though, make the language server accept options interface that can have for example definitionsFileExists function or something like that. What do you think? Do you have already an idea how those initialization tests should be implemented? By the way we can also get the language server from nuget in mason-registry. Perhaps that could be to consider as well? I’ll take a look at #33 after this PR gets merged! |
Hi @erikjuhani - yes, unfortunately this is probably a tough one for a newcomer to F#, and also a newcomer to the LSP and in particular the OmniSharp LSP Client that we are using in the tests! Not to mention, there are some F# abstractions I've added around the TestClient... In principal, this new test should follow the pattern of the existing tests:
We cannot inject anything into the language server, because the language server is invoked by the language client (TestClient) and then interacted with via the LSP messages. So the server must be able to configure itself only using information it has access to via the LSP messages. The following test should test the scenario where there is a workspace folder defined but no contextive path defined in the settings (we configure a
However, this test doesn't pass with your current implementation - because of line 46:
The tests are executing in the build folder, so the workspace at the time of running the tests is a folder that does not contain the We could construct a test fixture that simulates that, but for this purpose I'm not sure it's necessary. The existing logic just retrieves the setting value from config, it does not assert on the existence of the file - this is done later when actually loading the file. For consistency, I think we can think of your new method as just constructing the appropriate 'default' setting value - where we expect it should be. And then as it currently works, the file loader which runs later can handle the scenario of the file not existing. To that end, I'd suggest that the naming of some of the constants and methods you've added should indicate that this part is loading the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As noted on the PR comment, a few suggestions to clear up the purpose of the new methods and to make it easier to test.
@@ -12,6 +12,12 @@ open Serilog | |||
open System.IO | |||
open System.Reflection | |||
|
|||
[<Literal>] | |||
let contextiveFolderName = ".contextive" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaultContextiveFolderName
?
let contextiveFolderName = ".contextive" | ||
|
||
[<Literal>] | ||
let contextiveDefinitionsFileName = "definitions.yml" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
defaultContextiveDefinitionsFileName
?
else | ||
None | ||
|
||
let private getContextiveDefinitionsPath (workspaceFolder: string) = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getDefaultContextiveDefinitionsPath
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is now simply:
[<Literal>]
let defaultContextiveDefinitionsPath = ".contextive/definitions.yml"
|
||
let contextiveFolder = workspaceFolder |> combine contextiveFolderName | ||
|
||
if Directory.Exists contextiveFolder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can remove this check - constructing the default setting value doesn't need to check it's validity. Other parts of the codebase already have to handle the scenario that a configured location doesn't exist.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, I'm not sure we need to combine with the workspaceFolder at all.
The method below, (getConfig
) usually returns a relative path from the setting value supplied by VsCode. So the new getDefaultContextiveDefinitionsPath
can just return the relative path as well. Combining with the workspace folder can then happen later in the same way for both cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the way sorry for rebasing this already, the comments are no longer pointing to the right place and in hindsight I should have used fixup commits instead and rebase as the last operation.
I changed this to just be a literal value let defaultContextiveDefinitionsPath = ".contextive/definitions.yml"
To make things easier, I've also just pushed a new test on You can rebase from |
d20d1dc
to
43260fc
Compare
…it's not specified in the configuration. This enhancement to the language server allows an empty path configuration to fall back to a default location: `.contextive/definitions.yml`. Introduce a new literal value called `defaultContextiveDefinitionsPath` to serve as a fallback for the "path" configuration when it's not set. Modify the test "Server fails to load contextive file with an error when no configuration is supplied" in `InitializationTests` to align with the new functionality.
Yeah! I'm getting there, I hope! 😅 It's much clearer now after your explanation and example of the test. Thanks for that, it really helped me to move forward with the changes! I think it is correct now. 🤞
Yeah I agree! Now I understand the purpose better and I hope the changes I did reflect exactly what you mean. I removed the two new default constants and merged them as one, to simplify, and also that's what we want anyway. |
I did the changes you suggested and rebased the fork with the newest upstream main. Thank you again for the detailed explanation! Like I said it really helped me move forward, something definitely clicked after seeing the example test you provided and reading the steps and how to LSP should be treated. |
Thanks @erikjuhani - this looks great, I've merged the PR now and the github actions are running. I've completed #50 earlier today, so the next release should publish the language server as an independent binary to the github release files, and with this change it should be a language server that 'just works' with neovim 🚀 ! |
Hello @chrissimon-au! Firstly thanks for the great concept (and the language-server that comes with it!).
Background
This concept sounds really useful, as the knowledge bank can be stored in one file and work across different file formats. I can see multiple use cases for this. As an avid user of neovim, I was eager to try this language server with my setup. Unfortunately, probably due to my lack of knowledge in the realm of LSP (Language Server Protocol), I couldn't get it to work right out of the box. I kept encountering the
missing contextive.path
error. As a result, I decided to make the user experience a bit easier, meaning less necessary configuration, so that "it just works".Neovim setup
I'm using the neovim builtin lsp with lspconfig, and this is my working setup for contextive language-server:
The above language-server configuration is attached to all buffers / all filetypes.
Implementation
This is an enhancement to the language server that enables it to automatically use the contextive definitions path if it's found in the workspace, and if the
contextive.path
configuration is not defined.Add a new function called
getContextiveDefinitionsPath
, which returns the contextive definitions path if it exists in the workspace.By default, the language-server uses the
contextive.path
defined by the caller.And this is how it works and looks like in the sample repository: