ollie/tools/lsp/adapter.go

119 lines
2.8 KiB
Go

package lsp
import (
"path/filepath"
"ollie/util"
)
// Adapter describes an LSP server for a specific language.
type Adapter struct {
Name string
Extensions []string
RootMarkers []string
Cmd []string
InitOptions map[string]any
}
// WorkspaceRoot finds the project root for a file using this adapter's markers.
func (a *Adapter) WorkspaceRoot(file, fallback string) string {
return FindRoot(file, a.RootMarkers, fallback)
}
// Adapters is the registry of known LSP adapters.
var Adapters = []*Adapter{
{
Name: "gopls",
Extensions: []string{".go"},
RootMarkers: []string{"go.work", "go.mod"},
Cmd: []string{"gopls", "serve"},
InitOptions: map[string]any{
"usePlaceholders": true,
"staticcheck": true,
"gofumpt": true,
},
},
{
Name: "clangd",
Extensions: []string{".c", ".h", ".cc", ".cpp", ".cxx", ".hpp", ".hxx"},
RootMarkers: []string{"compile_commands.json", "CMakeLists.txt", ".clangd", "Makefile"},
Cmd: []string{"clangd", "--background-index"},
InitOptions: nil,
},
{
Name: "intelephense",
Extensions: []string{".php"},
RootMarkers: []string{"composer.json", ".git"},
Cmd: []string{"intelephense", "--stdio"},
InitOptions: nil,
},
}
// extMap builds on first call.
var extMap map[string]*Adapter
func buildExtMap() {
extMap = make(map[string]*Adapter, 16)
for _, a := range Adapters {
for _, ext := range a.Extensions {
extMap[ext] = a
}
}
}
// Detect returns the adapter for a file path based on extension, or nil.
func Detect(filepath string) *Adapter {
if extMap == nil {
buildExtMap()
}
ext := filepathExt(filepath)
return extMap[ext]
}
func filepathExt(path string) string {
return filepath.Ext(path)
}
// FileURI converts an absolute path to a file:// URI.
func FileURI(path string) string {
abs, err := filepath.Abs(path)
if err != nil {
abs = path
}
return "file://" + abs
}
// URIToPath converts a file:// URI to a local path.
func URIToPath(uri string) string {
const prefix = "file://"
if len(uri) > len(prefix) && uri[:len(prefix)] == prefix {
return uri[len(prefix):]
}
return uri
}
// LanguageID returns the LSP language identifier for a file extension.
func LanguageID(path string) string {
ext := filepath.Ext(path)
m := map[string]string{
".go": "go", ".c": "c", ".h": "c", ".cc": "cpp", ".cpp": "cpp",
".cxx": "cpp", ".hpp": "cpp", ".hxx": "cpp", ".php": "php",
".py": "python", ".js": "javascript", ".ts": "typescript",
".rs": "rust", ".java": "java", ".rb": "ruby",
}
if id, ok := m[ext]; ok {
return id
}
return "plaintext"
}
// SockPath returns the path to the bridge Unix socket.
func SockPath() string {
return filepath.Join(util.RuntimeDir(), "ollie-lsp.sock")
}
// PidPath returns the path to the bridge PID file.
func PidPath() string {
return SockPath() + ".pid"
}