(CCL_WRITE_CHAR): Check variable `extra_bytes'.
[bpt/emacs.git] / src / term.c
index 7900643..8e1443f 100644 (file)
@@ -31,21 +31,33 @@ Boston, MA 02111-1307, USA.  */
 #include "lisp.h"
 #include "charset.h"
 #include "coding.h"
+#include "keyboard.h"
 #include "frame.h"
 #include "disptab.h"
 #include "termhooks.h"
-#include "keyboard.h"
 #include "dispextern.h"
 #include "window.h"
 
-#ifdef HAVE_TERMCAP_H
+/* For now, don't try to include termcap.h.  On some systems,
+   configure finds a non-standard termcap.h that the main build
+   won't find.  */
+
+#if defined HAVE_TERMCAP_H && 0
 #include <termcap.h>
+#else
+extern void tputs P_ ((const char *, int, int (*)(int)));
+extern int tgetent P_ ((char *, const char *));
+extern int tgetflag P_ ((char *id));
+extern int tgetnum P_ ((char *id));
 #endif
 
 #include "cm.h"
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #endif
+#ifdef macintosh
+#include "macterm.h"
+#endif
 
 static void turn_on_face P_ ((struct frame *, int face_id));
 static void turn_off_face P_ ((struct frame *, int face_id));
@@ -268,6 +280,27 @@ char *TS_cursor_invisible; /* "vi" */
 char *TS_set_window;           /* "wi" (4 params, start and end of window,
                                   each as vpos and hpos) */
 
+/* Value of the "NC" (no_color_video) capability, or 0 if not
+   present.  */
+
+static int TN_no_color_video;
+
+/* Meaning of bits in no_color_video.  Each bit set means that the
+   corresponding attribute cannot be combined with colors.  */
+
+enum no_color_bit
+{
+  NC_STANDOUT   = 1 << 0,
+  NC_UNDERLINE  = 1 << 1,
+  NC_REVERSE    = 1 << 2,
+  NC_BLINK      = 1 << 3,
+  NC_DIM        = 1 << 4,
+  NC_BOLD       = 1 << 5,
+  NC_INVIS      = 1 << 6,
+  NC_PROTECT    = 1 << 7,
+  NC_ALT_CHARSET = 1 << 8
+};
+
 /* "md" -- turn on bold (extra bright mode).  */
 
 char *TS_enter_bold_mode;
@@ -683,7 +716,7 @@ reassert_line_highlight (highlight, vpos)
   else if (chars_wasted && chars_wasted[vpos] == 0)
     /* For terminals with standout markers, write one on this line
        if there isn't one already.  */
-    write_standout_marker (highlight, vpos);
+    write_standout_marker (inverse_video ? !highlight : highlight, vpos);
 }
 
 /* Call this when about to modify line at position VPOS
@@ -933,41 +966,59 @@ encode_terminal_code (src, dst, src_len, dst_len, consumed)
   int result;
   struct coding_system *coding;
 
-  coding = (CODING_REQUIRE_ENCODING (&terminal_coding)
+  /* If terminal_coding does any conversion, use it, otherwise use
+     safe_terminal_coding.  We can't use CODING_REQUIRE_ENCODING here
+     because it always return 1 if the member src_multibyte is 1.  */
+  coding = (terminal_coding.common_flags & CODING_REQUIRE_ENCODING_MASK
            ? &terminal_coding
            : &safe_terminal_coding);
 
   while (src < src_end)
     {
-      g = GLYPH_FROM_CHAR_GLYPH (*src);
-      
       /* We must skip glyphs to be padded for a wide character.  */
       if (! CHAR_GLYPH_PADDING_P (*src))
        {
-         c = src->u.ch.code;
-         if (! GLYPH_CHAR_VALID_P (c))
+         g = GLYPH_FROM_CHAR_GLYPH (src[0]);
+
+         if (g < 0 || g >= tlen)
            {
-             c = ' ';
-             g = MAKE_GLYPH (sf, c, GLYPH_FACE (sf, g));
+             /* This glyph doesn't has an entry in Vglyph_table.  */
+             if (! CHAR_VALID_P (src->u.ch, 0))
+               {
+                 len = 1;
+                 buf = " ";
+                 coding->src_multibyte = 0;
+               }
+             else
+               {
+                 len = CHAR_STRING (src->u.ch, workbuf);
+                 buf = workbuf;
+                 coding->src_multibyte = 1;
+               }
            }
-         if (c < tlen)
+         else
            {
-             /* G has an entry in Vglyph_table,
+             /* This glyph has an entry in Vglyph_table,
                 so process any alias before testing for simpleness.  */
              GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
-             c = GLYPH_CHAR (sf, g);
-           }
-         if (GLYPH_SIMPLE_P (tbase, tlen, g))
-           {
-             /* We set the multi-byte form of C at WORKBUF.  */
-             len = CHAR_STRING (c, workbuf);
-             buf = workbuf;
-           }
-         else
-           {
-             /* We have a string in Vglyph_table.  */
-             len = GLYPH_LENGTH (tbase, g);
-             buf = GLYPH_STRING (tbase, g);
+
+             if (GLYPH_SIMPLE_P (tbase, tlen, g))
+               {
+                 /* We set the multi-byte form of a character in G
+                    (that should be an ASCII character) at
+                    WORKBUF.  */
+                 workbuf[0] = FAST_GLYPH_CHAR (g);
+                 len = 1;
+                 buf = workbuf;
+                 coding->src_multibyte = 0;
+               }
+             else
+               {
+                 /* We have a string in Vglyph_table.  */
+                 len = GLYPH_LENGTH (tbase, g);
+                 buf = GLYPH_STRING (tbase, g);
+                 coding->src_multibyte = STRING_MULTIBYTE (tbase[g]);
+               }
            }
          
          result = encode_coding (coding, buf, dst, len, dst_end - dst);
@@ -1006,6 +1057,8 @@ write_glyphs (string, len)
   int produced, consumed;
   struct frame *sf = XFRAME (selected_frame);
   struct frame *f = updating_frame ? updating_frame : sf;
+  unsigned char conversion_buffer[1024];
+  int conversion_buffer_size = sizeof conversion_buffer;
 
   if (write_glyphs_hook
       && ! FRAME_TERMCAP_P (f))
@@ -1014,7 +1067,6 @@ write_glyphs (string, len)
       return;
     }
 
-  highlight_if_desired ();
   turn_off_insert ();
 
   /* Don't dare write in last column of bottom line, if Auto-Wrap,
@@ -1036,21 +1088,22 @@ write_glyphs (string, len)
   while (len > 0)
     {
       /* Identify a run of glyphs with the same face.  */
-      int face_id = string->u.ch.face_id;
+      int face_id = string->face_id;
       int n;
       
       for (n = 1; n < len; ++n)
-       if (string[n].u.ch.face_id != face_id)
+       if (string[n].face_id != face_id)
          break;
 
       /* Turn appearance modes of the face of the run on.  */
+      highlight_if_desired ();
       turn_on_face (f, face_id);
 
       while (n > 0)
        {
-         /* We use a shared conversion buffer of the current size
-            (1024 bytes at least).  Usually it is sufficient, but if
-            not, we just repeat the loop.  */
+         /* We use a fixed size (1024 bytes) of conversion buffer.
+            Usually it is sufficient, but if not, we just repeat the
+            loop.  */
          produced = encode_terminal_code (string, conversion_buffer,
                                           n, conversion_buffer_size,
                                           &consumed);
@@ -1069,6 +1122,7 @@ write_glyphs (string, len)
 
       /* Turn appearance modes off.  */
       turn_off_face (f, face_id);
+      turn_off_highlight ();
     }
   
   /* We may have to output some codes to terminate the writing.  */
@@ -1099,7 +1153,7 @@ insert_glyphs (start, len)
      register int len;
 {
   char *buf;
-  GLYPH g;
+  struct glyph *glyph = NULL;
   struct frame *f, *sf;
 
   if (len <= 0)
@@ -1113,7 +1167,6 @@ insert_glyphs (start, len)
 
   sf = XFRAME (selected_frame);
   f = updating_frame ? updating_frame : sf;
-  highlight_if_desired ();
 
   if (TS_ins_multi_chars)
     {
@@ -1132,14 +1185,20 @@ insert_glyphs (start, len)
   while (len-- > 0)
     {
       int produced, consumed;
-      struct glyph glyph;
+      unsigned char conversion_buffer[1024];
+      int conversion_buffer_size = sizeof conversion_buffer;
 
       OUTPUT1_IF (TS_ins_char);
       if (!start)
-       g = SPACEGLYPH;
+       {
+         conversion_buffer[0] = SPACEGLYPH;
+         produced = 1;
+       }
       else
        {
-         g = GLYPH_FROM_CHAR_GLYPH (*start);
+         highlight_if_desired ();
+         turn_on_face (f, start->face_id);
+         glyph = start;
          ++start;
          /* We must open sufficient space for a character which
             occupies more than one column.  */
@@ -1148,18 +1207,17 @@ insert_glyphs (start, len)
              OUTPUT1_IF (TS_ins_char);
              start++, len--;
            }
-       }
 
-      if (len <= 0)
-       /* This is the last glyph.  */
-       terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
+         if (len <= 0)
+           /* This is the last glyph.  */
+           terminal_coding.mode |= CODING_MODE_LAST_BLOCK;
+
+         /* The size of conversion buffer (1024 bytes) is surely
+            sufficient for just one glyph.  */
+         produced = encode_terminal_code (glyph, conversion_buffer, 1,
+                                          conversion_buffer_size, &consumed);
+       }
 
-      /* We use shared conversion buffer of the current size (1024
-        bytes at least).  It is surely sufficient for just one glyph.  */
-      SET_CHAR_GLYPH_FROM_GLYPH (glyph, g);
-      turn_on_face (f, glyph.u.ch.face_id);
-      produced = encode_terminal_code (&glyph, conversion_buffer,
-                                      1, conversion_buffer_size, &consumed);
       if (produced > 0)
        {
          fwrite (conversion_buffer, 1, produced, stdout);
@@ -1170,7 +1228,11 @@ insert_glyphs (start, len)
        }
 
       OUTPUT1_IF (TS_pad_inserted_char);
-      turn_off_face (f, glyph.u.ch.face_id);
+      if (start)
+       {
+         turn_off_face (f, glyph->face_id);
+         turn_off_highlight ();
+       }
     }
   
   cmcheckmagic ();
@@ -1429,16 +1491,6 @@ calculate_costs (frame)
   FRAME_COST_BAUD_RATE (frame) = baud_rate;
 
   scroll_region_cost = string_cost (f);
-#ifdef HAVE_X_WINDOWS
-  if (FRAME_X_P (frame))
-    {
-      do_line_insertion_deletion_costs (frame, 0, ".5*", 0, ".5*",
-                                       0, 0,
-                                       x_screen_planes (frame));
-      scroll_region_cost = 0;
-      return;
-    }
-#endif
 
   /* These variables are only used for terminal stuff.  They are allocated
      once for the terminal frame of X-windows emacs, but not used afterwards.
@@ -1752,9 +1804,9 @@ append_glyph (it)
     {
       glyph->type = CHAR_GLYPH;
       glyph->pixel_width = 1;
-      glyph->u.ch.code = it->c;
-      glyph->u.ch.face_id = it->face_id;
-      glyph->u.ch.padding_p = i > 0;
+      glyph->u.ch = it->c;
+      glyph->face_id = it->face_id;
+      glyph->padding_p = i > 0;
       glyph->charpos = CHARPOS (it->position);
       glyph->object = it->object;
       
@@ -1796,7 +1848,7 @@ produce_glyphs (it)
     it->pixel_width = it->nglyphs = 0;
   else if (it->c == '\t')
     {
-      int absolute_x = (it->current_x - it->prompt_width
+      int absolute_x = (it->current_x
                        + it->continuation_lines_width);
       int next_tab_x 
        = (((1 + absolute_x + it->tab_width - 1) 
@@ -1827,6 +1879,17 @@ produce_glyphs (it)
       it->pixel_width = nspaces;
       it->nglyphs = nspaces;
     }
+  else if (SINGLE_BYTE_CHAR_P (it->c))
+    {
+      /* Coming here means that it->c is from display table, thus we
+        must send the code as is to the terminal.  Although there's
+        no way to know how many columns it occupies on a screen, it
+        is a good assumption that a single byte code has 1-column
+        width.  */
+      it->pixel_width = it->nglyphs = 1;
+      if (it->glyph_row)
+       append_glyph (it);
+    }
   else
     {
       /* A multi-byte character.  The display width is fixed for all
@@ -1868,7 +1931,7 @@ produce_special_glyphs (it, what)
   temp_it.dp = NULL;
   temp_it.what = IT_CHARACTER;
   temp_it.len = 1;
-  temp_it.object = 0;
+  temp_it.object = make_number (0);
   bzero (&temp_it.current, sizeof temp_it.current);
 
   if (what == IT_CONTINUATION)
@@ -1879,7 +1942,7 @@ produce_special_glyphs (it, what)
          && GLYPH_CHAR_VALID_P (XINT (DISP_CONTINUE_GLYPH (it->dp))))
        {
          temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_CONTINUE_GLYPH (it->dp)));
-         temp_it.len = CHAR_LEN (temp_it.c);
+         temp_it.len = CHAR_BYTES (temp_it.c);
        }
       else
        temp_it.c = '\\';
@@ -1896,7 +1959,7 @@ produce_special_glyphs (it, what)
          && GLYPH_CHAR_VALID_P (XINT (DISP_TRUNC_GLYPH (it->dp))))
        {
          temp_it.c = FAST_GLYPH_CHAR (XINT (DISP_TRUNC_GLYPH (it->dp)));
-         temp_it.len = CHAR_LEN (temp_it.c);
+         temp_it.len = CHAR_BYTES (temp_it.c);
        }
       else
        temp_it.c = '$';
@@ -1930,6 +1993,15 @@ estimate_mode_line_height (f, face_id)
                                Faces
  ***********************************************************************/
 
+/* Value is non-zero if attribute ATTR may be used.  ATTR should be
+   one of the enumerators from enum no_color_bit, or a bit set built
+   from them.  Some display attributes may not be used together with
+   color; the termcap capability `NC' specifies which ones.  */
+
+#define MAY_USE_WITH_COLORS_P(ATTR)            \
+     (TN_max_colors > 0                                \
+      ? (TN_no_color_video & (ATTR)) == 0      \
+      : 1)
 
 /* Turn appearances of face FACE_ID on tty frame F on.  */
 
