Restore and enhance pager functionality
This commit is contained in:
		
							parent
							
								
									6fcebedeed
								
							
						
					
					
						commit
						3c69fb81e1
					
				
					 3 changed files with 316 additions and 151 deletions
				
			
		|  | @ -113,7 +113,6 @@ void read_terminal_list (void); | |||
| void grub_set_more (int onoff); | ||||
| 
 | ||||
| int grub_normal_get_char_counter (void); | ||||
| void grub_install_newline_hook (void); | ||||
| 
 | ||||
| void grub_xputs_normal (const char *str); | ||||
| 
 | ||||
|  |  | |||
|  | @ -661,7 +661,6 @@ GRUB_MOD_INIT(normal) | |||
| 
 | ||||
|   grub_set_history (GRUB_DEFAULT_HISTORY_SIZE); | ||||
| 
 | ||||
|   grub_install_newline_hook (); | ||||
|   grub_register_variable_hook ("pager", 0, grub_env_write_pager); | ||||
| 
 | ||||
|   /* Register a command "normal" for the rescue mode.  */ | ||||
|  |  | |||
							
								
								
									
										323
									
								
								normal/term.c
									
										
									
									
									
								
							
							
						
						
									
										323
									
								
								normal/term.c
									
										
									
									
									
								
							|  | @ -28,11 +28,17 @@ | |||
| struct term_state | ||||
| { | ||||
|   struct term_state *next; | ||||
|   struct grub_unicode_glyph *backlog; | ||||
|   int numlines; | ||||
|   const struct grub_unicode_glyph *backlog_glyphs; | ||||
|   const grub_uint32_t *backlog_ucs4; | ||||
|   grub_size_t backlog_len; | ||||
| 
 | ||||
|   void *free; | ||||
|   int num_lines; | ||||
|   char *term_name; | ||||
| }; | ||||
| 
 | ||||
| static struct term_state *term_states = NULL; | ||||
| 
 | ||||
| /* The amount of lines counted by the pager.  */ | ||||
| static unsigned grub_more_lines; | ||||
| 
 | ||||
|  | @ -48,39 +54,51 @@ grub_normal_get_char_counter (void) | |||
| } | ||||
| 
 | ||||
