Skip to content

Commit

Permalink
Implement a basic form of the diff/patch code block handling
Browse files Browse the repository at this point in the history
This is a special case as it needs to know the original file's path instead of just returning something so it is handler in the `processBlock` function itself.
  • Loading branch information
TomasHubelbauer committed Oct 28, 2024
1 parent 6892849 commit a2ae722
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 10 deletions.
1 change: 1 addition & 0 deletions demo/file-management/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
file-name-external.txt
file-name-internal.txt
file-name.txt
34 changes: 34 additions & 0 deletions demo/file-management/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ Hello, world! (Internal again)

The prefix to use here is `??`.

## Patch

When using the `diff` or `patch` language tags, special treatment will be used
and the content of the code block will be applied to the file by Git:

```txt ..file-name.txt
1
2
3
4
```

The file name is specified as the handler meta in this case!

```diff file-name.txt
@@ -1,4 +1,4 @@
-1
+100
2
-3
+300
4
```

We can check the operation worked with the match operation from before:

```txt ??file-name.txt
100
2
300
4
```

## Move, delete

Deleting and moving files is relegated to the shell handler, e.g.:
Expand Down
24 changes: 23 additions & 1 deletion processBlocks.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { $ } from 'bun';
import type { Block } from './Block';
import fs from 'fs';
import processStdoutBlock from './processStdoutBlock';
Expand Down Expand Up @@ -36,7 +37,7 @@ export default async function processBlocks(blocks: Block[]) {
throw new Error(`Duplicate handlers for the ${tag} language tag`);
}

if (!handlerWithMeta && !handlerWithoutMeta) {
if (!handlerWithMeta && !handlerWithoutMeta && block.tag !== 'diff' && block.tag !== 'patch') {
continue;
}

Expand All @@ -51,6 +52,27 @@ export default async function processBlocks(blocks: Block[]) {
continue;
}

// Bypass the handlers if the block mode is `diff` or `patch` and apply it
if (block.tag === 'diff' || block.tag === 'patch') {
if (!(await Bun.file(block.meta).exists())) {
console.error(`'${block.meta}' does not exist to patch changes to`);
}

const { stdout: stdoutBuffer, stderr: stderrBuffer } = await $`echo ${block.code} | patch ${block.meta}`.quiet();
const stdout = stdoutBuffer.toString();
const stderr = stderrBuffer.toString();

if (stdout !== `patching file ${block.meta}\n`) {
console.error(stdout);
}

if (stderr) {
console.error(stderr);
}

continue;
}

try {
// See https://github.com/oven-sh/bun/issues/14874 for a better option
const originalConsoleLog = console.log;
Expand Down
23 changes: 14 additions & 9 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,15 +167,20 @@ do in `processBlocks` and compare the expected output with the real output.

In file management demos, also check the files on disk and clean up after.

### Consider how to implement the `patch` and `diff` language tags

The `patch` and `diff` language tags might need special treatment as handlers do
not have access to the file content so these will need to work on the file
management level not like normal handlers probably.

See the `MarkRight` file in the Node-based implementation I replaced to see how
it used to work, but for the Bun-based implementation, probably just call out to
Git to apply the changes.
### Find a way to allow `diff`/`patch` code blocks to not have hunk context line

The `@@` line.
The `patch` utility seems to require these, it will not try to match and patch
loosely.
The `git apply` command has `--unidiff-zero` which seems to allow not providing
the context lines but it was giving me trouble probably because the file I am
trying to apply to is not necessarily tracked by Git?

If there is no way to get rid of these, maybe I could generate the hunk context
by assuming the changes are for the whole file?
This would massively lessen the utility of this code block though.
Maybe there is a path where I derive the start and end lines and only require
that the diff/patch code is a single hunk maybe?

### Consider allowing to specify what shell to use in the shell handler

Expand Down

0 comments on commit a2ae722

Please sign in to comment.