@@ -14,6 +14,7 @@ import {
1414 CMD_BUILD_AND_RUN_MAIN ,
1515 CMD_GPR_PROJECT_ARGS ,
1616 CMD_RESTART_LANG_SERVERS ,
17+ CMD_OPEN_USERS_GUIDE ,
1718 CMD_SHOW_ADA_LS_OUTPUT ,
1819 CMD_SHOW_EXTENSION_LOGS ,
1920 CMD_SHOW_GPR_LS_OUTPUT ,
@@ -22,11 +23,18 @@ import {
2223 CMD_SPARK_LIMIT_REGION_ARG ,
2324 CMD_SPARK_LIMIT_SUBP_ARG ,
2425 CMD_SPARK_PROVE_SUBP ,
26+ VSCODE_UG_LIVE_DOC_URL ,
2527} from './constants' ;
2628import { AdaConfig , getOrAskForProgram , initializeConfig } from './debugConfigProvider' ;
2729import { adaExtState , logger , mainOutputChannel } from './extension' ;
2830import { loadGnatCoverageReport } from './gnattest' ;
29- import { findAdaMain , getProjectFileRelPath , getSymbols } from './helpers' ;
31+ import {
32+ findAdaMain ,
33+ getProjectFileRelPath ,
34+ getSymbols ,
35+ isExtensionInstalled ,
36+ isRunningOnRemote ,
37+ } from './helpers' ;
3038import { registerSPARKTaskWrappers } from './sparkCommands' ;
3139import { askSPARKOptions , getLastSPARKOptions } from './sparkOptionsPicker' ;
3240import {
@@ -96,6 +104,9 @@ export function registerCommands(context: vscode.ExtensionContext, clients: Exte
96104 context . subscriptions . push (
97105 vscode . commands . registerCommand ( 'ada.subprogramBox' , addSubprogramBoxCommand ) ,
98106 ) ;
107+ context . subscriptions . push (
108+ vscode . commands . registerCommand ( CMD_OPEN_USERS_GUIDE , openUsersGuide ) ,
109+ ) ;
99110 context . subscriptions . push (
100111 vscode . commands . registerCommand ( CMD_SHOW_EXTENSION_LOGS , ( ) => mainOutputChannel . show ( ) ) ,
101112 ) ;
@@ -192,6 +203,117 @@ export function registerCommands(context: vscode.ExtensionContext, clients: Exte
192203 registerSPARKTaskWrappers ( context ) ;
193204}
194205
206+ /**
207+ * Get the extension user's guide URI, if it exists on disk.
208+ *
209+ * @returns the URI of the extension user's guide, or `null` if the file
210+ * does not exist.
211+ */
212+ export function getUsersGuideURI ( ) : vscode . Uri | null {
213+ const ug_path = vscode . Uri . joinPath (
214+ adaExtState . context . extensionUri ,
215+ 'share' ,
216+ 'doc' ,
217+ 'als' ,
218+ 'html' ,
219+ 'users_guide' ,
220+ 'index.html' ,
221+ ) ;
222+
223+ if ( existsSync ( ug_path . fsPath ) ) {
224+ return ug_path ;
225+ }
226+ return null ;
227+ }
228+
229+ /**
230+ * Open the extension user's guide in a new editor tab using LivePreview
231+ * if doable.
232+ * This requires the "Live Preview" extension by Microsoft to be installed.
233+ * The user will be warned if this extension is not installed or if the user's
234+ * guide cannot be found on disk.
235+ */
236+ async function openUsersGuide ( ) {
237+ const usersGuideURI = getUsersGuideURI ( ) ;
238+
239+ // The user's guide is not found on disk, warn the user and propose
240+ // to open the online documentation instead.
241+ if ( ! usersGuideURI ) {
242+ async function showUGNotFoundError ( ) {
243+ const action = await vscode . window . showErrorMessage (
244+ "The User's Guide was not found under the Ada & SPARK extension installation. " +
245+ 'Please consult the online documentation instead.' ,
246+ 'Open Online Docs' ,
247+ ) ;
248+ if ( action === 'Open Online Docs' ) {
249+ void vscode . env . openExternal ( vscode . Uri . parse ( VSCODE_UG_LIVE_DOC_URL ) ) ;
250+ }
251+ }
252+
253+ void showUGNotFoundError ( ) ;
254+ return ;
255+ }
256+
257+ // Live Preview extension is not installed, warn the user and propose
258+ // to open the user's guide with the default browser instead.
259+ if ( ! isExtensionInstalled ( 'ms-vscode.live-server' ) ) {
260+ /** Show the LivePreview extension's page in the marketplace
261+ */
262+ function showLivePreviewInMarketplace ( ) {
263+ void vscode . commands . executeCommand (
264+ 'workbench.extensions.search' ,
265+ '@id:ms-vscode.live-server' ,
266+ ) ;
267+ }
268+
269+ /** Show an error message proposing to install Live Preview or open the
270+ * user's guide with the default browser instead.
271+ */
272+ async function showNotLivePreviewInstalledError ( ) {
273+ // If not running on a remote, propose to open the locally installed
274+ // user's guide with the default browser instead.
275+ if ( ! isRunningOnRemote ( ) ) {
276+ const action = await vscode . window . showErrorMessage (
277+ "Microsoft's Live Preview extension is not installed. " +
278+ "Please install it to open the User's Guide directly in VS Code, " +
279+ 'otherwise open it with your system browser.' ,
280+ 'Install Live Preview' ,
281+ 'Open in Browser' ,
282+ ) ;
283+ if ( action === 'Open in Browser' ) {
284+ if ( usersGuideURI ) {
285+ void vscode . env . openExternal ( usersGuideURI ) ;
286+ }
287+ } else if ( action === 'Install Live Preview' ) {
288+ showLivePreviewInMarketplace ( ) ;
289+ }
290+ } else {
291+ // If running on a remote, propose to install Live Preview or
292+ // open the online documentation instead.
293+ const action = await vscode . window . showErrorMessage (
294+ "Microsoft's Live Preview extension is not installed. " +
295+ "Please install it to open the User's Guide directly in VS Code " +
296+ 'when connected to a remote machine, or consult ' +
297+ 'the online documentation instead.' ,
298+ 'Install Live Preview' ,
299+ 'Open Online Docs' ,
300+ ) ;
301+ if ( action === 'Open Online Docs' ) {
302+ void vscode . env . openExternal ( vscode . Uri . parse ( VSCODE_UG_LIVE_DOC_URL ) ) ;
303+ } else if ( action === 'Install Live Preview' ) {
304+ showLivePreviewInMarketplace ( ) ;
305+ }
306+ }
307+ }
308+
309+ void showNotLivePreviewInstalledError ( ) ;
310+ return ;
311+ }
312+
313+ // Open the user's guide using Live Preview
314+ await vscode . commands . executeCommand ( 'livePreview.start.internalPreview.atFile' , usersGuideURI ) ;
315+ }
316+
195317/**
196318 * Add a subprogram box above the subprogram enclosing the cursor's position, if any.
197319 *
0 commit comments