git-crecord 1.0.8 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4f6c8a30051ca52a3a3406430672f24506e6f30b
4
- data.tar.gz: c06ab9d96429ae54b0a4f126341a627e6a722b98
2
+ SHA256:
3
+ metadata.gz: 9faaad49aba11b3aad863f3923f1249cd6d83ae88148405bcb0799f6019cb6c5
4
+ data.tar.gz: 5ee14973f732a9117c37ea52cbc3040cdb4c4331a4342efb8624143121f84d87
5
5
  SHA512:
6
- metadata.gz: d06b9d27174afc185dbd30a5aa34958a15b6340067bc80de05c2296ac13df9e513d0b3986627cd23b3ecd1ca9ee01163bbb752f9e85bb41a822ce847d07f811d
7
- data.tar.gz: 9ad67d7e9f9b06b7fb17545d0a1d22c9741439671aaebcfe6d184f118309a28a7fc55272c0eea8596136876984908e5a0fa22d86ed3ae6ab158ea134c9659461
6
+ metadata.gz: 23c240bc80cda76c5aa13bd2d296b1a8f65a40a0364ea5eea0098f51b8af5f69a40f189a67abe8be19ac98f240e6bfd14f432aa051268e33352067305661c7c8
7
+ data.tar.gz: 8259cb00118d75e7ee7aa49c57ae949197fae66a6cc20e24a1644890fc4691a8049d88834dc91778d9689cd388566526337698e01884b9929314f5772353110d
data/.rubocop.yml CHANGED
@@ -1,20 +1,13 @@
1
- Metrics/LineLength:
2
- Max: 80
3
-
4
- Style/AlignParameters:
5
- EnforcedStyle: with_fixed_indentation
6
-
7
- Style/SpaceInsideHashLiteralBraces:
8
- EnforcedStyle: no_space
9
-
10
- Style/SpaceBeforeBlockBraces:
11
- EnforcedStyle: no_space
12
-
13
- Style/NumericLiterals:
14
- MinDigits: 666
15
-
16
1
  Documentation:
17
2
  Enabled: false
18
3
 
4
+ Metrics/ClassLength:
5
+ Enabled: false
6
+
7
+ Metrics/BlockLength:
8
+ Max: 30
9
+
19
10
  AllCops:
11
+ DisplayCopNames: true
20
12
  DisplayStyleGuide: true
13
+ TargetRubyVersion: 2.3
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
  gemspec
3
5
 
data/README.md CHANGED
@@ -15,6 +15,7 @@ $ gem install git-crecord
15
15
  ```shell
16
16
  $ git crecord
17
17
  $ git crecord --untracked-files # show untracked files
18
+ $ git crecord --reverse # unstage hunks
18
19
  ```
19
20
 
20
21
  Key-bindings:
@@ -55,6 +56,5 @@ $ ln -s bin/git-crecord /usr/bin/git-crecord
55
56
 
56
57
  Tests:
57
58
  ```shell
58
- $ bundle exec rake test
59
- $ bundle exec rake systemtest
59
+ $ bundle exec rake
60
60
  ```
data/Rakefile CHANGED
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rake'
2
4
  require 'rake/testtask'
3
5
  require 'bundler/gem_tasks'
6
+ require 'rubocop/rake_task'
4
7
 
5
8
  Rake::TestTask.new do |t|
6
9
  t.test_files = FileList['test/git_crecord/**/*test.rb']
@@ -11,4 +14,6 @@ task :systemtest do
11
14
  sh(File.join(__dir__, 'test/system-test.sh'))
12
15
  end
13
16
 
14
- task default: %i[test systemtest]
17
+ RuboCop::RakeTask.new
18
+
19
+ task default: %i[test systemtest rubocop]
data/bin/git-crecord CHANGED
@@ -1,4 +1,6 @@
1
1
  #! /usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
2
4
  require_relative '../lib/git_crecord'
3
5
 
4
6
  exit(GitCrecord.main(ARGV))
data/git-crecord.gemspec CHANGED
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'lib/git_crecord/version'
2
4
 
3
5
  GemSpec = Gem::Specification.new do |spec|
4
6
  spec.required_rubygems_version = Gem::Requirement.new('>= 1.3.6')
5
7
  spec.platform = Gem::Platform::RUBY
