Skip to content

Commit aef781c

Browse files
kermanxCopilot
andauthored
fix(vscode): fix line number decorations, upgrade reactive-vscode (#2418)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent afc1370 commit aef781c

12 files changed

Lines changed: 99 additions & 165 deletions

File tree

packages/vscode/src/commands.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ import { useCommand } from 'reactive-vscode'
44
import { ConfigurationTarget, window, workspace } from 'vscode'
55
import { useDevServer } from './composables/useDevServer'
66
import { useFocusedSlide } from './composables/useFocusedSlide'
7-
import { configuredPort, forceEnabled, include, previewSync } from './configs'
7+
import { config } from './configs'
88
import { activeEntry, activeProject, addProject, projects, rescanProjects } from './projects'
99
import { findPossibleEntries } from './utils/findPossibleEntries'
1010
import { getSlidesTitle } from './utils/getSlidesTitle'
1111
import { usePreviewWebview } from './views/previewWebview'
1212

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

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

@@ -55,7 +55,7 @@ export function useCommands() {
5555
const workspaceRoot = workspace.workspaceFolders[0].uri.fsPath
5656
const relatives = selected.map(s => slash(relative(workspaceRoot, s)))
5757
// write back to settings.json
58-
await include.update([...include.value, ...relatives])
58+
await config.update('include', [...config.include, ...relatives])
5959
}
6060
}
6161
return !!selected
@@ -102,7 +102,7 @@ export function useCommands() {
102102
}
103103
const port = await window.showInputBox({
104104
prompt: `Slidev Preview Port for ${getSlidesTitle(activeProject.value.data)}`,
105-
value: configuredPort.value.toString(),
105+
value: config.port.toString(),
106106
validateInput: (v) => {
107107
if (!v.match(/^\d+$/))
108108
return 'Port should be a number'
@@ -123,9 +123,9 @@ export function useCommands() {
123123
return
124124
}
125125

126-
const { start, showTerminal } = useDevServer(project)
126+
const { start, terminal } = useDevServer(project)
127127
start()
128-
showTerminal()
128+
terminal.value?.show()
129129
})
130130

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

138-
useCommand('slidev.enable-preview-sync', () => (previewSync.update(true, ConfigurationTarget.Global)))
139-
useCommand('slidev.disable-preview-sync', () => (previewSync.update(false, ConfigurationTarget.Global)))
138+
useCommand('slidev.enable-preview-sync', () => (config.update('preview-sync', true, ConfigurationTarget.Global)))
139+
useCommand('slidev.disable-preview-sync', () => (config.update('preview-sync', false, ConfigurationTarget.Global)))
140140
}
Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
import type { EffectScope, Ref } from 'reactive-vscode'
1+
import type { EffectScope, ShallowRef } from 'reactive-vscode'
22
import type { Terminal } from 'vscode'
33
import type { SlidevProject } from '../projects'
44
import { basename } from 'node:path'
5-
import { effectScope, onScopeDispose, useAbsolutePath, useControlledTerminal } from 'reactive-vscode'
6-
import { env, Uri } from 'vscode'
7-
import { devCommand } from '../configs'
5+
import { effectScope, onScopeDispose, shallowRef, useAbsoluteUri, useDisposable } from 'reactive-vscode'
6+
import { env, window } from 'vscode'
7+
import { config } from '../configs'
88
import { getSlidesTitle } from '../utils/getSlidesTitle'
99
import { useServerDetector } from './useServerDetector'
1010

1111
export interface SlidevServer {
1212
scope: EffectScope
13-
terminal: Ref<Terminal | null>
13+
terminal: ShallowRef<Terminal | null>
1414
start: () => void
15-
showTerminal: () => void
1615
}
1716

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

2524
const scope = effectScope(true)
2625
return server.value = scope.run(() => {
27-
const { terminal, getIsActive, show: showTerminal, sendText, close } = useControlledTerminal({
28-
name: getSlidesTitle(project.data),
29-
cwd: project.userRoot,
30-
iconPath: {
31-
light: Uri.file(useAbsolutePath('dist/res/logo-mono.svg').value),
32-
dark: Uri.file(useAbsolutePath('dist/res/logo-mono-dark.svg').value),
33-
},
34-
isTransient: true,
35-
})
26+
const terminal = shallowRef<Terminal | null>(null)
3627

3728
async function start() {
38-
if (getIsActive())
29+
if (terminal.value && terminal.value.exitStatus == null)
3930
return
31+
32+
terminal.value = useDisposable(window.createTerminal({
33+
name: getSlidesTitle(project.data),
34+
cwd: project.userRoot,
35+
iconPath: {
36+
light: useAbsoluteUri('dist/res/logo-mono.svg').value,
37+
dark: useAbsoluteUri('dist/res/logo-mono-dark.svg').value,
38+
},
39+
isTransient: true,
40+
}))
41+
4042
const p = port.value ??= await allocPort()
4143
const args = [
4244
JSON.stringify(basename(project.entry)),
4345
`--port ${p}`,
4446
env.remoteName != null ? '--remote' : '',
4547
].filter(Boolean).join(' ')
4648
// eslint-disable-next-line no-template-curly-in-string
47-
sendText(devCommand.value.replaceAll('${args}', args).replaceAll('${port}', `${p}`))
49+
terminal.value.sendText(config['dev-command'].replaceAll('${args}', args).replaceAll('${port}', `${p}`))
4850

4951
let intervalCount = 0
5052
const maxIntervals = 100
@@ -66,7 +68,6 @@ export function useDevServer(project: SlidevProject) {
6668
scope,
6769
terminal,
6870
start,
69-
showTerminal,
7071
}
7172
})!
7273
}

