(root)/
Python-3.11.7/
Lib/
idlelib/
outwin.py
       1  """Editor window that can serve as an output file.
       2  """
       3  
       4  import re
       5  
       6  from tkinter import messagebox
       7  
       8  from idlelib.editor import EditorWindow
       9  
      10  
      11  file_line_pats = [
      12      # order of patterns matters
      13      r'file "([^"]*)", line (\d+)',
      14      r'([^\s]+)\((\d+)\)',
      15      r'^(\s*\S.*?):\s*(\d+):',  # Win filename, maybe starting with spaces
      16      r'([^\s]+):\s*(\d+):',     # filename or path, ltrim
      17      r'^\s*(\S.*?):\s*(\d+):',  # Win abs path with embedded spaces, ltrim
      18  ]
      19  
      20  file_line_progs = None
      21  
      22  
      23  def compile_progs():
      24      "Compile the patterns for matching to file name and line number."
      25      global file_line_progs
      26      file_line_progs = [re.compile(pat, re.IGNORECASE)
      27                         for pat in file_line_pats]
      28  
      29  
      30  def file_line_helper(line):
      31      """Extract file name and line number from line of text.
      32  
      33      Check if line of text contains one of the file/line patterns.
      34      If it does and if the file and line are valid, return
      35      a tuple of the file name and line number.  If it doesn't match
      36      or if the file or line is invalid, return None.
      37      """
      38      if not file_line_progs:
      39          compile_progs()
      40      for prog in file_line_progs:
      41          match = prog.search(line)
      42          if match:
      43              filename, lineno = match.group(1, 2)
      44              try:
      45                  f = open(filename)
      46                  f.close()
      47                  break
      48              except OSError:
      49                  continue
      50      else:
      51          return None
      52      try:
      53          return filename, int(lineno)
      54      except TypeError:
      55          return None
      56  
      57  
      58  class ESC[4;38;5;81mOutputWindow(ESC[4;38;5;149mEditorWindow):
      59      """An editor window that can serve as an output file.
      60  
      61      Also the future base class for the Python shell window.
      62      This class has no input facilities.
      63  
      64      Adds binding to open a file at a line to the text widget.
      65      """
      66  
      67      # Our own right-button menu
      68      rmenu_specs = [
      69          ("Cut", "<<cut>>", "rmenu_check_cut"),
      70          ("Copy", "<<copy>>", "rmenu_check_copy"),
      71          ("Paste", "<<paste>>", "rmenu_check_paste"),
      72          (None, None, None),
      73          ("Go to file/line", "<<goto-file-line>>", None),
      74      ]
      75  
      76      allow_code_context = False
      77  
      78      def __init__(self, *args):
      79          EditorWindow.__init__(self, *args)
      80          self.text.bind("<<goto-file-line>>", self.goto_file_line)
      81  
      82      # Customize EditorWindow
      83      def ispythonsource(self, filename):
      84          "Python source is only part of output: do not colorize."
      85          return False
      86  
      87      def short_title(self):
      88          "Customize EditorWindow title."
      89          return "Output"
      90  
      91      def maybesave(self):
      92          "Customize EditorWindow to not display save file messagebox."
      93          return 'yes' if self.get_saved() else 'no'
      94  
      95      # Act as output file
      96      def write(self, s, tags=(), mark="insert"):
      97          """Write text to text widget.
      98  
      99          The text is inserted at the given index with the provided
     100          tags.  The text widget is then scrolled to make it visible
     101          and updated to display it, giving the effect of seeing each
     102          line as it is added.
     103  
     104          Args:
     105              s: Text to insert into text widget.
     106              tags: Tuple of tag strings to apply on the insert.
     107              mark: Index for the insert.
     108  
     109          Return:
     110              Length of text inserted.
     111          """
     112          assert isinstance(s, str)
     113          self.text.insert(mark, s, tags)
     114          self.text.see(mark)
     115          self.text.update_idletasks()
     116          return len(s)
     117  
     118      def writelines(self, lines):
     119          "Write each item in lines iterable."
     120          for line in lines:
     121              self.write(line)
     122  
     123      def flush(self):
     124          "No flushing needed as write() directly writes to widget."
     125          pass
     126  
     127      def showerror(self, *args, **kwargs):
     128          messagebox.showerror(*args, **kwargs)
     129  
     130      def goto_file_line(self, event=None):
     131          """Handle request to open file/line.
     132  
     133          If the selected or previous line in the output window
     134          contains a file name and line number, then open that file
     135          name in a new window and position on the line number.
     136  
     137          Otherwise, display an error messagebox.
     138          """
     139          line = self.text.get("insert linestart", "insert lineend")
     140          result = file_line_helper(line)
     141          if not result:
     142              # Try the previous line.  This is handy e.g. in tracebacks,
     143              # where you tend to right-click on the displayed source line
     144              line = self.text.get("insert -1line linestart",
     145                                   "insert -1line lineend")
     146              result = file_line_helper(line)
     147              if not result:
     148                  self.showerror(
     149                      "No special line",
     150                      "The line you point at doesn't look like "
     151                      "a valid file name followed by a line number.",
     152                      parent=self.text)
     153                  return
     154          filename, lineno = result
     155          self.flist.gotofileline(filename, lineno)
     156  
     157  
     158  # These classes are currently not used but might come in handy
     159  class ESC[4;38;5;81mOnDemandOutputWindow:
     160  
     161      tagdefs = {
     162          # XXX Should use IdlePrefs.ColorPrefs
     163          "stdout":  {"foreground": "blue"},
     164          "stderr":  {"foreground": "#007700"},
     165      }
     166  
     167      def __init__(self, flist):
     168          self.flist = flist
     169          self.owin = None
     170  
     171      def write(self, s, tags, mark):
     172          if not self.owin:
     173              self.setup()
     174          self.owin.write(s, tags, mark)
     175  
     176      def setup(self):
     177          self.owin = owin = OutputWindow(self.flist)
     178          text = owin.text
     179          for tag, cnf in self.tagdefs.items():
     180              if cnf:
     181                  text.tag_configure(tag, **cnf)
     182          text.tag_raise('sel')
     183          self.write = self.owin.write
     184  
     185  
     186  if __name__ == '__main__':
     187      from unittest import main
     188      main('idlelib.idle_test.test_outwin', verbosity=2, exit=False)