]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Fix tab and wide character handling in editor and menu.
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 27 Mar 2012 15:07:26 +0000 (17:07 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Tue, 27 Mar 2012 15:07:26 +0000 (17:07 +0200)
* grub-core/normal/charset.c (grub_unicode_aglomerate_comb): Don't
agglomerate control characters with combining marks.
(bidi_line_wrap): Allow break on tab.
(grub_unicode_get_comb_start): New function.
* grub-core/normal/menu_entry.c: Restructure to handle wide characters
and tab correctly.
* grub-core/normal/menu_text.c (print_entry): Replace \n, \r, \b and \e
with a space.
* grub-core/normal/term.c (print_ucs4_terminal): New argument
fixed_tab_size. All users updated.
* include/grub/term.h (GRUB_TERM_TAB_WIDTH): New const.
(grub_term_getcharwidth): Handle \t.
* include/grub/unicode.h (grub_unicode_glyph_dup): Fix allocation
and copy.

ChangeLog
grub-core/kern/term.c
grub-core/normal/charset.c
grub-core/normal/menu_entry.c
grub-core/normal/menu_text.c
grub-core/normal/term.c
include/grub/charset.h
include/grub/term.h
include/grub/unicode.h

index 0359a19aac80d66e9080994ce8999791b9e84fc1..b95a6e26aaf40ed7048ddbe4647be4b3811a4f43 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2012-03-27  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Fix tab and wide character handling in editor and menu.
+
+       * grub-core/normal/charset.c (grub_unicode_aglomerate_comb): Don't
+       agglomerate control characters with combining marks.
+       (bidi_line_wrap): Allow break on tab.
+       (grub_unicode_get_comb_start): New function.
+       * grub-core/normal/menu_entry.c: Restructure to handle wide characters
+       and tab correctly.
+       * grub-core/normal/menu_text.c (print_entry): Replace \n, \r, \b and \e
+       with a space.
+       * grub-core/normal/term.c (print_ucs4_terminal): New argument
+       fixed_tab_size. All users updated.
+       * include/grub/term.h (GRUB_TERM_TAB_WIDTH): New const.
+       (grub_term_getcharwidth): Handle \t.
+       * include/grub/unicode.h (grub_unicode_glyph_dup): Fix allocation
+       and copy.
+
 2012-03-26  Vladimir Serbinenko  <phcoder@gmail.com>
 
        Handle big-endian mdraid.
index 767f5c10795aad6d13560d8240f7c5bd3d9c7e62..5014caf624cddf4a914d8f0caecc2027e069e9ed 100644 (file)
@@ -50,7 +50,8 @@ grub_putcode_dumb (grub_uint32_t code,
     {
       int n;
 
-      n = 8 - ((term->getxy (term) >> 8) & 7);
+      n = GRUB_TERM_TAB_WIDTH - ((term->getxy (term) >> 8)
+                                % GRUB_TERM_TAB_WIDTH);
       while (n--)
        grub_putcode_dumb (' ', term);
 
index d369a39b516c8729860f6059526d72a131f94ba3..55151b944ff2d356fafc985b653f0d04f2d1e431 100644 (file)
@@ -418,6 +418,17 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
 
   grub_memset (out, 0, sizeof (*out));
 
+  if (inlen && grub_iscntrl (*in))
+    {
+      out->base = *in;
+      out->variant = 0;
+      out->attributes = 0;
+      out->ncomb = 0;
+      out->estimated_width = 1;
+      out->combining = NULL;
+      return 1;
+    }
+
   for (ptr = in; ptr < in + inlen; ptr++)
     {
       /* Variation selectors >= 17 are outside of BMP and SMP. 
@@ -429,7 +440,6 @@ grub_unicode_aglomerate_comb (const grub_uint32_t *in, grub_size_t inlen,
          if (haveout)
            out->variant = *ptr - GRUB_UNICODE_VARIATION_SELECTOR_1 + 1;
          continue;
-
        }
       if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
          && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
@@ -528,7 +538,8 @@ bidi_line_wrap (struct grub_unicode_glyph *visual_out,
       if (getcharwidth && k != visual_len)
        line_width += last_width = getcharwidth (&visual[k]);
 
-      if (k != visual_len && visual[k].base == ' ')
+      if (k != visual_len && (visual[k].base == ' '
+                             || visual[k].base == '\t'))
        {
          last_space = k;
          last_space_width = line_width;
@@ -1142,3 +1153,28 @@ grub_unicode_shape_code (grub_uint32_t in, grub_uint8_t attr)
 
   return in;
 }
+
+const grub_uint32_t *
+grub_unicode_get_comb_start (const grub_uint32_t *str, 
+                            const grub_uint32_t *cur)
+{
+  const grub_uint32_t *ptr;
+  for (ptr = cur; ptr >= str; ptr--)
+    {
+      if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_1
+         && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_16)
+       continue;
+
+      if (*ptr >= GRUB_UNICODE_VARIATION_SELECTOR_17
+         && *ptr <= GRUB_UNICODE_VARIATION_SELECTOR_256)
+       continue;
+       
+      enum grub_comb_type comb_type;
+      comb_type = grub_unicode_get_comb_type (*ptr);
+      if (comb_type)
+       continue;
+      return ptr;
+    }
+  return str;
+}
+
index b81500e0a27e341320d5774f18b16dcda82e6004..962d077ec2ae22edf79a05920dee1b0321bdcbfc 100644 (file)
@@ -38,7 +38,7 @@ enum update_mode
 struct line
 {
   /* The line buffer.  */
-  char *buf;
+  grub_uint32_t *buf;
   /* The length of the line.  */
   int len;
   /* The maximum length of the line.  */
@@ -52,6 +52,7 @@ struct per_term_screen
   int x;
   /* The Y coordinate.  */
   int y;
+  int y_line_start;
   /* Number of entries.  */
   int num_entries;
 };
@@ -80,7 +81,11 @@ struct screen
 };
 
 /* Used for storing completion items temporarily.  */
-static struct line completion_buffer;
+static struct {
+  char *buf;
+  grub_size_t len;
+  grub_size_t max_len;
+} completion_buffer;
 static int completion_type;
 
 /* Initialize a line.  */
@@ -88,8 +93,8 @@ static int
 init_line (struct line *linep)
 {
   linep->len = 0;
-  linep->max_len = 80; /* XXX */
-  linep->buf = grub_malloc (linep->max_len + 1);
+  linep->max_len = 80;
+  linep->buf = grub_malloc ((linep->max_len + 1) * sizeof (linep->buf[0]));
   if (! linep->buf)
     return 0;
 
@@ -102,8 +107,8 @@ ensure_space (struct line *linep, int extra)
 {
   if (linep->max_len < linep->len + extra)
     {
-      linep->max_len = linep->len + extra + 80; /* XXX */
-      linep->buf = grub_realloc (linep->buf, linep->max_len + 1);
+      linep->max_len = 2 * (linep->len + extra);
+      linep->buf = grub_realloc (linep->buf, (linep->max_len + 1) * sizeof (linep->buf[0]));
       if (! linep->buf)
        return 0;
     }
@@ -115,44 +120,99 @@ ensure_space (struct line *linep, int extra)
 static int
 get_logical_num_lines (struct line *linep, struct per_term_screen *term_screen)
 {
-  return (linep->len / grub_term_entry_width (term_screen->term)) + 1;
+  return (grub_getstringwidth (linep->buf, linep->buf + linep->len,
+                              term_screen->term)
+         / grub_term_entry_width (term_screen->term)) + 1;
 }
 
-/* Print a line.  */
 static void
-print_line (struct line *linep, int offset, int start, int y,
-           struct per_term_screen *term_screen)
+advance (struct screen *screen)
 {
-  grub_term_gotoxy (term_screen->term, 
-                   GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + start + 1,
-                   y + GRUB_TERM_FIRST_ENTRY_Y);
+  unsigned i;
+  struct grub_unicode_glyph glyph;
 
-  if (linep->len >= offset + grub_term_entry_width (term_screen->term))
-    {
-      char *p, c;
-      p = linep->buf + offset + grub_term_entry_width (term_screen->term);
-      c = *p;
-      *p = 0;
-      grub_puts_terminal (linep->buf + offset + start, term_screen->term);
-      *p = c;
-      grub_putcode ('\\', term_screen->term);
-    }
-  else
+  screen->column += grub_unicode_aglomerate_comb (screen->lines[screen->line].buf + screen->column,
+                                                 screen->lines[screen->line].len - screen->column,
+                                                 &glyph);
+
+  for (i = 0; i < screen->nterms; i++)
     {
-      int i;
-      char *p, c;
-
-      p = linep->buf + linep->len;
-      c = *p;
-      *p = 0;
-      grub_puts_terminal (linep->buf + offset + start, term_screen->term);
-      *p = c;
-
-      for (i = 0;
-          i <= grub_term_entry_width (term_screen->term) - linep->len + offset;
-          i++)
-       grub_putcode (' ', term_screen->term);
+      grub_ssize_t width;
+      width = grub_term_getcharwidth (screen->terms[i].term, &glyph);
+      screen->terms[i].x += width;
+      if (screen->terms[i].x
+         == grub_term_entry_width (screen->terms[i].term))
+       {
+         screen->terms[i].x = 0;
+         screen->terms[i].y++;
+       }
+      if (screen->terms[i].x
+         > grub_term_entry_width (screen->terms[i].term))
+       {
+         screen->terms[i].x = width;
+         screen->terms[i].y++;
+       }
     }
+  grub_free (glyph.combining);
+}
+
+static void
+advance_to (struct screen *screen, int c)
+{
+  if (c > screen->lines[screen->line].len)
+    c = screen->lines[screen->line].len;
+
+  while (screen->column < c)
+    advance (screen);
+}
+
+/* Print a line.  */
+static int
+print_line (struct line *linep, int offset, int y,
+           struct per_term_screen *term_screen, int dry_run)
+{
+  int x;
+  int i;
+
+  grub_term_gotoxy (term_screen->term, 
+                   GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1,
+                   y + GRUB_TERM_FIRST_ENTRY_Y);
+  x = 0;
+  for (i = 0; i + offset < (int) linep->len;)
+     {
+      grub_ssize_t width;
+      grub_size_t delta = 0;
+      struct grub_unicode_glyph glyph;
+
+      delta = grub_unicode_aglomerate_comb (linep->buf + offset + i,
+                                           linep->len - offset - i,
+                                           &glyph);
+      width = grub_term_getcharwidth (term_screen->term, &glyph);
+      grub_free (glyph.combining);
+
+      if (x + width > grub_term_entry_width (term_screen->term) && x != 0)
+       break;
+      x += width;
+      i += delta;
+     }
+
+  if (dry_run)
+    return i;
+
+  grub_print_ucs4 (linep->buf + offset,
+                  linep->buf + offset + i, 0, 0, term_screen->term);
+
+  if (i + offset != linep->len)
+    grub_putcode ('\\', term_screen->term);
+   else
+     {
+       for (;
+           x < (int) grub_term_entry_width (term_screen->term);
+           x++)
+        grub_putcode (' ', term_screen->term);
+     }
+  return i;
 }
 
 /* Print an empty line.  */
@@ -213,10 +273,13 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
   /* Check if scrolling is necessary.  */
   if (term_screen->y < 0 || term_screen->y >= term_screen->num_entries)
     {
+      int delta;
       if (term_screen->y < 0)
-       term_screen->y = 0;
+       delta = -term_screen->y;
       else
-       term_screen->y = term_screen->num_entries - 1;
+       delta = term_screen->num_entries - 1 - term_screen->y;
+      term_screen->y += delta;
+      term_screen->y_line_start += delta;
 
       region_start = 0;
       region_column = 0;
@@ -229,8 +292,7 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
     {
       /* Draw lines. This code is tricky, because this must calculate logical
         positions.  */
-      y = term_screen->y - screen->column
-       / grub_term_entry_width (term_screen->term);
+      y = term_screen->y_line_start;
       i = screen->line;
       linep = screen->lines + i;
       while (y > 0)
@@ -246,6 +308,7 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
       do
        {
          int column;
+         int off = 0;
 
          if (linep >= screen->lines + screen->num_lines)
            break;
@@ -256,7 +319,10 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
               column += grub_term_entry_width (term_screen->term), y++)
            {
              if (y < 0)
-               continue;
+               {
+                 off += print_line (linep, off, y, term_screen, 1);
+                 continue;
+               }
 
              if (i == region_start)
                {
@@ -264,18 +330,19 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
                      && region_column
                      < (column
                         + grub_term_entry_width (term_screen->term)))
-                   print_line (linep, column, region_column - column, y,
-                               term_screen);
+                   off += print_line (linep, off, y, term_screen, 0);
                  else if (region_column < column)
-                   print_line (linep, column, 0, y, term_screen);
+                   off += print_line (linep, off, y, term_screen, 0);
+                 else
+                   off += print_line (linep, off, y, term_screen, 1);
                }
              else if (i > region_start && mode == ALL_LINES)
-               print_line (linep, column, 0, y, term_screen);
+               off += print_line (linep, off, y, term_screen, 0);
            }
 
          if (y == term_screen->num_entries)
            {
-             if (column <= linep->len || i + 1 < screen->num_lines)
+             if (off <= linep->len || i + 1 < screen->num_lines)
                down_flag = 1;
            }
 
@@ -285,7 +352,6 @@ update_screen (struct screen *screen, struct per_term_screen *term_screen,
          if (mode == ALL_LINES && i == screen->num_lines)
            for (; y < term_screen->num_entries; y++)
              print_empty_line (y, term_screen);
-
        }
       while (y < term_screen->num_entries);
 
@@ -367,7 +433,7 @@ insert_string (struct screen *screen, const char *s, int update)
 
          grub_memmove (next_linep->buf,
                        current_linep->buf + screen->column,
-                       size);
+                       size * sizeof (next_linep->buf[0]));
          current_linep->len = screen->column;
          next_linep->len = size;
 
@@ -391,6 +457,7 @@ insert_string (struct screen *screen, const char *s, int update)
            {
              screen->terms[i].x = 0;
              screen->terms[i].y++;
+             screen->terms[i].y_line_start = screen->terms[i].y;
            }
          s++;
        }
@@ -401,6 +468,7 @@ insert_string (struct screen *screen, const char *s, int update)
          struct line *current_linep;
          int size;
          int orig_num[screen->nterms], new_num[screen->nterms];
+         grub_uint32_t *unicode_msg;
 
          /* Find a string delimited by LF.  */
          p = grub_strchr (s, '\n');
@@ -409,16 +477,26 @@ insert_string (struct screen *screen, const char *s, int update)
 
          /* Insert the string.  */
          current_linep = screen->lines + screen->line;
-         size = p - s;
+         unicode_msg = grub_malloc ((p - s) * sizeof (grub_uint32_t));
+
+         if (!unicode_msg)
+           return 0;
+
+         size = grub_utf8_to_ucs4 (unicode_msg, (p - s),
+                                   (grub_uint8_t *) s, (p - s), 0);
+
          if (! ensure_space (current_linep, size))
            return 0;
 
          grub_memmove (current_linep->buf + screen->column + size,
                        current_linep->buf + screen->column,
-                       current_linep->len - screen->column);
+                       (current_linep->len - screen->column)
+                       * sizeof (current_linep->buf[0]));
          grub_memmove (current_linep->buf + screen->column,
-                       s,
-                       size);
+                       unicode_msg,
+                       size * sizeof (current_linep->buf[0]));
+         grub_free (unicode_msg);
+
          for (i = 0; i < screen->nterms; i++)
            orig_num[i] = get_logical_num_lines (current_linep,
                                                 &screen->terms[i]);
@@ -444,16 +522,9 @@ insert_string (struct screen *screen, const char *s, int update)
              mode[i] = SINGLE_LINE;
 
          /* Move the cursor.  */
-         screen->column += size;
+         advance_to (screen, screen->column + size);
+
          screen->real_column = screen->column;
-         for (i = 0; i < screen->nterms; i++)
-           {
-             screen->terms[i].x += size;
-             screen->terms[i].y += screen->terms[i].x
-               / grub_term_entry_width (screen->terms[i].term);
-             screen->terms[i].x
-               %= grub_term_entry_width (screen->terms[i].term);
-           }
          s = p;
        }
     }
