Skip to content

Commit

Permalink
feat(core): auto redirect to subcommand, fix #476
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jan 28, 2022
1 parent 131b8d3 commit 9852598
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 64 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class App extends Context {
if (!key) return
const segments = key.split('.')
let i = 1, name = segments[0], cmd: Command
while ((cmd = this._commands.get(name)) && i < segments.length) {
while ((cmd = this.getCommand(name)) && i < segments.length) {
name = cmd.name + '.' + segments[i++]
}
return cmd
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class Command<U extends User.Field = never, G extends Channel.Field = nev

private _registerAlias(name: string) {
this._aliases.push(name)
const previous = this.app._commands.get(name)
const previous = this.app.getCommand(name)
if (!previous) {
this.app._commands.set(name, this)
} else if (previous !== this) {
Expand Down
6 changes: 5 additions & 1 deletion packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,10 @@ export class Context {
return this.createTimerDispose(setInterval(callback, ms, ...args))
}

getCommand(name: string) {
return this.app._commands.get(name)
}

command<D extends string>(def: D, config?: Command.Config): Command<never, never, Argv.ArgumentType<D>>
command<D extends string>(def: D, desc: string, config?: Command.Config): Command<never, never, Argv.ArgumentType<D>>
command(def: string, ...args: [Command.Config?] | [string, Command.Config?]) {
Expand All @@ -500,7 +504,7 @@ export class Context {
segments.forEach((segment, index) => {
const code = segment.charCodeAt(0)
const name = code === 46 ? parent.name + segment : code === 47 ? segment.slice(1) : segment
let command = this.app._commands.get(name)
let command = this.getCommand(name)
if (command) {
if (parent) {
if (command === parent) {
Expand Down
12 changes: 2 additions & 10 deletions packages/core/src/internal/help.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,7 @@ export interface HelpConfig extends Command.Config {
}

export function enableHelp<U extends User.Field, G extends Channel.Field, A extends any[], O extends {}>(cmd: Command<U, G, A, O>) {
return cmd
.option('help', '-h 显示此信息', { hidden: true })
.before(async ({ session, options }, ...args) => {
if (cmd['_actions'].length && !options['help']) return
return session.execute({
name: 'help',
args: [cmd.name],
})
})
return cmd.option('help', '-h 显示此信息', { hidden: true })
}

export default function help(ctx: Context, config: HelpConfig = {}) {
Expand Down Expand Up @@ -73,7 +65,7 @@ export default function help(ctx: Context, config: HelpConfig = {}) {
prefix: template('internal.help-suggestion-prefix'),
suffix: template('internal.help-suggestion-suffix'),
async apply(suggestion) {
return showHelp(app._commands.get(suggestion), this as any, options)
return showHelp(ctx.getCommand(suggestion), this as any, options)
},
})
return
Expand Down
25 changes: 25 additions & 0 deletions packages/core/src/internal/runtime.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineProperty, template, valueMap } from '@koishijs/utils'
import { Argv } from '../parser'
import { Context } from '../context'
import { Session } from '../session'
import { getCommandNames } from './help'

export default function runtime(ctx: Context) {
Expand Down Expand Up @@ -83,4 +84,28 @@ export default function runtime(ctx: Context) {
},
})
})

function executeHelp(session: Session, name: string) {
if (!ctx.getCommand('help')) return
return session.execute({
name: 'help',
args: [name],
})
}

ctx.before('command/execute', (argv) => {
const { args, command, options, session } = argv
if (options['help'] && command._options.help) {
return executeHelp(session, command.name)
}

if (command['_actions'].length) return
const arg0 = args.shift() || ''
const subcommand = ctx.getCommand(command.name + '.' + arg0)
if (subcommand) {
return session.execute({ ...argv, command: subcommand })
} else {
return executeHelp(session, command.name)
}
})
}
2 changes: 1 addition & 1 deletion packages/core/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ export class Session<U extends User.Field = never, G extends Channel.Field = nev
}
if (!this.resolve(argv)) return ''
} else {
argv.command ||= this.app._commands.get(argv.name)
argv.command ||= this.app.getCommand(argv.name)
if (!argv.command) {
logger.warn(new Error(`cannot find command ${argv.name}`))
return ''
Expand Down
4 changes: 2 additions & 2 deletions packages/core/tests/help.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ describe('Help Command', () => {
it('disable help command', async () => {
const app = new App({ help: false })
app.plugin(mock)
app.command('foo')
app.command('foo').action(() => {})
await app.start()

const client = app.mock.client('123')
Expand All @@ -149,7 +149,7 @@ describe('Help Command', () => {
it('disable help options', async () => {
const app = new App({ help: { options: false } })
app.plugin(mock)
app.command('foo')
app.command('foo').action(() => {})
await app.start()

const client = app.mock.client('123')
Expand Down
84 changes: 41 additions & 43 deletions plugins/common/forward/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Context, Session, Dict, Time, template, Schema } from 'koishi'
import { Context, Session, Dict, Time, template, Schema, Command } from 'koishi'
import { parsePlatform } from '@koishijs/helpers'

declare module 'koishi' {
Expand Down Expand Up @@ -95,48 +95,46 @@ export function apply(ctx: Context, { rules, interval }: Config) {
})

ctx.using(['database'], (ctx) => {
ctx.command('forward <channel:channel>', '设置消息转发', { authority: 3, checkUnknown: true })
.channelFields(['forward'])
.option('add', '-a 添加目标频道')
.option('delete', '-d 移除目标频道')
.option('clear', '-c 移除全部目标频道')
.option('list', '-l 查看目标频道列表')
const cmd = ctx
.command('forward [operation:string] <channel:channel>', '设置消息转发', { authority: 3 })
.usage(session => `当前频道 ID:${session.cid}`)
.before(async ({ session, options }, id) => {
if (options.add || options.delete) {
return id ? null : '请提供目标频道。'
} else if (Object.keys(options).length) {
return
}
return session.execute({
name: 'help',
args: ['forward'],
})
})
.action(async ({ session, options }, id) => {
const { forward } = session.channel
if (options.add) {
if (forward.includes(id)) {
return `${id} 已经是当前频道的目标频道。`
} else {
forward.push(id)
return `已成功添加目标频道 ${id}。`
}
} else if (options.delete) {
const index = forward.indexOf(id)
if (index >= 0) {
forward.splice(index, 1)
return `已成功移除目标频道 ${id}。`
} else {
return `${id} 不是当前频道的目标频道。`
}
} else if (options.clear) {
session.channel.forward = []
return '已成功移除全部目标频道。'
} else if (options.list) {
if (!forward.length) return '当前频道没有设置目标频道。'
return ['当前频道的目标频道列表为:', ...forward].join('\n')
}
})
.alias('fwd')

const register = (def: string, desc: string, callback: Command.Action<never, 'forward', [string]>) => cmd
.subcommand(def, desc, { authority: 3, checkArgCount: true })
.channelFields(['forward'])
.action(callback)

register('.add <channel:channel>', '添加目标频道', async ({ session }, id) => {
const { forward } = session.channel
if (forward.includes(id)) {
return `${id} 已经是当前频道的目标频道。`
} else {
forward.push(id)
return `已成功添加目标频道 ${id}。`
}
})

register('.remove <channel:channel>', '移除目标频道', async ({ session }, id) => {
const { forward } = session.channel
const index = forward.indexOf(id)
if (index >= 0) {
forward.splice(index, 1)
return `已成功移除目标频道 ${id}。`
} else {
return `${id} 不是当前频道的目标频道。`
}
}).alias('forward.rm')

register('.clear', '移除全部目标频道', async ({ session }) => {
session.channel.forward = []
return '已成功移除全部目标频道。'
})

register('.list', '查看目标频道列表', async ({ session }) => {
const { forward } = session.channel
if (!forward.length) return '当前频道没有设置目标频道。'
return ['当前频道的目标频道列表为:', ...forward].join('\n')
}).alias('forward.ls')
})
}
10 changes: 5 additions & 5 deletions plugins/common/forward/tests/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ describe('@koishijs/plugin-forward', () => {
await app.mock.initUser('123', 3)

await session2.shouldReply('forward', //)
await session2.shouldReply('forward -a #123', '已成功添加目标频道 mock:123。')
await session2.shouldReply('forward -l', '当前频道的目标频道列表为:\nmock:123')
await session2.shouldReply('forward -d #123', '已成功移除目标频道 mock:123。')
await session2.shouldReply('forward -l', '当前频道没有设置目标频道。')
await session2.shouldReply('forward -c', '已成功移除全部目标频道。')
await session2.shouldReply('forward add #123', '已成功添加目标频道 mock:123。')
await session2.shouldReply('forward ls', '当前频道的目标频道列表为:\nmock:123')
await session2.shouldReply('forward rm #123', '已成功移除目标频道 mock:123。')
await session2.shouldReply('forward ls', '当前频道没有设置目标频道。')
await session2.shouldReply('forward clear', '已成功移除全部目标频道。')
})
})

0 comments on commit 9852598

Please sign in to comment.