6
- spec.required_ruby_version = '>= 2.0.0'
8
+ spec.required_ruby_version = '>= 2.3.0'
7
9
  spec.name = 'git-crecord'
8
10
  spec.version = GitCrecord::VERSION
9
11
  spec.authors = 'Maik Brendler'
@@ -19,14 +21,14 @@ GemSpec = Gem::Specification.new do |spec|
19
21
  'issue_tracker' => 'https://github.com/mbrendler/git-crecord/issues'
20
22
  }
21
23
  spec.require_paths = %w[lib]
22
- spec.files = `git ls-files`.split($RS).delete_if{ |f| %r{^(spec|test)/} =~ f }
24
+ spec.files = `git ls-files`.split($RS).delete_if do |f|
25
+ %r{^(spec|test)/} =~ f
26
+ end
23
27
  spec.test_files = `git ls-files`.split($RS).grep(%r{^(spec|test)/})
24
28
  spec.executables = %w[git-crecord]
25
29
  spec.has_rdoc = false
26
- # Install curses dependency, via a native extension hack, because
27
- # ruby 2.0 includes curses and can't install curses-gem
28
- # spec.add_dependency 'curses', '~> 1.0'
29
- spec.extensions << 'ext/mkrf_conf.rb'
30
- spec.add_development_dependency 'rake', '~> 10.1', '>= 10.1.1'
30
+ spec.add_dependency 'curses', '~>1.0'
31
31
  spec.add_development_dependency 'minitest', '~> 5.8', '>= 5.8.4'
32
+ spec.add_development_dependency 'rake', '~> 10.1', '>= 10.1.1'
33
+ spec.add_development_dependency 'rubocop', '>= 0.56.0'
32
34
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../ui/color'
2
4
 
3
5
  module GitCrecord
@@ -12,9 +14,18 @@ module GitCrecord
12
14
  false => '[ ] ',
13
15
  :partly => '[~] '
14
16
  }.freeze
17
+
18
+ REVERSE_SELECTED_MAP = {
19
+ true => '[R] ',
20
+ false => '[X] ',
21
+ :partly => '[~] '
22
+ }.freeze
23
+
15
24
  SELECTION_MARKER_WIDTH = SELECTED_MAP[true].size
16
25
 
17
- def initialize
26
+ def initialize(reverse: false)
27
+ @reverse = reverse
28
+ @selection_marker_map = reverse ? REVERSE_SELECTED_MAP : SELECTED_MAP
18
29
  @subs = []
19
30
  end
20
31
 
@@ -44,15 +55,17 @@ module GitCrecord
44
55
  def selected
45
56
  s = selectable_subs.map(&:selected).uniq
46
57
  return s[0] if s.size == 1
58
+
47
59
  :partly
48
60
  end
49
61
 
50
62
  def selected=(value)
51
- selectable_subs.each{ |sub| sub.selected = value }
63
+ selectable_subs.each { |sub| sub.selected = value }
52
64
  end
53
65
 
54
66
  def style(is_highlighted)
55
67
  return Curses::A_BOLD | UI::Color.hl if is_highlighted
68
+
56
69
  Curses::A_BOLD | UI::Color.normal
57
70
  end
58
71
 
@@ -61,7 +74,9 @@ module GitCrecord
61
74
  end
62
75
 
63
76
  def prefix(line_number)
64
- return SELECTED_MAP.fetch(selected) if line_number.zero? && selectable?
77
+ show_selection_marker = line_number.zero? && selectable?
78
+ return @selection_marker_map.fetch(selected) if show_selection_marker
79
+
65
80
  ' ' * SELECTION_MARKER_WIDTH
66
81
  end
67
82
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'difference'
2
4
  require_relative 'hunk'
3
5
  require_relative '../ui/color'
@@ -8,28 +10,30 @@ module GitCrecord
8
10
  attr_reader :filename_a
9
11
  attr_reader :type
10
12
 
11
- def initialize(filename_a, filename_b, type: :modified)
13
+ def initialize(filename_a, filename_b, type: :modified, reverse: false)
12
14
  @filename_a = filename_a
13
15
  @filename_b = filename_b
14
16
  @type = type
15
17
  @expanded = false
16
- super()
18
+ super(reverse: reverse)
17
19
  end
18
20
 
19
21
  def to_s
