Skip to content

Language Server Protocol (LSP) #11187

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

Draft
wants to merge 31 commits into
base: master
Choose a base branch
from
Draft

Language Server Protocol (LSP) #11187

wants to merge 31 commits into from

Conversation

mmsaki
Copy link

@mmsaki mmsaki commented Aug 1, 2025

Motivation

This PR introduces native Language Server Protocol (LSP) support to Foundry via a new forge lsp command.

The motivation behind this is to provide a first-class developer experience for Solidity projects using Foundry by exposing core compiler features (like linting, syntax errors, remappings, etc.) directly to LSP-compatible editors such as Neovim and VSCode.

Previously, users had to rely on external plugins or custom tooling to get real-time feedback while editing Solidity code. This native integration unlocks accurate diagnostics, contextual tooling, and seamless integration with Forge projects out of the box.

Solution

This PR adds:

  • A new command: forge lsp
  • A tokio-based LSP server implementation using tower-lsp
  • The server is implemented in crates/lsp, and registered as a new Forge subcommand.
  • Designed for extensibility: future support for hover, go-to-definition, and code actions is planned.
  • Initial support for forge lint notification via "textDocument/publishDiagnostics" requests with streaming updates

PR Checklist

  • Added Tests
  • Added Documentation
  • forge lint errors
  • Diagnostics (compilation errors and warnings)

Planned

  • Go-to-definition
  • Symbol search and references
  • Code completion
  • Hover information
  • Code formatting
  • Code Actions
  • Rename

@0xClandestine
Copy link
Contributor

0xClandestine commented Aug 3, 2025

Thanks for carrying the torch on this, I have wanted a solid LSP for what feels like ages. The fact that forge lint is built-in is the cherry on top, well done brother.

@mmsaki
Copy link
Author

mmsaki commented Aug 3, 2025

Thanks for carrying the torch on this, I have wanted a solid LSP for what feels like ages. The fact that forge lint built-in is the cherry on top, well done brother.

It's so underrated. Already used the LSP to remove 84 unused imports in uniswap v4-core 👀 see PR Uniswap/v4-core#979, refactoring 45 files really easy with the LSP even without all the other features.

@0xClandestine Thanks for your work on forge lint too.

@0xClandestine
Copy link
Contributor

@mmsaki Lol, I had a similar PR the other day forge lint is putting in work.

This actually solves one of my main frustrations when running forge lint on larger repos, the output is super noisy without filtering. With forge lsp you can simply navigate to your desired file and hover over concerning highlights.

Anyways, I was able to get it to work with vscode (and cursor) using the following extension and config if others are interested in trying it out:

[
  {
    "languageId": "solidity",
    "command": "forge",
    "fileExtensions": [
      ".sol"
    ],
    "args": [
      "lsp"
    ]
  }
]
image

@mmsaki
Copy link
Author

mmsaki commented Aug 4, 2025

@0xClandestine Thanks for testing it on vscode! Looks amazing 🙌.

@mmsaki mmsaki changed the title Language Server Protocol (LSP) (feat): Language Server Protocol (LSP) Aug 4, 2025
@mmsaki mmsaki changed the title (feat): Language Server Protocol (LSP) Language Server Protocol (LSP) Aug 4, 2025
pub struct LspArgs {
/// See: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#implementationConsiderations
#[arg(long)]
pub stdio: bool,
Copy link
Member

Choose a reason for hiding this comment

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

this does nothing? I think stdin/stdout should be the default

Copy link
Author

Choose a reason for hiding this comment

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

it doesn’t do anything at the moment 🤔 spec recommended to use the —stdio flag just to be explicit which transport method we use but maybe we don’t need to do it after all. I think we can remove it.

Copy link
Member

Choose a reason for hiding this comment

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

Ah I see, this is fine then

Ok(InitializeResult {
server_info: Some(ServerInfo {
name: "forge lsp".to_string(),
version: Some(env!("CARGO_PKG_VERSION").to_string()),
Copy link
Member

Choose a reason for hiding this comment

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

we can use SHORT_VERSION from foundry_common

@sambacha
Copy link
Contributor

sambacha commented Aug 4, 2025

checkout https://github.com/ferranbt/solstice/tree/main/extension for potential reference

@foundry-rs foundry-rs deleted a comment from kaxhnet Aug 4, 2025
@foundry-rs foundry-rs deleted a comment from kaxhnet Aug 4, 2025
@mmsaki
Copy link
Author

mmsaki commented Aug 5, 2025

@DaniPopes can you help with the ci failures, is there something I am doing wrong with the way I set up my tests that they keep failing in CI but locally pass. The lsp implementation depends on forge being installed and available in PATH and test stored in crates/lsp/testdata/*. Could my test failing CI because of that or a different reason?

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

Successfully merging this pull request may close these issues.

5 participants