summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--code/defaultui.py16
-rw-r--r--code/directory.py1
-rw-r--r--code/environment.py24
-rw-r--r--code/fm.py73
-rw-r--r--code/fsobject.py2
-rw-r--r--code/ui.py57
-rw-r--r--code/wdisplay.py34
-rw-r--r--code/widget.py39
-rwxr-xr-x[-rw-r--r--]ranger21
-rw-r--r--test/__init__.py0
-rw-r--r--test/tc_directory.py19
-rw-r--r--test2.py7
-rw-r--r--test3.py69
13 files changed, 287 insertions, 75 deletions
diff --git a/code/defaultui.py b/code/defaultui.py
new file mode 100644
index 00000000..d46c89c8
--- /dev/null
+++ b/code/defaultui.py
@@ -0,0 +1,16 @@
+import ui
+import widget, wdisplay
+
+class DefaultUI(ui.UI):
+	def setup(self):
+		self.main_display = wdisplay.WDisplay(self.win, 0)
+		self.add_widget(self.main_display)
+		self.left_display = wdisplay.WDisplay(self.win, -1)
+		self.add_widget(self.left_display)
+	
+	def resize(self):
+		ui.UI.resize(self)
+		y, x = self.win.getmaxyx()
+		self.main_display.setdim(1, 40, 3, 37)
+		self.left_display.setdim(1, 0, 3, 37)
+
diff --git a/code/directory.py b/code/directory.py
index 2554ca72..4109ae2d 100644
--- a/code/directory.py
+++ b/code/directory.py
@@ -13,6 +13,7 @@ class Directory(fsobject.FSObject):
 		self.filter = None
 		self.pointed_index = None
 		self.pointed_file = None
+		self.index = None
 	
 	def load_content(self):
 		self.stop_if_frozen()
diff --git a/code/environment.py b/code/environment.py
index d0ff5763..515fc8c6 100644
--- a/code/environment.py
+++ b/code/environment.py
@@ -1,3 +1,5 @@
+import directory
+
 class Vector():
 	def __init__(self, x, y):
 		self.x = x
@@ -6,11 +8,31 @@ class Vector():
 class Environment():
 	# A collection of data which is relevant for more than
 	# one class.
-	def __init__(self):
+	def __init__(self, opt):
+		self.opt = opt
 		self.path = None
+		self.pathway = ()
 		self.directories = {}
 		self.pwd = None # current directory
 		self.cf = None # current file
 		self.keybuffer = ''
 		self.copy = None
 		self.termsize = Vector(80, 24)
+	
+	def at_level(self, level):
+		if level <= 0:
+			try:
+				return self.pathway[level - 1]
+			except IndexError:
+				return None
+		else:
+			return self.cf
+
+	def get_directory(self, path):
+		import os
+		path = os.path.abspath(path)
+		try:
+			return self.directories[path]
+		except KeyError:
+			self.directories[path] = directory.Directory(path)
+			return self.directories[path]
diff --git a/code/fm.py b/code/fm.py
index 6631aee4..924f6efc 100644
--- a/code/fm.py
+++ b/code/fm.py
@@ -1,51 +1,62 @@
-import sys
-import ui, debug, directory, fstype
+import sys, os
+import ui, debug, file, directory, fstype
 
 class FM():
-	def __init__(self, options, environment):
-		self.options = options
+	def __init__(self, environment):
 		self.env = environment
 
-	def setup(self, path, ui):
+	def feed(self, path, ui):
 		self.ui = ui
+		self.env.path = path
 		self.enter_dir(path)
 
 	def enter_dir(self, path):
+		# get the absolute path
+		path = os.path.normpath(os.path.join(self.env.path, path))
+
 		self.env.path = path
-		try:
-			self.pwd = self.env.directories[path]
-		except KeyError:
-			self.env.pwd = directory.Directory(path)
-			self.env.directories[path] = self.env.pwd
+		self.env.pwd = self.env.get_directory(path)
 
 		self.env.pwd.load_content()
