Commit 455d07d7 authored by Yuan Zhixiang's avatar Yuan Zhixiang
Browse files

迁移到新仓库

parents
Pipeline #45 canceled with stages
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo
{
"recommendations": ["Vue.volar"]
}
# c-render-vue
## 准备工作
```
npm install
```
## 不构建,实时开发调试
```
npm run dev
```
## 构建
```
npm run build
```
## 注意
构建后网页文件在 dist 目录下,请自行配置网页代理
请修改 main.js 中的 base_url 为后端地址
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>C-Render</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"exclude": ["node_modules", "dist"]
}
This diff is collapsed.
{
"name": "c-render-vue",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.6.8",
"vue": "^3.4.21"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.0.4",
"vite": "^5.1.6"
}
}
<script setup>
import { computed, provide, ref } from 'vue';
import axios from 'axios'
import { base_url } from '@/main'
import CodeEditor from './components/CodeEditor.vue';
import StdinEditor from './components/StdinEditor.vue';
import ControlPanel from './components/ControlPanel.vue';
import CodeViewer from './components/CodeViewer.vue';
import InfoView from './components/InfoView.vue';
import StackView from './components/StackView.vue';
const code_input = ref('') // 输入的代码
const stdin_input = ref('') // 测试用例
function send_request() { // 将输入的代码/测试用例发送给后端
data.value = {}
if (stdin_input.value.length == 0) {
axios.post(base_url + '/visualize', {
code: code_input.value
}, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
data.value = response.data
parse_result()
})
.catch(error => {
console.error(error);
});
} else {
axios.post(base_url + '/visualize', {
code: code_input.value,
stdin: stdin_input.value
}, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
data.value = response.data
parse_result()
})
.catch(error => {
console.error(error);
});
}
}
provide('input', { code_input, stdin_input, send_request })
const data = ref({}) // 后端返回的数据
function parse_result() { // 解析后端返回的结果
remove_back_slash_r()
loading.value = false
if (success.value) {
total_steps.value = data.value['trace'].length - 1
try_failed.value = false
edit_mode.value = false
} else {
try_failed.value = true
total_steps.value = 1
}
current_step.value = 1
highlight_steps.value = []
}
function remove_back_slash_r() { // 去除后端返回的code中的\r
if ('code' in data.value) {
let code = data.value['code']
code = code.replace(/\r/g, '')
data.value['code'] = code
}
}
const success = computed(() => {
try {
if (data.value['trace'][0]['event'] == 'step_line') {
return true
}
} catch (e) { }
return false
})
const exception_msg = computed(() => {
try {
if (data.value['trace'][0]['event'] == 'uncaught_exception') {
return data.value['trace'][0]['exception_msg'].replace(/`/g, "'").replace(/‘/g, "'").replace(/’/g, "'")
}
} catch (e) { }
return ''
})
function get_step(_step) {
if (_step < 1) {
_step = 1
}
if (_step > total_steps.value + 1) {
_step = total_steps.value + 1
}
try {
return data.value['trace'][_step - 1]
} catch (e) { }
}
const current_line = computed(() => {
try {
return get_step(current_step.value)['line']
} catch (e) { }
})
const next_line = computed(() => {
try {
return get_step(current_step.value + 1)['line']
} catch (e) { }
})
const try_failed = ref(false)
provide('data', { data, success, exception_msg, get_step, current_line, next_line, try_failed })
const total_steps = ref(1) // 总步骤数
const current_step = ref(1) // 当前步骤
const highlight_steps = ref([]) // 高亮的步骤
function click_step(clicked) {
current_step.value = clicked
}
const highlight_lines = ref([]) // 高亮的代码行
function enable_line(clicked) {
let actived = 0;
for (let i = 1; i <= total_steps.value + 1; i++) {
if (get_step(i)['line'] == clicked) {
highlight_steps.value.push(i)
actived += 1
}
}
if (actived != 0) {
highlight_lines.value.push(clicked)
}
}
function disable_line(clicked) {
for (let i = 1; i <= total_steps.value + 1; i++) {
if (get_step(i)['line'] == clicked) {
highlight_steps.value = highlight_steps.value.filter(item => item != i)
}
}
highlight_lines.value = highlight_lines.value.filter(item => item != clicked)
}
function click_line(clicked) {
if (Object.values(highlight_lines.value).includes(clicked)) {
disable_line(clicked)
} else {
enable_line(clicked)
}
}
provide('step', { total_steps, current_step, highlight_steps, click_step, highlight_lines, click_line })
const edit_mode = ref(true) // 编辑模式,成功运行时为false
provide('edit_mode', edit_mode)
const loading = ref(false)
provide('loading', loading)
</script>
<template>
<div class="out-out-container">
<div class="out-container">
<div class="out-big-box">
<div class="big-box" v-show="edit_mode">
<CodeEditor />
</div>
<div class="big-box" v-show="!edit_mode">
<CodeViewer />
</div>
</div>
<div class="out-big-box">
<div class="big-box" v-show="edit_mode">
<InfoView />
</div>
<div class="big-box" v-show="!edit_mode">
<StackView />
</div>
</div>
<div class="out-big-box">
<div class="big-box">
<StdinEditor />
</div>
</div>
<div class="out-big-box">
<div class="big-box">
<ControlPanel />
</div>
</div>
</div>
</div>
</template>
<style scoped>
.out-out-container {
/* 黑魔法,勿动 */
height: calc(100% - 1rem);
width: calc(100% - 1rem);
padding: 0.5rem;
}
.out-container {
/* 黑魔法,勿动 */
display: grid;
grid-template-columns: 34% 66%;
grid-template-rows: 80% 20%;
height: 100%;
width: 100%;
}
.out-big-box {
/* 黑魔法,勿动 */
padding: 0.5rem;
}
.big-box {
/* 黑魔法,勿动 */
border-radius: 1rem;
height: calc(100% - 2rem);
width: calc(100% - 2rem);
padding: 1rem;
background-color: #EEF4FA;
}
</style>
<style>
* {
margin: 0;
padding: 0;
font-family: "Maple Mono SC Lite";
font-weight: normal;
color: #011E2B;
}
@font-face {
font-family: "Maple Mono SC Lite";
src: url("./assets/MapleMono-SC-Lite.woff2")format('woff2');
}
#app {
height: 100vh;
}
</style>
.button {
background-color: white;
border-radius: 100rem; /* 足够大 */
border: 0rem;
padding: 0.5rem;
transition-duration: 200ms;
margin-right: 0.8rem;
}
.button:hover {
background-color: #c0e8ff;
transition-duration: 200ms;
}
.button:active {
background-color: #eef4fa;
transition-duration: 200ms;
}
button:disabled {
opacity: 0.5;
}
.code-input {
display: block;
width: calc(100% - 0.8rem);
height: calc(100% - 0.8rem);
resize: none;
border: 0rem;
border-radius: 0.3rem;
padding: 0.4rem;
background-color: #ffffff;
overflow-y: auto;
white-space: pre-wrap;
word-wrap: break-word;
transition-duration: 500ms;
font-size: 0.8rem;
}
.code-input:hover {
outline: none;
background-color: #eef4fa;
transition-duration: 500ms;
}
.code-input:focus {
outline: none;
}
<script setup>
import { inject } from 'vue';
const { code_input } = inject('input')
const placeholder = '将你的代码粘贴到这里'
</script>
<template>
<textarea class="code-input" v-model="code_input" :placeholder="placeholder"></textarea>
</template>
<style scoped>
@import '@/assets/code-input.css';
.code-input {
white-space: nowrap;
}
</style>
<script setup>
import { computed, inject } from 'vue';
import LineUnit from './LineUnit.vue';
const { data } = inject('data');
const code = computed(() => {
return data.value['code'];
})
const code_split = computed(() => {
return String(code.value).split('\n');
})
</script>
<template>
<div class="container">
<LineUnit v-for="(item, index) in code_split" :code="item" :line="index + 1" />
</div>
</template>
<style scoped>
.container {
font-size: 0.8rem;
background-color: white;
overflow: auto;
width: calc(100% - 0.8rem);
height: calc(100% - 0.8rem);
border: 0rem;
border-radius: 0.3rem;
padding: 0.4rem;
}
</style>
<script setup>
import { computed, inject } from 'vue';
import StepUnit from './StepUnit.vue'
import EditButton from './buttons/EditButton.vue';
import RunButton from './buttons/RunButton.vue';
import PrevButton from './buttons/PrevButton.vue';
import NextButton from './buttons/NextButton.vue';
const { total_steps, current_step } = inject('step')
const edit_mode = inject('edit_mode')
const css_grid_template_columns = computed(() => {
return `repeat(${total_steps.value}, 1fr)`;
})
</script>
<template>
<div class="container">
<div class="process-bar" v-show="!edit_mode">
<StepUnit v-for="(item, index) in total_steps" :step="index + 1" />
</div>
<EditButton v-show="!edit_mode" />
<RunButton v-show="edit_mode" />
<PrevButton v-show="!edit_mode" />
<NextButton v-show="!edit_mode" />
</div>
</template>
<style scoped>
.container {
height: 100%;
}
.process-bar {
display: grid;
grid-template-rows: 0.5rem;
grid-template-columns: v-bind(css_grid_template_columns);
border-radius: 100rem;
/* 足够大 */
overflow: hidden;
margin-bottom: 0.8rem;
}
</style>
\ No newline at end of file
<script setup>
import { inject } from 'vue';
const { exception_msg, try_failed } = inject('data')
</script>
<template>
<div class="info-view" v-show="!try_failed">
<h1>欢迎</h1>
</div>
<div class="info-view" v-show="try_failed">
<p class="big-face">🤔</p>
<p>你的代码好像有问题?</p><br>
<p>{{ exception_msg }}</p>
</div>
</template>
<style scoped>
.info-view {
width: 100%;
height: 100%;
overflow: auto;
}
.big-face {
font-size: 8rem;
}
</style>
\ No newline at end of file
<script setup>
import { computed, inject, ref } from 'vue';
const props = defineProps(['line', 'code'])
const { current_line, next_line } = inject('data')
const { click_line, highlight_lines } = inject('step')
const { success } = inject('data')
const line = computed(() => {
return props.line
})
const code = computed(() => {
return props.code
})
const mark = computed(() => {
if (line.value == current_line.value) {
return ''
}
if (line.value == next_line.value) {
return ''
}
return ' '
})
const is_current = computed(() => {
return line.value == current_line.value
})
const is_next = computed(() => {
return line.value == next_line.value
})
const css_code_background = computed(() => {
if (Object.values(highlight_lines.value).includes(line.value)) {
return '#FFDAD6'
} else {
return 'white'
}
})
function click() {
click_line(line.value)
}
</script>
<template>
<div>
<pre :class="{ blue: is_current, 'light-blue': is_next }">{{ mark }} </pre>
<pre :class="{ blue: is_current }" class="code" @click="click">{{ code }}</pre>
</div>
</template>
<style scoped>
pre {
display: inline;
}
.blue {
color: #00aeff;
}
.light-blue {
color: #c0e8ff;
}
.code {
border: 0rem;
border-radius: 0.3rem;
background-color: v-bind(css_code_background);
transition-duration: 200ms;
}
.code:hover {
/* background-color: #FFB4AB; */
filter: brightness(0.9);
transition-duration: 200ms;
}
.code:active {
filter: brightness(0.8);
transition-duration: 200ms;
}
</style>
\ No newline at end of file
<script setup>
import { computed, inject, provide, watch, ref } from 'vue';
import VarUnit from './VarUnit.vue';
const { get_step } = inject('data')
const { current_step } = inject('step')
const current_stack = computed(() => {
return get_step(current_step.value + 1)
})
const current_var_map = computed(() => {
let map = {}
function parse_array(array) {
if (array[0] == 'C_DATA') {
map[array[1]] = array[3]
} else {
for (let item of array) {
if (Array.isArray(item)) {
parse_array(item)
}
}
}
}
try {
for (let item of current_stack.value.stack_to_render) {
for (let [key, value] of Object.entries(item.encoded_locals)) {
parse_array(value)
}
}
for (let [key, value] of Object.entries(current_stack.value.globals)) {
parse_array(value)
}
} catch (e) { }
return map
})
const prev_stack = computed(() => {
return get_step(current_step.value)
})
const prev_var_map = computed(() => {
let map = {}
function parse_array(array) {
if (array[0] == 'C_DATA') {
map[array[1]] = array[3]
} else {
for (let item of array) {
if (Array.isArray(item)) {
parse_array(item)
}
}
}
}
try {
for (let item of prev_stack.value.stack_to_render) {
for (let [key, value] of Object.entries(item.encoded_locals)) {
parse_array(value)
}
}
for (let [key, value] of Object.entries(prev_stack.value.globals)) {
parse_array(value)
}
} catch (e) { }
return map
})
function check_changed(value) {
let address = value[1]
if (address in current_var_map.value) {
if (address in prev_var_map.value) {
if (current_var_map.value[address] !== prev_var_map.value[address]) {
return 'changed'
}
} else {
return 'new'
}
}
return 'x'
}
provide('check_changed', { check_changed })
const has_globals = computed(() => {
try {
return Object.keys(current_stack.value['globals']).length > 0
} catch (e) { }
return false
})
const stack_to_render = computed(() => {
try {
return current_stack.value['stack_to_render']
} catch (e) { }
})
const stdout = computed(() => {
try {
return current_stack.value['stdout']
} catch (e) { }
return ''
})
const has_stdout = computed(() => {
return stdout.value.length > 0
})
const highlight_addresses = ref({})
watch(current_step, () => {
highlight_addresses.value = {}
})
provide('highlight_address', { highlight_addresses })
function click() {
// console.log(Object.keys(current_stack.value['globals']).length)
// console.log(current_var_map.value)
// for(let [key,value] of current_stack.value.globals){
// console.log(value)
// }
// console.log(has_stdout.value)
console.log(highlight_addresses.value)
}
</script>
<template>
<div class="flex-container">
<div class="func-box" v-show="has_stdout">
<div class="big-box">
<div class="small-box head-box">输出</div>
</div>
<div class="big-box">
<div class="small-box">
<pre>{{ stdout }}</pre>
</div>
</div>
</div>
<div class="func-box" v-if="has_globals">
<div class="big-box">
<div class="small-box head-box">全局变量</div>
</div>
<VarUnit v-for="(value2, key2, index2) in current_stack.globals" :var_name="key2" :var_content="value2"
:changed="check_changed(value2)" />
</div>
<div class="func-box" v-for="value1 in stack_to_render">
<div class="big-box">
<div class="small-box head-box">{{ value1['func_name'] }}</div>
</div>
<VarUnit v-for="(value2, key2, index2) in value1['encoded_locals']" :var_name="key2" :var_content="value2"
:changed="check_changed(value2)" />
</div>
</div>
<button @click="click">log</button>
<!-- <div>{{ stack_to_render }}</div> -->
</template>
<style scoped>
.func-box {
font-size: 0.8rem;
background-color: white;
border-radius: 0.5rem;
padding: 0.2rem;
margin-right: 0.5rem;
/* width: min-content;
height: min-content; */
}
.flex-container {
display: flex;
flex-direction: column;
/* grid-auto-flow: column;
grid-template-columns: auto;
grid-template-rows: auto; */
/* grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); */
height: 100%;
width: calc(100% + 0.5rem);
gap: 1rem;
overflow: auto;
}
</style>
\ No newline at end of file
<script setup>
import { computed, inject } from 'vue';
const { stdin_input } = inject('input')
const edit_mode = inject('edit_mode')
const readonly = computed(() => {
return !(edit_mode.value)
})
const placeholder = '将你的测试用例粘贴到这里\n(如果有的话)'
</script>
<template>
<textarea class="code-input" v-model="stdin_input" :placeholder="placeholder" :readonly="!edit_mode"></textarea>
</template>
<style scoped>
@import '@/assets/code-input.css';
</style>
<script setup>
import { computed, inject } from 'vue';
const props = defineProps(['step'])
const this_step = computed(() => {
return props.step
})
const { current_step, click_step, highlight_steps } = inject('step')
const finished = computed(() => {
return this_step.value <= current_step.value
})
const css_background_color = computed(() => {
if (Object.values(highlight_steps.value).includes(this_step.value)) {
if (finished.value) {
return '#ffb4ab' // 已完成 高亮
} else {
return '#ffdad6' // 未完成 高亮
}
} else {
if (finished.value) {
return '#71d2ff' // 已完成
} else {
return '#c0e8ff' // 未完成
}
}
})
const css_filter = computed(() => {
if (finished.value) {
return 'brightness(0.8)' // 暗色情况下改为1.5
} else {
return 'brightness(0.8)' // 暗色情况下改为1.5
}
})
function click_step_unit() {
click_step(this_step.value)
}
</script>
<template>
<div class="step-unit" @click="click_step_unit">
</div>
</template>
<style scoped>
.step-unit {
background-color: v-bind(css_background_color);
transition-duration: 200ms;
}
.step-unit:hover {
filter: v-bind(css_filter);
transition-duration: 200ms;
}
</style>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment