about summary refs log tree commit diff stats
path: root/code/fm.rb
blob: 793c118a580873667ce5f3c62186b39caac1917e (plain) (blame)
1
2
3
4
5
6
7
8
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
require 'thread'

module Fm
	extend self
	COPY_PRIORITY = -2

	COLUMNS = 4
	
	def self.initialize(pwd=nil)
		@bars = []
		@bars_thread = nil

		@entering_directory = true
		@sort_time = Time.now
		
		@buffer = ''
		@pwd = nil
		@search_string = ''
		@copy = []
		@ignore_until = nil
		@trash = File.expand_path('~/.trash')
		pwd ||= Dir.getwd

		# `' and `` are the original PWD unless overwritten by .rangerrc
		@memory = {
			'`' => pwd,
			'\'' => pwd
		}

		# Read the .rangerrc
		@rangerrc = File.expand_path(Option.bookmark_file)
		if (File.exists?(@rangerrc))
			content = File.read(@rangerrc)
			unless content.empty?
				loaded = Marshal.load(content) rescue nil
				if Hash === loaded
					@memory.update(loaded)
				end
			end
		end
		@dump_config_on_exit = true

		# `0 is always the original PWD
		@memory['0'] = pwd

		boot_up(pwd)
	end

	attr_reader(:dirs, :pwd, :sort_time)

	def refresh()
		begin
			@pwd.refresh
			update_pointers
			draw if CLI.running?
		rescue
			lograise
		end
	end

	def edit( filename, mode=nil, flags=nil )
		file = Directory::Entry.new( filename )
		file.refresh
		raise "File doesn't exist" unless file.exists?
		runcontext = RunContext.new( file, mode, flags, 'editor' )
		externally do
			Action.run( runcontext )
		end
	end

	def reload_types()
		old_verbose_level = $VERBOSE
		$VERBOSE = nil
		load 'data/types.rb'
		load 'data/apps.rb'
		$VERBOSE = old_verbose_level
	end

	def dump_pwd_to_3()
		f = File.open(3, 'a')
		f.puts(Fm.pwd.path)
#		f.puts(Fm.pwd.path.bash_escape)
		f.close
	end

	def boot_up(pwd=nil)
		pwd ||= @pwd.path || Dir.getwd
		Scheduler.reset

		reload_types

		@dirs = Hash.new() do |hash, key|
			hash[key] = newdir = Directory.new(key)
#			newdir.schedule
			newdir
		end

		@path = [@dirs['/']]
		enter_dir(pwd)

		Scheduler.run
	end

	def lines
		CLI::lines - @bars.size
	end

	def externally(&block)
		closei
		yield if block_given?
		CLI.clear_keybuffer
		starti
	end

	def dump
		if defined? @dump_config_on_exit
			begin
				remember_dir
				dumped = Marshal.dump(@memory)
				File.open(@rangerrc, 'w') do |f|
					f.write(dumped)
				end
			rescue Exception
			end
		end
	end

	def on_interrupt
		@buffer = ''
		sleep 0.2
	end

	def terminal_killed?
		Process.ppid == 1
	end

	def main_loop
		bool = false
		while true
			exit if terminal_killed?
			@pwd.make_sure_cursor_is_in_range

			begin
				draw()
			rescue Interrupt
				on_interrupt
			rescue Exception
				log($!)
				log(caller)
			end

			begin
				key = geti
				CLI.clear_keybuffer
				press(key)
			rescue Interrupt
				on_interrupt
			end
		end
	end

	def current_path() @pwd.path end

	def reset_title() set_title("ranger: #{@pwd.path}") end

	def enter_dir_safely(dir)
		dir = File.expand_path(dir)
		if File.exists?(dir) and File.directory?(dir)
			olddir = @pwd.path
			begin
				enter_dir(dir)
				return true
			rescue
				log($!)
				log(caller)
				enter_dir(olddir)
				return false
			end
		end
	end

	def enter_dir(dir)
		@pwd.restore if @pwd
		@marked = []
		dir = File.expand_path(dir)
		return unless File.exists? dir

		oldpath = @path.dup

		# NOTE: @dirs[unknown] is not nil but Directory.new(unknown)
		## create @path, an array of directory objects
		@path = [@dirs['/']]
		unless dir == '/'
			dir.slice(0)
			accumulated = '/'
			for part in dir.split('/')
				unless part.empty?
					accumulated = File.join(accumulated, part)
					@path << @dirs[accumulated]
				end
			end
		end

		@pwd = @path.last
		@pwd.refresh! if @pwd.changed?
		@pwd.make_sure_cursor_is_in_range

		## initialize directories in @pwd
		@pwd.files_raw.dup.each do |x|
			@dirs[x] if File.directory?(x)
		end

		## set the title
		reset_title()

		## ???
		if @path.size < oldpath.size
			@pwd.pos = @pwd.files_raw.index(oldpath.last.path) || 0
		end

		i = 0

		@entering_directory = true
		Dir.chdir(@pwd.path)
	end

	def update_pointers
		@path.each_with_index do |p, i|
			## is this line necessary?
#			p.schedule
			unless i == @path.size - 1
				p.pointed_file = @path[i+1].path
			end
		end
	end

	def move_to_trash!(fn)
		unless File.exists?(@trash)
			Dir.mkdir(@trash)
		end
		new_path = File.join(@trash, fn.basename)

		Action.move(fn, new_path)

		return new_path
	end

	def move_to_trash(file)
		unless file
			return
		end

		if String === file
			file = Directory::Entry.new(file)
		end

		if file.exists?
			if file.dir?
				if !file.in?(@trash) and file.size > 0
					return move_to_trash!(file)
				else
					Dir.rmdir(file.path) rescue nil
				end
			elsif file.symlink?
				file.delete!
			else
				if !file.in?(@trash) and file.size > 0
					return move_to_trash!(file)
				else
					file.delete!
				end
			end
		end
		return nil
	end

	def bar_add(bar)
		if @bars.empty?
			# This thread updates the statusbars
			@bars_thread = Thread.new do
				while true
					draw_bars
					sleep 0.5
				end
			end
		end
		@bars << bar
	end

	def bar_del(bar)
		@bars.delete(bar)
		if @bars.empty?
			@bars_thread.kill
			@bars_thread = nil
			draw
		end
	end

	def currentfile
		@pwd.files[@pwd.pos]
	end
	def getfiles
		@marked.empty? ? [currentfile] : @marked.dup
	end
	alias selection getfiles
end