-		if len(self.env.pwd) > 0: self.env.cf = self.env.pwd[0]
+
+		# build the pathway, a tuple of directory objects which lie
+		# on the path to the current directory.
+		pathway = []
+		currentpath = '/'
+		for dir in path.split('/'):
+			currentpath = os.path.join(currentpath, dir)
+			debug.log(currentpath)
+			pathway.append(self.env.get_directory(currentpath))
+		self.env.pathway = tuple(pathway)
+
+		# set the current file.
+		if len(self.env.pwd) > 0:
+			self.env.cf = self.env.pwd[0]
+		else:
+			self.env.cf = None
 
 	def run(self):
-		try:
-			while 1:
-				try:
-#					if type(self.env.cf) is directory.Directory:
-#						self.env.cf.load_content_once()
-					self.ui.feed(self.env.directories, self.env.pwd, self.env.cf, self.env.termsize)
-					self.ui.draw()
-				except KeyboardInterrupt:
-					self.interrupt()
-				except:
-					raise
-
-				try:
-					key = self.ui.get_next_key()
-					self.press(key)
-				except KeyboardInterrupt:
-					self.interrupt()
-		except:
-			self.ui.exit()
-			raise
+		while 1:
+			try:
+				self.ui.draw()
+			except KeyboardInterrupt:
+				self.interrupt()
+			except:
+				raise
+
+			try:
+				key = self.ui.get_next_key()
+				self.press(key)
+			except KeyboardInterrupt:
+				self.interrupt()
 
 	def press(self, key):
 		if (key == ord('q')):
 			raise SystemExit()
+		elif (key == ord('h')):
+			self.enter_dir('..')
+		elif (key == ord('l')):
+			self.enter_dir(self.env.cf.path)
 
 	def interrupt(self):
 		import time
diff --git a/code/fsobject.py b/code/fsobject.py
index 6e93140f..f4268ef0 100644
--- a/code/fsobject.py
+++ b/code/fsobject.py
@@ -83,5 +83,5 @@ class FSObject(object):
 		return clone
 
 	def stop_if_frozen(self):
-		if self.frozen: raise FrozenException()
+		if self.frozen: raise FrozenException('Cannot modify datastructure while it is frozen')
 
diff --git a/code/ui.py b/code/ui.py
index 3994d7ce..d9c1de4e 100644
--- a/code/ui.py
+++ b/code/ui.py
@@ -1,26 +1,28 @@
 import curses, debug
 class UI():
-	def __init__(self, options):
-		self.scr = curses.initscr()
-		self.scr.leaveok(1)
+	def __init__(self, env):
+		self.env = env
+
+		self.widgets = []
+		self.win = curses.initscr()
+		self.win.leaveok(1)
 		curses.noecho()
 		curses.halfdelay(3)
 
-		self.options = options
-		self.directories = None
-		self.pwd = None
-		self.cf = None
-		self.termsize = None
-		self.rows = 0
-		self.cols = 0
-
-	def feed(self, directories, pwd, cf, termsize):
-		self.directories = directories
-		self.pwd = pwd
-		self.cf = cf
-		self.termsize = termsize
-		self.cols = termsize.x
-		self.rows = termsize.y
+		self.setup()
+		self.resize()
+
+	def setup(self):
+		pass
+
+	def resize(self):
+		self.env.termsize = self.win.getmaxyx()
+
+	def add_widget(self, widg):
+		self.widgets.append(widg)
+
+	def feed_env(self, env):
+		self.env = env
 
 	def exit(self):
 		curses.nocbreak()
@@ -28,16 +30,19 @@ class UI():
 		curses.endwin()
 
 	def draw(self):
-		import time
-		self.scr.erase()
-		for i in range(1, len(self.pwd)):
-			f = self.pwd.files[i]
-			self.scr.addstr(i, 0, f.path)
-			if f.infostring: self.scr.addstr(i, 50, f.infostring)
-		self.scr.refresh()
+		self.win.erase()
+		for widg in self.widgets:
+			widg.feed_env(self.env)
+			widg.draw()
+		self.win.refresh()
+
+#		for i in range(1, len(self.env.pwd)):
+#			f = self.env.pwd.files[i]
+#			self.win.addstr(i, 0, f.path)
+#			if f.infostring: self.win.addstr(i, 50, f.infostring)
 
 	def get_next_key(self):
