Skip to content

Commit

Permalink
feat(commands): support set alias args
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 25, 2024
1 parent 98dcb5b commit 466541f
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 28 deletions.
114 changes: 86 additions & 28 deletions plugins/commands/client/command.vue
Expand Up @@ -13,30 +13,29 @@
</div>

<div class="mb-8">
<h2 class="k-schema-header">名称设置</h2>
<h2 class="k-schema-header">
别名设置
<el-button class="float-right mr-4" @click="(inputName = target = '', inputSource = '')">添加</el-button>
</h2>
<table>
<colgroup>
<col/>
<col width="240px"/>
</colgroup>
<tr v-for="([name, item], index) in Object.entries(current.aliases)" :key="name">
<td class="text-left alias-name" :class="{ disabled: item.filter === false }">{{ name }}</td>
<tr v-for="([name, alias], index) in Object.entries(current.aliases)" :key="name">
<td class="text-left">
<span class="alias-name" :class="{ disabled: alias.filter === false }">{{ name }}</span>
{{ stringify(alias) ? `(${stringify(alias)})` : '' }}
</td>
<td class="text-right">
<el-button
v-if="index > 0"
:disabled="!item"
:disabled="alias.filter === false"
@click="setDefault(name)"
>{{ index > 0 ? '设为默认' : '显示名称' }}</el-button>
<el-button v-if="item.filter !== false" @click="deleteAlias(name)">
<el-button v-if="alias.filter !== false" @click="deleteAlias(name)">
{{ command.initial.aliases[name] ? '禁用' : '删除' }}
</el-button>
<el-button v-else @click="recoverAlias(name)">恢复</el-button>
</td>
</tr>
</table>
<p>
<el-button @click="showAliasDialog = true">添加别名</el-button>
</p>
</div>

<k-form
Expand All @@ -55,21 +54,45 @@
>选项:{{ option.syntax }}</k-form>
</template>

<el-dialog class="command-alias-dialog" destroy-on-close v-model="showAliasDialog" title="编辑别名" @open="handleOpen">
<el-input ref="inputEl" :class="{ invalid }" v-model="inputText" @keydown.enter.stop.prevent="onEnter" placeholder="请输入名称"></el-input>
<el-dialog
class="command-alias-dialog"
destroy-on-close
v-model="showAliasDialog"
:title="target ? '编辑别名' : '添加别名'"
@open="handleOpen"
>
<div>
<el-input
ref="inputEl"
:class="{ invalid: invalidName }"
v-model="inputName"
@keydown.enter.stop.prevent="onEnter"
placeholder="请输入别名"
></el-input>
</div>
<div class="mt-2">
<el-input
:class="{ invalid: parsed.error }"
v-model="inputSource"
@keydown.enter.stop.prevent="onEnter"
placeholder="请输入参数 (可选)"
></el-input>
</div>
<template #footer>
<el-button @click="showAliasDialog = false">取消</el-button>
<el-button type="primary" :disabled="invalid" @click="onEnter">确定</el-button>
<el-button type="primary" :disabled="invalidName || parsed.error" @click="onEnter">确定</el-button>
</template>
</el-dialog>
</template>

<script setup lang="ts">
import { ref, watch, computed, nextTick } from 'vue'
import { watchDebounced } from '@vueuse/core'
import { Schema, Dict, valueMap, clone, store, send, pick, useContext, deepEqual, useRpc } from '@koishijs/client'
import { createSchema } from './utils'
import { CommandData, CommandState } from '../lib'
import type { Argv, Command } from 'koishi'
const ctx = useContext()
const data = useRpc<Dict<CommandData>>()
Expand All @@ -84,10 +107,16 @@ const schema = ref<{
}>()
const inputEl = ref()
const inputText = ref<string>()
const showAliasDialog = ref(false)
const inputName = ref('')
const inputSource = ref('')
const target = ref<string>(null)
const current = ref<CommandState>()
const showAliasDialog = computed({
get: () => typeof target.value === 'string',
set: () => target.value = null,
})
watch(() => props.command, (value) => {
if (!value) return
const { initial, override } = value
Expand Down Expand Up @@ -129,27 +158,48 @@ function recoverAlias(name: string) {
send('command/aliases', props.command.name, current.value.aliases)
}
const aliases = computed(() => {
return Object.values(data.value).flatMap(command => command.override.aliases)
})
const invalid = computed(() => {
return !inputText.value || aliases.value[inputText.value]
})
function stringify(alias: Command.Alias) {
return [
...alias.args || [],
...Object.entries(alias.options || {}).map(([key, value]) => {
return value === true ? `--${key}` : `--${key}=${value}`
}),
].join(' ')
}
async function handleOpen() {
// https://github.com/element-plus/element-plus/issues/15250
await nextTick()
inputEl.value?.focus()
}
const aliases = computed(() => {
return Object.values(data.value).flatMap(command => command.override.aliases)
})
const invalidName = computed(() => {
return !inputName.value || aliases.value[inputName.value]
})
const parsed = ref<Argv>({})
watchDebounced(inputSource, async (value) => {
if (!value.trim()) return
parsed.value = await send('command/parse', props.command.name, inputSource.value)
}, { debounce: 500 })
async function onEnter() {
if (!invalid.value) {
current.value.aliases[inputText.value] = {}
await send('command/aliases', props.command.name, current.value.aliases)
if (invalidName.value) return
if (inputSource.value.trim()) {
const alias = await send('command/parse', props.command.name, inputSource.value)
if (alias.error) return
current.value.aliases[inputName.value] = alias
} else {
current.value.aliases[inputName.value] = {}
}
await send('command/aliases', props.command.name, current.value.aliases)
showAliasDialog.value = false
inputText.value = ''
inputSource.value = ''
}
</script>
Expand All @@ -161,4 +211,12 @@ async function onEnter() {
color: var(--k-color-disabled);
}
tr {
transition: var(--color-transition);
}
tr:hover {
background-color: var(--el-fill-color);
}
</style>
6 changes: 6 additions & 0 deletions plugins/commands/src/index.ts
Expand Up @@ -10,6 +10,7 @@ declare module '@koishijs/console' {
'command/update'(name: string, config: Pick<CommandState, 'config' | 'options'>): void
'command/teleport'(name: string, parent: string): void
'command/aliases'(name: string, aliases: Dict<Command.Alias>): void
'command/parse'(name: string, source: string): Argv
}
}

Expand Down Expand Up @@ -375,6 +376,11 @@ export class CommandManager {
this.remove(name)
this.refresh()
}, { authority: 4 })

ctx.console.addListener('command/parse', (name, source) => {
const command = this.ctx.$commander.get(name)
return command.parse(source)
})
})
}
}
Expand Down

0 comments on commit 466541f

Please sign in to comment.