@@ -520,6 +591,7 @@ make_screen (grub_menu_entry_t entry)
     {
       screen->terms[i].x = 0;
       screen->terms[i].y = 0;
+      screen->terms[i].y_line_start = screen->terms[i].y;
     }
 
   return screen;
@@ -537,19 +609,7 @@ forward_char (struct screen *screen, int update)
 
   linep = screen->lines + screen->line;
   if (screen->column < linep->len)
-    {
-      screen->column++;
-      for (i = 0; i < screen->nterms; i++)
-       {
-         screen->terms[i].x++;
-         if (screen->terms[i].x
-             == grub_term_entry_width (screen->terms[i].term))
-           {
-             screen->terms[i].x = 0;
-             screen->terms[i].y++;
-           }
-       }
-    }
+    advance (screen);
   else if (screen->num_lines > screen->line + 1)
     {
       screen->column = 0;
@@ -558,6 +618,7 @@ forward_char (struct screen *screen, int update)
        {
          screen->terms[i].x = 0;
          screen->terms[i].y++;
+         screen->terms[i].y_line_start = screen->terms[i].y;
        }
     }
 
@@ -575,31 +636,49 @@ backward_char (struct screen *screen, int update)
 
   if (screen->column > 0)
     {
+      struct grub_unicode_glyph glyph;
+      struct line *linep;
+
+      linep = screen->lines + screen->line;
+
       screen->column--;
+      screen->column = grub_unicode_get_comb_start (linep->buf, 
+                                                   linep->buf + screen->column)
+       - linep->buf;
+
+      grub_unicode_aglomerate_comb (screen->lines[screen->line].buf + screen->column,
+                                   screen->lines[screen->line].len - screen->column,
+                                   &glyph);
+
       for (i = 0; i < screen->nterms; i++)
        {
-         screen->terms[i].x--;
-         if (screen->terms[i].x == -1)
+         grub_ssize_t width;
+         width = grub_term_getcharwidth (screen->terms[i].term, &glyph);
+         screen->terms[i].x -= width;
+         if (screen->terms[i].x < 0)
            {
              screen->terms[i].x
                = grub_term_entry_width (screen->terms[i].term) - 1;
              screen->terms[i].y--;
            }
        }
+      grub_free (glyph.combining);
     }
   else if (screen->line > 0)
     {
       struct line *linep;
 
-      screen->line--;
       linep = screen->lines + screen->line;
-      screen->column = linep->len;
+      screen->column = 0;
+      screen->line--;
+
       for (i = 0; i < screen->nterms; i++)
        {
-         screen->terms[i].x = screen->column
-           % grub_term_entry_width (screen->terms[i].term);
-         screen->terms[i].y--;
+         screen->terms[i].y_line_start -= get_logical_num_lines (linep, &screen->terms[i]);
+         screen->terms[i].y = screen->terms[i].y_line_start;
+         screen->terms[i].x = 0;
        }
+      advance_to (screen, screen->lines[screen->line].len);
     }
 
   screen->real_column = screen->column;
