1. Purpose
Canon uses a carefully designed color scheme and symbol system to communicate the nature and severity of differences in document comparisons.
2. Diff classification
Canon classifies differences into three distinct categories, each with unique visual markers and directional colors.
| Type | Marker | Color | Meaning |
|---|---|---|---|
Formatting-only |
|
Dark gray (removed) |
Purely cosmetic differences with no semantic meaning. |
Informative |
|
Blue (removed) |
Differences that don’t affect current match results. |
Normative |
|
Red (removed) |
Semantic differences that affect match results. |
Mixed |
|
Yellow |
Line contains multiple separate changed regions. |
2.1. Classification hierarchy
The classification follows a strict hierarchy:
formatting < informative < normative
A difference is classified using the highest applicable category:
- normative
-
the differences leads to semantic changes that are considered normative
- informative
-
the differences leads to semantic changes that are considered informative
- formatting-only
-
the differences do not cause any semantic difference
3. Formatting-only detection
Formatting-only differences are detected through aggressive normalization:
-
Collapse all whitespace (spaces, tabs, newlines) to single space
-
Strip leading and trailing whitespace
-
Compare normalized content
If the normalized content is identical, the difference is classified as formatting-only.
5| 5[ | <p class="section-break"><br clear="all" class="section"></p>
| 5] | <p class="section-break"><br clear="all" class="section"><div class="WordSection2">
6| 6] | <div class="WordSection2">
These lines differ only in how content is split across lines. The semantic content (when
whitespace is normalized) is identical, so they show as formatting-only with [ (dark gray) for
removed and ] (light gray) for added lines.
4. Color Coding
4.1. By Difference Type
4.1.1. Formatting-Only (Gray Tones)
Formatting-only changes use directional gray tones to indicate low visual priority:
-
Dark gray (
[): Formatting-only removal -
Light gray (
]): Formatting-only addition -
Purely cosmetic
-
Safe to ignore
-
No semantic impact
5. Symbol Meanings
5.1. Line-Level Markers
5.1.1. Formatting Markers (Gray)
-
[- Line removed (formatting-only difference, dark gray) -
]- Line added (formatting-only difference, light gray)
5.1.2. Informative Markers (Blue)
-
<- Line removed (informative difference, blue) -
>- Line added (informative difference, cyan)
5.1.3. Normative Markers (Red/Green)
-
-- Line removed (normative difference, red) -
+- Line added (normative difference, green)
6. Visual Examples
6.1. Formatting-Only Change (Gray Tones)
5| 5[ | <p>Content that spans (dark gray)
| 5] | <p>Content that spans multiple lines</p> (light gray)
6| 6] | multiple lines</p> (light gray)
6.2. Informative Change (Blue Tones)
10| 10< | <div class="test"> (blue)
| 10> | <div class="test"> (cyan)
6.3. Normative Change (Red/Green)
15| 15- | <title>Old Title</title> (red)
| 15+ | <title>New Title</title> (green)
6.4. Mixed Context
20| 20 | <body>
21| 21[ | <p>Hello</p> (dark gray)
| 21] | <p>Hello</p><span>World</span> (light gray)
22| 22] | <span>World</span> (light gray)
23| 23- | <footer>2023</footer> (red)
| 23+ | <footer>2024</footer> (green)
24| 24 | </body>
This example shows:
-
Line 20, 24: Unchanged context (space marker)
-
Lines 21-22: Formatting-only change (
[dark gray,]light gray) -
Line 23: Normative change (
-red,+green)
7. Configuration
Colors can be disabled for terminal compatibility:
result = Canon.compare(doc1, doc2, format: :xml, use_color: false)
When colors are disabled:
-
Markers remain (` [ ] < > - +`)
-
All text appears in terminal default color
-
Line numbers and pipes remain visible
7.1. Tree Diff Symbols
In by-object diff mode, box-drawing characters create a visual tree structure:
| Symbol | Meaning |
|---|---|
|
Tree branch (child element) |
|
Last tree branch (last child) |
|
Tree continuation (vertical line) |
|
Deletion marker (red) |
|
Addition marker (green) |
|
Change marker (yellow) |
root
├── - item: "Old value" # Deleted (red -)
├── + item: "New value" # Added (green +)
└── ~ title # Modified (yellow ~)
├── - "Old Title" # Old value
└── + "New Title" # New value
8. Character Visualization Symbols
When use_color: true, Canon visualizes invisible characters using Unicode symbols. See Character Visualization for the complete mapping.
Common examples:
| Character | Symbol | Unicode |
|---|---|---|
Regular space |
|
U+2591 (Light Shade) |
Tab |
|
U+21E5 (Rightwards Arrow to Bar) |
Non-breaking space |
|
U+2423 (Open Box) |
Line feed |
|
U+21B5 (Downwards Arrow with Corner Leftwards) |
Zero-width space |
|
U+2192 (Rightwards Arrow) |
9. Namespace Rendering
9.1. Namespace Display Format
Canon makes namespace information explicit in diff output, particularly when comparing XML elements and attributes:
| Namespace State | Display Format |
|---|---|
Empty namespace |
|
Populated namespace |
|
# Element with no namespace
- <element ns:[{blank}]>content</element>
# Element with namespace
+ <element ns:[http://example.com]>content</element>
9.2. Namespace Mismatch Classification
When elements or attributes differ, Canon classifies the mismatch type:
| Mismatch Type | Message Format |
|---|---|
Same namespace, different name |
|
Different namespace, same name |
|
Both name and namespace differ |
|
# Name differs, same namespace
mismatched element name: 'item' vs 'product' (ns:[http://shop.com])
# Namespace differs, same name
mismatched element namespace: 'element' (ns:[{blank}] vs ns:[http://example.com])
9.3. Attribute Namespace Rendering
The same namespace rendering applies to attributes:
# Attribute with no namespace
- <element attr="value" ns:[{blank}]/>
# Attribute with namespace
+ <element ns:attr="value" ns:[http://ns.com]/>
# Mismatch message
mismatched attribute namespace: 'id' (ns:[{blank}] vs ns:[http://example.com])
10. Header and Metadata Colors
| Element | Color | Purpose |
|---|---|---|
Section headers |
Cyan + Bold |
"Visual Diff:", "Line-by-line diff:", etc. |
Algorithm name |
Cyan + Bold |
"Algorithm: SEMANTIC TREE DIFF", "Algorithm: DOM DIFF" |
Success messages |
Green + Bold |
"✅ Files are semantically equivalent" |
Separators |
Cyan + Bold |
"━━━━" (Unicode box drawing) |
Legend headers |
Cyan + Bold |
"Character Visualization Legend:" |
Category names |
Yellow + Bold |
"Common Whitespace:", "Unicode Spaces:", etc. |
11. Normative vs Informative Classification
The color distinction between normative and informative diffs is crucial:
11.1. Normative Diffs (Red/Green)
Definition: Differences that cause files to be non-equivalent based on the current match configuration.
When shown:
* Match dimension is set to :strict or :normalize
* The difference persists even after applying normalization
# With attribute_order: :strict
5| -| <item id="a" name="foo"/> # Red (normative)
| 6+| <item name="foo" id="a"/> # Green (normative)
The attribute order difference is normative because attribute_order: :strict treats it as significant.
11.2. Informative Diffs (Cyan)
Definition: Differences that don’t affect file equivalence based on the current match configuration.
When shown:
* Match dimension is set to :ignore or :normalize handled the difference
* The difference exists but is ignored for equivalence purposes
* Shown with show_diffs: :all or show_diffs: :informative
# With structural_whitespace: :ignore
5| ~~ | <item> # Cyan (informative)
| ~~ | <name>Widget</name> # Extra indentation ignored
The whitespace difference is informative because structural_whitespace: :ignore means it doesn’t affect equivalence.
12. Color Control
12.1. Theme System
Canon supports multiple color themes that adapt the diff display to your terminal background and personal preference. Four built-in themes are available:
-
:light— Light terminal backgrounds -
:dark— Dark terminals (default) -
:retro— Amber CRT, low blue light, accessibility -
:claude— Claude Code diff style with red/green backgrounds
See Diff display themes for full theme documentation.
12.2. Automatic Color Detection
Canon automatically detects whether the terminal supports color output:
-
TTY detection: Colors are only enabled when output is to a terminal (not when piped to a file)
-
NO_COLOR support: If the
NO_COLORenvironment variable is set (per https://no-color.org/), colors are disabled -
Terminal capability detection: Checks environment variables like
TERMandCOLORTERM -
CI environment awareness: Detects and adapts to CI systems (GitHub Actions, Travis CI, etc.)
This means colors work automatically in most scenarios without manual configuration.
12.3. Enabling/Disabling Colors
Colors can be explicitly controlled using the use_color option:
# Auto-detects color support (default)
canon diff file1.xml file2.xml
# Force enable colors
canon diff file1.xml file2.xml --color
# Force disable colors
canon diff file1.xml file2.xml --no-color
# Auto-detect (default)
Canon.compare(file1, file2, format: :xml)
# Explicit control
Canon.compare(file1, file2, format: :xml, use_color: false)
=== NO_COLOR Environment Variable
Per the NO_COLOR standard, setting the NO_COLOR
environment variable will disable colors:
# Disable colors (respected by Canon and other NO_COLOR-aware tools)
export NO_COLOR=1
# Run canon - colors will be disabled
canon diff file1.xml file2.xml
The NO_COLOR variable always takes precedence over other color settings.
== Diff Display Modes
Canon supports two display modes for changed lines, controlled by the diff_mode option:
=== Separate-Line Mode (default)
Each changed line is shown as two lines — old on top, new on bottom:
2| - | <p>John░Doe</p>
| 2+ | <p>Jane░Doe</p>
-
Old line: line number on left,
-marker, full content -
New line: line number on right,
+marker, full content -
Changes are highlighted with colors (red for old, green for new)
=== Inline Mode
Old and new content shown on the same line, with inline highlighting:
-
When color is ON: removed text appears in red, added text in green
-
When color is OFF: removed text has strikethrough (
\e[9m), added text has underline (\e[4m) -
Both sides of the change are visible simultaneously
result = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
diff_mode: :inline
)
=== Legacy Terminal Mode
For terminals without ANSI support, Canon forces separate-line mode with no color codes:
result = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
legacy_terminal: true
)
Legacy terminal mode automatically sets diff_mode: :separate and disables all color output.
=== Color-Off Effects (Separate-Line Mode)
When colors are disabled but ANSI is supported, Canon uses text effects to distinguish changes:
-
Strikethrough (
\e[9m): Removed text -
Underline (
\e[4m): Added text
These provide visual distinction even without color support.
=== Environment Variables
In addition to NO_COLOR, Canon supports these environment variables:
# Disable colors globally (CANON_USE_COLOR)
export CANON_USE_COLOR=false
# Enable colors globally (CANON_USE_COLOR)
export CANON_USE_COLOR=true
# Format-specific color control
export CANON_XML_DIFF_USE_COLOR=false
export CANON_HTML_DIFF_USE_COLOR=false
export CANON_JSON_DIFF_USE_COLOR=false
export CANON_YAML_DIFF_USE_COLOR=false
=== Terminal Detection
Canon detects terminal capabilities through these environment variables:
COLORTERM-
Set to
24bit,truecolor, ortrueindicates True Color support TERM-
Terminal type:
- 256-color support
-
xterm-256color,screen-256color - Direct color support
-
xterm-direct - No color support
-
dumb,emacs - Assume basic ANSI color support
-
Most other values
CI-
CI environment detection (plus CI-specific variables)
If no terminal information is available, Canon assumes color support for modern terminals.
== Diff Type Display Options
Control which types of diffs to show using the show_diffs option:
| Option | What’s Shown |
|---|---|
|
Both normative and informative diffs |
|
Only normative diffs (red/green) |
|
Only informative diffs (cyan) |
# CLI - only show differences that affect equivalence
canon diff file1.xml file2.xml --show-diffs normative
# Ruby API
Canon.compare(file1, file2,
format: :xml,
show_diffs: :normative
)
== Visual Examples
=== Complete Diff with All Colors
Algorithm: SEMANTIC TREE DIFF # Cyan + Bold
Visual Diff: # Cyan + Bold
root
├── ~ attributes # Yellow (normative)
│ ├── - id: "old" # Red (normative deletion)
│ └── + id: "new" # Green (normative addition)
├── ~~ whitespace # Cyan (informative)
│ └── ~~ extra spaces # Cyan (informative)
└── + element # Green (normative addition)
└── value: "new"
Line-by-line diff (XML mode): # Cyan + Bold
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Cyan
1| 1 | <root> # Default (context)
2| -| <item░id="old"/> # Red (normative deletion)
| 2+| <item░id="new"/> # Green (normative addition)
3| ~~ | <p>Text</p> # Cyan (informative)
| ~~ | <p>░░Text</p> # Cyan (extra spaces, informative)
== Colorblind-Friendly Features
While Canon uses colors, it also provides symbols that work without color:
-
Symbols (
-,+,~) distinguish change types -
Line numbers show correspondence
-
Tree structure shows hierarchy
-
Text labels describe differences
The combination ensures diffs are readable even without color perception.
== Related Features
-
Display Filtering - Control which diff types to show
-
Context and Grouping - Control surrounding context
-
Match Options - Configure what’s considered normative vs informative
== See Also
-
Character Visualization - Detailed whitespace visualization
-
Algorithm-Specific Output - Diff format variations
-
Context and Grouping - Controlling diff context
-
Diff Formatting - Overview of formatting features