Skip to content

Commit

Permalink
feat: add debug preview.
Browse files Browse the repository at this point in the history
  • Loading branch information
callme-taota committed Sep 20, 2024
1 parent d63b59b commit 5932380
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 83 deletions.
6 changes: 3 additions & 3 deletions spx-gui/src/components/editor/EditorContextProvider.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

<script lang="ts">
import { inject } from 'vue'
import type { RuntimeError } from '@/models/runtime'
import type { RuntimeLog } from '@/models/runtime'
export type EditorCtx = {
project: Project
userInfo: UserInfo
debugProject: boolean
debugErrorList: RuntimeError[]
debugLogList: RuntimeLog[]
}
const editorCtxKey: InjectionKey<EditorCtx> = Symbol('editor-ctx')
Expand All @@ -37,7 +37,7 @@ const editorCtx = computedShallowReactive(() => ({
project: props.project,
userInfo: props.userInfo,
debugProject: false,
debugErrorList: []
debugLogList: []
}))
provide(editorCtxKey, editorCtx)
Expand Down
6 changes: 4 additions & 2 deletions spx-gui/src/components/editor/ProjectEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
<EditorPlaceholder v-else />
</UICard>
<div class="sider">
<EditorPreview />
<EditorPreview v-if="!editorCtx.debugProject" />
<DebugPreview v-else :project="editorCtx.project" />
<EditorPanels v-if="!editorCtx.debugProject" />
<DebugInfoPanels v-else :project="editorCtx.project"/>
<DebugInfoPanels v-else :project="editorCtx.project" />
</div>
</template>
Expand All @@ -31,6 +32,7 @@ import EditorPreview from './preview/EditorPreview.vue'
import EditorPanels from './panels/EditorPanels.vue'
import EditorPlaceholder from './common/placeholder/EditorPlaceholder.vue'
import DebugInfoPanels from './panels/DebugInfoPanels.vue'
import DebugPreview from './preview/DebugPreview.vue'
import { useEditorCtx } from './EditorContextProvider.vue'
const editorCtx = useEditorCtx()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { ChatBot, Suggest } from '../chat-bot'
import { DocAbility } from '../document'
import { Project } from '@/models/project'
import { type IRange, type Position } from 'monaco-editor'
import { type Position as jumpPosition } from '@/models/runtime'
import { type Position as JumpPosition } from '@/models/runtime'
import {
controlCategory,
eventCategory,
Expand Down Expand Up @@ -413,7 +413,7 @@ export class Coordinator {
)
}

public jump(position: jumpPosition): void {}
public jump(position: JumpPosition): void {}
}

