di 0.1.4 → 0.1.5

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 (7) hide show
  1. data/HISTORY +4 -0
  2. data/README.rdoc +1 -1
  3. data/Rakefile +1 -0
  4. data/VERSION +1 -1
  5. data/bin/di +217 -6
  6. data/di.gemspec +2 -1
  7. metadata +6 -4
data/HISTORY CHANGED
@@ -1,5 +1,9 @@
1
1
  * Add --[no-]pager and turn it on by default.
2
2
 
3
+ * Add --[no-]color and colorize diff output by default.
4
+
5
+ * Read user's preferred default options from DI_OPTIONS.
6
+
3
7
  * Do not choke on file names starting with a hyphen.
4
8
 
5
9
  == 0.1.3 2010-03-10
@@ -31,7 +31,7 @@ Run di --help for help.
31
31
 
32
32
  == REQUIREMENTS:
33
33
 
34
- - Ruby 1.8.6 or later
34
+ - Ruby 1.8.7 or later
35
35
 
36
36
  - GNU diff(1)
37
37
 
data/Rakefile CHANGED
@@ -13,6 +13,7 @@ EOS
13
13
  gem.email = "knu@idaemons.org"
14
14
  gem.homepage = "http://github.com/knu/di"
15
15
  gem.authors = ["Akinori MUSHA"]
16
+ gem.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
16
17
  gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
17
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
18
19
  gem.executables = ["di"]
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.4
1
+ 0.1.5
data/bin/di CHANGED
@@ -73,8 +73,24 @@ def setup
73
73
  $diff.include = []
74
74
  $diff.flags = []
75
75
  $diff.format_flags = []
76
+ $diff.format = :normal
76
77
  $diff.custom_format_p = false
77
78
  $diff.use_pager = false
79
+ $diff.colorize = false
80
+ $diff.highlight_whitespace = true
81
+ $diff.colors = {
82
+ :comment => "\033[1m",
83
+ :file1 => "\033[1m",
84
+ :file2 => "\033[1m",
85
+ :header => "\033[36m",
86
+ :function => "\033[m",
87
+ :new => "\033[32m",
88
+ :old => "\033[31m",
89
+ :changed => "\033[33m",
90
+ :unchanged => "",
91
+ :whitespace => "\033[41m",
92
+ :off => "\033[m",
93
+ }
78
94
  end
79
95
 
80
96
  def parse_args!(args)
@@ -94,8 +110,12 @@ usage: #{MYNAME} [flags] [files]
94
110
  opts.accept(miniTrueClass, hash) {|arg, val| val == nil or val}
95
111
 
96
112
  opts.on('--[no-]pager',
97
- 'Pipe output into $PAGER (or more(1) if not defined) if stdout is a terminal. [!][*]') { |val|
98
- $diff.use_pager = val
113
+ 'Pipe output into pager if stdout is a terminal. [!][*]') { |val|
114
+ $diff.use_pager = val if $stdout.tty?
115
+ }
116
+ opts.on('--[no-]color',
117
+ 'Colorize output if stdout is a terminal and the format is unified or context. [!][*]') { |val|
118
+ $diff.colorize = val if $stdout.tty?
99
119
  }
100
120
  opts.on('--[no-]rsync-exclude', '--[no-]cvs-exclude',
101
121
  'Exclude some kinds of files and directories a la rsync(1). [!][*]') { |val|
@@ -339,14 +359,26 @@ usage: #{MYNAME} [flags] [files]
339
359
  Options without the [*] sign will be passed through to diff(1).
340
360
  Options marked as [!] sign are turned on by default. To turn them off,
341
361
  specify -?- for short options and --no-??? for long options, respectively.
362
+
363
+ Environment variables:
364
+ DIFF Path to diff(1)
365
+ DI_OPTIONS User's preferred default options
366
+ PAGER Path to pager (more(1) is used if not defined)
342
367
  EOS
343
368
  exit 0
344
369
  }
345
370
  }
346
371
 
347
372
  begin
