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