| 1 | """Buffer class.""" |
| 2 | |
| 3 | __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>" |
| 4 | __cvsid__ = "$Id$" |
| 5 | __revision__ = "$Revision$"[11:-2] |
| 6 | |
| 7 | from interpreter import Interpreter |
| 8 | import imp |
| 9 | import os |
| 10 | import sys |
| 11 | |
| 12 | import document |
| 13 | |
| 14 | |
| 15 | class Buffer: |
| 16 | """Buffer class.""" |
| 17 | |
| 18 | id = 0 |
| 19 | |
| 20 | def __init__(self, filename=None): |
| 21 | """Create a Buffer instance.""" |
| 22 | Buffer.id += 1 |
| 23 | self.id = Buffer.id |
| 24 | self.interp = Interpreter(locals={}) |
| 25 | self.name = '' |
| 26 | self.editors = {} |
| 27 | self.editor = None |
| 28 | self.modules = sys.modules.keys() |
| 29 | self.syspath = sys.path[:] |
| 30 | while True: |
| 31 | try: |
| 32 | self.syspath.remove('') |
| 33 | except ValueError: |
| 34 | break |
| 35 | while True: |
| 36 | try: |
| 37 | self.syspath.remove('.') |
| 38 | except ValueError: |
| 39 | break |
| 40 | self.open(filename) |
| 41 | |
| 42 | def addEditor(self, editor): |
| 43 | """Add an editor.""" |
| 44 | self.editor = editor |
| 45 | self.editors[editor.id] = editor |
| 46 | |
| 47 | def hasChanged(self): |
| 48 | """Return True if text in editor has changed since last save.""" |
| 49 | if self.editor: |
| 50 | return self.editor.hasChanged() |
| 51 | else: |
| 52 | return False |
| 53 | |
| 54 | def new(self, filepath): |
| 55 | """New empty buffer.""" |
| 56 | if not filepath: |
| 57 | return |
| 58 | if os.path.exists(filepath): |
| 59 | self.confirmed = self.overwriteConfirm(filepath) |
| 60 | else: |
| 61 | self.confirmed = True |
| 62 | |
| 63 | def open(self, filename): |
| 64 | """Open file into buffer.""" |
| 65 | self.doc = document.Document(filename) |
| 66 | self.name = self.doc.filename or ('Untitled:' + str(self.id)) |
| 67 | self.modulename = self.doc.filebase |
| 68 | # XXX This should really make sure filedir is first item in syspath. |
| 69 | # XXX Or maybe this should be moved to the update namespace method. |
| 70 | if self.doc.filedir and self.doc.filedir not in self.syspath: |
| 71 | # To create the proper context for updateNamespace. |
| 72 | self.syspath.insert(0, self.doc.filedir) |
| 73 | if self.doc.filepath and os.path.exists(self.doc.filepath): |
| 74 | self.confirmed = True |
| 75 | if self.editor: |
| 76 | text = self.doc.read() |
| 77 | self.editor._setBuffer(buffer=self, text=text) |
| 78 | |
| 79 | def overwriteConfirm(filepath): |
| 80 | """Confirm overwriting an existing file.""" |
| 81 | return False |
| 82 | |
| 83 | def save(self): |
| 84 | """Save buffer.""" |
| 85 | filepath = self.doc.filepath |
| 86 | if not filepath: |
| 87 | return # XXX Get filename |
| 88 | if not os.path.exists(filepath): |
| 89 | self.confirmed = True |
| 90 | if not self.confirmed: |
| 91 | self.confirmed = self.overwriteConfirm(filepath) |
| 92 | if self.confirmed: |
| 93 | self.doc.write(self.editor.getText()) |
| 94 | if self.editor: |
| 95 | self.editor.setSavePoint() |
| 96 | |
| 97 | def saveAs(self, filename): |
| 98 | """Save buffer.""" |
| 99 | self.doc = document.Document(filename) |
| 100 | self.name = self.doc.filename |
| 101 | self.modulename = self.doc.filebase |
| 102 | self.save() |
| 103 | |
| 104 | def updateNamespace(self): |
| 105 | """Update the namespace for autocompletion and calltips. |
| 106 | |
| 107 | Return True if updated, False if there was an error.""" |
| 108 | if not self.interp or not hasattr(self.editor, 'getText'): |
| 109 | return False |
| 110 | syspath = sys.path |
| 111 | sys.path = self.syspath |
| 112 | text = self.editor.getText() |
| 113 | text = text.replace('\r\n', '\n') |
| 114 | text = text.replace('\r', '\n') |
| 115 | name = self.modulename or self.name |
| 116 | module = imp.new_module(name) |
| 117 | newspace = module.__dict__.copy() |
| 118 | try: |
| 119 | try: |
| 120 | code = compile(text, name, 'exec') |
| 121 | except: |
| 122 | raise |
| 123 | # return False |
| 124 | try: |
| 125 | exec code in newspace |
| 126 | except: |
| 127 | raise |
| 128 | # return False |
| 129 | else: |
| 130 | # No problems, so update the namespace. |
| 131 | self.interp.locals.clear() |
| 132 | self.interp.locals.update(newspace) |
| 133 | return True |
| 134 | finally: |
| 135 | sys.path = syspath |
| 136 | for m in sys.modules.keys(): |
| 137 | if m not in self.modules: |
| 138 | del sys.modules[m] |