Home | History | Annotate | Download | only in idlelib
      1 from Tkinter import *
      2 from idlelib.EditorWindow import EditorWindow
      3 import re
      4 import tkMessageBox
      5 from idlelib import IOBinding
      6 
      7 class OutputWindow(EditorWindow):
      8 
      9     """An editor window that can serve as an output file.
     10 
     11     Also the future base class for the Python shell window.
     12     This class has no input facilities.
     13     """
     14 
     15     def __init__(self, *args):
     16         EditorWindow.__init__(self, *args)
     17         self.text.bind("<<goto-file-line>>", self.goto_file_line)
     18 
     19     # Customize EditorWindow
     20 
     21     def ispythonsource(self, filename):
     22         # No colorization needed
     23         return 0
     24 
     25     def short_title(self):
     26         return "Output"
     27 
     28     def maybesave(self):
     29         # Override base class method -- don't ask any questions
     30         if self.get_saved():
     31             return "yes"
     32         else:
     33             return "no"
     34 
     35     # Act as output file
     36 
     37     def write(self, s, tags=(), mark="insert"):
     38         # Tk assumes that byte strings are Latin-1;
     39         # we assume that they are in the locale's encoding
     40         if isinstance(s, str):
     41             try:
     42                 s = unicode(s, IOBinding.encoding)
     43             except UnicodeError:
     44                 # some other encoding; let Tcl deal with it
     45                 pass
     46         self.text.insert(mark, s, tags)
     47         self.text.see(mark)
     48         self.text.update()
     49 
     50     def writelines(self, lines):
     51         for line in lines:
     52             self.write(line)
     53 
     54     def flush(self):
     55         pass
     56 
     57     # Our own right-button menu
     58 
     59     rmenu_specs = [
     60         ("Cut", "<<cut>>", "rmenu_check_cut"),
     61         ("Copy", "<<copy>>", "rmenu_check_copy"),
     62         ("Paste", "<<paste>>", "rmenu_check_paste"),
     63         (None, None, None),
     64         ("Go to file/line", "<<goto-file-line>>", None),
     65     ]
     66 
     67     file_line_pats = [
     68         # order of patterns matters
     69         r'file "([^"]*)", line (\d+)',
     70         r'([^\s]+)\((\d+)\)',
     71         r'^(\s*\S.*?):\s*(\d+):',  # Win filename, maybe starting with spaces
     72         r'([^\s]+):\s*(\d+):',     # filename or path, ltrim
     73         r'^\s*(\S.*?):\s*(\d+):',  # Win abs path with embedded spaces, ltrim
     74     ]
     75 
     76     file_line_progs = None
     77 
     78     def goto_file_line(self, event=None):
     79         if self.file_line_progs is None:
     80             l = []
     81             for pat in self.file_line_pats:
     82                 l.append(re.compile(pat, re.IGNORECASE))
     83             self.file_line_progs = l
     84         # x, y = self.event.x, self.event.y
     85         # self.text.mark_set("insert", "@%d,%d" % (x, y))
     86         line = self.text.get("insert linestart", "insert lineend")
     87         result = self._file_line_helper(line)
     88         if not result:
     89             # Try the previous line.  This is handy e.g. in tracebacks,
     90             # where you tend to right-click on the displayed source line
     91             line = self.text.get("insert -1line linestart",
     92                                  "insert -1line lineend")
     93             result = self._file_line_helper(line)
     94             if not result:
     95                 tkMessageBox.showerror(
     96                     "No special line",
     97                     "The line you point at doesn't look like "
     98                     "a valid file name followed by a line number.",
     99                     master=self.text)
    100                 return
    101         filename, lineno = result
    102         edit = self.flist.open(filename)
    103         edit.gotoline(lineno)
    104 
    105     def _file_line_helper(self, line):
    106         for prog in self.file_line_progs:
    107             match = prog.search(line)
    108             if match:
    109                 filename, lineno = match.group(1, 2)
    110                 try:
    111                     f = open(filename, "r")
    112                     f.close()
    113                     break
    114                 except IOError:
    115                     continue
    116         else:
    117             return None
    118         try:
    119             return filename, int(lineno)
    120         except TypeError:
    121             return None
    122 
    123 # These classes are currently not used but might come in handy
    124 
    125 class OnDemandOutputWindow:
    126 
    127     tagdefs = {
    128         # XXX Should use IdlePrefs.ColorPrefs
    129         "stdout":  {"foreground": "blue"},
    130         "stderr":  {"foreground": "#007700"},
    131     }
    132 
    133     def __init__(self, flist):
    134         self.flist = flist
    135         self.owin = None
    136 
    137     def write(self, s, tags, mark):
    138         if not self.owin:
    139             self.setup()
    140         self.owin.write(s, tags, mark)
    141 
    142     def setup(self):
    143         self.owin = owin = OutputWindow(self.flist)
    144         text = owin.text
    145         for tag, cnf in self.tagdefs.items():
    146             if cnf:
    147                 text.tag_configure(tag, **cnf)
    148         text.tag_raise('sel')
    149         self.write = self.owin.write
    150