/* -*- mode: C; mode: fold; -*- */ /* Copyright (c) 1992, 1998, 2000, 2002, 2003, 2004, 2005, 2006 John E. Davis * This file is part of JED editor library source. * * You may distribute this file under the terms the GNU General Public * License. See the file COPYING for more information. */ #include "config.h" #include "jed-feat.h" #include #include #include "jdmacros.h" #include #if defined(IBMPC_SYSTEM) && !defined(__CYGWIN32__) && !defined(__IBMC__) # include #endif #include "buffer.h" #include "screen.h" #include "window.h" #include "paste.h" #include "ins.h" #include "ledit.h" #include "display.h" #include "sysdep.h" #include "misc.h" #include "file.h" #include "hooks.h" #include "menu.h" #include "version.h" #include "indent.h" #include "colors.h" #if JED_HAS_SUBPROCESSES # include "jprocess.h" #endif #include "sig.h" #if SLANG_VERSION < 20000 #define SLstack_depth _SLstack_depth extern int _SLstack_depth(void); #endif volatile int Jed_Resize_Pending; char *MiniBuf_Get_Response_String; int Jed_Simulate_Graphic_Chars; typedef struct Screen_Type { Line *line; /* buffer line structure */ int is_modified; unsigned char *hi0, *hi1; /* beg end of hilights */ } Screen_Type; static Screen_Type *JScreen; int Jed_Num_Screen_Rows; int Jed_Num_Screen_Cols; int Screen_Row = 1; int Screen_Col = 1; int Cursor_Motion; /* indicates cursor movement only -1 ^ v +1 < > */ int Jed_Dollar = '$'; int Jed_Highlight_Trailing_WS = 0; int User_Prefers_Line_Numbers = 0; int Mode_Has_Syntax_Highlight; int Wants_Syntax_Highlight = 1; /* if non-zero, highlight the syntax. */ int Wants_Attributes = 1; int Wants_HScroll = 20; /* controls automatic horizontal * scrolling. If positive, scroll * only line, if negative, whole wind */ int Term_Supports_Color = 1; /* optimistic assumption */ int Goal_Column; int Want_Eob = 0; int Display_Time = 1; /* Turn on %t processing in status line */ void (*X_Update_Open_Hook)(void); /* hooks called when starting */ void (*X_Update_Close_Hook)(void); /* and finishing update */ /* site.sl should modify this */ char Default_Status_Line[80] = " ^Ke: quit, ^Kg: get file, ^K^W: write file | %b (%m%n%o) %p"; static Line *HScroll_Line; static int HScroll; /* amount to scroll line by */ static int Absolute_Column; static int Point_Cursor_Flag = 1; /* if non-zero, point cursor */ int Jed_Display_Initialized; static Line Eob_Line = { NULL, NULL, (unsigned char *) "[EOB]", 5 #ifdef KEEP_SPACE_INFO ,5 #endif #if JED_HAS_LINE_ATTRIBUTES , JED_LINE_IS_READONLY #endif }; #if SLANG_VERSION < 20000 static unsigned char Char_Width[256]; static int Display_Eight_Bit = 0x7FFF; # define FIX_CHAR_WIDTH \ if (SLsmg_Display_Eight_Bit != Display_Eight_Bit) fix_char_width () #endif static void display_line (Line *line, int sy, int sx) { unsigned int len; int hscroll_col; int is_mini; Screen_Type *s; #if JED_HAS_LINE_MARKS Mark *line_marks; #endif int num_columns; int color_set; SLsmg_Tab_Width = Buffer_Local.tab; #if SLANG_VERSION >= 20000 (void) SLsmg_embedded_escape_mode (CBuf->flags & SMG_EMBEDDED_ESCAPE); #endif is_mini = (sy + 1 == Jed_Num_Screen_Rows); SLsmg_gotorc (sy, sx); SLsmg_set_color (0); s = JScreen + sy; s->line = line; s->is_modified = 0; if (line == NULL) { SLsmg_erase_eol (); return; } hscroll_col = JWindow->hscroll_column - 1; if ((line == HScroll_Line) && Wants_HScroll && HScroll) hscroll_col += HScroll; num_columns = JWindow->width; if (hscroll_col || sx || (CBuf->line_num_display_size)) { int tmp = hscroll_col - (sx + CBuf->line_num_display_size); SLsmg_set_screen_start (NULL, &tmp); num_columns -= CBuf->line_num_display_size; sx = 0; } len = line->len; if (is_mini) { SLsmg_Newline_Behavior = SLSMG_NEWLINE_PRINTABLE; SLsmg_write_string ((char *)Mini_Info.prompt); } else { SLsmg_Newline_Behavior = 0; if (len && (line->data[len - 1] == '\n')) len--; } color_set = 0; #if JED_HAS_LINE_ATTRIBUTES if (line->flags & JED_LINE_COLOR_BITS) { SLsmg_set_color (JED_GET_LINE_COLOR(line)); color_set = 1; } #endif #if JED_HAS_LINE_MARKS line_marks = CBuf->user_marks; if (color_set == 0) while (line_marks != NULL) { if ((line_marks->line == line) && (line_marks->flags & JED_LINE_MARK)) { SLsmg_set_color (line_marks->flags & MARK_COLOR_MASK); color_set = 1; break; } line_marks = line_marks->next; } #endif if (len) { if ((color_set == 0) && Mode_Has_Syntax_Highlight && (line != &Eob_Line) #if !defined(IBMPC_SYSTEM) && (*tt_Use_Ansi_Colors && Term_Supports_Color) #endif && Wants_Syntax_Highlight) write_syntax_highlight (sy, line, len); else { if (Jed_Highlight_Trailing_WS) { unsigned char *pmin = line->data; unsigned char *pmax = pmin + len; unsigned char *p = pmax; while (p > pmin) { p--; if ((*p != ' ') && (*p != '\t')) { p++; break; } } SLsmg_write_nchars ((char *)pmin, p - pmin); if (p != pmax) { SLsmg_set_color (JTWS_COLOR); SLsmg_write_nchars ((char *)p, pmax - p); } } else SLsmg_write_nchars ((char *)line->data, len); } } #if JED_HAS_LINE_ATTRIBUTES if ((line->next != NULL) && (line->next->flags & JED_LINE_HIDDEN)) { SLsmg_set_color (JDOTS_COLOR); SLsmg_write_string ("..."); SLsmg_set_color (0); } #endif SLsmg_erase_eol (); if (Jed_Dollar) { char dollar = (char) Jed_Dollar; if (hscroll_col + num_columns <= SLsmg_get_column ()) { SLsmg_gotorc (sy, hscroll_col + num_columns - 1); SLsmg_set_color (JDOLLAR_COLOR); SLsmg_write_nchars (&dollar, 1); } if (hscroll_col) { SLsmg_gotorc (sy, hscroll_col); SLsmg_set_color (JDOLLAR_COLOR); SLsmg_write_nchars (&dollar, 1); } } if ((s->hi0 != NULL) && Wants_Attributes) { int c; len = (int) (s->hi1 - s->hi0); if (len && (s->hi0[len - 1] == '\n')) len--; if (len) { c = jed_compute_effective_length (line->data, s->hi0); if (is_mini) c += Mini_Info.effective_prompt_len; SLsmg_gotorc (sy, c); SLsmg_set_color (JREGION_COLOR); SLsmg_write_nchars ((char *)s->hi0, len); } } /* if (hscroll_col + sx) */ SLsmg_set_screen_start (NULL, NULL); SLsmg_set_color (0); } #if JED_HAS_DISPLAY_LINE_NUMBERS static void display_line_numbers (void) { unsigned int i, imin, imax, linenum; Line *line_start, *line; char buf[32], format[32]; unsigned int c; imin = JWindow->sy; imax = imin + JWindow->rows; line = NULL; for (i = imin; i < imax; i++) { if (JScreen[i].line != CLine) continue; line = JScreen[i].line; break; } if (line == NULL) return; /* ??? */ line_start = JScreen[imin].line; linenum = LineNum + CBuf->nup; while (line != line_start) { if (line == NULL) return; /* ??? */ linenum--; line = line->prev; } sprintf (format, "%%%dd ", CBuf->line_num_display_size-1); SLsmg_set_color (JLINENUM_COLOR); c = JWindow->sx; for (i = imin; i < imax; i++) { line_start = JScreen[i].line; if (line_start == NULL) break; while (line != line_start) { if (line == NULL) return; /* ??? */ linenum++; line = line->next; } SLsmg_gotorc (i, c); sprintf (buf, format, linenum); SLsmg_write_string (buf); line = line->next; linenum++; } if (i < imax) { memset (buf, ' ', CBuf->line_num_display_size); buf[CBuf->line_num_display_size] = 0; while (i < imax) { SLsmg_gotorc (i, c); SLsmg_write_string (buf); i++; } } SLsmg_set_color (0); } #endif #if JED_HAS_LINE_ATTRIBUTES static int Non_Hidden_Point; Line *jed_find_non_hidden_line (Line *l) { int dir; Line *cline; Non_Hidden_Point = 0; if (0 == (l->flags & JED_LINE_HIDDEN)) { return l; } cline = l; dir = 1; while ((cline != NULL) && (cline->flags & JED_LINE_HIDDEN)) cline = cline->prev; if (cline == NULL) { cline = l; dir = -1; while ((cline != NULL) && (cline->flags & JED_LINE_HIDDEN)) cline = cline->next; if (cline == NULL) return NULL; } if (dir == 1) { Non_Hidden_Point = cline->len; } return cline; } #endif Line *jed_find_top_to_recenter (Line *cline) { int n; Line *prev, *last_prev; n = JWindow->rows / 2; last_prev = prev = cline; while ((n > 0) && (prev != NULL)) { n--; last_prev = prev; #if JED_HAS_LINE_ATTRIBUTES do { prev = prev->prev; } while ((prev != NULL) && (prev->flags & JED_LINE_HIDDEN)); #else prev = prev->prev; #endif } if (prev != NULL) return prev; return last_prev; } Line *find_top (void) { int nrows, i; Line *cline, *prev, *next; Line *top_window_line; cline = CLine; #if JED_HAS_LINE_ATTRIBUTES if (cline->flags & JED_LINE_HIDDEN) cline = jed_find_non_hidden_line (cline); if (cline == NULL) return NULL; #endif nrows = JWindow->rows; if (nrows <= 1) return cline; /* Note: top_window_line might be a bogus pointer. This means that I cannot * access it unless it really corresponds to a pointer in the buffer. */ top_window_line = JScreen [JWindow->sy].line; if (top_window_line == NULL) return jed_find_top_to_recenter (cline); /* Chances are that the current line is visible in the window. This means * that the top window line should be above it. */ prev = cline; i = 0; while ((i < nrows) && (prev != NULL)) { if (prev == top_window_line) { return top_window_line; } #if JED_HAS_LINE_ATTRIBUTES do { prev = prev->prev; } while ((prev != NULL) && (prev->flags & JED_LINE_HIDDEN)); #else prev = prev->prev; #endif i++; } /* Now check the borders of the window. Perhaps the current line lies * outsider the border by a line. Only do this if terminal can scroll. */ if ((*tt_Term_Cannot_Scroll) && (*tt_Term_Cannot_Scroll != -1)) return jed_find_top_to_recenter (cline); next = cline->next; #if JED_HAS_LINE_ATTRIBUTES while ((next != NULL) && (next->flags & JED_LINE_HIDDEN)) next = next->next; #endif if ((next != NULL) && (next == top_window_line)) return cline; prev = cline->prev; #if JED_HAS_LINE_ATTRIBUTES while ((prev != NULL) && (prev->flags & JED_LINE_HIDDEN)) prev = prev->prev; #endif top_window_line = JScreen [nrows + JWindow->sy - 1].line; if ((prev == NULL) || (prev != top_window_line)) return jed_find_top_to_recenter (cline); /* It looks like cline is below window by one line. See what line should * be at top to scroll it into view. */ i = 2; while ((i < nrows) && (prev != NULL)) { #if JED_HAS_LINE_ATTRIBUTES do { prev = prev->prev; } while ((prev != NULL) && (prev->flags & JED_LINE_HIDDEN)); #else prev = prev->prev; #endif i++; } if (prev != NULL) return prev; return jed_find_top_to_recenter (cline); } #if SLANG_VERSION >= 20000 static void init_smg_for_buffer (int *rowp, int *colp) { SLsmg_Tab_Width = Buffer_Local.tab; if (IS_MINIBUFFER) SLsmg_Newline_Behavior = SLSMG_NEWLINE_PRINTABLE; else SLsmg_Newline_Behavior = 0; (void) SLsmg_embedded_escape_mode (CBuf->flags & SMG_EMBEDDED_ESCAPE); *rowp = SLsmg_get_row (); *colp = SLsmg_get_column (); SLsmg_gotorc (0, 0); } void point_column (int n) { SLuchar_Type *p, *pmax; int row, col; /* Compensate for the prompt */ if (IS_MINIBUFFER) n -= Mini_Info.effective_prompt_len; p = CLine->data; pmax = p + CLine->len; if (LINE_HAS_NEWLINE (CLine)) pmax--; init_smg_for_buffer (&row, &col); n = (int) SLsmg_strbytes (p, pmax, (unsigned int) n); SLsmg_gotorc (row, col); jed_set_point (n); } int jed_compute_effective_length (unsigned char *pos, unsigned char *pmax) { int len, row, col; init_smg_for_buffer (&row, &col); len = (int) SLsmg_strwidth (pos, pmax); SLsmg_gotorc (row, col); return len; } #else /* This function has to be consistent with SLsmg. */ static void fix_char_width(void) { int i, ebit; ebit = SLsmg_Display_Eight_Bit; if (ebit < 128) ebit = 128; /* Control Characters */ for (i = 0; i < 32; i++) Char_Width[i] = 2; for (i = 32; i < 127; i++) Char_Width[i] = 1; Char_Width[127] = 2; for (i = 128; i < ebit; i++) Char_Width[i] = 3; /* ~^X */ for (i = ebit; i < 256; i++) Char_Width[i] = 1; Display_Eight_Bit = ebit; } void point_column (int n) { register unsigned char *p, *pmax; register int i; int tab, w; FIX_CHAR_WIDTH; if (IS_MINIBUFFER) n -= Mini_Info.effective_prompt_len; p = CLine->data; pmax = p + CLine->len; if (LINE_HAS_NEWLINE (CLine)) pmax--; tab = Buffer_Local.tab; i = 0; n--; /* start at 0 */ while (p < pmax) { unsigned int nconsumed = 1; if ((*p == '\t') && tab) { i = tab * (i / tab + 1); } else { w = Char_Width[*p]; i += w; } if (i > n) break; p += nconsumed; } jed_set_point (p - CLine->data); } int jed_compute_effective_length (unsigned char *pos, unsigned char *pmax) { int i; int tab, w; register unsigned char *cw = Char_Width; register unsigned char ch; FIX_CHAR_WIDTH; i = 0; tab = Buffer_Local.tab; while (pos < pmax) { ch = *pos++; if ((ch == '\t') && tab) { i = tab * (i/tab + 1); /* tab column tabs */ } else { w = cw[ch]; i += w; if (w == 0) pos++; } } return i; } #endif /* SLANG_VERSION >= 20000 */ int calculate_column (void) { int c; c = 1 + jed_compute_effective_length (CLine->data, CLine->data + Point); Absolute_Column = c; if (IS_MINIBUFFER) c += Mini_Info.effective_prompt_len; Screen_Col = c; return (c); } void point_cursor (int c) { int r, row; Line *tthis, *cline; if (JWindow->trashed) return; cline = CLine; #if JED_HAS_LINE_ATTRIBUTES if (cline->flags & JED_LINE_HIDDEN) { cline = jed_find_non_hidden_line (cline); if (cline != NULL) c = Non_Hidden_Point; } #endif r = JWindow->sy + 1; Point_Cursor_Flag = 0; for (row = r; row < r + JWindow->rows; row++) { tthis = JScreen[row-1].line; if (tthis == NULL) break; if ((tthis == cline) || (tthis == &Eob_Line)) { r = row; break; } } if (Point >= CLine->len) { Point = CLine->len - 1; if (Point < 0) Point = 0; else if ((*(CLine->data + Point) != '\n') || (CBuf == MiniBuffer)) Point++; } if (c == 0) c = calculate_column (); c -= (JWindow->hscroll_column - 1); if (cline == HScroll_Line) c -= HScroll; if (c < 1) c = 1; else if (c > JWindow->width) c = JWindow->width; c += JWindow->sx + CBuf->line_num_display_size; SLsmg_gotorc (r - 1, c - 1); Screen_Row = r; Screen_Col = c; SLsmg_refresh (); if (!Cursor_Motion) Goal_Column = c; } static unsigned long Status_Last_Time; static unsigned long Status_This_Time; static char *status_get_time(void) { static char status_time[10]; register char *t, ch, *t1; char am; int n; if (Display_Time == 0) return (NULL); if (Status_This_Time == 0) Status_This_Time = sys_time(); if (Status_This_Time - Status_Last_Time >= 30) { Status_Last_Time = Status_This_Time; am = 'a'; t = SLcurrent_time_string (); /* returns a string like: "Tue Nov 2 13:18:19 1993" */ t1 = status_time; while (ch = *t, (ch <= '0') || (ch > '9')) t++; /* on date number, skip it */ while (*t++ != ' '); if (*t == '0') t++; if (Display_Time > 0) { n = 0; while ((ch = *t++) != ':') { n = 10 * n + (int) (ch - '0'); } if (n >= 12) am = 'p'; n = n % 12; if (n == 0) n = 12; if (n >= 10) { n -= 10; *t1++ = '1'; } *t1++ = '0' + n; *t1++ = ':'; while ((*t1++ = *t++) != ':'); *(t1 - 1) = am; *t1++ = 'm'; *t1 = 0; } else { *t1++ = '['; while ((*t1++ = *t++) != ':'); while ((*t1++ = *t++) != ':'); *--t1 = ']'; *++t1 = 0; } } return (status_time); } static void finish_status(int col_flag) { char *v, ch; Line *l; int top, rows, narrows; char buf [256]; char *str; v = CBuf->status_line; if (*v == 0) v = Default_Status_Line; while (1) { while (1) { ch = *v++; if (ch == 0) return; if (ch == '%') break; SLsmg_write_nchars (&ch, 1); } ch = *v++; switch (ch) { case 'F': SLsmg_write_string (CBuf->dir); str = CBuf->file; break; case 'S': /* stack depth */ sprintf(buf, "%03d", SLstack_depth()); str = buf; break; case 'a': if (CBuf->flags & ABBREV_MODE) str = " abbrev"; else str = NULL; break; case 'f': str = CBuf->file; break; case 'n': narrows = jed_count_narrows (); if (narrows) { sprintf (buf, " Narrow[%d]", narrows); str = buf; } else str = NULL; break; case 'o': if (CBuf->flags & OVERWRITE_MODE) str = " Ovwrt"; else str = NULL; break; case 'O': if (CBuf->flags & OVERWRITE_MODE) str = " ovr"; else str = " ins"; break; case 'b': str = CBuf->name; break; case 'p': str = buf; if (0 == User_Prefers_Line_Numbers) { top = JWindow->sy; rows = JWindow->rows - 1; l = JScreen[top + rows].line; if (l == CBuf->end) l = NULL; if (JScreen[top].line == CBuf->beg) { if (l == NULL) str = "All"; else str = "Top"; } else if (l == NULL) str = "Bot"; else { sprintf(buf, "%d%%", (int) ((LineNum * 100L) / (long) Max_LineNum)); } } else { if (User_Prefers_Line_Numbers == 1) sprintf(buf, "%d/%d", LineNum, Max_LineNum); else { if (col_flag) (void) calculate_column (); sprintf(buf, "%d/%d,%d", LineNum, Max_LineNum, Absolute_Column); } } break; case 'l': sprintf(buf, "%d", LineNum); str=buf; break; case 'L': sprintf(buf, "%d", Max_LineNum); str=buf; break; case 'v': #if JED_HAS_UTF8_SUPPORT SLsmg_write_string (Jed_Version_String); if (Jed_UTF8_Mode) str = "U"; else str = NULL; #else str = Jed_Version_String; #endif break; case 'm': str = CBuf->mode_string; break; case 't': str = status_get_time(); break; case 'c': if (col_flag) (void) calculate_column (); sprintf(buf, "%d", Absolute_Column); str = buf; break; case '%': str = "%"; break; case 0: return; default: str = NULL; } if (str != NULL) SLsmg_write_string (str); } } void set_status_format(char *f, int *local) { char *s; if (*local) s = Default_Status_Line; else s = CBuf->status_line; strncpy(s, f, 79); s[79] = 0; } static int update_status_line (int col_flag) { unsigned char star0, star1; char buf[32], *b; int num; if (JWindow->sy + 1 == Jed_Num_Screen_Rows) return 0; /* minibuffer ? */ SLsmg_gotorc (JWindow->rows + JWindow->sy, 0); SLsmg_set_color (JSTATUS_COLOR); b = buf; if (JWindow->hscroll_column != 1) *b++ = '<'; else *b++ = '-'; if (CBuf->flags & BUFFER_MODIFIED) star0 = star1 = '*'; else star0 = star1 = '-'; if ((CBuf->flags & READ_ONLY) #if JED_HAS_LINE_ATTRIBUTES || (CLine->flags & JED_LINE_IS_READONLY) #endif ) star0 = star1 = '%'; #if JED_HAS_SUBPROCESSES if (CBuf->subprocess) star1 = 'S'; #endif *b++ = star0; *b++ = star1; if (CBuf->marks != NULL) *b++ = 'm'; else *b++ = '-'; if (CBuf->flags & FILE_MODIFIED) *b++ = 'd'; else *b++ = '-'; if (CBuf->spots != NULL) *b++ = 's'; else *b++ = '-'; if (CBuf->flags & BINARY_FILE) *b++ = 'B'; #ifdef IBMPC_SYSTEM else if ((CBuf->flags & ADD_CR_ON_WRITE_FLAG) == 0) *b++ = 'L'; #else # ifdef __unix__ else if (CBuf->flags & ADD_CR_ON_WRITE_FLAG) *b++ = 'C'; # endif #endif else *b++ = '-'; if (CBuf->flags & UNDO_ENABLED) *b++ = '+'; else *b++ = '-'; SLsmg_write_nchars (buf, (unsigned int) (b - buf)); finish_status (col_flag); if (Defining_Keyboard_Macro) SLsmg_write_string (" [Macro]"); num = Jed_Num_Screen_Cols - SLsmg_get_column (); star1 = '-'; while (num > 0) { SLsmg_write_nchars ((char *) &star1, 1); num--; } SLsmg_set_color (0); Point_Cursor_Flag = 1; return 1; } static int screen_input_pending (int tsec) { if (Input_Buffer_Len #ifdef HAS_RESIZE_PENDING || Jed_Resize_Pending #endif ) return 1; return input_pending (&tsec); } /* This routine is called before the window is updated. This means that the * line structures attached to the screen array cannot be trusted. However, * the current line (or nearest visible one) can be assumed to lie in * the window. */ static void mark_window_attributes (int wa) { register Screen_Type *s = &JScreen[JWindow->sy], *smax = s + JWindow->rows, *s1, *s2; Mark *m; register Line *l = JWindow->beg.line, *ml, *cline; unsigned char *hi0, *hi1; int mn, pn, dn, point, mpoint; s1 = s; #if JED_HAS_LINE_ATTRIBUTES cline = jed_find_non_hidden_line (CLine); if (cline != CLine) point = Non_Hidden_Point; /* updated by jed_find_non_hidden_line */ else point = Point; #else cline = CLine; point = Point; #endif if ((CBuf->vis_marks == 0) || (wa == 0) || (Wants_Attributes == 0) #if JED_HAS_LINE_ATTRIBUTES || (l->flags & JED_LINE_HIDDEN) #endif ) { s2 = s; goto done; /* I hate gotos but they are convenient */ } m = CBuf->marks; while ((m->flags & VISIBLE_MARK_MASK) == 0) m = m->next; ml = m->line; mn = m->n; /* already in canonical form */ pn = LineNum + CBuf->nup; /* not in canonical form */ dn = pn - mn; #if JED_HAS_LINE_ATTRIBUTES ml = jed_find_non_hidden_line (ml); if (ml == cline) dn = 0; if (ml != m->line) { mpoint = Non_Hidden_Point; /* updated by jed_find_non_hidden_line */ } else mpoint = m->point; #else mpoint = m->point; #endif /* find Screen Pos of point in window. It has to be there */ while (l != cline) { l = l->next; #if JED_HAS_LINE_ATTRIBUTES if (l->flags & JED_LINE_HIDDEN) continue; #endif s1++; } /* s1 now points at current line */ /* The whole point of all of this is to preserve the screen flags without * touching the screen. */ if (dn > 0) /* mark on prev lines */ { s2 = s1 + 1; hi0 = l->data; hi1 = l->data + point; if ((s1->hi0 != hi0) || (s1->hi1 != hi1)) { s1->hi0 = hi0; s1->hi1 = hi1; s1->is_modified = 1; } l = l->prev; s1--; while ((s1 >= s) && (l != ml) && (l != NULL)) { #if JED_HAS_LINE_ATTRIBUTES if (l->flags & JED_LINE_HIDDEN) { l = l->prev; continue; } #endif hi0 = l->data; hi1 = l->data + l->len; if ((s1->hi0 != hi0) || (s1->hi1 != hi1)) { s1->hi0 = hi0; s1->hi1 = hi1; s1->is_modified = 1; } s1--; l = l->prev; } if (s1 >= s) { hi0 = ml->data + mpoint; hi1 = ml->data + ml->len; if ((s1->hi0 != hi0) || (s1->hi1 != hi1)) { s1->hi0 = hi0; s1->hi1 = hi1; s1->is_modified = 1; } s1--; } } else if (dn < 0) /* mark ahead of point */ { s2 = s1; s1--; hi0 = l->data + point; hi1 = l->data + l->len; if ((s2->hi0 != hi0) || (s2->hi1 != hi1)) { s2->hi0 = hi0; s2->hi1 = hi1; s2->is_modified = 1; } l = l->next; s2++; while ((s2 < smax) && (l != ml) && (l != NULL)) { #if JED_HAS_LINE_ATTRIBUTES if (l->flags & JED_LINE_HIDDEN) { l = l->next; continue; } #endif hi0 = l->data; hi1 = l->data + l->len; if ((s2->hi0 != hi0) || (s2->hi1 != hi1)) { s2->hi0 = hi0; s2->hi1 = hi1; s2->is_modified = 1; } l = l->next; s2++; } if (s2 < smax) { hi0 = ml->data; hi1 = ml->data + mpoint; if ((s2->hi0 != hi0) || (s2->hi1 != hi1)) { s2->hi0 = hi0; s2->hi1 = hi1; s2->is_modified = 1; } s2++; } } else /* same line */ { if (point < mpoint) { s1->hi0 = l->data + point; s1->hi1 = l->data + mpoint; } else { s1->hi1 = l->data + point; s1->hi0 = l->data + mpoint; } s1->is_modified = 1; s2 = s1 + 1; s1--; } done: /* reached if there is no mark */ /* now do area outside the region */ while (s1 >= s) { if (s1->hi0 != NULL) { s2->hi1 = s1->hi0 = NULL; s1->is_modified = 1; } s1--; } while (s2 < smax) { if (s2->hi0 != NULL) { s2->hi1 = s2->hi0 = NULL; s2->is_modified = 1; } s2++; } } static void compute_line_display_size (void) { #if JED_HAS_DISPLAY_LINE_NUMBERS int max_num_len = 0; int n; if (CBuf->line_num_display_size == 0) return; n = Max_LineNum + CBuf->nup; while (n != 0) { n /= 10; max_num_len++; } max_num_len++; /* add one as a separator */ if (CBuf->line_num_display_size != max_num_len) { JWindow->trashed = 1; CBuf->line_num_display_size = max_num_len; } #endif } /* if force then do update otherwise return 1 if update or 0 if not */ static int update_1(Line *top, int force) { int i; Window_Type *w; int did_eob, time_has_expired = 0; if (Batch || (!force && (Executing_Keyboard_Macro || (Repeat_Factor != NULL) || screen_input_pending (0) || (Read_This_Character != NULL))) || (CBuf != JWindow->buffer)) { return(0); } if (Suspend_Screen_Update != 0) { Suspend_Screen_Update = 0; touch_screen (); } JWindow->mark.line = CLine; JWindow->mark.point = Point; JWindow->mark.n = LineNum + CBuf->nup; CBuf->linenum = LineNum; CBuf->max_linenum = Max_LineNum; if (Wants_Attributes && CBuf->vis_marks) { JWindow->trashed = 1; } /* Do not bother setting this unless it is really needed */ if (Display_Time) { Status_This_Time = sys_time(); time_has_expired = (Status_This_Time > Status_Last_Time + 45); } /* if cursor moves just left right, do not update status line */ if (!force && !JWindow->trashed && ((JWindow == JWindow->next) || (User_Prefers_Line_Numbers && Cursor_Motion)) /* if % wanted, assume user is like me and gets annoyed with * screen updates */ && (User_Prefers_Line_Numbers || time_has_expired)) { update_status_line(0); return(1); } if (!JWindow->trashed && Cursor_Motion) { #if JED_HAS_LINE_ATTRIBUTES if (CLine->flags & JED_LINE_IS_READONLY) update_status_line (0); #endif return 1; } w = JWindow; do { int imax; unsigned int start_column; #if JED_HAS_LINE_ATTRIBUTES if (CBuf->min_unparsed_line_num) jed_syntax_parse_buffer (0); #endif if (Wants_Syntax_Highlight) init_syntax_highlight (); #if JED_HAS_LINE_ATTRIBUTES if (top != NULL) top = jed_find_non_hidden_line (top); #endif #if SLANG_VERSION >= 20000 /* (void) SLsmg_utf8_enable (CBuf->local_vars.is_utf8); */ #endif if (top == NULL) { top = find_top(); if (top == NULL) top = CLine; } JWindow->beg.line = top; #if JED_HAS_LINE_ATTRIBUTES if (top->flags & JED_LINE_HIDDEN) top = NULL; else #endif mark_window_attributes ((w == JWindow) || (w->buffer != CBuf)); did_eob = 0; i = JWindow->sy; imax = i + JWindow->rows; compute_line_display_size (); start_column = JWindow->sx; while (i < imax) { #if JED_HAS_LINE_ATTRIBUTES if ((top != NULL) && (top->flags & JED_LINE_HIDDEN)) { top = top->next; continue; } #endif /* the next line is really optional */ #if 0 if (!force && (Exit_From_MiniBuffer || screen_input_pending (0))) break; #endif if ((JScreen[i].line != top) || JScreen[i].is_modified || (Want_Eob && !did_eob && (i != Jed_Num_Screen_Rows - 1) && (top == NULL))) { if (((top == NULL) || (top->len == 0)) && (Want_Eob && !did_eob && !(CBuf->flags & READ_ONLY))) { display_line(&Eob_Line, i, start_column); /* JScreen[i].line = top; */ did_eob = 1; } else display_line(top, i, start_column); } if (top != NULL) top = top->next; i++; } HScroll_Line = NULL; Mode_Has_Syntax_Highlight = 0; if (!force && screen_input_pending (0)) { while(JWindow != w) other_window(); JWindow->trashed = 1; /* since cursor not pointed */ #if SLANG_VERSION >= 20000 /* (void) SLsmg_utf8_enable (1); */ /* default state */ #endif return(0); } else update_status_line(w != JWindow); #if JED_HAS_DISPLAY_LINE_NUMBERS if (CBuf->line_num_display_size) display_line_numbers (); #endif JWindow->trashed = 0; other_window(); top = NULL; /* if (!JWindow->trashed) top = JWindow->beg.line; else top = NULL; */ } while (JWindow != w); #if SLANG_VERSION >= 20000 /* SLsmg_utf8_enable (1); */ /* default state */ #endif return 1; } int Mini_Ghost = 0; char Message_Buffer[256]; static void do_dialog(char *b) { char *quit = "Quit!"; if (Batch) return; #ifdef FIX_CHAR_WIDTH FIX_CHAR_WIDTH; #endif if (! *b) { if(!SLKeyBoard_Quit) return; b = quit; } if ((b == Error_Buffer) || (b == quit)) { SLsmg_set_color (JERROR_COLOR); touch_screen(); } else SLsmg_set_color (JMESSAGE_COLOR); SLsmg_Newline_Behavior = SLSMG_NEWLINE_PRINTABLE; SLsmg_gotorc (Jed_Num_Screen_Rows - 1, 0); SLsmg_write_string (b); SLsmg_set_color (0); SLsmg_erase_eol (); SLsmg_Newline_Behavior = 0; if ((b == Error_Buffer) || (SLKeyBoard_Quit)) { jed_beep(); flush_input(); } if (*b) { if (MiniBuffer != NULL) { SLsmg_refresh (); (void) input_pending(&Number_Ten); } Mini_Ghost = -1; } else Mini_Ghost = 0; } void clear_message (void) /*{{{*/ { message (NULL); } /*}}}*/ void message (char *msg) { if (Executing_Keyboard_Macro) return; if (msg == NULL) { if (Batch) return; msg = ""; } if (Batch) fprintf(stdout, "%s\n", msg); if (*msg == 0) Mini_Ghost = 1; strncpy(Message_Buffer, msg, sizeof(Message_Buffer)); Message_Buffer[sizeof(Message_Buffer)-1] = 0; } void flush_message (char *m) { message(m); if (Batch || (JWindow == NULL)) return; do_dialog(Message_Buffer); SLsmg_gotorc (Jed_Num_Screen_Rows - 1, strlen(Message_Buffer)); *Message_Buffer = 0; JWindow->trashed = 1; SLsmg_refresh (); } static void update_minibuffer(void) { Window_Type *w; if (Executing_Keyboard_Macro) return; if (MiniBuffer != NULL) { w = JWindow; while (!IS_MINIBUFFER) other_window(); JWindow->beg.line = CLine; mark_window_attributes (1); display_line(CLine, Jed_Num_Screen_Rows-1, 0); while (w != JWindow) other_window(); Mini_Ghost = 1; } else if (Mini_Ghost && !*Error_Buffer && !*Message_Buffer) { /* if < 0, it is a result of flush message so let it pass this round */ if (Mini_Ghost < 0) Mini_Ghost = 1; else Mini_Ghost = 0; } else Mini_Ghost = ((*Message_Buffer) || (*Error_Buffer)); if (Mini_Ghost == 0) display_line(NULL, Jed_Num_Screen_Rows-1, 0); } static void set_hscroll(int col) { int hdiff, whs = abs(Wants_HScroll), wc = JWindow->hscroll_column - 1; int sw = Jed_Num_Screen_Cols - CBuf->line_num_display_size - 1; static Line *last; Line *tmp; if (sw < 1) sw = 1; /* take care of last effect of horizontal scroll */ if (last != NULL) { tmp = CLine; CLine = last; register_change(0); CLine = tmp; if (last != CLine) { #if 0 /* I need to think about this more */ if (Wants_HScroll < 0) { if (wc != 0) { JWindow->column = 1; wc = 0; touch_window (); } } #endif HScroll = 0; } last = NULL; } col--; /* use 0 origin */ hdiff = col - wc; if ((HScroll >= hdiff) || (HScroll <= hdiff - sw)) { if (hdiff >= sw) { HScroll = hdiff - sw + whs; } else if ((hdiff == 0) && (wc == 0)) HScroll = 0; else if (hdiff <= 1) { HScroll = hdiff - whs - 1; } else HScroll = 0; } if (HScroll) { if (wc + HScroll < 0) HScroll = -wc; if (Wants_HScroll < 0) { JWindow->hscroll_column += HScroll; touch_window(); HScroll = 0; } else { register_change(0); last = HScroll_Line = CLine; } } } static char Top_Screen_Line_Buffer[132] = "If you see this, you have an installation problem."; void define_top_screen_line (char *neew) { SLang_push_string (Top_Screen_Line_Buffer); strncpy (Top_Screen_Line_Buffer, neew, sizeof (Top_Screen_Line_Buffer) - 1); Top_Screen_Line_Buffer[sizeof(Top_Screen_Line_Buffer) - 1] = 0; if (JScreen != NULL) JScreen[0].is_modified = 1; } static void update_top_screen_line (void) { #if JED_HAS_TTY_MENUS if (Jed_Menus_Active || (Top_Window_SY > 0)) { jed_redraw_menus (); return; } #else if (Top_Window_SY == 0) return; SLsmg_gotorc (0,0); SLsmg_set_color (JMENU_COLOR); SLsmg_write_string (Top_Screen_Line_Buffer); SLsmg_erase_eol (); JScreen[0].is_modified = 0; #endif } /* if flag is non-zero, do not touch the message/error buffers */ /* This routine is a mess and it, do_dialog, and the Mini_Ghost flag needs * to be totally redesigned. */ void update(Line *line, int force, int flag, int run_update_hook) { int pc_flag = 1; int col; static unsigned long last_time; Line *hscroll_line_save; if (0 == Jed_Display_Initialized) return; #if JED_HAS_SUBPROCESSES if (Child_Status_Changed_Flag) { jed_get_child_status (); force = 1; } #endif if (Batch) return; if (!force && !SLang_get_error () && !SLKeyBoard_Quit && (!*Error_Buffer)) { if (screen_input_pending (0)) { JWindow->trashed = 1; return; } } if (last_time + 30 < Status_This_Time) { if (last_time == 0) last_time = Status_This_Time; else { last_time = Status_This_Time; if (SLang_run_hooks ("update_timer_hook", 0)) flag = 0; } } if (run_update_hook && (CBuf->buffer_hooks != NULL) && (CBuf->buffer_hooks->update_hook != NULL) && (SLang_get_error () == 0)) { Suspend_Screen_Update = 1; SLexecute_function (CBuf->buffer_hooks->update_hook); if (SLang_get_error ()) CBuf->buffer_hooks->update_hook = NULL; } if (Suspend_Screen_Update != 0) { Suspend_Screen_Update = 0; touch_screen (); } if (X_Update_Open_Hook != NULL) (*X_Update_Open_Hook) (); #ifdef FIX_CHAR_WIDTH FIX_CHAR_WIDTH; #endif col = calculate_column (); HScroll_Line = NULL; if (Wants_HScroll) set_hscroll(col); else HScroll = 0; hscroll_line_save = HScroll_Line; if (SLang_get_error ()) flag = 0; /* update hook invalidates flag */ if (SLang_get_error () && !(*Error_Buffer || SLKeyBoard_Quit)) { #if SLANG_VERSION < 20000 SLang_doerror (""); #else SLang_verror (0, "%s", SLerr_strerror (0)); #endif } if (!flag && (*Error_Buffer || SLKeyBoard_Quit)) { do_dialog(Error_Buffer); #if 0 SLKeyBoard_Quit = 0; SLang_restart(0); SLang_set_error (0); #endif Mini_Ghost = 1; (void) update_1(line, 1); update_minibuffer(); } else if ((flag == 0) && *Message_Buffer) { if (!update_1(line, force)) goto done; do_dialog(Message_Buffer); Mini_Ghost = 1; update_minibuffer(); } else { pc_flag = JWindow->trashed || (JWindow != JWindow->next) || Cursor_Motion; if (!flag) update_minibuffer(); if (!update_1(line, force)) goto done; } if (!flag) *Error_Buffer = *Message_Buffer = 0; #if JED_HAS_TTY_MENUS update_top_screen_line (); #else if ((Top_Window_SY > 0) && JScreen[0].is_modified) { update_top_screen_line (); } #endif done: HScroll_Line = hscroll_line_save; if (MiniBuf_Get_Response_String != NULL) { do_dialog (MiniBuf_Get_Response_String); Mini_Ghost = 1; } else if (Point_Cursor_Flag || pc_flag) point_cursor(col); if (X_Update_Close_Hook != NULL) (*X_Update_Close_Hook) (); SLsmg_refresh (); } /* search for the CLine in the SCreen and flag it as changed */ /* n = 0 means line was changed, n = 1 means it was destroyed */ void register_change(int n) { Window_Type *w; register Screen_Type *s, *smax; register Line *cl = CLine; if (JScreen == NULL) return; JWindow->trashed = 1; if (Suspend_Screen_Update) return; if (No_Screen_Update) { No_Screen_Update = 0; if (((n == CINSERT) || (n == CDELETE)) && (JWindow->next == JWindow)) { /* Since no screen update, we are probably safe to do: */ /* JScreen[Screen_Row - 1].flags = 1; */ return; } w = JWindow->next; /* skip this window */ } else w = JWindow; do { s = &JScreen[w->sy]; smax = s + w->rows; while (s < smax) { if (s->line == cl) { s->is_modified = 1; if ((n == NLDELETE) || (n == LDELETE)) s->line = NULL; w->trashed = 1; } s++; } w = w->next; } while(w != JWindow); } int jed_get_screen_size (int *r, int *c) { if (tt_get_screen_size == NULL) { *r = 24; *c = 80; return 0; } (void) (*tt_get_screen_size) (r, c); if (*r <= 0) *r = 24; if (*c <= 0) *c = 80; if (*r > 1024) *r = 24; if (*c > 1024) *c = 80; /* Let's not be ridiculous */ if (*r <= 5) *r = 5; if (*c <= 5) *c = 5; return 0; } static void dealloc_display (void) { if (JScreen != NULL) { SLfree ((char *) JScreen); JScreen = NULL; } } void jed_reset_display (void) { if (Jed_Display_Initialized == 0) return; if (Batch) return; Jed_Display_Initialized = 0; #if defined(VMS) || defined(REAL_UNIX_SYSTEM) (void) jed_va_run_hooks ("_jed_reset_display_hooks", JED_HOOKS_RUN_ALL, 0); #endif dealloc_display (); SLsmg_reset_smg (); } static void alloc_display (void) { int r, c, i; jed_get_screen_size (&r, &c); jed_update_window_sizes (r, c); if (NULL == (JScreen = (Screen_Type *) jed_malloc0 (sizeof (Screen_Type) * r))) exit_error ("Out of memory", 0); for (i = 0; i < r; i++) JScreen[i].is_modified = 1; Jed_Num_Screen_Cols = c; Jed_Num_Screen_Rows = r; } void jed_init_display (void) { if (Batch) return; jed_reset_display (); alloc_display (); if (-1 == SLsmg_init_smg ()) exit_error ("init_display: error initializing display", 0); #if defined(VMS) || defined(REAL_UNIX_SYSTEM) (void) jed_va_run_hooks ("_jed_init_display_hooks", JED_HOOKS_RUN_ALL, 0); #endif Jed_Display_Initialized = 1; } void jed_resize_display (void) { Jed_Resize_Pending = 0; if (Jed_Display_Initialized == 0) return; dealloc_display (); alloc_display (); SLsmg_reinit_smg (); /* Add support for a resize-hook here */ /* (void) jed_va_run_hooks ("_jed_resize_display_hooks", JED_HOOKS_RUN_ALL, 0); */ jed_redraw_screen (0); } void jed_redraw_screen (int force) { int row, center; Window_Type *w; Line *l; if (Batch) return; SLsmg_set_color (0); SLsmg_cls (); if (JScreen == NULL) return; for (row = 0; row < Jed_Num_Screen_Rows; row++) { /* JScreen[row].line = NULL; */ JScreen[row].is_modified = 1; } if (NULL == (w = JWindow)) return; center = JWindow->trashed; do { w->trashed = 1; w = w->next; } while(w != JWindow); if (center) { for (row = 0; row < JWindow->rows; row++) { JScreen[row + JWindow->sy].line = NULL; } l = NULL; } else l = JWindow->beg.line; update(l, force, 0, 1); } void recenter(int *np) { Line *l = CLine; int i, n = *np; if (Batch) return; JWindow->trashed = 1; if (n == 0) { n = JWindow->rows / 2; i = 0; while (i < n) { if (l->prev == NULL) break; l = l->prev; #if JED_HAS_LINE_ATTRIBUTES if (l->flags & JED_LINE_HIDDEN) continue; #endif i++; } JWindow->beg.line = l; JWindow->beg.n -= i; JWindow->beg.point = 0; jed_redraw_screen (0); return; } if (CBuf != JWindow->buffer) return; if ((n <= 0) || (n > JWindow->rows)) n = JWindow->rows / 2; while (n > 1) { l = l->prev; if (l == NULL) { l = CBuf->beg; break; } #if JED_HAS_LINE_ATTRIBUTES if (l->flags & JED_LINE_HIDDEN) continue; #endif n--; } /* update(l, 1, 0, 1); */ JScreen [JWindow->sy].line = l; JScreen [JWindow->sy].is_modified = 1; } int window_line (void) { Line *cline; Line *top; int n; if (CBuf != JWindow->buffer) return 0; top = find_top (); #if JED_HAS_LINE_ATTRIBUTES cline = jed_find_non_hidden_line (CLine); #else cline = CLine; #endif n = 1; while ((top != NULL) && (top != cline)) { top = top->next; #if JED_HAS_LINE_ATTRIBUTES while ((top != NULL) && (top->flags & JED_LINE_HIDDEN)) top = top->next; #endif n++; } return n; } void touch_window (void) { Screen_Type *s, *smax; if (Suspend_Screen_Update) return; if (JScreen == NULL) return; s = JScreen + (JWindow->sy); if (JWindow->rows > Jed_Num_Screen_Rows) smax = s + Jed_Num_Screen_Rows; else smax = s + JWindow->rows; while (s < smax) { s->is_modified = 1; s++; } JWindow->trashed = 1; } void touch_screen (void) { Window_Type *w; No_Screen_Update = 0; if (Suspend_Screen_Update) return; if (JScreen == NULL) return; w = JWindow; do { touch_window(); JWindow = JWindow->next; } while(w != JWindow); if (Top_Window_SY > 0) JScreen[0].is_modified = 1; } void exit_error(char *str, int severity) { static int already_here; if (already_here) return; SLang_set_error (0); SLKeyBoard_Quit = 0; auto_save_all(); #if JED_HAS_EMACS_LOCKING (void) jed_unlock_buffer_files (); #endif jed_reset_display(); reset_tty(); fprintf (stderr, "***Fatal Error: %s\n\n", str); jed_show_version (stderr); if (*Error_Buffer) fprintf (stderr, "%s\n", Error_Buffer); if (CBuf != NULL) { if (Batch == 0) { fprintf(stderr, "CBuf: %p, CLine: %p, Point %d\n", (void *)CBuf, (void *) CLine, Point); if (CLine != NULL) fprintf(stderr, "CLine: data: %p, len = %d, next: %p, prev %p\n", (void *) CLine->data, CLine->len, (void *)CLine->next, (void *)CLine->prev); fprintf(stderr, "Max_LineNum: %d, LineNum: %d\n", Max_LineNum, LineNum); if (JWindow != NULL) fprintf(stderr, "JWindow: %p, top: %d, rows: %d, buffer: %p\n", (void *)JWindow, JWindow->sy, JWindow->rows, (void *)JWindow->buffer); } } if (severity) { #ifdef __unix__ fprintf(stderr, "Dumping Core."); abort (); #endif } exit (1); } void touch_window_hard(Window_Type *w, int all) { Window_Type *wsave = w; if (JScreen == NULL) return; do { Screen_Type *s, *smax; s = JScreen + (w->sy); if (w->rows > Jed_Num_Screen_Rows) smax = s + Jed_Num_Screen_Rows; else smax = s + w->rows; while (s < smax) { s->is_modified = 1; s->line = NULL; s++; } w->trashed = 1; w = w->next; } while (all && (w != wsave)); } #if 1 int jed_find_line_on_screen (Line *l, int min_line) { int i, imax; if (JScreen == NULL) return -1; imax = Jed_Num_Screen_Rows - 2; for (i = min_line; i < imax; i++) { if (JScreen[i].line == l) return i; } return -1; } #endif void update_cmd (int *force) { if (Batch) return; JWindow->trashed = 1; update((Line *) NULL, *force, 0, 1); } void update_sans_update_hook_cmd (int *force) { if (Batch) return; JWindow->trashed = 1; update((Line *) NULL, *force, 0, 0); }