-
Notifications
You must be signed in to change notification settings - Fork 302
Handle Markdown and Tutorial files in textDocument/doccDocumentation #1959
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
Handle Markdown and Tutorial files in textDocument/doccDocumentation #1959
Conversation
@swift-ci please test |
1 similar comment
@swift-ci please test |
@swift-ci please test windows platform |
aa29b89
to
2530549
Compare
@swift-ci please test |
@swift-ci please test windows platform |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this @matthewbastien 🙏🏽
I left some comments inline. On a layering level, I think we should not build the DocCDocumentation
module at all if we are building SourceKit-LSP without docc support. That way DocCDocumentation
doesn’t need any #if
statements and we should be able to eliminate all the protocols. Instead the code in the SourceKitLSP
module would need to be guarded by #if
statements.
Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift
Outdated
Show resolved
Hide resolved
Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift
Outdated
Show resolved
Hide resolved
Sources/DocCDocumentation/BuildSystemIntegrationExtensions.swift
Outdated
Show resolved
Hide resolved
Sources/DocCDocumentation/BuildSystemIntegrationExtensions.swift
Outdated
Show resolved
Hide resolved
// Do a lookup to find the top level symbol | ||
let topLevelSymbolName = components.removeLast().name | ||
var topLevelSymbolOccurrences = [SymbolOccurrence]() | ||
index.forEachCanonicalSymbolOccurrence(byName: topLevelSymbolName) { symbolOccurrence in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we resolve overloads here? Eg. if you have foo(x: Int)
and foo(y: Int)
in your module, how do we know which one to pick?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using LinkCompletionTools
gets us 80% of the way there for disambiguations, but currently this PR does not handle function overloads. We'll need a way to get the function parameter names from the index. I'll open up a separate PR for this after this one gets merged.
@swift-ci please test |
bbaa6e3
to
6306675
Compare
@swift-ci please test |
1 similar comment
@swift-ci please test |
22842b3
to
2bdc4c8
Compare
@swift-ci please test |
@swift-ci please test windows platform |
c75e2ab
to
3da95ef
Compare
@swift-ci please test |
@swift-ci please test windows platform |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Architecturally this looks good to me now, with one concern about the cursor info request on the helper document, the rest should be smaller comments. Also, just for my own sake, the following comments are still open from the last review:
- Handle Markdown and Tutorial files in textDocument/doccDocumentation #1959 (comment)
- Handle Markdown and Tutorial files in textDocument/doccDocumentation #1959 (comment)
- Handle Markdown and Tutorial files in textDocument/doccDocumentation #1959 (comment)
- Handle Markdown and Tutorial files in textDocument/doccDocumentation #1959 (comment)
Sources/BuildServerProtocol/Messages/BuildTargetSourcesRequest.swift
Outdated
Show resolved
Hide resolved
Sources/BuildServerProtocol/Messages/BuildTargetSourcesRequest.swift
Outdated
Show resolved
Hide resolved
/// | ||
/// This patches the arguments by searching for the argument corresponding to | ||
/// `originalFile` and replacing it. | ||
package func patching(newFile: String, originalFile: DocumentURI) -> FileBuildSettings { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might have missed it but I didn’t find a use of the patching
method taking a String
. Do we need it? Also, I didn’t find any use of patching
in your code, so I think this can continue to be internal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a remnant I forgot to clean up from an experiment I was doing locally. It's being used by cursorInfoFromDisk()
now.
Sources/DocCDocumentation/BuildSystemIntegrationExtensions.swift
Outdated
Show resolved
Hide resolved
Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift
Outdated
Show resolved
Hide resolved
Sources/SourceKitLSP/Documentation/DoccDocumentationHandler.swift
Outdated
Show resolved
Hide resolved
|
||
// If the document is not opened in the DocumentManager then send an open | ||
// request to sourcekitd. | ||
guard documentManager.openDocuments.contains(uri) else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I just noticed that DoccDocumentationRequest
is not covered in MessageHandlingDependencyTracker.swift. We definitely need to fix that.
This approach is racy. Consider the following two scenarios:
- We get a documentation request for a tutorial document. The .swift file for the symbol is open so we pass this check. Now, before we execute the cursor info request the clients sends us a
textDocument/didClose
notification for the symbol’s .swift file. UnlesstextDocument/doccDocumentation
is a workspace request, we can handle thedidClose
for the .swift file concurrently to the documentation request for the tutorial file because they don’t affect the same document. Now, the document will be closed in sourcekitd and the cursor info will fail. - We get a documentation request for a tutorial document. The .swift file for the symbol is not open so we open it here. Before we finish this request, we get a
textDocument/didOpen
for the symbol’s document, which triggers another open of the document. Then we close the document from here, which will close it in sourcekitd and now the user can’t get any functionality in the .swift document they opened in the editor unless they close and re-open it.
For other requests that use cursor info like hover, this is not an issue because they are .documentRequest
, which cannot be handled simultaneously to .documentUpdate
requests like didOpen
or didClose
.
I think there are two solutions here:
- Implement some kind of reference-counting-like logic by which we can say that we are interested in this document to prevent it from getting closed in sourcekitd. This will definitely be non-trivial to get right because you also need to consider cases like us opening a helper document with on-disk contents here and then a user sending a
textDocument/didOpen
request with contents that don’t match the on-disk contents. - We open a helper document that has a prefix like
DocumentSymbols:
here. If we can ensure that this document name is not getting used by anything else and that there will never be overlapping requests that open the same document, this will be safe because we have exclusive ownership of that helper document. One thing to consider here is that we could have multiple concurrenttextDocument/doccDocumentation
requests that could try and open the same helper document. One advantage of this approach is that we could also always open the on-disk contents, which means that in-memory modifications of the file can’t shift the positions of the symbol.
All of this would need to be handled by a separate cursorInfo
function and it can’t be implicit in the current cursorInfo
function, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a new cursorInfoFromDisk()
function that will always load the DocumentSnapshot
from disk for situations where a request needs to access a document that it isn't directly tied to. It uses a UUID prefix to avoid name collisions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, DoccDocumentationRequest
is a TextDocumentRequest
which is handled already by MessageHandlingDependencyTracker
.
fea9d88
to
c37c596
Compare
f4b086e
to
3610593
Compare
@swift-ci please test |
@swift-ci please test windows platform |
This way all dependencies on the `docc` libraries are wrapped inside the `DocCDocumentation` module.
… occurrence The index refers to on-disk locations and since the cursor info below also operates on the on-disk contents, we should use the on-disk contents of the file to convert the symbol occurrence location to a `Position`.
The value isn’t needed here and the calls become cleaner if only the key is passed.
The exact sorting here should not matter and `<` is the standard choice here instead of `>=`, reducing distraction.
The function isn’t used anymore
This overload is no longer needed.
@swift-ci please test |
@swift-ci Please test macOS |
@swift-ci Please test Windows |
@swift-ci please test |
@swift-ci please test Windows |
@swift-ci please test Linux |
…ntation Handle Markdown and Tutorial files in textDocument/doccDocumentation
…ntation Handle Markdown and Tutorial files in textDocument/doccDocumentation
Adds a handler to
DocumentationLanguageService
for thetextDocument/doccDocumentation
LSP extension. The request is handled much in the same way as forSwiftLanguageService
where the SwiftDocC convert request is assembled and then sent to SwiftDocC for processing. All of the SwiftDocC specific code has been moved into a newDocCDocumentation
module to try and keep SourceKit-LSP clean.SwiftDocC supports four different kinds of Markdown/Tutorial files:
*.tutorial
file extension and represents a self-contained tutorial.*.tutorial
file extension, but represents a group of tutorials.In addition to finding the Swift symbol for a symbol extension page, we must do the reverse when generating documentation for a symbol within a Swift file. This involves looking for
*.docc
documentation catalogs within the target and asking SwiftDocC to build an index for us. We can then retrieve all of the markdown extension pages and their associated symbols to do the lookup.