di 0.3.2 → 0.4.0

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 (4) hide show
  1. checksums.yaml +7 -0
  2. data/di.gemspec +1 -0
  3. data/lib/di.rb +233 -80
  4. metadata +24 -14
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 85e6d0dda9d8ab2f37c5781743238023291f5d3a
4
+ data.tar.gz: d08a5f0ea260bdd94ff720f73670490acdebf649
5
+ SHA512:
6
+ metadata.gz: 672d1f491243ad2ede807e4176ced0c0fa216965a223e2ea8e8bf44b853cb93ea8d792fb6fa5031708c31b84603d65f2b4a8a79ce03de371bda958983ede1e17
7
+ data.tar.gz: b5fd0a90f9bace17a97e72b3df21259d96f768b14042b0e1bd5623175b547f16ab2c44d9835905de9402f4c4c03bdf469c9741c221631a7c3943dbadd9c7dbde
data/di.gemspec CHANGED
@@ -25,4 +25,5 @@ EOS
25
25
  gem.require_paths = ["lib"]
26
26
 
27
27
  gem.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
28
+ gem.add_runtime_dependency("diff-lcs", ["~> 1.2.2"])
28
29
  end
data/lib/di.rb CHANGED
@@ -28,7 +28,7 @@
28
28
  # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
29
  # SUCH DAMAGE.
30
30
 
31
- MYVERSION = "0.3.2"
31
+ MYVERSION = "0.4.0"
32
32
  MYNAME = File.basename($0)
33
33
  MYCOPYRIGHT = "Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Akinori MUSHA"
34
34
 
@@ -59,6 +59,10 @@ FIGNORE_GLOBS = ENV.fetch('FIGNORE', '').split(':').map { |pat|
59
59
 
60
60
  IO::NULL = '/dev/null' unless defined? IO::NULL
61
61
 
62
+ PLUS_SIGN = '+'
63
+ MINUS_SIGN = '-'
64
+ EQUAL_SIGN = '='
65
+
62
66
  def main(args)
63
67
  setup
64
68
 
@@ -77,28 +81,32 @@ end
77
81
 
78
82
  def setup
79
83
  require 'ostruct'
80
- $diff = OpenStruct.new
81
- $diff.exclude = []
82
- $diff.include = []
83
- $diff.flags = []
84
- $diff.format_flags = []
85
- $diff.format = :normal
86
- $diff.colors = {
87
- :comment => "\e[1m",
88
- :file1 => "\e[1m",
89
- :file2 => "\e[1m",
90
- :header => "\e[36m",
91
- :function => "\e[m",
92
- :new => "\e[32m",
93
- :old => "\e[31m",
94
- :changed => "\e[33m",
95
- :unchanged => "",
96
- :whitespace => "\e[41m",
97
- :off => "\e[m",
98
- :open_inv => "\e[7m",
99
- :close_inv => "\e[27m",
100
- }
101
- $diff.reversed = false
84
+ $diff = OpenStruct.new({
85
+ :exclude => [],
86
+ :include => [],
87
+ :flags => [],
88
+ :format_flags => [],
89
+ :format => :normal,
90
+ :colors => OpenStruct.new({
91
+ :comment => "\e[1m",
92
+ :file1 => "\e[1m",
93
+ :file2 => "\e[1m",
94
+ :header => "\e[36m",
95
+ :function => "\e[m",
96
+ :new => "\e[32m",
97
+ :old => "\e[31m",
98
+ :new_word => "\e[7;32m",
99
+ :old_word => "\e[7;31m",
100
+ :changed => "\e[33m",
101
+ :unchanged => "",
102
+ :whitespace => "\e[40m",
103
+ :off => "\e[m",
104
+ :open_inv => "\e[7m",
105
+ :close_inv => "\e[27m",
106
+ }),
107
+ :reversed => false,
108
+ :word_regex => /([@$%]*[[:alnum:]_]+|[^\n])/,
109
+ })
102
110
  end
103
111
 
104
112
  def parse_args!(args)
@@ -127,7 +135,7 @@ usage: #{MYNAME} [flags] [files]
127
135
  $diff.colorize = val if $stdout.tty?
128
136
  }
129
137
  opts.on('--[no-]highlight-whitespace',
130
- 'Highlight suspicious whitespace differences in colorized output. [+][*]') { |val|
138
+ 'Highlight whitespace differences in colorized output. [+][*]') { |val|
131
139
  $diff.highlight_whitespace = val
132
140
  }
