operators were copying the properties from the rna operator into the class instance.
[blender.git] / release / scripts / ui / space_console.py
index 9bcd98be49e7e6693e0b238fb9e53ac781171887..8aa4df7b16a2d21292f8d691e48445dc8279556f 100644 (file)
@@ -1,5 +1,24 @@
-import sys
+# ##### 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 bpy
+from bpy.props import *
 
 
 class CONSOLE_HT_header(bpy.types.Header):
@@ -49,6 +68,7 @@ class CONSOLE_MT_console(bpy.types.Menu):
         layout.itemO("console.clear")
         layout.itemO("console.copy")
         layout.itemO("console.paste")
+        layout.itemM("CONSOLE_MT_language")
 
 
 class CONSOLE_MT_report(bpy.types.Menu):
@@ -63,131 +83,53 @@ class CONSOLE_MT_report(bpy.types.Menu):
         layout.itemO("console.report_copy")
 
 
-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
+class CONSOLE_MT_language(bpy.types.Menu):
+    bl_label = "Languages..."
 
-    try:
-        consoles = get_console.consoles
-    except:
-        consoles = get_console.consoles = {}
+    def draw(self, context):
+        import sys
+        
+        layout = self.layout
+        layout.column()
 
-    # 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]
-    '''
+        # Collect modules with 'console_*.execute'
+        languages = []
+        for modname, mod in sys.modules.items():
+            if modname.startswith("console_") and hasattr(mod, "execute"):
+                languages.append(modname.split('_', 1)[-1])
 
-    try:
-        console, stdout, stderr = consoles[console_id]
-    except:
-        namespace = {'__builtins__': __builtins__, 'bpy': bpy}
-        console = InteractiveConsole(namespace)
+        languages.sort()
 
-        import io
-        stdout = io.StringIO()
-        stderr = io.StringIO()
+        for language in languages:
+            layout.item_stringO("console.language", "language", language, text=language[0].upper() + language[1:])
 
-        consoles[console_id] = console, stdout, stderr
 
-    return console, stdout, stderr
+def add_scrollback(text, text_type):
+    for l in text.split('\n'):
+        bpy.ops.console.scrollback_append(text=l.replace('\t', '    '),
+            type=text_type)
 
 
-class CONSOLE_OT_exec(bpy.types.Operator):
+class ConsoleExec(bpy.types.Operator):
     '''Execute the current console line as a python expression.'''
     bl_idname = "console.execute"
     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))
-
-        # 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()
+        module = __import__("console_" + sc.language)
+        execute = getattr(module, "execute", None)
 
-        # 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
+        if execute:
+            return execute(context)
         else:
-            sc.prompt = self.PROMPT
-
-        # insert a new blank line
-        bpy.ops.console.history_append(text="", current_character=0,
-            remove_duplicates=True)
+            print("Error: bpy.ops.console.execute_" + sc.language + " - not found")
+            return ('FINISHED',)
 
-        # 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 CONSOLE_OT_autocomplete(bpy.types.Operator):
+class ConsoleAutocomplete(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"
@@ -195,40 +137,56 @@ class CONSOLE_OT_autocomplete(bpy.types.Operator):
     bl_register = False
 
     def poll(self, context):
-        return context.space_data.console_type == 'PYTHON'
+        return context.space_data.console_type != 'REPORT'
 
     def execute(self, context):
-        from console import intellisense
+        sc = context.space_data
+        module =  __import__("console_" + sc.language)
+        autocomplete = getattr(module, "autocomplete", None)
+
+        if autocomplete:
+            return autocomplete(context)
+        else:
+            print("Error: bpy.ops.console.autocomplete_" + sc.language + " - not found")
+            return ('FINISHED',)
 
+
+class ConsoleBanner(bpy.types.Operator):
+    bl_idname = "console.banner"
+
+    def execute(self, context):
         sc = context.space_data
 
-        console = get_console(hash(context.region))[0]
+        # default to python
+        if not sc.language:
+            sc.language = 'python'
+
+        module =  __import__("console_" + sc.language)
+        banner = getattr(module, "banner", None)
+
+        if banner:
+            return banner(context)
+        else:
+            print("Error: bpy.ops.console.banner_" + sc.language + " - not found")
+            return ('FINISHED',)
 
-        current_line = sc.history[-1]
-        line = current_line.line
 
-        if not console:
-            return ('CANCELLED',)
+class ConsoleLanguage(bpy.types.Operator):
+    '''Set the current language for this console'''
+    bl_idname = "console.language"
+    language = StringProperty(name="Language", maxlen=32, default="")
 
-        if sc.console_type != 'PYTHON':
-            return ('CANCELLED',)
+    def execute(self, context):
+        sc = context.space_data
 
-        # 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)
+        # defailt to python
+        sc.language = self.properties.language
 
-        # 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')
+        bpy.ops.console.banner()
 
-        context.area.tag_redraw()
+        # insert a new blank line
+        bpy.ops.console.history_append(text="", current_character=0,
+            remove_duplicates=True)
 
         return ('FINISHED',)
 
@@ -236,6 +194,12 @@ class CONSOLE_OT_autocomplete(bpy.types.Operator):
 bpy.types.register(CONSOLE_HT_header)
 bpy.types.register(CONSOLE_MT_console)
 bpy.types.register(CONSOLE_MT_report)
+bpy.types.register(CONSOLE_MT_language)
+
+# Stubs that call the language operators
+bpy.ops.add(ConsoleExec)
+bpy.ops.add(ConsoleAutocomplete)
+bpy.ops.add(ConsoleBanner)
 
-bpy.ops.add(CONSOLE_OT_exec)
-bpy.ops.add(CONSOLE_OT_autocomplete)
+# Set the language and call the banner
+bpy.ops.add(ConsoleLanguage)