git-crecord 1.0.8 → 1.1.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.
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