Blender  V2.59
console_ops.c
Go to the documentation of this file.
00001 /*
00002  * $Id: console_ops.c 37650 2011-06-20 03:10:02Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * Contributor(s): Campbell Barton
00021  *
00022  * ***** END GPL LICENSE BLOCK *****
00023  */
00024 
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <ctype.h> /* ispunct */
00033 #include <sys/stat.h>
00034 
00035 #include "MEM_guardedalloc.h"
00036 
00037 #include "DNA_userdef_types.h"
00038 
00039 #include "BLI_blenlib.h"
00040 #include "BLI_dynstr.h"
00041 #include "BLI_utildefines.h"
00042 
00043 #include "BKE_context.h"
00044 #include "BKE_text.h" /* only for character utility funcs */
00045 
00046 #include "WM_api.h"
00047 #include "WM_types.h"
00048 
00049 #include "UI_view2d.h"
00050 #include "ED_screen.h"
00051 
00052 #include "RNA_access.h"
00053 #include "RNA_define.h"
00054 
00055 #include "console_intern.h"
00056 
00057 static void console_textview_update_rect(SpaceConsole *sc, ARegion *ar)
00058 {
00059         View2D *v2d= &ar->v2d;
00060 
00061         UI_view2d_totRect_set(v2d, ar->winx-1, console_textview_height(sc, ar));
00062 }
00063 
00064 static void console_select_offset(SpaceConsole *sc, const int offset)
00065 {
00066         sc->sel_start += offset;
00067         sc->sel_end += offset;
00068 }
00069 
00070 void console_history_free(SpaceConsole *sc, ConsoleLine *cl)
00071 {
00072         BLI_remlink(&sc->history, cl);
00073         MEM_freeN(cl->line);
00074         MEM_freeN(cl);
00075 }
00076 void console_scrollback_free(SpaceConsole *sc, ConsoleLine *cl)
00077 {
00078         BLI_remlink(&sc->scrollback, cl);
00079         MEM_freeN(cl->line);
00080         MEM_freeN(cl);
00081 }
00082 
00083 static void console_scrollback_limit(SpaceConsole *sc)
00084 {
00085         int tot;
00086         
00087         if (U.scrollback < 32) U.scrollback= 256; // XXX - save in user defaults
00088         
00089         for(tot= BLI_countlist(&sc->scrollback); tot > U.scrollback; tot--)
00090                 console_scrollback_free(sc, sc->scrollback.first);
00091 }
00092 
00093 static ConsoleLine * console_history_find(SpaceConsole *sc, const char *str, ConsoleLine *cl_ignore)
00094 {
00095         ConsoleLine *cl;
00096 
00097         for(cl= sc->history.last; cl; cl= cl->prev) {
00098                 if (cl==cl_ignore)
00099                         continue;
00100 
00101                 if(strcmp(str, cl->line)==0)
00102                         return cl;
00103         }
00104 
00105         return NULL;
00106 }
00107 
00108 /* return 0 if no change made, clamps the range */
00109 static int console_line_cursor_set(ConsoleLine *cl, int cursor)
00110 {
00111         int cursor_new;
00112         
00113         if(cursor < 0)                          cursor_new= 0;
00114         else if(cursor > cl->len)       cursor_new= cl->len;
00115         else                                            cursor_new= cursor;
00116         
00117         if(cursor_new == cl->cursor)
00118                 return 0;
00119         
00120         cl->cursor= cursor_new;
00121         return 1;
00122 }
00123 
00124 static char cursor_char(ConsoleLine *cl)
00125 {
00126         /* assume cursor is clamped */
00127         return cl->line[cl->cursor];
00128 }
00129 
00130 static char cursor_char_prev(ConsoleLine *cl)
00131 {
00132         /* assume cursor is clamped */
00133         if(cl->cursor <= 0)
00134                 return '\0';
00135 
00136         return cl->line[cl->cursor-1];
00137 }
00138 
00139 #if 0 // XXX unused 
00140 static char cursor_char_next(ConsoleLine *cl)
00141 {
00142         /* assume cursor is clamped */
00143         if(cl->cursor + 1 >= cl->len)
00144                 return '\0';
00145 
00146         return cl->line[cl->cursor+1];
00147 }
00148 
00149 static void console_lb_debug__internal(ListBase *lb)
00150 {
00151         ConsoleLine *cl;
00152 
00153         printf("%d: ", BLI_countlist(lb));
00154         for(cl= lb->first; cl; cl= cl->next)
00155                 printf("<%s> ", cl->line);
00156         printf("\n");
00157 
00158 }
00159 
00160 static void console_history_debug(const bContext *C)
00161 {
00162         SpaceConsole *sc= CTX_wm_space_console(C);
00163 
00164         
00165         console_lb_debug__internal(&sc->history);
00166 }
00167 #endif
00168 
00169 static ConsoleLine *console_lb_add__internal(ListBase *lb, ConsoleLine *from)
00170 {
00171         ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add");
00172         
00173         if(from) {
00174                 ci->line= BLI_strdup(from->line);
00175                 ci->len= strlen(ci->line);
00176                 ci->len_alloc= ci->len;
00177                 
00178                 ci->cursor= from->cursor;
00179                 ci->type= from->type;
00180         } else {
00181                 ci->line= MEM_callocN(64, "console-in-line");
00182                 ci->len_alloc= 64;
00183                 ci->len= 0;
00184         }
00185         
00186         BLI_addtail(lb, ci);
00187         return ci;
00188 }
00189 
00190 static ConsoleLine *console_history_add(const bContext *C, ConsoleLine *from)
00191 {
00192         SpaceConsole *sc= CTX_wm_space_console(C);
00193         
00194         return console_lb_add__internal(&sc->history, from);
00195 }
00196 
00197 #if 0 /* may use later ? */
00198 static ConsoleLine *console_scrollback_add(const bContext *C, ConsoleLine *from)
00199 {
00200         SpaceConsole *sc= CTX_wm_space_console(C);
00201         
00202         return console_lb_add__internal(&sc->scrollback, from);
00203 }
00204 #endif
00205 
00206 static ConsoleLine *console_lb_add_str__internal(ListBase *lb, char *str, int own)
00207 {
00208         ConsoleLine *ci= MEM_callocN(sizeof(ConsoleLine), "ConsoleLine Add");
00209         if(own)         ci->line= str;
00210         else            ci->line= BLI_strdup(str);
00211         
00212         ci->len = ci->len_alloc = strlen(str);
00213         
00214         BLI_addtail(lb, ci);
00215         return ci;
00216 }
00217 ConsoleLine *console_history_add_str(SpaceConsole *sc, char *str, int own)
00218 {
00219         return console_lb_add_str__internal(&sc->history, str, own);
00220 }
00221 ConsoleLine *console_scrollback_add_str(SpaceConsole *sc, char *str, int own)
00222 {
00223         ConsoleLine *ci= console_lb_add_str__internal(&sc->scrollback, str, own);
00224         console_select_offset(sc, ci->len + 1);
00225         return ci;
00226 }
00227 
00228 ConsoleLine *console_history_verify(const bContext *C)
00229 {
00230         SpaceConsole *sc= CTX_wm_space_console(C);
00231         ConsoleLine *ci= sc->history.last;
00232         if(ci==NULL)
00233                 ci= console_history_add(C, NULL);
00234         
00235         return ci;
00236 }
00237 
00238 
00239 static void console_line_verify_length(ConsoleLine *ci, int len)
00240 {
00241         /* resize the buffer if needed */
00242         if(len >= ci->len_alloc) {
00243                 int new_len= len * 2; /* new length */
00244                 char *new_line= MEM_callocN(new_len, "console line");
00245                 memcpy(new_line, ci->line, ci->len);
00246                 MEM_freeN(ci->line);
00247                 
00248                 ci->line= new_line;
00249                 ci->len_alloc= new_len;
00250         }
00251 }
00252 
00253 static int console_line_insert(ConsoleLine *ci, char *str)
00254 {
00255         int len = strlen(str);
00256         
00257         if(len>0 && str[len-1]=='\n') {/* stop new lines being pasted at the end of lines */
00258                 str[len-1]= '\0';
00259                 len--;
00260         }
00261 
00262         if(len==0)
00263                 return 0;
00264         
00265         console_line_verify_length(ci, len + ci->len);
00266         
00267         memmove(ci->line+ci->cursor+len, ci->line+ci->cursor, (ci->len - ci->cursor)+1);
00268         memcpy(ci->line+ci->cursor, str, len);
00269         
00270         ci->len += len;
00271         ci->cursor += len;
00272         
00273         return len;
00274 }
00275 
00276 /* static funcs for text editing */
00277 
00278 /* similar to the text editor, with some not used. keep compatible */
00279 static EnumPropertyItem move_type_items[]= {
00280         {LINE_BEGIN, "LINE_BEGIN", 0, "Line Begin", ""},
00281         {LINE_END, "LINE_END", 0, "Line End", ""},
00282         {PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
00283         {NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
00284         {PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
00285         {NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
00286         {0, NULL, 0, NULL, NULL}};
00287 
00288 static int move_exec(bContext *C, wmOperator *op)
00289 {
00290         ConsoleLine *ci= console_history_verify(C);
00291         
00292         int type= RNA_enum_get(op->ptr, "type");
00293         int done= 0;
00294         
00295         switch(type) {
00296         case LINE_BEGIN:
00297                 done= console_line_cursor_set(ci, 0);
00298                 break;
00299         case LINE_END:
00300                 done= console_line_cursor_set(ci, INT_MAX);
00301                 break;
00302         case PREV_CHAR:
00303                 done= console_line_cursor_set(ci, ci->cursor-1);
00304                 break;
00305         case NEXT_CHAR:
00306                 done= console_line_cursor_set(ci, ci->cursor+1);
00307                 break;
00308 
00309         /* - if the character is a delimiter then skip delimiters (including white space)
00310          * - when jump over the word */
00311         case PREV_WORD:
00312                 while(text_check_delim(cursor_char_prev(ci)))
00313                         if(console_line_cursor_set(ci, ci->cursor-1)==FALSE)
00314                                 break;
00315 
00316                 while(text_check_delim(cursor_char_prev(ci))==FALSE)
00317                         if(console_line_cursor_set(ci, ci->cursor-1)==FALSE)
00318                                 break;
00319 
00320                 /* This isnt used for NEXT_WORD because when going back
00321                  * its more useful to have the cursor directly after a word then whitespace */
00322                 while(text_check_whitespace(cursor_char_prev(ci))==TRUE)
00323                         if(console_line_cursor_set(ci, ci->cursor-1)==FALSE)
00324                                 break;
00325 
00326                 done= 1; /* assume changed */
00327                 break;
00328         case NEXT_WORD:
00329                 while(text_check_delim(cursor_char(ci))==TRUE)
00330                         if (console_line_cursor_set(ci, ci->cursor+1)==FALSE)
00331                                 break;
00332 
00333                 while(text_check_delim(cursor_char(ci))==FALSE)
00334                         if (console_line_cursor_set(ci, ci->cursor+1)==FALSE)
00335                                 break;
00336 
00337                 done= 1; /* assume changed */
00338                 break;
00339         }
00340         
00341         if(done) {
00342                 ED_area_tag_redraw(CTX_wm_area(C));
00343         }
00344         
00345         return OPERATOR_FINISHED;
00346 }
00347 
00348 void CONSOLE_OT_move(wmOperatorType *ot)
00349 {
00350         /* identifiers */
00351         ot->name= "Move Cursor";
00352         ot->description= "Move cursor position";
00353         ot->idname= "CONSOLE_OT_move";
00354         
00355         /* api callbacks */
00356         ot->exec= move_exec;
00357         ot->poll= ED_operator_console_active;
00358 
00359         /* properties */
00360         RNA_def_enum(ot->srna, "type", move_type_items, LINE_BEGIN, "Type", "Where to move cursor to.");
00361 }
00362 
00363 #define TAB_LENGTH 4
00364 static int insert_exec(bContext *C, wmOperator *op)
00365 {
00366         SpaceConsole *sc= CTX_wm_space_console(C);
00367         ARegion *ar= CTX_wm_region(C);
00368         ConsoleLine *ci= console_history_verify(C);
00369         char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0);
00370         int len;
00371 
00372         // XXX, alligned tab key hack
00373         if(str[0]=='\t' && str[1]=='\0') {
00374                 len= TAB_LENGTH - (ci->cursor % TAB_LENGTH);
00375                 MEM_freeN(str);
00376                 str= MEM_mallocN(len + 1, "insert_exec");
00377                 memset(str, ' ', len);
00378                 str[len]= '\0';
00379         }
00380 
00381         len= console_line_insert(ci, str);
00382         
00383         MEM_freeN(str);
00384         
00385         if(len==0) {
00386                 return OPERATOR_CANCELLED;
00387         }
00388         else {
00389                 console_select_offset(sc, len);
00390         }
00391 
00392         console_textview_update_rect(sc, ar);
00393         ED_area_tag_redraw(CTX_wm_area(C));
00394         
00395         return OPERATOR_FINISHED;
00396 }
00397 
00398 static int insert_invoke(bContext *C, wmOperator *op, wmEvent *event)
00399 {
00400         // if(!RNA_property_is_set(op->ptr, "text")) { /* always set from keymap XXX */
00401         if(!RNA_string_length(op->ptr, "text")) {
00402                 /* if alt/ctrl/super are pressed pass through */
00403                 if(event->ctrl || event->oskey) {
00404                         return OPERATOR_PASS_THROUGH;
00405                 }
00406                 else {
00407                         char str[2];
00408                         str[0]= event->ascii;
00409                         str[1]= '\0';
00410 
00411                         RNA_string_set(op->ptr, "text", str);
00412                 }
00413         }
00414         return insert_exec(C, op);
00415 }
00416 
00417 void CONSOLE_OT_insert(wmOperatorType *ot)
00418 {
00419         /* identifiers */
00420         ot->name= "Insert";
00421         ot->description= "Insert text at cursor position";
00422         ot->idname= "CONSOLE_OT_insert";
00423         
00424         /* api callbacks */
00425         ot->exec= insert_exec;
00426         ot->invoke= insert_invoke;
00427         ot->poll= ED_operator_console_active;
00428 
00429         /* properties */
00430         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");
00431 }
00432 
00433 
00434 static EnumPropertyItem delete_type_items[]= {
00435         {DEL_NEXT_CHAR, "NEXT_CHARACTER", 0, "Next Character", ""},
00436         {DEL_PREV_CHAR, "PREVIOUS_CHARACTER", 0, "Previous Character", ""},
00437 //      {DEL_NEXT_WORD, "NEXT_WORD", 0, "Next Word", ""},
00438 //      {DEL_PREV_WORD, "PREVIOUS_WORD", 0, "Previous Word", ""},
00439         {0, NULL, 0, NULL, NULL}};
00440 
00441 static int delete_exec(bContext *C, wmOperator *op)
00442 {
00443         SpaceConsole *sc= CTX_wm_space_console(C);
00444         ARegion *ar= CTX_wm_region(C);
00445         ConsoleLine *ci= console_history_verify(C);
00446 
00447         const short type= RNA_enum_get(op->ptr, "type");
00448         int done = 0;
00449         
00450         if(ci->len==0) {
00451                 return OPERATOR_CANCELLED;
00452         }
00453         
00454         switch(type) {
00455         case DEL_NEXT_CHAR:
00456                 if(ci->cursor < ci->len) {
00457                         memmove(ci->line + ci->cursor, ci->line + ci->cursor+1, (ci->len - ci->cursor)+1);
00458                         ci->len--;
00459                         done= 1;
00460                 }
00461                 break;
00462         case DEL_PREV_CHAR:
00463                 if(ci->cursor > 0) {
00464                         ci->cursor--; /* same as above */
00465                         memmove(ci->line + ci->cursor, ci->line + ci->cursor+1, (ci->len - ci->cursor)+1);
00466                         ci->len--;
00467                         done= 1;
00468                 }
00469                 break;
00470         }
00471         
00472         if(!done) {
00473                 return OPERATOR_CANCELLED;
00474         }
00475         else {
00476                 console_select_offset(sc, -1);
00477         }
00478 
00479         console_textview_update_rect(sc, ar);
00480         ED_area_tag_redraw(CTX_wm_area(C));
00481         
00482         return OPERATOR_FINISHED;
00483 }
00484 
00485 
00486 void CONSOLE_OT_delete(wmOperatorType *ot)
00487 {
00488         /* identifiers */
00489         ot->name= "Delete";
00490         ot->description= "Delete text by cursor position";
00491         ot->idname= "CONSOLE_OT_delete";
00492         
00493         /* api callbacks */
00494         ot->exec= delete_exec;
00495         ot->poll= ED_operator_console_active;
00496 
00497         /* properties */
00498         RNA_def_enum(ot->srna, "type", delete_type_items, DEL_NEXT_CHAR, "Type", "Which part of the text to delete.");
00499 }
00500 
00501 
00502 /* the python exec operator uses this */
00503 static int clear_exec(bContext *C, wmOperator *op)
00504 {
00505         SpaceConsole *sc= CTX_wm_space_console(C);
00506         ARegion *ar= CTX_wm_region(C);
00507         
00508         short scrollback= RNA_boolean_get(op->ptr, "scrollback");
00509         short history= RNA_boolean_get(op->ptr, "history");
00510         
00511         /*ConsoleLine *ci= */ console_history_verify(C);
00512         
00513         if(scrollback) { /* last item in mistory */
00514                 while(sc->scrollback.first)
00515                         console_scrollback_free(sc, sc->scrollback.first);
00516         }
00517         
00518         if(history) {
00519                 while(sc->history.first)
00520                         console_history_free(sc, sc->history.first);
00521         }
00522 
00523         console_textview_update_rect(sc, ar);
00524         ED_area_tag_redraw(CTX_wm_area(C));
00525 
00526         return OPERATOR_FINISHED;
00527 }
00528 
00529 void CONSOLE_OT_clear(wmOperatorType *ot)
00530 {
00531         /* identifiers */
00532         ot->name= "Clear";
00533         ot->description= "Clear text by type";
00534         ot->idname= "CONSOLE_OT_clear";
00535         
00536         /* api callbacks */
00537         ot->exec= clear_exec;
00538         ot->poll= ED_operator_console_active;
00539         
00540         /* properties */
00541         RNA_def_boolean(ot->srna, "scrollback", 1, "Scrollback", "Clear the scrollback history");
00542         RNA_def_boolean(ot->srna, "history", 0, "History", "Clear the command history");
00543 }
00544 
00545 
00546 
00547 /* the python exec operator uses this */
00548 static int history_cycle_exec(bContext *C, wmOperator *op)
00549 {
00550         SpaceConsole *sc= CTX_wm_space_console(C);
00551         ARegion *ar= CTX_wm_region(C);
00552 
00553         ConsoleLine *ci= console_history_verify(C); /* TODO - stupid, just prevernts crashes when no command line */
00554         short reverse= RNA_boolean_get(op->ptr, "reverse"); /* assumes down, reverse is up */
00555         int prev_len= ci->len;
00556 
00557         /* keep a copy of the line above so when history is cycled
00558          * this is the only function that needs to know about the double-up */
00559         if(ci->prev) {
00560                 ConsoleLine *ci_prev= (ConsoleLine *)ci->prev;
00561 
00562                 if(strcmp(ci->line, ci_prev->line)==0)
00563                         console_history_free(sc, ci_prev);
00564         }
00565 
00566         if(reverse) { /* last item in mistory */
00567                 ci= sc->history.last;
00568                 BLI_remlink(&sc->history, ci);
00569                 BLI_addhead(&sc->history, ci);
00570         }
00571         else {
00572                 ci= sc->history.first;
00573                 BLI_remlink(&sc->history, ci);
00574                 BLI_addtail(&sc->history, ci);
00575         }
00576 
00577         {       /* add a duplicate of the new arg and remove all other instances */
00578                 ConsoleLine *cl;
00579                 while((cl= console_history_find(sc, ci->line, ci)))
00580                         console_history_free(sc, cl);
00581 
00582                 console_history_add(C, (ConsoleLine *)sc->history.last);
00583         }
00584         
00585         ci= sc->history.last;
00586         console_select_offset(sc, ci->len - prev_len);
00587 
00588         /* could be wrapped so update scroll rect */
00589         console_textview_update_rect(sc, ar);
00590         ED_area_tag_redraw(CTX_wm_area(C));
00591 
00592         return OPERATOR_FINISHED;
00593 }
00594 
00595 void CONSOLE_OT_history_cycle(wmOperatorType *ot)
00596 {
00597         /* identifiers */
00598         ot->name= "History Cycle";
00599         ot->description= "Cycle through history";
00600         ot->idname= "CONSOLE_OT_history_cycle";
00601         
00602         /* api callbacks */
00603         ot->exec= history_cycle_exec;
00604         ot->poll= ED_operator_console_active;
00605         
00606         /* properties */
00607         RNA_def_boolean(ot->srna, "reverse", 0, "Reverse", "reverse cycle history");
00608 }
00609 
00610 
00611 /* the python exec operator uses this */
00612 static int history_append_exec(bContext *C, wmOperator *op)
00613 {
00614         SpaceConsole *sc= CTX_wm_space_console(C);
00615         ScrArea *sa= CTX_wm_area(C);
00616         ConsoleLine *ci= console_history_verify(C);
00617         char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); /* own this text in the new line, dont free */
00618         int cursor= RNA_int_get(op->ptr, "current_character");
00619         short rem_dupes= RNA_boolean_get(op->ptr, "remove_duplicates");
00620         int prev_len= ci->len;
00621 
00622         if(rem_dupes) {
00623                 ConsoleLine *cl;
00624 
00625                 while((cl= console_history_find(sc, ci->line, ci)))
00626                         console_history_free(sc, cl);
00627 
00628                 if(strcmp(str, ci->line)==0) {
00629                         MEM_freeN(str);
00630                         return OPERATOR_FINISHED;
00631                 }
00632         }
00633 
00634         ci= console_history_add_str(sc, str, 1); /* own the string */
00635         console_select_offset(sc, ci->len - prev_len);
00636         console_line_cursor_set(ci, cursor);
00637 
00638         ED_area_tag_redraw(sa);
00639 
00640         return OPERATOR_FINISHED;
00641 }
00642 
00643 void CONSOLE_OT_history_append(wmOperatorType *ot)
00644 {
00645         /* identifiers */
00646         ot->name= "History Append";
00647         ot->description= "Append history at cursor position";
00648         ot->idname= "CONSOLE_OT_history_append";
00649         
00650         /* api callbacks */
00651         ot->exec= history_append_exec;
00652         ot->poll= ED_operator_console_active;
00653         
00654         /* properties */
00655         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");      
00656         RNA_def_int(ot->srna, "current_character", 0, 0, INT_MAX, "Cursor", "The index of the cursor.", 0, 10000);
00657         RNA_def_boolean(ot->srna, "remove_duplicates", 0, "Remove Duplicates", "Remove duplicate items in the history");
00658 }
00659 
00660 
00661 /* the python exec operator uses this */
00662 static int scrollback_append_exec(bContext *C, wmOperator *op)
00663 {
00664         SpaceConsole *sc= CTX_wm_space_console(C);
00665         ARegion *ar= CTX_wm_region(C);
00666         ConsoleLine *ci;
00667         
00668         char *str= RNA_string_get_alloc(op->ptr, "text", NULL, 0); /* own this text in the new line, dont free */
00669         int type= RNA_enum_get(op->ptr, "type");
00670 
00671         console_history_verify(C);
00672         
00673         ci= console_scrollback_add_str(sc, str, 1); /* own the string */
00674         ci->type= type;
00675         
00676         console_scrollback_limit(sc);
00677 
00678         console_textview_update_rect(sc, ar);
00679         ED_area_tag_redraw(CTX_wm_area(C));
00680         
00681         return OPERATOR_FINISHED;
00682 }
00683 
00684 void CONSOLE_OT_scrollback_append(wmOperatorType *ot)
00685 {
00686         /* defined in DNA_space_types.h */
00687         static EnumPropertyItem console_line_type_items[] = {
00688                 {CONSOLE_LINE_OUTPUT,   "OUTPUT", 0, "Output", ""},
00689                 {CONSOLE_LINE_INPUT,    "INPUT", 0, "Input", ""},
00690                 {CONSOLE_LINE_INFO,             "INFO", 0, "Information", ""},
00691                 {CONSOLE_LINE_ERROR,    "ERROR", 0, "Error", ""},
00692                 {0, NULL, 0, NULL, NULL}};
00693 
00694         /* identifiers */
00695         ot->name= "Scrollback Append";
00696         ot->description= "Append scrollback text by type";
00697         ot->idname= "CONSOLE_OT_scrollback_append";
00698         
00699         /* api callbacks */
00700         ot->exec= scrollback_append_exec;
00701         ot->poll= ED_operator_console_active;
00702         
00703         /* properties */
00704         RNA_def_string(ot->srna, "text", "", 0, "Text", "Text to insert at the cursor position.");      
00705         RNA_def_enum(ot->srna, "type", console_line_type_items, CONSOLE_LINE_OUTPUT, "Type", "Console output type.");
00706 }
00707 
00708 
00709 static int copy_exec(bContext *C, wmOperator *UNUSED(op))
00710 {
00711         SpaceConsole *sc= CTX_wm_space_console(C);
00712 
00713         DynStr *buf_dyn= BLI_dynstr_new();
00714         char *buf_str;
00715         
00716         ConsoleLine *cl;
00717         int sel[2];
00718         int offset= 0;
00719 
00720         ConsoleLine cl_dummy= {NULL};
00721 
00722 #if 0
00723         /* copy whole file */
00724         for(cl= sc->scrollback.first; cl; cl= cl->next) {
00725                 BLI_dynstr_append(buf_dyn, cl->line);
00726                 BLI_dynstr_append(buf_dyn, "\n");
00727         }
00728 #endif
00729 
00730         if(sc->sel_start == sc->sel_end)
00731                 return OPERATOR_CANCELLED;
00732 
00733         console_scrollback_prompt_begin(sc, &cl_dummy);
00734 
00735         for(cl= sc->scrollback.first; cl; cl= cl->next) {
00736                 offset += cl->len + 1;
00737         }
00738 
00739         if(offset==0) {
00740                 console_scrollback_prompt_end(sc, &cl_dummy);
00741                 return OPERATOR_CANCELLED;
00742         }
00743 
00744         offset -= 1;
00745         sel[0]= offset - sc->sel_end;
00746         sel[1]= offset - sc->sel_start;
00747 
00748         for(cl= sc->scrollback.first; cl; cl= cl->next) {
00749                 if(sel[0] <= cl->len && sel[1] >= 0) {
00750                         int sta= MAX2(sel[0], 0);
00751                         int end= MIN2(sel[1], cl->len);
00752 
00753                         if(BLI_dynstr_get_len(buf_dyn))
00754                                 BLI_dynstr_append(buf_dyn, "\n");
00755 
00756                         BLI_dynstr_nappend(buf_dyn, cl->line + sta, end - sta);
00757                 }
00758 
00759                 sel[0] -= cl->len + 1;
00760                 sel[1] -= cl->len + 1;
00761         }
00762 
00763         buf_str= BLI_dynstr_get_cstring(buf_dyn);
00764 
00765         BLI_dynstr_free(buf_dyn);
00766         WM_clipboard_text_set(buf_str, 0);
00767 
00768         MEM_freeN(buf_str);
00769 
00770         console_scrollback_prompt_end(sc, &cl_dummy);
00771 
00772         return OPERATOR_FINISHED;
00773 }
00774 
00775 void CONSOLE_OT_copy(wmOperatorType *ot)
00776 {
00777         /* identifiers */
00778         ot->name= "Copy to Clipboard";
00779         ot->description= "Copy selected text to clipboard";
00780         ot->idname= "CONSOLE_OT_copy";
00781 
00782         /* api callbacks */
00783         ot->poll= ED_operator_console_active;
00784         ot->exec= copy_exec;
00785 
00786         /* properties */
00787 }
00788 
00789 static int paste_exec(bContext *C, wmOperator *UNUSED(op))
00790 {
00791         SpaceConsole *sc= CTX_wm_space_console(C);
00792         ARegion *ar= CTX_wm_region(C);
00793         ConsoleLine *ci= console_history_verify(C);
00794 
00795         char *buf_str= WM_clipboard_text_get(0);
00796         char *buf_step, *buf_next;
00797 
00798         if(buf_str==NULL)
00799                 return OPERATOR_CANCELLED;
00800 
00801         buf_step= buf_str;
00802 
00803         while((buf_next=buf_step) && buf_next[0] != '\0') {
00804                 buf_step= strchr(buf_next, '\n');
00805                 if(buf_step) {
00806                         *buf_step= '\0';
00807                         buf_step++;
00808                 }
00809 
00810                 if(buf_next != buf_str) {
00811                         WM_operator_name_call(C, "CONSOLE_OT_execute", WM_OP_EXEC_DEFAULT, NULL);
00812                         ci= console_history_verify(C);
00813                 }
00814 
00815                 console_select_offset(sc, console_line_insert(ci, buf_next));
00816         }
00817 
00818         MEM_freeN(buf_str);
00819 
00820         console_textview_update_rect(sc, ar);
00821         ED_area_tag_redraw(CTX_wm_area(C));
00822 
00823         return OPERATOR_FINISHED;
00824 }
00825 
00826 void CONSOLE_OT_paste(wmOperatorType *ot)
00827 {
00828         /* identifiers */
00829         ot->name= "Paste from Clipboard";
00830         ot->description= "Paste text from clipboard";
00831         ot->idname= "CONSOLE_OT_paste";
00832 
00833         /* api callbacks */
00834         ot->poll= ED_operator_console_active;
00835         ot->exec= paste_exec;
00836 
00837         /* properties */
00838 }
00839 
00840 typedef struct SetConsoleCursor {
00841         int sel_old[2];
00842         int sel_init;
00843 } SetConsoleCursor;
00844 
00845 // TODO, cursor placement without selection
00846 static void set_cursor_to_pos(SpaceConsole *sc, ARegion *ar, SetConsoleCursor *scu, int mval[2], int UNUSED(sel))
00847 {
00848         int pos;
00849         pos= console_char_pick(sc, ar, mval);
00850 
00851         if(scu->sel_init == INT_MAX) {
00852                 scu->sel_init= pos;
00853                 sc->sel_start = sc->sel_end = pos;
00854                 return;
00855         }
00856 
00857         if (pos < scu->sel_init) {
00858                 sc->sel_start = pos;
00859                 sc->sel_end = scu->sel_init;
00860         }
00861         else if (pos > sc->sel_start) {
00862                 sc->sel_start = scu->sel_init;
00863                 sc->sel_end = pos;
00864         }
00865         else {
00866                 sc->sel_start = sc->sel_end = pos;
00867         }
00868 }
00869 
00870 static void console_modal_select_apply(bContext *C, wmOperator *op, wmEvent *event)
00871 {
00872         SpaceConsole *sc= CTX_wm_space_console(C);
00873         ARegion *ar= CTX_wm_region(C);
00874         SetConsoleCursor *scu= op->customdata;
00875         int mval[2];
00876         int sel_prev[2];
00877 
00878         mval[0]= event->mval[0];
00879         mval[1]= event->mval[1];
00880 
00881         sel_prev[0]= sc->sel_start;
00882         sel_prev[1]= sc->sel_end;
00883         
00884         set_cursor_to_pos(sc, ar, scu, mval, TRUE);
00885 
00886         /* only redraw if the selection changed */
00887         if(sel_prev[0] != sc->sel_start || sel_prev[1] != sc->sel_end) {
00888                 ED_area_tag_redraw(CTX_wm_area(C));
00889         }
00890 }
00891 
00892 static void set_cursor_exit(bContext *UNUSED(C), wmOperator *op)
00893 {
00894 //      SpaceConsole *sc= CTX_wm_space_console(C);
00895         SetConsoleCursor *scu= op->customdata;
00896 
00897         /*
00898         if(txt_has_sel(text)) {
00899                 buffer = txt_sel_to_buf(text);
00900                 WM_clipboard_text_set(buffer, 1);
00901                 MEM_freeN(buffer);
00902         }*/
00903 
00904         MEM_freeN(scu);
00905 }
00906 
00907 static int console_modal_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
00908 {
00909         SpaceConsole *sc= CTX_wm_space_console(C);
00910 //      ARegion *ar= CTX_wm_region(C);
00911         SetConsoleCursor *scu;
00912 
00913         op->customdata= MEM_callocN(sizeof(SetConsoleCursor), "SetConsoleCursor");
00914         scu= op->customdata;
00915 
00916         scu->sel_old[0]= sc->sel_start;
00917         scu->sel_old[1]= sc->sel_end;
00918 
00919         scu->sel_init = INT_MAX;
00920 
00921         WM_event_add_modal_handler(C, op);
00922 
00923         console_modal_select_apply(C, op, event);
00924 
00925         return OPERATOR_RUNNING_MODAL;
00926 }
00927 
00928 static int console_modal_select(bContext *C, wmOperator *op, wmEvent *event)
00929 {
00930         switch(event->type) {
00931                 case LEFTMOUSE:
00932                 case MIDDLEMOUSE:
00933                 case RIGHTMOUSE:
00934                         set_cursor_exit(C, op);
00935                         return OPERATOR_FINISHED;
00936                 case MOUSEMOVE:
00937                         console_modal_select_apply(C, op, event);
00938                         break;
00939         }
00940 
00941         return OPERATOR_RUNNING_MODAL;
00942 }
00943 
00944 static int console_modal_select_cancel(bContext *C, wmOperator *op)
00945 {
00946         set_cursor_exit(C, op);
00947         return OPERATOR_FINISHED;
00948 }
00949 
00950 void CONSOLE_OT_select_set(wmOperatorType *ot)
00951 {
00952         /* identifiers */
00953         ot->name= "Set Selection";
00954         ot->idname= "CONSOLE_OT_select_set";
00955         ot->description= "Set the console selection";
00956 
00957         /* api callbacks */
00958         ot->invoke= console_modal_select_invoke;
00959         ot->modal= console_modal_select;
00960         ot->cancel= console_modal_select_cancel;
00961         ot->poll= ED_operator_console_active;
00962 }