Skip to content

Commit 7b03aad

Browse files
committed
Refactor commit message generation to support back navigation and improve file selection flow
1 parent 9ecc2e9 commit 7b03aad

3 files changed

Lines changed: 179 additions & 70 deletions

File tree

‎apps/editor/src/commands/generate-commit-message-command/generate-commit-message-command.ts‎

Lines changed: 108 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { display_token_count } from '../../utils/display-token-count'
77
import { get_commit_message_config } from './utils/get-commit-message-config'
88
import { build_commit_message_prompt } from './utils/build-commit-message-prompt'
99
import { generate_commit_message_with_api } from './utils/generate-commit-message-with-api'
10+
import { ModelProvidersManager } from '@/services/model-providers-manager'
1011

1112
export const generate_commit_message_command = (
1213
context: vscode.ExtensionContext
@@ -31,73 +32,128 @@ export const generate_commit_message_command = (
3132
source_control: vscode.SourceControl | undefined,
3233
should_commit: boolean
3334
) => {
34-
const data = await get_prompt_data(source_control)
35-
if (!data) return
36-
const { repository, was_empty_stage, message_prompt } = data
35+
let files_staged_by_action = false
36+
const api_providers_manager = new ModelProvidersManager(context)
3737

38-
const api_config_data = await get_commit_message_config(context)
38+
while (true) {
39+
const data = await get_prompt_data(source_control)
40+
if (!data) return
41+
const { repository, message_prompt } = data
42+
let { was_empty_stage } = data
3943

40-
if (!api_config_data) {
4144
if (was_empty_stage) {
42-
await vscode.commands.executeCommand('git.unstageAll')
45+
files_staged_by_action = true
46+
} else if (files_staged_by_action) {
47+
was_empty_stage = true
4348
}
44-
return
45-
}
4649

47-
const commit_message = await generate_commit_message_with_api({
48-
endpoint_url: api_config_data.endpoint_url,
49-
provider: api_config_data.provider,
50-
config: api_config_data.config,
51-
message: message_prompt
52-
})
53-
54-
if (commit_message) {
55-
if (should_commit) {
56-
const edited_message = await new Promise<string | undefined>(
57-
(resolve) => {
58-
const input_box = vscode.window.createInputBox()
59-
input_box.value = commit_message
60-
input_box.title = 'Commit Message'
61-
input_box.prompt = 'Review the commit message.'
62-
63-
const close_button = {
64-
iconPath: new vscode.ThemeIcon('close'),
65-
tooltip: 'Close'
66-
}
50+
const default_config =
51+
await api_providers_manager.get_default_commit_messages_config()
52+
const has_default_config = !!default_config
53+
54+
const api_config_data = await get_commit_message_config(
55+
context,
56+
was_empty_stage
57+
)
6758

68-
input_box.buttons = [close_button]
59+
if (api_config_data === 'back') {
60+
if (was_empty_stage) {
61+
await vscode.commands.executeCommand('git.unstageAll')
62+
files_staged_by_action = false
63+
continue
64+
}
65+
return
66+
}
6967

70-
input_box.onDidTriggerButton((button) => {
71-
if (button == close_button) {
72-
input_box.hide()
68+
if (!api_config_data) {
69+
if (was_empty_stage) {
70+
await vscode.commands.executeCommand('git.unstageAll')
71+
}
72+
return
73+
}
74+
75+
const commit_message = await generate_commit_message_with_api({
76+
endpoint_url: api_config_data.endpoint_url,
77+
provider: api_config_data.provider,
78+
config: api_config_data.config,
79+
message: message_prompt
80+
})
81+
82+
if (commit_message) {
83+
if (should_commit) {
84+
const edited_message = await new Promise<string | 'back' | undefined>(
85+
(resolve) => {
86+
const input_box = vscode.window.createInputBox()
87+
input_box.value = commit_message
88+
input_box.title = 'Commit Message'
89+
input_box.prompt = 'Review the commit message.'
90+
91+
if (has_default_config && !files_staged_by_action) {
92+
input_box.buttons = [
93+
{
94+
iconPath: new vscode.ThemeIcon('close'),
95+
tooltip: 'Close'
96+
}
97+
]
98+
} else {
99+
input_box.buttons = [vscode.QuickInputButtons.Back]
73100
}
74-
})
75101

76-
input_box.onDidAccept(() => {
77-
resolve(input_box.value)
78-
input_box.hide()
79-
})
102+
let is_resolved = false
103+
104+
input_box.onDidTriggerButton((button) => {
105+
if (
106+
button === vscode.QuickInputButtons.Back ||
107+
button.tooltip == 'Close'
108+
) {
109+
is_resolved = true
110+
resolve('back')
111+
input_box.hide()
112+
}
113+
})
114+
115+
input_box.onDidAccept(() => {
116+
is_resolved = true
117+
resolve(input_box.value)
118+
input_box.hide()
119+
})
80120

81-
input_box.onDidHide(() => {
82-
resolve(undefined)
83-
input_box.dispose()
84-
})
121+
input_box.onDidHide(() => {
122+
if (!is_resolved) {
123+
resolve('back')
124+
}
125+
input_box.dispose()
126+
})
85127

86-
input_box.show()
128+
input_box.show()
129+
}
130+
)
131+
132+
if (edited_message === 'back') {
133+
if (has_default_config) {
134+
if (files_staged_by_action) {
135+
await vscode.commands.executeCommand('git.unstageAll')
136+
} else {
137+
return
138+
}
139+
}
140+
continue
87141
}
88-
)
89142

90-
if (edited_message) {
91-
repository.inputBox.value = edited_message
92-
await vscode.commands.executeCommand('git.commit', repository)
93-
} else if (was_empty_stage) {
94-
await vscode.commands.executeCommand('git.unstageAll')
143+
if (edited_message) {
144+
repository.inputBox.value = edited_message
145+
await vscode.commands.executeCommand('git.commit', repository)
146+
} else if (was_empty_stage) {
147+
await vscode.commands.executeCommand('git.unstageAll')
148+
}
149+
} else {
150+
repository.inputBox.value = commit_message
95151
}
96-
} else {
97-
repository.inputBox.value = commit_message
152+
} else if (was_empty_stage) {
153+
await vscode.commands.executeCommand('git.unstageAll')
98154
}
99-
} else if (was_empty_stage) {
100-
await vscode.commands.executeCommand('git.unstageAll')
155+
156+
break
101157
}
102158
}
103159

‎apps/editor/src/commands/generate-commit-message-command/utils/get-commit-message-config.ts‎

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,19 @@ export interface CommitMessageConfig {
1818
}
1919

2020
export const get_commit_message_config = async (
21-
context: vscode.ExtensionContext
22-
): Promise<{
23-
config: CommitMessageConfig
24-
provider: any
25-
endpoint_url: string
26-
} | null> => {
21+
context: vscode.ExtensionContext,
22+
show_back_button: boolean = true
23+
): Promise<
24+
| {
25+
config: CommitMessageConfig
26+
provider: any
27+
endpoint_url: string
28+
}
29+
| 'back'
30+
| null
31+
> => {
2732
const api_providers_manager = new ModelProvidersManager(context)
28-
let commit_message_config: CommitMessageConfig | null | undefined =
33+
let commit_message_config: CommitMessageConfig | null | undefined | 'back' =
2934
await api_providers_manager.get_default_commit_messages_config()
3035

3136
if (!commit_message_config) {
@@ -114,12 +119,18 @@ export const get_commit_message_config = async (
114119
}
115120

116121
const quick_pick = vscode.window.createQuickPick()
117-
const close_button = {
118-
iconPath: new vscode.ThemeIcon('close'),
119-
tooltip: 'Close'
122+
123+
if (show_back_button) {
124+
quick_pick.buttons = [vscode.QuickInputButtons.Back]
125+
} else {
126+
quick_pick.buttons = [
127+
{
128+
iconPath: new vscode.ThemeIcon('close'),
129+
tooltip: 'Close'
130+
}
131+
]
120132
}
121133

122-
quick_pick.buttons = [close_button]
123134
quick_pick.items = create_items()
124135
quick_pick.title = 'Configurations'
125136
quick_pick.placeholder = 'Select configuration'
@@ -139,10 +150,13 @@ export const get_commit_message_config = async (
139150
}
140151

141152
commit_message_config = await new Promise<
142-
CommitMessageConfig | undefined
153+
CommitMessageConfig | 'back' | undefined
143154
>((resolve) => {
144155
quick_pick.onDidTriggerButton((button) => {
145-
if (button == close_button) {
156+
if (button === vscode.QuickInputButtons.Back) {
157+
quick_pick.hide()
158+
resolve('back')
159+
} else if (button.tooltip === 'Close') {
146160
quick_pick.hide()
147161
resolve(undefined)
148162
}
@@ -175,7 +189,7 @@ export const get_commit_message_config = async (
175189
quick_pick.onDidHide(() => {
176190
quick_pick.dispose()
177191
if (quick_pick.selectedItems.length == 0) {
178-
resolve(undefined)
192+
resolve('back')
179193
}
180194
})
181195

@@ -184,6 +198,10 @@ export const get_commit_message_config = async (
184198
}
185199
}
186200

201+
if (commit_message_config === 'back') {
202+
return 'back'
203+
}
204+
187205
if (!commit_message_config) {
188206
return null
189207
}

‎apps/editor/src/utils/git-repository-utils.ts‎

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as vscode from 'vscode'
22
import { execSync } from 'child_process'
33
import { dictionary } from '@shared/constants/dictionary'
44
import * as path from 'path'
5+
import { natural_sort } from './natural-sort'
56

67
type GitRepository = {
78
rootUri: vscode.Uri
@@ -111,10 +112,44 @@ export const prepare_staged_changes = async (
111112
}
112113
})
113114

114-
const selected = await vscode.window.showQuickPick(items, {
115-
canPickMany: true,
116-
title: 'Unstaged Files',
117-
placeHolder: 'Select files to commit'
115+
items.sort((a, b) => {
116+
const label_diff = natural_sort(a.label, b.label)
117+
if (label_diff != 0) return label_diff
118+
return natural_sort(a.description || '', b.description || '')
119+
})
120+
121+
const selected = await new Promise<any[] | undefined>((resolve) => {
122+
const quick_pick = vscode.window.createQuickPick<any>()
123+
quick_pick.items = items
124+
quick_pick.selectedItems = items
125+
quick_pick.canSelectMany = true
126+
quick_pick.title = 'Unstaged Files'
127+
quick_pick.placeholder = 'Select files to commit'
128+
quick_pick.buttons = [
129+
{
130+
iconPath: new vscode.ThemeIcon('close'),
131+
tooltip: 'Close'
132+
}
133+
]
134+
135+
quick_pick.onDidTriggerButton((button) => {
136+
if (button.tooltip == 'Close') {
137+
resolve(undefined)
138+
quick_pick.hide()
139+
}
140+
})
141+
142+
quick_pick.onDidAccept(() => {
143+
resolve(Array.from(quick_pick.selectedItems))
144+
quick_pick.hide()
145+
})
146+
147+
quick_pick.onDidHide(() => {
148+
resolve(undefined)
149+
quick_pick.dispose()
150+
})
151+
152+
quick_pick.show()
118153
})
119154

120155
if (!selected || selected.length == 0) {

0 commit comments

Comments
 (0)