patcher 0.2.1

patcher is a Rust library for generating and applying Git-style unified diff patches.
Documentation
# Chapter 4: Operation

In the [previous chapter](03_chunk_.md), we learned about [Chunk](03_chunk_.md)s – the specific steps within our [Patch](02_patch_.md) recipe that group changes happening in one area of a file. But what are the actual, individual actions performed within each step? That's where the `Operation` comes in!

## What is an Operation? The Single Instruction

Let's go back to our recipe analogy. A [Patch](02_patch_.md) is the overall recipe, and a [Chunk](03_chunk_.md) is a specific step like "Step 1: Adjust the dry ingredients". An `Operation` is the *most basic instruction* within that step. It's the smallest unit of change.

Think of these single instructions:

*   `+ Add 1 tsp vanilla extract`
*   `- Remove the salt`
*   `  Keep 2 cups of flour (no change here)`

This is exactly what an `Operation` represents in `patcher`:

1.  **`Add`**: Indicates that a specific line of text needs to be **added**. In patch text, these lines start with `+`.
2.  **`Remove`**: Indicates that a specific line of text needs to be **removed**. In patch text, these lines start with `-`.
3.  **`Context`**: Indicates that a specific line of text is **unchanged** and exists in both the original and the new version. In patch text, these lines start with a space (` `).

**Why are Context lines important?** They act like landmarks! When the [Patcher](05_patcher_.md) (which we'll learn about soon) tries to apply the changes, it uses these `Context` lines to make sure it's in the *exact right place* in the file before adding or removing lines. Without context, it would be easy to apply changes in the wrong spot if similar lines exist elsewhere.

So, an `Operation` is the most granular level of detail within a [Chunk](03_chunk_.md), telling the [Patcher](05_patcher_.md) precisely what to do with each individual line in that section: add it, remove it, or confirm it's still there (context).

## Operations in Code: The `Operation` Enum

`patcher` represents these three possibilities using a Rust `enum` (a type that can be one of several specific variants).

*(From `src/patch.rs`)*
```rust
/// Represents a change operation in the patch
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operation {
    /// Add a new line
    Add(String),
    /// Remove a line
    Remove(String),
    /// Context line (unchanged)
    Context(String),
}
```

**Explanation:**

*   `pub enum Operation`: Defines a public enumeration named `Operation`.
*   `Add(String)`: One possible variant is `Add`. It holds a `String` which is the content of the line to be added.
*   `Remove(String)`: Another variant is `Remove`. It holds the `String` content of the line to be removed.
*   `Context(String)`: The third variant is `Context`. It holds the `String` content of a line that should remain unchanged and helps verify the location.

Each `Operation` object carries the actual text content of the line it affects.

## How Operations Fit Inside a Chunk

Remember the `Chunk` struct from the [previous chapter](03_chunk_.md)? It contains a list (`Vec`) of these `Operation`s.

*(From `src/patch.rs` - simplified `Chunk` view)*
```rust
// (Import Operation enum from above)

/// A chunk represents a continuous section of changes in a file
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Chunk {
    // ... (old_start, old_lines, new_start, new_lines) ...

    /// The sequence of operations in this chunk
    pub operations: Vec<Operation>, // <-- Here they are!
}
```

The `operations` field holds the ordered sequence of `Add`, `Remove`, and `Context` instructions for that specific chunk.

Let's revisit our example patch text and see how the lines map to `Operation`s within the single `Chunk`:

```diff
--- original
+++ modified
@@ -1,3 +1,4 @@   // Chunk Header
 line1           // -> Context("line1")
-line2           // -> Remove("line2")
+line two changed // -> Add("line two changed")
 line3           // -> Context("line3")
+new line4        // -> Add("new line4")

```

Now, let's expand the code example from Chapter 3 to actually look *inside* the `operations` vector of our chunk:

```rust
use patcher::{Differ, Operation}; // Import Operation

fn main() {
    let original = "line1\nline2\nline3";
    let modified = "line1\nline two changed\nline3\nnew line4";

    // 1. Generate the Patch
    let differ = Differ::new(original, modified);
    let patch = differ.generate();

    // 2. Loop through each chunk
    for (i, chunk) in patch.chunks.iter().enumerate() {
        println!("Chunk {}:", i + 1);

        // 3. Loop through each operation *within* the chunk
        for (op_idx, operation) in chunk.operations.iter().enumerate() {
            // 4. Check which type of operation it is
            match operation {
                Operation::Add(line) => {
                    println!("  Op {}: Add    (+) '{}'", op_idx + 1, line);
                }
                Operation::Remove(line) => {
                    println!("  Op {}: Remove (-) '{}'", op_idx + 1, line);
                }
                Operation::Context(line) => {
                    println!("  Op {}: Context( ) '{}'", op_idx + 1, line);
                }
            }
        }
    }
}
```

**Running this code would output:**

```
Chunk 1:
  Op 1: Context( ) 'line1'
  Op 2: Remove (-) 'line2'
  Op 3: Add    (+) 'line two changed'
  Op 4: Context( ) 'line3'
  Op 5: Add    (+) 'new line4'
```

This clearly shows the sequence of individual `Operation`s stored within the chunk, matching the ` `, `-`, and `+` lines from the text patch.

## How are Operations Created?

You don't usually create `Operation` objects manually. They are the direct result of the comparison performed by the [Differ](01_differ_.md) and its chosen diffing algorithm (like Myers or XDiff).

Here's a simplified idea of the process:

1.  **Line Comparison:** The diff algorithm compares the original and modified text line by line.
2.  **Identify Change Type:** It determines if each line is identical (`Context`), only in the original (`Remove`), or only in the new (`Add`).
3.  **Create Operation Object:** For each identified change or context line, the algorithm creates the corresponding `Operation` enum variant (e.g., `Operation::Add("new line4".to_string())`).
4.  **Group into Chunks:** These individual `Operation` objects are then grouped together with nearby operations and surrounding `Context` operations to form a [Chunk]03_chunk_.md.

```mermaid
sequenceDiagram
    participant Algo as Diff Algorithm
    participant Differ
    participant OperationEnum as Operation Enum
    participant ChunkObject as Chunk Object

    Note over Algo: Comparing line "X" (Original) <br/> with line "Y" (Modified)...
    Algo->>Differ: Found difference: Remove("X"), Add("Y")
    Differ->>OperationEnum: Create Operation::Remove("X")
    OperationEnum-->>Differ: remove_op
    Differ->>OperationEnum: Create Operation::Add("Y")
    OperationEnum-->>Differ: add_op
    Note over Differ: Grouping these ops with context...
    Differ->>ChunkObject: Add remove_op to operations list
    Differ->>ChunkObject: Add add_op to operations list
```

The core diffing algorithms handle the complex task of finding the most efficient sequence of adds and removes, and the `Differ` then translates these findings into the `Operation` objects we use.

## Conclusion

We've drilled down to the most fundamental unit of change: the `Operation`. You learned that an `Operation` represents a single instruction within a [Chunk](03_chunk_.md) – either `Add` a line, `Remove` a line, or keep an unchanged `Context` line. These operations are stored as variants of the `Operation` enum, each holding the relevant line content.

`Context` lines are crucial anchors, ensuring changes are applied correctly. While `Operation`s are generated automatically by the [Differ](01_differ_.md), understanding them is key to knowing exactly what a [Patch](02_patch_.md) describes.

Now that we understand how differences are found ([Differ](01_differ_.md)) and represented ([Patch](02_patch_.md), [Chunk](03_chunk_.md), `Operation`), how do we actually *use* a patch to modify a file? In the next chapter, we'll meet the component responsible for applying these changes: the [Patcher](05_patcher_.md).

Next: [Chapter 5: Patcher](05_patcher_.md)

---

Generated by [AI Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge)