package diag import ( "path/filepath" "strings" ) // serverSpec is how to start one language server and which files to send it. // Adding a server is adding a row to servers. type serverSpec struct { // Bin is the program looked up on PATH, and the Source the model sees. Bin string // Args are the extra arguments; most servers need "--stdio" to speak on // stdin and stdout rather than opening a socket. Args []string // Languages maps extension to the LSP languageId sent in didOpen. Languages map[string]string // Markers are the files whose nearest ancestor is the workspace root. Markers []string } // servers is the table of language servers, in the order they are tried. // // Every one is a server the language's own toolchain ships or recommends, // which is what makes it likely to be installed already. Detection is by // PATH lookup alone — no version checks, no probing — because a server that // is installed but broken shows up as a server that does not start, and that // path degrades to no diagnostics anyway. var servers = []serverSpec{ { Bin: "gopls", Languages: map[string]string{".go": "go"}, Markers: []string{"go.work", "go.mod"}, }, { Bin: "typescript-language-server", Args: []string{"--stdio"}, Languages: map[string]string{ ".ts": "typescript", ".mts": "typescript", ".cts": "typescript", ".tsx": "typescriptreact", ".js": "javascript", ".mjs": "javascript", ".cjs": "javascript", ".jsx": "javascriptreact", }, Markers: []string{"tsconfig.json", "jsconfig.json", "package.json"}, }, { Bin: "pyright-langserver", Args: []string{"--stdio"}, Languages: map[string]string{".py": "python", ".pyi": "python"}, Markers: []string{"pyproject.toml", "pyrightconfig.json", "setup.py", "setup.cfg", "requirements.txt"}, }, { Bin: "rust-analyzer", Languages: map[string]string{".rs": "rust"}, Markers: []string{"Cargo.toml"}, }, } // serverFor returns the first server that handles path's extension. func serverFor(path string) (serverSpec, bool) { ext := strings.ToLower(filepath.Ext(path)) for _, s := range servers { if _, ok := s.Languages[ext]; ok { return s, true } } return serverSpec{}, false } // languageID is the LSP languageId for path under spec. func (s serverSpec) languageID(path string) string { return s.Languages[strings.ToLower(filepath.Ext(path))] }