fixed #1988 Traceback handler

parent 133cda19
......@@ -26,6 +26,7 @@ import sys
import shlex
import curses
import threading
import traceback
from datetime import datetime
......@@ -79,20 +80,22 @@ class Core(object):
User interface using ncurses
"""
def __init__(self, xmpp):
# All uncaught exception are given to this callback, instead
# of being displayed on the screen and exiting the program.
sys.excepthook = self.on_exception
self.running = True
self.stdscr = curses.initscr()
self.init_curses(self.stdscr)
self.xmpp = xmpp
# a unique buffer used to store global informations
# that are displayed in almost all tabs, in an
# information window.
self.information_buffer = TextBuffer()
self.information_win_size = config.get('info_win_height', 2, 'var')
default_tab = tabs.InfoTab(self, "Info") if self.xmpp.anon\
else tabs.RosterInfoTab(self)
default_tab.on_gain_focus()
self.tabs = [default_tab]
# a unique buffer used to store global informations
# that are displayed in almost all tabs, in an
# information window.
self.resize_timer = None
self.previous_tab_nb = 0
self.own_nick = config.get('own_nick', self.xmpp.boundjid.bare)
......@@ -155,6 +158,20 @@ class Core(object):
self.xmpp.add_event_handler("roster_update", self.on_roster_update)
self.xmpp.add_event_handler("changed_status", self.on_presence)
def on_exception(self, typ, value, trace):
"""
When an exception in raised, open a special tab
displaying the traceback and some instructions to
make a bug report.
"""
try:
tb_tab = tabs.SimpleTextTab(self, "/!\ Oups, an error occured (this may not be fatal). /!\\\n\nPlease report this bug (by copying the present error message and explaining what you were doing) on the page http://codingteam.net/project/poezio/bugs/add\n\n%s\n\nIf Poezio does not respond anymore, kill it with Ctrl+\\, and sorry about that :(" % ''.join(traceback.format_exception(typ, value, trace)))
self.add_tab(tb_tab, focus=True)
except Exception: # If an exception is raised in this code, this is
# this is fatal, so we exit cleanly and display the traceback
curses.endwin()
raise
def grow_information_win(self):
"""
"""
......
......@@ -20,70 +20,9 @@
Starting point of poezio. Launches both the Connection and Gui
"""
import os
import curses
import sys
import traceback
import threading
import os
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
def installThreadExcepthook():
"""
Workaround for sys.excepthook thread bug
See http://bugs.python.org/issue1230540
Python, you made me sad :(
"""
init_old = threading.Thread.__init__
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
except:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init
class MyStdErr(object):
def __init__(self, fd):
"""
Change sys.stderr to something like /dev/null
to disable any printout on the screen that would
mess everything
"""
self.old_stderr = sys.stderr
sys.stderr = fd
def restore(self):
"""
Restore the good ol' sys.stderr, because we need
it in order to print the tracebacks
"""
sys.stderr.close()
sys.stderr = self.old_stderr
# my_stderr = MyStdErr(open('/dev/null', 'a'))
def exception_handler(type_, value, trace):
"""
on any traceback: exit ncurses and print the traceback
then exit the program
"""
my_stderr.restore()
try:
curses.endwin()
curses.echo()
except: # if an exception is raised but initscr has never been called yet
pass
traceback.print_exception(type_, value, trace, None, sys.stderr)
import os # used to quit the program even from a thread
os.abort()
# sys.excepthook = exception_handler
import signal
import logging
......@@ -96,4 +35,7 @@ if __name__ == '__main__':
if options.debug:
logging.basicConfig(filename=options.debug,level=logging.DEBUG)
connection.start() # Connect to remote server
# Disable any display of non-wanted text on the terminal
# by redirecting stderr to /dev/null
# sys.stderr = open('/dev/null', 'a')
core.main_loop() # Refresh the screen, wait for user events etc
......@@ -110,19 +110,19 @@ class Tab(object):
"""
returns the color that should be used in the GlobalInfoBar
"""
raise NotImplementedError
return theme.COLOR_TAB_NORMAL
def set_color_state(self, color):
"""
set the color state
"""
raise NotImplementedError
pass
def get_name(self):
"""
get the name of the tab
"""
raise NotImplementedError
return self.__class__.__name__
def get_text_window(self):
"""
......@@ -1039,14 +1039,51 @@ class MucListTab(Tab):
self.core.execute(txt)
return self.reset_help_message()
def get_name(self):
return self.name
def on_input(self, key):
res = self.input.do_command(key)
if res:
return True
if key in self.key_func:
return self.key_func[key]()
def on_lose_focus(self):
self._color_state = theme.COLOR_TAB_NORMAL
def on_gain_focus(self):
self._color_state = theme.COLOR_TAB_CURRENT
curses.curs_set(0)
def get_color_state(self):
return theme.COLOR_TAB_NORMAL
return self._color_state
def set_color_state(self, color):
pass
class SimpleTextTab(Tab):
"""
A very simple tab, with just a text displaying some
information or whatever.
For example used to display tracebacks
"""
def __init__(self, core, text):
Tab.__init__(self, core)
self._color_state = theme.COLOR_TAB_NORMAL
self.text_win = windows.SimpleTextWin(text)
self.tab_win = windows.GlobalInfoBar()
self.default_help_message = windows.HelpText("“Ctrl+q”: close")
self.input = self.default_help_message
self.key_func['^T'] = self.close
self.key_func["/"] = self.on_slash
self.resize()
def get_name(self):
return self.name
def on_slash(self):
"""
'/' is pressed, activate the input
"""
curses.curs_set(1)
self.input = windows.CommandInput("", self.reset_help_message, self.execute_slash_command)
self.input.resize(1, self.width, self.height-1, 0, self.core.stdscr)
self.input.do_command("/") # we add the slash
def on_input(self, key):
res = self.input.do_command(key)
......@@ -1055,6 +1092,19 @@ class MucListTab(Tab):
if key in self.key_func:
return self.key_func[key]()
def close(self):
self.core.close_tab()
def resize(self):
self.text_win.resize(self.height-2, self.width, 0, 0, self.core.stdscr)
self.tab_win.resize(1, self.width, self.height-2, 0, self.core.stdscr)
self.input.resize(1, self.width, self.height-1, 0, self.core.stdscr)
def refresh(self, tabs, information, roster):
self.text_win.refresh()
self.tab_win.refresh(tabs, tabs[0])
self.input.refresh()
def on_lose_focus(self):
self._color_state = theme.COLOR_TAB_NORMAL
......@@ -1065,18 +1115,6 @@ class MucListTab(Tab):
def get_color_state(self):
return self._color_state
# class SimpleTextTab(Tab):
# """
# A very simple tab, with just a text displaying some
# information or whatever
# """
# def __init__(self, core, text):
# Tab.__init__(self, core)
# self.text = text
# self.text_win =
# def resize(self):
# pass
def diffmatch(search, string):
"""
Use difflib and a loop to check if search_pattern can
......
......@@ -49,7 +49,7 @@ import theme
g_lock = Lock()
LINES_NB_LIMIT = 16384
LINES_NB_LIMIT = 4096
class Win(object):
def __init__(self):
......@@ -1425,16 +1425,35 @@ class ColumnHeaderWin(Win):
x += size
self._refresh()
# class SimpleTextWin(Win):
# def __init__(self, text):
# self._text = text
# self.built_lines = []
class SimpleTextWin(Win):
def __init__(self, text):
self._text = text
self.built_lines = []
# def resize(self, height, width, y, x, stdscr):
# self._resize(height, width, y, x, stdscr)
# self.rebuild_text()
def resize(self, height, width, y, x, stdscr):
self._resize(height, width, y, x, stdscr)
self.rebuild_text()
# def rebuild_text(self):
def rebuild_text(self):
"""
Transform the text in lines than can then be
displayed without any calculation or anything
at refresh() time
It is basically called on each resize
"""
self.built_lines = []
for line in self._text.split('\n'):
while len(line) >= self.width:
limit = line[:self.width].rfind(' ')
if limit <= 0:
limit = self.width
self.built_lines.append(line[:limit])
line = line[limit:]
self.built_lines.append(line)
# def refresh(self):
# pass
def refresh(self):
with g_lock:
self._win.erase()
for y, line in enumerate(self.built_lines):
self.addstr(y, 0, line)
self._refresh()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment