diff options
author | Campbell Barton <ideasman42@gmail.com> | 2009-11-07 02:53:40 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2009-11-07 02:53:40 +0300 |
commit | ddeb9f8e24da6076ed76be1573cc152def5751ae (patch) | |
tree | c5ab6b10a11fc0fc488cd25d4e2609301e35e108 /release/scripts/op | |
parent | 6e47d9bb9c3f7e12ee3bdcf171d9adf1b3d62091 (diff) |
- added console language type
- separated python console from the interactive console
- added shell console type (simple example)
- console types are autodetected and can be selected in the menu
Diffstat (limited to 'release/scripts/op')
-rw-r--r-- | release/scripts/op/console_python.py | 225 | ||||
-rw-r--r-- | release/scripts/op/console_shell.py | 102 |
2 files changed, 327 insertions, 0 deletions
diff --git a/release/scripts/op/console_python.py b/release/scripts/op/console_python.py new file mode 100644 index 00000000000..d3b745c7ead --- /dev/null +++ b/release/scripts/op/console_python.py @@ -0,0 +1,225 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import sys +import bpy + +language_id = 'python' + +def add_scrollback(text, text_type): + for l in text.split('\n'): + bpy.ops.console.scrollback_append(text=l.replace('\t', ' '), + type=text_type) + +def get_console(console_id): + ''' + helper function for console operators + currently each text datablock gets its own + console - bpython_code.InteractiveConsole() + ...which is stored in this function. + + console_id can be any hashable type + ''' + from code import InteractiveConsole + + try: + consoles = get_console.consoles + except: + consoles = get_console.consoles = {} + + # clear all dead consoles, use text names as IDs + # TODO, find a way to clear IDs + ''' + for console_id in list(consoles.keys()): + if console_id not in bpy.data.texts: + del consoles[id] + ''' + + try: + console, stdout, stderr = consoles[console_id] + except: + namespace = {'__builtins__': __builtins__, 'bpy': bpy} + console = InteractiveConsole(namespace) + + import io + stdout = io.StringIO() + stderr = io.StringIO() + + consoles[console_id] = console, stdout, stderr + + return console, stdout, stderr + + +class PyConsoleExec(bpy.types.Operator): + '''Execute the current console line as a python expression.''' + bl_idname = "console.execute_" + language_id + bl_label = "Console Execute" + bl_register = False + + # Both prompts must be the same length + PROMPT = '>>> ' + PROMPT_MULTI = '... ' + + # is this working??? + ''' + def poll(self, context): + return (context.space_data.type == 'PYTHON') + ''' + # its not :| + + def execute(self, context): + sc = context.space_data + + try: + line = sc.history[-1].line + except: + return ('CANCELLED',) + + if sc.console_type != 'PYTHON': + return ('CANCELLED',) + + console, stdout, stderr = get_console(hash(context.region)) + + # Hack, useful but must add some other way to access + #if "C" not in console.locals: + console.locals["C"] = context + + # redirect output + sys.stdout = stdout + sys.stderr = stderr + + # run the console + if not line.strip(): + line_exec = '\n' # executes a multiline statement + else: + line_exec = line + + is_multiline = console.push(line_exec) + + stdout.seek(0) + stderr.seek(0) + + output = stdout.read() + output_err = stderr.read() + + # cleanup + sys.stdout = sys.__stdout__ + sys.stderr = sys.__stderr__ + sys.last_traceback = None + + # So we can reuse, clear all data + stdout.truncate(0) + stderr.truncate(0) + + bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT') + + if is_multiline: + sc.prompt = self.PROMPT_MULTI + else: + sc.prompt = self.PROMPT + + # insert a new blank line + bpy.ops.console.history_append(text="", current_character=0, + remove_duplicates=True) + + # Insert the output into the editor + # not quite correct because the order might have changed, + # but ok 99% of the time. + if output: + add_scrollback(output, 'OUTPUT') + if output_err: + add_scrollback(output_err, 'ERROR') + + return ('FINISHED',) + + +class PyConsoleAutocomplete(bpy.types.Operator): + '''Evaluate the namespace up until the cursor and give a list of + options or complete the name if there is only one.''' + bl_idname = "console.autocomplete_" + language_id + bl_label = "Python Console Autocomplete" + bl_register = False + + def poll(self, context): + return context.space_data.console_type == 'PYTHON' + + def execute(self, context): + from console import intellisense + + sc = context.space_data + + console = get_console(hash(context.region))[0] + + current_line = sc.history[-1] + line = current_line.line + + if not console: + return ('CANCELLED',) + + if sc.console_type != 'PYTHON': + return ('CANCELLED',) + + # This function isnt aware of the text editor or being an operator + # just does the autocomp then copy its results back + current_line.line, current_line.current_character, scrollback = \ + intellisense.expand( + line=current_line.line, + cursor=current_line.current_character, + namespace=console.locals, + private='-d' in sys.argv) + + # Now we need to copy back the line from blender back into the + # text editor. This will change when we dont use the text editor + # anymore + if scrollback: + add_scrollback(scrollback, 'INFO') + + context.area.tag_redraw() + + return ('FINISHED',) + + +class PyConsoleBanner(bpy.types.Operator): + bl_idname = "console.banner_" + language_id + + def execute(self, context): + sc = context.space_data + version_string = sys.version.strip().replace('\n', ' ') + + add_scrollback(" * Python Interactive Console %s *" % version_string, 'OUTPUT') + add_scrollback("Command History: Up/Down Arrow", 'OUTPUT') + add_scrollback("Cursor: Left/Right Home/End", 'OUTPUT') + add_scrollback("Remove: Backspace/Delete", 'OUTPUT') + add_scrollback("Execute: Enter", 'OUTPUT') + add_scrollback("Autocomplete: Ctrl+Space", 'OUTPUT') + add_scrollback("Ctrl +/- Wheel: Zoom", 'OUTPUT') + add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, Mathutils, Geometry, BGL", 'OUTPUT') + add_scrollback("", 'OUTPUT') + add_scrollback("", 'OUTPUT') + sc.prompt = PyConsoleExec.PROMPT + + # Add context into the namespace for quick access + console = get_console(hash(context.region))[0] + console.locals["C"] = bpy.context + + return ('FINISHED',) + +bpy.ops.add(PyConsoleExec) +bpy.ops.add(PyConsoleAutocomplete) +bpy.ops.add(PyConsoleBanner) diff --git a/release/scripts/op/console_shell.py b/release/scripts/op/console_shell.py new file mode 100644 index 00000000000..4bf20e470e8 --- /dev/null +++ b/release/scripts/op/console_shell.py @@ -0,0 +1,102 @@ +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +# <pep8 compliant> +import sys +import bpy + +language_id = 'shell' + +def add_scrollback(text, text_type): + for l in text.split('\n'): + bpy.ops.console.scrollback_append(text=l.replace('\t', ' '), + type=text_type) + + +def shell_run(text): + import os + add_scrollback(os.popen(text).read(), 'OUTPUT') + +class ShellConsoleExec(bpy.types.Operator): + '''Execute the current console line as a python expression.''' + bl_idname = "console.execute_" + language_id + bl_label = "Console Execute" + bl_register = False + + # Both prompts must be the same length + PROMPT = '$ ' + + # is this working??? + ''' + def poll(self, context): + return (context.space_data.type == 'PYTHON') + ''' + # its not :| + + def execute(self, context): + sc = context.space_data + + try: + line = sc.history[-1].line + except: + return ('CANCELLED',) + + bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT') + + shell_run(line) + + # insert a new blank line + bpy.ops.console.history_append(text="", current_character=0, + remove_duplicates=True) + + return ('FINISHED',) + + +class ShellConsoleAutocomplete(bpy.types.Operator): + '''Evaluate the namespace up until the cursor and give a list of + options or complete the name if there is only one.''' + bl_idname = "console.autocomplete_" + language_id + bl_label = "Python Console Autocomplete" + bl_register = False + + def poll(self, context): + return context.space_data.console_type == 'PYTHON' + + def execute(self, context): + from console import intellisense + + sc = context.space_data + + # TODO + return ('CANCELLED',) + + +class ShellConsoleBanner(bpy.types.Operator): + bl_idname = "console.banner_" + language_id + + def execute(self, context): + sc = context.space_data + + shell_run("bash --version") + sc.prompt = ShellConsoleExec.PROMPT + + return ('FINISHED',) + +bpy.ops.add(ShellConsoleExec) +bpy.ops.add(ShellConsoleAutocomplete) +bpy.ops.add(ShellConsoleBanner) |