-		key = self.scr.getch()
+		key = self.win.getch()
 		curses.flushinp()
 		return key
 
diff --git a/code/wdisplay.py b/code/wdisplay.py
new file mode 100644
index 00000000..a564a6cb
--- /dev/null
+++ b/code/wdisplay.py
@@ -0,0 +1,34 @@
+import widget
+import curses
+import file, directory
+
+class WDisplay(widget.Widget):
+	def __init__(self, win, level):
+		widget.Widget.__init__(self,win)
+		self.level = level
+
+	def feed_env(self, env):
+		self.target = env.at_level(self.level)
+
+	def draw(self):
+		if type(self.target) == file.File:
+			self.draw_file()
+		elif type(self.target) == directory.Directory:
+			self.draw_directory()
+		elif self.target is None:
+			self.win.addnstr(self.y, self.x, "---", self.wid)
+		else:
+			self.win.addnstr(self.y, self.x, "unknown type.", self.wid)
+
+	def draw_file(self):
+		self.win.addnstr(self.y, self.x, "this is a file.", self.wid)
+
+	def draw_directory(self):
+		self.target.load_content_once()
+		for i in range(self.hei):
+			try:
+				f = self.target[i]
+			except IndexError:
+				break
+			self.win.addnstr(self.y + i, self.x, self.target[i].path, self.wid)
+
diff --git a/code/widget.py b/code/widget.py
new file mode 100644
index 00000000..e95e6a9d
--- /dev/null
+++ b/code/widget.py
@@ -0,0 +1,39 @@
+import curses
+
+class OutOfBoundsException(Exception): pass
+
+class Widget():
+	def __init__(self, win):
+		self.win = win
+		self.setdim(0, 0, 0, 0)
+
+	def setdim(self, y, x, hei=None, wid=None):
+		maxy, maxx = self.win.getmaxyx()
+		wid = wid or maxx - x
+		hei = hei or maxy - y
+		if x + wid > maxx or y + hei > maxy:
+			raise OutOfBoundsException()
+
+		self.x = x
+		self.y = y
+		self.wid = wid
+		self.hei = hei
+	
+	def contains_point(self, y, x):
+		return (x >= self.x and x < self.x + self.wid) and \
+				(y >= self.y and y < self.y + self.hei)
+
+	def feed_env(self):
+		pass
+
+	def feed(self):
+		pass
+
+	def click(self):
+		pass
+	
+	def draw(self):
+		pass
+
+	def destroy(self):
+		pass
diff --git a/ranger b/ranger
index b6050ca8..d83e8a3e 100644..100755
--- a/ranger
+++ b/ranger
@@ -3,7 +3,7 @@
 
 # TODO: cd after exit
 
-from code import debug, fm, ui, options, environment
+from code import debug, fm, defaultui, options, environment
 
 # TODO: find out the real name of this script and include files relative to here
 
@@ -16,12 +16,19 @@ def main():
 	os.stat_float_times(True)
 	locale.setlocale(locale.LC_ALL, 'en_US.utf8')
 
-	path = '/srv/music/compilations/'
-	opt = options.get()
-	env = environment.Environment()
+	try:
+		path = '/srv/music/compilations/'
+		opt = options.get()
+		env = environment.Environment(opt)
+
+		my_ui = defaultui.DefaultUI(env)
+		my_fm = fm.FM(env)
+		my_fm.feed(path, my_ui)
+		my_fm.run()
+
+	except:
+		my_ui.exit()
+		raise
 
-	my_fm = fm.FM(opt, env)
-	my_fm.setup(path, ui.UI(opt))
-	my_fm.run()
 
 if __name__ == "__main__": main()
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/__init__.py
diff --git a/test/tc_directory.py b/test/tc_directory.py
index ebbd6b5e..88c7a99e 100644
--- a/test/tc_directory.py
+++ b/test/tc_directory.py
@@ -1,15 +1,15 @@
 import unittest
 import sys, os, time
-sys.path.append('../code')
-os.stat_float_times(True)
-import directory, fsobject, file, debug
 
