summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--ranger/colorschemes/default.py3
-rw-r--r--ranger/core/actions.py45
-rw-r--r--ranger/core/environment.py4
-rw-r--r--ranger/core/fm.py4
-rw-r--r--ranger/defaults/keys.py7
-rw-r--r--ranger/gui/context.py2
-rw-r--r--ranger/gui/widgets/titlebar.py32
7 files changed, 93 insertions, 4 deletions
diff --git a/ranger/colorschemes/default.py b/ranger/colorschemes/default.py
index fbfaf479..24f8ab91 100644
--- a/ranger/colorschemes/default.py
+++ b/ranger/colorschemes/default.py
@@ -72,6 +72,9 @@ class Default(ColorScheme):
 				fg = context.bad and red or green
 			elif context.directory:
 				fg = blue
+			elif context.tab:
+				if context.good:
+					bg = green
 			elif context.link:
 				fg = cyan
 
diff --git a/ranger/core/actions.py b/ranger/core/actions.py
index 7da029cd..d52dac2b 100644
--- a/ranger/core/actions.py
+++ b/ranger/core/actions.py
@@ -419,6 +419,51 @@ class Actions(EnvironmentAware, SettingsAware):
 		if hasattr(self.ui, 'status'):
 			self.ui.status.need_redraw = True
 
+	# --------------------------
+	# -- Tabs
+	# --------------------------
+	# This implementation of tabs is very simple and keeps track of
+	# directory paths only.
+
+	def _get_tab_list(self):
+		return sorted(self.tabs)
+
+	def tab_open(self, name):
+		if name in self.tabs:
+			self.current_tab = name
+			self.enter_dir(self.tabs[name], remember=False)
+		else:
+			self.tab_new(name)
+
+	def tab_close(self, name=None):
+		if name is None:
+			name = self.current_tab
+		if name == self.current_tab:
+			previous = self.current_tab
+			self.tab_move(-1)
+			if previous == self.current_tab:
+				return  # can't close last tab
+		if name in self.tabs:
+			del self.tabs[name]
+
+	def tab_move(self, offset):
+		assert isinstance(offset, int)
+		tablist = self._get_tab_list()
+		current_index = tablist.index(self.current_tab)
+		newtab = tablist[(current_index + offset) % len(tablist)]
+		if newtab != self.current_tab:
+			self.tab_open(newtab)
+
+	def tab_new(self, name, path=None):
+		self.current_tab = name
+		if path:
+			self.enter_dir(path, remember=False)
+		else:
+			self._update_current_tab()
+
+	def _update_current_tab(self):
+		self.tabs[self.current_tab] = self.env.cwd.path
+
 	# ------------------------------------ filesystem operations
 
 	def copy(self):
diff --git a/ranger/core/environment.py b/ranger/core/environment.py
index 1d1464d2..00b152d3 100644
--- a/ranger/core/environment.py
+++ b/ranger/core/environment.py
@@ -172,6 +172,8 @@ class Environment(SettingsAware, SignalDispatcher):
 		if path is None: return
 		path = str(path)
 
+		previous = self.cwd
+
 		# get the absolute path
 		path = normpath(join(self.path, expanduser(path)))
 
@@ -215,4 +217,6 @@ class Environment(SettingsAware, SignalDispatcher):
 		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 2e65c776..a38b9147 100644
--- a/ranger/core/fm.py
+++ b/ranger/core/fm.py
@@ -47,10 +47,14 @@ class FM(Actions, SignalDispatcher):
 		self.log = deque(maxlen=20)
 		self.bookmarks = bookmarks
 		self.tags = tags
+		self.tabs = {}
+		self.current_tab = 1
 		self.loader = Loader()
 		self._executables = None
 		self.apps = self.settings.apps.CustomApplications()
 
