10a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom Tkinter import *
20a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom idlelib.EditorWindow import EditorWindow
30a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport re
40a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoimport tkMessageBox
50a8c90248264a8b26970b4473770bcc3df8515fJosh Gaofrom idlelib import IOBinding
60a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
70a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass OutputWindow(EditorWindow):
80a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
90a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """An editor window that can serve as an output file.
100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    Also the future base class for the Python shell window.
120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    This class has no input facilities.
130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    """
140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, *args):
160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        EditorWindow.__init__(self, *args)
170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.text.bind("<<goto-file-line>>", self.goto_file_line)
180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    # Customize EditorWindow
200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def ispythonsource(self, filename):
220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # No colorization needed
230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return 0
240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
250a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def short_title(self):
260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        return "Output"
270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def maybesave(self):
290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Override base class method -- don't ask any questions
300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.get_saved():
310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return "yes"
320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return "no"
340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    # Act as output file
360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def write(self, s, tags=(), mark="insert"):
380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # Tk assumes that byte strings are Latin-1;
390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # we assume that they are in the locale's encoding
400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if isinstance(s, str):
410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            try:
420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                s = unicode(s, IOBinding.encoding)
430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            except UnicodeError:
440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                # some other encoding; let Tcl deal with it
450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                pass
460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.text.insert(mark, s, tags)
470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.text.see(mark)
480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.text.update()
490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
500a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def writelines(self, lines):
510a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for line in lines:
520a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.write(line)
530a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
540a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def flush(self):
550a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        pass
560a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
570a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    # Our own right-button menu
580a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
590a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    rmenu_specs = [
600a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ("Cut", "<<cut>>", "rmenu_check_cut"),
610a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ("Copy", "<<copy>>", "rmenu_check_copy"),
620a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ("Paste", "<<paste>>", "rmenu_check_paste"),
630a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        (None, None, None),
640a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        ("Go to file/line", "<<goto-file-line>>", None),
650a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    ]
660a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
670a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    file_line_pats = [
680a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # order of patterns matters
690a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        r'file "([^"]*)", line (\d+)',
700a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        r'([^\s]+)\((\d+)\)',
710a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        r'^(\s*\S.*?):\s*(\d+):',  # Win filename, maybe starting with spaces
720a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        r'([^\s]+):\s*(\d+):',     # filename or path, ltrim
730a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        r'^\s*(\S.*?):\s*(\d+):',  # Win abs path with embedded spaces, ltrim
740a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    ]
750a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
760a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    file_line_progs = None
770a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
780a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def goto_file_line(self, event=None):
790a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if self.file_line_progs is None:
800a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            l = []
810a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            for pat in self.file_line_pats:
820a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                l.append(re.compile(pat, re.IGNORECASE))
830a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.file_line_progs = l
840a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # x, y = self.event.x, self.event.y
850a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # self.text.mark_set("insert", "@%d,%d" % (x, y))
860a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        line = self.text.get("insert linestart", "insert lineend")
870a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        result = self._file_line_helper(line)
880a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not result:
890a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # Try the previous line.  This is handy e.g. in tracebacks,
900a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            # where you tend to right-click on the displayed source line
910a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            line = self.text.get("insert -1line linestart",
920a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                                 "insert -1line lineend")
930a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            result = self._file_line_helper(line)
940a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if not result:
950a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                tkMessageBox.showerror(
960a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    "No special line",
970a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    "The line you point at doesn't look like "
980a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    "a valid file name followed by a line number.",
990a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    master=self.text)
1000a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                return
1010a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        filename, lineno = result
1020a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        edit = self.flist.open(filename)
1030a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        edit.gotoline(lineno)
1040a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1050a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def _file_line_helper(self, line):
1060a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for prog in self.file_line_progs:
1070a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            match = prog.search(line)
1080a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if match:
1090a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                filename, lineno = match.group(1, 2)
1100a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                try:
1110a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    f = open(filename, "r")
1120a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    f.close()
1130a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    break
1140a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                except IOError:
1150a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                    continue
1160a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        else:
1170a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return None
1180a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        try:
1190a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return filename, int(lineno)
1200a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        except TypeError:
1210a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            return None
1220a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1230a8c90248264a8b26970b4473770bcc3df8515fJosh Gao# These classes are currently not used but might come in handy
1240a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1250a8c90248264a8b26970b4473770bcc3df8515fJosh Gaoclass OnDemandOutputWindow:
1260a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1270a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    tagdefs = {
1280a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        # XXX Should use IdlePrefs.ColorPrefs
1290a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        "stdout":  {"foreground": "blue"},
1300a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        "stderr":  {"foreground": "#007700"},
1310a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    }
1320a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1330a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def __init__(self, flist):
1340a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.flist = flist
1350a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.owin = None
1360a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1370a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def write(self, s, tags, mark):
1380a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        if not self.owin:
1390a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            self.setup()
1400a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.owin.write(s, tags, mark)
1410a8c90248264a8b26970b4473770bcc3df8515fJosh Gao
1420a8c90248264a8b26970b4473770bcc3df8515fJosh Gao    def setup(self):
1430a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.owin = owin = OutputWindow(self.flist)
1440a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        text = owin.text
1450a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        for tag, cnf in self.tagdefs.items():
1460a8c90248264a8b26970b4473770bcc3df8515fJosh Gao            if cnf:
1470a8c90248264a8b26970b4473770bcc3df8515fJosh Gao                text.tag_configure(tag, **cnf)
1480a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        text.tag_raise('sel')
1490a8c90248264a8b26970b4473770bcc3df8515fJosh Gao        self.write = self.owin.write
150