359202ba022dd8da380fa3dcf5099dd993fa5e83
[blender-staging.git] / source / blender / editors / space_console / console_ops.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h> /* ispunct */
33 #include <sys/stat.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_windowmanager_types.h"
41
42 #include "BLI_blenlib.h"
43 #include "PIL_time.h"
44
45 #include "BKE_utildefines.h"
46 #include "BKE_context.h"
47 #include "BKE_depsgraph.h"
48 #include "BKE_global.h"
49 #include "BKE_library.h"
50 #include "BKE_main.h"
51 #include "BKE_report.h"
52 // #include "BKE_suggestions.h"
53 //#include "BKE_text.h"
54
55 #include "WM_api.h"
56 #include "WM_types.h"
57
58 #include "ED_screen.h"
59 #include "UI_interface.h"
60 #include "UI_resources.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "console_intern.h"
66
67 void console_history_free(SpaceConsole *sc, ConsoleLine *cl)
68 {
69         BLI_remlink(&sc->history, cl);
70         MEM_freeN(cl->line);
71         MEM_freeN(cl);
72 }
73 void console_scrollback_free(SpaceConsole *sc, ConsoleLine *cl)
74 {
75         BLI_remlink(&sc->scrollback, cl);
76         MEM_freeN(cl->line);
77         MEM_freeN(cl);
78 }
79
80 void console_scrollback_limit(SpaceConsole *sc)
81 {
82         int tot;
83         for(tot= BLI_countlist(&sc->scrollback); tot > CONSOLE_SCROLLBACK_LIMIT; tot--)
84                 console_scrollback_free(sc, sc->scrollback.first);
85 }
86
87 /* return 0 if no change made, clamps the range */
88 static int console_line_cursor_set(ConsoleLine *cl, int cursor)
89 {
90         int cursor_new;
91         
92         if(cursor < 0)                          cursor_new= 0;
93         else if(cursor > cl->len)       cursor_new= cl->len;
94         else                                            cursor_new= cursor;
95         
96         if(cursor_new == cl->cursor)
97                 return 0;
98         
99         cl->cursor= cursor_new;
100         return 1;
101 }
102
103 static ConsoleLine *console_lb_add__internal(ListBase *lb, ConsoleLine *from)
104 {
105         ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add");
106         
107         if(from) {
108                 ci->line= BLI_strdup(from->line);
109                 ci->len= strlen(ci->line);
110                 ci->len_alloc= ci->len;
111                 
112                 ci->cursor= from->cursor;
113                 ci->type= from->type;
114         } else {
115                 ci->line= MEM_callocN(64, "console-in-line");
116                 ci->len_alloc= 64;
117                 ci->len= 0;
118         }
119         
120         BLI_addtail(lb, ci);
121         return ci;
122 }
123
124 static ConsoleLine *console_history_add(const bContext *C, ConsoleLine *from)
125 {
126         SpaceConsole *sc= CTX_wm_space_console(C);
127         
128         return console_lb_add__internal(&sc->history, from);
129 }
130
131 #if 0 /* may use later ? */
132 static ConsoleLine *console_scrollback_add(const bContext *C, ConsoleLine *from)
133 {
134         SpaceConsole *sc= CTX_wm_space_console(C);
135         
136         return console_lb_add__internal(&sc->scrollback, from);
137 }
138 #endif
139
140 static ConsoleLine *console_lb_add_str__internal(ListBase *lb, const bContext *C, char *str, int own)
141 {
142         ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add");
143         if(own)         ci->line= str;
144         else            ci->line= BLI_strdup(str);
145         
146         ci->len = ci->len_alloc = strlen(str);
147         
148         BLI_addtail(lb, ci);
149         return ci;
150 }
151 ConsoleLine *console_history_add_str(const bContext *C, char *str, int own)
152 {
153         return console_lb_add_str__internal(&CTX_wm_space_console(C)->history, C, str, own);
154 }
155 ConsoleLine *console_scrollback_add_str(const bContext *C, char *str, int own)
156 {
157         return console_lb_add_str__internal(&CTX_wm_space_console(C)->scrollback, C, str, own);
158 }
159
160 ConsoleLine *console_history_verify(const bContext *C)
161 {
162         SpaceConsole *sc= CTX_wm_space_console(C);
163         ConsoleLine *ci= sc->history.last;
164         if(ci==NULL)
165                 ci= console_history_add(C, NULL);
166         
167         return ci;
168 }
169
170
171 static void console_line_verify_length(ConsoleLine *ci, int len)
172 {
173         /* resize the buffer if needed */
174         if(len > ci->len_alloc) {
175                 int new_len= len * 2; /* new length */
176                 char *new_line= MEM_callocN(new_len, "console line");
177                 memcpy(new_line, ci->line, ci->len);
178                 MEM_freeN(ci->line);
179                 
180                 ci->line= new_line;
181                 ci->len_alloc= new_len;
182         }
183 }
184
185 static int console_line_insert(ConsoleLine *ci, char *str)
186 {
187         int len = strlen(str);
188         
189         if(len==0)
190                 return 0;
191         
192         console_line_verify_length(ci, len + ci->len);
193         
194         memmove(ci->line+ci->cursor+len, ci->line+ci->cursor, (ci->len - ci->cursor)+1);
195         memcpy(ci->line+ci->cursor, str, len);
196         
197         ci->len += len;
198         ci->cursor += len;
199         
200         return len;
201 }
202
203 static int console_edit_poll(bContext *C)
204 {
205         SpaceConsole *sc= CTX_wm_space_console(C);
206
207         if(!sc || sc->type != CONSOLE_TYPE_PYTHON)
208                 return 0;
209
210         return 1;
211 }
212
213 /* static funcs for text editing */
214
215
216 /* similar to the text editor, with some not used. keep compatible */
217 static EnumPropertyItem move_type_items[]= {
218         {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
219         {LINE_END, "LINE_END", 0, "Line End", ""},
220         {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
221         {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
222         {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
223         {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
224         {0, NULL, 0, NULL, NULL}};
225         
226 static int move_exec(bContext *C, wmOperator *op)
227 {
228         ConsoleLine *ci= console_history_verify(C);
229         
230         int type= RNA_enum_get(op->ptr, "type");
231         int done= 0;
232         
233         switch(type) {
234         case LINE_BEGIN:
235                 done= console_line_cursor_set(ci, 0);
236                 break;
237         case LINE_END:
238                 done= console_line_cursor_set(ci, INT_MAX);
239                 break;
240         case PREV_CHAR:
241                 done= console_line_cursor_set(ci, ci->cursor-1);
242                 break;
243         case NEXT_CHAR:
244                 done= console_line_cursor_set(ci, ci->cursor+1);
245                 break;
246         }
247         
248         if(done) {
249                 ED_area_tag_redraw(CTX_wm_area(C));
250         }
251         
252         return OPERATOR_FINISHED;
253 }
254
255 void CONSOLE_OT_move(wmOperatorType *ot)
256 {
257         /* identifiers */
258         ot->name= "Move Cursor";
259         ot->idname= "CONSOLE_OT_move";
260         
261         /* api callbacks */
262         ot->exec= move_exec;
263         ot->poll= console_edit_poll;
264
265         /* flags */
266         ot->flag= OPTYPE_REGISTER;
267
268         /* properties */
269         RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to.");
270 }
271
272
273 static int insert_exec(bContext *C, wmOperator *op)
274 {
275         ConsoleLine *ci= console_history_verify(C);
276         char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
277         
278         int len= console_line_insert(ci, str);
279         
280         MEM_freeN(str);
281         
282         if(len==0)
283                 return OPERATOR_CANCELLED;
284                 
285         ED_area_tag_redraw(CTX_wm_area(C));
286         
287         return OPERATOR_FINISHED;
288 }
289
290 static int insert_invoke(bContext *C, wmOperator *op, wmEvent *event)
291 {
292         if(!RNA_property_is_set(op->ptr, "text")) {
293                 char str[2] = {event->ascii, '\0'};
294                 RNA_string_set(op->ptr, "text", str);
295         }
296         return insert_exec(C, op);
297 }
298
299 void CONSOLE_OT_insert(wmOperatorType *ot)
300 {
301         /* identifiers */
302         ot->name= "Insert";
303         ot->idname= "CONSOLE_OT_insert";
304         
305         /* api callbacks */
306         ot->exec= insert_exec;
307         ot->invoke= insert_invoke;
308         ot->poll= console_edit_poll;
309
310         /* flags */
311         ot->flag= OPTYPE_REGISTER;
312
313         /* properties */
314         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");
315 }
316
317
318 static EnumPropertyItem delete_type_items[]= {
319         {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
320         {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
321 //      {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
322 //      {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
323         {0, NULL, 0, NULL, NULL}};
324
325 static int delete_exec(bContext *C, wmOperator *op)
326 {
327         
328         ConsoleLine *ci= console_history_verify(C);
329         
330         
331         int done = 0;
332
333         int type= RNA_enum_get(op->ptr, "type");
334         
335         if(ci->len==0) {
336                 return OPERATOR_CANCELLED;
337         }
338         
339         switch(type) {
340         case DEL_NEXT_CHAR:
341                 if(ci->cursor < ci->len) {
342                         memmove(ci->line + ci->cursor, ci->line + ci->cursor+1, (ci->len - ci->cursor)+1);
343                         ci->len--;
344                         done= 1;
345                 }
346                 break;
347         case DEL_PREV_CHAR:
348                 if(ci->cursor > 0) {
349                         ci->cursor--; /* same as above */
350                         memmove(ci->line + ci->cursor, ci->line + ci->cursor+1, (ci->len - ci->cursor)+1);
351                         ci->len--;
352                         done= 1;
353                 }
354                 break;
355         }
356         
357         if(!done)
358                 return OPERATOR_CANCELLED;
359         
360         ED_area_tag_redraw(CTX_wm_area(C));
361         
362         return OPERATOR_FINISHED;
363 }
364
365
366 void CONSOLE_OT_delete(wmOperatorType *ot)
367 {
368         /* identifiers */
369         ot->name= "Delete";
370         ot->idname= "CONSOLE_OT_delete";
371         
372         /* api callbacks */
373         ot->exec= delete_exec;
374         ot->poll= console_edit_poll;
375
376         /* flags */
377         ot->flag= OPTYPE_REGISTER;
378
379         /* properties */
380         RNA_def_enum(ot->srna, "type", delete_type_items, DEL_NEXT_CHAR, "Type", "Which part of the text to delete.");
381 }
382
383
384 /* the python exec operator uses this */
385 static int clear_exec(bContext *C, wmOperator *op)
386 {
387         SpaceConsole *sc= CTX_wm_space_console(C);
388         
389         short scrollback= RNA_boolean_get(op->ptr, "scrollback");
390         short history= RNA_boolean_get(op->ptr, "history");
391         
392         /*ConsoleLine *ci= */ console_history_verify(C);
393         
394         if(scrollback) { /* last item in mistory */
395                 while(sc->scrollback.first)
396                         console_scrollback_free(sc, sc->scrollback.first);
397         }
398         
399         if(history) {
400                 while(sc->history.first)
401                         console_history_free(sc, sc->history.first);
402         }
403         
404         ED_area_tag_redraw(CTX_wm_area(C));
405         
406         return OPERATOR_FINISHED;
407 }
408
409 void CONSOLE_OT_clear(wmOperatorType *ot)
410 {
411         /* identifiers */
412         ot->name= "Clear";
413         ot->idname= "CONSOLE_OT_clear";
414         
415         /* api callbacks */
416         ot->exec= clear_exec;
417         ot->poll= console_edit_poll;
418
419         /* flags */
420         ot->flag= OPTYPE_REGISTER;
421         
422         /* properties */
423         RNA_def_boolean(ot->srna, "scrollback", 1, "Scrollback", "Clear the scrollback history");
424         RNA_def_boolean(ot->srna, "history", 0, "History", "Clear the command history");
425 }
426
427
428
429 /* the python exec operator uses this */
430 static int history_cycle_exec(bContext *C, wmOperator *op)
431 {
432         SpaceConsole *sc= CTX_wm_space_console(C);
433         ConsoleLine *ci= console_history_verify(C); /* TODO - stupid, just prevernts crashes when no command line */
434         
435         short reverse= RNA_boolean_get(op->ptr, "reverse"); /* assumes down, reverse is up */
436         
437         if(reverse) { /* last item in mistory */
438                 ci= sc->history.last;
439                 BLI_remlink(&sc->history, ci);
440                 BLI_addhead(&sc->history, ci);
441         }
442         else {
443                 ci= sc->history.first;
444                 BLI_remlink(&sc->history, ci);
445                 BLI_addtail(&sc->history, ci);
446         }
447         
448         ED_area_tag_redraw(CTX_wm_area(C));
449         
450         return OPERATOR_FINISHED;
451 }
452
453 void CONSOLE_OT_history_cycle(wmOperatorType *ot)
454 {
455         /* identifiers */
456         ot->name= "History Cycle";
457         ot->idname= "CONSOLE_OT_history_cycle";
458         
459         /* api callbacks */
460         ot->exec= history_cycle_exec;
461         ot->poll= console_edit_poll;
462
463         /* flags */
464         ot->flag= OPTYPE_REGISTER;
465         
466         /* properties */
467         RNA_def_boolean(ot->srna, "reverse", 0, "Reverse", "reverse cycle history");
468 }
469
470
471 /* the python exec operator uses this */
472 static int history_append_exec(bContext *C, wmOperator *op)
473 {
474         ConsoleLine *ci= console_history_verify(C);
475         
476         
477         char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); /* own this text in the new line, dont free */
478         int cursor= RNA_int_get(op->ptr, "current_character");
479         
480         ci= console_history_add_str(C, str, 1); /* own the string */
481         console_line_cursor_set(ci, cursor);
482         
483         ED_area_tag_redraw(CTX_wm_area(C));
484         
485         return OPERATOR_FINISHED;
486 }
487
488 void CONSOLE_OT_history_append(wmOperatorType *ot)
489 {
490         /* identifiers */
491         ot->name= "History Append";
492         ot->idname= "CONSOLE_OT_history_append";
493         
494         /* api callbacks */
495         ot->exec= history_append_exec;
496         ot->poll= console_edit_poll;
497
498         /* flags */
499         ot->flag= OPTYPE_REGISTER;
500         
501         /* properties */
502         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");      
503         RNA_def_int(ot->srna, "current_character", 0, 0, INT_MAX, "Cursor", "The index of the cursor.", 0, 10000);
504 }
505
506
507 /* the python exec operator uses this */
508 static int scrollback_append_exec(bContext *C, wmOperator *op)
509 {
510         SpaceConsole *sc= CTX_wm_space_console(C);
511         ConsoleLine *ci= console_history_verify(C);
512         
513         char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); /* own this text in the new line, dont free */
514         int type= RNA_enum_get(op->ptr, "type");
515         
516         ci= console_scrollback_add_str(C, str, 1); /* own the string */
517         ci->type= type;
518         
519         console_scrollback_limit(sc);
520         
521         ED_area_tag_redraw(CTX_wm_area(C));
522         
523         return OPERATOR_FINISHED;
524 }
525
526 void CONSOLE_OT_scrollback_append(wmOperatorType *ot)
527 {
528         /* defined in DNA_space_types.h */
529         static EnumPropertyItem console_line_type_items[] = {
530                 {CONSOLE_LINE_OUTPUT,   "OUTPUT", 0, "Output", ""},
531                 {CONSOLE_LINE_INPUT,    "INPUT", 0, "Input", ""},
532                 {CONSOLE_LINE_INFO,             "INFO", 0, "Information", ""},
533                 {CONSOLE_LINE_ERROR,    "ERROR", 0, "Error", ""},
534                 {0, NULL, 0, NULL, NULL}};
535
536         /* identifiers */
537         ot->name= "Scrollback Append";
538         ot->idname= "CONSOLE_OT_scrollback_append";
539         
540         /* api callbacks */
541         ot->exec= scrollback_append_exec;
542         ot->poll= console_edit_poll;
543
544         /* flags */
545         ot->flag= OPTYPE_REGISTER;
546         
547         /* properties */
548         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");      
549         RNA_def_enum(ot->srna, "type", console_line_type_items, CONSOLE_LINE_OUTPUT, "Type", "Console output type.");
550 }
551
552 static int zoom_exec(bContext *C, wmOperator *op)
553 {
554         SpaceConsole *sc= CTX_wm_space_console(C);
555         
556         int delta= RNA_int_get(op->ptr, "delta");
557         
558         sc->lheight += delta;
559         CLAMP(sc->lheight, 8, 32);
560         
561         ED_area_tag_redraw(CTX_wm_area(C));
562         
563         return OPERATOR_FINISHED;
564 }
565
566
567 void CONSOLE_OT_zoom(wmOperatorType *ot)
568 {
569         /* identifiers */
570         ot->name= "Console Zoom";
571         ot->idname= "CONSOLE_OT_zoom";
572         
573         /* api callbacks */
574         ot->exec= zoom_exec;
575
576         /* flags */
577         /* ot->flag= OPTYPE_REGISTER; */ /* super annoying */
578         
579         /* properties */
580         RNA_def_int(ot->srna, "delta", 0, 0, INT_MAX, "Delta", "Scale the view font.", 0, 1000);
581 }
582
583 /* Dummy operators, python will replace these, so blender can start without any errors */
584 void CONSOLE_OT_exec(wmOperatorType *ot)
585 {
586         /* identifiers */
587         ot->name= "CONSOLE_OT_exec dummy";
588         ot->idname= "CONSOLE_OT_exec";
589 }
590 void CONSOLE_OT_autocomplete(wmOperatorType *ot)
591 {
592         /* identifiers */
593         ot->name= "CONSOLE_OT_autocomplete dummy";
594         ot->idname= "CONSOLE_OT_autocomplete";
595 }