about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2012-08-05 08:11:33 +0200
committerhut <hut@lavabit.com>2012-08-05 14:36:33 +0200
commit7f9df493dd6b0fd13abe93ddfea2755ee24c3d72 (patch)
treeeb3a6001afccb9822049aa8c5b5dbbba3d3e3fea
parente38d42ca55285b61ed70722da92d9871c8686f88 (diff)
downloadranger-7f9df493dd6b0fd13abe93ddfea2755ee24c3d72.tar.gz
Replaced core.environment with core.tab
The Environment class was weird to begin with.  It had attributes and
methods that belonged to other classes. For example, keybinding
management (the attributes keybuffer and keymaps) should go to gui.ui,
directory management (garbage_collect, get_directory) should be in
core.fm whereas entering directories (enter_dir) and managing history
(history_go) should be the task of a separate Tab class.

This commit fixes it, all references to env should be only for backwards
compatibility now.  I still need to rewrite the tabbing API in
core.actions to work with the new system.  Every tab that is opened will
have its own Tab instance with its own history and pointer.  Tab, unlike
Environment, is no SignalDispatcher - Environment's signals were moved
to fm.

BEFORE: fm.env.cf
AFTER : fm.thisfile

BEFORE: fm.env.cwd
AFTER : fm.thisdir

BEFORE: fm.env.signal_bind("move", ...)   # same for the "cd" signal
AFTER : fm.signal_bind("move", ...)

BEFORE: fm.env.keybuffer                  # same for fm.env.keymaps
AFTER : fm.ui.keybuffer

BEFORE: fm.env.get_directory("/usr/lib")  # same for half of the env methods
AFTER : fm.get_directory("/usr/lib")

BEFORE: fm.env.get_selection()  # same for the other half of the env methods
AFTER : fm.thistab.get_selection()

Old configurations and hacks should still work because I added a
compatibility layer for the Environment class which translates all
getters and setters to the respective call of the new class.

What will NOT work are the Environment signals, please bind them to fm
instead.
-rw-r--r--ranger/api/commands.py4
-rw-r--r--ranger/config/commands.py58
-rw-r--r--ranger/config/rc.conf4
-rw-r--r--ranger/core/actions.py131
-rw-r--r--ranger/core/environment.py198
-rw-r--r--ranger/core/fm.py42
-rw-r--r--ranger/core/main.py7
-rw-r--r--ranger/core/tab.py140
-rw-r--r--ranger/fsobject/directory.py4
-rw-r--r--ranger/gui/displayable.py2
-rw-r--r--ranger/gui/ui.py6
-rw-r--r--ranger/gui/widgets/browsercolumn.py10
-rw-r--r--ranger/gui/widgets/browserview.py11
-rw-r--r--ranger/gui/widgets/statusbar.py29
-rw-r--r--ranger/gui/widgets/titlebar.py14
15 files changed, 369 insertions, 291 deletions
diff --git a/ranger/api/commands.py b/ranger/api/commands.py
index 97ef415c..aaadde5d 100644
--- a/ranger/api/commands.py
+++ b/ranger/api/commands.py
@@ -179,7 +179,7 @@ class Command(FileManagerAware):
 	def _tab_only_directories(self):
 		from os.path import dirname, basename, expanduser, join
 
-		cwd = self.fm.env.cwd.path
+		cwd = self.fm.thisdir.path
 
 		rel_dest = self.rest(1)
 
@@ -225,7 +225,7 @@ class Command(FileManagerAware):
 	def _tab_directory_content(self):
 		from os.path import dirname, basename, expanduser, join
 
-		cwd = self.fm.env.cwd.path
+		cwd = self.fm.thisdir.path
 
 		rel_dest = self.rest(1)
 
diff --git a/ranger/config/commands.py b/ranger/config/commands.py
index 88b50860..8579b019 100644
--- a/ranger/config/commands.py
+++ b/ranger/config/commands.py
@@ -54,16 +54,16 @@
 # self.fm.notify(string): Print the given string on the screen.
 # self.fm.notify(string, bad=True): Print the given string in RED.
 # self.fm.reload_cwd(): Reload the current working directory.
-# self.fm.env.cwd: The current working directory. (A File object.)
-# self.fm.env.cf: The current file. (A File object too.)
-# self.fm.env.cwd.get_selection(): A list of all selected files.
+# self.fm.thisdir: The current working directory. (A File object.)
+# self.fm.thisfile: The current file. (A File object too.)
+# self.fm.thistab.get_selection(): A list of all selected files.
 # self.fm.execute_console(string): Execute the string as a ranger command.
 # self.fm.open_console(string): Open the console with the given string
 #      already typed in for you.
 # self.fm.move(direction): Moves the cursor in the given direction, which
 #      can be something like down=3, up=5, right=1, left=1, to=6, ...
 #
-# File objects (for example self.fm.env.cf) have these useful attributes and
+# File objects (for example self.fm.thisfile) have these useful attributes and
 # methods:
 #
 # cf.path: The path to the file.
@@ -126,7 +126,7 @@ class cd(Command):
 	def tab(self):
 		from os.path import dirname, basename, expanduser, join
 
