static gchar *console_get_current_line (GtkTextBuffer *buf, GtkTextIter *iter) { GtkTextIter start, end; start = end = *iter; gtk_text_iter_set_line_index(&start, 2); gtk_text_iter_forward_to_line_end(&end); return gtk_text_buffer_get_text(buf, &start, &end, FALSE); }
/* vers=0: right == NOOPS*/ static void doc_shift_selection( Tdocument *doc, gboolean vers ) { GtkTextIter itstart, itend; if ( gtk_text_buffer_get_selection_bounds( doc->buffer, &itstart, &itend ) ) { GtkTextMark * end; doc_unbind_signals( doc ); doc_unre_new_group( doc ); /* we have a selection, now we loop trough the characters, and for every newline we add or remove a tab, we set the end with a mark */ end = gtk_text_buffer_create_mark( doc->buffer, NULL, &itend, TRUE ); /* set to: the fist char of the fist line */ if ( gtk_text_iter_get_line_offset( &itstart ) > 0 ) { gtk_text_iter_set_line_index( &itstart, 0 ); } /* remove one line from current selection for each step*/ while ( gtk_text_iter_compare( &itstart, &itend ) < 0 ) { GtkTextMark * cur; cur = gtk_text_buffer_create_mark( doc->buffer, NULL, &itstart, TRUE ); if ( vers ) { itend = itstart; gtk_text_iter_forward_chars( &itend, 1 ); gchar *buf = gtk_text_buffer_get_text( doc->buffer, &itstart, &itend, FALSE ); if ( !strstr( buf, "\n" ) ) { gint offsetstart, offsetend; offsetstart = gtk_text_iter_get_offset( &itstart ); offsetend = gtk_text_iter_get_offset( &itend ); gtk_text_buffer_delete( doc->buffer, &itstart, &itend ); doc_unre_add( doc, buf, offsetstart, offsetend, UndoDelete ); } g_free( buf ); } gtk_text_buffer_get_iter_at_mark( doc->buffer, &itstart, cur ); gtk_text_buffer_get_iter_at_mark( doc->buffer, &itend, end ); gtk_text_buffer_delete_mark( doc->buffer, cur ); /* forward one more line */ gtk_text_iter_forward_line( &itstart ); } gtk_text_buffer_delete_mark( doc->buffer, end ); doc_bind_signals( doc ); doc_set_modified( doc, 1 ); } else { /* there is no selection, work on the current line */ GtkTextIter iter; gtk_text_buffer_get_iter_at_mark( doc->buffer, &iter, gtk_text_buffer_get_insert( doc->buffer ) ); if ( vers ) { GtkTextIter itend; gtk_text_iter_set_line_offset( &iter, 0 ); itend = iter; gtk_text_iter_forward_chars( &itend, 1 ); gtk_text_buffer_delete( doc->buffer, &iter, &itend ); } } }
/* original version taken from bluefish's (doc_indent_selection) */ gint func_indent( GtkWidget *widget, GdkEventKey *kevent, Tbfwin *bfwin, gint opt) { Tdocument *doc = bfwin->current_document; if (!doc) return 0; gint unindent = opt & FUNC_VALUE_0; GtkTextIter itstart, itend; if ( gtk_text_buffer_get_selection_bounds( doc->buffer, &itstart, &itend ) ) { GtkTextMark * end; doc_unbind_signals( doc ); doc_unre_new_group( doc ); /* we have a selection, now we loop trough the characters, and for every newline we add or remove a tab, we set the end with a mark */ end = gtk_text_buffer_create_mark( doc->buffer, NULL, &itend, TRUE ); if ( gtk_text_iter_get_line_offset( &itstart ) > 0 ) { gtk_text_iter_set_line_index( &itstart, 0 ); } while ( gtk_text_iter_compare( &itstart, &itend ) < 0 ) { GtkTextMark * cur; cur = gtk_text_buffer_create_mark( doc->buffer, NULL, &itstart, TRUE ); if ( unindent ) { /* when unindenting we try to set itend to the end of the indenting step which might be a tab or 'tabsize' spaces, then we delete that part */ gboolean cont = TRUE; gchar *buf = NULL; gunichar cchar = gtk_text_iter_get_char( &itstart ); if ( cchar == 9 ) { /* 9 is ascii for tab */ itend = itstart; cont = gtk_text_iter_forward_char( &itend ); buf = g_strdup( "\t" ); } else if ( cchar == 32 ) { /* 32 is ascii for space */ gint i = 0; itend = itstart; gtk_text_iter_forward_chars( &itend, main_v->props.editor_tab_width ); buf = gtk_text_buffer_get_text( doc->buffer, &itstart, &itend, FALSE ); DEBUG_MSG( "func_indent: tab_width=%d, strlen(buf)=%d, buf='%s'\n", main_v->props.editor_tab_width, strlen( buf ), buf ); while ( cont && buf[ i ] != '\0' ) { cont = ( buf[ i ] == ' ' ); DEBUG_MSG( "func_indent: buf[%d]='%c'\n", i, buf[ i ] ); i++; } if ( !cont ) { g_free ( buf ); } } else { cont = FALSE; } if ( cont ) { gint offsetstart, offsetend; offsetstart = gtk_text_iter_get_offset( &itstart ); offsetend = gtk_text_iter_get_offset( &itend ); gtk_text_buffer_delete( doc->buffer, &itstart, &itend ); doc_unre_add( doc, buf, offsetstart, offsetend, UndoDelete ); g_free ( buf ); } } else { /* indent */ gint offsetstart = gtk_text_iter_get_offset( &itstart ); gchar *indentstring; gint indentlen; if ( main_v->props.view_bars & MODE_INDENT_WITH_SPACES ) { indentstring = bf_str_repeat( " ", main_v->props.editor_tab_width ); indentlen = main_v->props.editor_tab_width; } else { indentstring = g_strdup( "\t" ); indentlen = 1; } gtk_text_buffer_insert( doc->buffer, &itstart, indentstring, indentlen ); doc_unre_add( doc, indentstring, offsetstart, offsetstart + indentlen, UndoInsert ); g_free( indentstring ); } gtk_text_buffer_get_iter_at_mark( doc->buffer, &itstart, cur ); gtk_text_buffer_get_iter_at_mark( doc->buffer, &itend, end ); gtk_text_buffer_delete_mark( doc->buffer, cur ); gtk_text_iter_forward_line( &itstart ); DEBUG_MSG( "func_indent: itstart at %d, itend at %d\n", gtk_text_iter_get_offset( &itstart ), gtk_text_iter_get_offset( &itend ) ); } gtk_text_buffer_delete_mark( doc->buffer, end ); doc_bind_signals( doc ); doc_set_modified( doc, 1 ); } else { /* there is no selection, work on the current line */ GtkTextIter iter; gtk_text_buffer_get_iter_at_mark( doc->buffer, &iter, gtk_text_buffer_get_insert( doc->buffer ) ); gtk_text_iter_set_line_offset( &iter, 0 ); if ( unindent ) { gint deletelen = 0; gchar *tmpstr, *tmp2str; GtkTextIter itend = iter; gtk_text_iter_forward_chars( &itend, main_v->props.editor_tab_width ); tmpstr = gtk_text_buffer_get_text( doc->buffer, &iter, &itend, FALSE ); tmp2str = bf_str_repeat( " ", main_v->props.editor_tab_width ); if ( tmpstr[ 0 ] == '\t' ) { deletelen = 1; } else if ( tmpstr && strncmp( tmpstr, tmp2str, main_v->props.editor_tab_width ) == 0 ) { deletelen = main_v->props.editor_tab_width; } g_free( tmpstr ); g_free( tmp2str ); if ( deletelen ) { itend = iter; gtk_text_iter_forward_chars( &itend, deletelen ); gtk_text_buffer_delete( doc->buffer, &iter, &itend ); } } else { /* indent */ gchar *indentstring; gint indentlen; if ( main_v->props.view_bars & MODE_INDENT_WITH_SPACES ) { indentstring = bf_str_repeat( " ", main_v->props.editor_tab_width ); indentlen = main_v->props.editor_tab_width; } else { indentstring = g_strdup( "\t" ); indentlen = 1; } gtk_text_buffer_insert( doc->buffer, &iter, indentstring, indentlen ); g_free( indentstring ); } } return 1; }
static gint console_key_handler (GtkWidget *cview, GdkEventKey *event, gpointer p) { guint keyval = event->keyval; guint upkey = gdk_keyval_to_upper(keyval); GtkTextIter ins, end; GtkTextBuffer *buf; GtkTextMark *mark; gint ctrl = 0; #ifdef MAC_NATIVE if (cmd_key(event)) { if (upkey == GDK_C || upkey == GDK_X) { /* allow regular copy/cut behavior */ return FALSE; } } #endif if (event->state & GDK_CONTROL_MASK) { if (keyval == GDK_Control_L || keyval == GDK_Control_R) { return FALSE; } else if (upkey == GDK_C || upkey == GDK_X) { /* allow regular copy/cut behavior */ return FALSE; } else { ctrl = 1; } } buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(cview)); /* first find out where the insertion point and end are */ mark = gtk_text_buffer_get_insert(buf); gtk_text_buffer_get_iter_at_mark(buf, &ins, mark); gtk_text_buffer_get_end_iter(buf, &end); /* if the insertion point is not on the last line, move it */ if (gtk_text_iter_get_line(&ins) != gtk_text_iter_get_line(&end)) { gtk_text_buffer_place_cursor(buf, &end); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(cview), TRUE); gtk_text_buffer_get_end_iter(buf, &ins); } if (keyval == GDK_Home && (event->state & GDK_SHIFT_MASK)) { /* "select to start of line" */ GtkTextIter start = ins; gtk_text_iter_set_line_index(&start, 2); gtk_text_buffer_select_range(buf, &start, &ins); return TRUE; } if (IS_BACKKEY(keyval)) { /* if we're at the start of the input line, block backspacing */ if (gtk_text_iter_get_line_index(&ins) < 3) { return TRUE; } } else if (keyval == GDK_Home || (ctrl && upkey == GDK_A)) { /* go to start of typing area */ gtk_text_iter_set_line_index(&ins, 2); gtk_text_buffer_place_cursor(buf, &ins); return TRUE; } /* At this point 'ins' indicates the insertion point and 'end' points to the end of the current line of input, These may or may not be the same thing. */ if (keyval == GDK_Return) { /* execute the command, unless backslash-continuation is happening */ ExecState *state; gchar *thisline; int contd = 0, err = 0; state = g_object_get_data(G_OBJECT(cview), "ExecState"); thisline = console_get_current_line(buf, &ins); if (thisline != NULL) { g_strstrip(thisline); contd = command_continues(state->line, thisline, &err); g_free(thisline); } if (err) { gui_errmsg(err); } else if (contd) { console_insert_prompt(buf, &end, "\n> "); console_scroll_to_end(cview, buf, &end); } else { /* request execution of the completed command */ command_entered = 1; } event->keyval = GDK_End; return FALSE; } if (keyval == GDK_Up || keyval == GDK_Down) { /* up/down arrows: navigate the command history */ GtkTextIter start = ins; const char *histline; if (hpos == hlines && keyval == GDK_Up) { g_free(hist0); hist0 = console_get_current_line(buf, &ins); } histline = fetch_history_line(keyval); if (histline != NULL || keyval == GDK_Down) { gtk_text_iter_set_line_index(&start, 2); gtk_text_buffer_delete(buf, &start, &end); if (histline != NULL) { gtk_text_buffer_insert(buf, &start, histline, -1); } else if (hpos == hlines && hist0 != NULL) { gtk_text_buffer_insert(buf, &start, hist0, -1); } } return TRUE; } if (keyval == GDK_Tab) { /* tab completion for gretl commands, variable names */ return console_complete_word(buf, &ins); } return FALSE; }