Skip to content

Instantly share code, notes, and snippets.

@abhijangda
Created September 12, 2013 16:03
Show Gist options
  • Save abhijangda/6539982 to your computer and use it in GitHub Desktop.
Save abhijangda/6539982 to your computer and use it in GitHub Desktop.
import code, sys, threading
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.base import runTouchApp
from kivy.clock import Clock
from kivy.base import EventLoop
class PseudoFile(object):
def __init__(self, sh):
self.sh = sh
def write(self, s):
self.sh.write(s)
def writelines(self, lines):
for line in lines:
self.write(line)
def flush(self):
pass
def isatty(self):
return True
class Shell(code.InteractiveConsole):
"Wrapper around Python that can filter input/output to the shell"
def __init__(self, root):
code.InteractiveConsole.__init__(self)
self.thread = None
self.root = root
def write(self, data):
import functools
Clock.schedule_once(functools.partial(self.root.show_output, data), 0)
def push(self, line):
return code.InteractiveConsole.push(self, line)
def raw_input(self, prompt=""):
return self.root.get_input(prompt)
def runcode(self, _code):
"""Execute a code object.
When an exception occurs, self.showtraceback() is called to
display a traceback. All exceptions are caught except
SystemExit, which is reraised.
A note about KeyboardInterrupt: this exception may occur
elsewhere in this code, and may not always be caught. The
caller should be prepared to deal with it.
"""
org_stdout = sys.stdout
sys.stdout = PseudoFile(self)
try:
exec _code in self.locals
except SystemExit:
raise
except:
self.showtraceback()
else:
if code.softspace(sys.stdout, 0):
print
sys.stdout = org_stdout
def interact(self, banner=None):
"""Closely emulate the interactive Python console.
The optional banner argument specify the banner to print
before the first interaction; by default it prints a banner
similar to the one printed by the real Python interpreter,
followed by the current class name in parentheses (so as not
to confuse this with the real interpreter -- since it's so
close!).
"""
try:
sys.ps1
except AttributeError:
sys.ps1 = ">>> "
try:
sys.ps2
except AttributeError:
sys.ps2 = "... "
cprt = 'Type "help", "copyright", "credits" or "license" for more information.'
if banner is None:
self.write("Python %s on %s\n%s\n(%s)\n" %
(sys.version, sys.platform, cprt,
self.__class__.__name__))
else:
self.write("%s\n" % str(banner))
more = 0
while 1:
try:
if more:
prompt = sys.ps2
else:
prompt = sys.ps1
try:
line = self.raw_input(prompt)
# Can be None if sys.stdin was redefined
encoding = getattr(sys.stdin, "encoding", None)
if encoding and not isinstance(line, unicode):
line = line.decode(encoding)
except EOFError:
self.write("\n")
break
else:
more = self.push(line)
except KeyboardInterrupt:
self.write("\nKeyboardInterrupt\n")
self.resetbuffer()
more = 0
class InteractiveThread(threading.Thread):
def __init__(self, sh):
super(InteractiveThread, self).__init__()
self._sh = sh
self._sh.thread = self
def run(self):
self._sh.interact()
class InteractiveShellInput(TextInput):
__events__ = ('on_ready_to_input',)
def __init__(self, **kwargs):
super(InteractiveShellInput, self).__init__(**kwargs)
self.last_line = None
def _keyboard_on_key_down(self, window, keycode, text, modifiers):
if keycode[0] == 13:
#For enter
self.last_line = self.text[self._cursor_pos:]
self.dispatch('on_ready_to_input')
return super(InteractiveShellInput, self)._keyboard_on_key_down(window, keycode, text, modifiers)
def on_ready_to_input(self, *args):
pass
def show_output(self, output):
self.text += output
Clock.schedule_once(self._set_cursor_val, 0)
def _set_cursor_val(self, *args):
self._cursor_pos = self.cursor_index()
class Root(BoxLayout):
def __init__(self, **kwargs):
super(Root, self).__init__()
self.text_input = InteractiveShellInput()
self.text_input.bind(on_ready_to_input=self.ready_to_input)
self.add_widget(self.text_input)
self.sh = Shell(self)
self._thread = InteractiveThread(self.sh)
Clock.schedule_once(self.run_sh, -1)
self.ready_to_input = False
def ready_to_input(self, *args):
self.ready_to_input = True
def run_sh(self, *args):
self._thread.start()
def show_output(self, data, dt):
self.text_input.show_output(data)
def _show_prompt(self, *args):
self.text_input.show_output(self.prompt)
def get_input(self, prompt):
import time
self.prompt = prompt
Clock.schedule_once(self._show_prompt, 0.1)
while not self.ready_to_input:
time.sleep(0.1)
self.ready_to_input = False
return self.text_input.last_line
if __name__ == '__main__':
runTouchApp(Root())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment