/* Returns the line number of the previous marker that matches marker_mask, or -1. * marker_mask is a bitor of 1 << marker_index. (See MarkerHandleSet::MarkValue()). * Note: If there is a marker on the line, it returns the same line. */ gint sci_marker_previous(ScintillaObject *sci, gint line, gint marker_mask, gboolean wrap) { gint marker_line; marker_line = (gint) SSM(sci, SCI_MARKERPREVIOUS, (uptr_t) line, marker_mask); if (wrap && marker_line == -1) { gint len = sci_get_length(sci); gint last_line = sci_get_line_from_position(sci, len - 1); marker_line = (gint) SSM(sci, SCI_MARKERPREVIOUS, (uptr_t) last_line, marker_mask); } return marker_line; }
static void findMatchingClosingTag(ScintillaObject *sci, gchar *tagName, gint closingBracket) { gint pos; gint linesInDocument = sci_get_line_count(sci); gint endOfDocument = sci_get_position_from_line(sci, linesInDocument); gint openingTagsCount = 1; gint closingTagsCount = 0; for(pos=closingBracket; pos<endOfDocument; pos++) { /* are we inside tag? */ gint lineNumber = sci_get_line_from_position(sci, pos); gint lineEnd = sci_get_line_end_position(sci, lineNumber); gint matchingOpeningBracket = findBracket(sci, pos, lineEnd, '<', '\0', TRUE); gint matchingClosingBracket = findBracket(sci, pos, lineEnd, '>', '\0', TRUE); if(-1 != matchingOpeningBracket && -1 != matchingClosingBracket && (matchingClosingBracket > matchingOpeningBracket)) { /* we are inside of some tag. Let us check what tag*/ gboolean isMatchingTagOpening = is_tag_opening(sci, matchingOpeningBracket); gchar *matchingTagName = get_tag_name(sci, matchingOpeningBracket, matchingClosingBracket, isMatchingTagOpening); if(matchingTagName && strcmp(tagName, matchingTagName) == 0) { if(TRUE == isMatchingTagOpening) openingTagsCount++; else closingTagsCount++; } pos = matchingClosingBracket; g_free(matchingTagName); } if(openingTagsCount == closingTagsCount) { /* matching tag is found */ highlightedBrackets[2] = matchingOpeningBracket; highlightedBrackets[3] = matchingClosingBracket; highlight_matching_pair(sci); return; } } highlight_tag(sci, highlightedBrackets[0], highlightedBrackets[1], NONMATCHING_PAIR_COLOR); }
static gboolean improve_indent( ScintillaObject *sci, GeanyEditor *editor, gint pos) { gint ch, ch_next; gint line; gint indent, indent_width; gint end_pos; if (!ac_info->improved_cbracket_indent) return AC_CONTINUE_ACTION; ch = char_at(sci, pos - 1); if (ch != '{') return AC_CONTINUE_ACTION; /* if curly bracket completion is enabled - just make indents * but ensure that second "}" exists. If disabled - make indent * and complete second curly bracket */ ch_next = char_at(sci, pos); if (ac_info->cbracket && ch_next != '}') return AC_CONTINUE_ACTION; line = sci_get_line_from_position(sci, pos); indent = sci_get_line_indentation(sci, line); indent_width = editor_get_indent_prefs(editor)->width; sci_start_undo_action(sci); if (ac_info->cbracket) SSM(sci, SCI_ADDTEXT, 2, (sptr_t)"\n\n"); else SSM(sci, SCI_ADDTEXT, 3, (sptr_t)"\n\n}"); if (ac_info->whitesmiths_style) { sci_set_line_indentation(sci, line, indent); sci_set_line_indentation(sci, line + 1, indent); sci_set_line_indentation(sci, line + 2, indent); } else { sci_set_line_indentation(sci, line + 1, indent + indent_width); sci_set_line_indentation(sci, line + 2, indent); } /* move to the end of added line */ end_pos = sci_get_line_end_position(sci, line + 1); sci_set_current_position(sci, end_pos, TRUE); sci_end_undo_action(sci); /* do not alow internal auto-indenter to do the work */ return AC_STOP_ACTION; }
static PyObject * Scintilla_get_line_from_position(Scintilla *self, PyObject *args, PyObject *kwargs) { gint line, pos; static gchar *kwlist[] = { "pos", NULL }; SCI_RET_IF_FAIL(self); if (PyArg_ParseTupleAndKeywords(args, kwargs, "|i", kwlist, &pos)) { if (pos == -1) pos = sci_get_current_position(self->sci); line = sci_get_line_from_position(self->sci, pos); return Py_BuildValue("i", line); } Py_RETURN_NONE; }
static gboolean on_editor_notify(G_GNUC_UNUSED GObject *obj, GeanyEditor *editor, SCNotification *nt, G_GNUC_UNUSED gpointer gdata) { GeanyDocument *doc = editor->document; if (nt->nmhdr.code == SCN_MODIFIED && nt->linesAdded && utils_source_document(doc)) { gboolean active = debug_state() != DS_INACTIVE; ScintillaObject *sci = editor->sci; gint start = sci_get_line_from_position(sci, nt->position); if (active) threads_delta(sci, doc->real_path, start, nt->linesAdded); breaks_delta(sci, doc->real_path, start, nt->linesAdded, active); } return FALSE; }
static void send_complete(GeanyEditor* editor, int flag) { if (completion_framework == NULL) { return; } if (!is_completion_file_now()) { return; } int pos = get_completion_position(); if (pos == 0) { return; } // nothing to complete int line = sci_get_line_from_position(editor->sci, pos); int ls_pos = sci_get_position_from_line(editor->sci, line); int byte_line_len = pos - ls_pos; if (byte_line_len < 0) { return; } char* content = sci_get_contents(editor->sci, sci_get_length(editor->sci) + 1 + 1); content[sci_get_length(editor->sci)] = ' '; // replace null -> virtual space for clang content[sci_get_length(editor->sci)] = '\0'; // TODO clang's col is byte? character? completion_framework->complete_async(editor->document->file_name, content, line + 1, byte_line_len + 1); edit_tracker.valid = true; edit_tracker.start_pos = pos; edit_tracker.text.clear(); if (pos != sci_get_current_position(editor->sci)) { int len = sci_get_current_position(editor->sci) - pos; edit_tracker.text.append(content + pos, len); } g_free(content); }
static void check_on_text_changed(GeanyDocument *doc, gint position, gint lines_added) { gint line_number; gint line_count; /* Iterating over all lines which changed as indicated by lines_added. lines_added is 0 * if only a lines has changed, in this case set it to 1. Otherwise, iterating over all * new lines makes spell checking work for pasted text. */ line_count = MAX(1, lines_added); line_number = sci_get_line_from_position(doc->editor->sci, position); /* TODO: storing these information in the global check_line_data struct isn't that good. * The data gets overwritten when a new line is inserted and so there is a chance that thep * previous line is not checked to the end. One solution could be to simple maintain a list * of line numbers which needs to be checked and do this is the timeout handler. */ check_line_data.doc = doc; check_line_data.line_number = line_number; check_line_data.line_count = line_count; /* check only once in a while */ if (! need_delay()) check_lines(NULL); }
/* if type == -1 then we will try to autodetect the type */ void glatex_insert_environment(const gchar *environment, gint type) { GeanyDocument *doc = NULL; doc = document_get_current(); /* Only do anything if it is realy needed to */ if (doc != NULL && environment != NULL) { if (sci_has_selection(doc->editor->sci)) { gchar *selection = NULL; gchar *replacement = NULL; selection = sci_get_selection_contents(doc->editor->sci); sci_start_undo_action(doc->editor->sci); if (utils_str_equal(environment, "block") == TRUE) { replacement = g_strconcat("\\begin{", environment, "}{}\n", selection, "\n\\end{", environment, "}\n", NULL); } else { replacement = g_strconcat("\\begin{", environment, "}\n", selection, "\n\\end{", environment, "}\n", NULL); } sci_replace_sel(doc->editor->sci, replacement); sci_end_undo_action(doc->editor->sci); g_free(selection); g_free(replacement); } else { gint indent, pos; GString *tmpstring = NULL; gchar *tmp = NULL; static const GeanyIndentPrefs *indention_prefs = NULL; if (type == -1) { gint i; /* First, we check whether we have a known list over here * an reset type to fit new value*/ for (i = 0; i < GLATEX_LIST_END; i++) { if (utils_str_equal(glatex_list_environments[i], environment) == TRUE) { type = GLATEX_ENVIRONMENT_TYPE_LIST; break; } } } pos = sci_get_current_position(doc->editor->sci); sci_start_undo_action(doc->editor->sci); tmpstring = g_string_new("\\begin{"); g_string_append(tmpstring, environment); if (utils_str_equal(environment, "block") == TRUE) { g_string_append(tmpstring, "}{}"); } else { g_string_append(tmpstring, "}"); } g_string_append(tmpstring, "\n"); if (type == GLATEX_ENVIRONMENT_TYPE_LIST) { g_string_append(tmpstring, "\t\\item "); } tmp = g_string_free(tmpstring, FALSE); glatex_insert_string(tmp, TRUE); g_free(tmp); indent = sci_get_line_indentation(doc->editor->sci, sci_get_line_from_position(doc->editor->sci, pos)); tmp = g_strdup_printf("\n\\end{%s}", environment); glatex_insert_string(tmp, FALSE); g_free(tmp); indention_prefs = editor_get_indent_prefs(doc->editor); if (type == GLATEX_ENVIRONMENT_TYPE_LIST) { sci_set_line_indentation(doc->editor->sci, sci_get_current_line(doc->editor->sci), indent + indention_prefs->width); } sci_set_line_indentation(doc->editor->sci, sci_get_current_line(doc->editor->sci) + 1, indent); sci_end_undo_action(doc->editor->sci); } } }
/* * Occures on notify from editor. * Handles margin click to set/remove breakpoint */ gboolean on_editor_notify( GObject *object, GeanyEditor *editor, SCNotification *nt, gpointer data) { if (!editor->document->real_path) { /* no other way to handle removing a file from outside of geany */ markers_remove_all(editor->document); } switch (nt->nmhdr.code) { case SCN_MARGINCLICK: { char* file; int line; break_state bs; if (!editor->document->real_path || 1 != nt->margin) break; file = editor->document->file_name; line = sci_get_line_from_position(editor->sci, nt->position) + 1; bs = breaks_get_state(file, line); if (BS_NOT_SET == bs) breaks_add(file, line, NULL, TRUE, 0); else if (BS_ENABLED == bs) breaks_remove(file, line); else if (BS_DISABLED == bs) breaks_switch(file, line); scintilla_send_message(editor->sci, SCI_SETFOCUS, TRUE, 0); return TRUE; } case SCN_DWELLSTART: { GString *word; if (DBS_STOPPED != debug_get_state ()) break; /* get a word under the cursor */ word = get_word_at_position(editor->sci, nt->position); if (word->len) { gchar *calltip = debug_get_calltip_for_expression(word->str); if (calltip) { leave_signal = g_signal_connect(G_OBJECT(editor->sci), "leave-notify-event", G_CALLBACK(on_mouse_leave), NULL); scintilla_send_message (editor->sci, SCI_CALLTIPSHOW, nt->position, (long)calltip); } } g_string_free(word, TRUE); break; } case SCN_DWELLEND: { if (DBS_STOPPED != debug_get_state ()) break; if (scintilla_send_message (editor->sci, SCI_CALLTIPACTIVE, 0, 0)) { g_signal_handler_disconnect(G_OBJECT(editor->sci), leave_signal); scintilla_send_message (editor->sci, SCI_CALLTIPCANCEL, 0, 0); } break; } case SCN_MODIFYATTEMPTRO: { dialogs_show_msgbox(GTK_MESSAGE_INFO, _("To edit source files stop debugging session")); break; } case SCN_MODIFIED: { if(((SC_MOD_INSERTTEXT & nt->modificationType) || (SC_MOD_DELETETEXT && nt->modificationType)) && editor->document->file_name && nt->linesAdded) { int line = sci_get_line_from_position(editor->sci, nt->position) + 1; GList *breaks = breaks_get_for_document(editor->document->file_name); if (breaks) { GList *iter = breaks; while (iter) { breakpoint *bp = (breakpoint*)iter->data; if (nt->linesAdded > 0 && bp->line >= line) { breaks_move_to_line(bp->file, bp->line, bp->line + nt->linesAdded); bptree_update_breakpoint(bp); } else if (nt->linesAdded < 0 && bp->line >= line) { if (bp->line < line - nt->linesAdded) { breaks_remove(bp->file, bp->line); } else { breaks_move_to_line(bp->file, bp->line, bp->line + nt->linesAdded); bptree_update_breakpoint(bp); } } iter = iter->next; } config_set_debug_changed(); g_list_free(breaks); } } break; } } return FALSE; }
static void shift_left_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer gdata){ gchar *txt; gchar *txt_i; gchar char_before; gint txt_len; gint startpos; gint endpos; gint startline; gint endline; gint line_iter; gint linepos; gint linelen; gint startcol; gint endcol; gint i; gint n_spaces; gchar *spaces; ScintillaObject *sci; /* get a pointer to the scintilla object */ sci = document_get_current()->editor->sci; if (sci_has_selection(sci)){ startpos = sci_get_selection_start(sci); endpos = sci_get_selection_end(sci); /* sanity check -- we dont care which way the block was selected */ if(startpos > endpos){ i = endpos; endpos = startpos; startpos = i; } startline = sci_get_line_from_position(sci, startpos); /* Setting also start point for 1st line */ linepos = sci_get_position_from_line(sci, startline); endline = sci_get_line_from_position(sci, endpos); /* normal mode */ if(startline == endline){ /* get the text in question */ txt_len = endpos - startpos; txt_i = g_malloc(txt_len + 1); txt = g_malloc(txt_len + 2); sci_get_selected_text(sci, txt_i); char_before = sci_get_char_at(sci, startpos - 1); /* set up new text buf */ (void) g_sprintf(txt, "%s%c", txt_i, char_before); /* start undo */ sci_start_undo_action(sci); /* put the new text in */ sci_set_selection_start(sci, startpos - 1); sci_replace_sel(sci, txt); /* select the right bit again */ sci_set_selection_start(sci, startpos - 1); sci_set_selection_end(sci, endpos - 1); /* end undo */ sci_end_undo_action(sci); g_free(txt); g_free(txt_i); } /* rectangle mode (we hope!) */ else{ startcol = sci_get_col_from_position(sci, startpos); endcol = sci_get_col_from_position(sci, endpos); /* return early for the trivial case */ if(startcol == 0 || startcol == endcol){ return; } /* start undo */ sci_start_undo_action(sci); for(line_iter = startline; line_iter <= endline; line_iter++){ linepos = sci_get_position_from_line(sci, line_iter); linelen = sci_get_line_length(sci, line_iter); /* do we need to do something */ if(linelen >= startcol - 1 ){ /* if between the two columns */ /* pad to the end first */ if(linelen <= endcol){ /* bung in some spaces -- sorry, I dont like tabs */ n_spaces = endcol - linelen + 1; spaces = g_malloc(sizeof(gchar) * (n_spaces + 1)); for(i = 0; i < n_spaces; i++){ spaces[i] = ' '; } spaces[i] = '\0'; sci_insert_text(sci, linepos + linelen - 1, spaces); g_free(spaces); } /* now move the text itself */ sci_set_selection_mode(sci, 0); sci_set_selection_start(sci, linepos + startcol); sci_set_selection_end(sci, linepos + endcol); txt_len = sci_get_selected_text_length(sci); txt_i = g_malloc(txt_len + 1); txt = g_malloc(txt_len + 2); sci_get_selected_text(sci, txt_i); char_before = sci_get_char_at(sci, linepos + startcol - 1); /* set up new text buf */ (void) g_sprintf(txt, "%s%c", txt_i, char_before); /* put the new text in */ sci_set_selection_start(sci, linepos + startcol - 1); sci_replace_sel(sci, txt); g_free(txt); g_free(txt_i); } } /* put the selection box back */ /* here we rely upon the last result of linepos */ sci_set_selection_mode(sci, 1); sci_set_selection_start(sci, startpos - 1); sci_set_selection_end(sci, linepos + endcol - 1); /* end undo action */ sci_end_undo_action(sci); } } }
static void shift_right_cb(G_GNUC_UNUSED GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer gdata){ gchar *txt; gchar *txt_i; gchar char_after; gint txt_len; gint startpos; gint endpos; gint startline; gint endline; gint line_iter; gint linepos; gint linelen; gint startcol; gint endcol; gint i; ScintillaObject *sci; /* get a pointer to the scintilla object */ sci = document_get_current()->editor->sci; if (sci_has_selection(sci)){ startpos = sci_get_selection_start(sci); endpos = sci_get_selection_end(sci); /* sanity check -- we dont care which way the block was selected */ if(startpos > endpos){ i = endpos; endpos = startpos; startpos = i; } startline = sci_get_line_from_position(sci, startpos); linepos = sci_get_position_from_line(sci, startline); endline = sci_get_line_from_position(sci, endpos); /* normal mode */ if(startline == endline){ /* get the text in question */ txt_len = endpos - startpos; txt_i = g_malloc(txt_len + 1); txt = g_malloc(txt_len + 2); sci_get_selected_text(sci, txt_i); char_after = sci_get_char_at(sci, endpos); /* set up new text buf */ (void) g_sprintf(txt, "%c%s", char_after, txt_i); /* start undo */ sci_start_undo_action(sci); /* put the new text in */ sci_set_selection_end(sci, endpos + 1); sci_replace_sel(sci, txt); /* select the right bit again */ sci_set_selection_start(sci, startpos + 1); sci_set_selection_end(sci, endpos + 1); /* end undo */ sci_end_undo_action(sci); g_free(txt); g_free(txt_i); } /* rectangle mode (we hope!) */ else{ startcol = sci_get_col_from_position(sci, startpos); endcol = sci_get_col_from_position(sci, endpos); /* start undo */ sci_start_undo_action(sci); for(line_iter = startline; line_iter <= endline; line_iter++){ linepos = sci_get_position_from_line(sci, line_iter); linelen = sci_get_line_length(sci, line_iter); /* do we need to do something */ if(linelen >= startcol - 1 ){ /* if between the two columns or at the end */ /* add in a space */ if(linelen <= endcol || linelen - 1 == endcol){ txt = g_malloc(sizeof(gchar) * 2); sprintf(txt, " "); sci_insert_text(sci, linepos + startcol, txt); g_free(txt); } else{ /* move the text itself */ sci_set_selection_mode(sci, 0); sci_set_selection_start(sci, linepos + startcol); sci_set_selection_end(sci, linepos + endcol); txt_len = sci_get_selected_text_length(sci); txt_i = g_malloc(txt_len + 1); txt = g_malloc(txt_len + 2); sci_get_selected_text(sci, txt_i); char_after = sci_get_char_at(sci, linepos + endcol); /* set up new text buf */ (void) g_sprintf(txt, "%c%s", char_after, txt_i); /* put the new text in */ sci_set_selection_end(sci, linepos + endcol + 1); sci_replace_sel(sci, txt); g_free(txt); g_free(txt_i); } } } /* put the selection box back */ /* here we rely upon the last result of linepos */ sci_set_selection_mode(sci, 1); sci_set_selection_start(sci, startpos + 1); sci_set_selection_end(sci, linepos + endcol + 1); /* end undo action */ sci_end_undo_action(sci); } } }
void sc_speller_check_document(GeanyDocument *doc) { gchar *line; gint i; gint first_line, last_line; gchar *dict_string = NULL; gint suggestions_found = 0; g_return_if_fail(sc_speller_dict != NULL); g_return_if_fail(doc != NULL); ui_progress_bar_start(_("Checking")); enchant_dict_describe(sc_speller_dict, dict_describe, &dict_string); if (sci_has_selection(doc->editor->sci)) { first_line = sci_get_line_from_position( doc->editor->sci, sci_get_selection_start(doc->editor->sci)); last_line = sci_get_line_from_position( doc->editor->sci, sci_get_selection_end(doc->editor->sci)); if (sc_info->use_msgwin) msgwin_msg_add(COLOR_BLUE, -1, NULL, _("Checking file \"%s\" (lines %d to %d using %s):"), DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string); g_message("Checking file \"%s\" (lines %d to %d using %s):", DOC_FILENAME(doc), first_line + 1, last_line + 1, dict_string); } else { first_line = 0; last_line = sci_get_line_count(doc->editor->sci); if (sc_info->use_msgwin) msgwin_msg_add(COLOR_BLUE, -1, NULL, _("Checking file \"%s\" (using %s):"), DOC_FILENAME(doc), dict_string); g_message("Checking file \"%s\" (using %s):", DOC_FILENAME(doc), dict_string); } g_free(dict_string); if (first_line == last_line) { line = sci_get_selection_contents(doc->editor->sci); suggestions_found += sc_speller_process_line(doc, first_line, line); g_free(line); } else { for (i = first_line; i < last_line; i++) { line = sci_get_line(doc->editor->sci, i); suggestions_found += sc_speller_process_line(doc, i, line); /* process other GTK events to keep the GUI being responsive */ while (g_main_context_iteration(NULL, FALSE)); g_free(line); } } if (suggestions_found == 0 && sc_info->use_msgwin) msgwin_msg_add(COLOR_BLUE, -1, NULL, _("The checked text is spelled correctly.")); ui_progress_bar_stop(); }
static gboolean editor_notify_cb(GObject *object, GeanyEditor *editor, SCNotification *nt, gpointer data) { gint i = 0, val; gint old_position = 0; gint old_lposition = 0; gint old_line = 0; gint pos; if(NULL == editor || NULL == editor->sci) return FALSE; if(nt->nmhdr.code == SCN_CHARADDED) { if('\n' == nt->ch) define_format_newline(editor->sci); } if(nt->nmhdr.code == SCN_UPDATEUI) { if(g_array_index(lines_stack, gint, 0)) { /* save current position */ old_line = sci_get_current_line(editor->sci); old_lposition = sci_get_line_end_position(editor->sci, old_line) - sci_get_line_length(editor->sci, old_line); old_position = sci_get_current_position(editor->sci); sci_start_undo_action(editor->sci); } while((val = g_array_index(lines_stack, gint, i))) { i++; define_format_line(editor->sci, val - 1); dprintf("Removed from stack: %d\n", val); } if(i > 0) { sci_end_undo_action(editor->sci); g_array_remove_range(lines_stack, 0, i); /* restore current position */ pos = sci_get_line_end_position(editor->sci, old_line) - sci_get_line_length(editor->sci, old_line); sci_set_current_position(editor->sci, old_position + pos - old_lposition, FALSE); } } if(nt->nmhdr.code == SCN_MODIFIED) { if(nt->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { if(nt->modificationType & (SC_PERFORMED_UNDO | SC_PERFORMED_REDO)) return FALSE; gint line = sci_get_line_from_position(editor->sci, nt->position) + 1; if(sci_get_char_at(editor->sci, get_line_end(editor->sci, line - 1) - 1) == '\\') { gboolean found = FALSE; while((val = g_array_index(lines_stack, gint, i))) { if(val == line) { found = TRUE; break; } i++; } if(!found) { dprintf("Added line: %d\n", line); g_array_append_val(lines_stack, line); } } } } return FALSE; }
static gboolean handle_backspace( AutocloseUserData *data, ScintillaObject *sci, gchar ch, gchar *ch_left, gchar *ch_right, GdkEventKey *event, gint indent_width) { gint pos = sci_get_current_position(sci); gint end_pos; gint line_start, line_end, line; gint i; if (!ac_info->delete_pairing_brace) return AC_CONTINUE_ACTION; ch = char_at(sci, pos - 1); if (!check_chars(sci, ch, ch_left, ch_right)) return AC_CONTINUE_ACTION; if (event->state & GDK_SHIFT_MASK) { if ((ch_left[0] == ch || ch_right[0] == ch) && ac_info->bcksp_remove_pair) { end_pos = sci_find_matching_brace(sci, pos - 1); if (-1 == end_pos) return AC_CONTINUE_ACTION; sci_start_undo_action(sci); line_start = sci_get_line_from_position(sci, pos); line_end = sci_get_line_from_position(sci, end_pos); SSM(sci, SCI_DELETERANGE, end_pos, 1); if (end_pos < pos) pos--; SSM(sci, SCI_DELETERANGE, pos - 1, 1); /* remove indentation magick */ if (char_is_curly_bracket(ch)) { if (line_start == line_end) goto final; if (line_start > line_end) { line = line_end; line_end = line_start; line_start = line; } if (blank_line(sci, line_start)) { delete_line(sci, line_start); line_end--; } else line_start++; if (blank_line(sci, line_end)) delete_line(sci, line_end); line_end--; /* unindent */ for (i = line_start; i <= line_end; i++) { unindent_line(sci, i, indent_width); } } final: sci_end_undo_action(sci); return AC_STOP_ACTION; }