@@ -620,40 +699,29 @@ previous_line (struct screen *screen, int update)
       struct line *linep;
       int col;
 
-      /* How many physical lines from the current position
-        to the first physical line?  */
-      col = screen->column;
-
       screen->line--;
 
       linep = screen->lines + screen->line;
       if (linep->len < screen->real_column)
-       screen->column = linep->len;
+       col = linep->len;
       else
-       screen->column = screen->real_column;
+       col = screen->real_column;
+
+      screen->column = 0;
 
       for (i = 0; i < screen->nterms; i++)
        {
-         int dy;
-         dy = col / grub_term_entry_width (screen->terms[i].term);
-
-         /* How many physical lines from the current position
-            to the last physical line?  */
-         dy += (linep->len / grub_term_entry_width (screen->terms[i].term)
-                - screen->column
-                / grub_term_entry_width (screen->terms[i].term));
-       
-         screen->terms[i].y -= dy + 1;
-         screen->terms[i].x
-           = screen->column % grub_term_entry_width (screen->terms[i].term);
-      }
+         screen->terms[i].y_line_start -= get_logical_num_lines (linep, &screen->terms[i]);
+         screen->terms[i].y = screen->terms[i].y_line_start;
+         screen->terms[i].x = 0;
+       }
+      advance_to (screen, col);
     }
   else
     {
       for (i = 0; i < screen->nterms; i++)
        {
-         screen->terms[i].y
-           -= screen->column / grub_term_entry_width (screen->terms[i].term);
+         screen->terms[i].y = screen->terms[i].y_line_start;
          screen->terms[i].x = 0;
        }
       screen->column = 0;
@@ -673,53 +741,29 @@ next_line (struct screen *screen, int update)
   if (screen->line < screen->num_lines - 1)
     {
       struct line *linep;
-      int l1, c1;
+      int c;
 
       /* How many physical lines from the current position
         to the last physical line?  */
       linep = screen->lines + screen->line;
-      l1 = linep->len;
-      c1 = screen->column;
 
       screen->line++;
-
-      linep++;
-      if (linep->len < screen->real_column)
-       screen->column = linep->len;
+      if ((linep + 1)->len < screen->real_column)
+       c = (linep + 1)->len;
       else
-       screen->column = screen->real_column;
+       c = screen->real_column;
+      screen->column = 0;
 
       for (i = 0; i < screen->nterms; i++)
        {
-         int dy;
-         dy = l1 / grub_term_entry_width (screen->terms[i].term)
-           - c1 / grub_term_entry_width (screen->terms[i].term);
-         /* How many physical lines from the current position
-            to the first physical line?  */
-         dy += screen->column / grub_term_entry_width (screen->terms[i].term);
-         screen->terms[i].y += dy + 1;
-         screen->terms[i].x = screen->column
-           % grub_term_entry_width (screen->terms[i].term);
+         screen->terms[i].y_line_start += get_logical_num_lines (linep, &screen->terms[i]);
+         screen->terms[i].x = 0;
+         screen->terms[i].y = screen->terms[i].y_line_start;
        }
+      advance_to (screen, c);
     }
   else
-    {
-      struct line *linep;
-      int l, s;
-      
-      linep = screen->lines + screen->line;
-      l = linep->len;
-      s = screen->column;
-      screen->column = linep->len;
-      for (i = 0; i < screen->nterms; i++)
-       {
-         screen->terms[i].y 
-           += (l / grub_term_entry_width (screen->terms[i].term)
-               -  s / grub_term_entry_width (screen->terms[i].term));
-         screen->terms[i].x
-           = screen->column % grub_term_entry_width (screen->terms[i].term);
-       }
-    }
+    advance_to (screen, screen->lines[screen->line].len);
 
   if (update)
     update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
@@ -731,14 +775,12 @@ static int
 beginning_of_line (struct screen *screen, int update)
 {
   unsigned i;
-  int col;
-  
-  col = screen->column;
+
   screen->column = screen->real_column = 0;
   for (i = 0; i < screen->nterms; i++)
     {
       screen->terms[i].x = 0;
-      screen->terms[i].y -= col / grub_term_entry_width (screen->terms[i].term);
+      screen->terms[i].y = screen->terms[i].y_line_start;
     }
 
   if (update)
@@ -750,21 +792,7 @@ beginning_of_line (struct screen *screen, int update)
 static int
 end_of_line (struct screen *screen, int update)
 {
-  struct line *linep;
-  unsigned i;
-  int col;
-
-  linep = screen->lines + screen->line;
-  col = screen->column;
-  screen->column = screen->real_column = linep->len;
-  for (i = 0; i < screen->nterms; i++)
-    {
-      screen->terms[i].y 
-       += (linep->len / grub_term_entry_width (screen->terms->term)
-           - col / grub_term_entry_width (screen->terms->term));
-      screen->terms[i].x
-       = screen->column % grub_term_entry_width (screen->terms->term);
-    }
+  advance_to (screen, screen->lines[screen->line].len);
 
   if (update)
     update_screen_all (screen, screen->num_lines, 0, 0, 0, NO_LINE);
@@ -790,7 +818,8 @@ delete_char (struct screen *screen, int update)
 
       grub_memmove (linep->buf + screen->column,
                    linep->buf + screen->column + 1,
-                   linep->len - screen->column - 1);
+                   (linep->len - screen->column - 1)
+                   * sizeof (linep->buf[0]));
       linep->len--;
 
       start = screen->line;
@@ -820,7 +849,8 @@ delete_char (struct screen *screen, int update)
       if (! ensure_space (linep, next_linep->len))
        return 0;
 
-      grub_memmove (linep->buf + linep->len, next_linep->buf, next_linep->len);
+      grub_memmove (linep->buf + linep->len, next_linep->buf,
+                   next_linep->len * sizeof (linep->buf[0]));
       linep->len += next_linep->len;
 
       grub_free (next_linep->buf);
@@ -954,7 +984,10 @@ open_line (struct screen *screen, int update)
     return 0;
 
   for (i = 0; i < screen->nterms; i++)
-    screen->terms[i].y = saved_y[i];
+    {
+      screen->terms[i].y = saved_y[i];
+      screen->terms[i].y_line_start = screen->terms[i].y;
+    }
 
   if (update)
     update_screen_all (screen, screen->line, screen->column, 0, 1, ALL_LINES);
@@ -1003,7 +1036,6 @@ store_completion (const char *item, grub_completion_type_t type,
 static int
 complete (struct screen *screen, int continuous, int update)
 {
-  char saved_char;
   struct line *linep;
   int restore;
   char *insert;
@@ -1012,6 +1044,7 @@ complete (struct screen *screen, int continuous, int update)
   grub_uint32_t *ucs4;
   grub_size_t buflen;
   grub_ssize_t ucs4len;
+  char *u8;
 
   if (continuous)
     count++;
@@ -1023,12 +1056,11 @@ complete (struct screen *screen, int continuous, int update)
   completion_buffer.max_len = 0;
 
   linep = screen->lines + screen->line;
-  saved_char = linep->buf[screen->column];
-  linep->buf[screen->column] = '\0';
-
-  insert = grub_normal_do_completion (linep->buf, &restore, store_completion);
+  u8 = grub_ucs4_to_utf8_alloc (linep->buf, screen->column);
+  if (!u8)
+    return 1;
 
-  linep->buf[screen->column] = saved_char;
+  insert = grub_normal_do_completion (u8, &restore, store_completion);
   
   if (completion_buffer.buf)
     {
@@ -1287,6 +1319,7 @@ grub_menu_entry_run (grub_menu_entry_t entry)
     screen->terms[i].term = term;
     screen->terms[i].x = 0;
     screen->terms[i].y = 0;
+    screen->terms[i].y_line_start = screen->terms[i].y;
     i++;
   }
   /* Draw the screen.  */
index 1753c7bb06558b14ee7e5d5a6428379cd1dd2163..1687c2841e81389221d90f31b709385e26f230cb 100644 (file)
@@ -234,6 +234,12 @@ print_entry (int y, int highlight, grub_menu_entry_t entry,
   grub_term_gotoxy (term, GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN, y);
 
   int last_printed = 0;
+
+  for (i = 0; i < len; i++)
+    if (unicode_title[i] == '\n' || unicode_title[i] == '\b'
+       || unicode_title[i] == '\r' || unicode_title[i] == '\e')
+      unicode_title[i] = ' ';
+
   for (x = GRUB_TERM_LEFT_BORDER_X + GRUB_TERM_MARGIN + 1, i = 0;
        x < (int) (GRUB_TERM_LEFT_BORDER_X + grub_term_border_width (term)
                  - GRUB_TERM_MARGIN);)
index cb5dd829749c31095b9503956e4e35e8096e49fa..ffb3bfeac8f3b17802cf2e915b856bd7be0f19f4 100644 (file)
@@ -31,6 +31,7 @@ struct term_state
   struct term_state *next;
   const struct grub_unicode_glyph *backlog_glyphs;
   const grub_uint32_t *backlog_ucs4;
+  int backlog_fixed_tab;
   grub_size_t backlog_len;
 
   void *free;
@@ -38,13 +39,20 @@ struct term_state
   char *term_name;
 };
 
+static int
+print_ucs4_real (const grub_uint32_t * str,
+                const grub_uint32_t * last_position,
+                int margin_left, int margin_right,
+                struct grub_term_output *term, int backlog,
+                int dry_run, int fixed_tab);
+
 static struct term_state *term_states = NULL;
 
 /* If the more pager is active.  */
 static int grub_more;
 
 static void
-putcode_real (grub_uint32_t code, struct grub_term_output *term);
+putcode_real (grub_uint32_t code, struct grub_term_output *term, int fixed_tab);
 
 void
 grub_normal_reset_more (void)
@@ -235,7 +243,7 @@ grub_puts_terminal (const char *str, struct grub_term_output *term)
       return;
     }
 
-  grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term);
+  print_ucs4_real (unicode_str, unicode_last_position, 0, 0, term, 0, 0, 0);
   grub_free (unicode_str);
 }
 
@@ -398,7 +406,8 @@ read_terminal_list (const char *prefix)
 }
 
 static void
-putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term)
+putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term,
+         int fixed_tab)
 {
   struct grub_unicode_glyph c2 =
     {
@@ -409,11 +418,24 @@ putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term)
       .estimated_width = 1
     };
 
+  if (c->base == '\t' && fixed_tab)
+    {
+      int n;
+
+      n = GRUB_TERM_TAB_WIDTH;
+      c2.base = ' ';
+      while (n--)
+       (term->putchar) (term, &c2);
+
+      return;
+    }
+
   if (c->base == '\t' && term->getxy)
     {
       int n;
 
-      n = 8 - ((term->getxy (term) >> 8) & 7);
+      n = GRUB_TERM_TAB_WIDTH - ((term->getxy (term) >> 8)
+                                % GRUB_TERM_TAB_WIDTH);
       c2.base = ' ';
       while (n--)
        (term->putchar) (term, &c2);
@@ -469,7 +491,7 @@ putglyph (const struct grub_unicode_glyph *c, struct grub_term_output *term)
 }
 
 static void
-putcode_real (grub_uint32_t code, struct grub_term_output *term)
+putcode_real (grub_uint32_t code, struct grub_term_output *term, int fixed_tab)
 {
   struct grub_unicode_glyph c =
     {
@@ -481,7 +503,7 @@ putcode_real (grub_uint32_t code, struct grub_term_output *term)
     };
 
   c.base = map_code (code, term);
-  putglyph (&c, term);
+  putglyph (&c, term, fixed_tab);
 }
 
 /* Put a Unicode character.  */