packages/vscode/src/composables/useFocusedSlide.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export const useFocusedSlide = defineService(() => {
1616
const focusedSourceSlide = useDebouncedComputed(
1717
() => {
1818
const md = focusedMarkdown.value
19-
if (!md || !debouncedEditor.value) {
19+
if (!md || !debouncedEditor.value || !selection.value) {
2020
return null
2121
}
2222
const line = selection.value.active.line + 1

packages/vscode/src/composables/useServerDetector.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { SlidevProject } from '../projects'
22
import { createControlledPromise } from '@antfu/utils'
33
import { getPort as getPortPlease } from 'get-port-please'
44
import { computed, defineService, onScopeDispose, reactive, watch } from 'reactive-vscode'
5-
import { configuredPort } from '../configs'
5+
import { config } from '../configs'
66
import { activeProject, askAddProject, projects, scannedProjects } from '../projects'
77
import { logger } from '../views/logger'
88

@@ -68,7 +68,7 @@ export const useServerDetector = defineService(() => {
6868
}
6969

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

9494
function getDetected(project: SlidevProject) {
95-
const port = project.port.value || configuredPort.value
95+
const port = project.port.value || config.port
9696
const detected = detectedPorts.get(port)
9797
if (detected?.entry === project.entry)
9898
return detected

packages/vscode/src/configs.ts

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,12 @@
1-
import type { ConfigType } from 'reactive-vscode'
2-
import { defineConfigs } from 'reactive-vscode'
1+
import { defineConfig } from 'reactive-vscode'
32

4-
export const {
5-
'force-enabled': forceEnabled,
6-
'port': configuredPort,
7-
'annotations': displayAnnotations,
8-
'annotations-line-numbers': displayCodeBlockLineNumbers,
9-
'preview-sync': previewSync,
10-
include,
11-
exclude,
12-
'dev-command': devCommand,
13-
} = defineConfigs('slidev', {
14-
'force-enabled': Boolean,
15-
'port': Number,
16-
'annotations': Boolean,
17-
'annotations-line-numbers': Boolean,
18-
'preview-sync': Boolean,
19-
'include': Object as ConfigType<string[]>,
20-
'exclude': String,
21-
'dev-command': String,
22-
})
3+
export const config = defineConfig<{
4+
'force-enabled': boolean
5+
'port': number
6+
'annotations': boolean
7+
'annotations-line-numbers': boolean
8+
'preview-sync': boolean
9+
'include': string[]
10+
'exclude': string
11+
'dev-command': string
12+
}>('slidev')

packages/vscode/src/projects.ts

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import { basename, dirname } from 'node:path'
77
import { debounce, slash } from '@antfu/utils'
88
import { load } from '@slidev/parser/fs'
99
import { isMatch } from 'picomatch'
10-
import { computed, effectScope, extensionContext, markRaw, onScopeDispose, ref, shallowReactive, shallowRef, useDisposable, useFsWatcher, useVscodeContext, watch, watchEffect } from 'reactive-vscode'
10+
import { computed, effectScope, extensionContext, markRaw, onScopeDispose, ref, shallowReactive, shallowRef, useDisposable, useFileSystemWatcher, useVscodeContext, watch, watchEffect } from 'reactive-vscode'
1111
import { FileSystemError, Uri, window, workspace } from 'vscode'
1212
import { useServerDetector } from './composables/useServerDetector'
13-
import { exclude, forceEnabled, include } from './configs'
13+
import { config } from './configs'
1414
import { findShallowestPath } from './utils/findShallowestPath'
1515
import { logger } from './views/logger'
1616

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

3333
export function useProjects() {
34-
const watcher = useFsWatcher(include, false, true, false)
35-
watcher.onDidCreate(async (uri) => {
36-
const path = slash(uri.fsPath)
37-
if (!isMatch(path, exclude.value))
38-
await addProject(path)
39-
})
40-
watcher.onDidDelete(async (uri) => {
41-
removeProject(slash(uri.fsPath))
34+
useFileSystemWatcher(() => config.include, {
35+
async onDidCreate(uri) {
36+
const path = slash(uri.fsPath)
37+
if (!isMatch(path, config.exclude))
38+
await addProject(path)
39+
},
40+
onDidChange: false,
41+
async onDidDelete(uri) {
42+
removeProject(slash(uri.fsPath))
43+
},
4244
})
4345

4446
rescanProjects()
45-
watch([include, exclude], debounce(200, rescanProjects))
47+
watch(() => [config.include, config.exclude], debounce(200, rescanProjects))
4648

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

8284
useVscodeContext('slidev:enabled', () => {
83-
const enabled = forceEnabled.value == null ? everHadProjects.value : forceEnabled.value
85+
const forceEnabled = config['force-enabled']
86+
const enabled = forceEnabled == null ? everHadProjects.value : forceEnabled
8487
logger.info(`Slidev ${enabled ? 'enabled' : 'disabled'}.`)
8588
return enabled
8689
})
@@ -102,8 +105,8 @@ export async function rescanProjects() {
102105
scanningProjects = true
103106
try {
104107
const entries = new Set<string>()
105-
for (const glob of include.value) {
106-
(await workspace.findFiles(glob, exclude.value))
108+
for (const glob of config.include) {
109+
(await workspace.findFiles(glob, config.exclude))
107110
.forEach(file => entries.add(file.fsPath))
108111
}
109112
for (const entry of entries) {

packages/vscode/src/views/annotations.ts

Lines changed: 8 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import type { SourceSlideInfo } from '@slidev/types'
22
import type { DecorationOptions } from 'vscode'
3-
import { clamp, debounce, ensurePrefix } from '@antfu/utils'
4-
import { computed, defineService, onScopeDispose, useActiveTextEditor, watch } from 'reactive-vscode'
5-
import { Position, Range, ThemeColor, window, workspace } from 'vscode'
3+
import { clamp, ensurePrefix } from '@antfu/utils'
4+
import { computed, defineService, useActiveTextEditor, watch } from 'reactive-vscode'
5+
import { Position, Range, ThemeColor, window } from 'vscode'
66
import { useProjectFromDoc } from '../composables/useProjectFromDoc'
7-
import { displayAnnotations, displayCodeBlockLineNumbers } from '../configs'
7+
import { config } from '../configs'
88
import { activeProject } from '../projects'
99
import { toRelativePath } from '../utils/toRelativePath'
1010

@@ -94,7 +94,7 @@ function findCodeBlocks(docText: string): CodeBlockInfo[] {
9494
}
9595

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

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

144-
let debouncedUpdateLineNumbers: ((docText: string) => void) | null = null
145-
146-
watch(
147-
[editor, displayCodeBlockLineNumbers],
148-
([currentEditor, lineNumbersEnabled]) => {
149-
debouncedUpdateLineNumbers = null
150-
151-
if (!currentEditor || !lineNumbersEnabled) {
152-
if (currentEditor)
153-
currentEditor.setDecorations(codeBlockLineNumberDecoration, [])
154-
return
155-
}
156-
157-
debouncedUpdateLineNumbers = debounce(150, (docText: string) => {
158-
if (editor.value === currentEditor)
159-
updateCodeBlockLineNumbers(currentEditor, docText)
160-
})
161-
},
162-
{ immediate: true },
163-
)
164-
165-
const textChangeDisposable = workspace.onDidChangeTextDocument((e) => {
166-
if (editor.value?.document === e.document && displayCodeBlockLineNumbers.value && debouncedUpdateLineNumbers) {
167-
debouncedUpdateLineNumbers(e.document.getText())
168-
}
169-
})
170-
171-
onScopeDispose(() => {
172-
textChangeDisposable.dispose()
173-
})
174-
175144
watch(
176-
[editor, doc, projectInfo, activeProject, displayAnnotations, displayCodeBlockLineNumbers],
145+
[editor, doc, projectInfo, activeProject, () => config.annotations, () => config['annotations-line-numbers']],
177146
([editor, doc, projectInfo, activeProject, enabled, lineNumbersEnabled]) => {
178-
if (!editor || !doc || !projectInfo)
147+
if (!editor || !doc)
179148
return
180149

181-
if (!enabled) {
150+
if (!projectInfo || !enabled) {
182151
editor.setDecorations(firstLineDecoration, [])
183152
editor.setDecorations(dividerDecoration, [])
184153
editor.setDecorations(frontmatterContentDecoration, [])
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
import { useLogger } from 'reactive-vscode'
1+
import { defineLogger } from 'reactive-vscode'
22

3-
export const logger = useLogger('Slidev')
3+
export const logger = defineLogger('Slidev')

0 commit comments

Comments
 (0)