async function toolCategory2InputItemCategory(
Expand Down
6 changes: 3 additions & 3 deletions spx-gui/src/components/editor/code-editor/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { watch } from 'vue'
import type { RuntimeError } from '@/models/runtime'
import type { RuntimeLog } from '@/models/runtime'
import { Disposable, type Disposer } from '@/utils/disposable'
import type { EditorCtx } from '../EditorContextProvider.vue'

export class Runtime extends Disposable {
private errorCallbacks: ((errors: RuntimeError[]) => void)[] = []
private errorCallbacks: ((errors: RuntimeLog[]) => void)[] = []
private editorCtx: EditorCtx

constructor(editorCtx: EditorCtx) {
Expand All @@ -22,7 +22,7 @@ export class Runtime extends Disposable {
this.errorCallbacks.forEach((cb) => cb(this.editorCtx.debugErrorList))
}

onRuntimeErrors(cb: (errors: RuntimeError[]) => void): Disposer {
onRuntimeErrors(cb: (errors: RuntimeLog[]) => void): Disposer {
this.errorCallbacks.push(cb)
const disposer: Disposer = () => {
this.errorCallbacks = this.errorCallbacks.filter((callback) => callback !== cb)
Expand Down
67 changes: 19 additions & 48 deletions spx-gui/src/components/editor/panels/DebugInfoPanels.vue
Original file line number Diff line number Diff line change
@@ -1,45 +1,23 @@
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import UICard from '@/components/ui/UICard.vue'
import UIModalClose from '@/components/ui/modal/UIModalClose.vue'
import type { Project } from '@/models/project'
import UICardHeader from '@/components/ui/UICardHeader.vue'
import ProjectRunner from '@/components/project/runner/ProjectRunner.vue'
import { useEditorCtx } from '../EditorContextProvider.vue'
import { Runtime, type RuntimeError } from '@/models/runtime'
const projectRunnerRef = ref<InstanceType<typeof ProjectRunner>>()
import { type RuntimeLog } from '@/models/runtime'
const editorCtx = useEditorCtx()
const runTime = new Runtime()
const props = defineProps<{
project: Project
}>()
onMounted(() => {
if (!projectRunnerRef.value) throw new Error('projectRunnerRef is not ready')
projectRunnerRef.value.run()
})
const runtimeErrors = ref<RuntimeError[]>([])
const handleConsole = (type: 'log' | 'warn', args: unknown[]) => {
runTime.addRuntimeLog({ type, args }, props.project.currentFilesHash)
runtimeErrors.value = runTime.runtimeErrors
editorCtx.debugErrorList = runTime.runtimeErrors
}
const handleClick = (error: RuntimeError) => {
if (error.position.fileUri == 'main') {
const handleClick = (log: RuntimeLog) => {
if (log.position.abledToJump == false) {
return
}
if (log.position.fileUri == 'main') {
editorCtx.project.select({
type: 'stage'
})
} else {
editorCtx.project.select({
type: 'sprite',
name: error.position.fileUri
name: log.position.fileUri
})
}
//TODO: jump to column, line
Expand All @@ -53,30 +31,23 @@ const handleClick = (error: RuntimeError) => {
<div class="header">
{{ $t({ en: 'Console', zh: '日志信息' }) }}
</div>
<UIModalClose class="close" @click="editorCtx.debugProject = false" />
</UICardHeader>
<div class="hidden-runner">
<ProjectRunner
v-if="project"
ref="projectRunnerRef"
:project="project"
@console="handleConsole"
></ProjectRunner>
</div>
<div class="console">
<div
v-for="error in runtimeErrors"
:key="error.message"
v-for="(log, index) in editorCtx.debugLogList"
:key="index"
class="message"
@click="handleClick(error)"
@click="handleClick(log)"
>
<span class="fileUri">{{
$t({ en: 'file:', zh: '文件:' }) + error.position.fileUri
}}</span>
<span class="line">{{ $t({ en: 'line:', zh: '行:' }) + error.position.line }}</span>
<span class="column">{{ $t({ en: 'column:', zh: '列:' }) + error.position.column }}</span>
<br />
<span class="msg">{{ $t({ en: 'message:', zh: '信息:' }) + error.message }}</span>
<span v-if="log.position.abledToJump">
<span class="fileUri">{{
$t({ en: 'file:', zh: '文件:' }) + log.position.fileUri
}}</span>
<span class="line">{{ $t({ en: 'line:', zh: '行:' }) + log.position.line }}</span>
<span class="column">{{ $t({ en: 'column:', zh: '列:' }) + log.position.column }}</span>
<br />
</span>
<span class="msg">{{ $t({ en: 'message:', zh: '信息:' }) + log.message }}</span>
</div>
</div>
</UICard>
Expand Down
86 changes: 86 additions & 0 deletions spx-gui/src/components/editor/preview/DebugPreview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<script setup lang="ts">
import { ref, onMounted, type CSSProperties } from 'vue'
import UICard from '@/components/ui/UICard.vue'
import UICardHeader from '@/components/ui/UICardHeader.vue'
import UIModalClose from '@/components/ui/modal/UIModalClose.vue'
import ProjectRunner from '@/components/project/runner/ProjectRunner.vue'
import { useEditorCtx } from '../EditorContextProvider.vue'
import type { Project } from '@/models/project'
import { Runtime } from '@/models/runtime'
const editorCtx = useEditorCtx()
const projectRunnerRef = ref<InstanceType<typeof ProjectRunner>>()
const props = defineProps<{
project: Project
}>()
const runnerAspectRatio = ref<CSSProperties>({
aspectRatio: '1/1'
})
const runtime = new Runtime()
const handleConsole = (type: 'log' | 'warn', args: unknown[]) => {
runtime.addRuntimeLog({ type, args }, props.project.currentFilesHash)
editorCtx.debugLogList = runtime.runtimeLogs
}
onMounted(() => {
if (!projectRunnerRef.value) throw new Error('projectRunnerRef is not ready')
projectRunnerRef.value.run()
})
</script>

<template>
<UICard class="debug-preview">
<UICardHeader>
<div class="header">
{{ $t({ en: 'Debugging...', zh: '调试中...' }) }}
</div>
<UIModalClose class="close" @click="editorCtx.debugProject = false" />
</UICardHeader>
<div class="stage-debug-container">
<ProjectRunner
v-if="project"
ref="projectRunnerRef"
:project="project"
class="runner"
:style="runnerAspectRatio"
@console="handleConsole"
></ProjectRunner>
</div>
</UICard>
</template>

<style scoped>
.debug-preview {
height: 419px;
display: flex;
flex-direction: column;
position: relative;
overflow: hidden;
.header {
flex: 1;
color: var(--ui-color-title);
}
.stage-debug-container {
display: flex;
overflow: hidden;
justify-content: center;
padding: 12px;
height: 100%;
width: 100%;
}
}
.runner {
width: 100%;
max-height: 100%;
overflow: hidden;
border-radius: var(--ui-border-radius-1);
}
</style>
7 changes: 6 additions & 1 deletion spx-gui/src/components/editor/preview/EditorPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<div class="header">
{{ $t({ en: 'Preview', zh: '预览' }) }}
</div>
<UIButton class="debug-button" type="secondary" icon="play" @click="editorCtx.debugProject = true">
<UIButton class="debug-button" type="secondary" icon="play" @click="startDebug">
{{ $t({ en: 'Debug', zh: '调试' }) }}
</UIButton>
<UIButton class="run-button" type="primary" icon="play" @click="show = true">
Expand All @@ -31,6 +31,11 @@ import RunnerContainer from '@/components/project/runner/RunnerContainer.vue'
let show = ref(false)
const editorCtx = useEditorCtx()
const startDebug = () => {
editorCtx.debugProject = true
editorCtx.debugLogList = []
}
</script>

<style scoped lang="scss">
Expand Down
50 changes: 26 additions & 24 deletions spx-gui/src/models/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Disposable } from '@/utils/disposable'

export type Position = { line: number; column: number; fileUri: string }
export type Position = { line: number; column: number; fileUri: string; abledToJump: boolean }

export type RuntimeError = {
export type RuntimeLog = {
message: string
position: Position
filesHash: string
Expand All @@ -11,51 +11,53 @@ export type RuntimeError = {
type Log = { type: 'log' | 'warn'; args: unknown[] }

export class Runtime extends Disposable {
runtimeErrors: RuntimeError[] = []
runtimeLogs: RuntimeLog[] = []

addRuntimeLog(log: Log, filesHash: string) {
if (
this.runtimeErrors.length > 0 &&
filesHash !== this.runtimeErrors[this.runtimeErrors.length - 1].filesHash
this.runtimeLogs.length > 0 &&
filesHash !== this.runtimeLogs[this.runtimeLogs.length - 1].filesHash
) {
this.clearRuntimeErrors()
}
const runtimeError = this.parseRuntimeLog(log)
if (runtimeError !== null) {
runtimeError.filesHash = filesHash
this.runtimeErrors.push(runtimeError)
this.runtimeLogs = [...this.runtimeLogs, runtimeError]
}
}

private clearRuntimeErrors() {
this.runtimeErrors = []
this.runtimeLogs = []
}

private parseRuntimeLog(log: Log): RuntimeError | null {
private parseRuntimeLog(log: Log): RuntimeLog | null {
switch (log.args.length) {
case 1: {
const logRegex = /^[^:]+:\d+:\d+ [^:]+: ([^:]+):(\d+):(\d+): (.*)$/
const match = (log.args[0] as string).match(logRegex)

if (!match) {
return null
if (match) {
const [_, fileName, lineNumber, columnNumber, message] = match
const [fileUri] = fileName.split('.')

const position: Position = {
line: parseInt(lineNumber),
column: parseInt(columnNumber),
fileUri: fileUri,
abledToJump: true
}
return { position, message, filesHash: '' }
}

const [_, fileName, lineNumber, columnNumber, message] = match
const [fileUri] = fileName.split('.')

const position: Position = {
line: parseInt(lineNumber),
column: parseInt(columnNumber),
fileUri: fileUri
}


//TODO: make message easier to understand

return { position, message, filesHash: '' }
}
default:
return null
}
const msgs = log.args.join(' ')
return {
position: { line: 0, column: 0, fileUri: '', abledToJump: false },
message: msgs,
filesHash: ''
}
}
}

0 comments on commit 5932380

Please sign in to comment.