diff options
-rw-r--r-- | code/defaultui.py | 16 | ||||
-rw-r--r-- | code/directory.py | 1 | ||||
-rw-r--r-- | code/environment.py | 24 | ||||
-rw-r--r-- | code/fm.py | 73 | ||||
-rw-r--r-- | code/fsobject.py | 2 | ||||
-rw-r--r-- | code/ui.py | 57 | ||||
-rw-r--r-- | code/wdisplay.py | 34 | ||||
-rw-r--r-- | code/widget.py | 39 | ||||
-rwxr-xr-x[-rw-r--r--] | ranger | 21 | ||||
-rw-r--r-- | test/__init__.py | 0 | ||||
-rw-r--r-- | test/tc_directory.py | 19 | ||||
-rw-r--r-- | test2.py | 7 | ||||
-rw-r--r-- | test3.py | 69 |
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) + |