Skip to content

Commit

Permalink
feat(cz-git,cli): defaultScope support string[] to default-select…
Browse files Browse the repository at this point in the history
… for checkbox mode (#148)

* feat(plugin-inquirer): support item setting checked status on checkbox initial

link #140
  • Loading branch information
Zhengqbbb committed Dec 5, 2023
1 parent 44f6c49 commit a02b7d1
Show file tree
Hide file tree
Showing 13 changed files with 106 additions and 46 deletions.
2 changes: 1 addition & 1 deletion docs/config/show.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ Using ==default value== can produce many ways to make the tool more suitable for
## defaultScope

- **description** : pin scope item the top of the scope list (match `scopes` item value)
- **type** : `string`
- **type** : `string` | `string[]` <sup>For checkbox mode. items will automatic checked</sup>
- **default** : `""`
- **other** : Initialize the completion template in **custom scope**. you can use <kbd>Tab</kbd> or <kbd>→</kbd> to quickly complete; you can also use the <kbd> Enter</kbd> output template directly.

Expand Down
4 changes: 4 additions & 0 deletions docs/recipes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ module.exports = {

![demo-gif](https://user-images.githubusercontent.com/40693636/170836009-26331ad3-8e7f-4183-a4af-15372b6420d6.gif) <!-- size=720x263 -->

:::tip
In checkbox mode, if `defaultScope` is passed as a `string[]`, it will default-select and pin top the options whose values match those within the `scopes` range list.
:::

## Input mode

If you don't want to use selection mode, you want to use input mode.<br>
Expand Down
2 changes: 1 addition & 1 deletion docs/zh/config/show.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export ___X_CMD_THEME_COLOR_CODE="38;5;043"
## defaultScope

- **描述** : 如果 defaultScope 与 `scopes` 选择范围列表项中的 value 相匹配就会进行星标置顶操作。
- **类型** : `string`
- **类型** : `string` | `string[]` <sup>[...] 在多选模式中会默认选中</sup>
- **默认** : `""`
- **额外** : 在 **自定义范围** 中是否使用显示默认值

Expand Down
4 changes: 4 additions & 0 deletions docs/zh/recipes/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ module.exports = {

![demo-gif](https://user-images.githubusercontent.com/40693636/170836009-26331ad3-8e7f-4183-a4af-15372b6420d6.gif) <!-- size=720x263 -->

:::tip
在多选模式中,如果 `defaultScope` 传入的的 `string[]`, 会将 `scopes` 范围列表项中的 value 相匹配的选项进行默认选中和置顶操作
:::

## 输入模式

如果不想使用选择模式,想要使用输入模式 <sup>Input</sup>。可以使用自定义范围的输入框进行代替使用
Expand Down
12 changes: 12 additions & 0 deletions packages/@cz-git/plugin-inquirer/examples/checkbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ inquirer
type: "search-checkbox",
name: "testTwo",
themeColorCode: "38;5;043",
separator: "|",
message: "Select checkbox test:",
source: function (answers, input) {
return fuzzyFilter(input, testArr2);
}
},
{
type: "search-checkbox",
name: "testThree",
themeColorCode: "38;5;043",
initialCheckedValue: 'test5',
message: "Select checkbox test:",
source: function (answers, input) {
return fuzzyFilter(input, testArr2);
Expand All @@ -63,6 +74,7 @@ inquirer
name: "cz",
themeColorCode: "38;5;042",
message: "Select scope:",
initialCheckedValue: ['cz-git', 'docs'],
source: function (answers, input) {
return fuzzyFilter(input, testArr3);
}
Expand Down
33 changes: 23 additions & 10 deletions packages/@cz-git/plugin-inquirer/src/checkbox/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,17 @@ export class SearchCheckbox extends Base {
private searching = false
private haveSearched = false
private themeColorCode?: string
private initialCheckedValue?: string[] | string
private initialValue: any = -1
private lastSearchInput?: string
private paginator: Paginator = new Paginator(this.screen, { isInfinite: true })
private separator = ' ,'
private separator = ','
private answer?: boolean
private done: any

constructor(questions: Question, readline: ReadlineInterface, answers: Answers) {
super(questions, readline, answers)
const { source, separator, isInitDefault, themeColorCode } = this
const { source, separator, isInitDefault, themeColorCode, initialCheckedValue } = this
.opt as unknown as SearchPromptQuestionOptions
if (!source)
this.throwParamError('source')
Expand All @@ -46,6 +47,8 @@ export class SearchCheckbox extends Base {
this.initialValue = this.opt.default
if (themeColorCode)
this.themeColorCode = themeColorCode
if (initialCheckedValue)
this.initialCheckedValue = initialCheckedValue
this.renderChoices = new Choices([], {})
}

Expand Down Expand Up @@ -171,8 +174,21 @@ export class SearchCheckbox extends Base {

const realChoices = choices.filter(choice => isSelectable(choice))
this.choicesLen = realChoices.length
if (this.firstRender)

if (this.firstRender) {
if (this.initialCheckedValue) {
const initialCheckedValue = Array.isArray(this.initialCheckedValue)
? this.initialCheckedValue
: [this.initialCheckedValue]
initialCheckedValue.forEach((value) => {
const idx = this.renderChoices.realChoices.findIndex(choice => choice.value === value)
if (~idx)
this.renderChoices.realChoices[idx].checked = true
})
}

this.originChoices = JSON.parse(JSON.stringify(this.renderChoices.realChoices))
}

const selectedIndex = realChoices.findIndex(
choice => choice === this.initialValue || choice.value === this.initialValue,
Expand Down Expand Up @@ -326,16 +342,13 @@ function choicesRender(choices: ChoicesType['choices'],
output += ` (${typeof choice.disabled === 'string' ? choice.disabled : 'Disabled'})`
}
else {
const line
= (choice.value === false || choice.value === '___CUSTOM___')
? `${figures.squareSmallFilled} ${choice.name}`
const line = (choice.value === false || choice.value === '___CUSTOM___')
? `${figures.squareSmallFilled} ${choice.name}`
: `${getCheckbox(choice.checked || false)} ${choice.name}`

: `${getCheckbox(choice.checked || false)} ${choice.name}`
if (i - separatorOffset === pointer) {
themeColorCode
? (output += style.rgb(themeColorCode)(
` ${figures.pointer}${style.rgb(themeColorCode)(line)}`,
))
? (output += style.rgb(themeColorCode)(` ${figures.pointer}${style.rgb(themeColorCode)(line)}`))
: (output += style.cyan(` ${figures.pointer}${line}`))
}
else {
Expand Down
21 changes: 13 additions & 8 deletions packages/@cz-git/plugin-inquirer/src/shared/types/inquirer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ export interface ChoiceType<T> {
export interface ChoicesType {
getChoice(pointer: number): ChoiceType<any>
/**
* @description: origin choices
* @description origin choices
*/
choices: ChoiceType<Separator['type']>[]
/**
* @description: filter Separator choices
* @description filter Separator choices
*/
realChoices: ChoiceType<string>[]
}
Expand All @@ -36,27 +36,32 @@ export interface SearchPromptQuestionOptions<T extends Answers = Answers> extend
separator: string

/**
* @description: support rgb color code. e.g: `38;5;042`
* @default: cyan
* @description support rgb color code. e.g: `38;5;042`
* @default cyan
* @tip the rgb color see to check your number: https://github.com/sindresorhus/xterm-colors
*/
themeColorCode?: string

/**
* @description:
* @description default checked item's value array on initial
*/
initialCheckedValue?: string[] | string

/**
* @description
* Function to determine what options to display to user.
* Called with previous answers object and the current user input each time the user types, it must return a promise.
*/
source: (answersSoFar: T, input: string | undefined) => Promise<any[]>

/**
* @description: The number of elements to show on each page.
* @description The number of elements to show on each page.
*/
pageSize?: number | undefined

/**
* @description:
* default false. Setting it to true turns the input into a normal text input.
* @description Setting it to true turns the input into a normal text input.
* @default false
*/
isInitDefault?: boolean | undefined
}
Expand Down
3 changes: 2 additions & 1 deletion packages/cz-git/src/generator/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
getCurrentScopes,
getMaxSubjectLength,
isSingleItem,
isString,
parseStandardScopes,
useThemeCode,
wrap,
Expand Down Expand Up @@ -135,7 +136,7 @@ export function generateMessage(answers: Answers,
// resolve custom value
const { customScope, customFooterPrefix } = answers
answers.scope = getCustomValue(answers.scope, customScope)
|| (options.defaultScope?.startsWith('___CUSTOM___:') && customScope)
|| (isString(options.defaultScope) && (options.defaultScope as string).startsWith('___CUSTOM___:') && customScope)
|| ''
answers.footerPrefix = getCustomValue(answers.footerPrefix, customFooterPrefix) as string
// resolve single | multiple item
Expand Down
26 changes: 18 additions & 8 deletions packages/cz-git/src/generator/question.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
getMaxSubjectLength,
getProcessSubject,
isSingleItem,
isString,
log,
parseStandardScopes,
resolveDefaultType,
Expand Down Expand Up @@ -47,8 +48,9 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
type: options.enableMultipleScopes ? 'search-checkbox' : 'search-list',
name: 'scope',
message: options.messages?.scope,
themeColorCode: options?.themeColorCode,
separator: options.scopeEnumSeparator,
themeColorCode: options?.themeColorCode,
initialCheckedValue: options.defaultScope, // checkbox mode
source: (answer: Answers, input: string) => {
let scopeSource: Option[] = []
const _answerType = resolveDefaultType(options, answer)
Expand All @@ -63,7 +65,7 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
options.customScopesAlias,
options.allowCustomScopes,
options.allowEmptyScopes,
options.defaultScope as string,
options.defaultScope,
options.scopeFilters,
)
const searchTarget = options.scopesSearchValue
Expand All @@ -74,9 +76,9 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
validate: (input: string | Array<string>) => {
if (options.allowEmptyScopes)
return true

if (typeof input === 'string')
return input.length ? true : style.red('[ERROR] scope is required')

else
return input.length !== 0 ? true : style.red('[ERROR] scope is required')
},
Expand All @@ -95,7 +97,10 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
type: 'complete-input',
name: 'customScope',
message: options.messages?.customScope,
completeValue: options.defaultScope?.replace(/^___CUSTOM___:/, '') || undefined,
completeValue: (
// input mode
isString(options.defaultScope) && (options.defaultScope as string).replace(/^___CUSTOM___:/, '')
) || undefined,
validate: (input: string | Array<string>) => {
if (options.allowEmptyScopes)
return true
Expand All @@ -106,14 +111,16 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
return input.length !== 0 ? true : style.red('[ERROR] scope is required')
},
when: (answers: Answers) => {
return answers.scope === '___CUSTOM___' || options.defaultScope?.startsWith('___CUSTOM___:')
return answers.scope === '___CUSTOM___'
|| (isString(options.defaultScope) && (options.defaultScope as string).startsWith('___CUSTOM___:'))
},
transformer: (input: string) => useThemeCode(input, options.themeColorCode),
},
{
type: 'complete-input',
name: 'subject',
message: options.messages?.subject,
completeValue: options.defaultSubject || undefined,
validate: (subject: string, answers: Answers) => {
const processedSubject = getProcessSubject(subject)
if (processedSubject.length === 0)
Expand Down Expand Up @@ -166,15 +173,19 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
&& subjectLength <= maxSubjectLength
)
? style.gray(`[${tooltip}]`)
: isWarning ? style.yellow(`[${tooltip}]`) : style.red(`[${tooltip}]`)
: isWarning
? style.yellow(`[${tooltip}]`)
: style.red(`[${tooltip}]`)
subject
= (
minSubjectLength !== undefined
&& subjectLength >= minSubjectLength
&& subjectLength <= maxSubjectLength
)
? useThemeCode(subject, options.themeColorCode)
: isWarning ? useThemeCode(subject, options.themeColorCode) : style.red(subject)
: isWarning
? useThemeCode(subject, options.themeColorCode)
: style.red(subject)

return `${tooltip}\n` + ` ${subject}`
},
Expand All @@ -186,7 +197,6 @@ export function generateQuestions(options: CommitizenGitOptions, cz: any) {
+ subject.slice(1)
)
},
completeValue: options.defaultSubject || undefined,
},
{
type: 'complete-input',
Expand Down
3 changes: 2 additions & 1 deletion packages/cz-git/src/generator/questionAI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { fuzzyFilter, style } from '@cz-git/inquirer'
import type { CommitizenGitOptions, CommitizenType } from '../shared'
import {
isString,
log,
parseStandardScopes,
resolveListItemPinTop,
Expand All @@ -28,7 +29,7 @@ export async function generateAIPrompt(options: CommitizenGitOptions, cz: Commit
answers.subject = subject
}

if (options.defaultScope)
if (isString(options.defaultScope) && options.defaultScope)
answers.scope = options.defaultScope
return answers
}
Expand Down
10 changes: 6 additions & 4 deletions packages/cz-git/src/shared/types/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type Config = Omit<Partial<typeof defaultConfig>, 'scopes'> & {
maxHeaderLength?: number
maxSubjectLength?: number
minSubjectLength?: number
defaultScope?: string
defaultScope?: string | string[]
defaultSubject?: string
defaultBody?: string
defaultFooterPrefix?: string
Expand Down Expand Up @@ -161,7 +161,7 @@ export interface CommitMessageOptions {

export interface GenerateAIPromptType {
type?: string
defaultScope?: string
defaultScope?: string | string[]
maxSubjectLength?: number
upperCaseSubject?: boolean
diff?: string
Expand Down Expand Up @@ -493,11 +493,13 @@ export interface CommitizenGitOptions {
defaultType?: string

/**
* @description: Whether to use display default value in custom scope
* @description Whether to use display default value in custom scope
* @tip pin scope item the top of the scope list (match item value)
*
* `string[]` for checkbox mode will default-select the options whose values match those within the `scopes` range list.
* @example: When you want to use default, just keyboard <Enter> it
*/
defaultScope?: string
defaultScope?: string | string[]

/**
* @description: default value show subject template prompt
Expand Down

0 comments on commit a02b7d1

Please sign in to comment.