summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorLuke Parker <[email protected]>2025-11-16 13:18:39 +1000
committerGitHub <[email protected]>2025-11-15 21:18:39 -0600
commit35fbb011b2ec24eb81be385d860e98c7a15043cf (patch)
tree3f178c658509b4bf78275a36a07083cd7d256dfd
parent6527a123f0375eae6e141901195707df88f28411 (diff)
downloadopencode-35fbb011b2ec24eb81be385d860e98c7a15043cf.tar.gz
opencode-35fbb011b2ec24eb81be385d860e98c7a15043cf.zip
fix: Diff view now ignores line endings changes/windows autocrlf (#4356)
-rw-r--r--packages/opencode/src/cli/cmd/tui/context/theme.tsx3
-rw-r--r--packages/opencode/src/snapshot/index.ts32
-rw-r--r--packages/opencode/src/tool/edit.ts12
3 files changed, 34 insertions, 13 deletions
diff --git a/packages/opencode/src/cli/cmd/tui/context/theme.tsx b/packages/opencode/src/cli/cmd/tui/context/theme.tsx
index 2a79620e6..26a3f7950 100644
--- a/packages/opencode/src/cli/cmd/tui/context/theme.tsx
+++ b/packages/opencode/src/cli/cmd/tui/context/theme.tsx
@@ -864,18 +864,21 @@ function generateSyntax(theme: Theme) {
scope: ["diff.plus"],
style: {
foreground: theme.diffAdded,
+ background: theme.diffAddedBg,
},
},
{
scope: ["diff.minus"],
style: {
foreground: theme.diffRemoved,
+ background: theme.diffRemovedBg,
},
},
{
scope: ["diff.delta"],
style: {
foreground: theme.diffContext,
+ background: theme.diffContextBg,
},
},
{
diff --git a/packages/opencode/src/snapshot/index.ts b/packages/opencode/src/snapshot/index.ts
index e8500e09d..c71a1b676 100644
--- a/packages/opencode/src/snapshot/index.ts
+++ b/packages/opencode/src/snapshot/index.ts
@@ -24,6 +24,8 @@ export namespace Snapshot {
})
.quiet()
.nothrow()
+ // Configure git to not convert line endings on Windows
+ await $`git --git-dir ${git} config core.autocrlf false`.quiet().nothrow()
log.info("initialized")
}
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
@@ -45,10 +47,11 @@ export namespace Snapshot {
export async function patch(hash: string): Promise<Patch> {
const git = gitdir()
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
- const result = await $`git --git-dir ${git} --work-tree ${Instance.worktree} diff --name-only ${hash} -- .`
- .quiet()
- .cwd(Instance.directory)
- .nothrow()
+ const result =
+ await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} diff --name-only ${hash} -- .`
+ .quiet()
+ .cwd(Instance.directory)
+ .nothrow()
// If git diff fails, return empty patch
if (result.exitCode !== 0) {
@@ -122,10 +125,11 @@ export namespace Snapshot {
export async function diff(hash: string) {
const git = gitdir()
await $`git --git-dir ${git} --work-tree ${Instance.worktree} add .`.quiet().cwd(Instance.directory).nothrow()
- const result = await $`git --git-dir ${git} --work-tree ${Instance.worktree} diff ${hash} -- .`
- .quiet()
- .cwd(Instance.worktree)
- .nothrow()
+ const result =
+ await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} diff ${hash} -- .`
+ .quiet()
+ .cwd(Instance.worktree)
+ .nothrow()
if (result.exitCode !== 0) {
log.warn("failed to get diff", {
@@ -155,7 +159,7 @@ export namespace Snapshot {
export async function diffFull(from: string, to: string): Promise<FileDiff[]> {
const git = gitdir()
const result: FileDiff[] = []
- for await (const line of $`git --git-dir ${git} --work-tree ${Instance.worktree} diff --no-renames --numstat ${from} ${to} -- .`
+ for await (const line of $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} diff --no-renames --numstat ${from} ${to} -- .`
.quiet()
.cwd(Instance.directory)
.nothrow()
@@ -165,10 +169,16 @@ export namespace Snapshot {
const isBinaryFile = additions === "-" && deletions === "-"
const before = isBinaryFile
? ""
- : await $`git --git-dir ${git} --work-tree ${Instance.worktree} show ${from}:${file}`.quiet().nothrow().text()
+ : await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} show ${from}:${file}`
+ .quiet()
+ .nothrow()
+ .text()
const after = isBinaryFile
? ""
- : await $`git --git-dir ${git} --work-tree ${Instance.worktree} show ${to}:${file}`.quiet().nothrow().text()
+ : await $`git -c core.autocrlf=false --git-dir ${git} --work-tree ${Instance.worktree} show ${to}:${file}`
+ .quiet()
+ .nothrow()
+ .text()
result.push({
file,
before,
diff --git a/packages/opencode/src/tool/edit.ts b/packages/opencode/src/tool/edit.ts
index 96c62b86a..ca9859370 100644
--- a/packages/opencode/src/tool/edit.ts
+++ b/packages/opencode/src/tool/edit.ts
@@ -18,6 +18,10 @@ import { Instance } from "../project/instance"
import { Agent } from "../agent/agent"
import { Snapshot } from "@/snapshot"
+function normalizeLineEndings(text: string): string {
+ return text.replaceAll("\r\n", "\n")
+}
+
export const EditTool = Tool.define("edit", {
description: DESCRIPTION,
parameters: z.object({
@@ -91,7 +95,9 @@ export const EditTool = Tool.define("edit", {
contentOld = await file.text()
contentNew = replace(contentOld, params.oldString, params.newString, params.replaceAll)
- diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
+ diff = trimDiff(
+ createTwoFilesPatch(filePath, filePath, normalizeLineEndings(contentOld), normalizeLineEndings(contentNew)),
+ )
if (agent.permission.edit === "ask") {
await Permission.ask({
type: "edit",
@@ -111,7 +117,9 @@ export const EditTool = Tool.define("edit", {
file: filePath,
})
contentNew = await file.text()
- diff = trimDiff(createTwoFilesPatch(filePath, filePath, contentOld, contentNew))
+ diff = trimDiff(
+ createTwoFilesPatch(filePath, filePath, normalizeLineEndings(contentOld), normalizeLineEndings(contentNew)),
+ )
})()
FileTime.read(ctx.sessionID, filePath)