Skip to content

Commit 440f3ed

Browse files
authored
Merge pull request #478 from marp-team/browser-path-setting
[v3] `markdown.marp.browser` and `markdown.marp.browserPath` settings
2 parents c1d3cab + 11e5df1 commit 440f3ed

File tree

10 files changed

+294
-112
lines changed

10 files changed

+294
-112
lines changed

CHANGELOG.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,20 @@
1313
### Added
1414

1515
- `markdown.marp.html` setting to control rendering HTML within Marp Markdown ([#476](https://github.com/marp-team/marp-vscode/pull/476))
16-
17-
### Deprecated
18-
19-
- `markdown.marp.enableHtml` setting ([#476](https://github.com/marp-team/marp-vscode/pull/476))
16+
- `markdown.marp.browser` and `markdown.marp.browserPath` settings to control internally using browser to export ([#478](https://github.com/marp-team/marp-vscode/pull/478))
17+
- Support Firefox as a browser for exporting ([#473](https://github.com/marp-team/marp-vscode/pull/473), [#474](https://github.com/marp-team/marp-vscode/pull/474), [#478](https://github.com/marp-team/marp-vscode/pull/478))
2018

2119
### Changed
2220

21+
- Several allowed HTML elements through Marp Core are enabled by default ([#472](https://github.com/marp-team/marp-vscode/pull/472), [#474](https://github.com/marp-team/marp-vscode/pull/474), [#476](https://github.com/marp-team/marp-vscode/pull/476))
2322
- Upgrade development Node.js and dependent packages to the latest version ([#474](https://github.com/marp-team/marp-vscode/pull/474))
2423
- Migrate ESLint config to flat config ([#475](https://github.com/marp-team/marp-vscode/pull/475))
2524

25+
### Deprecated
26+
27+
- Deprecated `markdown.marp.enableHtml` setting in favor of `markdown.marp.html` ([#476](https://github.com/marp-team/marp-vscode/pull/476))
28+
- Deprecated `markdown.marp.chromePath` setting in favor of `markdown.marp.browserPath` ([#478](https://github.com/marp-team/marp-vscode/pull/478))
29+
2630
## v2.8.0 - 2023-10-28
2731

2832
### Changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,13 @@ You can also execute command from the Command Palette (<kbd>F1</kbd> or <kbd>Ctr
128128
- **PNG** (_First slide only)_
129129
- **JPEG** (_First slide only)_
130130

131-
Default file type can choose by `markdown.marp.exportType` preference.
131+
Default file type can choose by the `markdown.marp.exportType` setting.
132132

133-
> ⚠️ Export except HTML requires to install any one of [Google Chrome](https://www.google.com/chrome/), [Chromium](https://www.chromium.org/), or [Microsoft Edge](https://www.microsoft.com/edge). You may also specify the custom path for Chrome / Chromium-based browser by preference `markdown.marp.chromePath`.
133+
> [!IMPORTANT]
134+
> Exporting PDF, PPTX, and image formats requires to install any one of [Google Chrome](https://www.google.com/chrome/), [Chromium](https://www.chromium.org/), [Microsoft Edge](https://www.microsoft.com/edge), or [Firefox](https://www.mozilla.org/firefox/). You may control using browser and the custom path for the browser by `markdown.marp.browser` and `markdown.marp.browserPath` settings.
135+
136+
> [!NOTE]
137+
> A legacy setting `markdown.marp.chromePath` is deprecated since v2. Please use `markdown.marp.browserPath` instead.
134138
135139
### Use custom theme CSS 🛡️
136140

@@ -175,7 +179,7 @@ Markdown preview will reload updated theme CSS automatically when you edited the
175179

176180
### Outline extension
177181

178-
When Marp Markdown is enabled, you can use the extended [outline view](https://code.visualstudio.com/docs/languages/markdown#_outline-view) like following. They are enabled by default but you may disable by `markdown.marp.outlineExtension` preference.
182+
When Marp Markdown is enabled, you can use the extended [outline view](https://code.visualstudio.com/docs/languages/markdown#_outline-view) like following. They are enabled by default but you may disable by the `markdown.marp.outlineExtension` setting.
179183

180184
#### Outline view for each slide
181185

package.json

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,27 @@
115115
"Use inherited setting from `#markdown.preview.breaks#`."
116116
]
117117
},
118-
"markdown.marp.chromePath": {
118+
"markdown.marp.browser": {
119+
"type": "string",
120+
"enum": [
121+
"auto",
122+
"chrome",
123+
"edge",
124+
"firefox"
125+
],
126+
"default": "auto",
127+
"description": "Controls the installed browser using internally to export PDF, PPTX, and the image.",
128+
"enumDescriptions": [
129+
"Automatically detect Chrome, Chromium, Edge, or Firefox.",
130+
"Use Google Chrome.",
131+
"Use Microsoft Edge.",
132+
"Use Mozilla Firefox."
133+
]
134+
},
135+
"markdown.marp.browserPath": {
119136
"type": "string",
120137
"default": "",
121-
"description": "Sets the custom path for Chrome or Chromium-based browser to export PDF, PPTX, and image. If it's empty, Marp will find out the installed Google Chrome / Chromium / Microsoft Edge."
138+
"markdownDescription": "Configure the custom path for the installed browser using internally to export PDF, PPTX, and the image. The kind of browser is determined by `#markdown.marp.browser#`. When set to empty, Marp will find out a suitable installed browser automatically."
122139
},
123140
"markdown.marp.html": {
124141
"type": "string",
@@ -214,6 +231,12 @@
214231
"default": false,
215232
"description": "Enables all HTML elements in Marp Markdown. This setting is working only in the trusted workspace.",
216233
"deprecationMessage": "The setting \"markdown.marp.enableHtml\" is deprecated. Please use \"markdown.marp.html\" instead."
234+
},
235+
"markdown.marp.chromePath": {
236+
"type": "string",
237+
"default": "",
238+
"description": "Sets the custom path for Chrome or Chromium-based browser to export PDF, PPTX, and image. If it's empty, Marp will find out the installed Google Chrome / Chromium / Microsoft Edge.",
239+
"deprecationMessage": "The setting \"markdown.marp.chromePath\" is deprecated. Please use \"markdown.marp.browserPath\" instead."
217240
}
218241
}
219242
},

src/__mocks__/vscode.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ type MockedConf = Record<string, any>
55
const defaultVSCodeVersion = 'v1.62.1'
66
const defaultConf: MockedConf = {
77
'markdown.marp.breaks': 'on',
8-
'markdown.marp.chromePath': '',
9-
'markdown.marp.enableHtml': false,
8+
'markdown.marp.browser': 'auto',
9+
'markdown.marp.browserPath': '',
1010
'markdown.marp.html': 'default',
1111
'markdown.marp.exportType': 'pdf',
1212
'markdown.marp.outlineExtension': true,
1313
'markdown.marp.pdf.noteAnnotations': false,
1414
'markdown.marp.pdf.outlines': 'off',
1515
'window.zoomLevel': 0,
16+
17+
// Legacy
18+
'markdown.marp.chromePath': '',
19+
'markdown.marp.enableHtml': false,
1620
}
1721

1822
let currentConf: MockedConf = {}

src/commands/export.test.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import * as marpCliModule from '@marp-team/marp-cli'
12
import { commands, env, window, workspace } from 'vscode'
23
import * as marpCli from '../marp-cli'
34
import * as option from '../option'
@@ -317,6 +318,65 @@ describe('#doExport', () => {
317318
})
318319
})
319320

321+
describe('when CLI was thrown CLIError with BROWSER_NOT_FOUND error code', () => {
322+
it.each`
323+
browser | platform | expected
324+
${'auto'} | ${'win32'} | ${['Google Chrome', 'Microsoft Edge', 'Firefox']}
325+
${'auto'} | ${'darwin'} | ${['Google Chrome', 'Microsoft Edge', 'Firefox']}
326+
${'auto'} | ${'linux'} | ${['Google Chrome', 'Chromium', 'Microsoft Edge', 'Firefox']}
327+
${'chrome'} | ${'win32'} | ${['Google Chrome']}
328+
${'chrome'} | ${'darwin'} | ${['Google Chrome']}
329+
${'chrome'} | ${'linux'} | ${['Google Chrome', 'Chromium']}
330+
${'edge'} | ${'win32'} | ${['Microsoft Edge']}
331+
${'edge'} | ${'darwin'} | ${['Microsoft Edge']}
332+
${'edge'} | ${'linux'} | ${['Microsoft Edge']}
333+
${'firefox'} | ${'win32'} | ${['Firefox']}
334+
${'firefox'} | ${'darwin'} | ${['Firefox']}
335+
${'firefox'} | ${'linux'} | ${['Firefox']}
336+
`(
337+
'throws MarpCLIError with the message contains $expected to suggest browsers when running on $platform with browser option as $browser',
338+
async ({ browser, platform, expected }) => {
339+
expect.assertions(expected.length + 1)
340+
setConfiguration({ 'markdown.marp.browser': browser })
341+
342+
const { platform: originalPlatform } = process
343+
344+
try {
345+
Object.defineProperty(process, 'platform', { value: platform })
346+
347+
const runMarpCLI = jest
348+
.spyOn(marpCli, 'default')
349+
.mockImplementation(async (_, __, opts) => {
350+
opts?.onCLIError?.({
351+
error: new marpCliModule.CLIError(
352+
'mocked error',
353+
marpCliModule.CLIErrorCode.NOT_FOUND_BROWSER,
354+
),
355+
codes: marpCliModule.CLIErrorCode,
356+
})
357+
})
358+
359+
try {
360+
await exportModule.doExport(saveURI(), document)
361+
expect(window.showErrorMessage).toHaveBeenCalledTimes(1)
362+
363+
for (const fragment of expected) {
364+
expect(window.showErrorMessage).toHaveBeenCalledWith(
365+
expect.stringContaining(fragment),
366+
)
367+
}
368+
} finally {
369+
runMarpCLI.mockRestore()
370+
}
371+
} finally {
372+
Object.defineProperty(process, 'platform', {
373+
value: originalPlatform,
374+
})
375+
}
376+
},
377+
)
378+
})
379+
320380
describe('when the save path has non-file scheme', () => {
321381
it('exports the document into temporally path and copy it to the save path', async () => {
322382
const marpCliMock = jest.spyOn(marpCli, 'default').mockImplementation()

src/commands/export.ts

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ const descriptions = {
4545
[Types.jpeg]: 'JPEG image (first slide only)' as const,
4646
}
4747

48+
const browsers = {
49+
chrome: '[Google Chrome](https://www.google.com/chrome/)',
50+
chromium: '[Chromium](https://www.chromium.org/)',
51+
edge: '[Microsoft Edge](https://www.microsoft.com/edge)',
52+
firefox: '[Mozilla Firefox](https://www.mozilla.org/firefox/)',
53+
} as const
54+
4855
export const ITEM_CONTINUE_TO_EXPORT = 'Continue to export...'
4956
export const ITEM_MANAGE_WORKSPACE_TRUST = 'Manage Workspace Trust...'
5057

@@ -140,9 +147,51 @@ export const doExport = async (uri: Uri, document: TextDocument) => {
140147
})
141148

142149
try {
143-
await marpCli(['-c', conf.path, input.path, '-o', outputPath], {
144-
baseUrl,
145-
})
150+
await marpCli(
151+
['-c', conf.path, input.path, '-o', outputPath],
152+
{ baseUrl },
153+
{
154+
onCLIError: ({ error, codes }) => {
155+
if (error.errorCode === codes.NOT_FOUND_BROWSER) {
156+
// Throw error with user-friendly instructions based on the current configuration
157+
const browserOption = marpConfiguration().get<string>('browser')
158+
const suggestBrowsers: string[] = []
159+
160+
switch (browserOption) {
161+
case 'chrome':
162+
suggestBrowsers.push(
163+
...[
164+
browsers.chrome,
165+
process.platform === 'linux' ? browsers.chromium : '',
166+
].filter((b) => !!b),
167+
)
168+
break
169+
case 'edge':
170+
suggestBrowsers.push(browsers.edge)
171+
break
172+
case 'firefox':
173+
suggestBrowsers.push(browsers.firefox)
174+
break
175+
default:
176+
suggestBrowsers.push(
177+
...[
178+
browsers.chrome,
179+
process.platform === 'linux' ? browsers.chromium : '',
180+
browsers.edge,
181+
browsers.firefox,
182+
].filter((b) => !!b),
183+
)
184+
}
185+
186+
throw new MarpCLIError(
187+
`It requires to install a suitable browser, ${suggestBrowsers
188+
.join(', ')
189+
.replace(/, ([^,]*)$/, ' or $1')} for exporting.`,
190+
)
191+
}
192+
},
193+
},
194+
)
146195

147196
if (outputToLocalFS) {
148197
env.openExternal(uri)

src/marp-cli.test.ts

Lines changed: 1 addition & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ import { textEncoder } from './utils'
77

88
jest.mock('vscode')
99

10-
const setConfiguration: (conf?: Record<string, unknown>) => void = (
11-
workspace as any
12-
)._setConfiguration
13-
1410
describe('Marp CLI integration', () => {
1511
const runMarpCli = marpCli.default
1612

@@ -31,7 +27,7 @@ describe('Marp CLI integration', () => {
3127
})
3228

3329
it('runs Marp CLI with passed args', async () => {
34-
const marpCliSpy = jest.spyOn(marpCliModule, 'marpCli')
30+
const marpCliSpy = jest.spyOn(marpCliModule, 'marpCli').mockResolvedValue(0)
3531
await runMarpCli(['--version'])
3632

3733
expect(marpCliSpy).toHaveBeenCalledWith(['--version'], undefined)
@@ -50,67 +46,6 @@ describe('Marp CLI integration', () => {
5046
marpCliMock.mockRestore()
5147
}
5248
})
53-
54-
it.each`
55-
platform | expected
56-
${'win32'} | ${[/Google Chrome/, /Microsoft Edge/]}
57-
${'darwin'} | ${[/Google Chrome/, /Microsoft Edge/]}
58-
${'linux'} | ${[/Google Chrome/, /Chromium/]}
59-
`(
60-
'contains $expected to suggested browsers in error message when running on $platform',
61-
async ({ platform, expected }) => {
62-
expect.assertions(expected.length)
63-
64-
const originalPlatform = process.platform
65-
66-
try {
67-
Object.defineProperty(process, 'platform', { value: platform })
68-
69-
const marpCliMock = jest
70-
.spyOn(marpCliModule, 'marpCli')
71-
.mockRejectedValue(
72-
new marpCliModule.CLIError(
73-
'mocked error',
74-
marpCliModule.CLIErrorCode.NOT_FOUND_CHROMIUM,
75-
),
76-
)
77-
78-
try {
79-
for (const fragment of expected) {
80-
await expect(runMarpCli(['--version'])).rejects.toThrow(fragment)
81-
}
82-
} finally {
83-
marpCliMock.mockRestore()
84-
}
85-
} finally {
86-
Object.defineProperty(process, 'platform', { value: originalPlatform })
87-
}
88-
},
89-
)
90-
91-
describe('with markdown.marp.chromePath preference', () => {
92-
it('runs Marp CLI with overridden CHROME_PATH environment', async () => {
93-
const { CHROME_PATH } = process.env
94-
expect(process.env.CHROME_PATH).toBe(CHROME_PATH)
95-
96-
setConfiguration({ 'markdown.marp.chromePath': __filename })
97-
98-
const marpCliMock = jest
99-
.spyOn(marpCliModule, 'marpCli')
100-
.mockImplementation(async () => {
101-
expect(process.env.CHROME_PATH).toBe(__filename)
102-
return 0
103-
})
104-
105-
try {
106-
await runMarpCli(['--version'])
107-
expect(marpCliMock).toHaveBeenCalled()
108-
expect(process.env.CHROME_PATH).toBe(CHROME_PATH)
109-
} finally {
110-
marpCliMock.mockRestore()
111-
}
112-
})
113-
})
11449
})
11550

11651
describe('#createWorkFile', () => {

0 commit comments

Comments
 (0)