Skip to content

Commit 0e5a456

Browse files
committed
Merge branch 'release/v2026.16'
2 parents 7149a8d + 1ff1a4b commit 0e5a456

79 files changed

Lines changed: 1042 additions & 726 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

TRANSLATION.md

Lines changed: 82 additions & 188 deletions
Large diffs are not rendered by default.

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2026.15
1+
2026.16

build/resources/app/App.plist

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,21 @@
2020
<string>APPL</string>
2121
<key>CFBundleShortVersionString</key>
2222
<string>SOURCE_GIT_VERSION</string>
23+
<key>CFBundleDocumentTypes</key>
24+
<array>
25+
<dict>
26+
<key>CFBundleTypeName</key>
27+
<string>Supported Folder</string>
28+
<key>CFBundleTypeRole</key>
29+
<string>Viewer</string>
30+
<key>LSHandlerRank</key>
31+
<string>Alternate</string>
32+
<key>LSItemContentTypes</key>
33+
<array>
34+
<string>public.folder</string>
35+
</array>
36+
</dict>
37+
</array>
2338
<key>NSHighResolutionCapable</key>
2439
<true/>
2540
</dict>

src/AI/Agent.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public Agent(Service service)
1414
_service = service;
1515
}
1616

17-
public async Task GenerateCommitMessageAsync(string repo, string changeList, Action<string> onUpdate, CancellationToken cancellation)
17+
public async Task GenerateCommitMessageAsync(string repo, string currentBranch, string changeList, string amendParent, Action<string> onUpdate, CancellationToken cancellation)
1818
{
1919
var chatClient = _service.GetChatClient();
2020
if (chatClient == null)
@@ -28,6 +28,7 @@ public async Task GenerateCommitMessageAsync(string repo, string changeList, Act
2828
.AppendLine("- Output the conventional commit message (with detail changes in list) directly. Do not explain your output nor introduce your answer.")
2929
.AppendLine(_service.AdditionalPrompt)
3030
.Append("Repository path: ").AppendLine(repo.Quoted())
31+
.Append("Current branch: ").AppendLine(currentBranch.Quoted())
3132
.AppendLine("Changed files ('A' means added, 'M' means modified, 'D' means deleted, 'T' means type changed, 'R' means renamed, 'C' means copied): ")
3233
.Append(changeList);
3334

@@ -94,7 +95,7 @@ public async Task GenerateCommitMessageAsync(string repo, string changeList, Act
9495

9596
foreach (var call in completion.ToolCalls)
9697
{
97-
var result = await ChatTools.ProcessAsync(call, onUpdate);
98+
var result = await ChatTools.ProcessAsync(call, repo, amendParent, onUpdate);
9899
messages.Add(result);
99100
}
100101

src/AI/ChatTools.cs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ public static class ChatTools
1515
{
1616
"type": "object",
1717
"properties": {
18-
"repo": {
19-
"type": "string",
20-
"description": "The path to the repository."
21-
},
2218
"file": {
2319
"type": "string",
2420
"description": "The path to the file."
@@ -28,28 +24,25 @@ public static class ChatTools
2824
"description": "The path to the original file when it has been renamed or copied."
2925
}
3026
},
31-
"required": ["repo", "file"]
27+
"required": ["file"]
3228
}
3329
""")), false);
3430

35-
public static async Task<ToolChatMessage> ProcessAsync(ChatToolCall call, Action<string> output)
31+
public static async Task<ToolChatMessage> ProcessAsync(ChatToolCall call, string repo, string amendParent, Action<string> output)
3632
{
3733
using var doc = JsonDocument.Parse(call.FunctionArguments);
3834

3935
if (call.FunctionName.Equals(GetDetailChangesInFile.FunctionName))
4036
{
41-
var hasRepo = doc.RootElement.TryGetProperty("repo", out var repoPath);
4237
var hasFile = doc.RootElement.TryGetProperty("file", out var filePath);
4338
var hasOriginalFile = doc.RootElement.TryGetProperty("originalFile", out var originalFilePath);
44-
if (!hasRepo)
45-
throw new ArgumentException("repo", "The repo argument is required");
4639
if (!hasFile)
4740
throw new ArgumentException("file", "The file argument is required");
4841

4942
output?.Invoke($"Read changes in file: {filePath.GetString()}");
5043

5144
var orgFilePath = hasOriginalFile ? originalFilePath.GetString() : string.Empty;
52-
var rs = await new Commands.GetFileChangeForAI(repoPath.GetString(), filePath.GetString(), orgFilePath).ReadAsync();
45+
var rs = await new Commands.GetFileChangeForAI(repo, filePath.GetString(), orgFilePath, amendParent).ReadAsync();
5346
var message = rs.IsSuccess ? rs.StdOut : string.Empty;
5447
return new ToolChatMessage(call.Id, message);
5548
}

src/App.Extensions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.IO;
44
using System.Text;
5+
using System.Threading;
56
using Avalonia.Media;
67

78
namespace SourceGit
@@ -79,6 +80,12 @@ public static T Use<T>(this T cmd, Models.ICommandLog log) where T : Commands.Co
7980
cmd.Log = log;
8081
return cmd;
8182
}
83+
84+
public static T WithCancellation<T>(this T cmd, CancellationToken token) where T : Commands.Command
85+
{
86+
cmd.CancellationToken = token;
87+
return cmd;
88+
}
8289
}
8390

8491
public static class DirectoryInfoExtension

src/App.axaml.cs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Avalonia.Markup.Xaml;
1212
using Avalonia.Media;
1313
using Avalonia.Media.Fonts;
14+
using Avalonia.Platform;
1415
using Avalonia.Styling;
1516
using Avalonia.Threading;
1617

@@ -101,8 +102,11 @@ public static async Task<bool> AskConfirmAsync(string message, Models.ConfirmBut
101102

102103
public static void SetLocale(string localeKey)
103104
{
105+
var locale = Models.Locale.Supported.Find(x => x.Key.Equals(localeKey, StringComparison.OrdinalIgnoreCase));
106+
var finalLocaleKey = locale?.Key ?? "en_US";
107+
104108
if (Current is not App app ||
105-
app.Resources[localeKey] is not ResourceDictionary targetLocale ||
109+
app.Resources[finalLocaleKey] is not ResourceDictionary targetLocale ||
106110
targetLocale == app._activeLocale)
107111
return;
108112

@@ -472,6 +476,15 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
472476
Native.OS.SetupExternalTools();
473477
Models.AvatarManager.Instance.Start();
474478

479+
if (this.TryGetFeature<IActivatableLifetime>() is { } activatable)
480+
{
481+
activatable.Activated += (_, e) =>
482+
{
483+
if (e is FileActivatedEventArgs { Files: { Count: > 0 } } fileArgs)
484+
_launcher?.TryOpenRepositoryFromPath(fileArgs.Files[0].Path.LocalPath);
485+
};
486+
}
487+
475488
string startupRepo = null;
476489
if (desktop.Args is { Length: 1 })
477490
{
@@ -524,6 +537,9 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
524537
#region Check for Updates
525538
private void Check4Update(bool manually = false)
526539
{
540+
if (_launcher != null)
541+
_launcher.NewVersion = null;
542+
527543
Task.Run(async () =>
528544
{
529545
try
@@ -537,23 +553,20 @@ private void Check4Update(bool manually = false)
537553
if (ver == null)
538554
return;
539555

540-
// Check if already up-to-date.
541-
if (!ver.IsNewVersion)
556+
if (manually)
542557
{
543-
if (manually)
558+
if (ver.IsNewVersion)
559+
ShowSelfUpdateResult(ver);
560+
else
544561
ShowSelfUpdateResult(new Models.AlreadyUpToDate());
545-
return;
546562
}
547-
548-
// Should not check ignored tag if this is called manually.
549-
if (!manually)
563+
else if (_launcher != null)
550564
{
551-
var pref = ViewModels.Preferences.Instance;
552-
if (ver.TagName == pref.IgnoreUpdateTag)
565+
if (!ver.IsNewVersion || ver.TagName == ViewModels.Preferences.Instance.IgnoreUpdateTag)
553566
return;
554-
}
555567

556-
ShowSelfUpdateResult(ver);
568+
_launcher.NewVersion = ver;
569+
}
557570
}
558571
catch (Exception e)
559572
{

src/Commands/Branch.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ public async Task<bool> DeleteLocalAsync(bool force)
4848
return await ExecAsync().ConfigureAwait(false);
4949
}
5050

51-
public async Task<bool> DeleteRemoteAsync(string remote)
51+
public async Task<bool> DeleteRemoteAsync(string remote, bool force)
5252
{
53-
Args = $"branch -D -r {remote}/{_name}";
53+
Args = $"branch {(force ? "-D" : "-d")} -r {remote}/{_name}";
5454
return await ExecAsync().ConfigureAwait(false);
5555
}
5656

src/Commands/Command.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public async Task<bool> ExecAsync()
6262
lock (capturedLock)
6363
{
6464
if (captured is { Process: { HasExited: false } })
65-
captured.Process.Kill();
65+
captured.Process.Kill(true);
6666
}
6767
});
6868
}

src/Commands/Diff.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,20 +144,23 @@ private void ParseLine(ArraySegment<byte> lineBytes)
144144
if (line.Length == 0)
145145
return;
146146

147-
// If we are reading a chunk body, try to read the current line as body first (because
148-
// the number of chunk body is greater than the number of chunk indicator in most time.
147+
// If we are reading a chunk-body, try to read the current line as chunk-body first (because
148+
// there are usually more chunk-body lines than chunk-indicator lines).
149149
if (_isInChunk)
150150
{
151-
if (ParseChunkBodyLine(line, lineBytes[1..]))
151+
if (ParseChunkBodyLine(line, lineBytes))
152152
return;
153153

154154
ProcessInlineHighlights();
155155
_isInChunk = false;
156156
}
157157

158-
// If the current line is not a chunk body, try to parse it as chunk indicator
158+
// If the current line is not a chunk-body, try to parse it as chunk-indicator
159159
if (ParseChunkStartLine(line))
160+
{
161+
_isInChunk = true;
160162
return;
163+
}
161164

162165
// Fallback to diff headers to support type-changed diff (multiple headers).
163166
ParseDiffHeaderLine(line);
@@ -193,7 +196,6 @@ private bool ParseChunkStartLine(string line)
193196
_newLine = int.Parse(match.Groups[2].Value);
194197
_last = new Models.TextDiffLine(Models.TextDiffLineType.Indicator, line, null, 0, 0);
195198
_result.TextDiff.Lines.Add(_last);
196-
_isInChunk = true;
197199
return true;
198200
}
199201

@@ -204,13 +206,14 @@ private bool ParseChunkBodyLine(string line, ArraySegment<byte> lineBytes)
204206
{
205207
var prefix = line[0];
206208
var content = line.Substring(1);
209+
var rawContent = lineBytes[1..].ToArray();
207210
if (ParseLFSChange(prefix, content))
208211
return true;
209212

210213
if (prefix == PREFIX_DELETED)
211214
{
212215
_result.TextDiff.DeletedLines++;
213-
_last = new Models.TextDiffLine(Models.TextDiffLineType.Deleted, content, lineBytes.ToArray(), _oldLine, 0);
216+
_last = new Models.TextDiffLine(Models.TextDiffLineType.Deleted, content, rawContent, _oldLine, 0);
214217
_deleted.Add(_last);
215218
_oldLine++;
216219
return true;
@@ -219,7 +222,7 @@ private bool ParseChunkBodyLine(string line, ArraySegment<byte> lineBytes)
219222
if (prefix == PREFIX_ADDED)
220223
{
221224
_result.TextDiff.AddedLines++;
222-
_last = new Models.TextDiffLine(Models.TextDiffLineType.Added, content, lineBytes.ToArray(), 0, _newLine);
225+
_last = new Models.TextDiffLine(Models.TextDiffLineType.Added, content, rawContent, 0, _newLine);
223226
_added.Add(_last);
224227
_newLine++;
225228
return true;
@@ -229,7 +232,7 @@ private bool ParseChunkBodyLine(string line, ArraySegment<byte> lineBytes)
229232
{
230233
ProcessInlineHighlights();
231234

232-
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, content, lineBytes.ToArray(), _oldLine, _newLine);
235+
_last = new Models.TextDiffLine(Models.TextDiffLineType.Normal, content, rawContent, _oldLine, _newLine);
233236
_result.TextDiff.Lines.Add(_last);
234237
_oldLine++;
235238
_newLine++;

0 commit comments

Comments
 (0)