@@ -1943,30 +2015,42 @@ turn_on_face (f, face_id)
   xassert (face != NULL);
 
   if (face->tty_bold_p)
-    OUTPUT1_IF (TS_enter_bold_mode);
+    {
+      if (MAY_USE_WITH_COLORS_P (NC_BOLD))
+       OUTPUT1_IF (TS_enter_bold_mode);
+    }
   else if (face->tty_dim_p)
-    OUTPUT1_IF (TS_enter_dim_mode);
+    if (MAY_USE_WITH_COLORS_P (NC_DIM))
+      OUTPUT1_IF (TS_enter_dim_mode);
 
   /* Alternate charset and blinking not yet used.  */
-  if (face->tty_alt_charset_p)
+  if (face->tty_alt_charset_p
+      && MAY_USE_WITH_COLORS_P (NC_ALT_CHARSET))
     OUTPUT1_IF (TS_enter_alt_charset_mode);
 
-  if (face->tty_blinking_p)
+  if (face->tty_blinking_p
+      && MAY_USE_WITH_COLORS_P (NC_BLINK))
     OUTPUT1_IF (TS_enter_blink_mode);
 
   if (face->tty_underline_p
       /* Don't underline if that's difficult.  */
-      && TN_magic_cookie_glitch_ul <= 0)
+      && TN_magic_cookie_glitch_ul <= 0
+      && MAY_USE_WITH_COLORS_P (NC_UNDERLINE))
     OUTPUT1_IF (TS_enter_underline_mode);
 
