Skip to content

Commit a92721a

Browse files
committed
feat: add file viewer and fix file picker bugs in windows
1 parent 5ff27b8 commit a92721a

7 files changed

Lines changed: 551 additions & 54 deletions

File tree

lib/models/diff_result.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
class DiffResult {
2+
final String diffText;
3+
final String? baseCommitTime;
4+
final String? newCommitTime;
5+
final bool isNewFile;
6+
final bool isBinary;
7+
8+
DiffResult({
9+
required this.diffText,
10+
this.baseCommitTime,
11+
this.newCommitTime,
12+
this.isNewFile = false,
13+
this.isBinary = false,
14+
});
15+
}

lib/models/git_commit.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ class GitCommit {
1414
});
1515

1616
/// Parses a line from `git log` with format:
17-
/// `%H||%h||%s||%an||%aI`
17+
/// `%H%x1F%h%x1F%s%x1F%an%x1F%aI`
1818
factory GitCommit.fromLogLine(String line) {
19-
final parts = line.split('||');
19+
final parts = line.split('\x1F');
2020
if (parts.length < 5) {
2121
throw FormatException('Invalid git log line: $line');
2222
}

lib/services/git_service.dart

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:io';
22
import '../models/git_commit.dart';
33
import '../models/changed_file.dart';
4+
import '../models/diff_result.dart';
45

56
class GitService {
67
/// Check if the given path is a valid Git repository.
@@ -16,7 +17,7 @@ class GitService {
1617
}) async {
1718
final result = await Process.run('git', [
1819
'log',
19-
'--format=%H||%h||%s||%an||%aI',
20+
'--format=%H%x1F%h%x1F%s%x1F%an%x1F%aI',
2021
'-n',
2122
'$limit',
2223
], workingDirectory: projectPath);
@@ -73,4 +74,67 @@ class GitService {
7374
return allFiles.map((path) => ChangedFile(relativePath: path)).toList()
7475
..sort((a, b) => a.relativePath.compareTo(b.relativePath));
7576
}
77+
78+
/// Get the raw unified diff for a file between its base and new state.
79+
Future<DiffResult> getFileDiff(
80+
String projectPath,
81+
String filePath,
82+
String oldestCommit,
83+
String newestCommit,
84+
) async {
85+
// get parent of oldest commit
86+
String? baseCommit;
87+
final parentResult = await Process.run('git', [
88+
'log', '-1', '--format=%P', oldestCommit
89+
], workingDirectory: projectPath);
90+
91+
if (parentResult.exitCode == 0) {
92+
final parents = (parentResult.stdout as String).trim().split(' ');
93+
if (parents.isNotEmpty && parents.first.isNotEmpty) {
94+
baseCommit = parents.first;
95+
}
96+
}
97+
98+
String? baseTime;
99+
if (baseCommit != null) {
100+
final timeRes = await Process.run('git', [
101+
'log', '-1', '--format=%aI', baseCommit
102+
], workingDirectory: projectPath);
103+
if (timeRes.exitCode == 0) {
104+
baseTime = (timeRes.stdout as String).trim();
105+
}
106+
}
107+
108+
String? newTime;
109+
final newTimeRes = await Process.run('git', [
110+
'log', '-1', '--format=%aI', newestCommit
111+
], workingDirectory: projectPath);
112+
if (newTimeRes.exitCode == 0) {
113+
newTime = (newTimeRes.stdout as String).trim();
114+
}
115+
116+
final diffArgs = [
117+
'diff',
118+
if (baseCommit != null)
119+
'$baseCommit..$newestCommit'
120+
else
121+
'4b825dc642cb6eb9a060e54bf8d69288fbee4904..$newestCommit',
122+
'--',
123+
filePath
124+
];
125+
126+
final diffRes = await Process.run('git', diffArgs, workingDirectory: projectPath);
127+
final diffText = diffRes.stdout as String;
128+
129+
bool isNewFile = baseCommit == null || diffText.contains('new file mode ');
130+
bool isBinary = diffText.contains('Binary files ') && diffText.contains(' differ');
131+
132+
return DiffResult(
133+
diffText: diffText,
134+
baseCommitTime: baseTime,
135+
newCommitTime: newTime,
136+
isNewFile: isNewFile,
137+
isBinary: isBinary,
138+
);
139+
}
76140
}

0 commit comments

Comments
 (0)