use new preferences standard and fixes for various blender changes
[blender-addons-contrib.git] / text_intellisense.py
1 # ***** BEGIN GPL LICENSE BLOCK *****
2 #
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 #
18 # ***** END GPL LICENCE BLOCK *****
19
20 bl_info = {
21     "name": "Intellisense for Text Editor",
22     "author": "Mackraken",
23     "version": (0, 2),
24     "blender": (2, 60, 0),
25     "api": 41851,
26     "location": "Ctrl + Space at Text Editor",
27     "description": "Adds intellense to the Text Editor",
28     "warning": "Only works with 2.57 intellisense",
29     "wiki_url": "",
30     "tracker_url": "",
31     "category": "Development"}
32
33 import bpy
34
35 def complete(context):
36         from console import intellisense
37         from console_python import get_console
38         
39         sc = context.space_data
40         text = sc.text
41         
42         region = context.region
43         for area in context.screen.areas:
44                 if area.type=="CONSOLE":
45                         region = area.regions[1]
46                         break
47         
48         console = get_console(hash(region))[0]
49
50         line = text.current_line.body
51         cursor = text.current_character
52         
53         result  = intellisense.expand(line, cursor, console.locals, bpy.app.debug)
54         
55         return result
56
57         
58 class Intellimenu(bpy.types.Menu):
59         bl_label = ""
60         bl_idname = "IntelliMenu"
61         
62         text = ""
63         
64         def draw(self, context):
65                 layout = self.layout
66                 #Very ugly see how can i fix this
67                 options = complete(context)
68                 
69                 options = options[2].split("  ")
70                 for op in options:
71                         layout.operator("text.intellioptions", text=op).text=op
72                 
73 #This operator executes when hits Ctrl+Space at the text editor
74
75 class Intellisense(bpy.types.Operator):
76         #"""Tooltip"""
77         bl_idname = "text.intellisense"
78         bl_label = "Text Editor Intellisense"
79         
80         text = ""
81         
82 #       @classmethod
83 #       def poll(cls, context):
84 #               return context.active_object is not None
85
86         def execute(self, context):
87                 sc = context.space_data
88                 text = sc.text
89                 
90                 if text.current_character>0:
91                         result = complete(context)
92         
93                         #print(result)
94                         
95                         if result[2]=="":
96                                 text.current_line.body = result[0]
97                                 bpy.ops.text.move(type='LINE_END')
98                         else:
99                                 bpy.ops.wm.call_menu(name=Intellimenu.bl_idname)
100
101                 return {'FINISHED'}
102         
103 #this operator completes the line with the options you choose from the menu
104 class Intellioptions(bpy.types.Operator):
105         #"""Tooltip"""
106         bl_idname = "text.intellioptions"
107         bl_label = "Intellisense options"
108
109         text = bpy.props.StringProperty()
110         
111         @classmethod
112         def poll(cls, context):
113                 return context.active_object is not None
114
115         def execute(self, context):
116                 sc = context.space_data
117                 text = sc.text
118                 
119                 comp = self.text
120                 line = text.current_line.body
121                 
122                 lline = len(line)
123                 lcomp = len(comp)
124                 
125                 #intersect text 
126                 intersect = [-1,-1]
127                 
128                 for i in range(lcomp):
129                         val1 = comp[0:i+1]
130                         
131                         for j in range(lline):
132                                 val2 = line[lline-j-1::]
133                                 #print("        ",j, val2)
134                         
135                                 if val1==val2:
136                                         intersect = [i, j]
137                                         break
138                                 
139                 if intersect[0]>-1:
140                         newline = line[0:lline-intersect[1]-1]+comp
141                 else:
142                         newline = line + comp
143                         
144                 #print(newline)         
145                 text.current_line.body = newline
146                         
147                 bpy.ops.text.move(type='LINE_END')
148                    
149
150                 return {'FINISHED'}
151
152 def send_console(context, all=0):
153         
154         sc = context.space_data
155         text = sc.text
156         
157         console = None
158         
159         for area in bpy.context.screen.areas:
160                 if area.type=="CONSOLE":
161                         from console_python import get_console
162                                 
163                         console = get_console(hash(area.regions[1]))[0]
164
165         if console==None:
166                 return {'FINISHED'}
167         
168         if all:
169                 
170                 for l in text.lines:
171                         console.push(l.body)
172                         
173         else:
174                 #print(console.prompt)
175                 console.push(text.current_line.body)
176         
177         
178         
179         
180 class TestLine(bpy.types.Operator):
181         #"""Tooltip"""
182         bl_idname = "text.test_line"
183         bl_label = "Test line"
184
185         all = bpy.props.BoolProperty(default=False)
186         
187         
188 #   @classmethod
189 #   def poll(cls, context):
190 #          return context.active_object is not None
191
192         def execute(self, context):
193                 #print("test line")
194                 
195                 #send_console(context, self.all)
196                 sc = context.space_data
197                 text = sc.text
198                 
199                 line = text.current_line.body
200                 console = None
201                 
202                 for area in bpy.context.screen.areas:
203                         if area.type=="CONSOLE":
204                                 from console_python import get_console
205                                         
206                                 console = get_console(hash(area.regions[1]))[0]
207                 
208                 if console==None:
209                         return {'FINISHED'}
210                                 
211                 command = ""
212                         
213                 forindex = line.find("for ")
214                 if forindex >-1:
215                         
216                         var = line[forindex+4:-1]
217                         var = var[0:var.find(" ")]
218                         state = line[line.rindex(" ")+1:-1]
219                          
220                         command = var + " = " +state+"[0]"
221                         
222                                 
223                 else:
224                         command = line
225                         
226                 #print(command)
227                 try:
228                         console.push(command)
229                 except:
230                         pass
231                 
232                 bpy.ops.text.line_break()
233                 
234
235                 return {'FINISHED'}
236 class SetBreakPoint(bpy.types.Operator):
237         bl_idname = "text.set_breakpoint"
238         bl_label = "Set Breakpoint"
239         
240         def execute(self, context):
241                 
242                 sc = bpy.context.space_data
243                 text = sc.text
244                 
245                 line = text.current_line
246                 br = " #breakpoint"
247                 #print(line.body.find(br))
248                 if line.body.find(br)>-1:
249                         
250                         line.body = line.body.replace(br, "")
251                 else:
252                         
253                         line.body += br
254                 
255                 return {'FINISHED'}
256
257 class Debug(bpy.types.Operator):
258         bl_idname = "text.debug"
259         bl_label = "Debug"
260         
261         def execute(self, context):
262                 
263                 binpath = bpy.app.binary_path
264                         
265                 addonspath = binpath[0:binpath.rindex("\\")+1]+str(bpy.app.version[0])+"."+str(bpy.app.version[1])+"\\scripts\\addons\\"
266                 
267                 print(addonspath)
268                         
269                 sc = context.space_data
270                 text = sc.text
271                 
272                 br = " #breakpoint"
273         
274                 filepath = addonspath+"debug.py"
275                 file = open(filepath, "w")
276                 file.write("import pdb\n")
277                 
278                 for line in text.lines:
279                         l = line.body
280                         
281                         if line.body.find(br)>-1:
282                                 indent = ""
283                                 for letter in line.body:
284                                         
285                                         if not letter.isalpha():
286                                                 indent+=letter
287                                         else:
288                                                 break
289                                 file.write(l[0:-len(br)]+"\n")
290                                 
291                                 file.write(indent+"pdb.set_trace()\n")
292                                 
293                         else:
294                                 file.write(line.body+"\n")
295                                                 
296                                 
297                 
298                 file.close()
299                 
300                 import pdb
301                 import debug
302                 
303                 pdb.runcall("debug")    
304                 
305                 
306                 return {'FINISHED'}
307
308
309 class DebugPanel(bpy.types.Panel):
310         bl_label = "Debug"
311         bl_idname = "text.test_line"
312         bl_space_type = "TEXT_EDITOR"
313         bl_region_type = "UI"
314         #bl_context = "object"
315
316         text = bpy.props.StringProperty()
317         
318         def draw(self, context):
319                 layout = self.layout
320                 row = layout.row()
321                 
322                 text = self.text
323                 row = layout.row()
324                 row.operator("text.debug", text ="Debug")
325                 row = layout.row()
326                 row.operator("text.set_breakpoint")
327                 row = layout.row()
328                 row.operator("text.test_line").all=False
329                 row = layout.row()
330                 row.operator("text.test_line", text ="Test All").all=True
331                 
332                 row = layout.row()
333                 row.label(text="Coming Soon ...")
334
335
336 ### ASSIGN A KEY
337  
338 #section = Input section. "Window, Text, ..."
339 #name = operator name or wm.call_menu 
340 #type = key 
341 #event = keyboard event (Press, release, ...)
342 #mods = array containing key modifiers (["ctrl", "alt", "shift"]
343 #propvalue = menu name, if name is set to "wm.call_menu"
344 #overwrite doesnt work at the moment
345
346 def assignKey(section, name, type, event, mods=[],propvalue = "",  overwrite=0):
347         
348         kconf = bpy.context.window_manager.keyconfigs.active
349         
350         
351         #check section
352         validsections = [item.name for item in kconf.keymaps]
353         if not section in validsections:
354                 print(section  + " is not a valid section.")
355                 #print(validsections)   
356                 return False
357         
358         #check type
359         type = type.upper()
360         validkeys = [item.identifier for item in bpy.types.KeyMapItem.bl_rna.properties['type'].enum_items]
361         if not type in validkeys:
362                 print(type + " is not a valid key.")
363                 #print(validkeys)
364                 return False
365
366
367         #check event
368         event = event.upper()   
369         validevents = [item.identifier for item in bpy.types.KeyMapItem.bl_rna.properties['value'].enum_items]
370         if not event in validevents:
371                 print(event + " is not a valid event.")
372                 #print(validevents)
373                 
374         kmap = kconf.keymaps[section] 
375
376         
377 #   get mods
378         for i, mod in enumerate(mods):
379                 mods[i]= mod.lower()
380                 
381         #any, shift, ctrl, alt, oskey
382         kmod = [False, False, False, False, False]
383         
384         if "any" in mods: kmod[0] = True
385         if "shift" in mods: kmod[1] = True
386         if "ctrl" in mods: kmod[2] = True
387         if "alt" in mods: kmod[3] = True
388         if "oskey" in mods: kmod[4] = True
389         
390 #   #check if key exist
391         kexists = False
392   
393         for key in kmap.keymap_items:
394                 keymods = [key.any, key.shift, key.ctrl, key.alt, key.oskey]
395                 if key.type == type and keymods == kmod:
396                         kexists = True
397                         print(key,"key exists")
398                         break
399                         
400         if kexists:
401                 #overwrite?
402                 if overwrite:
403                         key.idname=name
404                         
405                         #key.type = type
406                 
407         else:
408                 #create key
409                 key = kmap.keymap_items.new(name, type, event, False)
410                 key.any = kmod[0]
411                 key.shift = kmod[1]
412                 key.ctrl = kmod[2]
413                 key.alt = kmod[3]
414                 key.oskey = kmod[4]
415                                 
416                 if propvalue!="": key.properties.name = propvalue
417
418
419
420
421 classes = [Intellisense, Intellioptions, Intellimenu, DebugPanel, TestLine, SetBreakPoint, Debug]
422
423 def register():
424         
425         for c in classes:
426                 bpy.utils.register_class(c)
427
428         assignKey("Text", "text.intellisense", "SPACE", "Press",  ["ctrl"])
429         assignKey("Text", "text.test_line", "RET", "Press", [],"",1)
430
431 def unregister():
432         for c in classes:
433                 bpy.utils.unregister_class(c)
434
435 if __name__ == "__main__":
436         register()