Hello everyone,
I am Padmashree S S, I have been working on implementing the DocC Language Features in SourceKit-LSP as a part of GSoC along with my mentors @matthewbastien and @snprajwal.
Project
This project extends SourceKit-LSP by adding DocC Language Features including:
- Go-to-definition for symbol links in DocC comments, Tutorial and Markdown files.
- Diagnostics for broken and invalid symbol links.
- Interactive documentation preview allowing users to click symbol links in the DocC preview and navigate to their definition in the editor.
- Syntax highlighting for DocC Markdown and Tutorial files.
Impact
Now developers can use IDE features for their documentation as well, making it easier for them to write and maintain high-quality documentation. Previously, broken symbol links and typos in links could only be identified after the entire documentation was built, but with these features, such issues can be identified and resolved during development itself, making it easier for developers to write and maintain their documentation.
Making documentation easier to write and maintain can encourage developers to create better documentation and tutorials for their iOS products. This makes their products easier for others to understand and use, leading to wider adoption and, in turn, help improve the overall iOS development experience. Since these features are part of SourceKit-LSP, they are not limited to a single editor and can be used across editors such as VS Code, Vim and others.
Demo Video
Implementation
1. Add Go-to-Definition for Symbol links in DocC Comments, Markdown and Tutorial files
- When the user triggers the go-to-definition on a symbol link, the editor sends the
textDocument/definitionrequest to the SourceKit-LSP. - The SourceKit-LSP receives the URI of the text Document along with the cursor position.
- We identify the symbol link under the cursor by using two parsing steps:
- Swift Parser - For Swift files, the Swift parser is first used to identify the comment block containing the symbol link. Since the Swift parser treats the contents of a comment as a comment block and does not parse the documentation content inside it, an additional parsing step is required.
- Markdown Parser - The Markdown parser then processes the contents of the comment block and identifies the symbol link located at the cursor position.
- We query the IndexStore using the symbol name to find candidate symbols, construct a Symbol Graph for each candidate, and compare them with the DocC symbol link to find the best match.
- The location of the matching symbol is returned to the editor, which opens the corresponding file and places the cursor at its definition.
Challenges Faced
- For Swift files as both
SwiftLanguageServiceandDocumentationLanguageServiceare registered. There was no error to indicate that a request was not meant for the current language service and should be passed to the next one. So, we implemented a new error,FallThroughToNextLanguageService, to handle this case. - The Swift parser uses UTF-16 offsets, while the Markdown parser uses UTF-8 offsets, so conversion between the two was necessary to correctly locate the symbol link.
- Initially, we would find the definition location by generating a symbol graph for the entire module during indexing, but this caused a lot of overhead, increasing the indexing time by 2x and resulting in the editor window freezing. Later, we switched to an index-based approach and generated the symbol graph for the specific symbol, improving the performance significantly.
PR Link:
- SourceKit-LSP - #2698
2. Emit Diagnostics for Broken/Invalid Symbol Links
- Extract all the Symbol Links from the open document along with their ranges using the Swift and Markdown parser.
- Try resolving the symbols using the index, similar to the approach used for go-to-definition.
- If a symbol link is broken or does not exist, generate a diagnostic for it.
- If the client supports pull diagnostics, provide the diagnostics in response to the
textDocument/diagnosticrequest. - If pull diagnostics is not supported, fall back to push diagnostics and send the diagnostics as a notification to the client (editor).
Challenges Faced
- For Swift files, both the
SwiftLanguageServiceandDocumentationLanguageServiceare registered, but only one set of diagnostics would be displayed at a time. - So we had to combine the diagnostics from both the language services before sending them to the client. The combined diagnostics are then sent as a notification for push diagnostics or as a response for pull diagnostics.
PR Link:
- SourceKit-LSP - #2729
3. Make Symbol Links in Documentation Preview Clickable
- When the user clicks on a Symbol link in Documentation Preview, the click event handler is triggered and a
textDocument/doccSymbolLinkDefinitionrequest is sent to the SourceKit-LSP. - As a part of this request, the
hrefattribute of the clicked symbol link along with the file URI is sent to the server. - SourceKit-LSP resolves the symbol definition using index and symbol graph when needed, similar to how it is done for go-to-definition.
- The location of the symbol definition is sent back to the editor, which opens the corresponding file and places the cursor at the symbol's definition.
Challenges Faced
- We were not able to reuse any of the existing requests because they required the cursor position as a parameter, which is not avaliable when the user clicks a symbo link in the Documentation Preview.
- So we had to implement a new request
textDocument/doccSymbolLinkDefinitionfor the same.
PR Links:
4. Add Syntax highlighting for DocC Tutorial and Markdown files
- Directives with and without arguments (
@Step,@Tutorial(...), etc.) are highlighted. @Comment { }blocks are highlighted separately as comments.- Braces,parentheses, quotes and backticks are auto-closed, along with corrected folding markers.
- Markdown syntax highlighting is retained for Markdown content in
.mdfiles.
PR Links:
Current Status
All four features are working locally and are currently being upstreamed. The PRs are at different stages of review, with the next steps being to add the remaining test cases, address mentor feedback and get the changes merged upstream.
I am really thankful to my mentors @matthewbastien and @snprajwal for all their guidance and feedback throughout the project. I am also grateful to @ahoppen for the detailed code reviews and for providing valuable insights into SourceKit-LSP.
It has been amazing working on this project and being a part of the Swift community.
Thank you everyone for being so welcoming and making this such a wonderful experience! :)