-  if (face->tty_reverse_p)
-    OUTPUT1_IF (TS_enter_reverse_mode);
+  if (MAY_USE_WITH_COLORS_P (NC_REVERSE))
+    if (face->tty_reverse_p
+       || face->foreground == FACE_TTY_DEFAULT_BG_COLOR
+       || face->background == FACE_TTY_DEFAULT_FG_COLOR)
+      OUTPUT1_IF (TS_enter_reverse_mode);
 
   if (TN_max_colors > 0)
     {
       char *p;
       
       if (face->foreground != FACE_TTY_DEFAULT_COLOR
+         && face->foreground != FACE_TTY_DEFAULT_FG_COLOR
+         && face->foreground != FACE_TTY_DEFAULT_BG_COLOR
          && TS_set_foreground)
        {
          p = tparam (TS_set_foreground, NULL, 0, (int) face->foreground);
@@ -1975,6 +2059,8 @@ turn_on_face (f, face_id)
        }
 
       if (face->background != FACE_TTY_DEFAULT_COLOR
+         && face->background != FACE_TTY_DEFAULT_BG_COLOR
+         && face->background != FACE_TTY_DEFAULT_FG_COLOR
          && TS_set_background)
        {
          p = tparam (TS_set_background, NULL, 0, (int) face->background);
@@ -2007,7 +2093,11 @@ turn_off_face (f, face_id)
          || face->tty_alt_charset_p
          || face->tty_blinking_p
          || face->tty_underline_p)
-       OUTPUT1_IF (TS_exit_attribute_mode);
+       {
+         OUTPUT1_IF (TS_exit_attribute_mode);
+         if (strcmp (TS_exit_attribute_mode, TS_end_standout_mode) == 0)
+           standout_mode = 0;
+       }
 
       if (face->tty_alt_charset_p)
        OUTPUT_IF (TS_exit_alt_charset_mode);
@@ -2027,8 +2117,10 @@ turn_off_face (f, face_id)
 
   /* Switch back to default colors.  */
   if (TN_max_colors > 0
-      && (face->foreground != FACE_TTY_DEFAULT_COLOR
-         || face->background != FACE_TTY_DEFAULT_COLOR))
+      && ((face->foreground != FACE_TTY_DEFAULT_COLOR
+          && face->foreground != FACE_TTY_DEFAULT_FG_COLOR)
+         || (face->background != FACE_TTY_DEFAULT_COLOR
+             && face->background != FACE_TTY_DEFAULT_BG_COLOR)))
     OUTPUT1_IF (TS_orig_pair);
 }
   
