Class: Rush::Shell

Inherits:
Object
  • Object
show all
Defined in:
lib/rush/shell.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeShell

Set up the user’s environment, including a pure binding into which env.rb and commands.rb are mixed.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rush/shell.rb', line 9

def initialize
	root = Rush::Dir.new('/')
	home = Rush::Dir.new(ENV['HOME']) if ENV['HOME']
	pwd = Rush::Dir.new(ENV['PWD']) if ENV['PWD']

	@config = Rush::Config.new

	@config.load_history.each do |item|
		Readline::HISTORY.push(item)
	end

	Readline.basic_word_break_characters = ""
	Readline.completion_append_character = nil
	Readline.completion_proc = completion_proc

	@box = Rush::Box.new
	@pure_binding = @box.instance_eval "binding"
	$last_res = nil

	eval @config.load_env, @pure_binding

	commands = @config.load_commands
	Rush::Dir.class_eval commands
	Array.class_eval commands
end

Instance Attribute Details

#suppress_outputObject

Returns the value of attribute suppress_output.



6
7
8
# File 'lib/rush/shell.rb', line 6

def suppress_output
  @suppress_output
end

Instance Method Details

#completion_procObject

Try to do tab completion on dir square brackets accessors.

Example:

dir[‘subd # presing tab here will produce dir[’subdir/ if subdir exists

This isn’t that cool yet, because it can’t do multiple levels of subdirs. It does work remotely, though, which is pretty sweet.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rush/shell.rb', line 124

def completion_proc
	proc do |input|
		possible_var, quote, partial_path, pre = path_parts(input)
		if possible_var
			original_var, fixed_path = possible_var, ''
			if /^(.+\/)([^\/]+)$/ === partial_path
				fixed_path, partial_path = $~.captures
				possible_var += "['#{fixed_path}']"
			end
			full_path = eval("#{possible_var}.full_path", @pure_binding) rescue nil
			box = eval("#{possible_var}.box", @pure_binding) rescue nil
			if full_path and box
				dir = Rush::Dir.new(full_path, box)
				return dir.entries.select do |e|
					e.name.match(/^#{Regexp.escape(partial_path)}/)
				end.map do |e|
					(pre || '') + original_var + '[' + quote + fixed_path + e.name + (e.dir? ? "/" : "")
				end
			end
		end
		nil
	end
end

#execute(cmd) ⇒ Object

Run a single command.



36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/rush/shell.rb', line 36

def execute(cmd)
	res = eval(cmd, @pure_binding)
	$last_res = res
	eval("_ = $last_res", @pure_binding)
	print_result res
rescue Rush::Exception => e
	puts "Exception #{e.class} -> #{e.message}"
rescue ::Exception => e
	puts "Exception #{e.class} -> #{e.message}"
	e.backtrace.each do |t|
		puts "   #{::File.expand_path(t)}"
	end
end

#finishObject

Save history to ~/.rush/history when the shell exists.



64
65
66
67
68
# File 'lib/rush/shell.rb', line 64

def finish
	@config.save_history(Readline::HISTORY.to_a)
	puts
	exit
end

#path_parts(input) ⇒ Object

:nodoc:



109
110
111
112
113
114
# File 'lib/rush/shell.rb', line 109

def path_parts(input)   # :nodoc:
	input.match(/(\w+(?:\[[^\]]+\])*)\[(['"])([^\]]+)$/)
	$~.to_a.slice(1, 3).push($~.pre_match)
rescue
	[ nil, nil, nil, nil ]
end

Nice printing of different return types, particularly Rush::SearchResults.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rush/shell.rb', line 71

def print_result(res)
	return if self.suppress_output
	if res.kind_of? String
		puts res
	elsif res.kind_of? Rush::SearchResults
		widest = res.entries.map { |k| k.full_path.length }.max
		res.entries_with_lines.each do |entry, lines|
			print entry.full_path
			print ' ' * (widest - entry.full_path.length + 2)
			print "=> "
			print res.colorize(lines.first.strip.head(30))
			print "..." if lines.first.strip.length > 30
			if lines.size > 1
				print " (plus #{lines.size - 1} more matches)"
			end
			print "\n"
		end
		puts "#{res.entries.size} matching files with #{res.lines.size} matching lines"
	elsif res.respond_to? :each
		counts = {}
		res.each do |item|
			puts item
			counts[item.class] ||= 0
			counts[item.class] += 1
		end
		if counts == {}
			puts "=> (empty set)"
		else
			count_s = counts.map do |klass, count|
				"#{count} x #{klass}"
			end.join(', ')
			puts "=> #{count_s}"
		end
	else
		puts "=> #{res.inspect}"
	end
end

#runObject

Run the interactive shell using readline.



51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rush/shell.rb', line 51

def run
	loop do
		cmd = Readline.readline('rush> ')

		finish if cmd.nil? or cmd == 'exit'
		next if cmd == ""
		Readline::HISTORY.push(cmd)

		execute(cmd)
	end
end