Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
document.py379 linesDownload Raw Back to editor
1# We no longer support the old, non-colour editor!2 3import os4import shutil5import traceback6 7import win32api8import win32con9import win32ui10from pywin.framework.editor import GetEditorOption11from pywin.mfc import docview, object12 13BAK_NONE = 014BAK_DOT_BAK = 115BAK_DOT_BAK_TEMP_DIR = 216BAK_DOT_BAK_BAK_DIR = 317 18MSG_CHECK_EXTERNAL_FILE = (19    win32con.WM_USER + 199920)  ## WARNING: Duplicated in editor.py and coloreditor.py21 22import pywin.scintilla.document23 24ParentEditorDocument = pywin.scintilla.document.CScintillaDocument25 26 27class EditorDocumentBase(ParentEditorDocument):28    def __init__(self, template):29        self.bAutoReload = GetEditorOption("Auto Reload", 1)30        self.bDeclinedReload = 0  # Has the user declined to reload.31        self.fileStat = None32        self.bReportedFileNotFound = 033 34        # what sort of bak file should I create.35        # default to write to %temp%/bak/filename.ext36        self.bakFileType = GetEditorOption("Backup Type", BAK_DOT_BAK_BAK_DIR)37 38        self.watcherThread = FileWatchingThread(self)39        self.watcherThread.CreateThread()40        # Should I try and use VSS integration?41        self.scModuleName = GetEditorOption("Source Control Module", "")42        self.scModule = None  # Loaded when first used.43        ParentEditorDocument.__init__(self, template, template.CreateWin32uiDocument())44 45    def OnCloseDocument(self):46        self.watcherThread.SignalStop()47        return self._obj_.OnCloseDocument()48 49    # 	def OnOpenDocument(self, name):50    # 		rc = ParentEditorDocument.OnOpenDocument(self, name)51    # 		self.GetFirstView()._SetLoadedText(self.text)52    # 		self._DocumentStateChanged()53    # 		return rc54 55    def OnSaveDocument(self, fileName):56        win32ui.SetStatusText("Saving file...", 1)57        # rename to bak if required.58        dir, basename = os.path.split(fileName)59        if self.bakFileType == BAK_DOT_BAK:60            bakFileName = dir + "\\" + os.path.splitext(basename)[0] + ".bak"61        elif self.bakFileType == BAK_DOT_BAK_TEMP_DIR:62            bakFileName = (63                win32api.GetTempPath() + "\\" + os.path.splitext(basename)[0] + ".bak"64            )65        elif self.bakFileType == BAK_DOT_BAK_BAK_DIR:66            tempPath = os.path.join(win32api.GetTempPath(), "bak")67            try:68                os.mkdir(tempPath, 0)69            except os.error:70                pass71            bakFileName = os.path.join(tempPath, basename)72        try:73            os.unlink(bakFileName)  # raise NameError if no bakups wanted.74        except (os.error, NameError):75            pass76        try:77            # Do a copy as it might be on different volumes,78            # and the file may be a hard-link, causing the link79            # to follow the backup.80            shutil.copy2(fileName, bakFileName)81        except (os.error, NameError, IOError):82            pass83        try:84            self.SaveFile(fileName)85        except IOError as details:86            win32ui.MessageBox("Error - could not save file\r\n\r\n%s" % details)87            return 088        except (UnicodeEncodeError, LookupError) as details:89            rc = win32ui.MessageBox(90                "Encoding failed: \r\n%s" % details91                + "\r\nPlease add desired source encoding as first line of file, eg \r\n"92                + "# -*- coding: mbcs -*-\r\n\r\n"93                + "If you continue, the file will be saved as binary and will\r\n"94                + "not be valid in the declared encoding.\r\n\r\n"95                + "Save the file as binary with an invalid encoding?",96                "File save failed",97                win32con.MB_YESNO | win32con.MB_DEFBUTTON2,98            )99            if rc == win32con.IDYES:100                try:101                    self.SaveFile(fileName, encoding="latin-1")102                except IOError as details:103                    win32ui.MessageBox(104                        "Error - could not save file\r\n\r\n%s" % details105                    )106                    return 0107            else:108                return 0109        self.SetModifiedFlag(0)  # No longer dirty110        self.bDeclinedReload = 0  # They probably want to know if it changes again!111        win32ui.AddToRecentFileList(fileName)112        self.SetPathName(fileName)113        win32ui.SetStatusText("Ready")114        self._DocumentStateChanged()115        return 1116 117    def FinalizeViewCreation(self, view):118        ParentEditorDocument.FinalizeViewCreation(self, view)119        if view == self.GetFirstView():120            self._DocumentStateChanged()121            if view.bFolding and GetEditorOption("Fold On Open", 0):122                view.FoldTopLevelEvent()123 124    def HookViewNotifications(self, view):125        ParentEditorDocument.HookViewNotifications(self, view)126 127    # Support for reloading the document from disk - presumably after some128    # external application has modified it (or possibly source control has129    # checked it out.130    def ReloadDocument(self):131        """Reloads the document from disk.  Assumes the file has132        been saved and user has been asked if necessary - it just does it!133        """134        win32ui.SetStatusText("Reloading document.  Please wait...", 1)135        self.SetModifiedFlag(0)136        # Loop over all views, saving their state, then reload the document137        views = self.GetAllViews()138        states = []139        for view in views:140            try:141                info = view._PrepareUserStateChange()142            except AttributeError:  # Not our editor view?143                info = None144            states.append(info)145        self.OnOpenDocument(self.GetPathName())146        for view, info in zip(views, states):147            if info is not None:148                view._EndUserStateChange(info)149        self._DocumentStateChanged()150        win32ui.SetStatusText("Document reloaded.")151 152    # Reloading the file153    def CheckExternalDocumentUpdated(self):154        if self.bDeclinedReload or not self.GetPathName():155            return156        try:157            newstat = os.stat(self.GetPathName())158        except os.error as exc:159            if not self.bReportedFileNotFound:160                print(161                    "The file '%s' is open for editing, but\nchecking it for changes caused the error: %s"162                    % (self.GetPathName(), exc.strerror)163                )164                self.bReportedFileNotFound = 1165            return166        if self.bReportedFileNotFound:167            print(168                "The file '%s' has re-appeared - continuing to watch for changes..."169                % (self.GetPathName(),)170            )171            self.bReportedFileNotFound = (172                0  # Once found again we want to start complaining.173            )174        changed = (175            (self.fileStat is None)176            or self.fileStat[0] != newstat[0]177            or self.fileStat[6] != newstat[6]178            or self.fileStat[8] != newstat[8]179            or self.fileStat[9] != newstat[9]180        )181        if changed:182            question = None183            if self.IsModified():184                question = (185                    "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it and LOSE THE CHANGES in the source editor?"186                    % self.GetPathName()187                )188                mbStyle = win32con.MB_YESNO | win32con.MB_DEFBUTTON2  # Default to "No"189            else:190                if not self.bAutoReload:191                    question = (192                        "%s\r\n\r\nThis file has been modified outside of the source editor.\r\nDo you want to reload it?"193                        % self.GetPathName()194                    )195                    mbStyle = win32con.MB_YESNO  # Default to "Yes"196            if question:197                rc = win32ui.MessageBox(question, None, mbStyle)198                if rc != win32con.IDYES:199                    self.bDeclinedReload = 1200                    return201            self.ReloadDocument()202 203    def _DocumentStateChanged(self):204        """Called whenever the documents state (on disk etc) has been changed205        by the editor (eg, as the result of a save operation)206        """207        if self.GetPathName():208            try:209                self.fileStat = os.stat(self.GetPathName())210            except os.error:211                self.fileStat = None212        else:213            self.fileStat = None214        self.watcherThread._DocumentStateChanged()215        self._UpdateUIForState()216        self._ApplyOptionalToViews("_UpdateUIForState")217        self._ApplyOptionalToViews("SetReadOnly", self._IsReadOnly())218        self._ApplyOptionalToViews("SCISetSavePoint")219        # Allow the debugger to reset us too.220        import pywin.debugger221 222        if pywin.debugger.currentDebugger is not None:223            pywin.debugger.currentDebugger.UpdateDocumentLineStates(self)224 225    # Read-only document support - make it obvious to the user226    # that the file is read-only.227    def _IsReadOnly(self):228        return self.fileStat is not None and (self.fileStat[0] & 128) == 0229 230    def _UpdateUIForState(self):231        """Change the title to reflect the state of the document -232        eg ReadOnly, Dirty, etc233        """234        filename = self.GetPathName()235        if not filename:236            return  # New file - nothing to do237        try:238            # This seems necessary so the internal state of the window becomes239            # "visible".  without it, it is still shown, but certain functions240            # (such as updating the title) dont immediately work?241            self.GetFirstView().ShowWindow(win32con.SW_SHOW)242            title = win32ui.GetFileTitle(filename)243        except win32ui.error:244            title = filename245        if self._IsReadOnly():246            title = title + " (read-only)"247        self.SetTitle(title)248 249    def MakeDocumentWritable(self):250        pretend_ss = 0  # Set to 1 to test this without source safe :-)251        if not self.scModuleName and not pretend_ss:  # No Source Control support.252            win32ui.SetStatusText(253                "Document is read-only, and no source-control system is configured"254            )255            win32api.MessageBeep()256            return 0257 258        # We have source control support - check if the user wants to use it.259        msg = "Would you like to check this file out?"260        defButton = win32con.MB_YESNO261        if self.IsModified():262            msg = msg + "\r\n\r\nALL CHANGES IN THE EDITOR WILL BE LOST"263            defButton = win32con.MB_YESNO264        if win32ui.MessageBox(msg, None, defButton) != win32con.IDYES:265            return 0266 267        if pretend_ss:268            print("We are only pretending to check it out!")269            win32api.SetFileAttributes(270                self.GetPathName(), win32con.FILE_ATTRIBUTE_NORMAL271            )272            self.ReloadDocument()273            return 1274 275        # Now call on the module to do it.276        if self.scModule is None:277            try:278                self.scModule = __import__(self.scModuleName)279                for part in self.scModuleName.split(".")[1:]:280                    self.scModule = getattr(self.scModule, part)281            except:282                traceback.print_exc()283                print("Error loading source control module.")284                return 0285 286        if self.scModule.CheckoutFile(self.GetPathName()):287            self.ReloadDocument()288            return 1289        return 0290 291    def CheckMakeDocumentWritable(self):292        if self._IsReadOnly():293            return self.MakeDocumentWritable()294        return 1295 296    def SaveModified(self):297        # Called as the document is closed.  If we are about298        # to prompt for a save, bring the document to the foreground.299        if self.IsModified():300            frame = self.GetFirstView().GetParentFrame()301            try:302                frame.MDIActivate()303                frame.AutoRestore()304            except:305                print("Could not bring document to foreground")306        return self._obj_.SaveModified()307 308 309# NOTE - I DONT use the standard threading module,310# as this waits for all threads to terminate at shutdown.311# When using the debugger, it is possible shutdown will312# occur without Pythonwin getting a complete shutdown,313# so we deadlock at the end - threading is waiting for314import pywin.mfc.thread315import win32event316 317 318class FileWatchingThread(pywin.mfc.thread.WinThread):319    def __init__(self, doc):320        self.doc = doc321        self.adminEvent = win32event.CreateEvent(None, 0, 0, None)322        self.stopEvent = win32event.CreateEvent(None, 0, 0, None)323        self.watchEvent = None324        pywin.mfc.thread.WinThread.__init__(self)325 326    def _DocumentStateChanged(self):327        win32event.SetEvent(self.adminEvent)328 329    def RefreshEvent(self):330        self.hwnd = self.doc.GetFirstView().GetSafeHwnd()331        if self.watchEvent is not None:332            win32api.FindCloseChangeNotification(self.watchEvent)333            self.watchEvent = None334        path = self.doc.GetPathName()335        if path:336            path = os.path.dirname(path)337        if path:338            filter = (339                win32con.FILE_NOTIFY_CHANGE_FILE_NAME340                | win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES341                | win32con.FILE_NOTIFY_CHANGE_LAST_WRITE342            )343            try:344                self.watchEvent = win32api.FindFirstChangeNotification(path, 0, filter)345            except win32api.error as exc:346                print("Can not watch file", path, "for changes -", exc.strerror)347 348    def SignalStop(self):349        win32event.SetEvent(self.stopEvent)350 351    def Run(self):352        while 1:353            handles = [self.stopEvent, self.adminEvent]354            if self.watchEvent is not None:355                handles.append(self.watchEvent)356            rc = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)357            if rc == win32event.WAIT_OBJECT_0:358                break359            elif rc == win32event.WAIT_OBJECT_0 + 1:360                self.RefreshEvent()361            else:362                win32api.PostMessage(self.hwnd, MSG_CHECK_EXTERNAL_FILE, 0, 0)363                try:364                    # If the directory has been removed underneath us, we get this error.365                    win32api.FindNextChangeNotification(self.watchEvent)366                except win32api.error as exc:367                    print(368                        "Can not watch file",369                        self.doc.GetPathName(),370                        "for changes -",371                        exc.strerror,372                    )373                    break374 375        # close a circular reference376        self.doc = None377        if self.watchEvent:378            win32api.FindCloseChangeNotification(self.watchEvent)379 
codekingpro/portable-devtools · Team Ai