di 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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