diff --git a/app/views/sources/direct_edit.html.haml b/app/views/sources/direct_edit.html.haml
--- a/app/views/sources/direct_edit.html.haml
+++ b/app/views/sources/direct_edit.html.haml
@@ -32,3 +32,233 @@
- if @submission
= render :partial => 'submission_short',
:locals => {:submission => @submission, :problem_name => @problem.name }
+ .row
+ .col-md-12
+ %h2 Console
+ %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
+
+:javascript
+ $(document).ready(function() {
+ brython();
+ });
+
+
+%script#__main__{type:'text/python3'}
+ :plain
+ import sys
+ import traceback
+
+ from browser import document as doc
+ from browser import window, alert, console
+
+ _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
+ for supporting Python development. See www.python.org for more information."""
+
+ _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
+ All Rights Reserved.
+
+ Copyright (c) 2001-2013 Python Software Foundation.
+ All Rights Reserved.
+
+ Copyright (c) 2000 BeOpen.com.
+ All Rights Reserved.
+
+ Copyright (c) 1995-2001 Corporation for National Research Initiatives.
+ All Rights Reserved.
+
+ Copyright (c) 1991-1995 Stichting Mathematisch Centrum, Amsterdam.
+ All Rights Reserved."""
+
+ _license = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer. Redistributions in binary
+ form must reproduce the above copyright notice, this list of conditions and
+ the following disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ Neither the name of the nor the names of its contributors may
+ be used to endorse or promote products derived from this software without
+ specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+ """
+
+ def credits():
+ print(_credits)
+ credits.__repr__ = lambda:_credits
+
+ def copyright():
+ print(_copyright)
+ copyright.__repr__ = lambda:_copyright
+
+ def license():
+ print(_license)
+ license.__repr__ = lambda:_license
+
+ def write(data):
+ doc['console'].value += str(data)
+
+
+ sys.stdout.write = sys.stderr.write = write
+ history = []
+ current = 0
+ _status = "main" # or "block" if typing inside a block
+
+ # execution namespace
+ editor_ns = {'credits':credits,
+ 'copyright':copyright,
+ 'license':license,
+ '__name__':'__main__'}
+
+ def cursorToEnd(*args):
+ pos = len(doc['console'].value)
+ doc['console'].setSelectionRange(pos, pos)
+ doc['console'].scrollTop = doc['console'].scrollHeight
+
+ def get_col(area):
+ # returns the column num of cursor
+ sel = doc['console'].selectionStart
+ lines = doc['console'].value.split('\n')
+ for line in lines[:-1]:
+ sel -= len(line) + 1
+ return sel
+
+
+ def myKeyPress(event):
+ global _status, current
+ if event.keyCode == 9: # tab key
+ event.preventDefault()
+ doc['console'].value += " "
+ elif event.keyCode == 13: # return
+ src = doc['console'].value
+ if _status == "main":
+ currentLine = src[src.rfind('>>>') + 4:]
+ elif _status == "3string":
+ currentLine = src[src.rfind('>>>') + 4:]
+ currentLine = currentLine.replace('\n... ', '\n')
+ else:
+ currentLine = src[src.rfind('...') + 4:]
+ if _status == 'main' and not currentLine.strip():
+ doc['console'].value += '\n>>> '
+ event.preventDefault()
+ return
+ doc['console'].value += '\n'
+ history.append(currentLine)
+ current = len(history)
+ if _status == "main" or _status == "3string":
+ try:
+ _ = editor_ns['_'] = eval(currentLine, editor_ns)
+ if _ is not None:
+ write(repr(_)+'\n')
+ doc['console'].value += '>>> '
+ _status = "main"
+ except IndentationError:
+ doc['console'].value += '... '
+ _status = "block"
+ except SyntaxError as msg:
+ if str(msg) == 'invalid syntax : triple string end not found' or \
+ str(msg).startswith('Unbalanced bracket'):
+ doc['console'].value += '... '
+ _status = "3string"
+ elif str(msg) == 'eval() argument must be an expression':
+ try:
+ exec(currentLine, editor_ns)
+ except:
+ traceback.print_exc()
+ doc['console'].value += '>>> '
+ _status = "main"
+ elif str(msg) == 'decorator expects function':
+ doc['console'].value += '... '
+ _status = "block"
+ else:
+ traceback.print_exc()
+ doc['console'].value += '>>> '
+ _status = "main"
+ except:
+ traceback.print_exc()
+ doc['console'].value += '>>> '
+ _status = "main"
+ elif currentLine == "": # end of block
+ block = src[src.rfind('>>>') + 4:].splitlines()
+ block = [block[0]] + [b[4:] for b in block[1:]]
+ block_src = '\n'.join(block)
+ # status must be set before executing code in globals()
+ _status = "main"
+ try:
+ _ = exec(block_src, editor_ns)
+ if _ is not None:
+ print(repr(_))
+ except:
+ traceback.print_exc()
+ doc['console'].value += '>>> '
+ else:
+ doc['console'].value += '... '
+
+ cursorToEnd()
+ event.preventDefault()
+
+ def myKeyDown(event):
+ global _status, current
+ if event.keyCode == 37: # left arrow
+ sel = get_col(doc['console'])
+ if sel < 5:
+ event.preventDefault()
+ event.stopPropagation()
+ elif event.keyCode == 36: # line start
+ pos = doc['console'].selectionStart
+ col = get_col(doc['console'])
+ doc['console'].setSelectionRange(pos - col + 4, pos - col + 4)
+ event.preventDefault()
+ elif event.keyCode == 38: # up
+ if current > 0:
+ pos = doc['console'].selectionStart
+ col = get_col(doc['console'])
+ # remove current line
+ doc['console'].value = doc['console'].value[:pos - col + 4]
+ current -= 1
+ doc['console'].value += history[current]
+ event.preventDefault()
+ elif event.keyCode == 40: # down
+ if current < len(history) - 1:
+ pos = doc['console'].selectionStart
+ col = get_col(doc['console'])
+ # remove current line
+ doc['console'].value = doc['console'].value[:pos - col + 4]
+ current += 1
+ doc['console'].value += history[current]
+ event.preventDefault()
+ elif event.keyCode == 8: # backspace
+ src = doc['console'].value
+ lstart = src.rfind('\n')
+ if (lstart == -1 and len(src) < 5) or (len(src) - lstart < 6):
+ event.preventDefault()
+ event.stopPropagation()
+
+
+ doc['console'].bind('keypress', myKeyPress)
+ doc['console'].bind('keydown', myKeyDown)
+ doc['console'].bind('click', cursorToEnd)
+ v = sys.implementation.version
+ doc['console'].value = "Brython %s.%s.%s on %s %s\n>>> " % (
+ v[0], v[1], v[2], window.navigator.appName, window.navigator.appVersion)
+ #doc['console'].value += 'Type "copyright", "credits" or "license" for more information.'
+ doc['console'].focus()
+ cursorToEnd()
+
+
+
+