コード例 #1
0
 def awakeFromNib(self):
     self = super(AppDelegate, self).init()
     self._font = NSFont.userFixedPitchFontOfSize_(10)
     self._stderrColor = NSColor.redColor()
     self._stdoutColor = NSColor.blueColor()
     self._codeColor = NSColor.blackColor()
     self._historyLength = 50
     self._history = [u'']
     self._historyView = 0
     self._characterIndexForInput = 0
     # self._stdin = PseudoUTF8Input(self._nestedRunLoopReaderUntilEOLchars_)
     #self._stdin = PseudoUTF8Input(self.readStdin)
     self._stdin = sys.stdin
     self._stderr = PseudoUTF8Output(self.writeStderr_)
     self._stdout = PseudoUTF8Output(self.writeStdout_)
     self._isInteracting = False
     self._console = AsyncInteractiveConsole()
     self._interp = self._console.asyncinteract(
         write=self.writeCode_, banner=""
     ).next
     self._autoscroll = True
コード例 #2
0
class AppDelegate (NibClassBuilder.AutoBaseClass):
    """
    AppDelegate is a delegate/controller for a NSTextView,
    turning it into a full featured interactive Python interpreter.
    """

    #
    #  Outlets - for documentation only
    #

    _NIBOutlets_ = (
        (NSTextView,    'textView',         'The interpreter'),
    )

    #
    #  NSApplicationDelegate methods
    #

    def applicationDidFinishLaunching_(self, aNotification):
        self.textView.setFont_(self.font())
        self.textView.setContinuousSpellCheckingEnabled_(False)
        self.textView.setRichText_(False)
        self._executeWithRedirectedIO(self._interp)
        self._executeWithRedirectedIO(self._executeLine_, 
            "execfile ('/System/Library/Frameworks/Python.framework/Versions/2.3/bin/pyraf')")
        self._stdin = PseudoUTF8Input(self._nestedRunLoopReaderUntilEOLchars_)
        self._executeWithRedirectedIO(self._executeLine_, "import pyraf.pycmdline")
        self._executeWithRedirectedIO(self._executeLine_, 
            "_pycmdline = pyraf.pycmdline.PyCmdLine(locals=globals())")
        self._executeWithRedirectedIO(self._executeLine_, "_pycmdline.start()")

    #
    #  NIB loading protocol
    #

    def awakeFromNib(self):
        self = super(AppDelegate, self).init()
        self._font = NSFont.userFixedPitchFontOfSize_(10)
        self._stderrColor = NSColor.redColor()
        self._stdoutColor = NSColor.blueColor()
        self._codeColor = NSColor.blackColor()
        self._historyLength = 50
        self._history = [u'']
        self._historyView = 0
        self._characterIndexForInput = 0
        # self._stdin = PseudoUTF8Input(self._nestedRunLoopReaderUntilEOLchars_)
        #self._stdin = PseudoUTF8Input(self.readStdin)
        self._stdin = sys.stdin
        self._stderr = PseudoUTF8Output(self.writeStderr_)
        self._stdout = PseudoUTF8Output(self.writeStdout_)
        self._isInteracting = False
        self._console = AsyncInteractiveConsole()
        self._interp = self._console.asyncinteract(
            write=self.writeCode_, banner=""
        ).next
        self._autoscroll = True

    #
    #  Modal input dialog support
    #

    def _nestedRunLoopReaderUntilEOLchars_(self, eolchars):
        """
        This makes the baby jesus cry.

        I want co-routines.
        """
        app = NSApplication.sharedApplication()
        window = self.textView.window()
        self.setCharacterIndexForInput_(self.lengthOfTextView())
        # change the color.. eh
        self.textView.setTypingAttributes_({
            NSFontAttributeName:self.font(),
            NSForegroundColorAttributeName:self.codeColor(),
        })
        while True:
            event = app.nextEventMatchingMask_untilDate_inMode_dequeue_(
                NSAnyEventMask,
                NSDate.distantFuture(),
                NSDefaultRunLoopMode,
                True)
            if (event.type() == NSKeyDown) and (event.window() == window):
                eol = event.characters()
                if eol in eolchars:
                    break
            app.sendEvent_(event)
        cl = self.currentLine()
        if eol == '\r':
            self.writeCode_('\n')
        return cl+eol

    #
    #  Interpreter functions
    #

    def _executeWithRedirectedIO(self, fn, *args, **kwargs):
        old = sys.stdin, sys.stdout, sys.stderr
        if self._stdin is not None:
            sys.stdin = self._stdin
        sys.stdout, sys.stderr = self._stdout, self._stderr
        try:
            rval = fn(*args, **kwargs)
        finally:
            sys.stdin, sys.stdout, sys.stderr = old
            self.setCharacterIndexForInput_(self.lengthOfTextView())
        return rval

    def executeLine_(self, line):
        self.addHistoryLine_(line)
        self._executeWithRedirectedIO(self._executeLine_, line)
        self._history = filter(None, self._history)
        self._history.append(u'')
        self._historyView = len(self._history) - 1
    
    def pyrafExecutedLine_ (self, line):
        self.addHistoryLine_(line)
        self._history = filter(None, self._history)
        self._history.append(u'')
        self._historyView = len(self._history) - 1
    
    def _executeLine_(self, line):
        self._interp()(line)
        self._more = self._interp()

    def executeInteractiveLine_(self, line):
        self.setIsInteracting(True)
        try:
            self.executeLine_(line)
        finally:
            self.setIsInteracting(False)

    def replaceLineWithCode_(self, s):
        idx = self.characterIndexForInput()
        ts = self.textView.textStorage()
        ts.replaceCharactersInRange_withAttributedString_(
            (idx, len(ts.mutableString())-idx), self.codeString_(s))

    #
    #  History functions
    #

    def historyLength(self):
        return self._historyLength

    def setHistoryLength_(self, length):
        self._historyLength = length

    def addHistoryLine_(self, line):
        line = line.rstrip('\n')
        if self._history[-1] == line:
            return False
        if not line:
            return False
        self._history.append(line)
        if len(self._history) > self.historyLength():
            self._history.pop(0)
        return True

    def historyDown_(self, sender):
        if self._historyView == (len(self._history) - 1):
            return
        self._history[self._historyView] = self.currentLine()
        self._historyView += 1
        self.replaceLineWithCode_(self._history[self._historyView])
        self.moveToEndOfLine_(self)

    def historyUp_(self, sender):
        if self._historyView == 0:
            return
        self._history[self._historyView] = self.currentLine()
        self._historyView -= 1
        self.replaceLineWithCode_(self._history[self._historyView])
        self.moveToEndOfLine_(self)

    #
    #  Convenience methods to create/write decorated text
    #

    def _formatString_forOutput_(self, s, name):
        return NSAttributedString.alloc().initWithString_attributes_(
            s,
            {
                NSFontAttributeName:self.font(),
                NSForegroundColorAttributeName:getattr(self, name+'Color')(),
            },
        )

    def _writeString_forOutput_(self, s, name):
        self.textView.textStorage().appendAttributedString_(getattr(self, name+'String_')(s))

        window = self.textView.window()
        app = NSApplication.sharedApplication()
        st = time.time()
        now = time.time

        if self._autoscroll:
            self.textView.scrollRangeToVisible_((self.lengthOfTextView(), 0))

        while app.isRunning() and now() - st < 0.01:
            event = app.nextEventMatchingMask_untilDate_inMode_dequeue_(
                NSAnyEventMask,
                NSDate.dateWithTimeIntervalSinceNow_(0.01),
                NSDefaultRunLoopMode,
                True)

            if event is None:
                continue

            if (event.type() == NSKeyDown) and (event.window() == window):
                chr = event.charactersIgnoringModifiers()
                if chr == 'c' and (event.modifierFlags() & NSControlKeyMask):
                    raise KeyboardInterrupt

            app.sendEvent_(event)


    codeString_   = lambda self, s: self._formatString_forOutput_(s, 'code')
    stderrString_ = lambda self, s: self._formatString_forOutput_(s, 'stderr')
    stdoutString_ = lambda self, s: self._formatString_forOutput_(s, 'stdout')
    writeCode_    = lambda self, s: self._writeString_forOutput_(s, 'code')
    writeStderr_  = lambda self, s: self._writeString_forOutput_(s, 'stderr')
    writeStdout_  = lambda self, s: self._writeString_forOutput_(s, 'stdout')

    #
    #  Accessors
    #

    def more(self):
        return self._more

    def font(self):
        return self._font

    def setFont_(self, font):
        self._font = font

    def stderrColor(self):
        return self._stderrColor

    def setStderrColor_(self, color):
        self._stderrColor = color

    def stdoutColor(self):
        return self._stdoutColor

    def setStdoutColor_(self, color):
        self._stdoutColor = color

    def codeColor(self):
        return self._codeColor

    def setStdoutColor_(self, color):
        self._codeColor = color

    def isInteracting(self):
        return self._isInteracting

    def setIsInteracting(self, v):
        self._isInteracting = v

    def isAutoScroll(self):
        return self._autoScroll

    def setAutoScroll(self, v):
        self._autoScroll = v


    #
    #  Convenience methods for manipulating the NSTextView
    #

    def currentLine(self):
        return self.textView.textStorage().mutableString()[self.characterIndexForInput():]

    def moveAndScrollToIndex_(self, idx):
        self.textView.scrollRangeToVisible_((idx, 0))
        self.textView.setSelectedRange_((idx, 0))

    def characterIndexForInput(self):
        return self._characterIndexForInput

    def lengthOfTextView(self):
        return len(self.textView.textStorage().mutableString())

    def setCharacterIndexForInput_(self, idx):
        self._characterIndexForInput = idx
        self.moveAndScrollToIndex_(idx)

    #
    #  NSTextViewDelegate methods
    #

    def textView_completions_forPartialWordRange_indexOfSelectedItem_(self, aTextView, completions, (begin, length), index):
        txt = self.textView.textStorage().mutableString()
        end = begin+length
        while (begin>0) and (txt[begin].isalnum() or txt[begin] in '._'):
            begin -= 1
        while not txt[begin].isalnum():
            begin += 1
        return self._console.recommendCompletionsFor(txt[begin:end])