+		self.env.signal_bind('cd', self._update_current_tab)
+
 		def mylogfunc(text):
 			self.notify(text, bad=True)
 		self.run = Runner(ui=self.ui, apps=self.apps,
diff --git a/ranger/defaults/keys.py b/ranger/defaults/keys.py
index 6b0948aa..6628e064 100644
--- a/ranger/defaults/keys.py
+++ b/ranger/defaults/keys.py
@@ -166,6 +166,13 @@ def initialize_commands(map):
 	map('gs', fm.cd('/srv'))
 	map('gR', fm.cd(RANGERDIR))
 
+	# ------------------------------------------------------------ tabs
+	map('gc', ctrl('W'), fm.tab_close())
+	map('gt', fm.tab_move(1))
+	map('gT', fm.tab_move(-1))
+	for n in range(10):
+		map('g' + str(n), fm.tab_open(n))
+
 	# ------------------------------------------------------- searching
 	map('/', fm.open_console(cmode.SEARCH))
 
diff --git a/ranger/gui/context.py b/ranger/gui/context.py
index 453eb9dc..4ea50714 100644
--- a/ranger/gui/context.py
+++ b/ranger/gui/context.py
@@ -26,7 +26,7 @@ CONTEXT_KEYS = ['reset', 'error',
 		'marked', 'tagged', 'tag_marker',
 		'help_markup',
 		'seperator', 'key', 'special', 'border',
-		'title', 'text', 'highlight', 'bars', 'quotes',
+		'title', 'text', 'highlight', 'bars', 'quotes', 'tab',
 		'keybuffer']
 
 class Context(object):
diff --git a/ranger/gui/widgets/titlebar.py b/ranger/gui/widgets/titlebar.py
index 18d363dc..4bd15e0f 100644
--- a/ranger/gui/widgets/titlebar.py
+++ b/ranger/gui/widgets/titlebar.py
@@ -30,24 +30,43 @@ class TitleBar(Widget):
 	old_wid = None
 	result = None
 	throbber = ' '
+	need_redraw = False
+	tab_width = 0
 
 	def draw(self):
-		if self.env.cf != self.old_cf or\
+		if self.need_redraw or \
+				self.env.cf != self.old_cf or\
 				str(self.env.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._calc_bar()
 		self._print_result(self.result)
 		if self.wid > 2:
 			self.color('in_titlebar', 'throbber')
-			self.win.addnstr(self.y, self.wid - 2, self.throbber, 1)
+			self.win.addnstr(self.y, self.wid - 2 - self.tab_width,
+					self.throbber, 1)
 
 	def click(self, event):
 		"""Handle a MouseEvent"""
+		direction = event.mouse_wheel_direction()
+		if direction:
+			self.fm.tab_move(direction)
+			self.need_redraw = True
+			return True
+
 		if not event.pressed(1) or not self.result:
 			return False
 
+		pos = self.wid - 3
+		for tabname in reversed(self.fm._get_tab_list()):
+			pos -= len(str(tabname)) + 1
+			if event.x > pos:
+				self.fm.tab_open(tabname)
+				self.need_redraw = True
+				return True
+
 		pos = 0
 		for i, part in enumerate(self.result):
 			pos += len(part.string)
@@ -61,7 +80,8 @@ class TitleBar(Widget):
 						self.fm.env.enter_dir(self.env.pathway[(i-3)/2])
 					except:
 						pass
-				return False
+				return True
+		return False
 
 	def _calc_bar(self):
 		bar = Bar('in_titlebar')
@@ -100,6 +120,12 @@ class TitleBar(Widget):
 		self.old_keybuffer = kb
 		bar.addright(kb, 'keybuffer', fixedsize=True)
 		bar.addright('  ', 'space', fixedsize=True)
+		self.tab_width = 0
+		if len(self.fm.tabs) > 1:
+			for tabname in self.fm._get_tab_list():
+				self.tab_width += len(str(tabname)) + 1
+				clr = 'good' if tabname == self.fm.current_tab else 'bad'
+				bar.addright(' '+str(tabname), 'tab', clr, fixedsize=True)
 
 	def _print_result(self, result):
 		import _curses