canon 0.1.21 → 0.1.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +50 -26
- data/README.adoc +8 -3
- data/docs/advanced/diff-pipeline.adoc +36 -9
- data/docs/features/diff-formatting/colors-and-symbols.adoc +82 -0
- data/docs/features/diff-formatting/index.adoc +12 -0
- data/docs/features/diff-formatting/themes.adoc +353 -0
- data/docs/features/environment-configuration/index.adoc +23 -0
- data/docs/internals/diff-char-range-pipeline.adoc +249 -0
- data/docs/internals/diffnode-enrichment.adoc +1 -0
- data/docs/internals/index.adoc +52 -4
- data/docs/reference/environment-variables.adoc +6 -0
- data/docs/understanding/architecture.adoc +5 -0
- data/examples/show_themes.rb +217 -0
- data/lib/canon/comparison/comparison_result.rb +9 -4
- data/lib/canon/config/env_schema.rb +3 -1
- data/lib/canon/config.rb +11 -0
- data/lib/canon/diff/diff_block.rb +7 -0
- data/lib/canon/diff/diff_block_builder.rb +2 -2
- data/lib/canon/diff/diff_char_range.rb +140 -0
- data/lib/canon/diff/diff_line.rb +42 -4
- data/lib/canon/diff/diff_line_builder.rb +907 -0
- data/lib/canon/diff/diff_node.rb +5 -1
- data/lib/canon/diff/diff_node_enricher.rb +1418 -0
- data/lib/canon/diff/diff_node_mapper.rb +54 -0
- data/lib/canon/diff/source_locator.rb +105 -0
- data/lib/canon/diff/text_decomposer.rb +103 -0
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +264 -24
- data/lib/canon/diff_formatter/by_line/html_formatter.rb +35 -20
- data/lib/canon/diff_formatter/by_line/json_formatter.rb +36 -19
- data/lib/canon/diff_formatter/by_line/simple_formatter.rb +33 -19
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +583 -98
- data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +36 -19
- data/lib/canon/diff_formatter/by_object/base_formatter.rb +62 -13
- data/lib/canon/diff_formatter/by_object/json_formatter.rb +59 -24
- data/lib/canon/diff_formatter/by_object/xml_formatter.rb +74 -34
- data/lib/canon/diff_formatter/diff_detail_formatter/color_helper.rb +4 -5
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +1 -1
- data/lib/canon/diff_formatter/legend.rb +4 -2
- data/lib/canon/diff_formatter/theme.rb +864 -0
- data/lib/canon/diff_formatter.rb +11 -6
- data/lib/canon/tree_diff/matchers/hash_matcher.rb +16 -1
- data/lib/canon/tree_diff/matchers/similarity_matcher.rb +10 -0
- data/lib/canon/tree_diff/operations/operation_detector.rb +5 -1
- data/lib/canon/tree_diff/tree_diff_integrator.rb +1 -1
- data/lib/canon/version.rb +1 -1
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08086e588946bb0f5f39a8235984058b5a5e8aea956b9652e0e366ff84500232'
|
|
4
|
+
data.tar.gz: bb078d67c1a68da1ca88b3d29fde336e291b0ff95186ade125ee1ccfb1a82de4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 35f7888d948f86fa4b504b060ee6d9976dc38b32232e8c86b9b8986ee08448cdad265fe4d091e810e5f63f0b0702e125317e07d15761b5cd6404905190546234
|
|
7
|
+
data.tar.gz: 4f57564289fdff8c73020f3ed9f9184b363688062cf1b89baea79f0d25c57905bcbc225b5e946afeb30305b91402b557ae65ce61b99a0d63b8bb1c569ec2d57f
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-
|
|
3
|
+
# on 2026-04-01 00:03:16 UTC using RuboCop version 1.86.0.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
@@ -11,36 +11,39 @@ Gemspec/RequiredRubyVersion:
|
|
|
11
11
|
Exclude:
|
|
12
12
|
- 'canon.gemspec'
|
|
13
13
|
|
|
14
|
-
# Offense count:
|
|
14
|
+
# Offense count: 2
|
|
15
15
|
# This cop supports safe autocorrection (--autocorrect).
|
|
16
16
|
# Configuration parameters: EnforcedStyleAlignWith.
|
|
17
17
|
# SupportedStylesAlignWith: either, start_of_block, start_of_line
|
|
18
18
|
Layout/BlockAlignment:
|
|
19
19
|
Exclude:
|
|
20
|
-
- '
|
|
20
|
+
- 'lib/canon/tree_diff/matchers/hash_matcher.rb'
|
|
21
|
+
- 'spec/canon/hash_matcher_regression_spec.rb'
|
|
21
22
|
|
|
22
|
-
# Offense count:
|
|
23
|
+
# Offense count: 2
|
|
23
24
|
# This cop supports safe autocorrection (--autocorrect).
|
|
24
25
|
Layout/BlockEndNewline:
|
|
25
26
|
Exclude:
|
|
26
|
-
- '
|
|
27
|
+
- 'lib/canon/tree_diff/matchers/hash_matcher.rb'
|
|
28
|
+
- 'spec/canon/hash_matcher_regression_spec.rb'
|
|
27
29
|
|
|
28
|
-
# Offense count:
|
|
30
|
+
# Offense count: 4
|
|
29
31
|
# This cop supports safe autocorrection (--autocorrect).
|
|
30
32
|
# Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
|
|
31
33
|
# SupportedStylesAlignWith: start_of_line, relative_to_receiver
|
|
32
34
|
Layout/IndentationWidth:
|
|
33
35
|
Exclude:
|
|
34
|
-
- '
|
|
36
|
+
- 'lib/canon/tree_diff/matchers/hash_matcher.rb'
|
|
37
|
+
- 'spec/canon/hash_matcher_regression_spec.rb'
|
|
35
38
|
|
|
36
|
-
# Offense count:
|
|
39
|
+
# Offense count: 1103
|
|
37
40
|
# This cop supports safe autocorrection (--autocorrect).
|
|
38
41
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
39
42
|
# URISchemes: http, https
|
|
40
43
|
Layout/LineLength:
|
|
41
44
|
Enabled: false
|
|
42
45
|
|
|
43
|
-
# Offense count:
|
|
46
|
+
# Offense count: 55
|
|
44
47
|
# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
|
|
45
48
|
Lint/DuplicateBranch:
|
|
46
49
|
Enabled: false
|
|
@@ -80,33 +83,43 @@ Lint/UnusedMethodArgument:
|
|
|
80
83
|
- 'lib/canon/diff_formatter/by_line/xml_formatter.rb'
|
|
81
84
|
- 'lib/canon/diff_formatter/by_object/base_formatter.rb'
|
|
82
85
|
|
|
83
|
-
# Offense count:
|
|
86
|
+
# Offense count: 1
|
|
87
|
+
Lint/UselessConstantScoping:
|
|
88
|
+
Exclude:
|
|
89
|
+
- 'lib/canon/diff_formatter/theme.rb'
|
|
90
|
+
|
|
91
|
+
# Offense count: 298
|
|
84
92
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
85
93
|
Metrics/AbcSize:
|
|
86
94
|
Enabled: false
|
|
87
95
|
|
|
88
|
-
# Offense count:
|
|
96
|
+
# Offense count: 29
|
|
89
97
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
|
|
90
98
|
# AllowedMethods: refine
|
|
91
99
|
Metrics/BlockLength:
|
|
92
|
-
Max:
|
|
100
|
+
Max: 92
|
|
93
101
|
|
|
94
|
-
# Offense count:
|
|
102
|
+
# Offense count: 1
|
|
103
|
+
# Configuration parameters: CountBlocks, CountModifierForms.
|
|
104
|
+
Metrics/BlockNesting:
|
|
105
|
+
Max: 4
|
|
106
|
+
|
|
107
|
+
# Offense count: 262
|
|
95
108
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
96
109
|
Metrics/CyclomaticComplexity:
|
|
97
110
|
Enabled: false
|
|
98
111
|
|
|
99
|
-
# Offense count:
|
|
112
|
+
# Offense count: 485
|
|
100
113
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
101
114
|
Metrics/MethodLength:
|
|
102
|
-
Max:
|
|
115
|
+
Max: 146
|
|
103
116
|
|
|
104
|
-
# Offense count:
|
|
117
|
+
# Offense count: 56
|
|
105
118
|
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
|
106
119
|
Metrics/ParameterLists:
|
|
107
|
-
Max:
|
|
120
|
+
Max: 10
|
|
108
121
|
|
|
109
|
-
# Offense count:
|
|
122
|
+
# Offense count: 213
|
|
110
123
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
111
124
|
Metrics/PerceivedComplexity:
|
|
112
125
|
Enabled: false
|
|
@@ -130,11 +143,12 @@ Naming/VariableNumber:
|
|
|
130
143
|
- 'lib/canon/comparison/markup_comparator.rb'
|
|
131
144
|
- 'lib/canon/comparison/xml_comparator/diff_node_builder.rb'
|
|
132
145
|
|
|
133
|
-
# Offense count:
|
|
146
|
+
# Offense count: 4
|
|
134
147
|
# Configuration parameters: MinSize.
|
|
135
148
|
Performance/CollectionLiteralInLoop:
|
|
136
149
|
Exclude:
|
|
137
150
|
- 'lib/canon/comparison/html_comparator.rb'
|
|
151
|
+
- 'lib/canon/diff_formatter/theme.rb'
|
|
138
152
|
- 'lib/canon/xml/xml_base_handler.rb'
|
|
139
153
|
- 'spec/canon/diff/diff_node_mapper_comments_spec.rb'
|
|
140
154
|
|
|
@@ -144,7 +158,7 @@ Performance/CollectionLiteralInLoop:
|
|
|
144
158
|
RSpec/ContextWording:
|
|
145
159
|
Enabled: false
|
|
146
160
|
|
|
147
|
-
# Offense count:
|
|
161
|
+
# Offense count: 34
|
|
148
162
|
# Configuration parameters: IgnoredMetadata.
|
|
149
163
|
RSpec/DescribeClass:
|
|
150
164
|
Enabled: false
|
|
@@ -155,10 +169,10 @@ RSpec/DescribeMethod:
|
|
|
155
169
|
- 'spec/canon/comparison/multiple_differences_spec.rb'
|
|
156
170
|
- 'spec/canon/diff_formatter/character_map_customization_spec.rb'
|
|
157
171
|
|
|
158
|
-
# Offense count:
|
|
172
|
+
# Offense count: 741
|
|
159
173
|
# Configuration parameters: CountAsOne.
|
|
160
174
|
RSpec/ExampleLength:
|
|
161
|
-
Max:
|
|
175
|
+
Max: 44
|
|
162
176
|
|
|
163
177
|
# Offense count: 8
|
|
164
178
|
# This cop supports safe autocorrection (--autocorrect).
|
|
@@ -207,7 +221,7 @@ RSpec/MultipleDescribes:
|
|
|
207
221
|
Exclude:
|
|
208
222
|
- 'spec/canon/comparison/match_options_spec.rb'
|
|
209
223
|
|
|
210
|
-
# Offense count:
|
|
224
|
+
# Offense count: 595
|
|
211
225
|
RSpec/MultipleExpectations:
|
|
212
226
|
Max: 15
|
|
213
227
|
|
|
@@ -240,10 +254,11 @@ RSpec/NoExpectationExample:
|
|
|
240
254
|
- 'spec/canon/isodoc_blockquotes_spec.rb'
|
|
241
255
|
- 'spec/canon/match_scenarios_spec.rb'
|
|
242
256
|
|
|
243
|
-
# Offense count:
|
|
257
|
+
# Offense count: 4
|
|
244
258
|
RSpec/RepeatedExample:
|
|
245
259
|
Exclude:
|
|
246
260
|
- 'spec/canon/comparison/encoding_normalization_spec.rb'
|
|
261
|
+
- 'spec/canon/diff_display_spec.rb'
|
|
247
262
|
|
|
248
263
|
# Offense count: 7
|
|
249
264
|
# Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata, InflectorPath, EnforcedInflector.
|
|
@@ -270,7 +285,7 @@ RSpec/VerifiedDoubles:
|
|
|
270
285
|
- 'spec/canon/diff_formatter/diff_detail_formatter_spec.rb'
|
|
271
286
|
- 'spec/canon/tree_diff/operation_converter_spec.rb'
|
|
272
287
|
|
|
273
|
-
# Offense count:
|
|
288
|
+
# Offense count: 2
|
|
274
289
|
# This cop supports safe autocorrection (--autocorrect).
|
|
275
290
|
# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
|
|
276
291
|
# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
|
|
@@ -279,7 +294,8 @@ RSpec/VerifiedDoubles:
|
|
|
279
294
|
# AllowedMethods: lambda, proc, it
|
|
280
295
|
Style/BlockDelimiters:
|
|
281
296
|
Exclude:
|
|
282
|
-
- '
|
|
297
|
+
- 'lib/canon/tree_diff/matchers/hash_matcher.rb'
|
|
298
|
+
- 'spec/canon/hash_matcher_regression_spec.rb'
|
|
283
299
|
|
|
284
300
|
# Offense count: 1
|
|
285
301
|
# This cop supports safe autocorrection (--autocorrect).
|
|
@@ -309,3 +325,11 @@ Style/IdenticalConditionalBranches:
|
|
|
309
325
|
Style/OptionalBooleanParameter:
|
|
310
326
|
Exclude:
|
|
311
327
|
- 'lib/canon/diff_formatter/debug_output.rb'
|
|
328
|
+
|
|
329
|
+
# Offense count: 1
|
|
330
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
331
|
+
# Configuration parameters: AllowedMethods.
|
|
332
|
+
# AllowedMethods: infinite?, nonzero?
|
|
333
|
+
Style/RedundantCondition:
|
|
334
|
+
Exclude:
|
|
335
|
+
- 'lib/canon/diff/diff_node_enricher.rb'
|
data/README.adoc
CHANGED
|
@@ -586,10 +586,15 @@ See link:docs/ENV_CONFIG#size-limits[ENV_CONFIG] for details on size limit confi
|
|
|
586
586
|
|
|
587
587
|
**By-line mode**: Traditional line-by-line diff with:
|
|
588
588
|
|
|
589
|
+
* **DiffCharRange pipeline**: DiffNodes are enriched with character-level positions (Phase 1: DiffNodeEnricher using SourceLocator + TextDecomposer), then assembled into display lines (Phase 2: DiffLineBuilder). The formatter only reads pre-computed positions — no tokenization or LCS during rendering.
|
|
590
|
+
* **Character-level highlighting**: Within changed lines, only the specific changed characters are highlighted, not entire lines. A text change like "Hello World" → "Hello Universe" shows "World" in red and "Universe" in green, with "Hello " in default color.
|
|
591
|
+
* **Inline and separate-line display modes**: Changed lines can be displayed inline (old→new on same line with effects) or as separate lines (traditional `-`/`+` format).
|
|
592
|
+
* **Mixed change detection**: The `*` marker identifies lines with multiple separate changed regions, distinguishing them from simple word replacements.
|
|
593
|
+
* **Legacy terminal support**: For terminals without ANSI support, forces separate-line mode with no color codes.
|
|
589
594
|
* DOM-guided semantic matching for XML
|
|
590
|
-
*
|
|
591
|
-
*
|
|
592
|
-
*
|
|
595
|
+
* Context lines around changes with configurable grouping
|
|
596
|
+
* Whitespace visualization (`░` for spaces, `⇥` for tabs)
|
|
597
|
+
* Three-tier classification with directional colors
|
|
593
598
|
|
|
594
599
|
**By-object mode**: Tree-based semantic diff with:
|
|
595
600
|
|
|
@@ -84,17 +84,21 @@ end
|
|
|
84
84
|
|
|
85
85
|
== Layer 3: Mapping
|
|
86
86
|
|
|
87
|
-
**Responsibility**:
|
|
87
|
+
**Responsibility**: Enrich semantic diffs with character-level positions and map to text lines
|
|
88
88
|
|
|
89
89
|
**Input**: DiffNode array + original text documents
|
|
90
90
|
|
|
91
91
|
**Process**:
|
|
92
|
-
1.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
1. **Enrichment** (DiffNodeEnricher): For each DiffNode, locate serialized content in source text and decompose into character ranges
|
|
93
|
+
- SourceLocator: Find serialized content position (char offset, line, column)
|
|
94
|
+
- TextDecomposer: Split into common prefix / changed / common suffix
|
|
95
|
+
- Create DiffCharRange objects with exact character positions
|
|
96
|
+
2. **Assembly** (DiffLineBuilder): Build DiffLine sequence from enriched DiffNodes
|
|
97
|
+
- Map DiffCharRanges to source lines
|
|
98
|
+
- Fill in unchanged lines between changes
|
|
99
|
+
- Detect reflow (lines that moved but content unchanged)
|
|
96
100
|
|
|
97
|
-
**Output**: Array of DiffLine objects
|
|
101
|
+
**Output**: Array of DiffLine objects, each carrying DiffCharRange arrays
|
|
98
102
|
|
|
99
103
|
[source,ruby]
|
|
100
104
|
----
|
|
@@ -102,13 +106,27 @@ end
|
|
|
102
106
|
{
|
|
103
107
|
line_number: 5,
|
|
104
108
|
content: "<p>Changed text</p>",
|
|
109
|
+
new_content: "<p>New text</p>",
|
|
105
110
|
type: :changed, # :added, :removed, :unchanged
|
|
106
111
|
diff_node: DiffNode reference,
|
|
112
|
+
char_ranges: [DiffCharRange, ...], # text1 side
|
|
113
|
+
new_char_ranges: [DiffCharRange, ...], # text2 side
|
|
107
114
|
normative: true # from diff_node
|
|
108
115
|
}
|
|
116
|
+
|
|
117
|
+
# DiffCharRange structure
|
|
118
|
+
{
|
|
119
|
+
line_number: 5,
|
|
120
|
+
start_col: 3,
|
|
121
|
+
end_col: 14,
|
|
122
|
+
side: :old,
|
|
123
|
+
status: :changed_old, # :unchanged, :changed_new, :removed, :added
|
|
124
|
+
role: :changed, # :before, :changed, :after
|
|
125
|
+
diff_node: DiffNode reference
|
|
126
|
+
}
|
|
109
127
|
----
|
|
110
128
|
|
|
111
|
-
**Key Point**: This layer bridges semantic differences to their textual representation.
|
|
129
|
+
**Key Point**: This layer bridges semantic differences to their textual representation with precise character-level positions. The two-phase approach (enrich then assemble) ensures the formatter receives pre-computed data requiring no further computation.
|
|
112
130
|
|
|
113
131
|
== Layer 4: Blocking
|
|
114
132
|
|
|
@@ -272,7 +290,15 @@ Result: Files differ, diff shown in red/green
|
|
|
272
290
|
|
|
273
291
|
=== Processing Layers
|
|
274
292
|
|
|
275
|
-
[`
|
|
293
|
+
[`DiffNodeEnricher`](../../lib/canon/diff/diff_node_enricher.rb):: Phase 1: Enriches DiffNodes with character-level positions (SourceLocator + TextDecomposer)
|
|
294
|
+
|
|
295
|
+
[`DiffLineBuilder`](../../lib/canon/diff/diff_line_builder.rb):: Phase 2: Assembles DiffLines from enriched DiffNodes (replaces DiffNodeMapper)
|
|
296
|
+
|
|
297
|
+
[`DiffCharRange`](../../lib/canon/diff/diff_char_range.rb):: Value object: a character range within a source line linked to a DiffNode
|
|
298
|
+
|
|
299
|
+
[`TextDecomposer`](../../lib/canon/diff/text_decomposer.rb):: Decomposes two strings into common prefix / changed / common suffix
|
|
300
|
+
|
|
301
|
+
[`SourceLocator`](../../lib/canon/diff/source_locator.rb):: Locates serialized content within source text, returns char offset + line/col
|
|
276
302
|
|
|
277
303
|
[`DiffBlockBuilder`](../../lib/canon/diff/diff_block_builder.rb):: Groups contiguous lines into blocks, filters by show_diffs
|
|
278
304
|
|
|
@@ -296,7 +322,8 @@ Each class does ONE thing:
|
|
|
296
322
|
|
|
297
323
|
* **Comparator**: Compares → DiffNodes
|
|
298
324
|
* **Classifier**: Classifies → normative flags
|
|
299
|
-
* **
|
|
325
|
+
* **Enricher**: Enriches → char positions on DiffNodes
|
|
326
|
+
* **LineBuilder**: Assembles → DiffLines with char ranges
|
|
300
327
|
* **BlockBuilder**: Groups lines → blocks
|
|
301
328
|
* **ContextBuilder**: Adds context → contexts
|
|
302
329
|
* **Formatter**: Renders → string
|
|
@@ -49,6 +49,13 @@ Green (added)
|
|
|
49
49
|
| Semantic differences that affect match results. +
|
|
50
50
|
Requires developer attention. +
|
|
51
51
|
Represents actual content changes.
|
|
52
|
+
|
|
53
|
+
h| Mixed
|
|
54
|
+
| `*`
|
|
55
|
+
| Yellow
|
|
56
|
+
| Line contains multiple separate changed regions. +
|
|
57
|
+
Both old and new lines are modified. +
|
|
58
|
+
Appears on both OLD and NEW lines.
|
|
52
59
|
|===
|
|
53
60
|
|
|
54
61
|
=== Classification hierarchy
|
|
@@ -141,6 +148,13 @@ Normative changes use red/green for high visual priority:
|
|
|
141
148
|
* `-` - Line removed (normative difference, red)
|
|
142
149
|
* `+` - Line added (normative difference, green)
|
|
143
150
|
|
|
151
|
+
==== Mixed Marker (Yellow)
|
|
152
|
+
|
|
153
|
+
* `*` - Line with multiple separate changed regions (yellow)
|
|
154
|
+
** Appears on BOTH old and new lines when changes are interleaved.
|
|
155
|
+
** A simple word replacement (e.g., "John" → "Jane") uses `-`/`+`, not `*`.
|
|
156
|
+
** Only used when there are 2+ separate changed regions in the same line.
|
|
157
|
+
|
|
144
158
|
==== Context Marker
|
|
145
159
|
|
|
146
160
|
* ` ` (space) - Unchanged line (context)
|
|
@@ -457,6 +471,17 @@ The whitespace difference is informative because `structural_whitespace: :ignore
|
|
|
457
471
|
|
|
458
472
|
== Color Control
|
|
459
473
|
|
|
474
|
+
=== Theme System
|
|
475
|
+
|
|
476
|
+
Canon supports multiple color themes that adapt the diff display to your terminal background and personal preference. Four built-in themes are available:
|
|
477
|
+
|
|
478
|
+
* `:light` -- Light terminal backgrounds
|
|
479
|
+
* `:dark` -- Dark terminals (default)
|
|
480
|
+
* `:retro` -- Amber CRT, low blue light, accessibility
|
|
481
|
+
* `:claude` -- Claude Code diff style with red/green backgrounds
|
|
482
|
+
|
|
483
|
+
See link:themes.adoc[Diff display themes] for full theme documentation.
|
|
484
|
+
|
|
460
485
|
=== Automatic Color Detection
|
|
461
486
|
|
|
462
487
|
Canon automatically detects whether the terminal supports color output:
|
|
@@ -522,6 +547,63 @@ canon diff file1.xml file2.xml
|
|
|
522
547
|
|
|
523
548
|
The `NO_COLOR` variable always takes precedence over other color settings.
|
|
524
549
|
|
|
550
|
+
== Diff Display Modes
|
|
551
|
+
|
|
552
|
+
Canon supports two display modes for changed lines, controlled by the `diff_mode` option:
|
|
553
|
+
|
|
554
|
+
=== Separate-Line Mode (default)
|
|
555
|
+
|
|
556
|
+
Each changed line is shown as two lines — old on top, new on bottom:
|
|
557
|
+
|
|
558
|
+
[source]
|
|
559
|
+
----
|
|
560
|
+
2| - | <p>John░Doe</p>
|
|
561
|
+
| 2+ | <p>Jane░Doe</p>
|
|
562
|
+
----
|
|
563
|
+
|
|
564
|
+
* Old line: line number on left, `-` marker, full content
|
|
565
|
+
* New line: line number on right, `+` marker, full content
|
|
566
|
+
* Changes are highlighted with colors (red for old, green for new)
|
|
567
|
+
|
|
568
|
+
=== Inline Mode
|
|
569
|
+
|
|
570
|
+
Old and new content shown on the same line, with inline highlighting:
|
|
571
|
+
|
|
572
|
+
* When color is ON: removed text appears in red, added text in green
|
|
573
|
+
* When color is OFF: removed text has strikethrough (`\e[9m`), added text has underline (`\e[4m`)
|
|
574
|
+
* Both sides of the change are visible simultaneously
|
|
575
|
+
|
|
576
|
+
[source,ruby]
|
|
577
|
+
----
|
|
578
|
+
result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
579
|
+
verbose: true,
|
|
580
|
+
diff_mode: :inline
|
|
581
|
+
)
|
|
582
|
+
----
|
|
583
|
+
|
|
584
|
+
=== Legacy Terminal Mode
|
|
585
|
+
|
|
586
|
+
For terminals without ANSI support, Canon forces separate-line mode with no color codes:
|
|
587
|
+
|
|
588
|
+
[source,ruby]
|
|
589
|
+
----
|
|
590
|
+
result = Canon::Comparison.equivalent?(xml1, xml2,
|
|
591
|
+
verbose: true,
|
|
592
|
+
legacy_terminal: true
|
|
593
|
+
)
|
|
594
|
+
----
|
|
595
|
+
|
|
596
|
+
Legacy terminal mode automatically sets `diff_mode: :separate` and disables all color output.
|
|
597
|
+
|
|
598
|
+
=== Color-Off Effects (Separate-Line Mode)
|
|
599
|
+
|
|
600
|
+
When colors are disabled but ANSI is supported, Canon uses text effects to distinguish changes:
|
|
601
|
+
|
|
602
|
+
* **Strikethrough** (`\e[9m`): Removed text
|
|
603
|
+
* **Underline** (`\e[4m`): Added text
|
|
604
|
+
|
|
605
|
+
These provide visual distinction even without color support.
|
|
606
|
+
|
|
525
607
|
=== Environment Variables
|
|
526
608
|
|
|
527
609
|
In addition to `NO_COLOR`, Canon supports these environment variables:
|
|
@@ -23,6 +23,7 @@ Canon's diff formatting includes:
|
|
|
23
23
|
* **Display filtering**: Control which differences appear in output based on
|
|
24
24
|
whether they affect equivalence
|
|
25
25
|
* **Colors and symbols**: Visual indicators for different types of changes
|
|
26
|
+
* **Diff display themes**: Choose from light, dark, retro, or claude color schemes
|
|
26
27
|
* **Character visualization**: Make invisible characters visible
|
|
27
28
|
* **Context and grouping**: Control how much surrounding context to show
|
|
28
29
|
* **Algorithm-specific output**: Different output styles for different diff
|
|
@@ -52,6 +53,17 @@ Canon uses color-coded output to distinguish different types of changes:
|
|
|
52
53
|
|
|
53
54
|
See link:colors-and-symbols.adoc[Colors and symbols] for details.
|
|
54
55
|
|
|
56
|
+
=== Diff display themes
|
|
57
|
+
|
|
58
|
+
Choose from 4 predefined color themes (light, dark, retro, claude) or create custom themes:
|
|
59
|
+
|
|
60
|
+
* Light theme: Light terminal backgrounds
|
|
61
|
+
* Dark theme: Dark terminals (default)
|
|
62
|
+
* Retro theme: Amber CRT, low blue light
|
|
63
|
+
* Claude theme: Maximum contrast with colored backgrounds
|
|
64
|
+
|
|
65
|
+
See link:themes.adoc[Themes] for complete theme documentation.
|
|
66
|
+
|
|
55
67
|
=== Character visualization
|
|
56
68
|
|
|
57
69
|
Make invisible characters visible in diff output:
|