|
Blender
V2.59
|
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 }