-TESTDIR = os.path.realpath(os.path.join(os.path.dirname(sys.argv[0]), 'testdir'))
+sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '../code')))
+import fsobject, file, directory
+
+TESTDIR = os.path.realpath(os.path.join(os.path.dirname(__file__), 'testdir'))
 TESTFILE = os.path.join(TESTDIR, 'testfile5234148')
 NONEXISTANT_DIR = '/this/directory/will/most/certainly/not/exist'
 
 class Test1(unittest.TestCase):
-	def testInitialCondition(self):
+	def test_initial_condition(self):
 		# Check for the expected initial condition
 		dir = directory.Directory(TESTDIR)
 
@@ -20,7 +20,7 @@ class Test1(unittest.TestCase):
 		self.assertRaises(fsobject.NotLoadedYet, len, dir)
 		self.assertRaises(fsobject.NotLoadedYet, dir.__getitem__, 0)
 
-	def testAfterContentLoaded(self):
+	def test_after_content_loaded(self):
 		# Check whether the directory has the correct list of filenames.
 		dir = directory.Directory(TESTDIR)
 		dir.load_content()
@@ -49,7 +49,7 @@ class Test1(unittest.TestCase):
 					equal += 1
 			self.assertEqual(equal, 1)
 
-	def testNonexistantDir(self):
+	def test_nonexistant_dir(self):
 		dir = directory.Directory(NONEXISTANT_DIR)
 		dir.load_content()
 		
@@ -60,7 +60,7 @@ class Test1(unittest.TestCase):
 		self.assertRaises(fsobject.NotLoadedYet, len, dir)
 		self.assertRaises(fsobject.NotLoadedYet, dir.__getitem__, 0)
 
-	def testModifyFrozenClone(self):
+	def test_modify_frozen_clone(self):
 		dir = directory.Directory(TESTDIR)
 		clone = dir.frozen_clone()
 
@@ -107,5 +107,6 @@ class Test1(unittest.TestCase):
 
 		self.assertTrue(dir.load_if_outdated())
 
-unittest.main()
+if __name__ == '__main__':
+	unittest.main()
 
diff --git a/test2.py b/test2.py
new file mode 100644
index 00000000..21c5a5f9
--- /dev/null
+++ b/test2.py
@@ -0,0 +1,7 @@
+from code import cli
+import signal
+
+with cli.lock:
+	with cli.lock:
+		print("this will be delayed forever")
+	print("hi!")
diff --git a/test3.py b/test3.py
new file mode 100644
index 00000000..3b1986b7
--- /dev/null
+++ b/test3.py
@@ -0,0 +1,69 @@
+#!/usr/bin/python3
+# coding=utf-8
+# some tests with curses, threads and unicode
+import os
+import curses
+import time
+import locale
+
+lock = _thread.allocate_lock()
+
+locale.setlocale(locale.LC_ALL, 'en_US.utf8')
+
+blocked = False
+stringy = 'ใ‚‹ใงใ‹'
+stdscr = curses.initscr()
+#win1 = curses.newwin(
+
+curses.noecho()
+curses.cbreak()
+curses.halfdelay(3)
+stdscr.keypad(1)
+#curses.curs_set(0)
+
+stdscr.addstr(4, 0, stringy)
+stdscr.refresh()
+
+class ThreadTest(threading.Thread):
+	def __init__(self, *a, **b):
+		threading.Thread.__init__(self, *a, **b)
+		self.killed = False
+
+	def run(self):
+		global stdscr
+		global blocked
+		for i in range(1,50):
+			while blocked: time.sleep(0.1)
+			blocked = True
+			stdscr.addstr(1, 0, str(i))
+			stdscr.refresh()
+			blocked = False
+			time.sleep(0.1)
+			if self.killed: raise SystemExit()
+
+	def kill(self):
+		self.killed = True
+
+thr = ThreadTest()
+thr.start()
+
+try:
+	while 1:
+		c = stdscr.getch()
+		if c == ord('q'): raise
+		while blocked: time.sleep(0.1)
+		blocked = True
+		stdscr.addstr(0, 0, str(c))
+		stdscr.refresh()
+		blocked = False
+
+except Exception:
+	thr.kill()
+	raise
+finally:
+	curses.nocbreak()
+	stdscr.keypad(1)
+	curses.echo()
+	curses.endwin()
+#	curses.curs_set(1)
+