daff 1.2.3 → 1.2.4

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.
Files changed (42) hide show
  1. data/README.md +4 -1
  2. data/lib/daff.rb +20 -7
  3. data/lib/lib/coopy/alignment.rb +6 -0
  4. data/lib/lib/coopy/cell_info.rb +1 -0
  5. data/lib/lib/coopy/compare_flags.rb +2 -0
  6. data/lib/lib/coopy/compare_table.rb +1 -1
  7. data/lib/lib/coopy/coopy.rb +80 -18
  8. data/lib/lib/coopy/csv.rb +1 -1
  9. data/lib/lib/coopy/diff_render.rb +61 -22
  10. data/lib/lib/coopy/flat_cell_builder.rb +1 -1
  11. data/lib/lib/coopy/highlight_patch.rb +8 -6
  12. data/lib/lib/coopy/mover.rb +1 -1
  13. data/lib/lib/coopy/ndjson.rb +134 -0
  14. data/lib/lib/coopy/nested_cell_builder.rb +74 -0
  15. data/lib/lib/coopy/simple_view.rb +29 -0
  16. data/lib/lib/coopy/sql_column.rb +35 -0
  17. data/lib/lib/coopy/sql_compare.rb +245 -0
  18. data/lib/lib/coopy/sql_database.rb +19 -0
  19. data/lib/lib/coopy/sql_helper.rb +12 -0
  20. data/lib/lib/coopy/sql_table.rb +216 -0
  21. data/lib/lib/coopy/sql_table_name.rb +23 -0
  22. data/lib/lib/coopy/sqlite_helper.rb +47 -0
  23. data/lib/lib/coopy/table_diff.rb +18 -6
  24. data/lib/lib/coopy/table_io.rb +5 -0
  25. data/lib/lib/coopy/terminal_diff_render.rb +8 -9
  26. data/lib/lib/coopy/view.rb +5 -0
  27. data/lib/lib/haxe/ds/int_map.rb +4 -0
  28. data/lib/lib/haxe/ds/string_map.rb +4 -0
  29. data/lib/lib/haxe/format/json_parser.rb +8 -8
  30. data/lib/lib/haxe/imap.rb +1 -0
  31. data/lib/lib/haxe/io/bytes.rb +1 -1
  32. data/lib/lib/haxe/io/bytes_output.rb +1 -1
  33. data/lib/lib/haxe/io/error.rb +1 -0
  34. data/lib/lib/haxe/io/output.rb +2 -2
  35. data/lib/lib/hx_overrides.rb +12 -0
  36. data/lib/lib/hx_sys.rb +1 -1
  37. data/lib/lib/rb/boot.rb +5 -1
  38. data/lib/lib/reflect.rb +1 -0
  39. data/lib/lib/sys/io/file_handle.rb +1 -0
  40. data/lib/lib/sys/io/file_output.rb +1 -1
  41. data/lib/lib/value_type.rb +1 -0
  42. metadata +36 -25
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/daff.svg)](http://badge.fury.io/rb/daff)
4
4
  [![PyPI version](https://badge.fury.io/py/daff.svg)](http://badge.fury.io/py/daff)
5
5
  [![PHP version](https://badge.fury.io/ph/paulfitz%2Fdaff-php.svg)](http://badge.fury.io/ph/paulfitz%2Fdaff-php)
6
+ [![tips](https://img.shields.io/gratipay/paulfitz.svg)](https://gratipay.com/paulfitz/)
6
7
 
7
8
  daff: data diff
8
9
  ===============
@@ -47,7 +48,7 @@ daff can produce and apply tabular diffs.
47
48
  Call as:
48
49
  daff [--output OUTPUT.csv] a.csv b.csv
49
50
  daff [--output OUTPUT.csv] parent.csv a.csv b.csv
50
- daff [--output OUTPUT.jsonbook] a.jsonbook b.jsonbook
51
+ daff [--output OUTPUT.ndjson] a.ndjson b.ndjson
51
52
  daff patch [--inplace] [--output OUTPUT.csv] a.csv patch.csv
52
53
  daff merge [--inplace] [--output OUTPUT.csv] parent.csv a.csv b.csv
53
54
  daff trim [--output OUTPUT.csv] source.csv
@@ -72,6 +73,8 @@ If you need more control, here is the full list of flags:
72
73
  --plain: do not use fancy utf8 characters to make arrows prettier
73
74
  ````
74
75
 
76
+ Formats supported are CSV, TSV, and [ndjson](http://dataprotocols.org/ndjson/).
77
+
75
78
  Using with git
76
79
  --------------
77
80
 
data/lib/daff.rb CHANGED
@@ -55,17 +55,25 @@ require_relative 'lib/coopy/index_item'
55
55
  require_relative 'lib/coopy/index_pair'
56
56
  require_relative 'lib/coopy/merger'
57
57
  require_relative 'lib/coopy/mover'
58
+ require_relative 'lib/coopy/ndjson'
59
+ require_relative 'lib/coopy/nested_cell_builder'
58
60
  require_relative 'lib/coopy/ordering'
59
61
  require_relative 'lib/coopy/table'
60
62
  require_relative 'lib/coopy/simple_table'
61
63
  require_relative 'lib/coopy/view'
62
64
  require_relative 'lib/coopy/simple_view'
63
65
  require_relative 'lib/coopy/sparse_sheet'
66
+ require_relative 'lib/coopy/sql_column'
67
+ require_relative 'lib/coopy/sql_compare'
68
+ require_relative 'lib/coopy/sql_database'
69
+ require_relative 'lib/coopy/sql_helper'
70
+ require_relative 'lib/coopy/sql_table'
71
+ require_relative 'lib/coopy/sql_table_name'
72
+ require_relative 'lib/coopy/sqlite_helper'
64
73
  require_relative 'lib/coopy/table_comparison_state'
65
74
  require_relative 'lib/coopy/table_diff'
66
75
  require_relative 'lib/coopy/table_io'
67
76
  require_relative 'lib/coopy/table_modifier'
68
- require_relative 'lib/coopy/table_text'
69
77
  require_relative 'lib/coopy/terminal_diff_render'
70
78
  require_relative 'lib/coopy/unit'
71
79
  require_relative 'lib/coopy/viterbi'
@@ -96,16 +104,21 @@ def _hx_ord(s) return 0 if s.nil?; s.ord end
96
104
  $hx_exception_classes = {}
97
105
  def hx_exception_class(c)
98
106
  $hx_exception_classes[c.name] ||= Class.new(RuntimeError) do
99
- Object.const_set((c.name.split(/::/).old_access(-1)||'') + 'HaxeException',self)
100
- def initialize(target) @target = target; end
101
- def method_missing(name, *args, &block)
102
- @target.send(name, *args, &block)
103
- end
107
+ Object.const_set((c.name.split(/::/)[-1]||'') + 'HaxeException',self)
108
+ attr_accessor :hx_exception_target
109
+ def initialize(target) @hx_exception_target = target; end
104
110
  end
105
111
  end
106
- def hx_exception(x)
112
+ def hx_raise(x)
107
113
  hx_exception_class(x.class).new(x)
108
114
  end
115
+ def hx_rescue(x)
116
+ hx_exception_class(x.class)
117
+ end
118
+ def hx_rescued(x)
119
+ return x.hx_exception_target if x.respond_to? :hx_exception_target
120
+ x
121
+ end
109
122
 
110
123
 
111
124
  Daff = Coopy
@@ -96,6 +96,12 @@ module Coopy
96
96
  return @order_cache
97
97
  end
98
98
 
99
+ def add_to_order(l,r,p = -2)
100
+ @order_cache = ::Coopy::Ordering.new if @order_cache == nil
101
+ @order_cache.add(l,r,p)
102
+ @order_cache_has_reference = p != -2
103
+ end
104
+
99
105
  def get_source
100
106
  return @ta
101
107
  end
@@ -7,6 +7,7 @@ module Coopy
7
7
  def initialize
8
8
  end
9
9
 
10
+ attr_accessor :raw
10
11
  attr_accessor :value
11
12
  attr_accessor :pretty_value
12
13
  attr_accessor :category
@@ -16,6 +16,7 @@ module Coopy
16
16
  @acts = nil
17
17
  @ids = nil
18
18
  @columns_to_ignore = nil
19
+ @allow_nested_cells = false
19
20
  end
20
21
 
21
22
  attr_accessor :ordered
@@ -29,6 +30,7 @@ module Coopy
29
30
  attr_accessor :acts
30
31
  attr_accessor :ids
31
32
  attr_accessor :columns_to_ignore
33
+ attr_accessor :allow_nested_cells
32
34
 
33
35
  def filter(act,allow)
34
36
  if @acts == nil
@@ -179,7 +179,7 @@ module Coopy
179
179
  return -1 if a1[1] > b1[1]
180
180
  return 0
181
181
  }
182
- columns_eval.sort{|a,b| sorter.call(a,b)}
182
+ columns_eval.sort!{|a,b| sorter.call(a,b)}
183
183
  columns = Lambda.array(Lambda.map(columns_eval,lambda {|v|
184
184
  return v[0]
185
185
  }))
@@ -9,6 +9,9 @@ module Coopy
9
9
  @format_preference = nil
10
10
  @delim_preference = nil
11
11
  @output_format = "copy"
12
+ @nested_output = false
13
+ @order_set = false
14
+ @order_preference = false
12
15
  end
13
16
 
14
17
  # protected - in ruby this doesn't play well with static/inline methods
@@ -17,6 +20,9 @@ module Coopy
17
20
  attr_accessor :delim_preference
18
21
  attr_accessor :extern_preference
19
22
  attr_accessor :output_format
23
+ attr_accessor :nested_output
24
+ attr_accessor :order_set
25
+ attr_accessor :order_preference
20
26
  attr_accessor :io
21
27
  attr_accessor :mv
22
28
 
@@ -25,10 +31,12 @@ module Coopy
25
31
  ext = ""
26
32
  pt = name.rindex(".",nil || 0) || -1
27
33
  if pt >= 0
28
- ext = name[pt + 1..-1].to_lower_case
34
+ ext = HxOverrides.substr(name,pt + 1,nil).to_lower_case
29
35
  case(ext)
30
36
  when "json"
31
37
  @format_preference = "json"
38
+ when "ndjson"
39
+ @format_preference = "ndjson"
32
40
  when "csv"
33
41
  @format_preference = "csv"
34
42
  @delim_preference = ","
@@ -38,10 +46,16 @@ module Coopy
38
46
  when "ssv"
39
47
  @format_preference = "csv"
40
48
  @delim_preference = ";"
49
+ when "sqlite3"
50
+ @format_preference = "sqlite"
51
+ when "sqlite"
52
+ @format_preference = "sqlite"
41
53
  else
42
54
  ext = ""
43
55
  end
44
56
  end
57
+ @nested_output = @format_preference == "json" || @format_preference == "ndjson"
58
+ @order_preference = !@nested_output
45
59
  return ext
46
60
  end
47
61
 
@@ -55,12 +69,17 @@ module Coopy
55
69
  self.set_format(@output_format) if @output_format != "copy"
56
70
  txt = ""
57
71
  self.check_format(name)
58
- if @format_preference != "json"
72
+ if @format_preference == "csv"
59
73
  csv = ::Coopy::Csv.new(@delim_preference)
60
74
  txt = csv.render_table(t)
75
+ elsif @format_preference == "ndjson"
76
+ txt = ::Coopy::Ndjson.new(t).render
77
+ elsif @format_preference == "sqlite"
78
+ @io.write_stderr("! Cannot yet output to sqlite, aborting\n")
79
+ return false
61
80
  else
62
81
  value = ::Coopy::Coopy.jsonify(t)
63
- txt = ::Haxe::Format::JsonPrinter._print(value,nil,nil)
82
+ txt = ::Haxe::Format::JsonPrinter._print(value,nil," ")
64
83
  end
65
84
  return self.save_text(name,txt)
66
85
  end
@@ -77,14 +96,40 @@ module Coopy
77
96
  def load_table(name)
78
97
  txt = @io.get_content(name)
79
98
  ext = self.check_format(name)
99
+ if ext == "sqlite"
100
+ sql = @io.open_sqlite_database(name)
101
+ if sql == nil
102
+ @io.write_stderr("! Cannot open database, aborting\n")
103
+ return nil
104
+ end
105
+ helper = ::Coopy::SqliteHelper.new
106
+ names = helper.get_table_names(sql)
107
+ if names == nil
108
+ @io.write_stderr("! Cannot find database tables, aborting\n")
109
+ return nil
110
+ end
111
+ if names.length == 0
112
+ @io.write_stderr("! No tables in database, aborting\n")
113
+ return nil
114
+ end
115
+ tab = ::Coopy::SqlTable.new(sql,::Coopy::SqlTableName.new(names[0]),helper)
116
+ return tab
117
+ end
118
+ if ext == "ndjson"
119
+ t = ::Coopy::SimpleTable.new(0,0)
120
+ ndjson = ::Coopy::Ndjson.new(t)
121
+ ndjson.parse(txt)
122
+ return t
123
+ end
80
124
  begin
81
125
  json = ::Haxe::Format::JsonParser.new(txt).parse_rec
82
126
  @format_preference = "json"
83
- t = ::Coopy::Coopy.json_to_table(json)
84
- raise "JSON failed" if t == nil
85
- return t
127
+ t1 = ::Coopy::Coopy.json_to_table(json)
128
+ raise hx_raise("JSON failed") if t1 == nil
129
+ return t1
86
130
  rescue => e
87
- raise e if ext == "json"
131
+ e = hx_rescued(e)
132
+ raise hx_raise(e) if ext == "json"
88
133
  end if ext == "json" || ext == ""
89
134
  @format_preference = "csv"
90
135
  csv = ::Coopy::Csv.new(@delim_preference)
@@ -344,6 +389,19 @@ module Coopy
344
389
  git = true
345
390
  args.slice!(i,1)
346
391
  break
392
+ elsif tag == "--unordered"
393
+ more = true
394
+ flags.ordered = false
395
+ flags.unchanged_context = 0
396
+ @order_set = true
397
+ args.slice!(i,1)
398
+ break
399
+ elsif tag == "--ordered"
400
+ more = true
401
+ flags.ordered = true
402
+ @order_set = true
403
+ args.slice!(i,1)
404
+ break
347
405
  elsif tag == "--color"
348
406
  more = true
349
407
  color = true
@@ -415,7 +473,7 @@ module Coopy
415
473
  io.write_stderr("Call as:\n")
416
474
  io.write_stderr(" daff [--color] [--output OUTPUT.csv] a.csv b.csv\n")
417
475
  io.write_stderr(" daff [--output OUTPUT.csv] parent.csv a.csv b.csv\n")
418
- io.write_stderr(" daff [--output OUTPUT.jsonbook] a.jsonbook b.jsonbook\n")
476
+ io.write_stderr(" daff [--output OUTPUT.ndjson] a.ndjson b.ndjson\n")
419
477
  io.write_stderr(" daff patch [--inplace] [--output OUTPUT.csv] a.csv patch.csv\n")
420
478
  io.write_stderr(" daff merge [--inplace] [--output OUTPUT.csv] parent.csv a.csv b.csv\n")
421
479
  io.write_stderr(" daff trim [--output OUTPUT.csv] source.csv\n")
@@ -428,14 +486,16 @@ module Coopy
428
486
  io.write_stderr("\n")
429
487
  io.write_stderr("If you need more control, here is the full list of flags:\n")
430
488
  io.write_stderr(" daff diff [--output OUTPUT.csv] [--context NUM] [--all] [--act ACT] a.csv b.csv\n")
431
- io.write_stderr(" --id: specify column to use as primary key (repeat for multi-column key)\n")
432
- io.write_stderr(" --ignore: specify column to ignore completely (can repeat)\n")
489
+ io.write_stderr(" --act ACT: show only a certain kind of change (update, insert, delete)\n")
490
+ io.write_stderr(" --all: do not prune unchanged rows\n")
433
491
  io.write_stderr(" --color: highlight changes with terminal colors\n")
434
492
  io.write_stderr(" --context NUM: show NUM rows of context\n")
435
- io.write_stderr(" --all: do not prune unchanged rows\n")
436
- io.write_stderr(" --act ACT: show only a certain kind of change (update, insert, delete)\n")
493
+ io.write_stderr(" --id: specify column to use as primary key (repeat for multi-column key)\n")
494
+ io.write_stderr(" --ignore: specify column to ignore completely (can repeat)\n")
437
495
  io.write_stderr(" --input-format [csv|tsv|ssv|json]: set format to expect for input\n")
496
+ io.write_stderr(" --ordered: assume row order is meaningful (default for CSV)\n")
438
497
  io.write_stderr(" --output-format [csv|tsv|ssv|json|copy]: set format for output\n")
498
+ io.write_stderr(" --unordered: assume row order is meaningless (default for json formats)\n")
439
499
  io.write_stderr("\n")
440
500
  io.write_stderr(" daff diff --git path old-file old-hex old-mode new-file new-hex new-mode\n")
441
501
  io.write_stderr(" --git: process arguments provided by git to diff drivers\n")
@@ -501,6 +561,11 @@ module Coopy
501
561
  output = "-" if output == nil
502
562
  ok = true
503
563
  if cmd1 == "diff"
564
+ if !@order_set
565
+ flags.ordered = @order_preference
566
+ flags.unchanged_context = 0 if !flags.ordered
567
+ end
568
+ flags.allow_nested_cells = @nested_output
504
569
  ct1 = ::Coopy::Coopy.compare_tables3(parent,a,b,flags)
505
570
  align = ct1.align
506
571
  td = ::Coopy::TableDiff.new(align,flags)
@@ -545,7 +610,7 @@ module Coopy
545
610
  class << self
546
611
  attr_accessor :version
547
612
  end
548
- @version = "1.2.3"
613
+ @version = "1.2.4"
549
614
 
550
615
  def Coopy.compare_tables(local,remote,flags = nil)
551
616
  comp = ::Coopy::TableComparisonState.new
@@ -578,6 +643,7 @@ module Coopy
578
643
  hp = ::Coopy::HighlightPatch.new(nil,nil)
579
644
  csv = ::Coopy::Csv.new
580
645
  tm = ::Coopy::TableModifier.new(nil)
646
+ sc = ::Coopy::SqlCompare.new(nil,nil,nil)
581
647
  return 0
582
648
  end
583
649
 
@@ -697,11 +763,7 @@ module Coopy
697
763
  x = _g1
698
764
  _g1+=1
699
765
  v = t.get_cell(x,y)
700
- if v != nil
701
- row.push(v[:to_s].call)
702
- else
703
- row.push(nil)
704
- end
766
+ row.push(v)
705
767
  end
706
768
  end
707
769
  sheet.push(row)
data/lib/lib/coopy/csv.rb CHANGED
@@ -188,7 +188,7 @@ module Coopy
188
188
  return nil if result == "NULL"
189
189
  if first_non_underscore > start
190
190
  del = first_non_underscore - start
191
- return result[1..-1] if result[del..-1] == "NULL"
191
+ return HxOverrides.substr(result,1,nil) if HxOverrides.substr(result,del,nil) == "NULL"
192
192
  end
193
193
  end
194
194
  return result
@@ -17,6 +17,7 @@ module Coopy
17
17
  attr_accessor :td_close
18
18
  attr_accessor :open
19
19
  attr_accessor :pretty_arrows
20
+ attr_accessor :section
20
21
 
21
22
  public
22
23
 
@@ -32,6 +33,22 @@ module Coopy
32
33
 
33
34
  def begin_table
34
35
  self.insert("<table>\n")
36
+ @section = nil
37
+ end
38
+
39
+ def set_section(str)
40
+ return if str == @section
41
+ if @section != nil
42
+ self.insert("</t")
43
+ self.insert(@section)
44
+ self.insert(">\n")
45
+ end
46
+ @section = str
47
+ if @section != nil
48
+ self.insert("<t")
49
+ self.insert(@section)
50
+ self.insert(">\n")
51
+ end
35
52
  end
36
53
 
37
54
  def begin_row(mode)
@@ -41,9 +58,8 @@ module Coopy
41
58
  if mode == "header"
42
59
  @td_open = "<th"
43
60
  @td_close = "</th>"
44
- else
45
- row_class = mode
46
61
  end
62
+ row_class = mode
47
63
  tr = "<tr>"
48
64
  tr = "<tr class=\"" + _hx_str(row_class) + "\">" if row_class != ""
49
65
  self.insert(tr)
@@ -62,6 +78,7 @@ module Coopy
62
78
  end
63
79
 
64
80
  def end_table
81
+ self.set_section(nil)
65
82
  self.insert("</table>\n")
66
83
  end
67
84
 
@@ -80,9 +97,9 @@ module Coopy
80
97
  render = self
81
98
  render.begin_table
82
99
  change_row = -1
83
- tt = ::Coopy::TableText.new(tab)
84
100
  cell = ::Coopy::CellInfo.new
85
- corner = tt.get_cell_text(0,0)
101
+ view = tab.get_cell_view
102
+ corner = view.to_s(tab.get_cell(0,0))
86
103
  off = nil
87
104
  if corner == "@:@"
88
105
  off = 1
@@ -99,11 +116,16 @@ module Coopy
99
116
  row = _g1
100
117
  _g1+=1
101
118
  open = false
102
- txt = tt.get_cell_text(off,row)
119
+ txt = view.to_s(tab.get_cell(off,row))
103
120
  txt = "" if txt == nil
104
- ::Coopy::DiffRender.examine_cell(0,row,txt,"",txt,corner,cell)
121
+ ::Coopy::DiffRender.examine_cell(off,row,view,txt,"",txt,corner,cell,off)
105
122
  row_mode = cell.category
106
123
  change_row = row if row_mode == "spec"
124
+ if row_mode == "header" || row_mode == "spec" || row_mode == "index"
125
+ self.set_section("head")
126
+ else
127
+ self.set_section("body")
128
+ end
107
129
  render.begin_row(row_mode)
108
130
  begin
109
131
  _g3 = 0
@@ -111,7 +133,7 @@ module Coopy
111
133
  while(_g3 < _g2)
112
134
  c = _g3
113
135
  _g3+=1
114
- ::Coopy::DiffRender.examine_cell(c,row,tt.get_cell_text(c,row),((change_row >= 0) ? tt.get_cell_text(c,change_row) : ""),txt,corner,cell)
136
+ ::Coopy::DiffRender.examine_cell(c,row,view,tab.get_cell(c,row),((change_row >= 0) ? view.to_s(tab.get_cell(c,change_row)) : ""),txt,corner,cell,off)
115
137
  render.insert_cell(((@pretty_arrows) ? cell.pretty_value : cell.value),cell.category_given_tr)
116
138
  end
117
139
  end
@@ -123,17 +145,20 @@ module Coopy
123
145
  end
124
146
 
125
147
  def sample_css
126
- return ".highlighter .add { \n background-color: #7fff7f;\n}\n\n.highlighter .remove { \n background-color: #ff7f7f;\n}\n\n.highlighter td.modify { \n background-color: #7f7fff;\n}\n\n.highlighter td.conflict { \n background-color: #f00;\n}\n\n.highlighter .spec { \n background-color: #aaa;\n}\n\n.highlighter .move { \n background-color: #ffa;\n}\n\n.highlighter .null { \n color: #888;\n}\n\n.highlighter table { \n border-collapse:collapse;\n}\n\n.highlighter td, .highlighter th {\n border: 1px solid #2D4068;\n padding: 3px 7px 2px;\n}\n\n.highlighter th, .highlighter .header { \n background-color: #aaf;\n font-weight: bold;\n padding-bottom: 4px;\n padding-top: 5px;\n text-align:left;\n}\n\n.highlighter tr:first-child td {\n border-top: 1px solid #2D4068;\n}\n\n.highlighter td:first-child { \n border-left: 1px solid #2D4068;\n}\n\n.highlighter td {\n empty-cells: show;\n}\n"
148
+ return ".highlighter .add { \n background-color: #7fff7f;\n}\n\n.highlighter .remove { \n background-color: #ff7f7f;\n}\n\n.highlighter td.modify { \n background-color: #7f7fff;\n}\n\n.highlighter td.conflict { \n background-color: #f00;\n}\n\n.highlighter .spec { \n background-color: #aaa;\n}\n\n.highlighter .move { \n background-color: #ffa;\n}\n\n.highlighter .null { \n color: #888;\n}\n\n.highlighter table { \n border-collapse:collapse;\n}\n\n.highlighter td, .highlighter th {\n border: 1px solid #2D4068;\n padding: 3px 7px 2px;\n}\n\n.highlighter th, .highlighter .header { \n background-color: #aaf;\n font-weight: bold;\n padding-bottom: 4px;\n padding-top: 5px;\n text-align:left;\n}\n\n.highlighter tr.header th {\n border-bottom: 2px solid black;\n}\n\n.highlighter tr.index td, .highlighter .index, .highlighter tr.header th.index {\n background-color: white;\n border: none;\n}\n\n.highlighter .gap {\n color: #888;\n}\n\n.highlighter td {\n empty-cells: show;\n}\n"
127
149
  end
128
150
 
129
151
  def complete_html
130
- @text_to_insert.insert(0,"<html>\n<meta charset='utf-8'>\n<head>\n<style TYPE='text/css'>\n")
152
+ @text_to_insert.insert(0,"<!DOCTYPE html>\n<html>\n<head>\n<meta charset='utf-8'>\n<style TYPE='text/css'>\n")
131
153
  @text_to_insert.insert(1,self.sample_css)
132
154
  @text_to_insert.insert(2,"</style>\n</head>\n<body>\n<div class='highlighter'>\n")
133
155
  @text_to_insert.push("</div>\n</body>\n</html>\n")
134
156
  end
135
157
 
136
- def DiffRender.examine_cell(x,y,value,vcol,vrow,vcorner,cell)
158
+ def DiffRender.examine_cell(x,y,view,raw,vcol,vrow,vcorner,cell,offset = 0)
159
+ nested = view.is_hash(raw)
160
+ value = nil
161
+ value = view.to_s(raw) if !nested
137
162
  cell.category = ""
138
163
  cell.category_given_tr = ""
139
164
  cell.separator = ""
@@ -148,6 +173,7 @@ module Coopy
148
173
  vcol = "" if vcol == nil
149
174
  removed_column = false
150
175
  cell.category = "move" if vrow == ":"
176
+ cell.category = "index" if vrow == "" && offset == 1 && y == 0
151
177
  if (vcol.index("+++",nil || 0) || -1) >= 0
152
178
  cell.category_given_tr = cell.category = "add"
153
179
  elsif (vcol.index("---",nil || 0) || -1) >= 0
@@ -158,6 +184,8 @@ module Coopy
158
184
  cell.category = "spec"
159
185
  elsif vrow == "@@"
160
186
  cell.category = "header"
187
+ elsif vrow == "..."
188
+ cell.category = "gap"
161
189
  elsif vrow == "+++"
162
190
  cell.category = "add" if !removed_column
163
191
  elsif vrow == "---"
@@ -168,20 +196,30 @@ module Coopy
168
196
  full = vrow
169
197
  part = tokens[1]
170
198
  part = full if part == nil
171
- if (cell.value.index(part,nil || 0) || -1) >= 0
199
+ if nested || (cell.value.index(part,nil || 0) || -1) >= 0
172
200
  cat = "modify"
173
201
  div = part
174
202
  if part != full
175
- if (cell.value.index(full,nil || 0) || -1) >= 0
203
+ if nested
204
+ cell.conflicted = view.hash_exists(raw,"theirs")
205
+ else
206
+ cell.conflicted = (cell.value.index(full,nil || 0) || -1) >= 0
207
+ end
208
+ if cell.conflicted
176
209
  div = full
177
210
  cat = "conflict"
178
- cell.conflicted = true
179
211
  end
180
212
  end
181
213
  cell.updated = true
182
214
  cell.separator = div
183
215
  cell.pretty_separator = div
184
- if cell.pretty_value == div
216
+ if nested
217
+ if cell.conflicted
218
+ tokens = [view.hash_get(raw,"before"),view.hash_get(raw,"ours"),view.hash_get(raw,"theirs")]
219
+ else
220
+ tokens = [view.hash_get(raw,"before"),view.hash_get(raw,"after")]
221
+ end
222
+ elsif cell.pretty_value == div
185
223
  tokens = ["",""]
186
224
  else
187
225
  tokens = cell.pretty_value.split(div)
@@ -199,18 +237,19 @@ module Coopy
199
237
  cell.pretty_separator = [8594].pack("U")
200
238
  cell.pretty_value = pretty_tokens.join(cell.pretty_separator)
201
239
  cell.category_given_tr = cell.category = cat
202
- offset = nil
240
+ offset1 = nil
203
241
  if cell.conflicted
204
- offset = 1
242
+ offset1 = 1
205
243
  else
206
- offset = 0
244
+ offset1 = 0
207
245
  end
208
- cell.lvalue = tokens[offset]
209
- cell.rvalue = tokens[offset + 1]
246
+ cell.lvalue = tokens[offset1]
247
+ cell.rvalue = tokens[offset1 + 1]
210
248
  cell.pvalue = tokens[0] if cell.conflicted
211
249
  end
212
250
  end
213
251
  end
252
+ cell.category_given_tr = cell.category = "index" if x == 0 && offset > 0
214
253
  end
215
254
 
216
255
  # protected - in ruby this doesn't play well with static/inline methods
@@ -244,16 +283,16 @@ module Coopy
244
283
 
245
284
  public
246
285
 
247
- def DiffRender.render_cell(tt,x,y)
286
+ def DiffRender.render_cell(tab,view,x,y)
248
287
  cell = ::Coopy::CellInfo.new
249
- corner = tt.get_cell_text(0,0)
288
+ corner = view.to_s(tab.get_cell(0,0))
250
289
  off = nil
251
290
  if corner == "@:@"
252
291
  off = 1
253
292
  else
254
293
  off = 0
255
294
  end
256
- ::Coopy::DiffRender.examine_cell(x,y,tt.get_cell_text(x,y),tt.get_cell_text(x,off),tt.get_cell_text(off,y),corner,cell)
295
+ ::Coopy::DiffRender.examine_cell(x,y,view,tab.get_cell(x,y),view.to_s(tab.get_cell(x,off)),view.to_s(tab.get_cell(off,y)),corner,cell,off)
257
296
  return cell
258
297
  end
259
298