Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
editor.py517 linesDownload Raw Back to editor
1#####################################################################2#3# editor.py4#5# A general purpose text editor, built on top of the win32ui edit6# type, which is built on an MFC CEditView7#8#9# We now support reloading of externally modified documented10# (eg, presumably by some other process, such as source control or11# another editor.12# We also suport auto-loading of externally modified files.13# - if the current document has not been modified in this14# editor, but has been modified on disk, then the file15# can be automatically reloaded.16#17# Note that it will _always_ prompt you if the file in the editor has been modified.18 19 20import re21 22import regex23import win32api24import win32con25import win32ui26from pywin.framework.editor import (27    GetEditorFontOption,28    GetEditorOption,29    SetEditorFontOption,30    SetEditorOption,31    defaultCharacterFormat,32)33from pywin.mfc import afxres, dialog, docview34 35patImport = regex.symcomp("import \(<name>.*\)")36patIndent = regex.compile("^\\([ \t]*[~ \t]\\)")37 38ID_LOCATE_FILE = 0xE20039ID_GOTO_LINE = 0xE200140MSG_CHECK_EXTERNAL_FILE = (41    win32con.WM_USER + 199942)  ## WARNING: Duplicated in document.py and coloreditor.py43 44# Key Codes that modify the bufffer when Ctrl or Alt are NOT pressed.45MODIFYING_VK_KEYS = [46    win32con.VK_BACK,47    win32con.VK_TAB,48    win32con.VK_RETURN,49    win32con.VK_SPACE,50    win32con.VK_DELETE,51]52for k in range(48, 91):53    MODIFYING_VK_KEYS.append(k)54 55# Key Codes that modify the bufffer when Ctrl is pressed.56MODIFYING_VK_KEYS_CTRL = [57    win32con.VK_BACK,58    win32con.VK_RETURN,59    win32con.VK_SPACE,60    win32con.VK_DELETE,61]62 63# Key Codes that modify the bufffer when Alt is pressed.64MODIFYING_VK_KEYS_ALT = [65    win32con.VK_BACK,66    win32con.VK_RETURN,67    win32con.VK_SPACE,68    win32con.VK_DELETE,69]70 71 72# The editor itself starts here.73# Using the MFC Document/View model, we have an EditorDocument, which is responsible for74# managing the contents of the file, and a view which is responsible for rendering it.75#76# Due to a limitation in the Windows edit controls, we are limited to one view77# per document, although nothing in this code assumes this (I hope!)78 79isRichText = 1  # We are using the Rich Text control.  This has not been tested with value "0" for quite some time!80 81# ParentEditorDocument=docview.Document82from .document import EditorDocumentBase83 84ParentEditorDocument = EditorDocumentBase85 86 87class EditorDocument(ParentEditorDocument):88    #89    # File loading and saving operations90    #91    def OnOpenDocument(self, filename):92        #93        # handle Unix and PC text file format.94        #95 96        # Get the "long name" of the file name, as it may have been translated97        # to short names by the shell.98        self.SetPathName(filename)  # Must set this early!99        # Now do the work!100        self.BeginWaitCursor()101        win32ui.SetStatusText("Loading file...", 1)102        try:103            f = open(filename, "rb")104        except IOError:105            win32ui.MessageBox(106                filename107                + "\nCan not find this file\nPlease verify that the correct path and file name are given"108            )109            self.EndWaitCursor()110            return 0111        raw = f.read()112        f.close()113        contents = self.TranslateLoadedData(raw)114        rc = 0115        try:116            self.GetFirstView().SetWindowText(contents)117            rc = 1118        except TypeError:  # Null byte in file.119            win32ui.MessageBox("This file contains NULL bytes, and can not be edited")120            rc = 0121 122        self.EndWaitCursor()123        self.SetModifiedFlag(0)  # No longer dirty124        self._DocumentStateChanged()125        return rc126 127    def TranslateLoadedData(self, data):128        """Given raw data read from a file, massage it suitable for the edit window"""129        # if a CR in the first 250 chars, then perform the expensive translate130        if data[:250].find("\r") == -1:131            win32ui.SetStatusText(132                "Translating from Unix file format - please wait...", 1133            )134            return re.sub("\r*\n", "\r\n", data)135        else:136            return data137 138    def SaveFile(self, fileName, encoding=None):139        if isRichText:140            view = self.GetFirstView()141            view.SaveTextFile(fileName, encoding=encoding)142        else:  # Old style edit view window.143            self.GetFirstView().SaveFile(fileName)144        try:145            # Make sure line cache has updated info about me!146            import linecache147 148            linecache.checkcache()149        except:150            pass151 152    #153    # Color state stuff154    #155    def SetAllLineColors(self, color=None):156        for view in self.GetAllViews():157            view.SetAllLineColors(color)158 159    def SetLineColor(self, lineNo, color):160        "Color a line of all views"161        for view in self.GetAllViews():162            view.SetLineColor(lineNo, color)163 164 165# 	def StreamTextOut(self, data): ### This seems unreliable???166# 		self.saveFileHandle.write(data)167# 		return 1 # keep em coming!168 169# ParentEditorView=docview.EditView170ParentEditorView = docview.RichEditView171 172 173class EditorView(ParentEditorView):174    def __init__(self, doc):175        ParentEditorView.__init__(self, doc)176        if isRichText:177            self.SetWordWrap(win32ui.CRichEditView_WrapNone)178 179        self.addToMRU = 1180        self.HookHandlers()181        self.bCheckingFile = 0182 183        self.defCharFormat = GetEditorFontOption("Default Font", defaultCharacterFormat)184 185        # Smart tabs override everything else if context can be worked out.186        self.bSmartTabs = GetEditorOption("Smart Tabs", 1)187 188        self.tabSize = GetEditorOption("Tab Size", 8)189        self.indentSize = GetEditorOption("Indent Size", 8)190        # If next indent is at a tab position, and useTabs is set, a tab will be inserted.191        self.bUseTabs = GetEditorOption("Use Tabs", 1)192 193    def OnInitialUpdate(self):194        rc = self._obj_.OnInitialUpdate()195        self.SetDefaultCharFormat(self.defCharFormat)196        return rc197 198    def CutCurLine(self):199        curLine = self._obj_.LineFromChar()200        nextLine = curLine + 1201        start = self._obj_.LineIndex(curLine)202        end = self._obj_.LineIndex(nextLine)203        if end == 0:  # must be last line.204            end = start + self.end.GetLineLength(curLine)205        self._obj_.SetSel(start, end)206        self._obj_.Cut()207 208    def _PrepareUserStateChange(self):209        "Return selection, lineindex, etc info, so it can be restored"210        self.SetRedraw(0)211        return self.GetModify(), self.GetSel(), self.GetFirstVisibleLine()212 213    def _EndUserStateChange(self, info):214        scrollOff = info[2] - self.GetFirstVisibleLine()215        if scrollOff:216            self.LineScroll(scrollOff)217        self.SetSel(info[1])218        self.SetModify(info[0])219        self.SetRedraw(1)220        self.InvalidateRect()221        self.UpdateWindow()222 223    def _UpdateUIForState(self):224        self.SetReadOnly(self.GetDocument()._IsReadOnly())225 226    def SetAllLineColors(self, color=None):227        if isRichText:228            info = self._PrepareUserStateChange()229            try:230                if color is None:231                    color = self.defCharFormat[4]232                self.SetSel(0, -1)233                self.SetSelectionCharFormat((win32con.CFM_COLOR, 0, 0, 0, color))234            finally:235                self._EndUserStateChange(info)236 237    def SetLineColor(self, lineNo, color):238        "lineNo is the 1 based line number to set.  If color is None, default color is used."239        if isRichText:240            info = self._PrepareUserStateChange()241            try:242                if color is None:243                    color = self.defCharFormat[4]244                lineNo = lineNo - 1245                startIndex = self.LineIndex(lineNo)246                if startIndex != -1:247                    self.SetSel(startIndex, self.LineIndex(lineNo + 1))248                    self.SetSelectionCharFormat((win32con.CFM_COLOR, 0, 0, 0, color))249            finally:250                self._EndUserStateChange(info)251 252    def Indent(self):253        """Insert an indent to move the cursor to the next tab position.254 255        Honors the tab size and 'use tabs' settings.  Assumes the cursor is already at the256        position to be indented, and the selection is a single character (ie, not a block)257        """258        start, end = self._obj_.GetSel()259        startLine = self._obj_.LineFromChar(start)260        line = self._obj_.GetLine(startLine)261        realCol = start - self._obj_.LineIndex(startLine)262        # Calulate the next tab stop.263        # Expand existing tabs.264        curCol = 0265        for ch in line[:realCol]:266            if ch == "\t":267                curCol = ((curCol / self.tabSize) + 1) * self.tabSize268            else:269                curCol = curCol + 1270        nextColumn = ((curCol / self.indentSize) + 1) * self.indentSize271        # 		print "curCol is", curCol, "nextColumn is", nextColumn272        ins = None273        if self.bSmartTabs:274            # Look for some context.275            if realCol == 0:  # Start of the line - see if the line above can tell us276                lookLine = startLine - 1277                while lookLine >= 0:278                    check = self._obj_.GetLine(lookLine)[0:1]279                    if check in ("\t", " "):280                        ins = check281                        break282                    lookLine = lookLine - 1283            else:  # See if the previous char can tell us284                check = line[realCol - 1]285                if check in ("\t", " "):286                    ins = check287 288        # Either smart tabs off, or not smart enough!289        # Use the "old style" settings.290        if ins is None:291            if self.bUseTabs and nextColumn % self.tabSize == 0:292                ins = "\t"293            else:294                ins = " "295 296        if ins == " ":297            # Calc the number of spaces to take us to the next stop298            ins = ins * (nextColumn - curCol)299 300        self._obj_.ReplaceSel(ins)301 302    def BlockDent(self, isIndent, startLine, endLine):303        "Indent/Undent all lines specified"304        if not self.GetDocument().CheckMakeDocumentWritable():305            return 0306        tabSize = self.tabSize  # hard-code for now!307        info = self._PrepareUserStateChange()308        try:309            for lineNo in range(startLine, endLine):310                pos = self._obj_.LineIndex(lineNo)311                self._obj_.SetSel(pos, pos)312                if isIndent:313                    self.Indent()314                else:315                    line = self._obj_.GetLine(lineNo)316                    try:317                        noToDel = 0318                        if line[0] == "\t":319                            noToDel = 1320                        elif line[0] == " ":321                            for noToDel in range(0, tabSize):322                                if line[noToDel] != " ":323                                    break324                            else:325                                noToDel = tabSize326                        if noToDel:327                            self._obj_.SetSel(pos, pos + noToDel)328                            self._obj_.Clear()329                    except IndexError:330                        pass331        finally:332            self._EndUserStateChange(info)333        self.GetDocument().SetModifiedFlag(1)  # Now dirty334        self._obj_.SetSel(self.LineIndex(startLine), self.LineIndex(endLine))335 336    def GotoLine(self, lineNo=None):337        try:338            if lineNo is None:339                lineNo = int(input("Enter Line Number"))340        except (ValueError, KeyboardInterrupt):341            return 0342        self.GetLineCount()  # Seems to be needed when file first opened???343        charNo = self.LineIndex(lineNo - 1)344        self.SetSel(charNo)345 346    def HookHandlers(self):  # children can override, but should still call me!347        # 		self.HookAllKeyStrokes(self.OnKey)348        self.HookMessage(self.OnCheckExternalDocumentUpdated, MSG_CHECK_EXTERNAL_FILE)349        self.HookMessage(self.OnRClick, win32con.WM_RBUTTONDOWN)350        self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)351        self.HookMessage(self.OnKeyDown, win32con.WM_KEYDOWN)352        self.HookKeyStroke(self.OnKeyCtrlY, 25)  # ^Y353        self.HookKeyStroke(self.OnKeyCtrlG, 7)  # ^G354        self.HookKeyStroke(self.OnKeyTab, 9)  # TAB355        self.HookKeyStroke(self.OnKeyEnter, 13)  # Enter356        self.HookCommand(self.OnCmdLocateFile, ID_LOCATE_FILE)357        self.HookCommand(self.OnCmdGotoLine, ID_GOTO_LINE)358        self.HookCommand(self.OnEditPaste, afxres.ID_EDIT_PASTE)359        self.HookCommand(self.OnEditCut, afxres.ID_EDIT_CUT)360 361    # Hook Handlers362    def OnSetFocus(self, msg):363        # Even though we use file change notifications, we should be very sure about it here.364        self.OnCheckExternalDocumentUpdated(msg)365 366    def OnRClick(self, params):367        menu = win32ui.CreatePopupMenu()368 369        # look for a module name370        line = self._obj_.GetLine().strip()371        flags = win32con.MF_STRING | win32con.MF_ENABLED372        if patImport.match(line) == len(line):373            menu.AppendMenu(374                flags, ID_LOCATE_FILE, "&Locate %s.py" % patImport.group("name")375            )376            menu.AppendMenu(win32con.MF_SEPARATOR)377        menu.AppendMenu(flags, win32ui.ID_EDIT_UNDO, "&Undo")378        menu.AppendMenu(win32con.MF_SEPARATOR)379        menu.AppendMenu(flags, win32ui.ID_EDIT_CUT, "Cu&t")380        menu.AppendMenu(flags, win32ui.ID_EDIT_COPY, "&Copy")381        menu.AppendMenu(flags, win32ui.ID_EDIT_PASTE, "&Paste")382        menu.AppendMenu(flags, win32con.MF_SEPARATOR)383        menu.AppendMenu(flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all")384        menu.AppendMenu(flags, win32con.MF_SEPARATOR)385        menu.AppendMenu(flags, ID_GOTO_LINE, "&Goto line...")386        menu.TrackPopupMenu(params[5])387        return 0388 389    def OnCmdGotoLine(self, cmd, code):390        self.GotoLine()391        return 0392 393    def OnCmdLocateFile(self, cmd, code):394        modName = patImport.group("name")395        if not modName:396            return 0397        import pywin.framework.scriptutils398 399        fileName = pywin.framework.scriptutils.LocatePythonFile(modName)400        if fileName is None:401            win32ui.SetStatusText("Can't locate module %s" % modName)402        else:403            win32ui.GetApp().OpenDocumentFile(fileName)404        return 0405 406    # Key handlers407    def OnKeyEnter(self, key):408        if not self.GetDocument().CheckMakeDocumentWritable():409            return 0410        curLine = self._obj_.GetLine()411        self._obj_.ReplaceSel("\r\n")  # insert the newline412        # If the current line indicates the next should be indented,413        # then copy the current indentation to this line.414        res = patIndent.match(curLine, 0)415        if res > 0 and curLine.strip():416            curIndent = patIndent.group(1)417            self._obj_.ReplaceSel(curIndent)418        return 0  # dont pass on419 420    def OnKeyCtrlY(self, key):421        if not self.GetDocument().CheckMakeDocumentWritable():422            return 0423        self.CutCurLine()424        return 0  # dont let him have it!425 426    def OnKeyCtrlG(self, key):427        self.GotoLine()428        return 0  # dont let him have it!429 430    def OnKeyTab(self, key):431        if not self.GetDocument().CheckMakeDocumentWritable():432            return 0433        start, end = self._obj_.GetSel()434        if start == end:  # normal TAB key435            self.Indent()436            return 0  # we handled this.437 438        # Otherwise it is a block indent/dedent.439        if start > end:440            start, end = end, start  # swap them.441        startLine = self._obj_.LineFromChar(start)442        endLine = self._obj_.LineFromChar(end)443 444        self.BlockDent(win32api.GetKeyState(win32con.VK_SHIFT) >= 0, startLine, endLine)445        return 0446 447    def OnEditPaste(self, id, code):448        # Return 1 if we can make the file editable.(or it already is!)449        return self.GetDocument().CheckMakeDocumentWritable()450 451    def OnEditCut(self, id, code):452        # Return 1 if we can make the file editable.(or it already is!)453        return self.GetDocument().CheckMakeDocumentWritable()454 455    def OnKeyDown(self, msg):456        key = msg[2]457        if win32api.GetKeyState(win32con.VK_CONTROL) & 0x8000:458            modList = MODIFYING_VK_KEYS_CTRL459        elif win32api.GetKeyState(win32con.VK_MENU) & 0x8000:460            modList = MODIFYING_VK_KEYS_ALT461        else:462            modList = MODIFYING_VK_KEYS463 464        if key in modList:465            # Return 1 if we can make the file editable.(or it already is!)466            return self.GetDocument().CheckMakeDocumentWritable()467        return 1  # Pass it on OK468 469    # 	def OnKey(self, key):470    # 		return self.GetDocument().CheckMakeDocumentWritable()471 472    def OnCheckExternalDocumentUpdated(self, msg):473        if self._obj_ is None or self.bCheckingFile:474            return475        self.bCheckingFile = 1476        self.GetDocument().CheckExternalDocumentUpdated()477        self.bCheckingFile = 0478 479 480from .template import EditorTemplateBase481 482 483class EditorTemplate(EditorTemplateBase):484    def __init__(485        self, res=win32ui.IDR_TEXTTYPE, makeDoc=None, makeFrame=None, makeView=None486    ):487        if makeDoc is None:488            makeDoc = EditorDocument489        if makeView is None:490            makeView = EditorView491        EditorTemplateBase.__init__(self, res, makeDoc, makeFrame, makeView)492 493    def _CreateDocTemplate(self, resourceId):494        return win32ui.CreateRichEditDocTemplate(resourceId)495 496    def CreateWin32uiDocument(self):497        return self.DoCreateRichEditDoc()498 499 500def Create(fileName=None, title=None, template=None):501    return editorTemplate.OpenDocumentFile(fileName)502 503 504from pywin.framework.editor import GetDefaultEditorModuleName505 506prefModule = GetDefaultEditorModuleName()507# Initialize only if this is the "default" editor.508if __name__ == prefModule:509    # For debugging purposes, when this module may be reloaded many times.510    try:511        win32ui.GetApp().RemoveDocTemplate(editorTemplate)512    except (NameError, win32ui.error):513        pass514 515    editorTemplate = EditorTemplate()516    win32ui.GetApp().AddDocTemplate(editorTemplate)517 
codekingpro/portable-devtools · Team Ai