133
141
  opts.on('--[no-]rsync-exclude', '--[no-]cvs-exclude',
@@ -702,91 +710,229 @@ def diff_exclude?(dir, basename)
702
710
  end
703
711
 
704
712
  def colorize_unified_diff(io)
713
+ begin
714
+ require 'diff/lcs'
715
+ colorize_unified_diff_hunk = method(:colorize_hunk_in_unified_diff_inline)
716
+ rescue LoadError
717
+ colorize_unified_diff_hunk = method(:colorize_hunk_in_unified_diff_normal)
718
+ end
719
+
705
720
  colors = $diff.colors
721
+ colors.to_function ||= colors.off + colors.function
706
722
 
707
723
  state = :comment
708
724
  hunk_left = nil
725
+ hunk = []
709
726
  io.each_line { |line|
727
+ line.chomp!
710
728
  replace_invalid_bytes!(line)
711
729
  case state
712
730
  when :comment
713
731
  case line
714
732
  when /^\+{3} /
715
- color = colors[:file1]
733
+ color = colors.file1
716
734
  when /^-{3} /
717
- color = colors[:file2]
735
+ color = colors.file2
718
736
  when /^@@ -[0-9]+(,([0-9]+))? \+[0-9]+(,([0-9]+))?/
719
737
  state = :hunk
720
738
  hunk_left = ($1 ? $2.to_i : 1) + ($3 ? $4.to_i : 1)
721
- line.sub!(/^(@@ .*? @@)( )?/) {
722
- $1 + ($2 ? colors[:off] + $2 + colors[:function] : '')
739
+ line.sub!(/^(@@ .*? @@ )/) {
740
+ $1 + colors.to_function
723
741
  }
724
- color = colors[:header]
742
+ color = colors.header
725
743
  else
726
- color = colors[:comment]
744
+ color = colors.comment
727
745
  end
728
746
  when :hunk
729
- check = false
747
+ hunk << line
730
748
  case line
731
- when /^\+/
732
- color = colors[:new]
733
- hunk_left -= 1
734
- check = $diff.highlight_whitespace
735
- when /^-/
736
- color = colors[:old]
749
+ when /^[-+]/
737
750
  hunk_left -= 1
738
- check = $diff.highlight_whitespace
739
751
  when /^ /
740
- color = colors[:unchanged]
741
752
  hunk_left -= 2
742
- else
743
- # error
744
- color = colors[:comment]
745
- end
746
- if check
747
- line.sub!(/([ \t]+)$/) {
748
- colors[:off] + colors[:whitespace] + $1
749
- }
750
- true while line.sub!(/^(.[ \t]*)( +)(\t)/) {
751
- $1 + colors[:off] + colors[:whitespace] + $2 + colors[:off] + color + $3
752
- }
753
753
  end
754
754
  if hunk_left <= 0
755
- state = :comment
755
+ colorize_unified_diff_hunk.call(hunk)
756
756
  hunk_left = nil
757
+ hunk.clear
758
+ state = :comment
757
759
  end
760
+ next
758
761
  end
759
762
 
760
- line.sub!(/^/, color)
761
- line.sub!(/$/, colors[:off])
762
-
763
- print line
763
+ print color, line, colors.off, "\n"
764
764
  }
765
765
 
766
766
  io.close
767
767
  end
768
768
 
769
+ def colorize_hunk_in_unified_diff_normal(hunk)
770
+ colors = $diff.colors
771
+
772
+ hunk.each { |line|
773
+ case line
774
+ when /^\+/
775
+ color = colors.new
776
+ ws = $diff.highlight_whitespace
777
+ when /^-/
778
+ color = colors.old
779
+ ws = $diff.highlight_whitespace
780
+ when /^ /
781
+ color = colors.unchanged
782
+ ws = false
783
+ end
784
+ if ws
785
+ highlight_whitespace_in_unified_diff!(line, color)
786
+ end
787
+ print color, line, colors.off, "\n"
788
+ }
789
+ end
790
+
791
+ def colorize_hunk_in_unified_diff_inline(hunk)
792
+ colors = $diff.colors
793
+
794
+ skip_next = false
795
+
796
+ Enumerator.new { |y|
797
+ y << nil
798
+ hunk.each { |line|
799
+ y << line
800
+ }
801
+ y << nil << nil
802
+ }.each_cons(4) { |line0, line1, line2, line3|
803
+ case
804
+ when skip_next
805
+ skip_next = false
806
+ next
807
+ when line1.nil?
808
+ break
809
+ when /^[-+]/ !~ line0 && /^-/ =~ line1 && /^\+/ =~ line2 && /^[-+]/ !~ line3
810
+ colorize_inline_diff(line1, line2)
811
+ skip_next = true
812
+ next
813
+ when /^\+/ =~ line1
814
+ color = colors.new
815
+ ws = $diff.highlight_whitespace
816
+ when /^-/ =~ line1
817
+ color = colors.old
818
+ ws = $diff.highlight_whitespace
819
+ when /^ / =~ line1
820
+ color = colors.unchanged
821
+ ws = false
822
+ end
823
+ if ws
824
+ line1 = line1.dup
825
+ highlight_whitespace_in_unified_diff!(line1, color)
826
+ end
827
+ print color, line1, colors.off, "\n"
828
+ }
829
+ end
830
+
831
+ def colorize_inline_diff(line1, line2)
832
+ words1, words2 = [line1, line2].map { |line|
833
+ line[1..-1].split($diff.word_regex)
834
+ }
835
+ xwords1, xwords2 = [words1, words2].map { |words|
836
+ words.each_with_index.map { |word, i| i.even? ? nil : word }
837
+ }
838
+ swords1, swords2, signs1, signs2 = [], [], [], []
839
+
840
+ Diff::LCS.sdiff(xwords1, xwords2).each { |tuple|
841
+ sign, (pos1, word1), (pos2, word2) = *tuple
842
+ case sign
843
+ when PLUS_SIGN
844
+ if signs2.last == sign
845
+ swords2.last << word2 if word2
846
+ else
847
+ swords2 << (word2 || '')
848
+ signs2 << sign
849
+ end
850
+ when MINUS_SIGN
851
+ if signs1.last == sign
852
+ swords1.last << word1 if word1
853
+ else
854
+ swords1 << (word1 || '')
855
+ signs1 << sign
856
+ end
857
+ else
858
+ if signs1.last == sign
859
+ swords1.last << words1[pos1]
860
+ else
861
+ swords1 << words1[pos1]
862
+ signs1 << sign
863
+ end
864
+ if signs2.last == sign
865
+ swords2.last << words2[pos2]
866
+ else
867
+ swords2 << words2[pos2]
868
+ signs2 << sign
869
+ end
870
+ end
871
+ }
872
+
873
+ colors = $diff.colors
874
+
875
+ aline1 = ''.tap { |line|
876
+ signs1.zip(swords1) { |sign, word|
877
+ case sign
878
+ when EQUAL_SIGN
879
+ line << colors.off << colors.old << word
880
+ else
881
+ line << colors.off << colors.old_word << word
882
+ end
883
+ }
884
+ }
885
+ aline2 = ''.tap { |line|
886
+ signs2.zip(swords2) { |sign, word|
887
+ case sign
888
+ when EQUAL_SIGN
889
+ line << colors.off << colors.new << word
890
+ else
891
+ line << colors.off << colors.new_word << word
892
+ end
893
+ }
894
+ }
895
+
896
+ print colors.old, '-', aline1, "\n",
897
+ colors.new, '+', aline2, "\n"
898
+ end
899
+
900
+ def highlight_whitespace_in_unified_diff!(line, color)
901
+ colors = $diff.colors
902
+ colors.to_whitespace ||= colors.off + colors.whitespace
903
+
904
+ line.gsub!(/([ \t]+)$|( +)(?=\t)/) {
905
+ if $1
906
+ colors.to_whitespace + $1
907
+ else
908
+ colors.to_whitespace + $2 << colors.off << color
909
+ end
910
+ }
911
+ end
912
+
769
913
  def colorize_context_diff(io)
770
914
  colors = $diff.colors
915
+ colors.to_function ||= colors.off + colors.function
771
916
 
772
917
  state = :comment
773
918
  hunk_part = nil
774
919
  io.each_line { |line|
920
+ line.chomp!
775
921
  replace_invalid_bytes!(line)
776
922
  case state
777
923
  when :comment
778
924
  case line
779
925
  when /^\*{3} /
780
- color = colors[:file1]
926
+ color = colors.file1
781
927
  when /^-{3} /
782
- color = colors[:file2]
928
+ color = colors.file2
783
929
  when /^\*{15}/
784
930
  state = :hunk
785
931
  hunk_part = 0
786
- line.sub!(/^(\*{15})( )?/) {
787
- $1 + ($2 ? colors[:off] + $2 + colors[:function] : '')
932
+ line.sub!(/^(\*{15} )/) {
933
+ $1 + colors.to_function
788
934
  }
789
- color = colors[:header]
935
+ color = colors.header
790
936
  end
791
937
  when :hunk
792
938
  case hunk_part
@@ -794,10 +940,10 @@ def colorize_context_diff(io)
794
940
  case line
795
941
  when /^\*{3} /
796
942
  hunk_part = 1
797
- color = colors[:header]
943
+ color = colors.header
798
944
  else
799
945
  # error
800
- color = colors[:comment]
946
+ color = colors.comment
801
947
  end
802
948
  when 1, 2
803
949
  check = false
@@ -805,53 +951,60 @@ def colorize_context_diff(io)
805
951
  when /^\-{3} /
806
952
  if hunk_part == 1
807
953
  hunk_part = 2
808
- color = colors[:header]
954
+ color = colors.header
809
955
  else
810
956
  #error
811
- color = colors[:comment]
957
+ color = colors.comment
812
958
  end
813
959
  when /^\*{3} /, /^\*{15} /
814
960
  state = :comment
815
961
  redo
816
962
  when /^\+ /
817
- color = colors[:new]
963
+ color = colors.new
818
964
  check = $diff.highlight_whitespace
819
965
  when /^- /
820
- color = colors[:old]
966
+ color = colors.old
821
967
  check = $diff.highlight_whitespace
822
968
  when /^! /
823
- color = colors[:changed]
969
+ color = colors.changed
824
970
  check = $diff.highlight_whitespace
825
971
  when /^ /
826
- color = colors[:unchanged]
972
+ color = colors.unchanged
827
973
  else
828
974
  # error
829
- color = colors[:comment]
975
+ color = colors.comment
830
976
  end
831
977
  if check
832
- line.sub!(/^(. .*)([ \t]+)$/) {
833
- $1 + colors[:off] + colors[:whitespace] + $2
834
- }
835
- true while line.sub!(/^(. [ \t]*)( +)(\t)/) {
836
- $1 + colors[:off] + colors[:whitespace] + $2 + colors[:off] + color + $3
837
- }
978
+ highlight_whitespace_in_context_diff!(line, color)
838
979
  end
839
980
  end
840
981
  end
841
982
 
842
- line.sub!(/^/, color)
843
- line.sub!(/$/, colors[:off])
844
-
845
- print line
983
+ print color, line, colors.off, "\n"
846
984
  }
847
985
 
848
986
  io.close
849
987
  end
850
988
 
989
+ def highlight_whitespace_in_context_diff!(line, color)
990
+ colors = $diff.colors
991
+ colors.to_whitespace ||= colors.off + colors.whitespace
992
+
993
+ line.gsub!(/^(..)|([ \t]+)$|( +)(?=\t)/) {
994
+ if $1
995
+ $1
996
+ elsif $2
997
+ colors.to_whitespace + $2
998
+ else
999
+ colors.to_whitespace + $3 << colors.off << color
1000
+ end
1001
+ }
1002
+ end
1003
+
851
1004
  def replace_invalid_bytes!(text)
852
1005
  colors = $diff.colors
853
1006
  text.replace(text.replace_invalid_bytes { |byte|
854
- '%s<%02X>%s' % [colors[:open_inv], byte, colors[:close_inv]]
1007
+ '%s<%02X>%s' % [colors.open_inv, byte, colors.close_inv]
855
1008
  })
856
1009
  end
857
1010
 
metadata CHANGED
@@ -1,21 +1,32 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: di
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
5
- prerelease:
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Akinori MUSHA
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-01-09 00:00:00.000000000 Z
13
- dependencies: []
14
- description: ! 'The di(1) command wraps around GNU diff(1) to provide reasonable
15
-
11
+ date: 2013-04-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: diff-lcs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 1.2.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 1.2.2
27
+ description: |
28
+ The di(1) command wraps around GNU diff(1) to provide reasonable
16
29
  default settings and some original features.
17
-
18
- '
19
30
  email:
20
31
  - knu@idaemons.org
21
32
  executables:
@@ -38,27 +49,26 @@ files:
38
49
  - test/test_di.rb
39
50
  homepage: https://github.com/knu/di
40
51
  licenses: []
52
+ metadata: {}
41
53
  post_install_message:
42
54
  rdoc_options: []
43
55
  require_paths:
44
56
  - lib
45
57
  required_ruby_version: !ruby/object:Gem::Requirement
46
- none: false
47
58
  requirements:
48
- - - ! '>='
59
+ - - '>='
49
60
  - !ruby/object:Gem::Version
50
61
  version: 1.8.7
51
62
  required_rubygems_version: !ruby/object:Gem::Requirement
52
- none: false
53
63
  requirements:
54
- - - ! '>='
64
+ - - '>='
55
65
  - !ruby/object:Gem::Version
56
66
  version: '0'
57
67
  requirements: []
58
68
  rubyforge_project:
59
- rubygems_version: 1.8.24
69
+ rubygems_version: 2.0.3
60
70
  signing_key:
61
- specification_version: 3
71
+ specification_version: 4
62
72
  summary: A wrapper around GNU diff(1)
63
73
  test_files:
64
74
  - test/helper.rb