warp-dir 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 +7 -0
- data/.atom-build.json +22 -0
- data/.codeclimate.yml +22 -0
- data/.gitignore +40 -0
- data/.idea/encodings.xml +6 -0
- data/.idea/misc.xml +14 -0
- data/.idea/modules.xml +8 -0
- data/.idea/runConfigurations/All_Specs.xml +33 -0
- data/.idea/vcs.xml +6 -0
- data/.idea/warp-dir.iml +224 -0
- data/.rspec +4 -0
- data/.rubocop.yml +1156 -0
- data/.travis.yml +13 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +114 -0
- data/ROADMAP.md +96 -0
- data/Rakefile +24 -0
- data/bin/console +11 -0
- data/bin/setup +8 -0
- data/bin/warp-dir +13 -0
- data/bin/warp-dir.bash +25 -0
- data/lib/warp.rb +4 -0
- data/lib/warp/dir.rb +65 -0
- data/lib/warp/dir/app/cli.rb +162 -0
- data/lib/warp/dir/app/response.rb +133 -0
- data/lib/warp/dir/command.rb +120 -0
- data/lib/warp/dir/command/add.rb +16 -0
- data/lib/warp/dir/command/help.rb +80 -0
- data/lib/warp/dir/command/install.rb +78 -0
- data/lib/warp/dir/command/list.rb +13 -0
- data/lib/warp/dir/command/ls.rb +31 -0
- data/lib/warp/dir/command/remove.rb +16 -0
- data/lib/warp/dir/command/warp.rb +24 -0
- data/lib/warp/dir/commander.rb +71 -0
- data/lib/warp/dir/config.rb +87 -0
- data/lib/warp/dir/errors.rb +60 -0
- data/lib/warp/dir/formatter.rb +77 -0
- data/lib/warp/dir/point.rb +53 -0
- data/lib/warp/dir/serializer.rb +14 -0
- data/lib/warp/dir/serializer/base.rb +43 -0
- data/lib/warp/dir/serializer/dotfile.rb +36 -0
- data/lib/warp/dir/store.rb +129 -0
- data/lib/warp/dir/version.rb +6 -0
- data/spec/fixtures/warprc +2 -0
- data/spec/spec_helper.rb +71 -0
- data/spec/support/cli_expectations.rb +118 -0
- data/spec/warp/dir/app/cli_spec.rb +225 -0
- data/spec/warp/dir/app/response_spec.rb +131 -0
- data/spec/warp/dir/command_spec.rb +62 -0
- data/spec/warp/dir/commands/add_spec.rb +40 -0
- data/spec/warp/dir/commands/install_spec.rb +20 -0
- data/spec/warp/dir/commands/list_spec.rb +37 -0
- data/spec/warp/dir/config_spec.rb +45 -0
- data/spec/warp/dir/errors_spec.rb +16 -0
- data/spec/warp/dir/formatter_spec.rb +38 -0
- data/spec/warp/dir/point_spec.rb +35 -0
- data/spec/warp/dir/store_spec.rb +105 -0
- data/warp-dir.gemspec +56 -0
- metadata +228 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require 'singleton'
|
|
2
|
+
|
|
3
|
+
module Warp
|
|
4
|
+
module Dir
|
|
5
|
+
module App
|
|
6
|
+
class Response
|
|
7
|
+
|
|
8
|
+
# Use Case exit code stream
|
|
9
|
+
#----------------------------------------------------------------
|
|
10
|
+
# Information / Help / List 0 STDOUT
|
|
11
|
+
# Error occured 1 STDERR
|
|
12
|
+
# Execute Shell Command 2 STDOUT
|
|
13
|
+
|
|
14
|
+
class Type < Struct.new(:exit_code, :stream)
|
|
15
|
+
def print(msg)
|
|
16
|
+
under_shell = ::Warp::Dir.eval_context?
|
|
17
|
+
if msg == ' '
|
|
18
|
+
under_shell ? stream.printf(%Q{printf '\\n'; }) : stream.printf("\n")
|
|
19
|
+
else
|
|
20
|
+
msg.split("\n").each do |line|
|
|
21
|
+
under_shell ? stream.printf(%Q{printf -- '#{line}\\n';}) : stream.printf("#{line}\n")
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def to_s
|
|
27
|
+
"code:#{exit_code}, stream:#{stream == STDOUT ? "STDOUT" : "STDERR"}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
INFO = Type.new(0, STDOUT)
|
|
32
|
+
ERROR = Type.new(1, STDERR)
|
|
33
|
+
SHELL = Type.new(2, STDOUT)
|
|
34
|
+
|
|
35
|
+
SHELL.instance_eval do
|
|
36
|
+
def print(msg)
|
|
37
|
+
under_shell = ::Warp::Dir.eval_context?
|
|
38
|
+
if under_shell then
|
|
39
|
+
stream.printf("#{msg};")
|
|
40
|
+
else
|
|
41
|
+
stream.printf(
|
|
42
|
+
'WARNING: '.red +
|
|
43
|
+
"This functionality is only available within shell eval{} context:\n\n\t#{msg.yellow.bold}\n\n" +
|
|
44
|
+
"Please install shell wrapper 'wd' via the 'install' command.\n")
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# can't change exit code in SHELL
|
|
49
|
+
def exit_code=(value)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
RETURN_TYPE = {
|
|
54
|
+
success: INFO,
|
|
55
|
+
error: ERROR,
|
|
56
|
+
shell: SHELL
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
attr_accessor :messages, :config
|
|
60
|
+
|
|
61
|
+
def initialize
|
|
62
|
+
@messages = []
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Public Methods
|
|
66
|
+
def print
|
|
67
|
+
raise ::ArgumentError.new('No type defined for Response object') unless @type
|
|
68
|
+
@type.print(@messages.shift) until @messages.empty?
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def exit!
|
|
73
|
+
raise ::ArgumentError.new('No type defined for Response object') unless @type
|
|
74
|
+
system_exit!(@type.exit_code)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Configure & Accessors
|
|
78
|
+
def configure(&block)
|
|
79
|
+
self.instance_eval(&block)
|
|
80
|
+
self
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def self.configure(&block)
|
|
84
|
+
self.instance.configure(&block)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def message(message = nil)
|
|
88
|
+
if message
|
|
89
|
+
@messages << message
|
|
90
|
+
self
|
|
91
|
+
else
|
|
92
|
+
@messages.join('')
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def type(a_type = nil)
|
|
97
|
+
if a_type
|
|
98
|
+
@type = a_type.kind_of?(Warp::Dir::App::Response::Type) ? a_type : RETURN_TYPE[a_type]
|
|
99
|
+
raise(::ArgumentError.new("Can't find response type #{a_type} #{@type}")) unless @type
|
|
100
|
+
self
|
|
101
|
+
else
|
|
102
|
+
@type
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def code(value = nil)
|
|
107
|
+
if value
|
|
108
|
+
@type.exit_code = value
|
|
109
|
+
self
|
|
110
|
+
else
|
|
111
|
+
@type.exit_code
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def inspect
|
|
116
|
+
"#{self.class.name}={#{type.inspect}, #{messages.inspect}}"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def to_s
|
|
120
|
+
"AppResponse[type: {#{type}}, messages: '#{messages.join(' ')}']"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
def system_exit!(code)
|
|
126
|
+
Kernel.exit(code) unless self.class.instance_variable_defined?(:@exit_disabled) && self.class.exit_disabled?
|
|
127
|
+
self
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require 'set'
|
|
2
|
+
require 'warp/dir/errors'
|
|
3
|
+
require 'warp/dir/formatter'
|
|
4
|
+
require 'warp/dir/commander'
|
|
5
|
+
require 'warp/dir/point'
|
|
6
|
+
require 'forwardable'
|
|
7
|
+
require_relative 'app/response'
|
|
8
|
+
|
|
9
|
+
module Warp
|
|
10
|
+
module Dir
|
|
11
|
+
class Command
|
|
12
|
+
class << self
|
|
13
|
+
def command_name
|
|
14
|
+
self.name.gsub(/.*::/, '').downcase.to_sym
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def help
|
|
18
|
+
sprintf('%16s %-20s %s%s',
|
|
19
|
+
self.command_name.to_s.yellow,
|
|
20
|
+
(self.send(:needs_a_point?) ? '<point>'.cyan : ' '.cyan),
|
|
21
|
+
self.send(:description).blue.bold,
|
|
22
|
+
(self.respond_to?(:aliases) && !aliases.empty? ? ", aka: " + aliases.join(', ').blue + '' : '')
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def inherited(subclass)
|
|
27
|
+
::Warp::Dir::Commander.instance.register(subclass)
|
|
28
|
+
subclass.class_eval do
|
|
29
|
+
extend Forwardable
|
|
30
|
+
def_delegators :@klazz, :command_name, :help, :description
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
subclass.instance_eval do
|
|
34
|
+
@description = nil
|
|
35
|
+
@aliases = []
|
|
36
|
+
@needs_a_point = false
|
|
37
|
+
|
|
38
|
+
class << self
|
|
39
|
+
def description(value = nil)
|
|
40
|
+
@description = value if value
|
|
41
|
+
@description
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def aliases(*args)
|
|
45
|
+
if args
|
|
46
|
+
@aliases << args unless !args || args.empty?
|
|
47
|
+
@aliases.flatten!
|
|
48
|
+
end
|
|
49
|
+
@aliases
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def needs_a_point?(value = nil)
|
|
53
|
+
@needs_a_point = value if value
|
|
54
|
+
@needs_a_point
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def installed_commands
|
|
61
|
+
::Warp::Dir::Commander.instance.commands
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
attr_accessor :store, :formatter, :point_name, :point_path, :point
|
|
66
|
+
|
|
67
|
+
def initialize(store, point_name = nil, point_path = nil)
|
|
68
|
+
@store = store
|
|
69
|
+
@formatter = ::Warp::Dir::Formatter.new(@store)
|
|
70
|
+
@klazz = self.class
|
|
71
|
+
if point_name
|
|
72
|
+
if point_name.is_a?(::Warp::Dir::Point)
|
|
73
|
+
self.point = point_name
|
|
74
|
+
else
|
|
75
|
+
self.point_name = point_name
|
|
76
|
+
end
|
|
77
|
+
self.point_path = point_path if point_path
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
if store.config.debug
|
|
81
|
+
require 'pp'
|
|
82
|
+
STDERR.printf 'Initialized Command: '.yellow.bold
|
|
83
|
+
pp self
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def config
|
|
88
|
+
self.store.config
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# def chain(another_command)
|
|
92
|
+
# command = Warp::Dir.commander.find(another_command.name)
|
|
93
|
+
# command.new(point_name, point_path).run
|
|
94
|
+
# end
|
|
95
|
+
def on(type, &block)
|
|
96
|
+
this_config = self.store.config
|
|
97
|
+
::Warp::Dir.on(type, &block).configure do
|
|
98
|
+
self.config = this_config
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def inspect
|
|
103
|
+
"#{self.class.name}[#{self.command_name}]->(#{self.description})"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def needs_point?
|
|
107
|
+
false # the default
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def puts(stream, *args)
|
|
111
|
+
if store.shell
|
|
112
|
+
stream.printf("printf \"#{args.join(', ')}\n\"")
|
|
113
|
+
else
|
|
114
|
+
stream.printf("#{args.join(', ')}\n")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
Warp::Dir.require_all_from '/dir/commands'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
|
|
3
|
+
class Warp::Dir::Command::Add < Warp::Dir::Command
|
|
4
|
+
description %q(Adds the current directory as a new Warp Point)
|
|
5
|
+
needs_a_point? true
|
|
6
|
+
aliases :new, :save, :store
|
|
7
|
+
|
|
8
|
+
def run(*args)
|
|
9
|
+
self.point_path ||= Dir.pwd
|
|
10
|
+
store.insert point_name: point_name, point_path: point_path, overwrite: config.force
|
|
11
|
+
|
|
12
|
+
on :success do
|
|
13
|
+
message 'Warp point saved!'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
require 'warp/dir/command/install'
|
|
3
|
+
class Warp::Dir::Command::Help < Warp::Dir::Command
|
|
4
|
+
description 'Show this extremely unhelpful text'
|
|
5
|
+
aliases :wtf
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def run(opts, flags = [])
|
|
9
|
+
commander = ::Warp::Dir.commander
|
|
10
|
+
on :success do
|
|
11
|
+
message USAGE
|
|
12
|
+
message ' '
|
|
13
|
+
message 'Warp Point Commands:'.bold.green
|
|
14
|
+
message ' '
|
|
15
|
+
commander.commands.select{|cmd| cmd.needs_a_point?}.map(&:command_name).each do |installed_commands|
|
|
16
|
+
message sprintf(" %s\n", commander.find(installed_commands).help)
|
|
17
|
+
end
|
|
18
|
+
message ' '
|
|
19
|
+
message 'Global Commands:'.bold.green
|
|
20
|
+
message ' '
|
|
21
|
+
commander.commands.reject{|cmd| cmd.needs_a_point?}.map(&:command_name).each do |installed_commands|
|
|
22
|
+
message sprintf(" %s\n", commander.find(installed_commands).help)
|
|
23
|
+
end
|
|
24
|
+
message EXAMPLES
|
|
25
|
+
message INSTALLATION
|
|
26
|
+
message opts.to_s
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
USAGE = <<EOF
|
|
31
|
+
#{"Usage:".bold.green} wd [ --command ] [ list | help ] [ wd-flags ]
|
|
32
|
+
wd [ --command ] [ [ warp ] | add [-f] | rm | ls ] [ wd flags ] <point> -- [ cmd-flags ]
|
|
33
|
+
wd --help | help
|
|
34
|
+
EOF
|
|
35
|
+
|
|
36
|
+
EXAMPLES = <<EOF
|
|
37
|
+
|
|
38
|
+
#{'Examples'.bold.green}
|
|
39
|
+
wd add proj add current directory as a warp point
|
|
40
|
+
cd ~/
|
|
41
|
+
wd proj jumps to proj
|
|
42
|
+
wd list lists all points
|
|
43
|
+
wd rm proj removes proj
|
|
44
|
+
EOF
|
|
45
|
+
|
|
46
|
+
if ::Warp::Dir::Command::Install.wrapper_installed?
|
|
47
|
+
INSTALLATION = <<EOF
|
|
48
|
+
|
|
49
|
+
#{'Installation'.bold.green}
|
|
50
|
+
It appears that you already have a wrapper installed in one of your
|
|
51
|
+
shell init files (#{::Warp::Dir::DOTFILES.join(', ')}
|
|
52
|
+
|
|
53
|
+
Which means that 'wd' should be working on your system. If not, edit your
|
|
54
|
+
shell init file, remove any lines related to warp-dir gem, and then reinstall:
|
|
55
|
+
|
|
56
|
+
#{'wd install [ --dotfile <filename> ]'.bold.green}
|
|
57
|
+
|
|
58
|
+
If you experience any problem, please log an issue at:
|
|
59
|
+
https://github.com/kigster/warp-dir/issues
|
|
60
|
+
EOF
|
|
61
|
+
else
|
|
62
|
+
INSTALLATION = <<EOF
|
|
63
|
+
|
|
64
|
+
#{'Installation'.bold.green}
|
|
65
|
+
In order for you to start warping all around, you must install the shell wrapper which
|
|
66
|
+
calls into the ruby to do the job. Shell wrapper function is required in order to
|
|
67
|
+
change directory in the outer shell (parent process). Do not worry about this if you
|
|
68
|
+
do not understand it, but please run this command:
|
|
69
|
+
|
|
70
|
+
#{'wd install [ --dotfile <filename> ]'.bold.green}
|
|
71
|
+
|
|
72
|
+
This command will ensure you have the wrapper installed in your ~/.bashrc or ~/.zshrc
|
|
73
|
+
files. Once installed, just restart your shell!
|
|
74
|
+
|
|
75
|
+
If you experience any problem, please log an issue at:
|
|
76
|
+
https://github.com/kigster/warp-dir/issues
|
|
77
|
+
EOF
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
require 'warp/dir'
|
|
3
|
+
class Warp::Dir::Command::Install < Warp::Dir::Command
|
|
4
|
+
description %q(Installs warp-dir shell wrapper in your ~/.bashrc)
|
|
5
|
+
needs_a_point? false
|
|
6
|
+
|
|
7
|
+
attr_accessor :installed, :existing, :wrapper, :shell_init_files
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def wrapper_installed?
|
|
11
|
+
::Warp::Dir::DOTFILES.any?{ |file| already_installed?(file) }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def already_installed?(file_path)
|
|
15
|
+
path = ::Warp::Dir.absolute(file_path)
|
|
16
|
+
matches = if File.exists?(path)
|
|
17
|
+
File.open path do |file|
|
|
18
|
+
file.find { |line| line =~ /warp-dir/ }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
matches
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def initialize(*args)
|
|
26
|
+
self.installed = []
|
|
27
|
+
self.existing = []
|
|
28
|
+
self.wrapper = File.read(::Warp::Dir::SHELL_WRAPPER)
|
|
29
|
+
self.shell_init_files = ::Warp::Dir::DOTFILES
|
|
30
|
+
super(*args)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def run(*args)
|
|
34
|
+
self.shell_init_files = config[:dotfile].split(',') if config[:dotfile]
|
|
35
|
+
self.shell_init_files.each { |dotfile| append_wrapper_to(dotfile) }
|
|
36
|
+
local_existing = self.existing
|
|
37
|
+
local_installed = self.installed
|
|
38
|
+
local_shell_files = self.shell_init_files
|
|
39
|
+
if installed.empty?
|
|
40
|
+
if existing.empty?
|
|
41
|
+
on :error do
|
|
42
|
+
if local_shell_files.size > 1 then
|
|
43
|
+
message "Shell init files #{local_shell_files.join(', ').yellow.bold} were not found on the filesystem.".red
|
|
44
|
+
else
|
|
45
|
+
message "Shell init file #{local_shell_files.join(', ').yellow.bold} was not found on the filesystem.".red
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
on :error do
|
|
50
|
+
message 'Looks like you already have shell support installed.'.red
|
|
51
|
+
message "#{local_existing.join(', ').yellow.bold} already warp-dir definition. Use --force to override."
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
else
|
|
55
|
+
on :success do
|
|
56
|
+
message 'Shell support is installed in the following files:'.green.bold
|
|
57
|
+
message "#{local_installed.join(', ')}".bold.yellow
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def append_wrapper_to(shell_init_file)
|
|
65
|
+
file = ::Warp::Dir.absolute(shell_init_file)
|
|
66
|
+
pre_installed = self.class.already_installed?(file)
|
|
67
|
+
self.existing << file if pre_installed
|
|
68
|
+
if File.exists?(file)
|
|
69
|
+
if !pre_installed || config[:force]
|
|
70
|
+
File.open(file, 'a') do |f|
|
|
71
|
+
f.write(wrapper)
|
|
72
|
+
end
|
|
73
|
+
self.installed << shell_init_file
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'warp/dir/command'
|
|
2
|
+
require 'warp/dir/formatter'
|
|
3
|
+
|
|
4
|
+
class Warp::Dir::Command::List < Warp::Dir::Command
|
|
5
|
+
description %q(Print all stored warp points)
|
|
6
|
+
|
|
7
|
+
def run(*args)
|
|
8
|
+
formatted_list = ::Warp::Dir::Formatter.new(store).format_store
|
|
9
|
+
on :success do
|
|
10
|
+
message formatted_list.blue.bold
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|