@@ -35,7 +35,7 @@ export interface QuartoContext {
35
35
36
36
/**
37
37
* Initialize a Quarto context.
38
- *
38
+ *
39
39
* @param quartoPath A path to a user-specified Quarto executable. If
40
40
* supplied, this will be used in preference to other methods of detecting
41
41
* Quarto.
@@ -44,14 +44,15 @@ export interface QuartoContext {
44
44
* @param additionalSearchPaths Additional paths to search for Quarto. These will only be used if
45
45
* Quarto is not found in the default locations or the system path.
46
46
* @param showWarning A function to call to show a warning message.
47
- *
47
+ *
48
48
* @returns A Quarto context.
49
49
*/
50
50
export function initQuartoContext (
51
51
quartoPath ?: string ,
52
52
workspaceFolder ?: string ,
53
53
additionalSearchPaths ?: string [ ] ,
54
- showWarning ?: ( msg : string ) => void
54
+ showWarning ?: ( msg : string ) => void ,
55
+ pandocPath ?: string
55
56
) : QuartoContext {
56
57
// default warning to log
57
58
showWarning = showWarning || console . log ;
@@ -80,20 +81,30 @@ export function initQuartoContext(
80
81
// use cmd suffix for older versions of quarto on windows
81
82
const windows = os . platform ( ) == "win32" ;
82
83
const useCmd = windows && semver . lte ( quartoInstall . version , "1.1.162" ) ;
83
- let pandocPath = path . join ( quartoInstall ! . binPath , "tools" , "pandoc" ) ;
84
- // more recent versions of quarto use architecture-specific tools dir,
85
- // if the pandocPath is not found then look in the requisite dir for this arch
86
- if ( ! windows && ! fs . existsSync ( pandocPath ) ) {
87
- pandocPath = path . join (
88
- path . dirname ( pandocPath ) ,
89
- isArm_64 ( ) ? "aarch64" : "x86_64" ,
90
- path . basename ( pandocPath )
91
- ) ;
84
+
85
+ // Look for pandoc in settings
86
+ let pandocInstall : PandocInstallation | undefined ;
87
+ if ( pandocPath ) {
88
+ if ( ! path . isAbsolute ( pandocPath ) && workspaceFolder ) {
89
+ pandocPath = path . join ( workspaceFolder , pandocPath ) ;
90
+ }
91
+ pandocInstall = detectUserSpecifiedPandoc ( pandocPath , showWarning ) ;
92
+ }
93
+
94
+ // next look on the path
95
+ if ( ! pandocInstall ) {
96
+ pandocInstall = detectPandoc ( "pandoc" ) ;
92
97
}
98
+
99
+ // if still not found, scan for versions of quarto in known locations
100
+ if ( ! pandocInstall ) {
101
+ pandocInstall = scanForPandoc ( quartoInstall , additionalSearchPaths ) ;
102
+ }
103
+
93
104
return {
94
105
available : true ,
95
106
...quartoInstall ,
96
- pandocPath,
107
+ pandocPath : pandocInstall ?. binPath || "" ,
97
108
workspaceDir : workspaceFolder ,
98
109
useCmd,
99
110
runQuarto : ( options : ExecFileSyncOptions , ...args : string [ ] ) =>
@@ -104,7 +115,7 @@ export function initQuartoContext(
104
115
) ,
105
116
runPandoc : ( options : ExecFileSyncOptions , ...args : string [ ] ) =>
106
117
execProgram (
107
- pandocPath ,
118
+ pandocInstall ?. binPath || "" ,
108
119
args ,
109
120
options
110
121
) ,
@@ -114,7 +125,7 @@ export function initQuartoContext(
114
125
}
115
126
}
116
127
117
- export function quartoContextUnavailable ( ) : QuartoContext {
128
+ export function quartoContextUnavailable ( ) : QuartoContext {
118
129
return {
119
130
available : false ,
120
131
version : "" ,
@@ -179,8 +190,8 @@ function detectUserSpecifiedQuarto(
179
190
if ( ! fs . statSync ( quartoPath ) . isFile ( ) ) {
180
191
showWarning (
181
192
"Specified quarto executable is a directory not a file: '" +
182
- quartoPath +
183
- "'"
193
+ quartoPath +
194
+ "'"
184
195
) ;
185
196
return undefined ;
186
197
}
@@ -191,9 +202,9 @@ function detectUserSpecifiedQuarto(
191
202
192
203
/**
193
204
* Scan for Quarto in known locations.
194
- *
205
+ *
195
206
* @param additionalSearchPaths Additional paths to search for Quarto (optional)
196
- *
207
+ *
197
208
* @returns A Quarto installation if found, otherwise undefined
198
209
*/
199
210
function scanForQuarto ( additionalSearchPaths ?: string [ ] ) : QuartoInstallation | undefined {
@@ -231,3 +242,119 @@ function scanForQuarto(additionalSearchPaths?: string[]): QuartoInstallation | u
231
242
232
243
return undefined ;
233
244
}
245
+
246
+ type PandocInstallation = {
247
+ version : string ;
248
+ binPath : string ;
249
+ } ;
250
+
251
+ function detectPandoc ( pandocPath : string ) : PandocInstallation | undefined {
252
+ // detect version and paths (fall back to .cmd on windows if necessary)
253
+ const windows = os . platform ( ) == "win32" ;
254
+ let version : string | undefined ;
255
+ const readPandocInfo = ( bin : string ) => {
256
+ version = execProgram ( bin , [ "--version" ] ) . substring ( 7 , 10 ) . trim ( ) ;
257
+ } ;
258
+ try {
259
+ readPandocInfo ( pandocPath ) ;
260
+ } catch ( e ) {
261
+ if ( windows ) {
262
+ try {
263
+ readPandocInfo ( pandocPath + ".cmd" ) ;
264
+ } catch ( e ) { /* */ }
265
+ }
266
+ }
267
+ // return version if we have it
268
+ if ( version ) {
269
+ return {
270
+ version,
271
+ binPath : pandocPath ,
272
+ } ;
273
+ } else {
274
+ return undefined ;
275
+ }
276
+ }
277
+
278
+ function detectUserSpecifiedPandoc (
279
+ pandocPath : string ,
280
+ showWarning : ( msg : string ) => void
281
+ ) : PandocInstallation | undefined {
282
+ // validate that it exists
283
+ if ( ! fs . existsSync ( pandocPath ) ) {
284
+ showWarning (
285
+ "Unable to find specified pandoc executable: '" + pandocPath + "'"
286
+ ) ;
287
+ return undefined ;
288
+ }
289
+
290
+ // validate that it is a file
291
+ if ( ! fs . statSync ( pandocPath ) . isFile ( ) ) {
292
+ showWarning (
293
+ "Specified pandoc executable is a directory not a file: '" +
294
+ pandocPath +
295
+ "'"
296
+ ) ;
297
+ return undefined ;
298
+ }
299
+
300
+ // detect
301
+ return detectPandoc ( pandocPath ) ;
302
+ }
303
+
304
+ /**
305
+ * Scan for Pandoc in known locations.
306
+ *
307
+ * @param quartoInstall QuartoInstall instance to use for search first
308
+ * @param additionalSearchPaths Additional paths to search for Quarto (optional)
309
+ *
310
+ * @returns A Quarto installation if found, otherwise undefined
311
+ */
312
+ function scanForPandoc ( quartoInstall : QuartoInstallation , additionalSearchPaths ?: string [ ] ) : PandocInstallation | undefined {
313
+ const scanPaths : string [ ] = [ ] ;
314
+ const windows = os . platform ( ) === "win32"
315
+
316
+ let pandocPath = path . join ( quartoInstall ! . binPath , "tools" , "pandoc" ) ;
317
+ // more recent versions of quarto use architecture-specific tools dir,
318
+ // if the pandocPath is not found then look in the requisite dir for this arch
319
+ if ( ! windows && ! fs . existsSync ( pandocPath ) ) {
320
+ pandocPath = path . join (
321
+ path . dirname ( pandocPath ) ,
322
+ isArm_64 ( ) ? "aarch64" : "x86_64" ,
323
+ path . basename ( pandocPath )
324
+ ) ;
325
+ }
326
+ scanPaths . push ( pandocPath )
327
+
328
+ if ( windows ) {
329
+ // scanPaths.push("C:\\Program Files\\Quarto\\bin");
330
+ // const localAppData = process.env["LOCALAPPDATA"];
331
+ // if (localAppData) {
332
+ // scanPaths.push(path.join(localAppData, "Programs", "Quarto", "bin"));
333
+ // }
334
+ // scanPaths.push("C:\\Program Files\\RStudio\\bin\\quarto\\bin");
335
+ } else if ( os . platform ( ) === "darwin" ) {
336
+ // scanPaths.push("/Applications/quarto/bin/");
337
+ // const home = process.env.HOME;
338
+ // if (home) {
339
+ // scanPaths.push(path.join(home, "Applications", "quarto", "bin"));
340
+ // }
341
+ // scanPaths.push("/Applications/RStudio.app/Contents/MacOS/quarto/bin");
342
+ } else if ( os . platform ( ) === "linux" ) {
343
+ // scanPaths.push("/opt/quarto/bin");
344
+ // scanPaths.push("/usr/lib/rstudio/bin/quarto/bin");
345
+ // scanPaths.push("/usr/lib/rstudio-server/bin/quarto/bin");
346
+ }
347
+
348
+ if ( additionalSearchPaths ) {
349
+ scanPaths . push ( ...additionalSearchPaths ) ;
350
+ }
351
+
352
+ for ( const scanPath of scanPaths . filter ( fs . existsSync ) ) {
353
+ const install = detectPandoc ( path . join ( scanPath , "pandoc" ) ) ;
354
+ if ( install ) {
355
+ return install ;
356
+ }
357
+ }
358
+
359
+ return undefined
360
+ }
0 commit comments