Skip to content
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

WIP: feat: code action to add a misspelling to the config file #72

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

mikavilpas
Copy link
Contributor

Here's a draft on what could become the solution for #12

This adds a code action like this:

image

Selecting the code action will make the lsp server to edit the configuration file. Here's what the edits look like in this repository:

image

Requesting feedback

Some things are a bit open right now, and I'd like to discuss how they should be worked on:

  1. Do you think this general idea is valid? Or should another idea be attempted?
  2. The typos configuration can be overridden on each directory level, so I started a scheme that would allow choosing the configuration file to add the misspelling to. The starting directory (typically the project root, I guess?) is always suggested - the others should be suggested only if they exist. Do you think this is a good idea?
  3. Tests obviously need to be added - I think this could be tested quite thoroughly as the existing tests looked really good.
  4. Error handling is not as clean as I would like. I have worked in some OS rust projects that use anyhow, but I couldn't find a way to use it since the tower lsp crate requires a certain error type 😓 Maybe some trait implementations could be added that could automatically handle this?
  5. Reloading the configuration has not been implemented in the project yet, as far as I can tell. I think this needs to be solved as currently the misspellings are ignored only after the LSP server has been restarted.

@mikavilpas mikavilpas marked this pull request as draft June 12, 2024 19:26
@tekumara tekumara force-pushed the main branch 3 times, most recently from 29703cd to 6111f00 Compare June 16, 2024 05:10
Copy link
Owner

@tekumara tekumara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thank you, and much how I'd approach it too! Some initial suggestions below:

/// all config files are read by typos_cli, and the settings are applied in precedence order:
///
/// <https://github.com/crate-ci/typos/blob/master/docs/reference.md>
pub fn config_files_in_project(
Copy link
Owner

@tekumara tekumara Jun 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The way config resolution works is a bit gnarly.

typos cli will implicitly look for and use the first config file it finds in this order:

  1. in the current working directory
  2. in parents of the current working directory

If a config file is provided explicitly by --config then it will be used together with the implicit file found as per the above, and its settings will take precedence over the implicit file's.

typos lsp tries to mimic this behaviour as closely as possible. It accepts an explicit config file and needs to initialise an equivalent typos cli Instance and decide what it's path (ie: current working directory) should be. For path it uses the workspace folder provided when typos lsp is initialised (or the folders change). path is used to find the first implicit config file as the cli does above. We assume this best mimics how users run typos cli locally or in CI.

NB: it is possible, particularly with nvim, to initialise typos lsp without a workspace folder (see the conditions mentioned here). In these cases the current working directory is effectively set to the root of the filesystem. This means only a config file in the root of the filesystem will be used (together with an explicit config file).

Ok, so what?

Whether or not config resolution is currently optimal (and maybe its not for the case where we don't have a workspace folder) it probably makes sense to only offer config files that would actually be used by the Instance.

So I think that would mean offering all of:

  1. the explicit config file, if it has been set.
  2. a config file based in the current Instance's path, whether or not that config file exists.
    1. (optional bonus) config files in ancestors of this path, but only if they already exist.

What do you think, does that makes sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see - this is totally reasonable. I think I misunderstood how the config files are "inherited".

I will change the logic to what you proposed in 1 and 2 👍🏻

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, now the typo can be ignored in two places:

  • in the project's configuration file
  • in the explicit configuration file
image

However, it looks like if I remove the project's configuration file, the root is resolved to my home directory. This causes "ignore foo in the project" to add the ignore to that file instead.

🤔 I'm not sure what causes this. I do have that file in my home directory, so maybe this is some weirdness in the config resolution logic.

image

Any idea what could be a more reliable way to resolve the project directory?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you using nvim-lspconfig? It's root_dir logic is:

root_dir = util.root_pattern('typos.toml', '_typos.toml', '.typos.toml'),

ie: it will include ancestors in its search for config files

}
}

Err(anyhow::anyhow!(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI - I've been using anyhow elsewhere in the project and then handling it in the LanguageServer impl like this - which seems to be working so far ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, on a quick glance that looks like anyhow can be used fine in these "worker" functions, and then unwrapped to comply with the return type expected by the language server implementation. I'll see if I can do the same, this looks quite good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did some improvement here, and it works. It also enabled some additional testing since the different concerns are no longer so tightly bound together.

Would you prefer more integration testing? Didn't look into it that much yet.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice one thank you - and yes it would be great to an integration test cover the execute command logic, if that's not too much trouble 🙏

};
}

Ok(None)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI probably the easiest way to trigger reloading the config file would be to call update_router which resets the router with new Instances (this approach does have a memory leak but that could be solved independently see #11)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good, thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reloading seems to work for me now!


std::fs::write(
&config_file_path,
toml::to_string_pretty(&config).expect("cannot serialize config"),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this appears to rewrite the entire file, removing comments and inserting empty defaults, eg:

[default]
extend-ignore-identifiers-re = []
extend-ignore-words-re = []
extend-ignore-re = []

could we do a more surgical update, that only modifies default.extend-words and preserves comments ... perhaps toml_edit would help?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea, will definitely do this. I didn't realize comments get removed too, that's not good 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toml_edit worked nicely, and now the config file is preserved when ignoring a typo.

@mikavilpas mikavilpas force-pushed the add-misspelling-to-config-file branch 3 times, most recently from 5e8403a to ef9a6ad Compare June 21, 2024 10:04
@Chaitanyabsprip
Copy link

any update/eta on this?

@mikavilpas
Copy link
Contributor Author

I kinda forgot about this for a long time... But I think I could still finish it.

To do this, I think the following can be worked on:

  • There are some open comment threads above that need to be solved
  • Additional testing would be welcomed. @Chaitanyabsprip if you have the time, let me know and I can explain how I tested this

@mikavilpas
Copy link
Contributor Author

Also rebased to the latest main branch now.

@tekumara
Copy link
Owner

tekumara commented Sep 11, 2024

My apologies I missed the unanswered questions 🤦 and thank you @mikavilpas for offering to finish this! would be great to get this merged

@Chaitanyabsprip
Copy link

I will help you test this PR. I would require help in setting it up with my neovim configuration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants