1. Purpose

Context lines and diff grouping control how much unchanged content is shown around changes in line-by-line diffs. These features help you understand the location and scope of changes while keeping output readable.

Context and grouping apply only to by-line diff mode. By-object mode shows only changed elements without context lines.

2. Context Lines

Context lines are unchanged lines displayed before and after each change to show where modifications occur in the file.

2.1. Default Behavior

By default, Canon shows 3 context lines before and after each change:

Example 1. Default context example
   5|  5 | <section>              # Context line
   6|  6 |   <title>Intro</title> # Context line
   7|  7 |   <p>Welcome</p>       # Context line
   8|   -|   <p>Old text</p>      # Deleted line (change)
     |  8+|   <p>New text</p>      # Added line (change)
   9|  9 |   <p>Goodbye</p>       # Context line
  10| 10 |   <p>End</p>           # Context line
  11| 11 | </section>             # Context line

Three unchanged lines are shown before and after the change.

2.2. Configuring Context Lines

Control the number of context lines with the context_lines option:

Example 2. CLI
# Show 5 context lines
canon diff file1.xml file2.xml --context-lines 5

# Show no context (changes only)
canon diff file1.xml file2.xml --context-lines 0

# Show 10 context lines
canon diff file1.xml file2.xml --context-lines 10
Example 3. Ruby API
# Show 5 context lines
Canon.compare(file1, file2,
  format: :xml,
  context_lines: 5
)

# Show no context
Canon.compare(file1, file2,
  format: :xml,
  context_lines: 0
)
Example 4. RSpec
RSpec.configure do |config|
  # Show more context in local development
  config.canon.xml.diff.context_lines = 5
end
Example 5. Environment Variable
# Set default context lines globally
export CANON_CONTEXT_LINES=5

2.3. Zero Context Lines

Setting context_lines: 0 shows only changed lines without any surrounding context:

Example 6. No context example
   8|   -|   <p>Old text</p>      # Only the deletion
     |  8+|   <p>New text</p>      # Only the addition

This is useful when:

  • Changes are self-explanatory

  • You want minimal output

  • File structure is already known

2.4. Large Context Values

Larger context values show more surrounding content:

Example 7. Large context example (context_lines: 10)
   1|  1 | <root>
   2|  2 |   <header>
   3|  3 |     <title>Document</title>
   4|  4 |   </header>
   5|  5 |   <body>
   6|  6 |     <section>
   7|  7 |       <h1>Title</h1>
   8|  8 |       <p>Para 1</p>
   9|  9 |       <p>Para 2</p>
  10| 10 |       <p>Para 3</p>
  11|   -|       <p>Old</p>        # The change
     | 11+|       <p>New</p>
  12| 12 |       <p>Para 4</p>
  13| 13 |       <p>Para 5</p>
  14| 14 |       <p>Para 6</p>
  15| 15 |     </section>
  16| 16 |   </body>
  17| 17 | </root>

Ten lines of context before and after the change.

3. Diff Grouping

Diff grouping controls whether nearby changes are shown as separate blocks or merged into a single continuous block.

3.1. Default Behavior

By default, Canon uses 10 lines as the grouping threshold. Changes within 10 lines of each other are shown in the same context block:

Example 8. Grouped changes (within 10 lines)
   5|  5 | <section>
   6|  6 |   <p>Text 1</p>
   7|   -|   <p>Old A</p>         # First change
     |  7+|   <p>New A</p>
   8|  8 |   <p>Text 2</p>
   9|  9 |   <p>Text 3</p>
  10| 10 |   <p>Text 4</p>
  11| 11 |   <p>Text 5</p>
  12|   -|   <p>Old B</p>         # Second change (within 10 lines)
     | 12+|   <p>New B</p>
  13| 13 |   <p>Text 6</p>
  14| 14 | </section>

Both changes appear in one continuous block because they’re only 4 lines apart.

3.2. Separate Blocks

When changes are far apart (more than grouping threshold), they appear as separate blocks:

Example 9. Separate blocks (beyond 10 lines apart)
   5|  5 | <section>
   6|  6 |   <p>Text 1</p>
   7|   -|   <p>Old A</p>         # First change
     |  7+|   <p>New A</p>
   8|  8 |   <p>Text 2</p>
   9|  9 |   <p>Text 3</p>
  10| 10 | </section>

  ...  (lines 11-25 omitted)     # Gap indicator

  26| 26 | <section>
  27| 27 |   <p>Text N</p>
  28|   -|   <p>Old B</p>         # Second change (far from first)
     | 28+|   <p>New B</p>
  29| 29 |   <p>Text M</p>
  30| 30 | </section>

The two changes appear as separate blocks with a gap indicator between them.

3.3. Configuring Grouping

Control grouping behavior with the diff_grouping_lines option:

Example 10. CLI
# Group changes within 5 lines
canon diff file1.xml file2.xml --diff-grouping-lines 5

# Group changes within 20 lines
canon diff file1.xml file2.xml --diff-grouping-lines 20

# Never group (each change in its own block)
canon diff file1.xml file2.xml --diff-grouping-lines 0
Example 11. Ruby API
# Tight grouping (5 lines)
Canon.compare(file1, file2,
  format: :xml,
  diff_grouping_lines: 5
)

# Loose grouping (20 lines)
Canon.compare(file1, file2,
  format: :xml,
  diff_grouping_lines: 20
)
Example 12. RSpec
RSpec.configure do |config|
  # Tighter grouping for specs
  config.canon.xml.diff.grouping_lines = 5
end
Example 13. Environment Variable
# Set default grouping globally
export CANON_GROUPING_LINES=15

4. Interaction Between Context and Grouping

Context lines and grouping work together to determine diff block boundaries:

4.1. Example: Tight Context, Loose Grouping

Example 14. context_lines: 1, diff_grouping_lines: 20
   6|  6 |   <p>Text 1</p>       # 1 line context before
   7|   -|   <p>Old A</p>
     |  7+|   <p>New A</p>
   8|  8 |   <p>Text 2</p>       # 1 line context after
   9|  9 |   <p>Text 3</p>       # Continues because next change within 20 lines
  10| 10 |   <p>Text 4</p>
  11| 11 |   <p>Text 5</p>
  12|   -|   <p>Old B</p>
     | 12+|   <p>New B</p>
  13| 13 |   <p>Text 6</p>       # 1 line context after

Minimal context but changes stay grouped.

4.2. Example: Wide Context, Tight Grouping

Example 15. context_lines: 5, diff_grouping_lines: 3
# First change block
   2|  2 | <root>
   3|  3 |   <section>
   4|  4 |     <p>A</p>
   5|  5 |     <p>B</p>
   6|  6 |     <p>C</p>
   7|   -|     <p>Old A</p>
     |  7+|     <p>New A</p>
   8|  8 |     <p>D</p>
   9|  9 |     <p>E</p>
  10| 10 |     <p>F</p>
  11| 11 |     <p>G</p>
  12| 12 |     <p>H</p>

  ...  (lines 13-17 omitted)

# Second change block (separated by > 3 lines)
  13| 13 |     <p>I</p>
  14| 14 |     <p>J</p>
  15| 15 |     <p>K</p>
  16| 16 |     <p>L</p>
  17| 17 |     <p>M</p>
  18|   -|     <p>Old B</p>
     | 18+|     <p>New B</p>
  19| 19 |     <p>N</p>
  20| 20 |     <p>O</p>
  21| 21 |     <p>P</p>
  22| 22 |     <p>Q</p>
  23| 23 |   </section>

Wide context but changes in separate blocks due to tight grouping.

5. Use Cases

5.1. Debugging: Wide Context

When debugging unexpected test failures, use wide context to see surrounding structure:

canon diff expected.xml actual.xml \
  --context-lines 10 \
  --diff-grouping-lines 20

5.2. CI/CD: Minimal Output

In CI environments, minimize output for faster log scanning:

export CANON_CONTEXT_LINES=1
export CANON_GROUPING_LINES=5

5.3. Documentation: Complete Context

When documenting changes, show complete sections:

Canon.compare(old_doc, new_doc,
  format: :xml,
  context_lines: 15,
  diff_grouping_lines: 30
)

5.4. Code Review: Balanced View

For code reviews, balance readability and completeness:

RSpec.configure do |config|
  config.canon.xml.diff.context_lines = 5
  config.canon.xml.diff.grouping_lines = 10
end

6. Performance Considerations

6.1. Large Files

With large files and many changes:

  • Smaller context: Reduces output size, faster to scan

  • Tighter grouping: More separate blocks, easier to locate specific changes

  • Larger context: Better understanding, but more verbose

Example 16. Recommended for large files
# Keep output manageable
canon diff large1.xml large2.xml \
  --context-lines 2 \
  --diff-grouping-lines 5

6.2. Many Small Changes

When files have numerous small scattered changes:

  • Smaller context: Avoids repetitive output

  • Tighter grouping: Keeps unrelated changes separate

  • Larger grouping: May merge everything into one block

Example 17. Recommended for scattered changes
# Separate unrelated changes
canon diff file1.xml file2.xml \
  --context-lines 1 \
  --diff-grouping-lines 3

7. Gap Indicators

When changes are far apart, Canon shows gap indicators:

  10| 10 |   <p>End of first section</p>

  ...  (lines 11-45 omitted)

  46| 46 |   <p>Start of next section</p>

The gap indicator shows: * How many lines were skipped * That there are no changes in the skipped region

8. Troubleshooting

8.1. Too Much Output

Problem: Diff output is overwhelming.

Solutions: * Reduce context_lines (try 1 or 2) * Reduce diff_grouping_lines (try 5 or less) * Use show_diffs: :normative to hide informative changes

8.2. Not Enough Context

Problem: Can’t understand where changes occur.

Solutions: * Increase context_lines (try 7-10) * Increase diff_grouping_lines (try 15-20) * Check file structure separately

8.3. Changes Grouped Incorrectly

Problem: Unrelated changes appear together.

Solution: * Decrease diff_grouping_lines to separate them

Problem: Related changes appear in separate blocks.

Solution: * Increase diff_grouping_lines to group them together

9. See Also