Skip to content

Commit 1ecd334

Browse files
committed
Optimize commit message generation and staging by parallelizing file processing and using asynchronous git commands
1 parent c6ba0d4 commit 1ecd334

2 files changed

Lines changed: 220 additions & 162 deletions

File tree

‎apps/editor/src/commands/generate-commit-message-commands/utils/build-commit-message-prompt.ts‎

Lines changed: 168 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -32,71 +32,161 @@ export const build_commit_message_prompt = async (
3232
let changes_content = ''
3333
let context_content = ''
3434

35-
for (const file_diff_content of file_diffs) {
36-
const full_file_diff = 'diff --git ' + file_diff_content
37-
const lines = full_file_diff.split('\n')
38-
const old_path_line = lines.find((l) => l.startsWith('--- a/'))
39-
const new_path_line = lines.find((l) => l.startsWith('+++ b/'))
40-
const rename_from_line = lines.find((l) => l.startsWith('rename from '))
41-
42-
const old_path = old_path_line
43-
? old_path_line.substring('--- a/'.length)
44-
: undefined
45-
const new_path = new_path_line
46-
? new_path_line.substring('+++ b/'.length)
47-
: undefined
48-
49-
let final_diff_content = full_file_diff
50-
let file_path: string | undefined
51-
let is_deleted = false
52-
const is_binary = lines.some((l) => l.startsWith('Binary files '))
53-
54-
if (new_path && new_path !== '/dev/null') {
55-
file_path = new_path
56-
} else if (old_path && old_path !== '/dev/null') {
57-
file_path = old_path
58-
is_deleted = true
59-
// Shorten diff of a deleted file
60-
const split_diff = full_file_diff.split('+++ /dev/null')
61-
final_diff_content = split_diff[0] + '+++ /dev/null'
62-
} else {
63-
// Fallback: try to identify file from diff header (e.g. binary files)
64-
// diff --git a/path b/path
65-
const diff_header = lines[0]
66-
const match = diff_header.match(/^diff --git a\/(.*) b\/(.*)$/)
67-
if (match) {
68-
file_path = match[2]
69-
}
70-
}
71-
72-
if (file_path) {
73-
let status: 'created' | 'deleted' | 'renamed' | 'updated' = 'updated'
74-
75-
if (is_deleted) {
76-
status = 'deleted'
77-
} else if (!old_path && new_path) {
78-
status = 'created'
79-
} else if (rename_from_line) {
80-
status = 'renamed'
81-
} else if (lines.some((l) => l.startsWith('new file mode'))) {
82-
status = 'created'
83-
} else if (lines.some((l) => l.startsWith('deleted file mode'))) {
84-
status = 'deleted'
35+
const diff_results = await Promise.all(
36+
file_diffs.map(async (file_diff_content) => {
37+
let changes_content_part = ''
38+
let context_content_part = ''
39+
40+
const full_file_diff = 'diff --git ' + file_diff_content
41+
const lines = full_file_diff.split('\n')
42+
const old_path_line = lines.find((l) => l.startsWith('--- a/'))
43+
const new_path_line = lines.find((l) => l.startsWith('+++ b/'))
44+
const rename_from_line = lines.find((l) => l.startsWith('rename from '))
45+
46+
const old_path = old_path_line
47+
? old_path_line.substring('--- a/'.length)
48+
: undefined
49+
const new_path = new_path_line
50+
? new_path_line.substring('+++ b/'.length)
51+
: undefined
52+
53+
let final_diff_content = full_file_diff
54+
let file_path: string | undefined
55+
let is_deleted = false
56+
const is_binary = lines.some((l) => l.startsWith('Binary files '))
57+
58+
if (new_path && new_path !== '/dev/null') {
59+
file_path = new_path
60+
} else if (old_path && old_path !== '/dev/null') {
61+
file_path = old_path
8562
is_deleted = true
63+
const split_diff = full_file_diff.split('+++ /dev/null')
64+
final_diff_content = split_diff[0] + '+++ /dev/null'
65+
} else {
66+
const diff_header = lines[0]
67+
const match = diff_header.match(/^diff --git a\/(.*) b\/(.*)$/)
68+
if (match) {
69+
file_path = match[2]
70+
}
8671
}
8772

88-
let old_path_attr: string | undefined
89-
if (status === 'renamed') {
90-
if (rename_from_line) {
91-
old_path_attr = rename_from_line
92-
.substring('rename from '.length)
93-
.trim()
73+
if (file_path) {
74+
let status: 'created' | 'deleted' | 'renamed' | 'updated' = 'updated'
75+
76+
if (is_deleted) {
77+
status = 'deleted'
78+
} else if (!old_path && new_path) {
79+
status = 'created'
80+
} else if (rename_from_line) {
81+
status = 'renamed'
82+
} else if (lines.some((l) => l.startsWith('new file mode'))) {
83+
status = 'created'
84+
} else if (lines.some((l) => l.startsWith('deleted file mode'))) {
85+
status = 'deleted'
86+
is_deleted = true
87+
}
88+
89+
let old_path_attr: string | undefined
90+
if (status === 'renamed') {
91+
if (rename_from_line) {
92+
old_path_attr = rename_from_line
93+
.substring('rename from '.length)
94+
.trim()
95+
}
96+
}
97+
98+
let is_ignored = false
99+
100+
if (file_path && workspace_provider) {
101+
const absolute_path = vscode.Uri.joinPath(
102+
repository.rootUri,
103+
file_path
104+
).fsPath
105+
if (
106+
workspace_provider.is_ignored_by_patterns(absolute_path) ||
107+
workspace_provider.is_excluded(file_path)
108+
) {
109+
is_ignored = true
110+
}
111+
}
112+
113+
if (is_binary) {
114+
if (status === 'created')
115+
final_diff_content = DIFF_PLACEHOLDERS.BINARY_FILE_CREATED
116+
else if (status === 'deleted')
117+
final_diff_content = DIFF_PLACEHOLDERS.BINARY_FILE_DELETED
118+
else final_diff_content = DIFF_PLACEHOLDERS.BINARY_FILE_MODIFIED
119+
} else if (is_ignored) {
120+
if (status === 'created')
121+
final_diff_content = DIFF_PLACEHOLDERS.FILE_CREATED
122+
else if (status === 'deleted')
123+
final_diff_content = DIFF_PLACEHOLDERS.FILE_DELETED
124+
else if (status === 'renamed')
125+
final_diff_content = DIFF_PLACEHOLDERS.FILE_RENAMED
126+
else final_diff_content = DIFF_PLACEHOLDERS.FILE_MODIFIED
127+
} else {
128+
const hunk_start_index = final_diff_content.indexOf('\n@@ ')
129+
if (hunk_start_index !== -1) {
130+
final_diff_content = final_diff_content.substring(
131+
hunk_start_index + 1
132+
)
133+
} else if (!final_diff_content.startsWith('@@ ')) {
134+
final_diff_content = ''
135+
}
136+
}
137+
138+
const should_include_full_content = !is_ignored
139+
140+
if (
141+
!is_deleted &&
142+
file_path &&
143+
!is_binary &&
144+
should_include_full_content
145+
) {
146+
try {
147+
let full_content = ''
148+
try {
149+
full_content = await repository.show('', file_path)
150+
} catch (e) {
151+
const uri = vscode.Uri.joinPath(repository.rootUri, file_path)
152+
const content = await vscode.workspace.fs.readFile(uri)
153+
if (!content.includes(0)) {
154+
full_content = Buffer.from(content).toString('utf8')
155+
}
156+
}
157+
if (full_content && !full_content.includes('\0')) {
158+
const full_content_tokens = Math.ceil(full_content.length / 4)
159+
if (full_content_tokens <= MAX_FILE_TOKENS_FOR_COMMIT_MESSAGE) {
160+
context_content_part = PromptBuilder.build_file_context({
161+
filepath: file_path,
162+
content: full_content,
163+
is_binary: false
164+
})
165+
}
166+
}
167+
} catch (err) {}
94168
}
169+
170+
changes_content_part = PromptBuilder.build_diff_file_context({
171+
status,
172+
filepath: file_path,
173+
old_filepath: old_path_attr,
174+
diff_content: final_diff_content
175+
})
95176
}
96177

97-
let is_ignored = false
178+
return { changes_content_part, context_content_part }
179+
})
180+
)
98181

99-
if (file_path && workspace_provider) {
182+
for (const res of diff_results) {
183+
if (res.context_content_part) context_content += res.context_content_part
184+
if (res.changes_content_part) changes_content += res.changes_content_part
185+
}
186+
187+
const context_results = await Promise.all(
188+
context_files.map(async (file_path) => {
189+
if (workspace_provider) {
100190
const absolute_path = vscode.Uri.joinPath(
101191
repository.rootUri,
102192
file_path
@@ -105,105 +195,32 @@ export const build_commit_message_prompt = async (
105195
workspace_provider.is_ignored_by_patterns(absolute_path) ||
106196
workspace_provider.is_excluded(file_path)
107197
) {
108-
is_ignored = true
109-
}
110-
}
111-
112-
if (is_binary) {
113-
if (status === 'created')
114-
final_diff_content = DIFF_PLACEHOLDERS.BINARY_FILE_CREATED
115-
else if (status === 'deleted')
116-
final_diff_content = DIFF_PLACEHOLDERS.BINARY_FILE_DELETED
117-
else final_diff_content = DIFF_PLACEHOLDERS.BINARY_FILE_MODIFIED
118-
} else if (is_ignored) {
119-
if (status === 'created')
120-
final_diff_content = DIFF_PLACEHOLDERS.FILE_CREATED
121-
else if (status === 'deleted')
122-
final_diff_content = DIFF_PLACEHOLDERS.FILE_DELETED
123-
else if (status === 'renamed')
124-
final_diff_content = DIFF_PLACEHOLDERS.FILE_RENAMED
125-
else final_diff_content = DIFF_PLACEHOLDERS.FILE_MODIFIED
126-
} else {
127-
const hunk_start_index = final_diff_content.indexOf('\n@@ ')
128-
if (hunk_start_index !== -1) {
129-
final_diff_content = final_diff_content.substring(
130-
hunk_start_index + 1
131-
)
132-
} else if (!final_diff_content.startsWith('@@ ')) {
133-
final_diff_content = ''
198+
return ''
134199
}
135200
}
136201

137-
const should_include_full_content = !is_ignored
138-
139-
if (
140-
!is_deleted &&
141-
file_path &&
142-
!is_binary &&
143-
should_include_full_content
144-
) {
145-
try {
146-
let full_content = ''
147-
try {
148-
full_content = await repository.show('', file_path)
149-
} catch (e) {
150-
const uri = vscode.Uri.joinPath(repository.rootUri, file_path)
151-
const content = await vscode.workspace.fs.readFile(uri)
152-
if (!content.includes(0)) {
153-
full_content = Buffer.from(content).toString('utf8')
154-
}
155-
}
156-
if (full_content && !full_content.includes('\0')) {
157-
const full_content_tokens = Math.ceil(full_content.length / 4)
158-
if (full_content_tokens <= MAX_FILE_TOKENS_FOR_COMMIT_MESSAGE) {
159-
context_content += PromptBuilder.build_file_context({
160-
filepath: file_path,
161-
content: full_content,
162-
is_binary: false
163-
})
164-
}
202+
try {
203+
const uri = vscode.Uri.joinPath(repository.rootUri, file_path)
204+
const content_uint8 = await vscode.workspace.fs.readFile(uri)
205+
if (!content_uint8.includes(0)) {
206+
const full_content = Buffer.from(content_uint8).toString('utf8')
207+
const full_content_tokens = Math.ceil(full_content.length / 4)
208+
if (full_content_tokens <= MAX_FILE_TOKENS_FOR_COMMIT_MESSAGE) {
209+
return PromptBuilder.build_file_context({
210+
filepath: file_path,
211+
content: full_content,
212+
is_binary: false
213+
})
165214
}
166-
} catch (err) {}
167-
}
215+
}
216+
} catch (err) {}
168217

169-
changes_content += PromptBuilder.build_diff_file_context({
170-
status,
171-
filepath: file_path,
172-
old_filepath: old_path_attr,
173-
diff_content: final_diff_content
174-
})
175-
}
176-
}
218+
return ''
219+
})
220+
)
177221

178-
for (const file_path of context_files) {
179-
if (workspace_provider) {
180-
const absolute_path = vscode.Uri.joinPath(
181-
repository.rootUri,
182-
file_path
183-
).fsPath
184-
if (
185-
workspace_provider.is_ignored_by_patterns(absolute_path) ||
186-
workspace_provider.is_excluded(file_path)
187-
) {
188-
continue
189-
}
190-
}
191-
192-
try {
193-
const uri = vscode.Uri.joinPath(repository.rootUri, file_path)
194-
const content_uint8 = await vscode.workspace.fs.readFile(uri)
195-
if (!content_uint8.includes(0)) {
196-
const full_content = Buffer.from(content_uint8).toString('utf8')
197-
const full_content_tokens = Math.ceil(full_content.length / 4)
198-
if (full_content_tokens <= MAX_FILE_TOKENS_FOR_COMMIT_MESSAGE) {
199-
context_content += PromptBuilder.build_file_context({
200-
filepath: file_path,
201-
content: full_content,
202-
is_binary: false
203-
})
204-
}
205-
}
206-
} catch (err) {}
222+
for (const res of context_results) {
223+
if (res) context_content += res
207224
}
208225

209226
let prompt_sections = ''

0 commit comments

Comments
 (0)