OutputWindow.py 4.5 KB

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