20
- prefix = {modified: 'M', untracked: '?'}.fetch(type)
22
+ prefix = { modified: 'M', untracked: '?' }.fetch(type)
21
23
  return "#{prefix} #{@filename_a}" if @filename_a == @filename_b
24
+
22
25
  "#{prefix} #{filename_a} -> #{filename_b}"
23
26
  end
24
27
 
25
28
  def info_string
26
- line_count = subs.reduce(0){ |a, e| e.selectable_subs.size + a }
29
+ line_count = subs.reduce(0) { |a, e| e.selectable_subs.size + a }
27
30
  " #{subs.size} hunk(s), #{line_count} line(s) changed"
28
31
  end
29
32
 
30
33
  def strings(width)
31
34
  result = super
32
35
  return result unless expanded
36
+
33
37
  result += info_string.scan(/.{1,#{content_width(width)}}/)
34
38
  result << ''
35
39
  end
@@ -43,7 +47,7 @@ module GitCrecord
43
47
  end
44
48
 
45
49
  def <<(hunk)
46
- subs << Hunk.new(hunk)
50
+ subs << Hunk.new(hunk, reverse: @reverse)
47
51
  self
48
52
  end
49
53
 
@@ -53,6 +57,7 @@ module GitCrecord
53
57
 
54
58
  def generate_diff
55
59
  return unless selected
60
+
56
61
  [
57
62
  "diff --git a/#{@filename_a} b/#{@filename_b}",
58
63
  "--- a/#{@filename_a}",
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'difference'
2
4
  require_relative 'line'
3
5
  require_relative '../ui/color'
@@ -5,10 +7,10 @@ require_relative '../ui/color'
5
7
  module GitCrecord
6
8
  module Diff
7
9
  class Hunk < Difference
8
- def initialize(head)
10
+ def initialize(head, reverse: false)
9
11
  @head = head
10
12
  @expanded = true
11
- super()
13
+ super(reverse: reverse)
12
14
  end
13
15
 
14
16
  def to_s
@@ -20,12 +22,13 @@ module GitCrecord
20
22
  end
21
23
 
22
24
  def <<(line)
23
- subs << Line.new(line)
25
+ subs << Line.new(line, reverse: @reverse)
24
26
  self
25
27
  end
26
28
 
27
29
  def generate_diff
28
30
  return nil unless selected
31
+
29
32
  [generate_header, *subs.map(&:generate_diff).compact].join("\n")
30
33
  end
31
34
 
@@ -33,6 +36,7 @@ module GitCrecord
33
36
  old_start, old_count, new_start, new_count = parse_header
34
37
  selectable_subs.each do |sub|
35
38
  next if sub.selected
39
+
36
40
  new_count -= 1 if sub.add?
37
41
  new_count += 1 if sub.del?
38
42
  end
@@ -42,6 +46,7 @@ module GitCrecord
42
46
  def parse_header
43
47
  match = @head.match(/@@ -(\d+)(,(\d+))? \+(\d+)(,(\d+))? @@/)
44
48
  raise "mismatching hunk-header - '#{@head}'" if match.nil?
49
+
45
50
  [match[1], match[3] || 1, match[4], match[6] || 1].map(&:to_i)
46
51
  end
47
52
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'difference'
2
4
  require_relative '../ui/color'
3
5
 
@@ -40,10 +42,10 @@ module GitCrecord
40
42
  class Line < Difference
41
43
  attr_reader :selected
42
44
 
43
- def initialize(line)
45
+ def initialize(line, reverse: false)
44
46
  @line = line
45
47
  @selected = true
46
- super()
48
+ super(reverse: reverse)
47
49
  end
48
50
 
49
51
  def to_s
@@ -77,6 +79,7 @@ module GitCrecord
77
79
  def generate_diff
78
80
  return " #{@line[1..-1]}" if !selected && del?
79
81
  return @line if selected
82
+
80
83
  nil
81
84
  end
82
85
 
@@ -84,6 +87,7 @@ module GitCrecord
84
87
  return UI::Color.hl if is_highlighted
85
88
  return UI::Color.green if add?
86
89
  return UI::Color.red if del?
90
+
87
91
  UI::Color.normal
88
92
  end
89
93
  end
@@ -1,15 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'diff/file'
2
4
 
3
5
  module GitCrecord
4
6
  module Diff
5
- def self.parse(diff)
7
+ def self.parse(diff, reverse = false)
6
8
  files = []
7
9
  enum = diff.lines.each
8
10
  loop do
9
11
  line = enum.next
10
12
  line.chomp!
11
- next files << parse_file_header(line, enum) if file_start?(line)
13
+ next files << parse_file_head(line, enum, reverse) if file_start?(line)
12
14
  next files[-1] << line if hunk_start?(line)
15
+
13
16
  files[-1].add_hunk_line(line)
14
17
  end
15
18
  files
@@ -23,11 +26,14 @@ module GitCrecord
23
26
  line.start_with?('@@')
24
27
  end
25
28
 
26
- def self.parse_file_header(line, enum)
27
- enum.next # index ...
29
+ def self.parse_file_head(line, enum, reverse)
30
+ index_line = enum.next # index ... or new ...
31
+ is_new_file = index_line.start_with?('new')
32
+ enum.next if is_new_file
28
33
  enum.next # --- ...
29
34
  enum.next # +++ ...
30
- File.new(*parse_filenames(line))
35
+ type = is_new_file ? :untracked : :modified
36
+ File.new(*parse_filenames(line), type: type, reverse: reverse)
31
37
  end
32
38
 
33
39
  def self.parse_filenames(line)
@@ -35,7 +41,7 @@ module GitCrecord
35
41
  end
36
42
 
37
43
  def self.untracked_files(git_status)
38
- git_status.lines.select{ |l| l.start_with?('??') }.flat_map do |path|
44
+ git_status.lines.select { |l| l.start_with?('??') }.flat_map do |path|
39
45
  path = path.chomp[3..-1]
40
46
  ::File.directory?(path) ? untracked_dir(path) : untracked_file(path)
41
47
  end.compact
@@ -46,7 +52,7 @@ module GitCrecord
46
52
  lines, err = file_lines(filename)
47
53
  file << "@@ -0,0 +1,#{lines.size} @@"
48
54
  file.subs[0].subs << PseudoLine.new(err) if lines.empty?
49
- lines.each{ |line| file.add_hunk_line("+#{line.chomp}") }
55
+ lines.each { |line| file.add_hunk_line("+#{line.chomp}") }
50
56
  file.selected = false
51
57
  end
52
58
  end
@@ -64,6 +70,7 @@ module GitCrecord
64
70
  def self.file_lines(filename)
65
71
  encoding = file_encoding(filename)
66
72
  return [[], 'binary'] if encoding == 'binary'
73
+
67
74
  [::File.open(filename, "r:#{encoding}", &:readlines), nil]
68
75
  end
69
76
  end
@@ -1,17 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'logger'
2
4
  require 'open3'
3
5
 
4
6
  module GitCrecord
5
7
  module Git
6
- def self.stage(files)
8
+ def self.stage(files, reverse = false)
7
9
  selected_files = files.select(&:selected)
8
- add_files(selected_files.select{ |file| file.type == :untracked })
10
+ untracked_files = selected_files.select { |file| file.type == :untracked }
11
+ add_files(untracked_files) unless reverse
9
12
  diff = selected_files.map(&:generate_diff).join("\n")
10
- _stage(diff).success?
13
+ status = _stage(diff, reverse).success?
14
+ return status unless reverse
15
+
16
+ reset_files(untracked_files.select { |file| file.selected == true })
17
+ true
11
18
  end
12
19
 
13
- def self._stage(diff)
14
- cmd = 'git apply --cached --unidiff-zero - '
20
+ def self._stage(diff, reverse = false)
21
+ cmd = "git apply --cached --unidiff-zero #{reverse ? '-R' : ''} - "
15
22
  content, status = Open3.capture2e(cmd, stdin_data: diff)
16
23
  LOGGER.info(cmd)
17
24
  LOGGER.info(diff)
@@ -33,6 +40,17 @@ module GitCrecord
33
40
  system("git add -N #{filename}")
34
41
  end
35
42
 
43
+ def self.reset_files(files)
44
+ files.each do |file|
45
+ success = reset_file(file.filename_a)
46
+ raise "could not reset file #{file.filename_a}" unless success
47
+ end
48
+ end
49
+
50
+ def self.reset_file(filename)
51
+ system("git reset -q #{filename}")
52
+ end
53
+
36
54
  def self.status
37
55
  `git status --porcelain`
38
56
  end
@@ -41,8 +59,8 @@ module GitCrecord
41
59
  exec('git commit')
42
60
  end
43
61
 
44
- def self.diff
45
- `git diff --no-ext-diff --no-color`
62
+ def self.diff(staged: false)
63
+ `git diff --no-ext-diff --no-color #{staged ? '--staged' : ''}`
46
64
  end
47
65
 
48
66
  def self.toplevel_dir
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
 
3
5
  module GitCrecord
4
6
  LOGGER = Logger.new(File.new(File.join(ENV['HOME'], '.git-crecord.log'), 'w'))
5
- LOGGER.formatter = proc{ |_severity, _datetime, _progname, msg| "#{msg}\n" }
7
+ LOGGER.formatter = proc { |_severity, _datetime, _progname, msg| "#{msg}\n" }
6
8
  LOGGER.level = Logger::INFO
7
9
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  module GitCrecord
3
4
  class QuitAction < Proc
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'curses'
2
4
 
3
5
  module GitCrecord
@@ -20,7 +22,7 @@ module GitCrecord
20
22
  end
21
23
 
22
24
  MAP.each_pair do |name, number|
23
- define_singleton_method(name){ Curses.color_pair(number) }
25
+ define_singleton_method(name) { Curses.color_pair(number) }
24
26
  end
25
27
  end
26
28
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'curses'
2
4
 
3
5
  module GitCrecord
4
6
  module UI
5
7
  module HelpWindow
6
- CONTENT = <<EOS.freeze
8
+ CONTENT = <<HELP
7
9
  q - quit
8
10
  s - stage selection and quit
9
11
  c - commit selection and quit
@@ -20,7 +22,7 @@ module GitCrecord
20
22
  A - toggle all selections
21
23
  ? - display help
22
24
  R - force redraw
23
- EOS
25
+ HELP
24
26
 
25
27
  def self.show
26
28
  win = Curses::Window.new(height, width, 0, 0)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'curses'
2
4
  require_relative 'color'
3
5
  require_relative 'help_window'
@@ -39,12 +41,13 @@ module GitCrecord
39
41
  new_width = Curses.cols
40
42
  new_height = [Curses.lines, content_height(new_width)].max
41
43
  return if width == new_width && @win.maxy == new_height
44
+
42
45
  @win.resize(new_height, new_width)
43
46
  redraw
44
47
  end
45
48
 
46
49
  def content_height(width)
47
- @files.reduce(@files.size){ |a, e| a + e.max_height(width) }
50
+ @files.reduce(@files.size) { |a, e| a + e.max_height(width) }
48
51
  end
49
52
 
50
53
  def scroll_position
@@ -59,6 +62,7 @@ module GitCrecord
59
62
 
60
63
  def move_highlight(to)
61
64
  return if to == @highlighted || to.nil?
65
+
62
66
  from = @highlighted
63
67
  @highlighted = to
64
68
  from.print(self, from.y1 - 1, false)
@@ -66,12 +70,13 @@ module GitCrecord
66
70
  refresh
67
71
  end
68
72
 
69
- def addstr(str, y = nil, x = 0, attr: 0, fill: false)
70
- @win.setpos(y, x) unless y.nil?
73
+ def addstr(str, y_pos = nil, x_pos = 0, attr: 0, fill: false)
74
+ @win.setpos(y_pos, x_pos) unless y_pos.nil?
71
75
  @win.attrset(attr)
72
76
  @win.addstr(str)
73
77
  fill_size = width - @win.curx
74
- return unless fill && fill_size > 0
78
+ return unless fill && fill_size.positive?
79
+
75
80
  @win.addstr((fill * fill_size)[0..fill_size])
76
81
  end
77
82
 
@@ -79,6 +84,7 @@ module GitCrecord
79
84
  list.each do |entry|
80
85
  line_number = entry.print(self, line_number, entry == @highlighted)
81
86
  next unless entry.expanded
87
+
82
88
  line_number = print_list(entry.subs, line_number)
83
89
  addstr('', line_number += 1, fill: '_') if entry.is_a?(Diff::File)
84
90
  end
@@ -89,6 +95,7 @@ module GitCrecord
89
95
  @visibles = @files.each_with_object([]) do |entry, vs|
90
96
  vs << entry
91
97
  next unless entry.expanded
98
+
92
99
  entry.selectable_subs.each do |entryy|
93
100
  vs << entryy
94
101
  vs.concat(entryy.selectable_subs) if entryy.expanded
@@ -101,11 +108,11 @@ module GitCrecord
101
108
  end
102
109
 
103
110
  def stage
104
- QuitAction.new{ Git.stage(@files) }
111
+ QuitAction.new { |reverse| Git.stage(@files, reverse) }
105
112
  end
106
113
 
107
114
  def commit
108
- QuitAction.new{ Git.stage(@files) && Git.commit }
115
+ QuitAction.new { |reverse| Git.stage(@files, reverse) && Git.commit }
109
116
  end
110
117
 
111
118
  def highlight_next
@@ -127,14 +134,14 @@ module GitCrecord
127
134
  def highlight_next_hunk
128
135
  index = @visibles.index(@highlighted)
129
136
  move_highlight(
130
- @visibles[(index + 1)..-1].find{ |entry| !entry.subs.empty? }
137
+ @visibles[(index + 1)..-1].find { |entry| !entry.subs.empty? }
131
138
  )
132
139
  end
133
140
 
134
141
  def highlight_previous_hunk
135
142
  index = @visibles.index(@highlighted)
136
143
  move_highlight(
137
- @visibles[0...index].reverse_each.find{ |entry| !entry.subs.empty? }
144
+ @visibles[0...index].reverse_each.find { |entry| !entry.subs.empty? }
138
145
  )
139
146
  end
140
147
 
@@ -159,7 +166,7 @@ module GitCrecord
159
166
 
160
167
  def toggle_all_selections
161
168
  new_selected = @files[0].selected == false
162
- @files.each{ |file| file.selected = new_selected }
169
+ @files.each { |file| file.selected = new_selected }
163
170
  redraw
164
171
  end
165
172
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'curses'
2
4
  require_relative 'ui/color'
3
5
  require_relative 'ui/hunks_window'
@@ -34,7 +36,7 @@ module GitCrecord
34
36
  Curses.clear
35
37
  Curses.noecho
36
38
  Curses.curs_set(0)
37
- pad = Curses::Pad.new(1, 1).tap{ |p| p.keypad = true }
39
+ pad = Curses::Pad.new(1, 1).tap { |p| p.keypad = true }
38
40
  run_loop(HunksWindow.new(pad, files))
39
41
  ensure
40
42
  Curses.close_screen
@@ -44,6 +46,7 @@ module GitCrecord
44
46
  loop do
45
47
  c = win.getch
46
48
  next if ACTIONS[c].nil?
49
+
47
50
  quit = win.send(ACTIONS[c])
48
51
  break quit if quit == :quit
49
52
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module GitCrecord
2
- VERSION = '1.0.8'.freeze
4
+ VERSION = '1.1.0'
3
5
  end
data/lib/git_crecord.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative 'git_crecord/diff'
2
4
  require_relative 'git_crecord/git'
3
5
  require_relative 'git_crecord/ui'
@@ -13,37 +15,47 @@ module GitCrecord
13
15
  help
14
16
  true
15
17
  else
16
- run(with_untracked_files: untracked_files?(argv))
18
+ run(with_untracked_files: untracked_files?(argv), reverse: reverse?(argv))
17
19
  end
18
20
  end
19
21
 
20
22
  def self.untracked_files?(argv)
23
+ return false if reverse?(argv)
24
+
21
25
  argv.include?('--untracked-files') || argv.include?('-u')
22
26
  end
23
27
 
24
- def self.run(with_untracked_files: false)
28
+ def self.reverse?(argv)
29
+ argv.include?('--reverse') || argv.include?('-R')
30
+ end
31
+
32
+ def self.run(with_untracked_files: false, reverse: false)
25
33
  toplevel_dir = Git.toplevel_dir
26
34
  return false if toplevel_dir.empty?
35
+
27
36
  Dir.chdir(toplevel_dir) do
28
- files = Diff.parse(Git.diff)
37
+ files = Diff.parse(Git.diff(staged: reverse), reverse)
29
38
  files.concat(Diff.untracked_files(Git.status)) if with_untracked_files
30
39
  return false if files.empty?
40
+
31
41
  result = UI.run(files)
32
- return result.call == true if result.respond_to?(:call)
42
+ return result.call(reverse) == true if result.respond_to?(:call)
43
+
33
44
  true
34
45
  end
35
46
  end
36
47
 
37
48
  def self.help
38
- puts <<EOS
39
- usage: git crecord [<options>]
49
+ puts <<~HELP
50
+ usage: git crecord [<options>]
40
51
 
41
- -u, --untracked-files -- show untracked files
42
- --version -- show version information
43
- -h -- this help message
52
+ -u, --untracked-files -- show untracked files
53
+ -R, --reverse -- unstage hunks
54
+ --version -- show version information
55
+ -h -- this help message
44
56
 
45
- in-program commands:
46
- #{UI::HelpWindow::CONTENT.gsub(/^/, ' ')}
47
- EOS
57
+ in-program commands:
58
+ #{UI::HelpWindow::CONTENT.gsub(/^/, ' ')}
59
+ HELP
48
60
  end
49
61
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative '../../test_helper'
2
4
 
3
5
  class HunkTest < Minitest::Test
@@ -23,6 +25,6 @@ class HunkTest < Minitest::Test
23
25
 
24
26
  def test_parse_header_failure
25
27
  hunk = Hunk.new('ugly header')
26
- assert_raises(RuntimeError){ hunk.parse_header }
28
+ assert_raises(RuntimeError) { hunk.parse_header }
27
29
  end
28
30
  end
data/test/system-test.sh CHANGED
@@ -4,13 +4,15 @@ set -euo pipefail
4
4
 
5
5
  function assert-equal() {
6
6
  local expected=$1
7
- local actual=$1
7
+ local actual=$2
8
8
  if test "$expected" != "$actual" ; then
9
- cat << 'EOF'
9
+ cat << EOF
10
10
  expect:
11
- $expect
11
+ $expected
12
12
  but got:
13
13
  $actual
14
+ EOF
15
+ cat << 'EOF'
14
16
  ____ _
15
17
  | _ \ __ _ _ __ (_) ___
16
18
  | |_) / _` | '_ \| |/ __|
@@ -31,9 +33,14 @@ function assert-status() {
31
33
  assert-equal "$expected" "$(git status -s)"
32
34
  }
33
35
 
34
- function run-git-crecord(){
36
+ function run-git-crecord() {
35
37
  local keys=$1
36
- "$EXECUTABLE" -u <<<"$keys"
38
+ "$EXECUTABLE" -u "$@" <<<"$keys"
39
+ }
40
+
41
+ function run-git-crecord-reverse() {
42
+ local keys=$1
43
+ "$EXECUTABLE" -R <<<"$keys"
37
44
  }
38
45
 
39
46
  readonly HERE="$(dirname "$(readlink -m "${BASH_SOURCE[0]}")")"
@@ -68,7 +75,7 @@ assert-diff ""
68
75
  git reset > /dev/null
69
76
 
70
77
  echo "add first line ----------------------------------------------------------"
71
- run-git-crecord " lj s"
78
+ run-git-crecord " ljj s"
72
79
  assert-diff "+This is the second line.
73
80
  +This is line 3.
74
81
  +This is line 4."
@@ -76,7 +83,7 @@ assert-diff "+This is the second line.
76
83
  git reset > /dev/null
77
84
 
78
85
  echo "add another line --------------------------------------------------------"
79
- run-git-crecord " ljjj s"
86
+ run-git-crecord " ljjjj s"
80
87
  assert-diff "+This is line 1.
81
88
  +This is the second line.
82
89
  +This is line 4."
@@ -92,8 +99,8 @@ assert-diff ""
92
99
 
93
100
  git reset > /dev/null
94
101
 
95
- echo "delete one lines --------------------------------------------------------"
96
- run-git-crecord " ljj s"
102
+ echo "delete one line ---------------------------------------------------------"
103
+ run-git-crecord " ljjj s"
97
104
  assert-diff "-This is line 1.
98
105
  -This is line 3."
99
106
 
@@ -125,14 +132,14 @@ assert-diff ""
125
132
  git reset > /dev/null
126
133
 
127
134
  echo "add lines of second hunk ------------------------------------------------"
128
- run-git-crecord " ljjj sq "
135
+ run-git-crecord " ljjjj sq "
129
136
  assert-diff "-This is the second line.
130
137
  +This is line 2."
131
138
 
132
139
  git reset > /dev/null
133
140
 
134
141
  echo "add some lines of all hunks ---------------------------------------------"
135
- run-git-crecord " ljj jj jj j s"
142
+ run-git-crecord " ljjj jj jj j s"
136
143
  assert-diff "-This is the second line.
137
144
  -This is line 11."
138
145
 
@@ -176,6 +183,19 @@ echo "++++" >> b_file.txt
176
183
  run-git-crecord "s"
177
184
  assert-diff ""
178
185
 
186
+ echo "test unstage ------------------------------------------------------------"
187
+ echo new line1 > new.txt
188
+ echo new line2 >> new.txt
189
+ git add new.txt
190
+ run-git-crecord-reverse 'j k lj Gkljj s'
191
+ assert-status 'MM a_file.txt
192
+ M b_file.txt
193
+ AM new.txt
194
+ ?? sub/'
195
+ assert-diff '-This is the second line.
196
+ +This is line 2.
197
+ +new line2'
198
+
179
199
  popd > /dev/null # $REPO_DIR
180
200
 
181
201
  cat << 'EOF'
data/test/test_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'minitest/autorun'
2
4
 
3
5
  require_relative '../lib/git_crecord'
metadata CHANGED
@@ -1,15 +1,49 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git-crecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.8
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maik Brendler
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-23 00:00:00.000000000 Z
11
+ date: 2018-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: curses
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.8'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 5.8.4
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '5.8'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 5.8.4
13
47
  - !ruby/object:Gem::Dependency
14
48
  name: rake
15
49
  requirement: !ruby/object:Gem::Requirement
@@ -31,32 +65,25 @@ dependencies:
31
65
  - !ruby/object:Gem::Version
32
66
  version: 10.1.1
33
67
  - !ruby/object:Gem::Dependency
34
- name: minitest
68
+ name: rubocop
35
69
  requirement: !ruby/object:Gem::Requirement
36
70
  requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: '5.8'
40
71
  - - ">="
41
72
  - !ruby/object:Gem::Version
42
- version: 5.8.4
73
+ version: 0.56.0
43
74
  type: :development
44
75
  prerelease: false
45
76
  version_requirements: !ruby/object:Gem::Requirement
46
77
  requirements:
47
- - - "~>"
48
- - !ruby/object:Gem::Version
49
- version: '5.8'
50
78
  - - ">="
51
79
  - !ruby/object:Gem::Version
52
- version: 5.8.4
80
+ version: 0.56.0
53
81
  description: This gem adds the git-crecord command. It provides a curses UI to stage/commit
54
82
  git-hunks.
55
83
  email: maik.brendler@invision.de
56
84
  executables:
57
85
  - git-crecord
58
- extensions:
59
- - ext/mkrf_conf.rb
86
+ extensions: []
60
87
  extra_rdoc_files: []
61
88
  files:
62
89
  - ".gitignore"
@@ -66,7 +93,6 @@ files:
66
93
  - README.md
67
94
  - Rakefile
68
95
  - bin/git-crecord
69
- - ext/mkrf_conf.rb
70
96
  - git-crecord.gemspec
71
97
  - lib/git_crecord.rb
72
98
  - lib/git_crecord/diff.rb
@@ -99,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
125
  requirements:
100
126
  - - ">="
101
127
  - !ruby/object:Gem::Version
102
- version: 2.0.0
128
+ version: 2.3.0
103
129
  required_rubygems_version: !ruby/object:Gem::Requirement
104
130
  requirements:
105
131
  - - ">="
@@ -107,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
133
  version: 1.3.6
108
134
  requirements: []
109
135
  rubyforge_project:
110
- rubygems_version: 2.6.11
136
+ rubygems_version: 2.7.6
111
137
  signing_key:
112
138
  specification_version: 4
113
139
  summary: Git command to stage/commit hunks the simple way.
data/ext/mkrf_conf.rb DELETED
@@ -1,15 +0,0 @@
1
- require 'rubygems'
2
- require 'rubygems/dependency_installer'
3
-
4
- # This is a hack to not install curses for ruby-2.0.
5
-
6
- di = Gem::DependencyInstaller.new
7
-
8
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.1.0')
9
- puts 'install curses'
10
- di.install 'curses', '~>1.0'
11
- end
12
-
13
- File.open(File.join(__dir__, 'Rakefile'), 'w') do |f|
14
- f.write("task :default#{$/}")
15
- end