|  |  | @ -148,15 +148,17 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_REDO        keyboard input to perform redo
 |  |  |  | //    STB_TEXTEDIT_K_REDO        keyboard input to perform redo
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //
 |  |  |  | //
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // Optional:
 |  |  |  | // Optional:
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_INSERT      keyboard input to toggle insert mode
 |  |  |  | //    STB_TEXTEDIT_K_INSERT              keyboard input to toggle insert mode
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_IS_SPACE(ch)  true if character is whitespace (e.g. 'isspace'),
 |  |  |  | //    STB_TEXTEDIT_IS_SPACE(ch)          true if character is whitespace (e.g. 'isspace'),
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //                                 required for WORDLEFT/WORDRIGHT
 |  |  |  | //                                          required for default WORDLEFT/WORDRIGHT handlers
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_WORDLEFT    keyboard input to move cursor left one word // e.g. ctrl-LEFT
 |  |  |  | //    STB_TEXTEDIT_MOVEWORDLEFT(obj,i)   custom handler for WORDLEFT, returns index to move cursor to
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_WORDRIGHT   keyboard input to move cursor right one word // e.g. ctrl-RIGHT
 |  |  |  | //    STB_TEXTEDIT_MOVEWORDRIGHT(obj,i)  custom handler for WORDRIGHT, returns index to move cursor to
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_LINESTART2  secondary keyboard input to move cursor to start of line
 |  |  |  | //    STB_TEXTEDIT_K_WORDLEFT            keyboard input to move cursor left one word // e.g. ctrl-LEFT
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_LINEEND2    secondary keyboard input to move cursor to end of line
 |  |  |  | //    STB_TEXTEDIT_K_WORDRIGHT           keyboard input to move cursor right one word // e.g. ctrl-RIGHT
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_TEXTSTART2  secondary keyboard input to move cursor to start of text
 |  |  |  | //    STB_TEXTEDIT_K_LINESTART2          secondary keyboard input to move cursor to start of line
 | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_TEXTEND2    secondary keyboard input to move cursor to end of text
 |  |  |  | //    STB_TEXTEDIT_K_LINEEND2            secondary keyboard input to move cursor to end of line
 | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //    STB_TEXTEDIT_K_TEXTSTART2          secondary keyboard input to move cursor to start of text
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | //    STB_TEXTEDIT_K_TEXTEND2            secondary keyboard input to move cursor to end of text
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //
 |  |  |  | //
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // Todo:
 |  |  |  | // Todo:
 | 
			
		
	
		
		
			
				
					
					|  |  |  | //    STB_TEXTEDIT_K_PGUP        keyboard input to move cursor up a page
 |  |  |  | //    STB_TEXTEDIT_K_PGUP        keyboard input to move cursor up a page
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -615,9 +617,9 @@ static int is_word_boundary( STB_TEXTEDIT_STRING *_str, int _idx ) | 
			
		
	
		
		
			
				
					
					|  |  |  |    return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1; |  |  |  |    return _idx > 0 ? (STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str,_idx-1) ) && !STB_TEXTEDIT_IS_SPACE( STB_TEXTEDIT_GETCHAR(_str, _idx) ) ) : 1; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) |  |  |  | #ifndef STB_TEXTEDIT_MOVEWORDLEFT | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, int c ) | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |    int c = _state->cursor - 1; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    while( c >= 0 && !is_word_boundary( _str, c ) ) |  |  |  |    while( c >= 0 && !is_word_boundary( _str, c ) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |       --c; |  |  |  |       --c; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -626,11 +628,13 @@ static int stb_textedit_move_to_word_previous( STB_TEXTEDIT_STRING *_str, STB_Te | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    return c; |  |  |  |    return c; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #define STB_TEXTEDIT_MOVEWORDLEFT stb_textedit_move_to_word_previous | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #endif | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_TexteditState *_state ) |  |  |  | #ifndef STB_TEXTEDIT_MOVEWORDRIGHT | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, int c ) | 
			
		
	
		
		
			
				
					
					|  |  |  | { |  |  |  | { | 
			
		
	
		
		
			
				
					
					|  |  |  |    const int len = STB_TEXTEDIT_STRINGLEN(_str); |  |  |  |    const int len = STB_TEXTEDIT_STRINGLEN(_str); | 
			
		
	
		
		
			
				
					
					|  |  |  |    int c = _state->cursor+1; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |    while( c < len && !is_word_boundary( _str, c ) ) |  |  |  |    while( c < len && !is_word_boundary( _str, c ) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |       ++c; |  |  |  |       ++c; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -639,6 +643,9 @@ static int stb_textedit_move_to_word_next( STB_TEXTEDIT_STRING *_str, STB_Texted | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |    return c; |  |  |  |    return c; | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #define STB_TEXTEDIT_MOVEWORDRIGHT stb_textedit_move_to_word_next | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #endif | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #endif |  |  |  | #endif | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // update selection and cursor to match each other
 |  |  |  | // update selection and cursor to match each other
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -760,21 +767,12 @@ retry: | 
			
		
	
		
		
			
				
					
					|  |  |  |          state->has_preferred_x = 0; |  |  |  |          state->has_preferred_x = 0; | 
			
		
	
		
		
			
				
					
					|  |  |  |          break; |  |  |  |          break; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | #ifdef STB_TEXTEDIT_IS_SPACE |  |  |  | #ifdef STB_TEXTEDIT_MOVEWORDLEFT | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |       case STB_TEXTEDIT_K_WORDLEFT: |  |  |  |       case STB_TEXTEDIT_K_WORDLEFT: | 
			
		
	
		
		
			
				
					
					|  |  |  |          if (STB_TEXT_HAS_SELECTION(state)) |  |  |  |          if (STB_TEXT_HAS_SELECTION(state)) | 
			
		
	
		
		
			
				
					
					|  |  |  |             stb_textedit_move_to_first(state); |  |  |  |             stb_textedit_move_to_first(state); | 
			
		
	
		
		
			
				
					
					|  |  |  |          else { |  |  |  |          else { | 
			
		
	
		
		
			
				
					
					|  |  |  |             state->cursor = stb_textedit_move_to_word_previous(str, state); |  |  |  |             state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor-1); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |             stb_textedit_clamp( str, state ); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |          } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |          break; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       case STB_TEXTEDIT_K_WORDRIGHT: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |          if (STB_TEXT_HAS_SELECTION(state)) 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             stb_textedit_move_to_last(str, state); |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |          else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             state->cursor = stb_textedit_move_to_word_next(str, state); |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             stb_textedit_clamp( str, state ); |  |  |  |             stb_textedit_clamp( str, state ); | 
			
		
	
		
		
			
				
					
					|  |  |  |          } |  |  |  |          } | 
			
		
	
		
		
			
				
					
					|  |  |  |          break; |  |  |  |          break; | 
			
		
	
	
		
		
			
				
					|  |  | @ -783,17 +781,28 @@ retry: | 
			
		
	
		
		
			
				
					
					|  |  |  |          if( !STB_TEXT_HAS_SELECTION( state ) ) |  |  |  |          if( !STB_TEXT_HAS_SELECTION( state ) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             stb_textedit_prep_selection_at_cursor(state); |  |  |  |             stb_textedit_prep_selection_at_cursor(state); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |          state->cursor = stb_textedit_move_to_word_previous(str, state); |  |  |  |          state->cursor = STB_TEXTEDIT_MOVEWORDLEFT(str, state->cursor-1); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |          state->select_end = state->cursor; |  |  |  |          state->select_end = state->cursor; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |          stb_textedit_clamp( str, state ); |  |  |  |          stb_textedit_clamp( str, state ); | 
			
		
	
		
		
			
				
					
					|  |  |  |          break; |  |  |  |          break; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #endif | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | #ifdef STB_TEXTEDIT_MOVEWORDRIGHT | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       case STB_TEXTEDIT_K_WORDRIGHT: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          if (STB_TEXT_HAS_SELECTION(state)) 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stb_textedit_move_to_last(str, state); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor+1); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             stb_textedit_clamp( str, state ); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |          break; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |       case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: |  |  |  |       case STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT: | 
			
		
	
		
		
			
				
					
					|  |  |  |          if( !STB_TEXT_HAS_SELECTION( state ) ) |  |  |  |          if( !STB_TEXT_HAS_SELECTION( state ) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             stb_textedit_prep_selection_at_cursor(state); |  |  |  |             stb_textedit_prep_selection_at_cursor(state); | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |          state->cursor = stb_textedit_move_to_word_next(str, state); |  |  |  |          state->cursor = STB_TEXTEDIT_MOVEWORDRIGHT(str, state->cursor+1); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |          state->select_end = state->cursor; |  |  |  |          state->select_end = state->cursor; | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |          stb_textedit_clamp( str, state ); |  |  |  |          stb_textedit_clamp( str, state ); | 
			
		
	
	
		
		
			
				
					|  |  | 
 |