@@ -492,7 +514,7 @@ grub_putcode (grub_uint32_t code, struct grub_term_output *term)
   if (grub_unicode_get_comb_type (code) != GRUB_UNICODE_COMB_NONE)
     return;
 
-  putcode_real (code, term);
+  putcode_real (code, term, 0);
 }
 
 static grub_ssize_t
@@ -524,7 +546,7 @@ print_ucs4_terminal (const grub_uint32_t * str,
                     int margin_left, int margin_right,
                     struct grub_term_output *term,
                     struct term_state *state,
-                    int dry_run)
+                    int dry_run, int fixed_tab)
 {
   const grub_uint32_t *ptr;
   grub_ssize_t startwidth = dry_run ? 0 : get_startwidth (term, margin_left);
@@ -582,7 +604,7 @@ print_ucs4_terminal (const grub_uint32_t * str,
                      && grub_unicode_get_comb_type (*ptr2)
                      != GRUB_UNICODE_COMB_NONE)
                    continue;
-                 putcode_real (*ptr2, term);
+                 putcode_real (*ptr2, term, fixed_tab);
                }
 
              grub_print_spaces (term, margin_right);
@@ -593,6 +615,7 @@ print_ucs4_terminal (const grub_uint32_t * str,
                  state->backlog_ucs4 = (ptr == last_space || *ptr == '\n') 
                    ? ptr + 1 : ptr;
                  state->backlog_len = last_position - state->backlog_ucs4;
+                 state->backlog_fixed_tab = fixed_tab;
                  return 1;
                }
            }
