Skip to content

Commit

Permalink
feat(spx-gui): implement audio preview (#908)
Browse files Browse the repository at this point in the history
* feat: implement audio preview

* feat: complete audio player event ,audio player wave bar has different performance in playing
  • Loading branch information
molinla authored Sep 18, 2024
1 parent 2f7a646 commit 6306e48
Show file tree
Hide file tree
Showing 10 changed files with 537 additions and 53 deletions.
14 changes: 13 additions & 1 deletion spx-gui/src/components/editor/code-editor/EditorUI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,11 @@ export class EditorUI extends Disposable {
.filter((item): item is { type: 'doc'; layer: DocPreview } => item.type === 'doc')
.map((item) => item.layer)

const audioPlayers = result
// add `item is { type: 'audio'; layer: AudioPlayer }` to pass npm script type-check
.filter((item): item is { type: 'audio'; layer: AudioPlayer } => item.type === 'audio')
.map((item) => item.layer)

const attentionHintDecorations = this.attentionHint?.attentionHintDecorations.filter(
(item) => item.range.startLineNumber === position.lineNumber
)
Expand All @@ -498,7 +503,14 @@ export class EditorUI extends Disposable {
endColumn: word.endColumn
})

// todo: when show audio preview, add code `item is { type: 'audio'; layer: AudioPlayer }` to pass npm script type-check
const [audioPlayer] = audioPlayers
if (audioPlayer)
this.hoverPreview?.showAudioPlayer(audioPlayer, {
startLineNumber: position.lineNumber,
startColumn: word.startColumn,
endLineNumber: position.lineNumber,
endColumn: word.endColumn
})

return {
// we only need to know when to trigger hover preview, no need to show raw content
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { EditorUI, LayerContent, TextModel } from '@/components/editor/code-editor/EditorUI'
import { DocPreviewLevel, Icon } from '@/components/editor/code-editor/EditorUI'
import {
DocPreviewLevel,
type EditorUI,
Icon,
type LayerContent,
type TextModel
} from '@/components/editor/code-editor/EditorUI'
import { DocAbility } from '@/components/editor/code-editor/document'
import type { Position } from 'monaco-editor'
import type { Definition, TokenUsage } from '@/components/editor/code-editor/compiler'
Expand All @@ -11,6 +16,10 @@ import {
import type { TokenWithDoc, UsageWithDoc } from '@/components/editor/code-editor/tokens/types'
import { usageEffect2Icon } from '@/components/editor/code-editor/coordinators/index'
import type { Project } from '@/models/project'
import type { Sound } from '@/models/sound'
import { useAudioDuration } from '@/utils/audio'
import { untilNotNull } from '@/utils/utils'
import { useFileUrl } from '@/utils/file'

export class HoverProvider {
private ui: EditorUI
Expand Down Expand Up @@ -41,20 +50,27 @@ export class HoverProvider {
}
): Promise<LayerContent[]> {
const definition = this.findDefinition(this.currentFilename, ctx.position)
if (!definition) return []
const sound = this.findMediaName(this.currentFilename, ctx.position)
if (!definition && !sound) return []
const layerContents: LayerContent[] = []
if (definition) {
const content = await this.docAbility.getNormalDoc({
pkgPath: definition.pkgPath,
name: definition.name
})

const content = await this.docAbility.getNormalDoc({
pkgPath: definition.pkgPath,
name: definition.name
})
if (this.isDefinitionCanBeRenamed(definition)) {
const [usage] = definition.usages
if (!usage) throw new Error('definition should have at least one usage!')
layerContents.push(this.createVariableRenameContent(usage, definition))
} else {
layerContents.push(...this.createDocContents(content, definition))
}
}

const layerContents: LayerContent[] = []
if (this.isDefinitionCanBeRenamed(definition)) {
const [usage] = definition.usages
if (!usage) throw new Error('definition should have at least one usage!')
layerContents.push(this.createVariableRenameContent(usage, definition))
} else {
layerContents.push(...this.createDocContents(content, definition))
if (sound) {
const [audioSrc] = useFileUrl(() => sound.file)
layerContents.push(await this.createAudioContent(await untilNotNull(audioSrc)))
}

return layerContents
Expand All @@ -79,6 +95,36 @@ export class HoverProvider {
})
}

private findMediaName(filename: string, position: Position): Sound | undefined {
const hint = this.coordinatorState.inlayHints.find((inlayHint) => {
if (inlayHint.startPosition.filename !== filename) return false
const tokenLen = inlayHint.endPos - inlayHint.startPos
const line = inlayHint.startPosition.line
const startColumn = inlayHint.startPosition.column
const endColumn = startColumn + tokenLen
return (
position.lineNumber === line &&
position.column >= startColumn &&
position.column <= endColumn &&
inlayHint.name === 'mediaName'
)
})
if (!hint) return
return this.project.sounds.find((sound) => `"${sound.name}"` === hint.value)
}

private async createAudioContent(audioSrc: string): Promise<LayerContent> {
const { duration: _duration } = useAudioDuration(() => audioSrc)
const duration = await untilNotNull(_duration)
return {
type: 'audio',
layer: {
duration,
src: audioSrc
}
}
}

private createVariableRenameContent(usage: TokenUsage, definition: Definition): LayerContent {
// if this is function we need remap declaration
const declarationMap = this.createDefinitionDeclaration(definition.name, [usage])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
type TextModel
} from '@/components/editor/code-editor/EditorUI'
import { Runtime } from '../runtime'
import type { Definition, TokenDetail } from '../compiler'
import type { Definition, TokenDetail, Hint } from '../compiler'
import { Compiler } from '../compiler'
import { ChatBot, Suggest } from '../chat-bot'
import { DocAbility } from '../document'
Expand Down Expand Up @@ -41,6 +41,7 @@ type JumpPosition = {

export type CoordinatorState = {
definitions: Definition[]
inlayHints: Hint[]
}

export class Coordinator {
Expand All @@ -51,7 +52,8 @@ export class Coordinator {
compiler: Compiler
public updateDefinition = debounce(this._updateDefinition, 300)
private coordinatorState: CoordinatorState = {
definitions: []
definitions: [],
inlayHints: []
}
private readonly hoverProvider: HoverProvider
private suggest: Suggest
Expand Down Expand Up @@ -245,7 +247,7 @@ export class Coordinator {
)

if (ctx.signal.aborted) return []

this.coordinatorState.inlayHints = inlayHints
return inlayHints.flatMap((inlayHint): InlayHintDecoration[] => {
// from compiler has two type of inlay hint, so here use if else to distinguish
if (inlayHint.type === 'play') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ onUnmounted(() => {
</script>

<template>
<!-- eslint-disable vue/no-v-html -->
<!-- this ul element area is sidebar tab nav -->
<ul
class="categories-wrapper skeleton-wrapper"
Expand Down
Loading

0 comments on commit 6306e48

Please sign in to comment.