348
- opts.parse('--rsync-exclude', '--fignore-exclude', '--ignore-cvs-lines', '--pager',
373
+ opts.parse('--rsync-exclude', '--fignore-exclude', '--ignore-cvs-lines',
374
+ '--pager', '--color',
349
375
  '-U3', '-N', '-r', '-p', '-d')
376
+
377
+ if value = ENV['DI_OPTIONS']
378
+ require 'shellwords'
379
+ opts.parse(*value.shellsplit)
380
+ end
381
+
350
382
  opts.parse!(args)
351
383
 
352
384
  $diff.format_flags.each { |format_flag|
@@ -401,20 +433,28 @@ EOS
401
433
  end
402
434
 
403
435
  def invoke_pager
404
- invoke_pager! if $diff.use_pager && $stdout.tty?
436
+ invoke_pager! if $diff.use_pager
405
437
  end
406
438
 
407
439
  def invoke_pager!
408
440
  $stdout.flush
409
441
  $stderr.flush
410
442
  pr, pw = IO.pipe
443
+ ppid = Process.pid
411
444
  pid = fork {
412
445
  $stdin.reopen(pr)
413
446
  pr.close
414
447
  pw.close
415
448
  IO.select([$stdin], nil, [$stdin])
416
- exec(ENV['PAGER'] || 'more')
449
+ if system(ENV['PAGER'] || 'more')
450
+ Process.kill(:TERM, ppid)
451
+ else
452
+ $stderr.puts "Pager failed."
453
+ Process.kill(:INT, ppid)
454
+ end
417
455
  }
456
+ trap(:TERM) { exit(0) }
457
+ trap(:INT) { exit(130) }
418
458
  $stdout.reopen(pw)
419
459
  $stderr.reopen(pw) if $stderr.tty?
420
460
  pw.close
@@ -442,6 +482,24 @@ end
442
482
  def set_format_flag(flag, *val)
443
483
  $diff.format_flags.clear
444
484
  $diff.custom_format_p = false
485
+ case flag
486
+ when '-C'
487
+ $diff.format = :context
488
+ when '-U'
489
+ $diff.format = :unified
490
+ when '-e'
491
+ $diff.format = :ed
492
+ when '--normal'
493
+ $diff.format = :normal
494
+ when '-n'
495
+ $diff.format = :rcs
496
+ when '-y'
497
+ $diff.format = :side_by_side
498
+ when '-D'
499
+ $diff.format = :ifdef
500
+ else
501
+ $diff.format = :unknown
502
+ end
445
503
  $diff.format_flags.push([flag, *val])
446
504
  end
447
505
 
@@ -450,6 +508,7 @@ def set_custom_format_flag(flag, *val)
450
508
  $diff.format_flags.clear
451
509
  $diff.custom_format_p = true
452
510
  end
511
+ $diff.format = :custom
453
512
  $diff.format_flags.push([flag, *val])
454
513
  end
455
514
 
@@ -509,7 +568,21 @@ def diff_files(file1, file2)
509
568
  end
510
569
 
511
570
  def call_diff(*args)
512
- system(*[DIFF_CMD, $diff.flags, args].flatten)
571
+ command_args = [DIFF_CMD, $diff.flags, args].flatten
572
+ if $diff.colorize
573
+ case $diff.format
574
+ when :unified
575
+ filter = method(:colorize_unified_diff)
576
+ when :context
577
+ filter = method(:colorize_context_diff)
578
+ end
579
+ end
580
+ if filter
581
+ require 'shellwords'
582
+ filter.call(IO.popen(command_args.shelljoin, 'r'))
583
+ else
584
+ system(*command_args)
585
+ end
513
586
  status = $? >> 8
514
587
  $status = status if $status < status
515
588
  return status
@@ -594,4 +667,142 @@ def diff_exclude?(basename)
594
667
  return false
595
668
  end
596
669
 
670
+ def colorize_unified_diff(io)
671
+ colors = $diff.colors
672
+
673
+ state = :comment
674
+ hunk_left = nil
675
+ io.each_line { |line|
676
+ case state
677
+ when :comment
678
+ case line
679
+ when /^\+{3} /
680
+ color = colors[:file1]
681
+ when /^-{3} /
682
+ color = colors[:file2]
683
+ when /^@@ -[0-9]+,([0-9]+)/
684
+ state = :hunk
685
+ hunk_left = $1.to_i
686
+ line.sub!(/^(@@ .*? @@)( )?/) {
687
+ $1 + ($2 ? colors[:off] + $2 + colors[:function] : '')
688
+ }
689
+ color = colors[:header]
690
+ else
691
+ color = colors[:comment]
692
+ end
693
+ when :hunk
694
+ check = false
695
+ case line
696
+ when /^\+/
697
+ color = colors[:new]
698
+ check = $diff.highlight_whitespace
699
+ when /^-/
700
+ color = colors[:old]
701
+ hunk_left -= 1
702
+ check = $diff.highlight_whitespace
703
+ when /^ /
704
+ color = colors[:unchanged]
705
+ hunk_left -= 1
706
+ else
707
+ # error
708
+ color = colors[:comment]
709
+ end
710
+ if check
711
+ line.sub!(/([ \t]+)$/) {
712
+ colors[:off] + colors[:whitespace] + $1
713
+ }
714
+ end
715
+ if hunk_left <= 0
716
+ state = :comment
717
+ hunk_left = nil
718
+ end
719
+ end
720
+
721
+ line.sub!(/^/, color)
722
+ line.sub!(/$/, colors[:off])
723
+
724
+ print line
725
+ }
726
+
727
+ io.close
728
+ end
729
+
730
+ def colorize_context_diff(io)
731
+ colors = $diff.colors
732
+
733
+ state = :comment
734
+ hunk_part = nil
735
+ io.each_line { |line|
736
+ case state
737
+ when :comment
738
+ case line
739
+ when /^\*{3} /
740
+ color = colors[:file1]
741
+ when /^-{3} /
742
+ color = colors[:file2]
743
+ when /^\*{15}/
744
+ state = :hunk
745
+ hunk_part = 0
746
+ line.sub!(/^(\*{15})( )?/) {
747
+ $1 + ($2 ? colors[:off] + $2 + colors[:function] : '')
748
+ }
749
+ color = colors[:header]
750
+ end
751
+ when :hunk
752
+ case hunk_part
753
+ when 0
754
+ case line
755
+ when /^\*{3} /
756
+ hunk_part = 1
757
+ color = colors[:header]
758
+ else
759
+ # error
760
+ color = colors[:comment]
761
+ end
762
+ when 1, 2
763
+ check = false
764
+ case line
765
+ when /^\-{3} /
766
+ if hunk_part == 1
767
+ hunk_part = 2
768
+ color = colors[:header]
769
+ else
770
+ #error
771
+ color = colors[:comment]
772
+ end
773
+ when /^\*{3} /, /^\*{15} /
774
+ state = :comment
775
+ redo
776
+ when /^\+ /
777
+ color = colors[:new]
778
+ check = $diff.highlight_whitespace
779
+ when /^- /
780
+ color = colors[:old]
781
+ check = $diff.highlight_whitespace
782
+ when /^! /
783
+ color = colors[:changed]
784
+ check = $diff.highlight_whitespace
785
+ when /^ /
786
+ color = colors[:unchanged]
787
+ else
788
+ # error
789
+ color = colors[:comment]
790
+ end
791
+ if check
792
+ line.sub!(/^(...*)([ \t]+)$/) {
793
+ $1 + colors[:off] + colors[:whitespace] + $2
794
+ }
795
+ end
796
+ end
797
+ end
798
+
799
+ line.sub!(/^/, color)
800
+ line.sub!(/$/, colors[:off])
801
+
802
+ print line
803
+ }
804
+
805
+ io.close
806
+ end
807
+
597
808
  main(ARGV)
data/di.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{di}
8
- s.version = "0.1.4"
8
+ s.version = "0.1.5"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Akinori MUSHA"]
@@ -36,6 +36,7 @@ default settings and some original features.
36
36
  s.homepage = %q{http://github.com/knu/di}
37
37
  s.rdoc_options = ["--charset=UTF-8"]
38
38
  s.require_paths = ["lib"]
39
+ s.required_ruby_version = Gem::Requirement.new(">= 1.8.7")
39
40
  s.rubygems_version = %q{1.3.6}
40
41
  s.summary = %q{A wrapper around GNU diff(1)}
41
42
  s.test_files = [
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 4
9
- version: 0.1.4
8
+ - 5
9
+ version: 0.1.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Akinori MUSHA
@@ -67,8 +67,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  segments:
70
- - 0
71
- version: "0"
70
+ - 1
71
+ - 8
72
+ - 7
73
+ version: 1.8.7
72
74
  required_rubygems_version: !ruby/object:Gem::Requirement
73
75
  requirements:
74
76
  - - ">="