mirror of
https://github.com/viarotel-org/escrcpy.git
synced 2025-01-19 09:27:30 +01:00
feat: 🎉 Add Terminal Debugging
This commit is contained in:
parent
4cc6617b9f
commit
fdf40c70e8
@ -43,12 +43,16 @@
|
|||||||
"husky": "^8.0.0",
|
"husky": "^8.0.0",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
|
"postcss": "^8.4.31",
|
||||||
|
"postcss-nested": "^6.0.1",
|
||||||
|
"postcss-scss": "^4.0.9",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
"vite": "^4.5.0",
|
"vite": "^4.5.0",
|
||||||
"vite-plugin-electron": "^0.14.1",
|
"vite-plugin-electron": "^0.14.1",
|
||||||
"vite-plugin-electron-renderer": "^0.14.5",
|
"vite-plugin-electron-renderer": "^0.14.5",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^4.0.0",
|
||||||
|
"vue-command": "^35.2.1",
|
||||||
"vue-i18n": "^9.5.0",
|
"vue-i18n": "^9.5.0",
|
||||||
"which": "^4.0.0"
|
"which": "^4.0.0"
|
||||||
}
|
}
|
||||||
|
7
postcss.config.mjs
Normal file
7
postcss.config.mjs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import nested from 'postcss-nested'
|
||||||
|
import postcssScss from 'postcss-scss'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
parser: postcssScss,
|
||||||
|
plugins: [nested],
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import { createStderr, createStdout } from 'vue-command'
|
||||||
|
|
||||||
|
const $adb = window.adbkit
|
||||||
|
|
||||||
|
export function useAdb({ loading }) {
|
||||||
|
const adb = async (args) => {
|
||||||
|
loading.value = true
|
||||||
|
const command = args.slice(1).join(' ')
|
||||||
|
|
||||||
|
const { stderr, stdout } = await $adb.shell(command || 'help')
|
||||||
|
|
||||||
|
if (stderr) {
|
||||||
|
return createStderr(stderr)
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = false
|
||||||
|
|
||||||
|
return createStdout(stdout)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
adb,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import { debounce } from 'lodash-es'
|
||||||
|
import { createStderr, createStdout, textFormatter } from 'vue-command'
|
||||||
|
|
||||||
|
const $gnirehtet = window.gnirehtet
|
||||||
|
|
||||||
|
const fixCursor = (history) => {
|
||||||
|
const length = history.value.length
|
||||||
|
if (history.value[length - 1]?.__name === 'VueCommandQuery') {
|
||||||
|
history.value.splice(length - 1, 1, textFormatter('Waiting...'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGnirehtet({ vShell, history, loading } = {}) {
|
||||||
|
const gnirehtet = async (args) => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
const command = args.slice(1).join(' ')
|
||||||
|
|
||||||
|
const appendToHistory = debounce(vShell.value.appendToHistory, 500)
|
||||||
|
|
||||||
|
let stdoutText = ''
|
||||||
|
let stderrText = ''
|
||||||
|
$gnirehtet.shell(command, {
|
||||||
|
stdout(text) {
|
||||||
|
loading.value = false
|
||||||
|
|
||||||
|
stdoutText += text
|
||||||
|
|
||||||
|
fixCursor(history)
|
||||||
|
|
||||||
|
appendToHistory(createStdout(stdoutText))
|
||||||
|
},
|
||||||
|
stderr(text) {
|
||||||
|
loading.value = false
|
||||||
|
|
||||||
|
stderrText += text
|
||||||
|
|
||||||
|
fixCursor(history)
|
||||||
|
|
||||||
|
appendToHistory(createStderr(stderrText))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return textFormatter('Loading...')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
gnirehtet,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
import { debounce } from 'lodash-es'
|
||||||
|
import { createStderr, createStdout, textFormatter } from 'vue-command'
|
||||||
|
|
||||||
|
const $scrcpy = window.scrcpy
|
||||||
|
|
||||||
|
const fixCursor = (history) => {
|
||||||
|
const length = history.value.length
|
||||||
|
if (history.value[length - 1]?.__name === 'VueCommandQuery') {
|
||||||
|
history.value.splice(length - 1, 1, textFormatter('Waiting...'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useScrcpy({ vShell, history, loading } = {}) {
|
||||||
|
const scrcpy = async (args) => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
const command = args.slice(1).join(' ')
|
||||||
|
|
||||||
|
const appendToHistory = debounce(vShell.value.appendToHistory, 500)
|
||||||
|
|
||||||
|
let stdoutText = ''
|
||||||
|
let stderrText = ''
|
||||||
|
$scrcpy.shell(command, {
|
||||||
|
stdout(text) {
|
||||||
|
loading.value = false
|
||||||
|
|
||||||
|
stdoutText += text
|
||||||
|
|
||||||
|
fixCursor(history)
|
||||||
|
|
||||||
|
appendToHistory(createStdout(stdoutText))
|
||||||
|
},
|
||||||
|
stderr(text) {
|
||||||
|
loading.value = false
|
||||||
|
|
||||||
|
stderrText += text
|
||||||
|
|
||||||
|
fixCursor(history)
|
||||||
|
|
||||||
|
appendToHistory(createStderr(stderrText))
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return textFormatter('Loading...')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
scrcpy,
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog
|
||||||
|
v-model="visible"
|
||||||
|
width="80%"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
:close-on-press-escape="false"
|
||||||
|
class="overflow-hidden rounded-xl el-dialog-headless"
|
||||||
|
@open="onOpen"
|
||||||
|
>
|
||||||
|
<el-icon
|
||||||
|
class="cursor-pointer absolute top-2 right-2 w-8 h-8 flex items-center justify-center text-gray-200 hover:bg-gray-700 !active:bg-red-600 rounded"
|
||||||
|
@click="hide"
|
||||||
|
>
|
||||||
|
<CloseBold />
|
||||||
|
</el-icon>
|
||||||
|
|
||||||
|
<VueCommand
|
||||||
|
v-if="visible"
|
||||||
|
:ref="(value) => (vShell = value)"
|
||||||
|
v-model:history="history"
|
||||||
|
:commands="commands"
|
||||||
|
hide-bar
|
||||||
|
show-help
|
||||||
|
help-text="Type in help"
|
||||||
|
:help-timeout="3500"
|
||||||
|
class=""
|
||||||
|
:dispatched-queries="dispatchedQueries"
|
||||||
|
>
|
||||||
|
<template #prompt>
|
||||||
|
<div class="flex items-center pr-2">
|
||||||
|
<span class="">escrcpy~$</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VueCommand>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import VueCommand, {
|
||||||
|
createQuery,
|
||||||
|
createStdout,
|
||||||
|
listFormatter,
|
||||||
|
} from 'vue-command'
|
||||||
|
import 'vue-command/dist/vue-command.css'
|
||||||
|
import { useAdb } from './composables/adb.js'
|
||||||
|
import { useScrcpy } from './composables/scrcpy.js'
|
||||||
|
import { useGnirehtet } from './composables/gnirehtet.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
VueCommand,
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const vShell = ref(null)
|
||||||
|
const history = ref([createQuery()])
|
||||||
|
const loading = ref(false)
|
||||||
|
const dispatchedQueries = ref(new Set([]))
|
||||||
|
|
||||||
|
const { adb } = useAdb({ vShell, history, loading })
|
||||||
|
const { scrcpy } = useScrcpy({ vShell, history, loading })
|
||||||
|
const { gnirehtet } = useGnirehtet({ vShell, history, loading })
|
||||||
|
|
||||||
|
const commands = ref({
|
||||||
|
adb,
|
||||||
|
scrcpy,
|
||||||
|
gnirehtet,
|
||||||
|
clear() {
|
||||||
|
history.value = []
|
||||||
|
return createQuery()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
commands.value.help = () => {
|
||||||
|
const commandList = Object.keys(commands.value)
|
||||||
|
return createStdout(listFormatter('Supported Commands:', ...commandList))
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatchedQueries.value = new Set(Object.keys(commands.value))
|
||||||
|
|
||||||
|
return {
|
||||||
|
vShell,
|
||||||
|
loading,
|
||||||
|
history,
|
||||||
|
commands,
|
||||||
|
dispatchedQueries,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
visible: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show() {
|
||||||
|
this.visible = true
|
||||||
|
},
|
||||||
|
hide() {
|
||||||
|
this.visible = false
|
||||||
|
},
|
||||||
|
async onOpen() {
|
||||||
|
console.log('vShell', this.vShell)
|
||||||
|
|
||||||
|
this.vShell.signals.off('SIGINT')
|
||||||
|
|
||||||
|
this.vShell.signals.on('SIGINT', () => {
|
||||||
|
console.log('vShell.signals.on.SIGINT')
|
||||||
|
this.$gnirehtet.shell('stop')
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
23
src/components/Device/components/Terminal/index.vue
Normal file
23
src/components/Device/components/Terminal/index.vue
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
<slot :show="show" />
|
||||||
|
<TerminalDialog ref="terminalDialog" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import TerminalDialog from './components/TerminalDialog/index.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
TerminalDialog,
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
show() {
|
||||||
|
this.$refs.terminalDialog.show()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
@ -19,6 +19,14 @@
|
|||||||
<el-button icon="View" @click="handleLog">
|
<el-button icon="View" @click="handleLog">
|
||||||
{{ $t("device.log.name") }}
|
{{ $t("device.log.name") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
|
||||||
|
<Terminal>
|
||||||
|
<template #default="{ show }">
|
||||||
|
<el-button icon="View" @click="show">
|
||||||
|
{{ $t("device.terminal.name") }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</Terminal>
|
||||||
</div>
|
</div>
|
||||||
<div class="pt-4 flex-1 h-0 overflow-hidden">
|
<div class="pt-4 flex-1 h-0 overflow-hidden">
|
||||||
<el-table
|
<el-table
|
||||||
@ -157,6 +165,7 @@
|
|||||||
import ControlBar from './components/ControlBar/index.vue'
|
import ControlBar from './components/ControlBar/index.vue'
|
||||||
import Remark from './components/Remark/index.vue'
|
import Remark from './components/Remark/index.vue'
|
||||||
import Wireless from './components/Wireless/index.vue'
|
import Wireless from './components/Wireless/index.vue'
|
||||||
|
import Terminal from './components/Terminal/index.vue'
|
||||||
import { isIPWithPort, sleep } from '@/utils/index.js'
|
import { isIPWithPort, sleep } from '@/utils/index.js'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -164,6 +173,7 @@ export default {
|
|||||||
Wireless,
|
Wireless,
|
||||||
ControlBar,
|
ControlBar,
|
||||||
Remark,
|
Remark,
|
||||||
|
Terminal,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
"device.name": "设备名称",
|
"device.name": "设备名称",
|
||||||
"device.remark": "备注",
|
"device.remark": "备注",
|
||||||
"device.permission.error": "设备可能未授权成功,请重新插拔设备并点击允许USB调试",
|
"device.permission.error": "设备可能未授权成功,请重新插拔设备并点击允许USB调试",
|
||||||
|
"device.terminal.name": "终端调试",
|
||||||
|
|
||||||
"device.wireless.name": "无线",
|
"device.wireless.name": "无线",
|
||||||
"device.wireless.mode": "无线模式",
|
"device.wireless.mode": "无线模式",
|
||||||
|
@ -36,3 +36,26 @@
|
|||||||
@apply h-full overflow-auto;
|
@apply h-full overflow-auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-dialog-flex {
|
||||||
|
height: calc(100% - 20vh - 8px) !important;
|
||||||
|
@apply flex flex-col !my-[10vh];
|
||||||
|
.el-dialog__header,
|
||||||
|
.el-dialog__footer {
|
||||||
|
@apply flex-none;
|
||||||
|
}
|
||||||
|
.el-dialog__body {
|
||||||
|
@apply flex-1 !h-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog-headless {
|
||||||
|
.el-dialog__header,
|
||||||
|
.el-dialog__footer {
|
||||||
|
@apply !hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-dialog__body {
|
||||||
|
@apply !p-0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,6 +10,8 @@ import useUnoCSS from 'unocss/vite'
|
|||||||
import useSvg from 'vite-svg-loader'
|
import useSvg from 'vite-svg-loader'
|
||||||
import useI18n from '@intlify/unplugin-vue-i18n/vite'
|
import useI18n from '@intlify/unplugin-vue-i18n/vite'
|
||||||
|
|
||||||
|
import postcssConfig from './postcss.config.mjs'
|
||||||
|
|
||||||
const merge = (config, { command = '' } = {}) =>
|
const merge = (config, { command = '' } = {}) =>
|
||||||
mergeConfig(
|
mergeConfig(
|
||||||
{
|
{
|
||||||
@ -58,5 +60,8 @@ export default params =>
|
|||||||
]),
|
]),
|
||||||
useRenderer(),
|
useRenderer(),
|
||||||
],
|
],
|
||||||
|
css: {
|
||||||
|
postcss: postcssConfig,
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user