@@ -2036,9 +2128,10 @@ turn_off_face (f, face_id)
 /* Return non-zero if the terminal is capable to display colors.  */
 
 DEFUN ("tty-display-color-p", Ftty_display_color_p, Stty_display_color_p,
-       0, 0, 0,
-  "Return non-nil if TTY can display colors.")
-     ()
+       0, 1, 0,
+  "Return non-nil if TTY can display colors on FRAME.")
+     (frame)
+     Lisp_Object frame;
 {
   return TN_max_colors > 0 ? Qt : Qnil;
 }
@@ -2092,6 +2185,7 @@ term_init (terminal_type)
 
   FRAME_CAN_HAVE_SCROLL_BARS (sf) = 0;
   FRAME_VERTICAL_SCROLL_BAR_TYPE (sf) = vertical_scroll_bar_none;
+  TN_max_colors = 16;  /* Required to be non-zero for tty-display-color-p */
 
   return;
 #else  /* not WINDOWSNT */
@@ -2140,7 +2234,7 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
   TS_clr_to_bottom = tgetstr ("cd", address);
   TS_clr_line = tgetstr ("ce", address);
   TS_clr_frame = tgetstr ("cl", address);
-  ColPosition = tgetstr ("ch", address);
+  ColPosition = NULL; /* tgetstr ("ch", address); */
   AbsPosition = tgetstr ("cm", address);
   CR = tgetstr ("cr", address);
   TS_set_scroll_region = tgetstr ("cs", address);
@@ -2223,8 +2317,13 @@ to do `unset TERMCAP' (C-shell: `unsetenv TERMCAP') as well.",
          TS_set_foreground = tgetstr ("Sf", address);
          TS_set_background = tgetstr ("Sb", address);
        }
+      
       TN_max_colors = tgetnum ("Co");
       TN_max_pairs = tgetnum ("pa");
+      
+      TN_no_color_video = tgetnum ("NC");
+      if (TN_no_color_video == -1)
+       TN_no_color_video = 0;
     }
 
   MagicWrap = tgetflag ("xn");