返回 slidev
commands.ts
根目录 / packages / vscode / src / commands.ts
1 import { slash } from '@antfu/utils'
2 import { relative } from 'pathe'
3 import { useCommand } from 'reactive-vscode'
4 import { ConfigurationTarget, window, workspace } from 'vscode'
5 import { useDevServer } from './composables/useDevServer'
6 import { useFocusedSlide } from './composables/useFocusedSlide'
7 import { config } from './configs'
8 import { activeEntry, activeProject, addProject, projects, rescanProjects } from './projects'
9 import { findPossibleEntries } from './utils/findPossibleEntries'
10 import { getSlidesTitle } from './utils/getSlidesTitle'
11 import { usePreviewWebview } from './views/previewWebview'
12
13 const RE_DIGITS = /^\d+$/
14
15 export function useCommands() {
16 useCommand('slidev.enable-extension', () => config.update('force-enabled', true, ConfigurationTarget.Workspace))
17 useCommand('slidev.disable-extension', () => config.update('force-enabled', false, ConfigurationTarget.Workspace))
18
19 useCommand('slidev.rescan-projects', rescanProjects)
20
21 useCommand('slidev.choose-entry', async () => {
22 while (true) {
23 const addNewEntry = '$(add) Add new slides entry...'
24 const entry = await window.showQuickPick(
25 [...projects.keys(), addNewEntry],
26 {
27 title: 'Choose active slides entry.',
28 },
29 )
30 if (entry === addNewEntry) {
31 if (!await addEntry()) {
32 break
33 }
34 }
35 else if (entry) {
36 activeEntry.value = entry
37 break
38 }
39 else {
40 break
41 }
42 }
43 })
44
45 useCommand('slidev.add-entry', addEntry)
46
47 async function addEntry() {
48 const files = await findPossibleEntries()
49 const selected = await window.showQuickPick(files, {
50 title: 'Choose Markdown files to add as slides entries.',
51 canPickMany: true,
52 })
53 if (selected) {
54 for (const entry of selected)
55 await addProject(entry)
56 if (workspace.workspaceFolders) {
57 const workspaceRoot = workspace.workspaceFolders[0].uri.fsPath
58 const relatives = selected.map(s => slash(relative(workspaceRoot, s)))
59 // write back to settings.json
60 await config.update('include', [...config.include, ...relatives])
61 }
62 }
63 return !!selected
64 }
65
66 useCommand('slidev.remove-entry', async (node: any) => {
67 const entry = slash(node.treeItem.resourceUri.fsPath)
68 if (activeEntry.value === entry)
69 activeEntry.value = null
70 projects.delete(entry)
71 })
72
73 useCommand('slidev.set-as-active', async (node: any) => {
74 const entry = slash(node.treeItem.resourceUri.fsPath)
75 activeEntry.value = entry
76 })
77
78 useCommand('slidev.goto', (filepath: string, index: number) => {
79 const { gotoSlide } = useFocusedSlide()
80 gotoSlide(filepath, index)
81 })
82 useCommand('slidev.next', () => {
83 const { focusedMarkdown, focusedSourceSlide, gotoSlide } = useFocusedSlide()
84 if (!focusedMarkdown.value || focusedSourceSlide.value == null)
85 return
86 gotoSlide(focusedMarkdown.value.filepath, focusedSourceSlide.value.index + 1)
87 })
88 useCommand('slidev.prev', () => {
89 const { focusedMarkdown, focusedSourceSlide, gotoSlide } = useFocusedSlide()
90 if (!focusedMarkdown.value || focusedSourceSlide.value == null)
91 return
92 gotoSlide(focusedMarkdown.value.filepath, focusedSourceSlide.value.index - 1)
93 })
94
95 useCommand('slidev.refresh-preview', async () => {
96 const { refresh } = usePreviewWebview()
97 await refresh()
98 })
99
100 useCommand('slidev.config-port', async () => {
101 if (!activeProject.value) {
102 window.showErrorMessage('No active project to configure port.')
103 return
104 }
105 const port = await window.showInputBox({
106 prompt: `Slidev Preview Port for ${getSlidesTitle(activeProject.value.data)}`,
107 value: config.port.toString(),
108 validateInput: (v) => {
109 if (!RE_DIGITS.test(v))
110 return 'Port should be a number'
111 if (+v < 1024 || +v > 65535)
112 return 'Port should be between 1024 and 65535'
113 return null
114 },
115 })
116 if (port && activeProject.value) {
117 activeProject.value.port.value = +port
118 }
119 })
120
121 useCommand('slidev.start-dev', async () => {
122 const project = activeProject.value
123 if (!project) {
124 window.showErrorMessage('Cannot start dev server: No active slides project.')
125 return
126 }
127
128 const { start, terminal } = useDevServer(project)
129 start()
130 terminal.value?.show()
131 })
132
133 useCommand('slidev.open-in-browser', () => usePreviewWebview().openExternal())
134
135 useCommand('slidev.preview-prev-click', () => usePreviewWebview().prevClick())
136 useCommand('slidev.preview-next-click', () => usePreviewWebview().nextClick())
137 useCommand('slidev.preview-prev-slide', () => usePreviewWebview().prevSlide())
138 useCommand('slidev.preview-next-slide', () => usePreviewWebview().nextSlide())
139 useCommand('slidev.show-slide-preview', () => usePreviewWebview().setPreviewMode('slide'))
140 useCommand('slidev.show-overview-preview', () => usePreviewWebview().setPreviewMode('overview'))
141
142 useCommand('slidev.enable-preview-sync', () => (config.update('preview-sync', true, ConfigurationTarget.Global)))
143 useCommand('slidev.disable-preview-sync', () => (config.update('preview-sync', false, ConfigurationTarget.Global)))
144 }
145
145 lines TYPESCRIPT