@@ -18,6 +18,7 @@ import * as path from "path";
1818import { WebviewMessage } from "./webview/WebviewMessage" ;
1919import { WorkspaceContext } from "../WorkspaceContext" ;
2020import { Target } from "../SwiftPackage" ;
21+ import { fileExists } from "../utilities/filesystem" ;
2122
2223export class DocumentationPreviewEditor implements vscode . Disposable {
2324 private readonly webviewPanel : vscode . WebviewPanel ;
@@ -49,25 +50,35 @@ export class DocumentationPreviewEditor implements vscode.Disposable {
4950 const scriptURI = this . webviewPanel . webview . asWebviewUri (
5051 vscode . Uri . file ( this . extension . asAbsolutePath ( "assets/documentation-webview/index.js" ) )
5152 ) ;
52- this . currentRoute =
53- this . extractPathFromTextDocument ( vscode . window . activeTextEditor ) ??
54- getDefaultDocumentationPath ( this . context ) ;
55- fs . readFile ( path . join ( archivePath , "index.html" ) , "utf-8" ) . then ( documentationHTML => {
53+ this . currentRoute = getDefaultDocumentationPath ( this . context ) ;
54+ Promise . all ( [
55+ this . findRouteFromTextDocument ( vscode . window . activeTextEditor ) ,
56+ fs . readFile ( path . join ( archivePath , "index.html" ) , "utf-8" ) ,
57+ ] ) . then ( ( [ activeTextEditorRoute , documentationHTML ] ) => {
58+ if ( activeTextEditorRoute ) {
59+ this . currentRoute = activeTextEditorRoute ;
60+ }
5661 documentationHTML = documentationHTML
5762 . replaceAll ( "{{BASE_PATH}}" , webviewBaseURI . toString ( ) )
5863 . replace ( "</body>" , `<script src="${ scriptURI . toString ( ) } "></script></body>` ) ;
5964 this . webviewPanel . webview . html = documentationHTML ;
6065 this . subscriptions . push (
6166 this . webviewPanel . webview . onDidReceiveMessage ( this . receiveMessage . bind ( this ) ) ,
6267 vscode . window . onDidChangeActiveTextEditor ( this . activeTextEditorChanged . bind ( this ) ) ,
68+ vscode . window . onDidChangeTextEditorSelection (
69+ this . textEditorSelectionChanged . bind ( this )
70+ ) ,
6371 this . webviewPanel . onDidDispose ( this . dispose . bind ( this ) )
6472 ) ;
65-
6673 // Reveal the editor, but don't change the focus of the active text editor
6774 this . webviewPanel . reveal ( undefined , true ) ;
6875 } ) ;
6976 }
7077
78+ reveal ( ) {
79+ this . webviewPanel . reveal ( ) ;
80+ }
81+
7182 dispose ( ) {
7283 this . subscriptions . forEach ( subscription => subscription . dispose ( ) ) ;
7384 this . subscriptions = [ ] ;
@@ -94,15 +105,28 @@ export class DocumentationPreviewEditor implements vscode.Disposable {
94105 }
95106
96107 private activeTextEditorChanged ( editor : vscode . TextEditor | undefined ) {
97- const navigateToPath = this . extractPathFromTextDocument ( editor ) ;
98- if ( ! navigateToPath ) {
99- return ;
100- }
108+ this . findRouteFromTextDocument ( editor ) . then ( navigateToPath => {
109+ if ( ! navigateToPath ) {
110+ return ;
111+ }
101112
102- this . postMessage ( { type : "navigate" , route : navigateToPath } ) ;
113+ this . postMessage ( { type : "navigate" , route : navigateToPath } ) ;
114+ } ) ;
103115 }
104116
105- private extractPathFromTextDocument ( editor : vscode . TextEditor | undefined ) : string | undefined {
117+ private textEditorSelectionChanged ( event : vscode . TextEditorSelectionChangeEvent ) {
118+ this . findRouteFromTextDocument ( event . textEditor ) . then ( navigateToPath => {
119+ if ( ! navigateToPath ) {
120+ return ;
121+ }
122+
123+ this . postMessage ( { type : "navigate" , route : navigateToPath } ) ;
124+ } ) ;
125+ }
126+
127+ private async findRouteFromTextDocument (
128+ editor : vscode . TextEditor | undefined
129+ ) : Promise < string | undefined > {
106130 const document = editor ?. document ;
107131 if ( ! document || document . uri . scheme !== "file" ) {
108132 return undefined ;
@@ -113,9 +137,71 @@ export class DocumentationPreviewEditor implements vscode.Disposable {
113137 return ;
114138 }
115139
116- const targetRoute = `/documentation/${ target . name . toLocaleLowerCase ( ) } ` ;
140+ const targetRoute = `/documentation/${ target . name } ` ;
141+ if (
142+ document . uri . fsPath . endsWith ( ".md" ) &&
143+ ( await fileExists (
144+ this . archivePath ,
145+ "data" ,
146+ "documentation" ,
147+ target . name . toLocaleLowerCase ( ) ,
148+ path . basename ( document . uri . fsPath , ".md" ) + ".json"
149+ ) )
150+ ) {
151+ return targetRoute + "/" + path . basename ( document . uri . fsPath , ".md" ) ;
152+ } else if ( document . uri . fsPath . endsWith ( ".tutorial" ) ) {
153+ return `/tutorials/${ target . name } /${ path . basename ( document . uri . fsPath , ".tutorial" ) . replaceAll ( " " , "-" ) } ` ;
154+ } else if ( document . languageId === "swift" ) {
155+ const symbolRoute = await this . findSymbolInDocument ( document , editor . selection ) ;
156+ if ( symbolRoute ) {
157+ return targetRoute + "/" + symbolRoute ;
158+ }
159+ }
117160 return targetRoute ;
118161 }
162+
163+ private async findSymbolInDocument (
164+ document : vscode . TextDocument ,
165+ range : vscode . Range
166+ ) : Promise < string | undefined > {
167+ const symbols : ( vscode . SymbolInformation | vscode . DocumentSymbol ) [ ] =
168+ await vscode . commands . executeCommand (
169+ "vscode.executeDocumentSymbolProvider" ,
170+ document . uri
171+ ) ;
172+ for ( const symbol of symbols ) {
173+ if ( ! ( "children" in symbol ) ) {
174+ continue ;
175+ }
176+ const symbolRoute = this . searchSymbol ( symbol , range ) ;
177+ if ( symbolRoute ) {
178+ return symbolRoute ;
179+ }
180+ }
181+ return undefined ;
182+ }
183+
184+ private searchSymbol (
185+ symbol : vscode . DocumentSymbol ,
186+ range : vscode . Range ,
187+ context ?: string
188+ ) : string | undefined {
189+ if ( ! symbol . range . contains ( range ) ) {
190+ return ;
191+ }
192+ if ( ! context ) {
193+ context = symbol . name ;
194+ } else {
195+ context += "/" + symbol . name ;
196+ }
197+ for ( const child of symbol . children ) {
198+ const childResult = this . searchSymbol ( child , range , context ) ;
199+ if ( childResult ) {
200+ return childResult ;
201+ }
202+ }
203+ return context ;
204+ }
119205}
120206
121207function findTargetForFile ( file : string , ctx : WorkspaceContext ) : Target | undefined {
0 commit comments