[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [24389] trunk/blender: - added console language type

Campbell Barton ideasman42 at gmail.com
Sat Nov 7 00:53:40 CET 2009


Revision: 24389
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=24389
Author:   campbellbarton
Date:     2009-11-07 00:53:40 +0100 (Sat, 07 Nov 2009)

Log Message:
-----------
- 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

Modified Paths:
--------------
    trunk/blender/release/scripts/ui/space_console.py
    trunk/blender/source/blender/makesdna/DNA_space_types.h
    trunk/blender/source/blender/makesrna/intern/rna_space.c

Added Paths:
-----------
    trunk/blender/release/scripts/op/console_python.py
    trunk/blender/release/scripts/op/console_shell.py

Added: trunk/blender/release/scripts/op/console_python.py
===================================================================
--- trunk/blender/release/scripts/op/console_python.py	                        (rev 0)
+++ trunk/blender/release/scripts/op/console_python.py	2009-11-06 23:53:40 UTC (rev 24389)
@@ -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)

Added: trunk/blender/release/scripts/op/console_shell.py
===================================================================
--- trunk/blender/release/scripts/op/console_shell.py	                        (rev 0)
+++ trunk/blender/release/scripts/op/console_shell.py	2009-11-06 23:53:40 UTC (rev 24389)
@@ -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
+

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list