| static void | ||||
| process_newline (void) | ||||
| print_more (void) | ||||
| { | ||||
|   struct grub_term_output *cur; | ||||
|   unsigned height = -1; | ||||
| 
 | ||||
|   FOR_ACTIVE_TERM_OUTPUTS(cur) | ||||
|     if (grub_term_height (cur) < height) | ||||
|       height = grub_term_height (cur); | ||||
|   grub_more_lines++; | ||||
| 
 | ||||
|   if (grub_more && grub_more_lines >= height - 1) | ||||
|     { | ||||
|   char key; | ||||
|   grub_uint16_t *pos; | ||||
|   grub_term_output_t term; | ||||
|   grub_uint32_t *unicode_str, *unicode_last_position; | ||||
| 
 | ||||
|   pos = grub_term_save_pos (); | ||||
| 
 | ||||
|   grub_utf8_to_ucs4_alloc ("--MORE--", &unicode_str, | ||||
| 			   &unicode_last_position); | ||||
| 
 | ||||
|   if (!unicode_str) | ||||
|     { | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); | ||||
|       grub_printf ("--MORE--"); | ||||
| 
 | ||||
|   FOR_ACTIVE_TERM_OUTPUTS(term) | ||||
|   { | ||||
|     grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term); | ||||
|   } | ||||
|   grub_setcolorstate (GRUB_TERM_COLOR_STANDARD); | ||||
| 
 | ||||
|   grub_free (unicode_str); | ||||
|    | ||||
|   key = grub_getkey (); | ||||
| 
 | ||||
|   /* Remove the message.  */ | ||||
|   grub_term_restore_pos (pos); | ||||
|       grub_printf ("        "); | ||||
|   FOR_ACTIVE_TERM_OUTPUTS(term) | ||||
|     grub_print_spaces (term, 8); | ||||
|   grub_term_restore_pos (pos); | ||||
| 
 | ||||
|   /* Scroll one lines or an entire page, depending on the key.  */ | ||||
| 
 | ||||
|   { | ||||
|     static struct term_state *state; | ||||
|     for (state = term_states; state; state = state->next) | ||||
|       if (key == '\r' || key =='\n') | ||||
| 	grub_more_lines = height - 2; | ||||
| 	state->num_lines = 0; | ||||
|       else | ||||
| 	grub_more_lines = 0; | ||||
| 	state->num_lines -= 2; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
|  | @ -95,12 +113,6 @@ grub_set_more (int onoff) | |||
|   grub_more_lines = 0; | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_install_newline_hook (void) | ||||
| { | ||||
|   grub_newline_hook = process_newline; | ||||
| } | ||||
| 
 | ||||
| static grub_uint32_t | ||||
| map_code (grub_uint32_t in, struct grub_term_output *term) | ||||
| { | ||||
|  | @ -431,16 +443,10 @@ grub_putcode (grub_uint32_t code, struct grub_term_output *term) | |||
|   putcode_real (code, term); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_print_ucs4 (const grub_uint32_t * str, | ||||
| 		 const grub_uint32_t * last_position, | ||||
| 		 int margin_left, int margin_right, | ||||
| 		 struct grub_term_output *term) | ||||
| static grub_ssize_t | ||||
| get_maxwidth (struct grub_term_output *term, | ||||
| 	      int margin_left, int margin_right) | ||||
| { | ||||
|   grub_ssize_t max_width; | ||||
|   grub_ssize_t startwidth; | ||||
| 
 | ||||
|   { | ||||
|   struct grub_unicode_glyph space_glyph = { | ||||
|     .base = ' ', | ||||
|     .variant = 0, | ||||
|  | @ -448,56 +454,30 @@ grub_print_ucs4 (const grub_uint32_t * str, | |||
|     .ncomb = 0, | ||||
|     .combining = 0 | ||||
|   }; | ||||
|     max_width = grub_term_width (term) | ||||
|   return (grub_term_width (term) | ||||
| 	  - grub_term_getcharwidth (term, &space_glyph)  | ||||
|       * (margin_left + margin_right) - 1; | ||||
|   } | ||||
| 	  * (margin_left + margin_right) - 1); | ||||
| } | ||||
| 
 | ||||
|   if (((term->getxy () >> 8) & 0xff) < margin_left) | ||||
|     grub_print_spaces (term, margin_left - ((term->getxy () >> 8) & 0xff)); | ||||
| static grub_ssize_t | ||||
| get_startwidth (struct grub_term_output *term, | ||||
| 		int margin_left) | ||||
| { | ||||
|   return ((term->getxy () >> 8) & 0xff) - margin_left; | ||||
| } | ||||
| 
 | ||||
|   startwidth = ((term->getxy () >> 8) & 0xff) - margin_left; | ||||
| 
 | ||||
|   if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)  | ||||
|       == GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS | ||||
|       || (term->flags & GRUB_TERM_CODE_TYPE_MASK)  | ||||
|       == GRUB_TERM_CODE_TYPE_UTF8_VISUAL) | ||||
|     { | ||||
|       grub_ssize_t visual_len; | ||||
|       struct grub_unicode_glyph *visual; | ||||
|       struct grub_unicode_glyph *visual_ptr; | ||||
| 
 | ||||
|       auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c); | ||||
|       grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c) | ||||
|       { | ||||
| 	return grub_term_getcharwidth (term, c); | ||||
|       } | ||||
| 
 | ||||
|       visual_len = grub_bidi_logical_to_visual (str, last_position - str, | ||||
| 						&visual, getcharwidth, | ||||
| 						max_width, startwidth); | ||||
|       if (visual_len < 0) | ||||
| 	{ | ||||
| 	  grub_print_error (); | ||||
| 	  return; | ||||
| 	} | ||||
|       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); | ||||
| 	  if (visual_ptr->base == '\n') | ||||
| 	    grub_print_spaces (term, margin_left); | ||||
| 	  grub_free (visual_ptr->combining); | ||||
| 	} | ||||
|       grub_free (visual); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   { | ||||
| static int | ||||
| print_ucs4_terminal (const grub_uint32_t * str, | ||||
| 		     const grub_uint32_t * last_position, | ||||
| 		     int margin_left, int margin_right, | ||||
| 		     struct grub_term_output *term, | ||||
| 		     struct term_state *state) | ||||
| { | ||||
|   const grub_uint32_t *ptr; | ||||
|   grub_ssize_t startwidth = get_startwidth (term, margin_left); | ||||
|   grub_ssize_t line_width = startwidth; | ||||
|   grub_ssize_t lastspacewidth = 0; | ||||
|   grub_ssize_t max_width = get_maxwidth (term, margin_left, margin_right); | ||||
|   const grub_uint32_t *line_start = str, *last_space = str - 1; | ||||
| 
 | ||||
|   for (ptr = str; ptr < last_position; ptr++) | ||||
|  | @ -549,6 +529,15 @@ grub_print_ucs4 (const grub_uint32_t * str, | |||
| 
 | ||||
| 	  grub_print_spaces (term, margin_right); | ||||
| 	  grub_putcode ('\n', term); | ||||
| 	  if (state && state->num_lines++ | ||||
| 	      >= (grub_ssize_t) grub_term_height (term)) | ||||
| 	    { | ||||
| 	      state->backlog_ucs4 = (ptr == last_space || *ptr == '\n')  | ||||
| 		? ptr + 1 : ptr; | ||||
| 	      state->backlog_len = last_position - state->backlog_ucs4; | ||||
| 	      return 1; | ||||
| 	    } | ||||
| 
 | ||||
| 	  line_width -= lastspacewidth; | ||||
| 	  grub_print_spaces (term, margin_left); | ||||
| 	  if (ptr == last_space || *ptr == '\n') | ||||
|  | @ -570,20 +559,198 @@ grub_print_ucs4 (const grub_uint32_t * str, | |||
| 	putcode_real (*ptr2, term); | ||||
|       } | ||||
|   } | ||||
|   } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static struct term_state * | ||||
| find_term_state (struct grub_term_output *term) | ||||
| { | ||||
|   struct term_state *state; | ||||
|   for (state = term_states; state; state = state->next) | ||||
|     if (grub_strcmp (state->term_name, term->name) == 0) | ||||
|       return state; | ||||
| 
 | ||||
|   state = grub_zalloc (sizeof (*state)); | ||||
|   if (!state) | ||||
|     { | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|       return NULL; | ||||
|     } | ||||
| 
 | ||||
|   state->term_name = grub_strdup (term->name); | ||||
|   state->next = term_states; | ||||
|   term_states = state; | ||||
| 
 | ||||
|   return state; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| 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) | ||||
| { | ||||
|   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); | ||||
|       if (state && state->num_lines++ >= (grub_ssize_t) grub_term_height (term)) | ||||
|       { | ||||
| 	state->backlog_glyphs = visual_ptr + 1; | ||||
| 	state->backlog_len = visual_len - (visual - visual_ptr) - 1; | ||||
| 	return 1; | ||||
|       } | ||||
| 
 | ||||
|       if (visual_ptr->base == '\n') | ||||
| 	grub_print_spaces (term, margin_left); | ||||
|       grub_free (visual_ptr->combining); | ||||
|     } | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| print_backlog (struct grub_term_output *term, | ||||
| 	       int margin_left, int margin_right) | ||||
| { | ||||
|   struct term_state *state = find_term_state (term); | ||||
| 
 | ||||
|   if (!state) | ||||
|     return 0; | ||||
| 
 | ||||
|   if (state->backlog_ucs4) | ||||
|     { | ||||
|       int ret; | ||||
|       ret = print_ucs4_terminal (state->backlog_ucs4, | ||||
| 				 state->backlog_ucs4 + state->backlog_len, | ||||
| 				 margin_left, margin_right, term, state); | ||||
|       if (!ret) | ||||
| 	{ | ||||
| 	  grub_free (state->free); | ||||
| 	  state->free = NULL; | ||||
| 	  state->backlog_len = 0; | ||||
| 	} | ||||
|       return ret; | ||||
|     } | ||||
| 
 | ||||
|   if (state->backlog_glyphs) | ||||
|     { | ||||
|       int ret; | ||||
|       ret = put_glyphs_terminal (state->backlog_glyphs, | ||||
| 				 state->backlog_len, | ||||
| 				 margin_left, margin_right, term, state); | ||||
|       if (!ret) | ||||
| 	{ | ||||
| 	  grub_free (state->free); | ||||
| 	  state->free = NULL; | ||||
| 	  state->backlog_len = 0; | ||||
| 	} | ||||
|       return ret; | ||||
|     } | ||||
| 
 | ||||
|   return 0; | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|   struct term_state *state = NULL; | ||||
| 
 | ||||
|   if (backlog) | ||||
|     state = find_term_state (term); | ||||
| 
 | ||||
|   if (((term->getxy () >> 8) & 0xff) < margin_left) | ||||
|     grub_print_spaces (term, margin_left - ((term->getxy () >> 8) & 0xff)); | ||||
| 
 | ||||
|   if ((term->flags & GRUB_TERM_CODE_TYPE_MASK)  | ||||
|       == GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS | ||||
|       || (term->flags & GRUB_TERM_CODE_TYPE_MASK)  | ||||
|       == GRUB_TERM_CODE_TYPE_UTF8_VISUAL) | ||||
|     { | ||||
|       grub_ssize_t visual_len; | ||||
|       struct grub_unicode_glyph *visual; | ||||
|       int ret; | ||||
| 
 | ||||
|       auto grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c); | ||||
|       grub_ssize_t getcharwidth (const struct grub_unicode_glyph *c) | ||||
|       { | ||||
| 	return grub_term_getcharwidth (term, c); | ||||
|       } | ||||
| 
 | ||||
|       visual_len = grub_bidi_logical_to_visual (str, last_position - str, | ||||
| 						&visual, getcharwidth, | ||||
| 						get_maxwidth (term,  | ||||
| 							      margin_left, | ||||
| 							      margin_right), | ||||
| 						get_startwidth (term,  | ||||
| 								margin_left)); | ||||
|       if (visual_len < 0) | ||||
| 	{ | ||||
| 	  grub_print_error (); | ||||
| 	  return 0; | ||||
| 	} | ||||
|       ret = put_glyphs_terminal (visual, visual_len, margin_left, margin_right, | ||||
| 				 term, state); | ||||
|       if (!ret) | ||||
| 	grub_free (visual); | ||||
|       else | ||||
| 	state->free = visual; | ||||
|       return ret; | ||||
|     } | ||||
|   return print_ucs4_terminal (str, last_position, margin_left, margin_right, | ||||
| 			      term, state); | ||||
| } | ||||
| 
 | ||||
