Skip to content

Commit

Permalink
refactor(vscode): migrate to reactive-vscode (#1673)
Browse files Browse the repository at this point in the history
  • Loading branch information
kermanx authored Jul 13, 2024
1 parent 4982e45 commit 4f20e30
Show file tree
Hide file tree
Showing 31 changed files with 254 additions and 521 deletions.
1 change: 1 addition & 0 deletions packages/vscode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Presentation <b>slide</b>s for <b>dev</b>elopers<br>
<p align="center">
<a href="https://marketplace.visualstudio.com/items?itemName=antfu.slidev" target="__blank"><img src="https://img.shields.io/visual-studio-marketplace/v/antfu.slidev.svg?color=4EC5D4&amp;label=VS%20Code%20Marketplace&logo=visual-studio-code" alt="Visual Studio Marketplace Version" /></a>
<a href="https://marketplace.visualstudio.com/items?itemName=antfu.slidev" target="__blank"><img src="https://img.shields.io/visual-studio-marketplace/d/antfu.slidev.svg?color=2B90B6" alt="Visual Studio Marketplace Downloads" /></a>
<a href="https://kermanx.github.io/reactive-vscode/" target="__blank"><img src="https://img.shields.io/badge/made_with-reactive--vscode-%23007ACC?style=flat&labelColor=%23229863" alt="Made with reacrive-vscode" /></a>
</p>

<br>
Expand Down
10 changes: 4 additions & 6 deletions packages/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,8 @@
"scripts": {
"publish": "esno scripts/publish.ts",
"pack": "vsce package --no-dependencies",
"build": "tsup --env.NODE_ENV production",
"dev": "nr build --watch",
"build": "tsup --env.NODE_ENV production --treeshake",
"dev": "tsup --watch ./src --env.NODE_ENV development",
"vscode:prepublish": "nr build"
},
"devDependencies": {
Expand All @@ -359,10 +359,8 @@
"@slidev/types": "workspace:*",
"@types/node": "^20.14.10",
"@types/vscode": "~1.89.0",
"@vue/reactivity": "^3.4.31",
"@vue/runtime-core": "^3.4.31",
"@vue/shared": "^3.4.31",
"get-port-please": "^3.1.2",
"ovsx": "^0.9.1"
"ovsx": "^0.9.1",
"reactive-vscode": "0.2.0-beta.3"
}
}
62 changes: 28 additions & 34 deletions packages/vscode/src/commands.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { relative } from 'node:path'
import { onScopeDispose } from '@vue/runtime-core'
import type { Disposable } from 'vscode'
import { Position, Range, Selection, TextEditorRevealType, Uri, commands, window, workspace } from 'vscode'
import { save as saveSlidevMarkdown } from '@slidev/parser/fs'
import { slash } from '@antfu/utils'
import { save as saveSlidevMarkdown } from '@slidev/parser/fs'
import { useCommand } from 'reactive-vscode'
import { Position, Range, Selection, TextEditorRevealType, Uri, window, workspace } from 'vscode'
import { useDevServer } from './composables/useDevServer'
import { useEditingSlideSource } from './composables/useEditingSlideSource'
import { useFocusedSlideNo } from './composables/useFocusedSlideNo'
Expand All @@ -12,29 +11,23 @@ import type { SlidevProject } from './projects'
import { activeEntry, activeProject, activeSlidevData, addProject, projects, rescanProjects } from './projects'
import { findPossibleEntries } from './utils/findPossibleEntries'
import { usePreviewWebview } from './views/previewWebview'
import type { SlidesTreeElement } from './views/slidesTree'
import type { SlidesTreeNode } from './views/slidesTree'