-		cwd = self.fm.env.cwd.path
+		cwd = self.fm.thisdir.path
 		rel_dest = self.rest(1)
 
 		bookmarks = [v.path for v in self.fm.bookmarks.dct.values()
@@ -222,7 +222,7 @@ class shell(Command):
 			return (start + program + ' ' for program \
 					in get_executables() if program.startswith(command))
 		if position_of_last_space == len(command) - 1:
-			selection = self.fm.env.get_selection()
+			selection = self.fm.thistab.get_selection()
 			if len(selection) == 1:
 				return self.line + selection[0].shell_escaped_basename + ' '
 			else:
@@ -230,14 +230,14 @@ class shell(Command):
 		else:
 			before_word, start_of_word = self.line.rsplit(' ', 1)
 			return (before_word + ' ' + file.shell_escaped_basename \
-					for file in self.fm.env.cwd.files \
+					for file in self.fm.thisdir.files \
 					if file.shell_escaped_basename.startswith(start_of_word))
 
 class open_with(Command):
 	def execute(self):
 		app, flags, mode = self._get_app_flags_mode(self.rest(1))
 		self.fm.execute_file(
-				files = [f for f in self.fm.env.cwd.get_selection()],
+				files = [f for f in self.fm.thistab.get_selection()],
 				app = app,
 				flags = flags,
 				mode = mode)
@@ -346,7 +346,7 @@ class find(Command):
 
 	def quick(self):
 		self.count = 0
-		cwd = self.fm.env.cwd
+		cwd = self.fm.thisdir
 		arg = self.rest(1)
 		if not arg:
 			return False
@@ -369,7 +369,7 @@ class find(Command):
 				self.count += 1
 				if self.count == 1:
 					cwd.move(to=(cwd.pointer + i) % len(cwd.files))
-					self.fm.env.cf = cwd.pointed_obj
+					self.fm.thisfile.cf = cwd.pointed_obj
 			if self.count > 1:
 				return False
 			i += 1
@@ -490,8 +490,8 @@ class delete(Command):
 			# user did not confirm deletion
 			return
 
-		cwd = self.fm.env.cwd
-		cf = self.fm.env.cf
+		cwd = self.fm.thisdir
+		cf = self.fm.thisfile.cf
 
 		if cwd.marked_items or (cf.is_directory and not cf.is_link \
 				and len(os.listdir(cf.path)) > 0):
@@ -513,7 +513,7 @@ class mark(Command):
 
 	def execute(self):
 		import re
-		cwd = self.fm.env.cwd
+		cwd = self.fm.thisdir
 		input = self.rest(1)
 		searchflags = re.UNICODE
 		if input.lower() == input: # "smartcase"
@@ -604,7 +604,7 @@ class mkdir(Command):
 		from os.path import join, expanduser, lexists
 		from os import mkdir
 
-		dirname = join(self.fm.env.cwd.path, expanduser(self.rest(1)))
+		dirname = join(self.fm.thisdir.path, expanduser(self.rest(1)))
 		if not lexists(dirname):
 			mkdir(dirname)
 		else:
@@ -621,7 +621,7 @@ class touch(Command):
 	def execute(self):
 		from os.path import join, expanduser, lexists
 
-		fname = join(self.fm.env.cwd.path, expanduser(self.rest(1)))
+		fname = join(self.fm.thisdir.path, expanduser(self.rest(1)))
 		if not lexists(fname):
 			open(fname, 'a').close()
 		else:
@@ -637,7 +637,7 @@ class edit(Command):
 
 	def execute(self):
 		if not self.arg(1):
-			self.fm.edit_file(self.fm.env.cf.path)
+			self.fm.edit_file(self.fm.thisfile.path)
 		else:
 			self.fm.edit_file(self.rest(1))
 
@@ -655,7 +655,7 @@ class eval_(Command):
 
 	Examples:
 	:eval fm
-	:eval len(fm.env.directories)
+	:eval len(fm.directories)
 	:eval p("Hello World!")
 	"""
 	name = 'eval'
@@ -702,16 +702,16 @@ class rename(Command):
 		if not new_name:
 			return self.fm.notify('Syntax: rename <newname>', bad=True)
 
-		if new_name == self.fm.env.cf.basename:
+		if new_name == self.fm.thisfile.basename:
 			return
 
 		if access(new_name, os.F_OK):
 			return self.fm.notify("Can't rename: file already exists!", bad=True)
 
-		self.fm.rename(self.fm.env.cf, new_name)
+		self.fm.rename(self.fm.thisfile, new_name)
 		f = File(new_name)
-		self.fm.env.cwd.pointed_obj = f
-		self.fm.env.cf = f
+		self.fm.thisdir.pointed_obj = f
+		self.fm.thisfile = f
 
 	def tab(self):
 		return self._tab_directory_content()
@@ -743,7 +743,7 @@ class chmod(Command):
 			self.fm.notify("Need an octal number between 0 and 777!", bad=True)
 			return
 
-		for file in self.fm.env.get_selection():
+		for file in self.fm.thistab.get_selection():
 			try:
 				os.chmod(file.path, mode)
 			except Exception as ex:
@@ -752,7 +752,7 @@ class chmod(Command):
 		try:
 			# reloading directory.  maybe its better to reload the selected
 			# files only.
-			self.fm.env.cwd.load_content()
+			self.fm.thisdir.load_content()
 		except:
 			pass
 
@@ -776,7 +776,7 @@ class bulkrename(Command):
 		py3 = sys.version > "3"
 
 		# Create and edit the file list
-		filenames = [f.basename for f in self.fm.env.get_selection()]
+		filenames = [f.basename for f in self.fm.thistab.get_selection()]
 		listfile = tempfile.NamedTemporaryFile()
 
 		if py3:
@@ -823,7 +823,7 @@ class relink(Command):
 		from ranger.fsobject import File
 
 		new_path = self.rest(1)
-		cf = self.fm.env.cf
+		cf = self.fm.thisfile
 
 		if not new_path:
 			return self.fm.notify('Syntax: relink <newpath>', bad=True)
@@ -841,12 +841,12 @@ class relink(Command):
 			self.fm.notify(err)
 
 		self.fm.reset()
-		self.fm.env.cwd.pointed_obj = cf
-		self.fm.env.cf = cf
+		self.fm.thisdir.pointed_obj = cf
+		self.fm.thisfile = cf
 
 	def tab(self):
 		if not self.rest(1):
-			return self.line+os.readlink(self.fm.env.cf.path)
+			return self.line+os.readlink(self.fm.thisfile.path)
 		else:
 			return self._tab_directory_content()
 
@@ -1009,5 +1009,5 @@ class grep(Command):
 		if self.rest(1):
 			action = ['grep', '--color=always', '--line-number']
 			action.extend(['-e', self.rest(1), '-r'])
-			action.extend(f.path for f in self.fm.env.get_selection())
+			action.extend(f.path for f in self.fm.thistab.get_selection())
 			self.fm.execute_command(action, flags='p')
diff --git a/ranger/config/rc.conf b/ranger/config/rc.conf
index a347d116..1b802fd5 100644
--- a/ranger/config/rc.conf
+++ b/ranger/config/rc.conf
@@ -139,8 +139,8 @@ map yn shell -d echo -n %f    | xsel -i
 map =  chmod
 
 map cw console rename 
-map A  eval fm.open_console('rename ' + fm.env.cf.basename)
-map I  eval fm.open_console('rename ' + fm.env.cf.basename, position=7)
+map A  eval fm.open_console('rename ' + fm.thisfile.basename)
+map I  eval fm.open_console('rename ' + fm.thisfile.basename, position=7)
 
 map pp paste
 map po paste overwrite=True
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index da4c480c..bf2e84dd 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -40,9 +40,9 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 	def reset(self):
 		"""Reset the filemanager, clearing the directory buffer"""
-		old_path = self.env.cwd.path
+		old_path = self.thisdir.path
 		self.previews = {}
-		self.env.garbage_collect(-1, self.tabs)
+		self.garbage_collect(-1, self.tabs)
 		self.enter_dir(old_path)
 		self.change_mode('normal')
 
@@ -50,9 +50,9 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		if mode == self.mode:
 			return
 		if mode == 'visual':
-			self._visual_start       = self.env.cwd.pointed_obj
-			self._visual_start_pos   = self.env.cwd.pointer
-			self._previous_selection = set(self.env.cwd.marked_items)
+			self._visual_start       = self.thisdir.pointed_obj
+			self._visual_start_pos   = self.thisdir.pointer
+			self._previous_selection = set(self.thisdir.marked_items)
 			self.mark_files(val=not self._visual_reverse, movedown=False)
 		elif mode == 'normal':
 			if self.mode == 'visual':
@@ -73,7 +73,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 	def reload_cwd(self):
 		try:
-			cwd = self.env.cwd
+			cwd = self.thisdir
 		except:
 			pass
 		cwd.unload()
@@ -102,7 +102,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 			self.loader.remove(index=0)
 
 	def get_cumulative_size(self):
-		for f in self.env.get_selection() or ():
+		for f in self.thistab.get_selection() or ():
 			f.look_up_cumulative_size()
 		self.ui.status.request_redraw()
 		self.ui.redraw_main_column()
@@ -168,13 +168,13 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 		macros['rangerdir'] = ranger.RANGERDIR
 
-		if self.fm.env.cf:
-			macros['f'] = self.fm.env.cf.basename
+		if self.fm.thisfile:
+			macros['f'] = self.fm.thisfile.basename
 		else:
 			macros['f'] = MACRO_FAIL
 
-		if self.fm.env.get_selection:
-			macros['s'] = [fl.basename for fl in self.fm.env.get_selection()]
+		if self.fm.thistab.get_selection:
+			macros['s'] = [fl.basename for fl in self.fm.thistab.get_selection()]
 		else:
 			macros['s'] = MACRO_FAIL
 
@@ -183,14 +183,14 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		else:
 			macros['c'] = MACRO_FAIL
 
-		if self.fm.env.cwd.files:
-			macros['t'] = [fl.basename for fl in self.fm.env.cwd.files
+		if self.fm.thisdir.files:
+			macros['t'] = [fl.basename for fl in self.fm.thisdir.files
 					if fl.realpath in (self.fm.tags or [])]
 		else:
 			macros['t'] = MACRO_FAIL
 
-		if self.fm.env.cwd:
-			macros['d'] = self.fm.env.cwd.path
+		if self.fm.thisdir:
+			macros['d'] = self.fm.thisdir.path
 		else:
 			macros['d'] = '.'
 
@@ -272,11 +272,11 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		# ranger can act as a file chooser when running with --choosefile=...
 		if mode == 0 and 'label' not in kw:
 			if ranger.arg.choosefile:
-				open(ranger.arg.choosefile, 'w').write(self.fm.env.cf.path)
+				open(ranger.arg.choosefile, 'w').write(self.fm.thisfile.path)
 
 			if ranger.arg.choosefiles:
 				open(ranger.arg.choosefiles, 'w').write("".join(
-					f.path + "\n" for f in self.fm.env.get_selection()))
+					f.path + "\n" for f in self.fm.thistab.get_selection()))
 
 			if ranger.arg.choosefile or ranger.arg.choosefiles:
 				raise SystemExit()
@@ -288,7 +288,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 		flags = kw.get('flags', '')
 		if 'c' in squash_flags(flags):
-			files = [self.fm.env.cf]
+			files = [self.fm.thisfile]
 
 		self.signal_emit('execute.before', keywords=kw)
 		filenames = [f.path for f in files]
@@ -318,7 +318,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		self.move(to=2, pages=True)  # moves to page 2.
 		self.move(to=1, percentage=True)  # moves to 80%
 		"""
-		cwd = self.env.cwd
+		cwd = self.thisdir
 		direction = Direction(kw)
 		if 'left' in direction or direction.left() > 0:
 			steps = direction.left()
@@ -328,16 +328,16 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 				directory = os.path.join(*(['..'] * steps))
 			except:
 				return
-			self.env.enter_dir(directory)
+			self.thistab.enter_dir(directory)
 			self.change_mode('normal')
 		if cwd and cwd.accessible and cwd.content_loaded:
 			if 'right' in direction:
 				mode = 0
 				if narg is not None:
 					mode = narg
-				cf = self.env.cf
-				selection = self.env.get_selection()
-				if not self.env.enter_dir(cf) and selection:
+				cf = self.thisfile
+				selection = self.thistab.get_selection()
+				if not self.thistab.enter_dir(cf) and selection:
 					if self.execute_file(selection, mode=mode) is False:
 						self.open_console('open_with ')
 			elif direction.vertical() and cwd.files:
@@ -378,35 +378,36 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		self.change_mode('normal')
 		if narg is not None:
 			n *= narg
-		parent = self.env.at_level(-1)
+		parent = self.thistab.at_level(-1)
 		if parent is not None:
 			if parent.pointer + n < 0:
 				n = 0 - parent.pointer
 			try:
-				self.env.enter_dir(parent.files[parent.pointer+n])
+				self.thistab.enter_dir(parent.files[parent.pointer+n])
 			except IndexError:
 				pass
 
 	def select_file(self, path):
 		path = path.strip()
 		if self.enter_dir(os.path.dirname(path)):
-			self.env.cwd.move_to_obj(path)
+			self.thisdir.move_to_obj(path)
 
 	def history_go(self, relative):
 		"""Move back and forth in the history"""
-		self.env.history_go(int(relative))
+		self.thistab.history_go(int(relative))
 
+	# TODO: remove this method since it is not used?
 	def scroll(self, relative):
 		"""Scroll down by <relative> lines"""
 		if self.ui.browser and self.ui.browser.main_column:
 			self.ui.browser.main_column.scroll(relative)
-			self.env.cf = self.env.cwd.pointed_obj
+			self.thisfile = self.thisdir.pointed_obj
 
 	def enter_dir(self, path, remember=False, history=True):
 		"""Enter the directory at the given path"""
-		cwd = self.env.cwd
-		result = self.env.enter_dir(path, history=history)
-		if cwd != self.env.cwd:
+		cwd = self.thisdir
+		result = self.thistab.enter_dir(path, history=history)
+		if cwd != self.thisdir:
 			if remember:
 				self.bookmarks.remember(cwd)
 			self.change_mode('normal')
@@ -418,14 +419,14 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 	def traverse(self):
 		self.change_mode('normal')
-		cf = self.env.cf
-		cwd = self.env.cwd
+		cf = self.thisfile
+		cwd = self.thisdir
 		if cf is not None and cf.is_directory:
 			self.enter_dir(cf.path)
 		elif cwd.pointer >= len(cwd) - 1:
 			while True:
 				self.move(left=1)
-				cwd = self.env.cwd
+				cwd = self.thisdir
 				if cwd.pointer < len(cwd) - 1:
 					break
 				if cwd.path == '/':
@@ -467,7 +468,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def edit_file(self, file=None):
 		"""Calls execute_file with the current file and label='editor'"""
 		if file is None:
-			file = self.env.cf
+			file = self.thisfile
 		elif isinstance(file, str):
 			file = File(os.path.expanduser(file))
 		if file is None:
@@ -476,23 +477,23 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 	def toggle_option(self, string):
 		"""Toggle a boolean option named <string>"""
-		if isinstance(self.env.settings[string], bool):
-			self.env.settings[string] ^= True
+		if isinstance(self.settings[string], bool):
+			self.settings[string] ^= True
 
 	def set_option(self, optname, value):
 		"""Set the value of an option named <optname>"""
-		self.env.settings[optname] = value
+		self.settings[optname] = value
 
 	def sort(self, func=None, reverse=None):
 		if reverse is not None:
-			self.env.settings['sort_reverse'] = bool(reverse)
+			self.settings['sort_reverse'] = bool(reverse)
 
 		if func is not None:
-			self.env.settings['sort'] = str(func)
+			self.settings['sort'] = str(func)
 
 	def set_filter(self, fltr):
 		try:
-			self.env.cwd.filter = fltr
+			self.thisdir.filter = fltr
 		except:
 			pass
 
@@ -506,10 +507,10 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		val - mark or unmark?
 		"""
 
-		if self.env.cwd is None:
+		if self.thisdir is None:
 			return
 
-		cwd = self.env.cwd
+		cwd = self.thisdir
 
 		if not cwd.accessible:
 			return
@@ -543,7 +544,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		self.ui.status.need_redraw = True
 
 	def mark_in_direction(self, val=True, dirarg=None):
-		cwd = self.env.cwd
+		cwd = self.thisdir
 		direction = Direction(dirarg)
 		pos, selected = direction.select(lst=cwd.files, current=cwd.pointer,
 				pagesize=self.ui.termsize[0])
@@ -562,7 +563,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 				text = re.compile(text, re.L | re.U | re.I)
 			except:
 				return False
-		self.env.last_search = text
+		self.thistab.last_search = text
 		self.search_next(order='search', offset=offset)
 
 	def search_next(self, order=None, offset=1, forward=True):
@@ -575,7 +576,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 		if order in ('search', 'tag'):
 			if order == 'search':
-				arg = self.env.last_search
+				arg = self.thistab.last_search
 				if arg is None:
 					return False
 				if hasattr(arg, 'search'):
@@ -585,10 +586,10 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 			elif order == 'tag':
 				fnc = lambda x: x.realpath in self.tags
 
-			return self.env.cwd.search_fnc(fnc=fnc, offset=offset, forward=forward)
+			return self.thisdir.search_fnc(fnc=fnc, offset=offset, forward=forward)
 
 		elif order in ('size', 'mimetype', 'ctime', 'mtime', 'atime'):
-			cwd = self.env.cwd
+			cwd = self.thisdir
 			if original_order is not None or not cwd.cycle_list:
 				lst = list(cwd.files)
 				if order == 'size':
@@ -621,7 +622,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		if not self.tags:
 			return
 		if paths is None:
-			tags = tuple(x.realpath for x in self.env.get_selection())
+			tags = tuple(x.realpath for x in self.thistab.get_selection())
 		else:
 			tags = [realpath(path) for path in paths]
 		if value is True:
@@ -654,7 +655,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		try:
 			self.bookmarks.update_if_outdated()
 			destination = self.bookmarks[str(key)]
-			cwd = self.env.cwd
+			cwd = self.thisdir
 			if destination.path != cwd.path:
 				self.bookmarks.enter(str(key))
 				self.bookmarks.remember(cwd)
@@ -664,7 +665,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def set_bookmark(self, key):
 		"""Set the bookmark with the name <key> to the current directory"""
 		self.bookmarks.update_if_outdated()
-		self.bookmarks[str(key)] = self.env.cwd
+		self.bookmarks[str(key)] = self.thisdir
 
 	def unset_bookmark(self, key):
 		"""Delete the bookmark with the name <key>"""
@@ -679,7 +680,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 
 	def draw_possible_programs(self):
 		try:
-			target = self.env.get_selection()[0]
+			target = self.thistab.get_selection()[0]
 		except:
 			self.ui.browser.draw_info = []
 			return
@@ -733,11 +734,11 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 			pager.set_source(["Message Log:", "No messages!"])
 
 	def display_file(self):
-		if not self.env.cf or not self.env.cf.is_file:
+		if not self.thisfile or not self.thisfile.is_file:
 			return
 
 		pager = self.ui.open_embedded_pager()
-		pager.set_source(self.env.cf.get_preview_source(pager.wid, pager.hei))
+		pager.set_source(self.thisfile.get_preview_source(pager.wid, pager.hei))
 
 	# --------------------------
 	# -- Previews
@@ -801,12 +802,12 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 						f.close()
 					else:
 						data[(-1, -1)] = None
-					if self.env.cf.realpath == path:
+					if self.thisfile.realpath == path:
 						self.ui.browser.need_redraw = True
 					data['loading'] = False
 					pager = self.ui.browser.pager
-					if self.env.cf and self.env.cf.is_file:
-						pager.set_source(self.env.cf.get_preview_source(
+					if self.thisfile and self.thisfile.is_file:
+						pager.set_source(self.thisfile.get_preview_source(
 							pager.wid, pager.hei))
 				def on_destroy(signal):
 					try:
@@ -830,6 +831,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	# --------------------------
 	# This implementation of tabs is very simple and keeps track of
 	# directory paths only.
+	# TODO: Need to rewrite this to fit the new tab model
 
 	def tab_open(self, name, path=None):
 		tab_has_changed = name != self.current_tab
@@ -872,9 +874,6 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 		assert len(self.tabs) > 0, "There must be >=1 tabs at all times"
 		return sorted(self.tabs)
 
-	def _update_current_tab(self):
-		self.tabs[self.current_tab] = self.env.cwd.path
-
 	# --------------------------
 	# -- Overview of internals
 	# --------------------------
@@ -955,9 +954,9 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def copy(self, mode='set', narg=None, dirarg=None):
 		"""Copy the selected items.  Modes are: 'set', 'add', 'remove'."""
 		assert mode in ('set', 'add', 'remove')
-		cwd = self.env.cwd
+		cwd = self.thisdir
 		if not narg and not dirarg:
-			selected = (f for f in self.env.get_selection() if f in cwd.files)
+			selected = (f for f in self.thistab.get_selection() if f in cwd.files)
 		else:
 			if not dirarg and narg:
 				direction = Direction(down=1)
@@ -1038,7 +1037,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 			cwd = self.get_directory(original_path)
 			cwd.load_content()
 
-		cwd = self.env.cwd
+		cwd = self.thisdir
 		original_path = cwd.path
 		one_file = copied_files[0]
 		if overwrite:
@@ -1080,7 +1079,7 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 	def delete(self):
 		# XXX: warn when deleting mount points/unseen marked files?
 		self.notify("Deleting!")
-		selected = self.env.get_selection()
+		selected = self.thistab.get_selection()
 		self.copy_buffer -= set(selected)
 		if selected:
 			for f in selected:
@@ -1094,11 +1093,11 @@ class Actions(FileManagerAware, EnvironmentAware, SettingsAware):
 						os.remove(f.path)
 					except OSError as err:
 						self.notify(err)
-		self.env.ensure_correct_pointer()
+		self.thistab.ensure_correct_pointer()
 
 	def mkdir(self, name):
 		try:
-			os.mkdir(os.path.join(self.env.cwd.path, name))
+			os.mkdir(os.path.join(self.thisdir.path, name))
 		except OSError as err:
 			self.notify(err)
 
diff --git a/ranger/core/environment.py b/ranger/core/environment.py
index f04fc307..61bbb6b2 100644
--- a/ranger/core/environment.py
+++ b/ranger/core/environment.py
@@ -1,16 +1,17 @@
 # Copyright (C) 2009, 2010, 2011  Roman Zimbelmann <romanz@lavabit.com>
 # This software is distributed under the terms of the GNU GPL version 3.
 
-import os
-from os.path import abspath, normpath, join, expanduser, isdir
+# THIS WHOLE FILE IS OBSOLETE AND EXISTS FOR BACKWARDS COMPATIBILITIY
 
-from ranger.fsobject import Directory
-from ranger.container.history import History
+import os
 from ranger.ext.signals import SignalDispatcher
 from ranger.core.shared import SettingsAware, FileManagerAware
 
 # COMPAT
-class EnvironmentCompatibilityWrapper(object):
+class Environment(SettingsAware, FileManagerAware, SignalDispatcher):
+	def __init__(self, path):
+		SignalDispatcher.__init__(self)
+
 	def _get_copy(self): return self.fm.copy_buffer
 	def _set_copy(self, obj): self.fm.copy_buffer = obj
 	copy = property(_get_copy, _set_copy)
@@ -43,143 +44,68 @@ class EnvironmentCompatibilityWrapper(object):
 	def _set_get_directory(self, obj): self.fm.get_directory = obj
 	get_directory = property(_get_get_directory, _set_get_directory)
 
-	def _get_garbage_collect(self): return self.fm.thistab.garbage_collect
-	def _set_garbage_collect(self, obj): self.fm.thistab.garbage_collect = obj
+	def _get_garbage_collect(self): return self.fm.garbage_collect
+	def _set_garbage_collect(self, obj): self.fm.garbage_collect = obj
 	garbage_collect = property(_get_garbage_collect, _set_garbage_collect)
 
-class Environment(SettingsAware, FileManagerAware, SignalDispatcher,
-		EnvironmentCompatibilityWrapper):
-	"""
-	A collection of data which is relevant for more than one class.
-	"""
-
-	def __init__(self, path):
-		SignalDispatcher.__init__(self)
-		self.cwd = None  # Current Working Directory
-		self._cf = None  # Current File
-		self.history = History(self.settings.max_history_size, unique=False)
-		self.last_search = None
-		self.path = abspath(expanduser(path))
-		self.pathway = ()
-		self.signal_bind('move', self._set_cf_from_signal, priority=0.1,
-				weak=True)
-
-	def _set_cf_from_signal(self, signal):
-		self._cf = signal.new
-
-	def _set_cf(self, value):
-		if value is not self._cf:
-			previous = self._cf
-			self.signal_emit('move', previous=previous, new=value)
-
-	def _get_cf(self):
-		return self._cf
+	def _get_cwd(self): return self.fm.thisdir
+	def _set_cwd(self, obj): self.fm.thisdir = obj
+	cwd = property(_get_cwd, _set_cwd)
 
+	def _get_cf(self): return self.fm.thisfile
+	def _set_cf(self, obj): self.fm.thisfile = obj
 	cf = property(_get_cf, _set_cf)
 
-	def at_level(self, level):
-		"""
-		Returns the FileSystemObject at the given level.
-		level >0 => previews
-		level 0 => current file/directory
-		level <0 => parent directories
-		"""
-		if level <= 0:
-			try:
-				return self.pathway[level - 1]
-			except IndexError:
-				return None
-		else:
-			directory = self.cf
-			for i in range(level - 1):
-				if directory is None:
-					return None
-				if directory.is_directory:
-					directory = directory.pointed_obj
-				else:
-					return None
-			try:
-				return self.fm.directories[directory.path]
-			except AttributeError:
-				return None
-			except KeyError:
-				return directory
-
-	def get_selection(self):
-		if self.cwd:
-			return self.cwd.get_selection()
-		return set()
+	def _get_history(self): return self.fm.thistab.history
+	def _set_history(self, obj): self.fm.thistab.history = obj
+	history = property(_get_history, _set_history)
+
+	def _get_last_search(self): return self.fm.thistab.last_search
+	def _set_last_search(self, obj): self.fm.thistab.last_search = obj
+	last_search = property(_get_last_search, _set_last_search)
+
+	def _get_path(self): return self.fm.thistab.path
+	def _set_path(self, obj): self.fm.thistab.path = obj
+	path = property(_get_path, _set_path)
+
+	def _get_pathway(self): return self.fm.thistab.pathway
+	def _set_pathway(self, obj): self.fm.thistab.pathway = obj
+	pathway = property(_get_pathway, _set_pathway)
+
+	def _get_enter_dir(self): return self.fm.thistab.enter_dir
+	def _set_enter_dir(self, obj): self.fm.thistab.enter_dir = obj
+	enter_dir = property(_get_enter_dir, _set_enter_dir)
+
+	def _get_at_level(self): return self.fm.thistab.at_level
+	def _set_at_level(self, obj): self.fm.thistab.at_level = obj
+	at_level = property(_get_at_level, _set_at_level)
+
+	def _get_get_selection(self): return self.fm.thistab.get_selection
+	def _set_get_selection(self, obj): self.fm.thistab.get_selection = obj
+	get_selection = property(_get_get_selection, _set_get_selection)
+
+	def _get_assign_cursor_positions_for_subdirs(self):
+		return self.fm.thistab.assign_cursor_positions_for_subdirs
+	def _set_assign_cursor_positions_for_subdirs(self, obj):
+		self.fm.thistab.assign_cursor_positions_for_subdirs = obj
+	assign_cursor_positions_for_subdirs = property(
+			_get_assign_cursor_positions_for_subdirs,
+			_set_assign_cursor_positions_for_subdirs)
+
+	def _get_ensure_correct_pointer(self):
+		return self.fm.thistab.ensure_correct_pointer
+	def _set_ensure_correct_pointer(self, obj):
+		self.fm.thistab.ensure_correct_pointer = obj
+	ensure_correct_pointer = property(_get_ensure_correct_pointer,
+			_set_ensure_correct_pointer)
+
+	def _get_history_go(self): return self.fm.thistab.history_go
+	def _set_history_go(self, obj): self.fm.thistab.history_go = obj
+	history_go = property(_get_history_go, _set_history_go)
+
+	def _set_cf_from_signal(self, signal):
+		self.fm._cf = signal.new
 
 	def get_free_space(self, path):
 		stat = os.statvfs(path)
 		return stat.f_bavail * stat.f_bsize
-
-	def assign_cursor_positions_for_subdirs(self):
-		"""Assign correct cursor positions for subdirectories"""
-		last_path = None
-		for path in reversed(self.pathway):
-			if last_path is None:
-				last_path = path
-				continue
-
-			path.move_to_obj(last_path)
-			last_path = path
-
-	def ensure_correct_pointer(self):
-		if self.cwd:
-			self.cwd.correct_pointer()
-
-	def history_go(self, relative):
-		"""Move relative in history"""
-		if self.history:
-			self.history.move(relative).go(history=False)
-
-	def enter_dir(self, path, history = True):
-		"""Enter given path"""
-		if path is None: return
-		path = str(path)
-
-		previous = self.cwd
-
-		# get the absolute path
-		path = normpath(join(self.path, expanduser(path)))
-
-		if not isdir(path):
-			return False
-		new_cwd = self.fm.get_directory(path)
-
-		try:
-			os.chdir(path)
-		except:
-			return True
-		self.path = path
-		self.cwd = new_cwd
-
-		self.cwd.load_content_if_outdated()
-
-		# build the pathway, a tuple of directory objects which lie
-		# on the path to the current directory.
-		if path == '/':
-			self.pathway = (self.fm.get_directory('/'), )
-		else:
-			pathway = []
-			currentpath = '/'
-			for dir in path.split('/'):
-				currentpath = join(currentpath, dir)
-				pathway.append(self.fm.get_directory(currentpath))
-			self.pathway = tuple(pathway)
-
-		self.assign_cursor_positions_for_subdirs()
-
-		# set the current file.
-		self.cwd.sort_directories_first = self.settings.sort_directories_first
-		self.cwd.sort_reverse = self.settings.sort_reverse
-		self.cwd.sort_if_outdated()
-		self.cf = self.cwd.pointed_obj
-
-		if history:
-			self.history.add(new_cwd)
-
-		self.signal_emit('cd', previous=previous, new=self.cwd)
-
-		return True
diff --git a/ranger/core/fm.py b/ranger/core/fm.py
index 814d16ba..34e761bd 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -16,6 +16,7 @@ import sys
 
 import ranger
 from ranger.core.actions import Actions
+from ranger.core.tab import Tab
 from ranger.container.tags import Tags
 from ranger.gui.ui import UI
 from ranger.container.bookmarks import Bookmarks
@@ -49,11 +50,11 @@ class FM(Actions, SignalDispatcher):
 		self.directories = dict()
 		self.log = deque(maxlen=20)
 		self.bookmarks = bookmarks
-		self.tags = tags
+		self.current_tab = 1
 		self.tabs = {}
+		self.tags = tags
 		self.py3 = sys.version_info >= (3, )
 		self.previews = {}
-		self.current_tab = 1
 		self.loader = Loader()
 		self.copy_buffer = set()
 		self.do_cut = False
@@ -76,6 +77,8 @@ class FM(Actions, SignalDispatcher):
 	def initialize(self):
 		"""If ui/bookmarks are None, they will be initialized here."""
 
+		self.thistab = Tab(".")
+		self.tabs[self.current_tab] = self.thistab
 		if not ranger.arg.clean and os.path.isfile(self.confpath('rifle.conf')):
 			rifleconf = self.confpath('rifle.conf')
 		else:
@@ -110,8 +113,6 @@ class FM(Actions, SignalDispatcher):
 			self.notify(text, bad=True)
 		self.run = Runner(ui=self.ui, logfunc=mylogfunc, fm=self)
 
-		self.env.signal_bind('cd', self._update_current_tab)
-
 		if self.settings.init_function:
 			self.settings.init_function(self)
 
@@ -130,6 +131,21 @@ class FM(Actions, SignalDispatcher):
 				if debug:
 					raise
 
+	def _get_thisfile(self):
+		return self.thistab.thisfile
+
+	def _set_thisfile(self, obj):
+		self.thistab.thisfile = obj
+
+	def _get_thisdir(self):
+		return self.thistab.thisdir
+
+	def _set_thisdir(self, obj):
+		self.thistab.thisdir = obj
+
+	thisfile = property(_get_thisfile, _set_thisfile)
+	thisdir  = property(_get_thisdir,  _set_thisdir)
+
 	def block_input(self, sec=0):
 		self.input_blocked = sec != 0
 		self.input_blocked_until = time() + sec
@@ -190,14 +206,13 @@ class FM(Actions, SignalDispatcher):
 			self.directories[path] = obj
 			return obj
 
-	def garbage_collect(self, age, tabs):
+	def garbage_collect(self, age, tabs=None):  # tabs=None is for COMPATibility
 		"""Delete unused directory objects"""
 		for key in tuple(self.directories):
 			value = self.directories[key]
 			if age != -1:
-				if not value.is_older_than(age) or value in self.pathway:
-					continue
-				if value in tabs.values():
+				if not value.is_older_than(age) \
+						or any(value in tab.pathway for tab in self.tabs.values()):
 					continue
 			del self.directories[key]
 			if value.is_directory:
@@ -215,7 +230,7 @@ class FM(Actions, SignalDispatcher):
 		5. after X loops: collecting unused directory objects
 		"""
 
-		self.env.enter_dir(self.env.path)
+		self.enter_dir(self.thistab.path)
 
 		gc_tick = 0
 
@@ -249,8 +264,7 @@ class FM(Actions, SignalDispatcher):
 				gc_tick += 1
 				if gc_tick > ranger.TICKS_BEFORE_COLLECTING_GARBAGE:
 					gc_tick = 0
-					self.garbage_collect(
-						ranger.TIME_BEFORE_FILE_BECOMES_GARBAGE, self.tabs)
+					self.garbage_collect(ranger.TIME_BEFORE_FILE_BECOMES_GARBAGE)
 
 		except KeyboardInterrupt:
 			# this only happens in --debug mode. By default, interrupts
@@ -258,9 +272,9 @@ class FM(Actions, SignalDispatcher):
 			raise SystemExit
 
 		finally:
-			if ranger.arg.choosedir and self.env.cwd and self.env.cwd.path:
+			if ranger.arg.choosedir and self.thisdir and self.thisdir.path:
 				# XXX: UnicodeEncodeError: 'utf-8' codec can't encode character
 				# '\udcf6' in position 42: surrogates not allowed
-				open(ranger.arg.choosedir, 'w').write(self.env.cwd.path)
-			self.bookmarks.remember(self.env.cwd)
+				open(ranger.arg.choosedir, 'w').write(self.thisdir.path)
+			self.bookmarks.remember(self.thisdir)
 			self.bookmarks.save()
diff --git a/ranger/core/main.py b/ranger/core/main.py
index 1d25c54f..b0ddc4d1 100644
--- a/ranger/core/main.py
+++ b/ranger/core/main.py
@@ -12,8 +12,7 @@ def main():
 	import locale
 	import ranger
 	import sys
-	from ranger.core.shared import (EnvironmentAware, FileManagerAware,
-			SettingsAware)
+	from ranger.core.shared import FileManagerAware, SettingsAware
 	from ranger.core.fm import FM
 
 	if not sys.stdin.isatty():
@@ -86,10 +85,8 @@ def main():
 	crash_traceback = None
 	try:
 		# Initialize objects
-		from ranger.core.environment import Environment
 		fm = FM()
 		FileManagerAware.fm = fm
-		EnvironmentAware.env = Environment(target)
 		fm.tabs = dict((n+1, os.path.abspath(path)) for n, path \
 				in enumerate(targets[:9]))
 		load_settings(fm, arg.clean)
@@ -141,7 +138,7 @@ def main():
 	finally:
 		if crash_traceback:
 			try:
-				filepath = fm.env.cf.path if fm.env.cf else "None"
+				filepath = fm.thisfile.path if fm.thisfile else "None"
 			except:
 				filepath = "None"
 		try:
diff --git a/ranger/core/tab.py b/ranger/core/tab.py
new file mode 100644
index 00000000..8157ac37
--- /dev/null
+++ b/ranger/core/tab.py
@@ -0,0 +1,140 @@
+# Copyright (C) 2009, 2010, 2011  Roman Zimbelmann <romanz@lavabit.com>
+# This software is distributed under the terms of the GNU GPL version 3.
+
+import os
+from os.path import abspath, normpath, join, expanduser, isdir
+
+from ranger.container.history import History
+from ranger.core.shared import FileManagerAware, SettingsAware
+from ranger.ext.signals import SignalDispatcher
+
+class Tab(FileManagerAware, SettingsAware):
+	def __init__(self, path):
+		self.thisdir = None  # Current Working Directory
+		self._thisfile = None  # Current File
+		self.history = History(self.settings.max_history_size, unique=False)
+		self.last_search = None
+		self.path = abspath(expanduser(path))
+		self.pathway = ()
+		self.fm.signal_bind('move', self._set_thisfile_from_signal, priority=0.1,
+				weak=True)
+
+	def _set_thisfile_from_signal(self, signal):
+		if self == self.fm.thistab:
+			self._thisfile = signal.new
+
+	def _set_thisfile(self, value):
+		if value is not self._thisfile:
+			previous = self._thisfile
+			self.fm.signal_emit('move', previous=previous, new=value)
+
+	def _get_thisfile(self):
+		return self._thisfile
+
+	thisfile = property(_get_thisfile, _set_thisfile)
+
+	def at_level(self, level):
+		"""
+		Returns the FileSystemObject at the given level.
+		level >0 => previews
+		level 0 => current file/directory
+		level <0 => parent directories
+		"""
+		if level <= 0:
+			try:
+				return self.pathway[level - 1]
+			except IndexError:
+				return None
+		else:
+			directory = self.thisfile
+			for i in range(level - 1):
+				if directory is None:
+					return None
+				if directory.is_directory:
+					directory = directory.pointed_obj
+				else:
+					return None
+			try:
+				return self.fm.directories[directory.path]
+			except AttributeError:
+				return None
+			except KeyError:
+				return directory
+
+	def get_selection(self):
+		if self.thisdir:
+			return self.thisdir.get_selection()
+		return set()
+
+	def assign_cursor_positions_for_subdirs(self):
+		"""Assign correct cursor positions for subdirectories"""
+		last_path = None
+		for path in reversed(self.pathway):
+			if last_path is None:
+				last_path = path
+				continue
+
+			path.move_to_obj(last_path)
+			last_path = path
+
+	def ensure_correct_pointer(self):
+		if self.thisdir:
+			self.thisdir.correct_pointer()
+
+	def history_go(self, relative):
+		"""Move relative in history"""
+		if self.history:
+			self.history.move(relative).go(history=False)
+
+	def enter_dir(self, path, history = True):
+		"""Enter given path"""
+		if path is None: return
+		path = str(path)
+
+		previous = self.thisdir
+
+		# get the absolute path
+		path = normpath(join(self.path, expanduser(path)))
+
+		if not isdir(path):
+			return False
+		new_thisdir = self.fm.get_directory(path)
+
+		try:
+			os.chdir(path)
+		except:
+			return True
+		self.path = path
+		self.thisdir = new_thisdir
+
+		self.thisdir.load_content_if_outdated()
+
+		# build the pathway, a tuple of directory objects which lie
+		# on the path to the current directory.
+		if path == '/':
+			self.pathway = (self.fm.get_directory('/'), )
+		else:
+			pathway = []
+			currentpath = '/'
+			for dir in path.split('/'):
+				currentpath = join(currentpath, dir)
+				pathway.append(self.fm.get_directory(currentpath))
+			self.pathway = tuple(pathway)
+
+		self.assign_cursor_positions_for_subdirs()
+
+		# set the current file.
+		self.thisdir.sort_directories_first = self.fm.settings.sort_directories_first
+		self.thisdir.sort_reverse = self.fm.settings.sort_reverse
+		self.thisdir.sort_if_outdated()
+		self.thisfile = self.thisdir.pointed_obj
+
+		if history:
+			self.history.add(new_thisdir)
+
+		self.fm.signal_emit('cd', previous=previous, new=self.thisdir)
+
+		return True
+
+	def __repr__(self):
+		return "<Tab '%s'>" % self.thisdir
diff --git a/ranger/fsobject/directory.py b/ranger/fsobject/directory.py
index 70543351..a8088cb2 100644
--- a/ranger/fsobject/directory.py
+++ b/ranger/fsobject/directory.py
@@ -454,8 +454,8 @@ class Directory(FileSystemObject, Accumulator, Loadable, SettingsAware):
 		Accumulator.correct_pointer(self)
 
 		try:
-			if self == self.fm.env.cwd:
-				self.fm.env.cf = self.pointed_obj
+			if self == self.fm.thisdir:
+				self.fm.thisfile = self.pointed_obj
 		except:
 			pass
 
diff --git a/ranger/gui/displayable.py b/ranger/gui/displayable.py
index a70dd2ff..cbd77fe4 100644
--- a/ranger/gui/displayable.py
+++ b/ranger/gui/displayable.py
@@ -37,7 +37,7 @@ class Displayable(EnvironmentAware, FileManagerAware, CursesShortcuts):
 		win -- the own curses window object
 		parent -- the parent (DisplayableContainer) object or None
 		x, y, wid, hei -- absolute coordinates and boundaries
-		settings, fm, env -- inherited shared variables
+		settings, fm -- inherited shared variables
 	"""
 
 	def __init__(self, win, env=None, fm=None, settings=None):
diff --git a/ranger/gui/ui.py b/ranger/gui/ui.py
index 835c4cc0..cc7e985e 100644
--- a/ranger/gui/ui.py
+++ b/ranger/gui/ui.py
@@ -47,10 +47,7 @@ class UI(DisplayableContainer):
 		self._draw_title = os.environ["TERM"] in TERMINALS_WITH_TITLE
 		self.keybuffer = KeyBuffer()
 		self.keymaps = KeyMaps(self.keybuffer)
-		self.keymaps.use_keymap('browser')
 
-		if env is not None:
-			self.env = env
 		if fm is not None:
 			self.fm = fm
 
@@ -63,6 +60,7 @@ class UI(DisplayableContainer):
 				os.environ['TERM'] = 'linux'
 				self.win = curses.initscr()
 		self.termsize = self.win.getmaxyx()
+		self.keymaps.use_keymap('browser')
 		DisplayableContainer.__init__(self, None)
 
 	def initialize(self):
@@ -279,7 +277,7 @@ class UI(DisplayableContainer):
 		self.win.touchwin()
 		DisplayableContainer.draw(self)
 		if self._draw_title and self.settings.update_title:
-			cwd = self.fm.env.cwd.path
+			cwd = self.fm.thisdir.path
 			if cwd.startswith(self.fm.home_path):
 				cwd = '~' + cwd[len(self.fm.home_path):]
 			if self.settings.shorten_title:
diff --git a/ranger/gui/widgets/browsercolumn.py b/ranger/gui/widgets/browsercolumn.py
index b94fd7e5..adf79e92 100644
--- a/ranger/gui/widgets/browsercolumn.py
+++ b/ranger/gui/widgets/browsercolumn.py
@@ -21,7 +21,7 @@ class BrowserColumn(Pager):
 	ellipsis = { False: '~', True: '…' }
 
 	old_dir = None
-	old_cf = None
+	old_thisfile = None
 
 	def __init__(self, win, level):
 		"""
@@ -75,7 +75,7 @@ class BrowserColumn(Pager):
 						if clicked_file.is_directory:
 							self.fm.enter_dir(clicked_file.path)
 						elif self.level == 0:
-							self.fm.env.cwd.move_to_obj(clicked_file)
+							self.fm.thisdir.move_to_obj(clicked_file)
 							self.fm.execute_file(clicked_file)
 					except:
 						pass
@@ -118,7 +118,7 @@ class BrowserColumn(Pager):
 
 	def poke(self):
 		Widget.poke(self)
-		self.target = self.env.at_level(self.level)
+		self.target = self.fm.thistab.at_level(self.level)
 
 	def draw(self):
 		"""Call either _draw_file() or _draw_directory()"""
@@ -131,9 +131,9 @@ class BrowserColumn(Pager):
 
 		if self.target and self.target.is_directory \
 				and (self.level <= 0 or self.settings.preview_directories):
-			if self.target.pointed_obj != self.old_cf:
+			if self.target.pointed_obj != self.old_thisfile:
 				self.need_redraw = True
-				self.old_cf = self.target.pointed_obj
+				self.old_thisfile = self.target.pointed_obj
 
 			if self.target.load_content_if_outdated() \
 			or self.target.sort_if_outdated() \
diff --git a/ranger/gui/widgets/browserview.py b/ranger/gui/widgets/browserview.py
index b539ad4b..3c45b7ca 100644
--- a/ranger/gui/widgets/browserview.py
+++ b/ranger/gui/widgets/browserview.py
@@ -36,7 +36,7 @@ class BrowserView(Widget, DisplayableContainer):
 			self.settings.signal_bind('setopt.' + option,
 					self._request_clear_if_has_borders, weak=True)
 
-		self.fm.env.signal_bind('move', self.request_clear)
+		self.fm.signal_bind('move', self.request_clear)
 		self.settings.signal_bind('setopt.column_ratios', self.request_clear)
 
 	def change_ratios(self, ratios):
@@ -87,11 +87,10 @@ class BrowserView(Widget, DisplayableContainer):
 			self.win.erase()
 			self.need_redraw = True
 			self.need_clear = False
-		for path in self.fm.tabs.values():
-			if path is not None:
-				directory = self.fm.get_directory(path)
-				directory.load_content_if_outdated()
-				directory.use()
+		for tab in self.fm.tabs.values():
+			directory = tab.thisdir
+			directory.load_content_if_outdated()
+			directory.use()
 		DisplayableContainer.draw(self)
 		if self.settings.draw_borders:
 			self._draw_borders()
diff --git a/ranger/gui/widgets/statusbar.py b/ranger/gui/widgets/statusbar.py
index 20bc7c60..bf5ee641 100644
--- a/ranger/gui/widgets/statusbar.py
+++ b/ranger/gui/widgets/statusbar.py
@@ -9,6 +9,7 @@ print for the current file.  The right side shows directory information
 such as the space used by all the files in this directory.
 """
 
+import os
 from pwd import getpwuid
 from grp import getgrgid
 from os import getuid, readlink
@@ -26,7 +27,7 @@ class StatusBar(Widget):
 	hint = None
 	msg = None
 
-	old_cf = None
+	old_thisfile = None
 	old_ctime = None
 	old_du = None
 	old_hint = None
@@ -69,10 +70,10 @@ class StatusBar(Widget):
 				self.msg = None
 				self.need_redraw = True
 
-		if self.env.cf:
-			self.env.cf.load_if_outdated()
+		if self.fm.thisfile:
+			self.fm.thisfile.load_if_outdated()
 			try:
-				ctime = self.env.cf.stat.st_ctime
+				ctime = self.fm.thisfile.stat.st_ctime
 			except:
 				ctime = -1
 		else:
@@ -81,12 +82,12 @@ class StatusBar(Widget):
 		if not self.result:
 			self.need_redraw = True
 
-		if self.old_du and not self.env.cwd.disk_usage:
-			self.old_du = self.env.cwd.disk_usage
+		if self.old_du and not self.fm.thisdir.disk_usage:
+			self.old_du = self.fm.thisdir.disk_usage
 			self.need_redraw = True
 
-		if self.old_cf != self.env.cf:
-			self.old_cf = self.env.cf
+		if self.old_thisfile != self.fm.thisfile:
+			self.old_thisfile = self.fm.thisfile
 			self.need_redraw = True
 
 		if self.old_ctime != ctime:
@@ -139,7 +140,7 @@ class StatusBar(Widget):
 				and self.column.target.is_directory:
 			target = self.column.target.pointed_obj
 		else:
-			target = self.env.at_level(0).pointed_obj
+			target = self.fm.thistab.at_level(0).pointed_obj
 		try:
 			stat = target.stat
 		except:
@@ -215,9 +216,9 @@ class StatusBar(Widget):
 		max_pos = len(target) - self.column.hei
 		base = 'scroll'
 
-		if self.env.cwd.filter:
+		if self.fm.thisdir.filter:
 			right.add(" f=", base, 'filter')
-			right.add(repr(self.env.cwd.filter), base, 'filter')
+			right.add(repr(self.fm.thisdir.filter), base, 'filter')
 			right.add(", ", "space")
 
 		if target.marked_items:
@@ -231,7 +232,7 @@ class StatusBar(Widget):
 		else:
 			right.add(human_readable(target.disk_usage, separator='') + " sum")
 			try:
-				free = self.env.get_free_space(target.mount_path)
+				free = get_free_space(target.mount_path)
 			except OSError:
 				pass
 			else:
@@ -265,6 +266,10 @@ class StatusBar(Widget):
 			self.addstr(str(part))
 		self.color_reset()
 
+def get_free_space(path):
+	stat = os.statvfs(path)
+	return stat.f_bavail * stat.f_bsize
+
 class Message(object):
 	elapse = None
 	text = None
diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py
index fddf2e64..04fdb7b6 100644
--- a/ranger/gui/widgets/titlebar.py
+++ b/ranger/gui/widgets/titlebar.py
@@ -13,7 +13,7 @@ from . import Widget
 from ranger.gui.bar import Bar
 
 class TitleBar(Widget):
-	old_cf = None
+	old_thisfile = None
 	old_keybuffer = None
 	old_wid = None
 	result = None
@@ -30,12 +30,12 @@ class TitleBar(Widget):
 
 	def draw(self):
 		if self.need_redraw or \
-				self.env.cf != self.old_cf or\
+				self.fm.thisfile != self.old_thisfile or\
 				str(self.fm.ui.keybuffer) != str(self.old_keybuffer) or\
 				self.wid != self.old_wid:
 			self.need_redraw = False
 			self.old_wid = self.wid
-			self.old_cf = self.env.cf
+			self.old_thisfile = self.fm.thisfile
 			self._calc_bar()
 		self._print_result(self.result)
 		if self.wid > 2:
@@ -101,9 +101,9 @@ class TitleBar(Widget):
 		bar.add(self.fm.hostname, 'hostname', clr, fixed=True)
 		bar.add(':', 'hostname', clr, fixed=True)
 
-		pathway = self.env.pathway
+		pathway = self.fm.thistab.pathway
 		if self.settings.tilde_in_titlebar and \
-				self.fm.env.cwd.path.startswith(self.fm.home_path):
+				self.fm.thisdir.path.startswith(self.fm.home_path):
 			pathway = pathway[self.fm.home_path.count('/')+1:]
 			bar.add('~/', 'directory', fixed=True)
 
@@ -116,8 +116,8 @@ class TitleBar(Widget):
 			bar.add(path.basename, clr, directory=path)
 			bar.add('/', clr, fixed=True, directory=path)
 
-		if self.env.cf is not None:
-			bar.add(self.env.cf.basename, 'file')
+		if self.fm.thisfile is not None:
+			bar.add(self.fm.thisfile.basename, 'file')
 
 	def _get_right_part(self, bar):
 		# TODO: fix that pressed keys are cut off when chaining CTRL keys