| void | ||||
| grub_print_ucs4 (const grub_uint32_t * str, | ||||
| 		 const grub_uint32_t * last_position, | ||||
| 		 int margin_left, int margin_right, | ||||
| 		 struct grub_term_output *term) | ||||
| { | ||||
|   print_ucs4_real (str, last_position, margin_left, margin_right, | ||||
| 		   term, 0); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void | ||||
| grub_xputs_normal (const char *str) | ||||
| { | ||||
|   grub_term_output_t term; | ||||
|   grub_uint32_t *unicode_str, *unicode_last_position; | ||||
|   int backlog = 0; | ||||
|   grub_utf8_to_ucs4_alloc (str, &unicode_str, | ||||
| 			   &unicode_last_position); | ||||
| 
 | ||||
|   if (!unicode_str) | ||||
|     { | ||||
|       grub_errno = GRUB_ERR_NONE; | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|   FOR_ACTIVE_TERM_OUTPUTS(term) | ||||
|   { | ||||
|     grub_print_ucs4 (unicode_str, unicode_last_position, 0, 0, term); | ||||
|     int cur; | ||||
|     cur = print_ucs4_real (unicode_str, unicode_last_position, 0, 0, | ||||
| 			   term, 1); | ||||
|     if (cur) | ||||
|       backlog = 1; | ||||
|   } | ||||
|   while (backlog) | ||||
|     { | ||||
|       print_more (); | ||||
|       backlog = 0; | ||||
|       FOR_ACTIVE_TERM_OUTPUTS(term) | ||||
|       { | ||||
| 	int cur; | ||||
| 	cur = print_backlog (term, 0, 0); | ||||
| 	if (cur) | ||||
| 	  backlog = 1; | ||||
|       } | ||||
|     } | ||||
|   grub_free (unicode_str); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue