| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package langserver |
| |
| import ( |
| "context" |
| "fmt" |
| "path/filepath" |
| |
| "github.com/sourcegraph/go-lsp" |
| "github.com/sourcegraph/jsonrpc2" |
| |
| "fidl-lsp/analysis" |
| ) |
| |
| // clientConfig are the configuration settings from the LSP client. These are |
| // relevant to the Analyzer. If they are left unset, the Analyzer uses its |
| // defaults. |
| type clientConfig struct { |
| FidlProject string `json:"fidlProject,omitempty"` |
| BuildRoot string `json:"projectRoot,omitempty"` |
| Tools toolsConfig `json:"tools,omitempty"` |
| } |
| |
| type toolsConfig struct { |
| Compiler string `json:"compiler,omitempty"` |
| Linter string `json:"linter,omitempty"` |
| Formatter string `json:"formatter,omitempty"` |
| } |
| |
| func (h *LangHandler) requestConfiguration(ctx context.Context, conn *jsonrpc2.Conn) { |
| go func() { |
| var cfg []clientConfig |
| conn.Call( |
| ctx, |
| "workspace/configuration", |
| lsp.ConfigurationParams{ |
| Items: []lsp.ConfigurationItem{{Section: "fidl"}}, |
| }, |
| &cfg, |
| ) |
| if len(cfg) < 1 { |
| h.log.Printf("received invalid configuration settings. unable to update\n") |
| return |
| } |
| h.updateConfig(ctx, conn, cfg[0]) |
| }() |
| } |
| |
| func (h *LangHandler) handleDidChangeConfiguration(ctx context.Context, conn *jsonrpc2.Conn, params lsp.DidChangeConfigurationParams) { |
| h.log.Printf("updating with new config settings: %#v", params.Settings) |
| |
| cfg, ok := params.Settings.([]clientConfig) |
| if !ok { |
| h.log.Printf("received invalid configuration settings. unable to update\n") |
| return |
| } |
| if len(cfg) < 1 { |
| h.log.Printf("received invalid configuration settings. unable to update\n") |
| return |
| } |
| h.updateConfig(ctx, conn, cfg[0]) |
| } |
| |
| func (h *LangHandler) updateConfig(ctx context.Context, conn *jsonrpc2.Conn, cfg clientConfig) { |
| if cfg.FidlProject != "" { |
| h.LoadFidlProject(ctx, conn, cfg.FidlProject) |
| |
| // If the BuildRoot is unset, set it to the directory containing |
| // `FidlProject` |
| if cfg.BuildRoot == "" { |
| cfg.BuildRoot = filepath.Dir(cfg.FidlProject) |
| } |
| } |
| |
| h.analyzer.SetConfig(analysis.Config{ |
| BuildRootDir: cfg.BuildRoot, |
| FidlcPath: cfg.Tools.Compiler, |
| FidlLintPath: cfg.Tools.Linter, |
| FidlFormatPath: cfg.Tools.Formatter, |
| }) |
| } |
| |
| // LoadFidlProject attempts to read in the fidl_project.json file at |
| // `fidlProjectPath`, and if it can't, it displays an error dialog in the client |
| // so the user can try to regenerate the file. |
| func (h *LangHandler) LoadFidlProject(ctx context.Context, conn *jsonrpc2.Conn, fidlProjectPath string) { |
| fidlProject, err := analysis.LoadFidlProject(fidlProjectPath) |
| if err != nil { |
| h.log.Printf("failed to parse fidl_project.json at `%s`: %s\n", fidlProjectPath, err) |
| h.Notify(ctx, conn, "window/showMessage", lsp.ShowMessageParams{ |
| Type: lsp.MTError, |
| Message: fmt.Sprintf( |
| "Failed to load fidl_project.json at '%s'.\n"+ |
| "To generate this file, run "+ |
| "`fx gen && fx build build/fidl:validate_fidl_project_json`. "+ |
| "Alternatively, custom path can be specified in settings.", |
| fidlProjectPath, |
| ), |
| }) |
| } |
| h.analyzer.ImportCompiledLibraries(fidlProject) |
| } |