export function useCommands() {
const disposables: Disposable[] = []
onScopeDispose(() => disposables.forEach(d => d.dispose()))
function registerCommand(command: string, callback: (...args: any[]) => any) {
disposables.push(commands.registerCommand(command, callback))
}

registerCommand('slidev.enable-extension', () => forceEnabled.value = true)
registerCommand('slidev.disable-extension', () => forceEnabled.value = false)
useCommand('slidev.enable-extension', () => forceEnabled.value = true)
useCommand('slidev.disable-extension', () => forceEnabled.value = false)

registerCommand('slidev.rescan-projects', rescanProjects)
useCommand('slidev.rescan-projects', rescanProjects)

registerCommand('slidev.choose-entry', async () => {
useCommand('slidev.choose-entry', async () => {
const entry = await window.showQuickPick([...projects.keys()], {
title: 'Choose active slides entry.',
})
if (entry)
activeEntry.value = entry
})

registerCommand('slidev.add-entry', async () => {
useCommand('slidev.add-entry', async () => {
const files = await findPossibleEntries()
const selected = await window.showQuickPick(files, {
title: 'Choose Markdown files to add as slides entries.',
Expand All @@ -46,23 +39,24 @@ export function useCommands() {
if (workspace.workspaceFolders) {
const workspaceRoot = workspace.workspaceFolders[0].uri.fsPath
const relatives = selected.map(s => slash(relative(workspaceRoot, s)))
include.value = [...include.value, ...relatives]
// write back to settings.json
include.update([...include.value, ...relatives])
}
}
})

registerCommand('slidev.remove-entry', async (project: SlidevProject) => {
useCommand('slidev.remove-entry', async (project: SlidevProject) => {
const entry = project.entry
if (activeEntry.value === entry)
activeEntry.value = null
projects.delete(entry)
})

registerCommand('slidev.set-as-active', async (project: SlidevProject) => {
useCommand('slidev.set-as-active', async (project: SlidevProject) => {
activeEntry.value = project.entry
})

registerCommand('slidev.stop-dev', async (project: SlidevProject) => {
useCommand('slidev.stop-dev', async (project: SlidevProject) => {
const { stop } = useDevServer(project)
stop()
})
Expand Down Expand Up @@ -98,24 +92,24 @@ export function useCommands() {
}
}

registerCommand('slidev.goto', gotoSlide)
registerCommand('slidev.next', () => {
useCommand('slidev.goto', gotoSlide)
useCommand('slidev.next', () => {
const { markdown, index } = useEditingSlideSource()
const focusedSlideNo = useFocusedSlideNo()
gotoSlide(markdown.value!.filepath, index.value + 1, () => focusedSlideNo.value + 1)
})
registerCommand('slidev.prev', () => {
useCommand('slidev.prev', () => {
const { markdown, index } = useEditingSlideSource()
const focusedSlideNo = useFocusedSlideNo()
gotoSlide(markdown.value!.filepath, index.value - 1, () => focusedSlideNo.value - 1)
})

registerCommand('slidev.refresh-preview', () => {
useCommand('slidev.refresh-preview', () => {
const { refresh } = usePreviewWebview()
refresh()
})

registerCommand('slidev.config-port', async () => {
useCommand('slidev.config-port', async () => {
const port = await window.showInputBox({
prompt: 'Slidev Preview Port',
value: configuredPort.value.toString(),
Expand All @@ -132,7 +126,7 @@ export function useCommands() {
configuredPort.value = +port
})

registerCommand('slidev.start-dev', async () => {
useCommand('slidev.start-dev', async () => {
const project = activeProject.value
if (!project) {
window.showErrorMessage('Cannot start dev server: No active slides project.')
Expand All @@ -150,17 +144,17 @@ export function useCommands() {
setTimeout(retry, 9000)
})

registerCommand('slidev.open-in-browser', () => usePreviewWebview().openExternal())
useCommand('slidev.open-in-browser', () => usePreviewWebview().openExternal())

registerCommand('slidev.preview-prev-click', () => usePreviewWebview().prevClick())
registerCommand('slidev.preview-next-click', () => usePreviewWebview().nextClick())
registerCommand('slidev.preview-prev-slide', () => usePreviewWebview().prevSlide())
registerCommand('slidev.preview-next-slide', () => usePreviewWebview().nextSlide())
useCommand('slidev.preview-prev-click', () => usePreviewWebview().prevClick())
useCommand('slidev.preview-next-click', () => usePreviewWebview().nextClick())
useCommand('slidev.preview-prev-slide', () => usePreviewWebview().prevSlide())
useCommand('slidev.preview-next-slide', () => usePreviewWebview().nextSlide())

registerCommand('slidev.enable-preview-sync', () => (previewSync.value = true))
registerCommand('slidev.disable-preview-sync', () => (previewSync.value = false))
useCommand('slidev.enable-preview-sync', () => (previewSync.value = true))
useCommand('slidev.disable-preview-sync', () => (previewSync.value = false))

registerCommand('slidev.remove-slide', async ({ slide }: SlidesTreeElement) => {
useCommand('slidev.remove-slide', async ({ slide }: SlidesTreeNode) => {
const md = activeSlidevData.value!.markdownFiles[slide.filepath]
md.slides.splice(md.slides.indexOf(slide), 1)
await saveSlidevMarkdown(md)
Expand Down
19 changes: 0 additions & 19 deletions packages/vscode/src/composables/useActiveTextEditor.ts

This file was deleted.

16 changes: 8 additions & 8 deletions packages/vscode/src/composables/useDevServer.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { basename } from 'node:path'
import type { Ref } from '@vue/runtime-core'
import { toRef } from '@vue/runtime-core'
import type { Ref } from 'reactive-vscode'
import { toRef } from 'reactive-vscode'
import { getPort as getPortPlease } from 'get-port-please'
import type { Terminal } from 'vscode'
import type { SlidevProject } from '../projects'
import { useTerminal } from '../views/terminal'
import { useServerTerminal } from '../views/serverTerminal'
import { useServerDetector } from './useServerDetector'

export type Server = {
port: Ref<number | null>
terminal: Ref<Terminal | null>
start: () => Promise<void>
showTerminal: () => Promise<void>
start: () => void
showTerminal: () => void
stop: () => void
} & ReturnType<typeof useServerDetector>

Expand All @@ -22,18 +22,18 @@ export function useDevServer(project: SlidevProject) {
if (existing)
return existing

const { terminal, isTerminalActive, showTerminal, sendText, closeTerminal } = useTerminal(project)
const { terminal, getIsActive, show: showTerminal, sendText, close } = useServerTerminal(project)
const port = toRef(project, 'port')

async function start() {
if (isTerminalActive())
if (getIsActive())
return
port.value ??= await getPort()
sendText(`npm exec slidev -- --port ${port.value} ${JSON.stringify(basename(project.entry))}`)
}

function stop() {
closeTerminal()
close()
port.value = null
}

Expand Down
7 changes: 0 additions & 7 deletions packages/vscode/src/composables/useDisposable.ts

This file was deleted.

20 changes: 0 additions & 20 deletions packages/vscode/src/composables/useDocumentText.ts

This file was deleted.

21 changes: 6 additions & 15 deletions packages/vscode/src/composables/useEditingSlideSource.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,24 @@
import { computed, ref, watch } from '@vue/runtime-core'
import { window } from 'vscode'
import { activeSlidevData } from '../projects'
import { createSingletonComposable } from '../utils/singletonComposable'
import { useActiveTextEditor } from './useActiveTextEditor'
import { useDisposable } from './useDisposable'
import { computed, createSingletonComposable, ref, useActiveTextEditor, useTextEditorSelection, watchEffect } from 'reactive-vscode'
import { useProjectFromDoc } from './useProjectFromDoc'

export const useEditingSlideSource = createSingletonComposable(() => {
const editor = useActiveTextEditor()
const projectInfo = useProjectFromDoc(() => editor.value?.document)
const markdown = computed(() => projectInfo.value?.md)
const selection = useTextEditorSelection(editor)

const index = ref(0)

function updateSlideNo() {
watchEffect(() => {
const md = markdown.value
if (!md || !editor.value) {
index.value = 0
return
}
const line = editor.value.selection.active.line + 1
const line = selection.value.active.line + 1
const slide = md.slides.find(s => line <= s.end)
index.value = slide ? slide.index : md.slides.length - 1
}

updateSlideNo()

useDisposable(window.onDidChangeTextEditorSelection(updateSlideNo))

watch([editor, activeSlidevData], updateSlideNo)
})

return {
markdown,
Expand Down
23 changes: 6 additions & 17 deletions packages/vscode/src/composables/useFocusedSlideNo.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
import { ref, watch } from '@vue/runtime-core'
import { TextEditorSelectionChangeKind, window } from 'vscode'
import { createSingletonComposable, ref, useActiveTextEditor, useTextEditorSelection, watchEffect } from 'reactive-vscode'
import { TextEditorSelectionChangeKind } from 'vscode'
import { activeSlidevData } from '../projects'
import { getFirstDisplayedChild } from '../utils/getFirstDisplayedChild'
import { createSingletonComposable } from '../utils/singletonComposable'
import { useActiveTextEditor } from './useActiveTextEditor'
import { useDisposable } from './useDisposable'
import { getProjectFromDoc } from './useProjectFromDoc'

export const useFocusedSlideNo = createSingletonComposable(() => {
const editor = useActiveTextEditor()
const selection = useTextEditorSelection(editor, [TextEditorSelectionChangeKind.Command, undefined])

const slideNo = ref(1)

function updateSlideNo() {
watchEffect(() => {
const data = activeSlidevData.value
const projectInfo = getProjectFromDoc(editor.value?.document)
if (!data || !projectInfo || !editor.value)
return
const line = editor.value.selection.active.line + 1
const line = selection.value.active.line + 1
const slide = projectInfo.md.slides.find(s => s.start <= line && line <= s.end)
if (slide) {
const source = getFirstDisplayedChild(slide)
Expand All @@ -28,16 +26,7 @@ export const useFocusedSlideNo = createSingletonComposable(() => {
if (no)
slideNo.value = no
}
}

updateSlideNo()

useDisposable(window.onDidChangeTextEditorSelection(({ kind }) => {
if (kind !== TextEditorSelectionChangeKind.Command)
updateSlideNo()
}))

watch(activeSlidevData, updateSlideNo)
})

return slideNo
})
8 changes: 3 additions & 5 deletions packages/vscode/src/composables/usePreviewState.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { computed, onScopeDispose, watchEffect } from '@vue/runtime-core'
import { computed, createSingletonComposable, onScopeDispose, useVscodeContext, watchEffect } from 'reactive-vscode'
import { window } from 'vscode'
import { activeEntry, activeProject, projects } from '../projects'
import { createSingletonComposable } from '../utils/singletonComposable'
import { configuredPort } from '../configs'
import { generateReadyHtml } from '../html/ready'
import { generateErrorHtml } from '../html/error'
import { generateReadyHtml } from '../html/ready'
import { activeEntry, activeProject, projects } from '../projects'
import { useDevServer } from './useDevServer'
import { useServerDetector } from './useServerDetector'
import { useVscodeContext } from './useVscodeContext'

export const usePreviewState = createSingletonComposable(() => {
const detectServer = useServerDetector(configuredPort)
Expand Down
4 changes: 2 additions & 2 deletions packages/vscode/src/composables/useProjectFromDoc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { slash } from '@antfu/utils'
import type { MaybeRefOrGetter } from '@vue/runtime-core'
import { computed, toValue } from '@vue/runtime-core'
import type { MaybeRefOrGetter } from 'reactive-vscode'
import { computed, toValue } from 'reactive-vscode'
import type { TextDocument } from 'vscode'
import { activeProject, projects } from '../projects'

Expand Down
4 changes: 2 additions & 2 deletions packages/vscode/src/composables/useServerDetector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Ref } from '@vue/runtime-core'
import { reactive, watch } from '@vue/runtime-core'
import type { Ref } from 'reactive-vscode'
import { reactive, watch } from 'reactive-vscode'

const versionRE = /<meta name="slidev:version" content="([^"]+)">/
const entryRE = /<meta charset="slidev:entry" content="([^"]+)">/
Expand Down
9 changes: 0 additions & 9 deletions packages/vscode/src/composables/useViewVisibility.ts

This file was deleted.

Loading

0 comments on commit 4f20e30

Please sign in to comment.