diff --git a/rtv/history.py b/rtv/history.py new file mode 100644 index 0000000..1ca48fa --- /dev/null +++ b/rtv/history.py @@ -0,0 +1,68 @@ +import os + + +__all__ = ['load_history', 'save_history'] + + +def history_path(): + """ + Create the path to the history log + """ + HOME = os.path.expanduser('~') + XDG_CONFIG_HOME = os.getenv('XDG_CACHE_HOME', os.path.join(HOME, '.config')) + path = os.path.join(XDG_CONFIG_HOME, 'rtv') + if not os.path.exists(path): + os.makedirs(path) + return os.path.join(path, 'history.log') + + +def load_history(): + """ + Load the history file into memory if it exists + """ + path = history_path() + if os.path.exists(path): + with open(path) as history_file: + # reverse the list so the newest ones are first + history = [line.strip() for line in history_file][::-1] + return OrderedSet(history) + return OrderedSet() + + +def save_history(history): + """ + Save the visited links to the history log + """ + path = history_path() + with open(path, 'w+') as history_file: + for i in range(200): + if not history: + break + try: + history_file.write(history.pop() + '\n') + except UnicodeEncodeError: + # Ignore unicode URLS, may want to handle this at some point + continue + +class OrderedSet(object): + """ + A simple implementation of an ordered set. A set is used to check + for membership, and a list is used to maintain ordering. + """ + + def __init__(self, elements=[]): + self._set = set(elements) + self._list = elements + + def __contains__(self, item): + return item in self._set + + def __len__(self): + return len(self._list) + + def add(self, item): + self._set.add(item) + self._list.append(item) + + def pop(self): + return self._list.pop() diff --git a/rtv/page.py b/rtv/page.py index 5e671d9..41911ee 100644 --- a/rtv/page.py +++ b/rtv/page.py @@ -533,26 +533,21 @@ class BasePage(object): def _move_cursor(self, direction): self._remove_cursor() valid, redraw = self.nav.move(direction, len(self._subwindows)) - if not valid: curses.flash() # Note: ACS_VLINE doesn't like changing the attribute, so always redraw. - # if redraw: self._draw_content() self._draw_content() self._add_cursor() def _move_page(self, direction): self._remove_cursor() - valid, redraw = self.nav.move_page(direction, - len(self._subwindows)-1) + valid, redraw = self.nav.move_page(direction, len(self._subwindows)-1) if not valid: curses.flash() + # Note: ACS_VLINE doesn't like changing the attribute, so always redraw. self._draw_content() - # Don't allow the cursor to go over the subwindow number - if self.nav.cursor_index >= len(self._subwindows): - self.nav.cursor_index = len(self._subwindows)-1 self._add_cursor() def _edit_cursor(self, attribute=None): @@ -561,6 +556,12 @@ class BasePage(object): if self.nav.absolute_index < 0: return + # Don't allow the cursor to go over the number of subwindows + # This could happen if the window is resized and the cursor index is + # pushed out of bounds + if self.nav.cursor_index >= len(self._subwindows): + self.nav.cursor_index = len(self._subwindows)-1 + window, attr = self._subwindows[self.nav.cursor_index] if attr is not None: attribute |= attr diff --git a/rtv/subreddit.py b/rtv/subreddit.py index 86b106f..5ae1f6a 100644 --- a/rtv/subreddit.py +++ b/rtv/subreddit.py @@ -1,6 +1,7 @@ import curses import time import logging +import atexit import requests import praw @@ -14,12 +15,17 @@ from .docs import SUBMISSION_FILE from .curses_helpers import (GOLD, Color, LoadScreen, add_line, get_arrow, show_notification, prompt_input) -__all__ = ['opened_links', 'SubredditController', 'SubredditPage'] +__all__ = ['history', 'SubredditController', 'SubredditPage'] _logger = logging.getLogger(__name__) -# Used to keep track of browsing history across the current session -opened_links = set() +history = load_history() + + +@atexit.register +def save_links(): + global history + save_history(history) class SubredditController(BaseController): @@ -96,8 +102,8 @@ class SubredditPage(BasePage): page.loop() if data['url'] == 'selfpost': - global opened_links - opened_links.add(data['url_full']) + global history + history.add(data['url_full']) @SubredditController.register(curses.KEY_ENTER, 10, 'o') def open_link(self): @@ -106,8 +112,8 @@ class SubredditPage(BasePage): url = self.content.get(self.nav.absolute_index)['url_full'] open_browser(url) - global opened_links - opened_links.add(url) + global history + history.add(url) @SubredditController.register('p') def post_submission(self): @@ -167,7 +173,7 @@ class SubredditPage(BasePage): row = n_title + offset if row in valid_rows: - seen = (data['url_full'] in opened_links) + seen = (data['url_full'] in history) link_color = Color.MAGENTA if seen else Color.BLUE attr = curses.A_UNDERLINE | link_color add_line(win, u'{url}'.format(**data), row, 1, attr)