zomgit 0.0.1
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 +7 -0
- data/.gitignore +21 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +51 -0
- data/Rakefile +10 -0
- data/bin/zomgit +12 -0
- data/lib/zomgit.rb +81 -0
- data/lib/zomgit/commands.rb +18 -0
- data/lib/zomgit/commands/find.rb +49 -0
- data/lib/zomgit/commands/status.rb +248 -0
- data/lib/zomgit/concerns/findable.rb +135 -0
- data/lib/zomgit/exceptions.rb +37 -0
- data/lib/zomgit/helpers/file_helper.rb +17 -0
- data/lib/zomgit/helpers/rainbow_helper.rb +46 -0
- data/lib/zomgit/persistor.rb +51 -0
- data/lib/zomgit/version.rb +3 -0
- data/share/commands/add.zsh +92 -0
- data/share/commands/branch.zsh +11 -0
- data/share/commands/checkout.zsh +18 -0
- data/share/commands/clone.zsh +18 -0
- data/share/commands/commit.zsh +7 -0
- data/share/commands/diff.zsh +89 -0
- data/share/commands/log.zsh +11 -0
- data/share/commands/push.zsh +3 -0
- data/share/commands/reset.zsh +80 -0
- data/share/commands/status.zsh +30 -0
- data/share/zomgit.zsh +14 -0
- data/zomgit.gemspec +22 -0
- metadata +129 -0
@@ -0,0 +1,135 @@
|
|
1
|
+
module Zomgit
|
2
|
+
module Concerns
|
3
|
+
module Findable
|
4
|
+
class Finder
|
5
|
+
# IMPROVE: Permit the query to be more complex (e.g.: a regex)
|
6
|
+
def self.fuzzy_find(files, query, options = {})
|
7
|
+
return Array.new if query.empty?
|
8
|
+
|
9
|
+
eager_pattern = "\\b#{Regexp.escape(query)}"
|
10
|
+
|
11
|
+
if query.include?("/")
|
12
|
+
greedy_pattern = query.split("/").map { |p| p.split("").map { |c| Regexp.escape(c) }.join(")[^\/]*?(").prepend("[^\/]*?(") + ")[^\/]*?" }.join("\/")
|
13
|
+
greedy_pattern << "\/" if query[-1] == "/"
|
14
|
+
else
|
15
|
+
greedy_pattern = query.split("").map { |c| Regexp.escape(c) }.join(").*?(").prepend(".*?(") + ").*?"
|
16
|
+
end
|
17
|
+
|
18
|
+
eager_results = []
|
19
|
+
greedy_results = []
|
20
|
+
exact_match_found = false
|
21
|
+
|
22
|
+
files.each do |f|
|
23
|
+
if f =~ /#{eager_pattern}/
|
24
|
+
eager_results << f
|
25
|
+
exact_match_found = true
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
if exact_match_found
|
30
|
+
next unless !!options[:greedy]
|
31
|
+
end
|
32
|
+
|
33
|
+
greedy_results << f if f =~ /#{greedy_pattern}/
|
34
|
+
end
|
35
|
+
|
36
|
+
if eager_results.empty? || !!options[:greedy]
|
37
|
+
eager_results + greedy_results
|
38
|
+
else
|
39
|
+
eager_results
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def search(arguments, options = [])
|
45
|
+
greedy = !!options[:greedy] && !!!options[:G]
|
46
|
+
clean = !!options[:refine]
|
47
|
+
files = Array.new
|
48
|
+
|
49
|
+
case options[:filter].to_s.to_sym
|
50
|
+
when :all
|
51
|
+
cmds = ["ls-files --others --cached --exclude-standard"]
|
52
|
+
when :untracked
|
53
|
+
cmds = ["ls-files --others --exclude-standard"]
|
54
|
+
when :tracked
|
55
|
+
cmds = ["ls-files"]
|
56
|
+
when :unstaged
|
57
|
+
cmds = ["ls-files --others --exclude-standard", "diff --name-only"]
|
58
|
+
when :staged
|
59
|
+
cmds = ["diff --name-only --cached"]
|
60
|
+
when :modified
|
61
|
+
cmds = ["diff --name-only"]
|
62
|
+
else
|
63
|
+
cmds = ["ls-files --others --cached --exclude-standard"]
|
64
|
+
end
|
65
|
+
|
66
|
+
cmds.each { |c| files << `command git #{c}`.split("\n") }
|
67
|
+
files.flatten!
|
68
|
+
|
69
|
+
if files.count == 0
|
70
|
+
raise Zomgit::Exceptions::NoChangesError.new("No changes matching this filter")
|
71
|
+
end
|
72
|
+
|
73
|
+
if arguments.count == 1 && arguments.first == "."
|
74
|
+
found = files
|
75
|
+
else
|
76
|
+
indices = arguments.map { |a| a if a =~ /\A[1-9]+(?:\.{2}[0-9]+)?\Z/ }.compact
|
77
|
+
|
78
|
+
unless indices.empty?
|
79
|
+
index = Zomgit::Persistor.instance.index
|
80
|
+
|
81
|
+
if index.empty?
|
82
|
+
raise Zomgit::Exceptions::NoIndexError.new("No index found")
|
83
|
+
end
|
84
|
+
|
85
|
+
arguments -= indices
|
86
|
+
|
87
|
+
indices.map! do |i|
|
88
|
+
if i.include?("..")
|
89
|
+
head, tail = i.split("..").map(&:to_i)
|
90
|
+
|
91
|
+
if head > tail || head > files.count || tail > index.count
|
92
|
+
raise Zomgit::Exceptions::InvalidIndexRangeError.new("Invalid index range: #{[head, tail].join("..")}")
|
93
|
+
end
|
94
|
+
|
95
|
+
index[Range.new(head - 1, tail - 1)]
|
96
|
+
else
|
97
|
+
ii = i.to_i
|
98
|
+
|
99
|
+
unless ii > 0 && ii <= index.count
|
100
|
+
raise Zomgit::Exceptions::InvalidIndexError.new("Invalid index: #{i}")
|
101
|
+
end
|
102
|
+
|
103
|
+
index[ii - 1]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
indices.flatten!
|
108
|
+
end
|
109
|
+
|
110
|
+
if clean
|
111
|
+
found = files
|
112
|
+
|
113
|
+
arguments.each do |arg|
|
114
|
+
found = Finder.fuzzy_find(found, arg, greedy: greedy)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
found = Array.new
|
118
|
+
|
119
|
+
arguments.each do |arg|
|
120
|
+
found << Finder.fuzzy_find(files, arg, greedy: greedy)
|
121
|
+
end
|
122
|
+
|
123
|
+
found = found.flatten.uniq
|
124
|
+
end
|
125
|
+
|
126
|
+
unless indices.empty?
|
127
|
+
found = (found + indices).uniq
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
found
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Zomgit
|
2
|
+
module Exceptions
|
3
|
+
#
|
4
|
+
# Base exception
|
5
|
+
#
|
6
|
+
class BaseError < ArgumentError; end
|
7
|
+
|
8
|
+
#
|
9
|
+
# Global exceptions
|
10
|
+
#
|
11
|
+
class NoGitRepoFoundError < BaseError; end
|
12
|
+
class InvalidOptionError < BaseError; end
|
13
|
+
class NoChangesError < BaseError; end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Indices exceptions
|
17
|
+
#
|
18
|
+
class NoIndexError < BaseError; end
|
19
|
+
class InvalidIndexError < BaseError; end
|
20
|
+
class InvalidIndexRangeError < BaseError; end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Status command exceptions
|
24
|
+
#
|
25
|
+
class TooManyChangesError < BaseError; end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Find command exceptions
|
29
|
+
#
|
30
|
+
class MissingQueryError < BaseError; end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Add command exceptions
|
34
|
+
#
|
35
|
+
class FileOrDirectoryNotFoundError < BaseError; end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Zomgit
|
2
|
+
module Helpers
|
3
|
+
module FileHelper
|
4
|
+
def relative_path(base, target)
|
5
|
+
back = ""
|
6
|
+
|
7
|
+
while target.sub(base, "") == target
|
8
|
+
base = base.sub(/\/[^\/]*$/, "")
|
9
|
+
back = "../#{back}"
|
10
|
+
end
|
11
|
+
|
12
|
+
"#{back}#{target.sub("#{base}/","")}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Zomgit
|
2
|
+
module Helpers
|
3
|
+
module RainbowHelper
|
4
|
+
# Black 0;30 Dark Gray 1;30
|
5
|
+
# Blue 0;34 Light Blue 1;34
|
6
|
+
# Green 0;32 Light Green 1;32
|
7
|
+
# Cyan 0;36 Light Cyan 1;36
|
8
|
+
# Red 0;31 Light Red 1;31
|
9
|
+
# Purple 0;35 Light Purple 1;35
|
10
|
+
# Brown 0;33 Yellow 1;33
|
11
|
+
# Light Gray 0;37 White 1;37
|
12
|
+
|
13
|
+
COLOR_CODES = {
|
14
|
+
white: "0",
|
15
|
+
black: "30",
|
16
|
+
red: "31",
|
17
|
+
green: "32",
|
18
|
+
yellow: "33",
|
19
|
+
blue: "34",
|
20
|
+
purple: "35",
|
21
|
+
cyan: "36",
|
22
|
+
gray: "37"
|
23
|
+
}
|
24
|
+
|
25
|
+
COLOR_CODE_PREFIX = "\033["
|
26
|
+
COLOR_CODE_SUFFIX = "m"
|
27
|
+
|
28
|
+
def paint(message, color = "white", options = {})
|
29
|
+
options[:bold] ||= false
|
30
|
+
|
31
|
+
raise ArgumentError, "Invalid color (#{color})" unless COLOR_CODES.has_key?(color.to_sym)
|
32
|
+
raise ArgumentError, "Invalid color (white, bold)" if color == "white" && options[:bold]
|
33
|
+
|
34
|
+
modifier = options[:bold] ? "1;" : "0;"
|
35
|
+
|
36
|
+
"#{COLOR_CODE_PREFIX}#{modifier}#{COLOR_CODES[color.to_sym]}#{COLOR_CODE_SUFFIX}#{message}#{COLOR_CODE_PREFIX}#{COLOR_CODES[:white]}#{COLOR_CODE_SUFFIX}"
|
37
|
+
end
|
38
|
+
|
39
|
+
COLOR_CODES.keys.each do |color|
|
40
|
+
define_method color do |message, options = {}|
|
41
|
+
paint message, color, options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "singleton"
|
2
|
+
require "fileutils"
|
3
|
+
|
4
|
+
module Zomgit
|
5
|
+
class Persistor
|
6
|
+
attr_reader :index, :indexed, :index_file
|
7
|
+
alias_method :indexed?, :indexed
|
8
|
+
|
9
|
+
RUNTIME_DIR = File.expand_path(File.join(ENV["HOME"], ".zomgit"))
|
10
|
+
INDEXES_DIR = File.join(RUNTIME_DIR, "indexes")
|
11
|
+
|
12
|
+
include Singleton
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
unless File.directory?(RUNTIME_DIR)
|
16
|
+
FileUtils.mkdir_p([RUNTIME_DIR, INDEXES_DIR])
|
17
|
+
end
|
18
|
+
|
19
|
+
if File.file?(self.index_file)
|
20
|
+
@index = File.read(self.index_file).split("\n")
|
21
|
+
@indexed = true
|
22
|
+
else
|
23
|
+
@index = []
|
24
|
+
@indexed = false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def cache_index(files)
|
29
|
+
@index = files
|
30
|
+
|
31
|
+
File.open(self.index_file, "wb") { |f| f.puts files.join("\n") }
|
32
|
+
|
33
|
+
@indexed = true
|
34
|
+
end
|
35
|
+
|
36
|
+
def clean_index_cache!
|
37
|
+
if self.indexed?
|
38
|
+
File.unlink(self.index_file)
|
39
|
+
@indexed = false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def index_file
|
44
|
+
unless @index_file
|
45
|
+
@index_file = File.join(INDEXES_DIR, Zomgit::project_root.gsub(/#{Regexp.escape(File::SEPARATOR)}/, "~~"))
|
46
|
+
end
|
47
|
+
|
48
|
+
@index_file
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
ga() {
|
2
|
+
local gitopts
|
3
|
+
local fileopts
|
4
|
+
local options
|
5
|
+
local files
|
6
|
+
|
7
|
+
gitopts=()
|
8
|
+
options=()
|
9
|
+
|
10
|
+
if (( $# == 0 )); then
|
11
|
+
fileopts="."
|
12
|
+
options=( --filter unstaged )
|
13
|
+
else
|
14
|
+
local opts
|
15
|
+
|
16
|
+
gitopts=( $(echo "${@}" | command grep -o -E "(--( (.*)))$" | command sed -E "s/^-- ?//") )
|
17
|
+
opts=( $(echo "$@" | sed -E "s/(.*)(--( .*))$/\1/g") )
|
18
|
+
|
19
|
+
# Remove the git options from the regular options array
|
20
|
+
set -- "${opts[@]}"
|
21
|
+
|
22
|
+
#
|
23
|
+
# Parse ZOMGit options
|
24
|
+
#
|
25
|
+
local opt_filter
|
26
|
+
local opt_greedy
|
27
|
+
local opt_refine
|
28
|
+
|
29
|
+
opt_filter=( unstaged )
|
30
|
+
opt_greedy=()
|
31
|
+
opt_refine=()
|
32
|
+
|
33
|
+
zparseopts -K -D f:=opt_filter -filter:=opt_filter g=opt_greedy G=opt_greedy -greedy=opt_greedy -no-greedy=opt_greedy r=opt_refine -refine=opt_refine
|
34
|
+
|
35
|
+
local filter=${opt_filter[${#opt_filter}]}
|
36
|
+
local greedy=${opt_greedy[${#opt_greedy}]}
|
37
|
+
local refine=${#opt_refine}
|
38
|
+
|
39
|
+
if [[ "${filter}" != "" ]]; then
|
40
|
+
options=( $options --filter $filter )
|
41
|
+
fi
|
42
|
+
|
43
|
+
if [[ "${greedy}" != "" && "${greedy}" =~ "G|no" ]]; then
|
44
|
+
options=( $options $greedy )
|
45
|
+
fi
|
46
|
+
|
47
|
+
if (( $refine > 0 )); then
|
48
|
+
options=( $options --refine )
|
49
|
+
fi
|
50
|
+
|
51
|
+
if (( $# == 0 )); then
|
52
|
+
fileopts="."
|
53
|
+
else
|
54
|
+
fileopts="$@"
|
55
|
+
fi
|
56
|
+
fi
|
57
|
+
|
58
|
+
if (( ${#gitopts} == 0 )); then
|
59
|
+
gitopts=( -A )
|
60
|
+
else
|
61
|
+
typeset -U gitopts
|
62
|
+
fi
|
63
|
+
|
64
|
+
files="$(zomgit find ${options[@]} ${fileopts} 2>&1)"
|
65
|
+
local exitcode=$?
|
66
|
+
|
67
|
+
if (( ${exitcode} > 0 )); then
|
68
|
+
echo "${fg[red]}${files}${reset_color}"
|
69
|
+
return ${exitcode}
|
70
|
+
fi
|
71
|
+
|
72
|
+
local params
|
73
|
+
params=( add ${gitopts[@]} $(echo ${files} | command tr '\n' ' ') )
|
74
|
+
|
75
|
+
if type hub > /dev/null; then
|
76
|
+
command hub ${params[@]}
|
77
|
+
elif type gh > /dev/null; then
|
78
|
+
command gh ${params[@]}
|
79
|
+
else
|
80
|
+
command git ${params[@]}
|
81
|
+
fi
|
82
|
+
|
83
|
+
zomgit status
|
84
|
+
}
|
85
|
+
|
86
|
+
gau() {
|
87
|
+
ga --filter untracked ${@}
|
88
|
+
}
|
89
|
+
|
90
|
+
gap() {
|
91
|
+
ga ${@} -- -p
|
92
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
gco() {
|
2
|
+
local output
|
3
|
+
output="$(command git checkout ${@} 2>&1)"
|
4
|
+
local exitcode=$?
|
5
|
+
|
6
|
+
if (( $exitcode > 0 )); then
|
7
|
+
echo "${fg[red]}Error running git checkout!${reset_color}"
|
8
|
+
return $exitcode
|
9
|
+
fi
|
10
|
+
|
11
|
+
echo "${fg[green]}$(echo -n $output | command head -1)${reset_color}"
|
12
|
+
|
13
|
+
zomgit status
|
14
|
+
}
|
15
|
+
|
16
|
+
gcob() {
|
17
|
+
gco -b ${@}
|
18
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
gcl() {
|
2
|
+
local params
|
3
|
+
params=( clone --recursive )
|
4
|
+
|
5
|
+
if (( $# == 0 )); then
|
6
|
+
params=( $params $(pbpaste) )
|
7
|
+
else
|
8
|
+
params=( $params ${@} )
|
9
|
+
fi
|
10
|
+
|
11
|
+
if type hub > /dev/null; then
|
12
|
+
command hub ${params[@]}
|
13
|
+
elif type gh > /dev/null; then
|
14
|
+
command gh ${params[@]}
|
15
|
+
else
|
16
|
+
command git ${params[@]}
|
17
|
+
fi
|
18
|
+
}
|