Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions packages/vscode/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { useCommand } from 'reactive-vscode'
import { ConfigurationTarget, window, workspace } from 'vscode'
import { useDevServer } from './composables/useDevServer'
import { useFocusedSlide } from './composables/useFocusedSlide'
import { configuredPort, forceEnabled, include, previewSync } from './configs'
import { config } from './configs'
import { activeEntry, activeProject, addProject, projects, rescanProjects } from './projects'
import { findPossibleEntries } from './utils/findPossibleEntries'
import { getSlidesTitle } from './utils/getSlidesTitle'
import { usePreviewWebview } from './views/previewWebview'

export function useCommands() {
useCommand('slidev.enable-extension', () => forceEnabled.value = true)
useCommand('slidev.disable-extension', () => forceEnabled.value = false)
useCommand('slidev.enable-extension', () => config.update('enabled', true, ConfigurationTarget.Workspace))
useCommand('slidev.disable-extension', () => config.update('enabled', false, ConfigurationTarget.Workspace))

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

Expand Down Expand Up @@ -55,7 +55,7 @@ export function useCommands() {
const workspaceRoot = workspace.workspaceFolders[0].uri.fsPath
const relatives = selected.map(s => slash(relative(workspaceRoot, s)))
// write back to settings.json
await include.update([...include.value, ...relatives])
await config.update('include', [...config.include, ...relatives])
}
}
return !!selected
Expand Down Expand Up @@ -102,7 +102,7 @@ export function useCommands() {
}
const port = await window.showInputBox({
prompt: `Slidev Preview Port for ${getSlidesTitle(activeProject.value.data)}`,
value: configuredPort.value.toString(),
value: config.port.toString(),
validateInput: (v) => {
if (!v.match(/^\d+$/))
return 'Port should be a number'
Expand All @@ -123,9 +123,9 @@ export function useCommands() {
return
}

const { start, showTerminal } = useDevServer(project)
const { start, terminal } = useDevServer(project)
start()
showTerminal()
terminal.value?.show()
})

useCommand('slidev.open-in-browser', () => usePreviewWebview().openExternal())
Expand All @@ -135,6 +135,6 @@ export function useCommands() {
useCommand('slidev.preview-prev-slide', () => usePreviewWebview().prevSlide())
useCommand('slidev.preview-next-slide', () => usePreviewWebview().nextSlide())

useCommand('slidev.enable-preview-sync', () => (previewSync.update(true, ConfigurationTarget.Global)))
useCommand('slidev.disable-preview-sync', () => (previewSync.update(false, ConfigurationTarget.Global)))
useCommand('slidev.enable-preview-sync', () => (config.update('preview-sync', true, ConfigurationTarget.Global)))
useCommand('slidev.disable-preview-sync', () => (config.update('preview-sync', false, ConfigurationTarget.Global)))
}
37 changes: 19 additions & 18 deletions packages/vscode/src/composables/useDevServer.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import type { EffectScope, Ref } from 'reactive-vscode'
import type { EffectScope, ShallowRef } from 'reactive-vscode'
import type { Terminal } from 'vscode'
import type { SlidevProject } from '../projects'
import { basename } from 'node:path'
import { effectScope, onScopeDispose, useAbsolutePath, useControlledTerminal } from 'reactive-vscode'
import { env, Uri } from 'vscode'
import { devCommand } from '../configs'
import { effectScope, onScopeDispose, shallowRef, useAbsoluteUri, useDisposable } from 'reactive-vscode'
import { env, window } from 'vscode'
import { config } from '../configs'
import { getSlidesTitle } from '../utils/getSlidesTitle'
import { useServerDetector } from './useServerDetector'

export interface SlidevServer {
scope: EffectScope
terminal: Ref<Terminal | null>
terminal: ShallowRef<Terminal | null>
start: () => void
showTerminal: () => void
}

export function useDevServer(project: SlidevProject) {
Expand All @@ -24,27 +23,30 @@ export function useDevServer(project: SlidevProject) {

const scope = effectScope(true)
return server.value = scope.run(() => {
const { terminal, getIsActive, show: showTerminal, sendText, close } = useControlledTerminal({
name: getSlidesTitle(project.data),
cwd: project.userRoot,
iconPath: {
light: Uri.file(useAbsolutePath('dist/res/logo-mono.svg').value),
dark: Uri.file(useAbsolutePath('dist/res/logo-mono-dark.svg').value),
},
isTransient: true,
})
const terminal = shallowRef<Terminal | null>(null)

async function start() {
if (getIsActive())
if (terminal.value && terminal.value.exitStatus == null)
return

terminal.value = useDisposable(window.createTerminal({
name: getSlidesTitle(project.data),
cwd: project.userRoot,
iconPath: {
light: useAbsoluteUri('dist/res/logo-mono.svg').value,
dark: useAbsoluteUri('dist/res/logo-mono-dark.svg').value,
},
isTransient: true,
}))

const p = port.value ??= await allocPort()
const args = [
JSON.stringify(basename(project.entry)),
`--port ${p}`,
env.remoteName != null ? '--remote' : '',
].filter(Boolean).join(' ')
// eslint-disable-next-line no-template-curly-in-string
sendText(devCommand.value.replaceAll('${args}', args).replaceAll('${port}', `${p}`))
terminal.value.sendText(config['dev-command'].replaceAll('${args}', args).replaceAll('${port}', `${p}`))

let intervalCount = 0
const maxIntervals = 100
Expand All @@ -66,7 +68,6 @@ export function useDevServer(project: SlidevProject) {
scope,
terminal,
start,
showTerminal,
}
})!
}
2 changes: 1 addition & 1 deletion packages/vscode/src/composables/useFocusedSlide.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const useFocusedSlide = defineService(() => {
const focusedSourceSlide = useDebouncedComputed(
() => {
const md = focusedMarkdown.value
if (!md || !debouncedEditor.value) {
if (!md || !debouncedEditor.value || !selection.value) {
return null
}
const line = selection.value.active.line + 1
Expand Down
6 changes: 3 additions & 3 deletions packages/vscode/src/composables/useServerDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { SlidevProject } from '../projects'
import { createControlledPromise } from '@antfu/utils'
import { getPort as getPortPlease } from 'get-port-please'
import { computed, defineService, onScopeDispose, reactive, watch } from 'reactive-vscode'
import { configuredPort } from '../configs'
import { config } from '../configs'
import { activeProject, askAddProject, projects, scannedProjects } from '../projects'
import { logger } from '../views/logger'

Expand Down Expand Up @@ -68,7 +68,7 @@ export const useServerDetector = defineService(() => {
}

const portsToDetect = computed(() => {
const ports = new Set([configuredPort.value])
const ports = new Set([config.port])
for (const project of projects.values()) {
if (project.port.value)
ports.add(project.port.value)
Expand All @@ -92,7 +92,7 @@ export const useServerDetector = defineService(() => {
onScopeDispose(() => clearInterval(interval))

function getDetected(project: SlidevProject) {
const port = project.port.value || configuredPort.value
const port = project.port.value || config.port
const detected = detectedPorts.get(port)
if (detected?.entry === project.entry)
return detected
Expand Down
32 changes: 11 additions & 21 deletions packages/vscode/src/configs.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
import type { ConfigType } from 'reactive-vscode'
import { defineConfigs } from 'reactive-vscode'
import { defineConfig } from 'reactive-vscode'

export const {
'force-enabled': forceEnabled,
'port': configuredPort,
'annotations': displayAnnotations,
'annotations-line-numbers': displayCodeBlockLineNumbers,
'preview-sync': previewSync,
include,
exclude,
'dev-command': devCommand,
} = defineConfigs('slidev', {
'force-enabled': Boolean,
'port': Number,
'annotations': Boolean,
'annotations-line-numbers': Boolean,
'preview-sync': Boolean,
'include': Object as ConfigType<string[]>,
'exclude': String,
'dev-command': String,
})
export const config = defineConfig<{
'force-enabled': boolean
'port': number
'annotations': boolean
'annotations-line-numbers': boolean
'preview-sync': boolean
'include': string[]
'exclude': string
'dev-command': string
}>('slidev')
31 changes: 17 additions & 14 deletions packages/vscode/src/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import { basename, dirname } from 'node:path'
import { debounce, slash } from '@antfu/utils'
import { load } from '@slidev/parser/fs'
import { isMatch } from 'picomatch'
import { computed, effectScope, extensionContext, markRaw, onScopeDispose, ref, shallowReactive, shallowRef, useDisposable, useFsWatcher, useVscodeContext, watch, watchEffect } from 'reactive-vscode'
import { computed, effectScope, extensionContext, markRaw, onScopeDispose, ref, shallowReactive, shallowRef, useDisposable, useFileSystemWatcher, useVscodeContext, watch, watchEffect } from 'reactive-vscode'
import { FileSystemError, Uri, window, workspace } from 'vscode'
import { useServerDetector } from './composables/useServerDetector'
import { exclude, forceEnabled, include } from './configs'
import { config } from './configs'
import { findShallowestPath } from './utils/findShallowestPath'
import { logger } from './views/logger'

Expand All @@ -31,18 +31,20 @@ export const activeProject = computed(() => activeEntry.value ? projects.get(act
export const activeData = computed(() => activeProject.value?.data)

export function useProjects() {
const watcher = useFsWatcher(include, false, true, false)
watcher.onDidCreate(async (uri) => {
const path = slash(uri.fsPath)
if (!isMatch(path, exclude.value))
await addProject(path)
})
watcher.onDidDelete(async (uri) => {
removeProject(slash(uri.fsPath))
useFileSystemWatcher(() => config.include, {
async onDidCreate(uri) {
const path = slash(uri.fsPath)
if (!isMatch(path, config.exclude))
await addProject(path)
},
onDidChange: false,
async onDidDelete(uri) {
removeProject(slash(uri.fsPath))
},
})

rescanProjects()
watch([include, exclude], debounce(200, rescanProjects))
watch(() => [config.include, config.exclude], debounce(200, rescanProjects))

// In case all the projects are removed manually, and the user may not want to disable the extension.
const everHadProjects = ref(false)
Expand Down Expand Up @@ -80,7 +82,8 @@ export function useProjects() {
}, { immediate: true })

useVscodeContext('slidev:enabled', () => {
const enabled = forceEnabled.value == null ? everHadProjects.value : forceEnabled.value
const forceEnabled = config['force-enabled']
const enabled = forceEnabled == null ? everHadProjects.value : forceEnabled
logger.info(`Slidev ${enabled ? 'enabled' : 'disabled'}.`)
return enabled
})
Expand All @@ -102,8 +105,8 @@ export async function rescanProjects() {
scanningProjects = true
try {
const entries = new Set<string>()
for (const glob of include.value) {
(await workspace.findFiles(glob, exclude.value))
for (const glob of config.include) {
(await workspace.findFiles(glob, config.exclude))
.forEach(file => entries.add(file.fsPath))
}
for (const entry of entries) {
Expand Down
47 changes: 8 additions & 39 deletions packages/vscode/src/views/annotations.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { SourceSlideInfo } from '@slidev/types'
import type { DecorationOptions } from 'vscode'
import { clamp, debounce, ensurePrefix } from '@antfu/utils'
import { computed, defineService, onScopeDispose, useActiveTextEditor, watch } from 'reactive-vscode'
import { Position, Range, ThemeColor, window, workspace } from 'vscode'
import { clamp, ensurePrefix } from '@antfu/utils'
import { computed, defineService, useActiveTextEditor, watch } from 'reactive-vscode'
import { Position, Range, ThemeColor, window } from 'vscode'
import { useProjectFromDoc } from '../composables/useProjectFromDoc'
import { displayAnnotations, displayCodeBlockLineNumbers } from '../configs'
import { config } from '../configs'
import { activeProject } from '../projects'
import { toRelativePath } from '../utils/toRelativePath'

Expand Down Expand Up @@ -94,7 +94,7 @@ function findCodeBlocks(docText: string): CodeBlockInfo[] {
}

function updateCodeBlockLineNumbers(editor: ReturnType<typeof useActiveTextEditor>['value'], docText: string) {
if (!editor || !displayCodeBlockLineNumbers.value)
if (!editor || !config['annotations-line-numbers'])
return

const codeBlockLineNumbers: DecorationOptions[] = []
Expand Down Expand Up @@ -141,44 +141,13 @@ export const useAnnotations = defineService(() => {
const doc = computed(() => editor.value?.document)
const projectInfo = useProjectFromDoc(doc)

let debouncedUpdateLineNumbers: ((docText: string) => void) | null = null

watch(
[editor, displayCodeBlockLineNumbers],
([currentEditor, lineNumbersEnabled]) => {
debouncedUpdateLineNumbers = null

if (!currentEditor || !lineNumbersEnabled) {
if (currentEditor)
currentEditor.setDecorations(codeBlockLineNumberDecoration, [])
return
}

debouncedUpdateLineNumbers = debounce(150, (docText: string) => {
if (editor.value === currentEditor)
updateCodeBlockLineNumbers(currentEditor, docText)
})
},
{ immediate: true },
)

const textChangeDisposable = workspace.onDidChangeTextDocument((e) => {
if (editor.value?.document === e.document && displayCodeBlockLineNumbers.value && debouncedUpdateLineNumbers) {
debouncedUpdateLineNumbers(e.document.getText())
}
})

onScopeDispose(() => {
textChangeDisposable.dispose()
})

watch(
[editor, doc, projectInfo, activeProject, displayAnnotations, displayCodeBlockLineNumbers],
[editor, doc, projectInfo, activeProject, () => config.annotations, () => config['annotations-line-numbers']],
([editor, doc, projectInfo, activeProject, enabled, lineNumbersEnabled]) => {
if (!editor || !doc || !projectInfo)
if (!editor || !doc)
return

if (!enabled) {
if (!projectInfo || !enabled) {
editor.setDecorations(firstLineDecoration, [])
editor.setDecorations(dividerDecoration, [])
editor.setDecorations(frontmatterContentDecoration, [])
Expand Down
4 changes: 2 additions & 2 deletions packages/vscode/src/views/logger.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import { useLogger } from 'reactive-vscode'
import { defineLogger } from 'reactive-vscode'

export const logger = useLogger('Slidev')
export const logger = defineLogger('Slidev')
Loading
Loading