Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
interact.py986 linesDownload Raw Back to framework
1##################################################################2##3## Interactive Shell Window4##5 6import array7import code8import os9import string10import sys11import traceback12 13import __main__14import afxres15import pywin.framework.app16import pywin.scintilla.control17import pywin.scintilla.formatter18import pywin.scintilla.IDLEenvironment19import win32api20import win32clipboard21import win32con22import win32ui23 24## sequential after ID_GOTO_LINE defined in editor.py25ID_EDIT_COPY_CODE = 0xE200226ID_EDIT_EXEC_CLIPBOARD = 0x200327 28trace = pywin.scintilla.formatter.trace29 30import re31 32from . import winout33 34# from IDLE.35_is_block_opener = re.compile(r":\s*(#.*)?$").search36_is_block_closer = re.compile(37    r"""38    \s*39    ( return40    | break41    | continue42    | raise43    | pass44    )45    \b46""",47    re.VERBOSE,48).match49 50tracebackHeader = "Traceback (".encode("ascii")51 52sectionProfile = "Interactive Window"53valueFormatTitle = "FormatTitle"54valueFormatInput = "FormatInput"55valueFormatOutput = "FormatOutput"56valueFormatOutputError = "FormatOutputError"57 58# These are defaults only.  Values are read from the registry.59formatTitle = (-536870897, 0, 220, 0, 16711680, 184, 34, "Arial")60formatInput = (-402653169, 0, 200, 0, 0, 0, 49, "Courier New")61formatOutput = (-402653169, 0, 200, 0, 8421376, 0, 49, "Courier New")62formatOutputError = (-402653169, 0, 200, 0, 255, 0, 49, "Courier New")63 64try:65    sys.ps166except AttributeError:67    sys.ps1 = ">>> "68    sys.ps2 = "... "69 70 71def LoadPreference(preference, default=""):72    return win32ui.GetProfileVal(sectionProfile, preference, default)73 74 75def SavePreference(prefName, prefValue):76    win32ui.WriteProfileVal(sectionProfile, prefName, prefValue)77 78 79def GetPromptPrefix(line):80    ps1 = sys.ps181    if line[: len(ps1)] == ps1:82        return ps183    ps2 = sys.ps284    if line[: len(ps2)] == ps2:85        return ps286 87 88#############################################################89#90# Colorizer related code.91#92#############################################################93STYLE_INTERACTIVE_EOL = "Interactive EOL"94STYLE_INTERACTIVE_OUTPUT = "Interactive Output"95STYLE_INTERACTIVE_PROMPT = "Interactive Prompt"96STYLE_INTERACTIVE_BANNER = "Interactive Banner"97STYLE_INTERACTIVE_ERROR = "Interactive Error"98STYLE_INTERACTIVE_ERROR_FINALLINE = "Interactive Error (final line)"99 100INTERACTIVE_STYLES = [101    STYLE_INTERACTIVE_EOL,102    STYLE_INTERACTIVE_OUTPUT,103    STYLE_INTERACTIVE_PROMPT,104    STYLE_INTERACTIVE_BANNER,105    STYLE_INTERACTIVE_ERROR,106    STYLE_INTERACTIVE_ERROR_FINALLINE,107]108 109FormatterParent = pywin.scintilla.formatter.PythonSourceFormatter110 111 112class InteractiveFormatter(FormatterParent):113    def __init__(self, scintilla):114        FormatterParent.__init__(self, scintilla)115        self.bannerDisplayed = False116 117    def SetStyles(self):118        FormatterParent.SetStyles(self)119        Style = pywin.scintilla.formatter.Style120        self.RegisterStyle(Style(STYLE_INTERACTIVE_EOL, STYLE_INTERACTIVE_PROMPT))121        self.RegisterStyle(Style(STYLE_INTERACTIVE_PROMPT, formatInput))122        self.RegisterStyle(Style(STYLE_INTERACTIVE_OUTPUT, formatOutput))123        self.RegisterStyle(Style(STYLE_INTERACTIVE_BANNER, formatTitle))124        self.RegisterStyle(Style(STYLE_INTERACTIVE_ERROR, formatOutputError))125        self.RegisterStyle(126            Style(STYLE_INTERACTIVE_ERROR_FINALLINE, STYLE_INTERACTIVE_ERROR)127        )128 129    def LoadPreference(self, name, default):130        rc = win32ui.GetProfileVal("Format", name, default)131        if rc == default:132            rc = win32ui.GetProfileVal(sectionProfile, name, default)133        return rc134 135    def ColorizeInteractiveCode(self, cdoc, styleStart, stylePyStart):136        lengthDoc = len(cdoc)137        if lengthDoc == 0:138            return139        state = styleStart140        # As per comments in Colorize(), we work with the raw utf8141        # bytes. To avoid too muych py3k pain, we treat each utf8 byte142        # as a latin-1 unicode character - we only use it to compare143        # against ascii chars anyway...144        chNext = cdoc[0:1].decode("latin-1")145        startSeg = 0146        i = 0147        lastState = state  # debug only148        while i < lengthDoc:149            ch = chNext150            chNext = cdoc[i + 1 : i + 2].decode("latin-1")151 152            # 			trace("ch=%r, i=%d, next=%r, state=%s" % (ch, i, chNext, state))153            if state == STYLE_INTERACTIVE_EOL:154                if ch not in "\r\n":155                    self.ColorSeg(startSeg, i - 1, state)156                    startSeg = i157                    if ch in (sys.ps1[0], sys.ps2[0]):158                        state = STYLE_INTERACTIVE_PROMPT159                    elif cdoc[i : i + len(tracebackHeader)] == tracebackHeader:160                        state = STYLE_INTERACTIVE_ERROR161                    else:162                        state = STYLE_INTERACTIVE_OUTPUT163            elif state == STYLE_INTERACTIVE_PROMPT:164                if ch not in sys.ps1 + sys.ps2 + " ":165                    self.ColorSeg(startSeg, i - 1, state)166                    startSeg = i167                    if ch in "\r\n":168                        state = STYLE_INTERACTIVE_EOL169                    else:170                        state = stylePyStart  # Start coloring Python code.171            elif state in (STYLE_INTERACTIVE_OUTPUT,):172                if ch in "\r\n":173                    self.ColorSeg(startSeg, i - 1, state)174                    startSeg = i175                    state = STYLE_INTERACTIVE_EOL176            elif state == STYLE_INTERACTIVE_ERROR:177                if ch in "\r\n" and chNext and chNext not in string.whitespace:178                    # Everything including me179                    self.ColorSeg(startSeg, i, state)180                    startSeg = i + 1181                    state = STYLE_INTERACTIVE_ERROR_FINALLINE182                elif i == 0 and ch not in string.whitespace:183                    # If we are coloring from the start of a line,184                    # we need this better check for the last line185                    # Color up to not including me186                    self.ColorSeg(startSeg, i - 1, state)187                    startSeg = i188                    state = STYLE_INTERACTIVE_ERROR_FINALLINE189            elif state == STYLE_INTERACTIVE_ERROR_FINALLINE:190                if ch in "\r\n":191                    self.ColorSeg(startSeg, i - 1, state)192                    startSeg = i193                    state = STYLE_INTERACTIVE_EOL194            elif state == STYLE_INTERACTIVE_BANNER:195                if ch in "\r\n" and (chNext == "" or chNext in ">["):196                    # Everything including me197                    self.ColorSeg(startSeg, i - 1, state)198                    startSeg = i199                    state = STYLE_INTERACTIVE_EOL200            else:201                # It is a PythonColorizer state - seek past the end of the line202                # and ask the Python colorizer to color that.203                end = startSeg204                while end < lengthDoc and cdoc[end] not in "\r\n".encode("ascii"):205                    end = end + 1206                self.ColorizePythonCode(cdoc[:end], startSeg, state)207                stylePyStart = self.GetStringStyle(end - 1)208                if stylePyStart is None:209                    stylePyStart = pywin.scintilla.formatter.STYLE_DEFAULT210                else:211                    stylePyStart = stylePyStart.name212                startSeg = end213                i = end - 1  # ready for increment.214                chNext = cdoc[end : end + 1].decode("latin-1")215                state = STYLE_INTERACTIVE_EOL216            if lastState != state:217                lastState = state218            i = i + 1219        # and the rest220        if startSeg < i:221            self.ColorSeg(startSeg, i - 1, state)222 223    def Colorize(self, start=0, end=-1):224        # scintilla's formatting is all done in terms of utf, so225        # we work with utf8 bytes instead of unicode.  This magically226        # works as any extended chars found in the utf8 don't change227        # the semantics.228        stringVal = self.scintilla.GetTextRange(start, end, decode=False)229        styleStart = None230        stylePyStart = None231        if start > 1:232            # Likely we are being asked to color from the start of the line.233            # We find the last formatted character on the previous line.234            # If TQString, we continue it.  Otherwise, we reset.235            look = start - 1236            while look and self.scintilla.SCIGetCharAt(look) in "\n\r":237                look = look - 1238            if look and look < start - 1:  # Did we find a char before the \n\r sets?239                strstyle = self.GetStringStyle(look)240                quote_char = None241                if strstyle is not None:242                    if strstyle.name == pywin.scintilla.formatter.STYLE_TQSSTRING:243                        quote_char = "'"244                    elif strstyle.name == pywin.scintilla.formatter.STYLE_TQDSTRING:245                        quote_char = '"'246                    if quote_char is not None:247                        # It is a TQS.  If the TQS is not terminated, we248                        # carry the style through.249                        if look > 2:250                            look_str = (251                                self.scintilla.SCIGetCharAt(look - 2)252                                + self.scintilla.SCIGetCharAt(look - 1)253                                + self.scintilla.SCIGetCharAt(look)254                            )255                            if look_str != quote_char * 3:256                                stylePyStart = strstyle.name257        if stylePyStart is None:258            stylePyStart = pywin.scintilla.formatter.STYLE_DEFAULT259 260        if start > 0:261            stylenum = self.scintilla.SCIGetStyleAt(start - 1)262            styleStart = self.GetStyleByNum(stylenum).name263        elif self.bannerDisplayed:264            styleStart = STYLE_INTERACTIVE_EOL265        else:266            styleStart = STYLE_INTERACTIVE_BANNER267            self.bannerDisplayed = True268        self.scintilla.SCIStartStyling(start, 31)269        self.style_buffer = array.array("b", (0,) * len(stringVal))270        self.ColorizeInteractiveCode(stringVal, styleStart, stylePyStart)271        self.scintilla.SCISetStylingEx(self.style_buffer)272        self.style_buffer = None273 274 275###############################################################276#277# This class handles the Python interactive interpreter.278#279# It uses a basic EditWindow, and does all the magic.280# This is triggered by the enter key hander attached by the281# start-up code.  It determines if a command is to be executed282# or continued (ie, emit "... ") by snooping around the current283# line, looking for the prompts284#285class PythonwinInteractiveInterpreter(code.InteractiveInterpreter):286    def __init__(self, locals=None, globals=None):287        if locals is None:288            locals = __main__.__dict__289        if globals is None:290            globals = locals291        self.globals = globals292        code.InteractiveInterpreter.__init__(self, locals)293 294    def showsyntaxerror(self, filename=None):295        sys.stderr.write(296            tracebackHeader.decode("ascii")297        )  # So the color syntaxer recognises it.298        code.InteractiveInterpreter.showsyntaxerror(self, filename)299 300    def runcode(self, code):301        try:302            exec(code, self.globals, self.locals)303        except SystemExit:304            raise305        except:306            self.showtraceback()307 308 309class InteractiveCore:310    def __init__(self, banner=None):311        self.banner = banner312 313    # 		LoadFontPreferences()314    def Init(self):315        self.oldStdOut = self.oldStdErr = None316 317        # 		self.SetWordWrap(win32ui.CRichEditView_WrapNone)318        self.interp = PythonwinInteractiveInterpreter()319 320        self.OutputGrab()  # Release at cleanup.321 322        if self.GetTextLength() == 0:323            if self.banner is None:324                suffix = ""325                if win32ui.debug:326                    suffix = ", debug build"327                sys.stderr.write(328                    "PythonWin %s on %s%s.\n" % (sys.version, sys.platform, suffix)329                )330                sys.stderr.write(331                    "Portions %s - see 'Help/About PythonWin' for further copyright information.\n"332                    % (win32ui.copyright,)333                )334            else:335                sys.stderr.write(banner)336        rcfile = os.environ.get("PYTHONSTARTUP")337        if rcfile:338            import __main__339 340            try:341                exec(342                    compile(343                        open(rcfile, "rb").read(), rcfile, "exec", dont_inherit=True344                    ),345                    __main__.__dict__,346                    __main__.__dict__,347                )348            except:349                sys.stderr.write(350                    ">>> \nError executing PYTHONSTARTUP script %r\n" % (rcfile)351                )352                traceback.print_exc(file=sys.stderr)353        self.AppendToPrompt([])354 355    def SetContext(self, globals, locals, name="Dbg"):356        oldPrompt = sys.ps1357        if globals is None:358            # Reset359            sys.ps1 = ">>> "360            sys.ps2 = "... "361            locals = globals = __main__.__dict__362        else:363            sys.ps1 = "[%s]>>> " % name364            sys.ps2 = "[%s]... " % name365        self.interp.locals = locals366        self.interp.globals = globals367        self.AppendToPrompt([], oldPrompt)368 369    def GetContext(self):370        return self.interp.globals, self.interp.locals371 372    def DoGetLine(self, line=-1):373        if line == -1:374            line = self.LineFromChar()375        line = self.GetLine(line)376        while line and line[-1] in ("\r", "\n"):377            line = line[:-1]378        return line379 380    def AppendToPrompt(self, bufLines, oldPrompt=None):381        "Take a command and stick it at the end of the buffer (with python prompts inserted if required)."382        self.flush()383        lastLineNo = self.GetLineCount() - 1384        line = self.DoGetLine(lastLineNo)385        if oldPrompt and line == oldPrompt:386            self.SetSel(self.GetTextLength() - len(oldPrompt), self.GetTextLength())387            self.ReplaceSel(sys.ps1)388        elif line != str(sys.ps1):389            if len(line) != 0:390                self.write("\n")391            self.write(sys.ps1)392        self.flush()393        self.idle.text.mark_set("iomark", "end-1c")394        if not bufLines:395            return396        terms = (["\n" + sys.ps2] * (len(bufLines) - 1)) + [""]397        for bufLine, term in zip(bufLines, terms):398            if bufLine.strip():399                self.write(bufLine + term)400        self.flush()401 402    def EnsureNoPrompt(self):403        # Get ready to write some text NOT at a Python prompt.404        self.flush()405        lastLineNo = self.GetLineCount() - 1406        line = self.DoGetLine(lastLineNo)407        if not line or line in (sys.ps1, sys.ps2):408            self.SetSel(self.GetTextLength() - len(line), self.GetTextLength())409            self.ReplaceSel("")410        else:411            # Just add a new line.412            self.write("\n")413 414    def _GetSubConfigNames(self):415        return ["interactive"]  # Allow [Keys:Interactive] sections to be specific416 417    def HookHandlers(self):418        # Hook menu command (executed when a menu item with that ID is selected from a menu/toolbar419        self.HookCommand(self.OnSelectBlock, win32ui.ID_EDIT_SELECT_BLOCK)420        self.HookCommand(self.OnEditCopyCode, ID_EDIT_COPY_CODE)421        self.HookCommand(self.OnEditExecClipboard, ID_EDIT_EXEC_CLIPBOARD)422        mod = pywin.scintilla.IDLEenvironment.GetIDLEModule("IdleHistory")423        if mod is not None:424            self.history = mod.History(self.idle.text, "\n" + sys.ps2)425        else:426            self.history = None427        # hack for now for event handling.428 429    # GetBlockBoundary takes a line number, and will return the430    # start and and line numbers of the block, and a flag indicating if the431    # block is a Python code block.432    # If the line specified has a Python prompt, then the lines are parsed433    # backwards and forwards, and the flag is true.434    # If the line does not start with a prompt, the block is searched forward435    # and backward until a prompt _is_ found, and all lines in between without436    # prompts are returned, and the flag is false.437    def GetBlockBoundary(self, lineNo):438        line = self.DoGetLine(lineNo)439        maxLineNo = self.GetLineCount() - 1440        prefix = GetPromptPrefix(line)441        if prefix is None:  # Non code block442            flag = 0443            startLineNo = lineNo444            while startLineNo > 0:445                if GetPromptPrefix(self.DoGetLine(startLineNo - 1)) is not None:446                    break  # there _is_ a prompt447                startLineNo = startLineNo - 1448            endLineNo = lineNo449            while endLineNo < maxLineNo:450                if GetPromptPrefix(self.DoGetLine(endLineNo + 1)) is not None:451                    break  # there _is_ a prompt452                endLineNo = endLineNo + 1453        else:  # Code block454            flag = 1455            startLineNo = lineNo456            while startLineNo > 0 and prefix != str(sys.ps1):457                prefix = GetPromptPrefix(self.DoGetLine(startLineNo - 1))458                if prefix is None:459                    break460                    # there is no prompt.461                startLineNo = startLineNo - 1462            endLineNo = lineNo463            while endLineNo < maxLineNo:464                prefix = GetPromptPrefix(self.DoGetLine(endLineNo + 1))465                if prefix is None:466                    break  # there is no prompt467                if prefix == str(sys.ps1):468                    break  # this is another command469                endLineNo = endLineNo + 1470                # continue until end of buffer, or no prompt471        return (startLineNo, endLineNo, flag)472 473    def ExtractCommand(self, lines):474        start, end = lines475        retList = []476        while end >= start:477            thisLine = self.DoGetLine(end)478            promptLen = len(GetPromptPrefix(thisLine))479            retList = [thisLine[promptLen:]] + retList480            end = end - 1481        return retList482 483    def OutputGrab(self):484        # 		import win32traceutil; return485        self.oldStdOut = sys.stdout486        self.oldStdErr = sys.stderr487        sys.stdout = self488        sys.stderr = self489        self.flush()490 491    def OutputRelease(self):492        # a command may have overwritten these - only restore if not.493        if self.oldStdOut is not None:494            if sys.stdout == self:495                sys.stdout = self.oldStdOut496        if self.oldStdErr is not None:497            if sys.stderr == self:498                sys.stderr = self.oldStdErr499        self.oldStdOut = None500        self.oldStdErr = None501        self.flush()502 503    ###################################504    #505    # Message/Command/Key Hooks.506    #507    # Enter key handler508    #509    def ProcessEnterEvent(self, event):510        # If autocompletion has been triggered, complete and do not process event511        if self.SCIAutoCActive():512            self.SCIAutoCComplete()513            self.SCICancel()514            return515 516        self.SCICancel()517        # First, check for an error message518        haveGrabbedOutput = 0519        if self.HandleSpecialLine():520            return 0521 522        lineNo = self.LineFromChar()523        start, end, isCode = self.GetBlockBoundary(lineNo)524        # If we are not in a code block just go to the prompt (or create a new one)525        if not isCode:526            self.AppendToPrompt([])527            win32ui.SetStatusText(win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE))528            return529 530        lines = self.ExtractCommand((start, end))531 532        # If we are in a code-block, but it isnt at the end of the buffer533        # then copy it to the end ready for editing and subsequent execution534        if end != self.GetLineCount() - 1:535            win32ui.SetStatusText("Press ENTER to execute command")536            self.AppendToPrompt(lines)537            self.SetSel(-2)538            return539 540        # If SHIFT held down, we want new code here and now!541        bNeedIndent = (542            win32api.GetKeyState(win32con.VK_SHIFT) < 0543            or win32api.GetKeyState(win32con.VK_CONTROL) < 0544        )545        if bNeedIndent:546            self.ReplaceSel("\n")547        else:548            self.SetSel(-2)549            self.ReplaceSel("\n")550            source = "\n".join(lines)551            while source and source[-1] in "\t ":552                source = source[:-1]553            self.OutputGrab()  # grab the output for the command exec.554            try:555                if self.interp.runsource(556                    source, "<interactive input>"557                ):  # Need more input!558                    bNeedIndent = 1559                else:560                    # If the last line isnt empty, append a newline561                    if self.history is not None:562                        self.history.history_store(source)563                    self.AppendToPrompt([])564                    win32ui.SetStatusText(565                        win32ui.LoadString(afxres.AFX_IDS_IDLEMESSAGE)566                    )567            # 					win32ui.SetStatusText('Successfully executed statement')568            finally:569                self.OutputRelease()570        if bNeedIndent:571            win32ui.SetStatusText("Ready to continue the command")572            # Now attempt correct indentation (should use IDLE?)573            curLine = self.DoGetLine(lineNo)[len(sys.ps2) :]574            pos = 0575            indent = ""576            while len(curLine) > pos and curLine[pos] in string.whitespace:577                indent = indent + curLine[pos]578                pos = pos + 1579            if _is_block_opener(curLine):580                indent = indent + "\t"581            elif _is_block_closer(curLine):582                indent = indent[:-1]583            # use ReplaceSel to ensure it goes at the cursor rather than end of buffer.584            self.ReplaceSel(sys.ps2 + indent)585        return 0586 587    # ESC key handler588    def ProcessEscEvent(self, event):589        # Implement a cancel.590        if self.SCIAutoCActive() or self.SCICallTipActive():591            self.SCICancel()592        else:593            win32ui.SetStatusText("Cancelled.")594            self.AppendToPrompt(("",))595        return 0596 597    def OnSelectBlock(self, command, code):598        lineNo = self.LineFromChar()599        start, end, isCode = self.GetBlockBoundary(lineNo)600        startIndex = self.LineIndex(start)601        endIndex = self.LineIndex(end + 1) - 2  # skip \r + \n602        if endIndex < 0:  # must be beyond end of buffer603            endIndex = -2  # self.Length()604        self.SetSel(startIndex, endIndex)605 606    def OnEditCopyCode(self, command, code):607        """Sanitizes code from interactive window, removing prompts and output,608        and inserts it in the clipboard."""609        code = self.GetSelText()610        lines = code.splitlines()611        out_lines = []612        for line in lines:613            if line.startswith(sys.ps1):614                line = line[len(sys.ps1) :]615                out_lines.append(line)616            elif line.startswith(sys.ps2):617                line = line[len(sys.ps2) :]618                out_lines.append(line)619        out_code = os.linesep.join(out_lines)620        win32clipboard.OpenClipboard()621        try:622            win32clipboard.SetClipboardData(623                win32clipboard.CF_UNICODETEXT, str(out_code)624            )625        finally:626            win32clipboard.CloseClipboard()627 628    def OnEditExecClipboard(self, command, code):629        """Executes python code directly from the clipboard."""630        win32clipboard.OpenClipboard()631        try:632            code = win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)633        finally:634            win32clipboard.CloseClipboard()635 636        code = code.replace("\r\n", "\n") + "\n"637        try:638            o = compile(code, "<clipboard>", "exec")639            exec(o, __main__.__dict__)640        except:641            traceback.print_exc()642 643    def GetRightMenuItems(self):644        # Just override parents645        ret = []646        flags = 0647        ret.append((flags, win32ui.ID_EDIT_UNDO, "&Undo"))648        ret.append(win32con.MF_SEPARATOR)649        ret.append((flags, win32ui.ID_EDIT_CUT, "Cu&t"))650        ret.append((flags, win32ui.ID_EDIT_COPY, "&Copy"))651 652        start, end = self.GetSel()653        if start != end:654            ret.append((flags, ID_EDIT_COPY_CODE, "Copy code without prompts"))655        if win32clipboard.IsClipboardFormatAvailable(win32clipboard.CF_UNICODETEXT):656            ret.append(657                (flags, ID_EDIT_EXEC_CLIPBOARD, "Execute python code from clipboard")658            )659 660        ret.append((flags, win32ui.ID_EDIT_PASTE, "&Paste"))661        ret.append(win32con.MF_SEPARATOR)662        ret.append((flags, win32ui.ID_EDIT_SELECT_ALL, "&Select all"))663        ret.append((flags, win32ui.ID_EDIT_SELECT_BLOCK, "Select &block"))664        ret.append((flags, win32ui.ID_VIEW_WHITESPACE, "View &Whitespace"))665        return ret666 667    def MDINextEvent(self, event):668        win32ui.GetMainFrame().MDINext(0)669 670    def MDIPrevEvent(self, event):671        win32ui.GetMainFrame().MDINext(0)672 673    def WindowBackEvent(self, event):674        parent = self.GetParentFrame()675        if parent == win32ui.GetMainFrame():676            # It is docked.677            try:678                wnd, isactive = parent.MDIGetActive()679                wnd.SetFocus()680            except win32ui.error:681                # No MDI window active!682                pass683        else:684            # Normal Window685            try:686                lastActive = self.GetParentFrame().lastActive687                # If the window is invalid, reset it.688                if lastActive is not None and (689                    lastActive._obj_ is None or lastActive.GetSafeHwnd() == 0690                ):691                    lastActive = self.GetParentFrame().lastActive = None692                    win32ui.SetStatusText("The last active Window has been closed.")693            except AttributeError:694                print("Can't find the last active window!")695                lastActive = None696            if lastActive is not None:697                lastActive.MDIActivate()698 699 700class InteractiveView(InteractiveCore, winout.WindowOutputView):701    def __init__(self, doc):702        InteractiveCore.__init__(self)703        winout.WindowOutputView.__init__(self, doc)704        self.encoding = pywin.default_scintilla_encoding705 706    def _MakeColorizer(self):707        return InteractiveFormatter(self)708 709    def OnInitialUpdate(self):710        winout.WindowOutputView.OnInitialUpdate(self)711        self.SetWordWrap()712        self.Init()713 714    def HookHandlers(self):715        winout.WindowOutputView.HookHandlers(self)716        InteractiveCore.HookHandlers(self)717 718 719class CInteractivePython(winout.WindowOutput):720    def __init__(self, makeDoc=None, makeFrame=None):721        self.IsFinalDestroy = 0722        winout.WindowOutput.__init__(723            self,724            sectionProfile,725            sectionProfile,726            winout.flags.WQ_LINE,727            1,728            None,729            makeDoc,730            makeFrame,731            InteractiveView,732        )733        self.Create()734 735    def OnViewDestroy(self, view):736        if self.IsFinalDestroy:737            view.OutputRelease()738        winout.WindowOutput.OnViewDestroy(self, view)739 740    def Close(self):741        self.IsFinalDestroy = 1742        winout.WindowOutput.Close(self)743 744 745class InteractiveFrame(winout.WindowOutputFrame):746    def __init__(self):747        self.lastActive = None748        winout.WindowOutputFrame.__init__(self)749 750    def OnMDIActivate(self, bActive, wndActive, wndDeactive):751        if bActive:752            self.lastActive = wndDeactive753 754 755######################################################################756##757## Dockable Window Support758##759######################################################################760ID_DOCKED_INTERACTIVE_CONTROLBAR = 0xE802761 762DockedInteractiveViewParent = InteractiveView763 764 765class DockedInteractiveView(DockedInteractiveViewParent):766    def HookHandlers(self):767        DockedInteractiveViewParent.HookHandlers(self)768        self.HookMessage(self.OnSetFocus, win32con.WM_SETFOCUS)769        self.HookMessage(self.OnKillFocus, win32con.WM_KILLFOCUS)770 771    def OnSetFocus(self, msg):772        self.GetParentFrame().SetActiveView(self)773        return 1774 775    def OnKillFocus(self, msg):776        # If we are losing focus to another in this app, reset the main frame's active view.777        hwnd = wparam = msg[2]778        try:779            wnd = win32ui.CreateWindowFromHandle(hwnd)780            reset = wnd.GetTopLevelFrame() == self.GetTopLevelFrame()781        except win32ui.error:782            reset = 0  # Not my window783        if reset:784            self.GetParentFrame().SetActiveView(None)785        return 1786 787    def OnDestroy(self, msg):788        newSize = self.GetWindowPlacement()[4]789        pywin.framework.app.SaveWindowSize("Interactive Window", newSize, "docked")790        try:791            if self.GetParentFrame().GetActiveView == self:792                self.GetParentFrame().SetActiveView(None)793        except win32ui.error:794            pass795        try:796            if win32ui.GetMainFrame().GetActiveView() == self:797                win32ui.GetMainFrame().SetActiveView(None)798        except win32ui.error:799            pass800        return DockedInteractiveViewParent.OnDestroy(self, msg)801 802 803class CDockedInteractivePython(CInteractivePython):804    def __init__(self, dockbar):805        self.bFirstCreated = 0806        self.dockbar = dockbar807        CInteractivePython.__init__(self)808 809    def NeedRecreateWindow(self):810        if self.bCreating:811            return 0812        try:813            frame = win32ui.GetMainFrame()814            if frame.closing:815                return 0  # Dieing!816        except (win32ui.error, AttributeError):817            return 0  # The app is dieing!818        try:819            cb = frame.GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR)820            return not cb.IsWindowVisible()821        except win32ui.error:822            return 1  # Control bar does not exist!823 824    def RecreateWindow(self):825        try:826            dockbar = win32ui.GetMainFrame().GetControlBar(827                ID_DOCKED_INTERACTIVE_CONTROLBAR828            )829            win32ui.GetMainFrame().ShowControlBar(dockbar, 1, 1)830        except win32ui.error:831            CreateDockedInteractiveWindow()832 833    def Create(self):834        self.bCreating = 1835        doc = InteractiveDocument(None, self.DoCreateDoc())836        view = DockedInteractiveView(doc)837        defRect = pywin.framework.app.LoadWindowSize("Interactive Window", "docked")838        if defRect[2] - defRect[0] == 0:839            defRect = 0, 0, 500, 200840        style = win32con.WS_CHILD | win32con.WS_VISIBLE | win32con.WS_BORDER841        id = 1050  # win32ui.AFX_IDW_PANE_FIRST842        view.CreateWindow(self.dockbar, id, style, defRect)843        view.OnInitialUpdate()844        self.bFirstCreated = 1845 846        self.currentView = doc.GetFirstView()847        self.bCreating = 0848        if self.title:849            doc.SetTitle(self.title)850 851 852# The factory we pass to the dockable window support.853def InteractiveViewCreator(parent):854    global edit855    edit = CDockedInteractivePython(parent)856    return edit.currentView857 858 859def CreateDockedInteractiveWindow():860    # Later, the DockingBar should be capable of hosting multiple861    # children.862    from pywin.docking.DockingBar import DockingBar863 864    bar = DockingBar()865    creator = InteractiveViewCreator866    bar.CreateWindow(867        win32ui.GetMainFrame(),868        creator,869        "Interactive Window",870        ID_DOCKED_INTERACTIVE_CONTROLBAR,871    )872    bar.SetBarStyle(873        bar.GetBarStyle()874        | afxres.CBRS_TOOLTIPS875        | afxres.CBRS_FLYBY876        | afxres.CBRS_SIZE_DYNAMIC877    )878    bar.EnableDocking(afxres.CBRS_ALIGN_ANY)879    win32ui.GetMainFrame().DockControlBar(bar, afxres.AFX_IDW_DOCKBAR_BOTTOM)880 881 882######################################################################883#884# The public interface to this module.885#886######################################################################887# No extra functionality now, but maybe later, so888# publicize these names.889InteractiveDocument = winout.WindowOutputDocument890 891# We remember our one and only interactive window in the "edit" variable.892edit = None893 894 895def CreateInteractiveWindowUserPreference(makeDoc=None, makeFrame=None):896    """Create some sort of interactive window if the user's preference say we should."""897    bCreate = LoadPreference("Show at startup", 1)898    if bCreate:899        CreateInteractiveWindow(makeDoc, makeFrame)900 901 902def CreateInteractiveWindow(makeDoc=None, makeFrame=None):903    """Create a standard or docked interactive window unconditionally"""904    assert edit is None, "Creating second interactive window!"905    bDocking = LoadPreference("Docking", 0)906    if bDocking:907        CreateDockedInteractiveWindow()908    else:909        CreateMDIInteractiveWindow(makeDoc, makeFrame)910    assert edit is not None, "Created interactive window, but did not set the global!"911    edit.currentView.SetFocus()912 913 914def CreateMDIInteractiveWindow(makeDoc=None, makeFrame=None):915    """Create a standard (non-docked) interactive window unconditionally"""916    global edit917    if makeDoc is None:918        makeDoc = InteractiveDocument919    if makeFrame is None:920        makeFrame = InteractiveFrame921    edit = CInteractivePython(makeDoc=makeDoc, makeFrame=makeFrame)922 923 924def DestroyInteractiveWindow():925    """Destroy the interactive window.926    This is different to Closing the window,927    which may automatically re-appear.  Once destroyed, it can never be recreated,928    and a complete new instance must be created (which the various other helper929    functions will then do after making this call930    """931    global edit932    if edit is not None and edit.currentView is not None:933        if edit.currentView.GetParentFrame() == win32ui.GetMainFrame():934            # It is docked - do nothing now (this is only called at shutdown!)935            pass936        else:937            # It is a standard window - call Close on the container.938            edit.Close()939            edit = None940 941 942def CloseInteractiveWindow():943    """Close the interactive window, allowing it to be re-created on demand."""944    global edit945    if edit is not None and edit.currentView is not None:946        if edit.currentView.GetParentFrame() == win32ui.GetMainFrame():947            # It is docked, just hide the dock bar.948            frame = win32ui.GetMainFrame()949            cb = frame.GetControlBar(ID_DOCKED_INTERACTIVE_CONTROLBAR)950            frame.ShowControlBar(cb, 0, 1)951        else:952            # It is a standard window - destroy the frame/view, allowing the object itself to remain.953            edit.currentView.GetParentFrame().DestroyWindow()954 955 956def ToggleInteractiveWindow():957    """If the interactive window is visible, hide it, otherwise show it."""958    if edit is None:959        CreateInteractiveWindow()960    else:961        if edit.NeedRecreateWindow():962            edit.RecreateWindow()963        else:964            # Close it, allowing a reopen.965            CloseInteractiveWindow()966 967 968def ShowInteractiveWindow():969    """Shows (or creates if necessary) an interactive window"""970    if edit is None:971        CreateInteractiveWindow()972    else:973        if edit.NeedRecreateWindow():974            edit.RecreateWindow()975        else:976            parent = edit.currentView.GetParentFrame()977            if parent == win32ui.GetMainFrame():  # It is docked.978                edit.currentView.SetFocus()979            else:  # It is a "normal" window980                edit.currentView.GetParentFrame().AutoRestore()981                win32ui.GetMainFrame().MDIActivate(edit.currentView.GetParentFrame())982 983 984def IsInteractiveWindowVisible():985    return edit is not None and not edit.NeedRecreateWindow()986 
codekingpro/portable-devtools · Team Ai