Skip to content
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

Add support for a compile database file not at the root of a workspace #915

Merged

Conversation

GeorgeLyon
Copy link
Contributor

Introduce a new command-line flag (--compile-db-search-path) to sourcekit-lsp, which can be used to specify which subdirectories in a workspace should be searched for a clangd-style compile database (compile_commands.json or compile_flags.txt). Originally, I was going to add a clangd-like --compile-commands-dir flag, but upon further investigation decided this wasn't a good approach, as sourcekit-lsp supports multiple workspaces and clangd does not. In a world with multiple workspaces it does not make sense to specify a single absolute path to a compile-database, so instead I opted for a set of relative search paths, which apply to all databases managed by a particular instance of sourcekit-lsp.

Sources/SKCore/CompilationDatabase.swift Show resolved Hide resolved
@@ -55,7 +55,7 @@ public final class SKSwiftPMTestWorkspace {
/// Connection to the language server.
public let testClient: TestSourceKitLSPClient

/// When `testServer` is not `nil`, the workspace will be opened in that server, otherwise a new server will be created for the workspace
/// When `testClient` is not `nil`, the workspace will be opened in that client's server, otherwise a new client will be created for the workspace
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not really related, but I was confused by the wording here when browsing the codebase.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, I recently changed testServer to testClient and looks like I forgot that comment. Thanks for updating it.

@GeorgeLyon GeorgeLyon marked this pull request as ready for review October 20, 2023 19:59
var compilationDatabaseSearchPaths = try! [
// These defaults match the behavior of clangd
RelativePath(validating: "."),
RelativePath(validating: "build"),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It may make sense to pull these out and make the search paths "additional" so the defaults persist even in the presence of custom search paths.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, I think that would make sense. IMO the search precedence should be user-defined search paths, ., build.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

Copy link
Collaborator

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Nice. Thanks for opening a PR for this so quickly 🤩.

I would like to think about the naming of the command line option a little bit more. I’m not unconditionally happy with it but don’t have any better ideas either, so maybe it’s fine. @bnbarham Maybe you’ve got an opinion here as well.

Sources/SKCore/CompilationDatabase.swift Show resolved Hide resolved
Comment on lines 81 to 90
try?
(JSONCompilationDatabase(directory: $0, fileSystem)
?? FixedCompilationDatabase(directory: $0, fileSystem))
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the initializers now return nil when the file doesn’t exist, I think we no longer need to do try? here and can change it to try. That way we don’t silently ignore errors anymore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I looked into this but it is actually a bigger change than it seems as the throws will propagate all the way up to things like the BuildSystem protocol, so you may want to do that separately (if at all). In the meantime I made it try! since decoding errors should be very infrequent and shouldn't fail silently.

@@ -55,7 +55,7 @@ public final class SKSwiftPMTestWorkspace {
/// Connection to the language server.
public let testClient: TestSourceKitLSPClient

/// When `testServer` is not `nil`, the workspace will be opened in that server, otherwise a new server will be created for the workspace
/// When `testClient` is not `nil`, the workspace will be opened in that client's server, otherwise a new client will be created for the workspace
Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh, I recently changed testServer to testClient and looks like I forgot that comment. Thanks for updating it.

@@ -137,6 +150,18 @@ struct SourceKitLSP: ParsableCommand {
)
var indexPrefixMappings = [PathPrefixMapping]()

@Option(
name: .customLong("compilation-db-search-path", withSingleDash: false),
parsing: .unconditionalSingleValue,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Any reason why you decided to choose unconditionalSingleValue here instead of the default singleValue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No strong reason, though now that I think about it singleValue might be better as --compilation-db-search-path --some-other-flag may have a better compilation error.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That’s what I thought as well.

Comment on lines 46 to 51
let compilationDatabase = try JSONCompilationDatabase(
file: AbsolutePath(validating: compilationDatabaseUrl.path)
)!
let newCommands = compilationDatabase.allCommands.map {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you use XCTUnwrap instead of ! here so the test doesn’t crash if the database is nil?

@@ -137,6 +150,18 @@ struct SourceKitLSP: ParsableCommand {
)
var indexPrefixMappings = [PathPrefixMapping]()

@Option(
name: .customLong("compilation-db-search-path", withSingleDash: false),
Copy link
Collaborator

Choose a reason for hiding this comment

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

withSingleDash defaults to false, so we don’t need to specify it.

var compilationDatabaseSearchPaths = try! [
// These defaults match the behavior of clangd
RelativePath(validating: "."),
RelativePath(validating: "build"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, I think that would make sense. IMO the search precedence should be user-defined search paths, ., build.

Sources/sourcekit-lsp/SourceKitLSP.swift Outdated Show resolved Hide resolved
@bnbarham
Copy link
Contributor

I would like to think about the naming of the command line option a little bit more. I’m not unconditionally happy with it but don’t have any better ideas either, so maybe it’s fine. @bnbarham Maybe you’ve got an opinion here as well.

No particularly strong ones. compile-commands-search-path maybe?

@GeorgeLyon
Copy link
Contributor Author

No particularly strong ones. compile-commands-search-path maybe?

This confused me when I was looking into this. I was used to "compile_commands.json", but the term "compile database" is more accurate (and what is used in the sourcekit-lsp code itself), since you could use "compile_flags.txt" as well. If we were being 100% pedantic (and we are all Swift developers, no? 😜) it would be something like "clang-style-compile-database-search-path", but even that may not be 100% correct. I think the current form is a good balance between being specific and being correct and not being too wordy, and the help text is pretty explicit which helps.

Sources/SKCore/CompilationDatabase.swift Outdated Show resolved Hide resolved
Sources/SKCore/CompilationDatabase.swift Outdated Show resolved Hide resolved
Sources/SKCore/CompilationDatabase.swift Outdated Show resolved Hide resolved
Sources/SKCore/CompilationDatabase.swift Outdated Show resolved Hide resolved
@@ -137,6 +150,18 @@ struct SourceKitLSP: ParsableCommand {
)
var indexPrefixMappings = [PathPrefixMapping]()

@Option(
name: .customLong("compilation-db-search-path", withSingleDash: false),
parsing: .unconditionalSingleValue,
Copy link
Collaborator

Choose a reason for hiding this comment

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

That’s what I thought as well.

@ahoppen
Copy link
Collaborator

ahoppen commented Oct 21, 2023

No particularly strong ones. compile-commands-search-path maybe?

I think compilation-db-search-path is better because it also handles compile_flags.txt. For the lack of better ideas, let’s leave it for now.

Copy link
Collaborator

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

I have a couple more minor formatting comments inline.

Copy link
Collaborator

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Just one more note on the doc comments.

Also: Could you squash your commits? It makes for a nicer git history.

let path = directory.appending(component: "compile_flags.txt")
try self.init(file: path, fileSystem)
}

public init(file: AbsolutePath, _ fileSystem: FileSystem = localFileSystem) throws {
/// Loads the compilation database from `file`
/// returns: `nil` if the file does not exist
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you also update the other returns: lines to use docc markup?

@GeorgeLyon GeorgeLyon force-pushed the dev/george/compilation-db-search-paths branch from 65b2571 to 170b44b Compare October 21, 2023 05:17
@GeorgeLyon
Copy link
Contributor Author

Updated comments, and squash-force0pushed... do you guys not use GitHub's "squash and merge"?

@ahoppen
Copy link
Collaborator

ahoppen commented Oct 23, 2023

Updated comments, and squash-force0pushed... do you guys not use GitHub's "squash and merge"?

I prefer not to squash and merge for the reasons outlined here: https://github.com/apple/swift-syntax/blob/main/CONTRIBUTING.md#authoring-commits

Copy link
Collaborator

@ahoppen ahoppen left a comment

Choose a reason for hiding this comment

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

Nice. Let’s get this in 🚢

@ahoppen
Copy link
Collaborator

ahoppen commented Oct 23, 2023

@swift-ci Please test

@ahoppen
Copy link
Collaborator

ahoppen commented Oct 23, 2023

@swift-ci Please test Windows

@ahoppen ahoppen merged commit 645b511 into apple:main Oct 24, 2023
3 checks passed
@GeorgeLyon GeorgeLyon deleted the dev/george/compilation-db-search-paths branch October 24, 2023 14:45
@GeorgeLyon
Copy link
Contributor Author

Thanks for working with me on this @ahoppen!

@ahoppen
Copy link
Collaborator

ahoppen commented Oct 24, 2023

Thanks for your contribution!

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

Successfully merging this pull request may close these issues.

None yet

3 participants