diff --git a/cmd/ftl/cmd_build.go b/cmd/ftl/cmd_build.go index 01f5857fc2..e6eec2ea02 100644 --- a/cmd/ftl/cmd_build.go +++ b/cmd/ftl/cmd_build.go @@ -19,7 +19,7 @@ type buildCmd struct { func (b *buildCmd) Run(ctx context.Context, projConfig projectconfig.Config) error { client := rpc.ClientFromContext[ftlv1connect.ControllerServiceClient](ctx) if len(b.Dirs) == 0 && len(b.External) == 0 { - b.Dirs = projConfig.ModuleDirsOrDefault() + b.Dirs = projConfig.AbsModuleDirsOrDefault() b.External = projConfig.ExternalDirs } if len(b.Dirs) == 0 && len(b.External) == 0 { diff --git a/cmd/ftl/cmd_dev.go b/cmd/ftl/cmd_dev.go index 6de51bb3c0..c964f7ff2a 100644 --- a/cmd/ftl/cmd_dev.go +++ b/cmd/ftl/cmd_dev.go @@ -28,7 +28,7 @@ type devCmd struct { func (d *devCmd) Run(ctx context.Context, projConfig projectconfig.Config) error { if len(d.Dirs) == 0 && len(d.External) == 0 { - d.Dirs = projConfig.ModuleDirsOrDefault() + d.Dirs = projConfig.AbsModuleDirsOrDefault() d.External = projConfig.ExternalDirs } if len(d.Dirs) == 0 && len(d.External) == 0 { diff --git a/common/projectconfig/merge.go b/common/projectconfig/merge.go index da7b4181c6..baf64b7445 100644 --- a/common/projectconfig/merge.go +++ b/common/projectconfig/merge.go @@ -1,5 +1,9 @@ package projectconfig +import ( + "path/filepath" +) + // Merge configuration files. // // Config is merged left to right, with later files taking precedence over earlier files. @@ -11,7 +15,24 @@ func Merge(paths ...string) (Config, error) { return config, err } config = merge(config, partial) + + // Make module-dirs absolute to mimic the behavior of the CLI + config.absModuleDirs = []string{} + for _, dir := range config.ModuleDirs { + if !filepath.IsAbs(dir) { + absDir := filepath.Join(filepath.Dir(path), dir) + config.absModuleDirs = append(config.absModuleDirs, absDir) + } else { + config.absModuleDirs = append(config.absModuleDirs, dir) + } + } + + // If no module-dirs are defined, default to the directory of the config file + if len(config.absModuleDirs) == 0 { + config.absModuleDirs = []string{filepath.Dir(path)} + } } + return config, nil } diff --git a/common/projectconfig/projectconfig.go b/common/projectconfig/projectconfig.go index dfa65c3b19..dce1180ef6 100644 --- a/common/projectconfig/projectconfig.go +++ b/common/projectconfig/projectconfig.go @@ -32,16 +32,12 @@ type Config struct { ExternalDirs []string `toml:"external-dirs"` Commands Commands `toml:"commands"` FTLMinVersion string `toml:"ftl-min-version"` + absModuleDirs []string } -// ModuleDirsOrDefault returns the module-dirs field from the ftl-project.toml, unless +// AbsModuleDirsOrDefault returns the absolute path for the module-dirs field from the ftl-project.toml, unless // that is not defined, in which case it defaults to the root directory. -func (c Config) ModuleDirsOrDefault() []string { - if len(c.ModuleDirs) > 0 { - return c.ModuleDirs - } - return []string{"."} -} +func (c Config) AbsModuleDirsOrDefault() []string { return c.absModuleDirs } // ConfigPaths returns the computed list of configuration paths to load. func ConfigPaths(input []string) []string { @@ -136,6 +132,7 @@ func loadFile(path string) (Config, error) { } return Config{}, fmt.Errorf("unknown configuration keys: %s", strings.Join(keys, ", ")) } + return config, nil } diff --git a/lsp/lsp.go b/lsp/lsp.go index 0c9e2ea234..81dfa2cd0f 100644 --- a/lsp/lsp.go +++ b/lsp/lsp.go @@ -78,9 +78,12 @@ func (s *Server) post(err error) { errUnspecified := []error{} // Deduplicate and associate by filename. - for _, err := range ftlErrors.DeduplicateErrors(ftlErrors.UnwrapAll(err)) { + for _, e := range ftlErrors.DeduplicateErrors(ftlErrors.UnwrapAll(err)) { + if !ftlErrors.Innermost(e) { + continue + } var ce *schema.Error - if errors.As(err, &ce) { + if errors.As(e, &ce) { filename := ce.Pos.Filename if _, exists := errByFilename[filename]; !exists { errByFilename[filename] = errSet{}