This is cmds.c in view mode; [Download] [Up]
/* * Copyright (c) 1992, 1995 John E. Davis (davis@space.mit.edu) * All Rights Reserved. */ #include <config.h> #include <stdio.h> #include <slang.h> #include <string.h> #include "buffer.h" #include "screen.h" #include "window.h" #include "ins.h" #include "ledit.h" #include "cmds.h" #include "line.h" #include "paste.h" #include "display.h" #include "vterm.h" #include "sysdep.h" #include "text.h" #include "file.h" #include "misc.h" #include "search.h" #include "hooks.h" #include "abbrev.h" #ifdef HAS_SUBPROCESSES # include "jprocess.h" #endif void (*X_Suspend_Hook)(void); int Blink_Flag = 1; int Indented_Text_Mode = 0; /* if non zero, intent line after wrap */ int Kill_Line_Feature = 1; /* non-zero means kill through eol if bolp */ int C_Bra_Newline = 1; /* if zero, do not insert newline before '{' */ int C_Comment_Hint; static char *Top_Of_Buffer_Error = "Top Of Buffer."; static char *End_Of_Buffer_Error = "End Of Buffer."; /* return 1 if line extends beyond the screen */ static int long_line(void) { int p, col; col = Screen_Col; p = Point; Point = CLine->len - 1; if ((*(CLine->data + Point) != '\n') || (CBuf == MiniBuffer)) Point++; if (calculate_column() >= JWindow->width - 1) { Point = p; Screen_Col = col; return(1); } Screen_Col = col; Point = p; return(0); } #define FAST_NOT_OK ((Repeat_Factor != NULL) || JWindow->trashed\ || (ch < ' ') || (ch > 126) || Input_Buffer_Len\ || Suspend_Screen_Update\ || (Screen_Col >= JWindow->width - 2) || (JWindow->column > 1)\ || Batch || (CLine->len == 0)\ || ((CBuf->marks != NULL) && Wants_Attributes)\ || input_pending(&Number_Zero) || Executing_Keyboard_Macro\ || tabs_present()\ || (Read_This_Character != NULL)) int newline() { #if 0 int push = 0; #endif CHECK_READ_ONLY if (CBuf == MiniBuffer) return exit_minibuffer(); insert_string ("\n"); #if 0 /* This bit of nonsense gives a better looking screen update. The problem * with doing this is that it screws up the marks. */ if (bolp() && (CLine->prev != NULL) && (CLine->len > 1)) { push = 1; push_spot(); CLine = CLine->prev; LineNum--; Point = 0; eol(); } split_line(); ins('\n'); check_line(); if (push) { pop_spot(); return(1); } Point--; forwchars(&Number_One); #endif return(1); } int previous_char_cmd() { int pnt; Cursor_Motion = 1; if (bobp()) { msg_error(Top_Of_Buffer_Error); return(0); } pnt = Point - 1; backwchars(&Number_One); Goal_Column = calculate_column(); /* For syntax highlighting */ if ((Last_Key_Function != (FVOID_STAR) previous_char_cmd) && ((Last_Key_Function == (FVOID_STAR) ins_char_cmd) || (Last_Key_Function == (FVOID_STAR) delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify))) register_change(0); return (pnt == -1) || JWindow->trashed; } /* Slang calls by reference so make this a pointer ! */ void insert_whitespace(int *n) { int tab = Buffer_Local.tab; int c1, c2, i, k, nspace; if ((nspace = *n) <= 0) return; CHECK_READ_ONLY_VOID c1 = calculate_column() - 1; c2 = c1 + nspace; if (tab) { i = c1 / tab; k = c2 / tab - i; if (k) nspace = c2 - (i + k) * tab; ins_char_n_times('\t', k); } ins_char_n_times(' ', nspace); } /* check from point to end of line looking for tabs */ static int tabs_present(void) { unsigned char *p, *pmax; if (!Buffer_Local.tab) return(0); pmax = CLine->data + CLine->len; p = CLine->data + Point; while (p < pmax) if (*p++ == '\t') return(1); return(0); } int delete_char_cmd() { int upd, n; char ch; CHECK_READ_ONLY if (eobp()) { msg_error(End_Of_Buffer_Error); return(0); } ch = *(CLine->data + Point); if (FAST_NOT_OK || long_line () || *tt_Term_Cannot_Insert ) { if ((Point == 0) && eolp() #ifdef JED_LINE_ATTRIBUTES && ((CLine->prev != NULL) && ((CLine->prev->flags & JED_LINE_READONLY) == 0)) #endif ) n = 1; else n = 0; /* same effect, update looks better */ n = backwchars(&n); del(); forwchars(&n); upd = 1; } else { upd = ((CBuf->flags & BUFFER_TRASHED) == 0); fast_del(); tt_delete_char (); } return(upd); } int backward_delete_char_cmd() { char ch; int ret; CHECK_READ_ONLY if (bobp()) { msg_error(Top_Of_Buffer_Error); return(0); } if (bolp()) { backwchars(&Number_One); return delete_char_cmd(); } ch = *(CLine->data + (Point - 1)); if (FAST_NOT_OK || long_line () || *tt_Term_Cannot_Insert ) { backwchars(&Number_One); del(); return(1); } ret = ((CBuf->flags & BUFFER_TRASHED) == 0); backwchars(&Number_One); tt_putchar('\b'); Screen_Col--; fast_del(); tt_delete_char(); return(ret); } int backward_delete_char_untabify() { unsigned char *p; int n; CHECK_READ_ONLY p = CLine->data + (Point - 1); /* note that short circuit is assumed to avoid seg fault */ if (!Point || bobp() || (*p != '\t') || !Buffer_Local.tab) return backward_delete_char_cmd(); n = calculate_column() - 1; backwchars(&Number_One); del(); n = n - calculate_column(); ins_char_n_times(' ', n); return(1); } int previous_line_cmd() { int ret, gc; if (CLine == CBuf->beg) { msg_error(Top_Of_Buffer_Error); return(0); } check_line(); gc = calculate_column(); if (Cursor_Motion <= 0) Goal_Column = gc; else if (Goal_Column < gc) Goal_Column = gc; Cursor_Motion = 2; /* For syntax highlighting */ if ((Last_Key_Function != (FVOID_STAR) previous_line_cmd) && ((Last_Key_Function == (FVOID_STAR) ins_char_cmd) || (Last_Key_Function == (FVOID_STAR) delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify))) register_change(0); ret = JWindow->trashed || (CLine == JScreen[JWindow->top - 1].line); CLine = CLine->prev; LineNum--; point_column(Goal_Column); return(ret); } int next_line_cmd() { int ret, gc; if (CLine == CBuf->end) { msg_error(End_Of_Buffer_Error); return(0); } check_line(); gc = calculate_column(); if (Cursor_Motion <= 0) Goal_Column = gc; else if (Goal_Column < gc) Goal_Column = gc; Cursor_Motion = 2; /* For syntax highlighting */ if ((Last_Key_Function != (FVOID_STAR) next_line_cmd) && ((Last_Key_Function == (FVOID_STAR) ins_char_cmd) || (Last_Key_Function == (FVOID_STAR) delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify))) register_change(0); ret = JWindow->trashed || (CLine == JScreen[JWindow->top + JWindow->rows - 2].line); CLine = CLine->next; LineNum++; point_column(Goal_Column); return(ret); } int next_char_cmd() { Cursor_Motion = 1; /* For syntax highlighting */ if ((Last_Key_Function != (FVOID_STAR) next_char_cmd) && ((Last_Key_Function == (FVOID_STAR) ins_char_cmd) || (Last_Key_Function == (FVOID_STAR) delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_cmd) || (Last_Key_Function == (FVOID_STAR) backward_delete_char_untabify))) register_change(0); if (!forwchars(&Number_One)) { msg_error(End_Of_Buffer_Error); return (0); } Goal_Column = calculate_column(); return !Point || JWindow->trashed; /* Point = 0 ==> moved a line */ } extern Buffer *Paste_Buffer; int kill_line() { int n, pnt, flag = 0; CHECK_READ_ONLY if (eobp()) { msg_error(End_Of_Buffer_Error); return(0); } push_mark(); push_spot(); pnt = Point; eol(); n = Point - pnt; if ((!pnt && Kill_Line_Feature) || !n) { /* Either of these (flag =0,1) have the same effect on the buffer. * However, the first sets the mark at the end of the line and moves * the point to the end of the previous line. This way the current * line structure is deleted and the screen update looks better. */ if (!pnt && (CLine->prev != NULL) && (CLine->next != NULL)) { flag = 1; forwchars(&Number_One); } else n += forwchars(&Number_One); } if ((Last_Key_Function == (FVOID_STAR) kill_line) && (Paste_Buffer != NULL)) { copy_region_to_buffer(Paste_Buffer); } else copy_to_pastebuffer(); pop_spot(); if (flag) n += backwchars(&Number_One); generic_deln(&n); if (flag) forwchars(&Number_One); return(1); } /* get indent value of current line, n is the column */ unsigned char *get_current_indent(int *np) { unsigned char *p, *pmax; int tab, n; tab = Buffer_Local.tab; p = CLine->data; pmax = CLine->data + CLine->len; n = 0; while((p < pmax) && ((*p == ' ') || (tab && (*p == '\t')))) { if (*p == '\t') n = tab * (n / tab + 1); else n++; p++; } *np = n; return p; } int trim_whitespace() { register unsigned char *p, *pmax, ch; int n, save_point, len; CHECK_READ_ONLY len = CLine->len; if (len == 0) return(0); save_point = Point; if (Point == len) Point--; /* Note that we save the point before --ing it. This way the comparison made below will effectively restore it if pointing at non whitespace */ p = CLine->data + Point; if (Point && (*p == '\n') && (CBuf != MiniBuffer)) { Point--; p--; } while ((Point > 0) && (((ch = *p) == '\t') || (ch == ' '))) { Point--; p--; } if (save_point != Point) if (!eolp() && ((*p != ' ') && (*p != '\t'))) { Point++; p++; } n = 0; /* this needs to be inlined. Actually for undo, I need del(n)! */ pmax = CLine->data + CLine->len; while ((p < pmax) && ((ch = *p) != '\n') && ((ch == ' ') || (ch == '\t'))) p++, n++; deln(&n); return(1); } /* indent line to column n */ void indent_to(int n) { int m; get_current_indent(&m); if (n != m) { Point = 0; trim_whitespace(); if (n >= 0) insert_whitespace(&n); } } int indent_line () { int n, n1; static int in_function; if (in_function) return -1; if (CBuf->indent_hook != NULL) { in_function = 1; SLexecute_function(CBuf->indent_hook); in_function = 0; return 1; } CHECK_READ_ONLY if (CLine == CBuf->beg) return(0); push_spot(); CLine = CLine->prev; get_current_indent (&n); CLine = CLine->next; indent_to(n); pop_spot(); /* This moves the cursor to the first non whitspace char if we are before it. Otherwise leave it alone */ n1 = calculate_column(); get_current_indent(&n); if (n1 <= n) point_column(n + 1); return 1; } int newline_and_indent() { static int in_function; if (in_function) return -1; if (CBuf->newline_indent_hook != NULL) { in_function = 1; SLexecute_function(CBuf->newline_indent_hook); in_function = 0; return 1; } newline(); indent_line(); return(1); } int ins_char_cmd() { char ch; int wrap = User_Vars.wrap_column; int ret, ll; CHECK_READ_ONLY ch = (char) SLang_Last_Key_Char; if (ch == '\n') { newline(); return(1); } #ifdef HAS_ABBREVS if (CBuf->flags & ABBREV_MODE) { expand_abbrev (ch); } #endif if ((CBuf->flags & OVERWRITE_MODE) && !eolp()) del(); if (((ch == ' ') || (Point >= wrap)) && (CBuf->modes & WRAP_MODE) && (calculate_column() > wrap)) /* JWindow->width */ { ins(ch); wrap_line(0); /* do not format--- just wrap */ if (Indented_Text_Mode) indent_line (); if (CBuf->wrap_hook != NULL) SLexecute_function(CBuf->wrap_hook); return(1); } if ((ch == ' ') || FAST_NOT_OK || (CBuf->flags & OVERWRITE_MODE) || (*tt_Term_Cannot_Insert && !eolp()) ) { ins(ch); if ((CBuf->syntax_table != NULL) && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX) && !input_pending(&Number_Zero)) blink_match (); /* (ch); */ return(1); } ret = ((CBuf->flags & BUFFER_TRASHED) == 0) || (User_Prefers_Line_Numbers > 1); if (long_line ()) ll = 1; else ll = 0; ret = ret || ll; /* fast_ins goes first so that screen structure is updated now for following calls to use. */ fast_ins(ch); if (!eolp() || ll) { tt_begin_insert(); tt_putchar(ch); tt_end_insert(); if (ll) register_change(0); } else tt_putchar(ch); Screen_Col++; if ((CBuf->syntax_table != NULL) && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX) && !input_pending(&Number_Zero)) blink_match (); /* (ch); */ return(ret); } int eol_cmd (void) { eol(); if ((0 == (CBuf->flags & READ_ONLY)) #ifdef JED_LINE_ATTRIBUTES && (0 == (CLine->flags & JED_LINE_READONLY)) #endif ) trim_whitespace(); return(1); } int sys_spawn_cmd() { if (Jed_Secure_Mode) { msg_error ("Access to shell denied."); return -1; } if (Batch) { sys_suspend (); return 0; } if (X_Suspend_Hook != NULL) { (*X_Suspend_Hook) (); return (0); } SLang_run_hooks("suspend_hook", NULL, NULL); if (SLang_Error) return(0); reset_display(); reset_tty(); sys_suspend(); init_tty(); flush_input (); init_display(1); /* cls(); */ SLang_run_hooks("resume_hook", NULL, NULL); check_buffers(); return(1); } int quit_jed(void) { Buffer *b = CBuf; /* Any buffer marked with AUTO_SAVE_JUST_SAVE flag should be saved * if it has not already been. That is what the flag is for and this * code fragment carries this out. */ do { if ((b->flags & AUTO_SAVE_JUST_SAVE) && (b->flags & BUFFER_TRASHED) && (*b->file)) { while (b->narrow != NULL) widen_buffer(b); auto_save_buffer(b); /* actually, it will save it */ } #if defined(__WIN32__) && defined(HAS_SUBPROCESSES) if (b->subprocess) jed_kill_process(b->subprocess - 1); #endif b = b->next; } while (b != CBuf); reset_display(); reset_tty(); #ifdef VMS vms_cancel_exithandler(); #endif #ifdef SLANG_STATS SLang_dump_stats("slang.dat"); #endif #ifdef MALLOC_DEBUG SLmalloc_dump_statistics (); #endif exit(0); return(1); } int quoted_insert() { char ch; int lerr = SLang_Error; CHECK_READ_ONLY if (*Error_Buffer || SLKeyBoard_Quit) return(0); if (Repeat_Factor != NULL) { ch = *Repeat_Factor; Repeat_Factor = NULL; } else { SLang_Key_TimeOut_Flag = 1; ch = jed_getkey(); SLang_Key_TimeOut_Flag = 0; } SLang_Error = lerr; /* ^G may set it */ if ((ch == '\n') && (CBuf == MiniBuffer)) { ins('\n'); /* msg_error("Not allowed!"); */ return (1); } SLKeyBoard_Quit = 0; ins_char_n_times(ch, 1); if ((CBuf->syntax_table != NULL) && (CBuf->syntax_table->char_syntax[(unsigned char) ch] & CLOSE_DELIM_SYNTAX) && !input_pending(&Number_Zero)) blink_match (); /* (ch); */ return(1); } /* I should try it like emacs--- if prefix argument, then save all without user intervention */ int save_some_buffers(void) { Buffer *b, *tmp; int ans = 0; char msg[256]; int err; b = CBuf; do { if ((b->flags & BUFFER_TRASHED) && (*b->file)) { if (b->flags & AUTO_SAVE_JUST_SAVE) ans = 'y'; else { sprintf(msg,"Buffer %s not saved. Save it? (y/n)", b->name); flush_message(msg); ans = my_getkey(); } while (1) { if ((ans == 'y') || (ans == 'Y')) { tmp = CBuf; switch_to_buffer(b); while (b->narrow != NULL) widen_buffer(b); err = write_file_with_backup(b->dir, b->file); switch_to_buffer(tmp); if (err < 0) return(-1); b->flags &= ~BUFFER_TRASHED; b->flags |= AUTO_SAVE_BUFFER; b->hits = 0; break; } else if ((ans == 'n') || (ans == 'N')) { /* disabling this */ /* auto_save_buffer(b); */ break; } else if (SLKeyBoard_Quit) { /* warning--- bug here if user edits file at startup and forgets to save it then aborts. */ return(-1); } else { beep(); sprintf(msg,"Buffer %s not saved. Save it", b->name); ans = get_yes_no(msg); if (ans == 1) ans = 'y'; else if (!ans) ans = 'n'; else return(-1); } } } b = b->next; } while (b != CBuf); clear_message (); return(1); } int exit_jed() { static int in_exit_jed = 0; if (!in_exit_jed) { in_exit_jed = 1; if (SLang_run_hooks("exit_hook", NULL, NULL)) { in_exit_jed = 0; return(1); } } in_exit_jed = 0; if (SLang_Error) return(0); if (save_some_buffers() > 0) quit_jed(); return(1); } int jed_buffer_visible (char *b) { return buffer_visible (find_buffer(b)); } static void scroll_completion (int dir) { Window_Type *w; if (jed_buffer_visible (Completion_Buffer)) { pop_to_buffer (Completion_Buffer); if (dir > 0) pagedown_cmd (); else pageup_cmd (); while (!IS_MINIBUFFER) other_window (); } else { w = JWindow; other_window(); if (!IS_MINIBUFFER) { if (dir > 0) pagedown_cmd (); else pageup_cmd (); } while (JWindow != w) other_window (); } } static int goto_bottom_of_window (void) { int n; n = JWindow->rows - window_line (); return n == nextline (&n); } static void goto_top_of_window (void) { int n; n = window_line () - 1; (void) prevline (&n); } static int Last_Page_Line; static int Last_Page_Point; /* the page up/down commands set cursor_motion to -1 because we do not want to use any goal column information */ int pagedown_cmd() { int col, this_line, this_point; int n; Cursor_Motion = -1; if (IS_MINIBUFFER) { scroll_completion (1); return 1; } if (eobp()) { msg_error(End_Of_Buffer_Error); return 1; } n = JWindow->rows; if ((CBuf != JWindow->buffer) || (n == 1)) { return (nextline(&n)); } if (JWindow->trashed) { update (NULL, 0, 0); if (JWindow->trashed) return nextline(&n); } this_line = LineNum; this_point = Point; col = calculate_column (); if (goto_bottom_of_window ()) { recenter (&Number_One); } goto_column1 (&col); if ((Last_Key_Function == (FVOID_STAR) pageup_cmd) && is_line_visible (Last_Page_Line)) { goto_line (&Last_Page_Line); Point = Last_Page_Point; } else if (CLine->next == NULL) eol(); else Point = 0; Last_Page_Line = this_line; Last_Page_Point = this_point; return(1); } int pageup_cmd (void) { int col, this_line, this_point; int n; Cursor_Motion = -1; if (IS_MINIBUFFER) { scroll_completion (-1); return 1; } if (bobp()) { msg_error(Top_Of_Buffer_Error); return 1; } n = JWindow->rows; if ((CBuf != JWindow->buffer) || (n == 1)) { return prevline(&n); } if (JWindow->trashed) { update (NULL, 0, 0); if (JWindow->trashed) return prevline (&n); } this_line = LineNum; this_point = Point; col = calculate_column (); goto_top_of_window (); (void) goto_column1(&col); recenter(&JWindow->rows); if ((Last_Key_Function == (FVOID_STAR) pagedown_cmd) && is_line_visible (Last_Page_Line)) { goto_line (&Last_Page_Line); Point = Last_Page_Point; } else Point = 0; /* something like: Point = point_column(JWindow->column) better? */ Last_Page_Line = this_line; Last_Page_Point = this_point; return(1); } int scroll_right() { if (JWindow->column == 1) return(0); if ((JWindow->column = JWindow->column - JWindow->width / 2) < 1) { JWindow->column = 1; } touch_window(); return(1); } int scroll_left() { JWindow->column = JWindow->column + JWindow->width / 2; touch_window(); return(1); } /* goto to column c, returns actual column */ int goto_column1(int *cp) { int c1, c = *cp; if (c <= 0) c = 1; eol(); c1 = calculate_column(); if (c1 > c) { point_column(c); c1 = calculate_column(); } return(c1); } /* move cursor to column c adding spaces if necessary */ void goto_column(int *c) { int c1 = *c; if (c1 <= 0) c1 = 1; c1 = c1 - goto_column1(&c1); insert_whitespace(&c1); } /* does not leave current line */ unsigned int skip_whitespace() { unsigned char *p, *pmax; if (CLine->len == 0) return('\n'); p = CLine->data + Point; eol(); pmax = CLine->data + Point; while(p < pmax) { if ((*p != ' ') && (*p != '\t')) break; p++; } Point = (int) (p - CLine->data); return(*p); } #define upcase(ch) (Case_Sensitive ? ch : UPPER_CASE(ch)) /* returns < 0 if what is smaller than current thing, 0 if matched, pos otherwise */ int looking_at(char *what) { register unsigned char *p, *pmax; register unsigned char *w = (unsigned char *) what, ch; Line *l = CLine; p = l->data + Point; while (1) { pmax = l->data + l->len; while (((ch = *w) != 0) && (p < pmax)) { if ((upcase(ch) != upcase(*p))) return 0; p++; w++; } if (ch == 0) return 1; l = l->next; if (l == NULL) return 0; p = l->data; } } void skip_chars1(char *range, int reverse) { unsigned char lut[256]; unsigned char *p, *pmax; Line *line; int n = 0; SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse); /* more flexibility is achieved with following line */ if (reverse && lut['\n']) lut['\n'] = 0; line = CLine; while (line != NULL) { CLine = line; p = line->data + Point; pmax = line->data + line->len; while (p < pmax) { if (0 == lut[*p]) { Point = (int)(p - CLine->data); LineNum += n; return; } p++; } Point = 0; line = CLine->next; n++; } eob(); } void bskip_chars1(char *range, int reverse) { unsigned char lut[256]; unsigned char *p; Line *line = CLine; int n = 0; SLmake_lut(lut, (unsigned char *) range, (unsigned char) reverse); /* more flexibility is achieved with following line */ if (reverse && lut['\n']) lut['\n'] = 0; while (1) { if (Point == 0) { if (lut['\n'] == 0) return; if (NULL == (line = CLine->prev)) break; Point = line->len - 1; n++; } CLine = line; p = line->data + (Point - 1); while (p >= line->data) { if (0 == lut[*p]) { Point = 1 + (int)(p - line->data); LineNum -= n; return; } p--; } Point = 0; } bob(); } void skip_chars (char *range) { if (*range == '^') skip_chars1(range + 1, 1); else { if (*range == '\\') range++; skip_chars1(range, 0); } } void bskip_chars (char *range) { if (*range == '^') bskip_chars1(range + 1, 1); else { if (*range == '\\') range++; bskip_chars1(range, 0); } }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.