@@ -619,7 +642,7 @@ print_ucs4_terminal (const grub_uint32_t * str,
              && grub_unicode_get_comb_type (*ptr2)
              != GRUB_UNICODE_COMB_NONE)
            continue;
-         putcode_real (*ptr2, term);
+         putcode_real (*ptr2, term, fixed_tab);
        }
     }
   return dry_run ? lines : 0;
@@ -652,14 +675,14 @@ put_glyphs_terminal (const struct grub_unicode_glyph *visual,
                     grub_ssize_t visual_len,
                     int margin_left, int margin_right,
                     struct grub_term_output *term,
-                    struct term_state *state)
+                    struct term_state *state, int fixed_tab)
 {
   const struct grub_unicode_glyph *visual_ptr;
   for (visual_ptr = visual; visual_ptr < visual + visual_len; visual_ptr++)
     {
       if (visual_ptr->base == '\n')
        grub_print_spaces (term, margin_right);
-      putglyph (visual_ptr, term);
+      putglyph (visual_ptr, term, fixed_tab);
       if (visual_ptr->base == '\n')
        {
          if (state && ++state->num_lines
@@ -667,6 +690,7 @@ put_glyphs_terminal (const struct grub_unicode_glyph *visual,
            {
              state->backlog_glyphs = visual_ptr + 1;
              state->backlog_len = visual_len - (visual_ptr - visual) - 1;
+             state->backlog_fixed_tab = fixed_tab;
              return 1;
            }
 
@@ -691,7 +715,8 @@ print_backlog (struct grub_term_output *term,
       int ret;
       ret = print_ucs4_terminal (state->backlog_ucs4,
                                 state->backlog_ucs4 + state->backlog_len,
-                                margin_left, margin_right, term, state, 0);
+                                margin_left, margin_right, term, state, 0,
+                                state->backlog_fixed_tab);
       if (!ret)
        {
          grub_free (state->free);
@@ -707,7 +732,8 @@ print_backlog (struct grub_term_output *term,
       int ret;
       ret = put_glyphs_terminal (state->backlog_glyphs,
                                 state->backlog_len,
-                                margin_left, margin_right, term, state);
+                                margin_left, margin_right, term, state,
+                                state->backlog_fixed_tab);
       if (!ret)
        {
          grub_free (state->free);
@@ -726,7 +752,7 @@ print_ucs4_real (const grub_uint32_t * str,
                 const grub_uint32_t * last_position,
                 int margin_left, int margin_right,
                 struct grub_term_output *term, int backlog,
-                int dry_run)
+                int dry_run, int fixed_tab)
 {
   struct term_state *state = NULL;
 
@@ -780,7 +806,7 @@ print_ucs4_real (const grub_uint32_t * str,
       else
        {
          ret = put_glyphs_terminal (visual, visual_len, margin_left,
-                                    margin_right, term, state);
+                                    margin_right, term, state, fixed_tab);
          if (!ret)
            grub_free (visual);
          else
@@ -789,7 +815,7 @@ print_ucs4_real (const grub_uint32_t * str,
       return ret;
     }
   return print_ucs4_terminal (str, last_position, margin_left, margin_right,
-                             term, state, dry_run);
+                             term, state, dry_run, fixed_tab);
 }
 
 void
@@ -799,7 +825,7 @@ grub_print_ucs4 (const grub_uint32_t * str,
                 struct grub_term_output *term)
 {
   print_ucs4_real (str, last_position, margin_left, margin_right,
-                  term, 0, 0);
+                  term, 0, 0, 1);
 }
 
 int
@@ -809,7 +835,7 @@ grub_ucs4_count_lines (const grub_uint32_t * str,
                       struct grub_term_output *term)
 {
   return print_ucs4_real (str, last_position, margin_left, margin_right,
-                         term, 0, 1);
+                         term, 0, 1, 1);
 }
 
 void
@@ -859,7 +885,7 @@ grub_xputs_normal (const char *str)
   {
     int cur;
     cur = print_ucs4_real (unicode_str, unicode_last_position, 0, 0,
-                          term, grub_more, 0);
+                          term, grub_more, 0, 0);
     if (cur)
       backlog = 1;
   }
index 0e14e64cf72815ee2fe9a9150527a434a23d4cca..92927176cea299fe06f6c6643f46aa440a5d62bc 100644 (file)
@@ -293,4 +293,8 @@ grub_ssize_t
 grub_encode_utf8_character (grub_uint8_t *dest, grub_uint8_t *destend,
                            grub_uint32_t code);
 
+const grub_uint32_t *
+grub_unicode_get_comb_start (const grub_uint32_t *str, 
+                            const grub_uint32_t *cur);
+
 #endif
index e73f8aa25491ae215cf85ba9f3360743bfeb3abb..e28279015cdff9329e133723170491e7fa37c2f0 100644 (file)
@@ -435,10 +435,15 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c __attribute__ ((
 
 #endif
 
+#define GRUB_TERM_TAB_WIDTH 8
+
 static inline grub_ssize_t 
 grub_term_getcharwidth (struct grub_term_output *term,
                        const struct grub_unicode_glyph *c)
 {
+  if (c->base == '\t')
+    return GRUB_TERM_TAB_WIDTH;
+
   if (term->getcharwidth)
     return term->getcharwidth (term, c);
   else if (((term->flags & GRUB_TERM_CODE_TYPE_MASK)
index 24240a019bf520e8562ea6940255907fb5deb9fb..22a0df11c7a3ba78e2ab39292f1b64a3b9e501b0 100644 (file)
@@ -243,13 +243,14 @@ grub_unicode_glyph_dup (const struct grub_unicode_glyph *in)
   grub_memcpy (out, in, sizeof (*in));
   if (in->combining)
     {
-      out->combining = grub_malloc (in->ncomb * sizeof (*in));
+      out->combining = grub_malloc (in->ncomb * sizeof (out->combining[0]));
       if (!out->combining)
        {
          grub_free (out);
          return NULL;
        }
-      grub_memcpy (out->combining, in->combining, in->ncomb * sizeof (*in));
+      grub_memcpy (out->combining, in->combining,
+                  in->ncomb * sizeof (out->combining[0]));
     }
   return out;
 }