* Modified files : dispextern.h dispnew.c indent.c window.c xdisp.c * Modified structs, macros and functions : struct glyph_row MATRIX_ROW_CONTINUATION_LINE_P MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P compute_motion buffer_posn_from_coords Fvertical_motion window_scroll_pixel_based start_display move_it_in_display_line_to move_it_to move_it_vertically_backward move_it_by_lines try_window try_window_id display_line $(C":(B Changes in dispextern.h $(C"9(BChage of struct glyph_row. /* XXXX : Added. 1 means that this row displays a continued line, i.e. it has a continuation mark at the left side. */ unsigned left_continued_p : 1; Added this. This represent the continuation mark on the left side. (For the right side there is a member named continued_p.) One and only write access to this member is at the beginning of display_line() in xdisp.c. The reason which call for this member is hard to understand. That is because it is not an ideal treatment but a kind of ad hac one. The macro MATRIX_ROW_CONTINUATION_LINE_P originally defined as ((ROW)->continuation_lines_width > 0). (ROW is a pointer to struct glyph_row.) OTOH there was occuring of skrewed up display when the very first line in the window is of continuation, according to the other fixes, which required setting both row->continuation_lines_width and it->continuation_lines_width to 0. Here setting these to 0 is the ad hoc treatment. I decided to employ this treatment because I couldn't guess how much of work is required to fix all things without this. Fortunately it has been settled with minimum change. $(C"9(BChanged MATRIX_ROW_CONTINUATION_LINE_P to see left_continued_p. See above for explanation. $(C"9(BChange of MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P. #define MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P(ROW) \ ((ROW)->end.dpvec_index > 0 \ || (ROW)->end.overlay_string_index >= 0 \ || (ROW)->ends_in_middle_of_char_p) Originally it was coded (ROW)->end.dpvec_index >= 0 and it was wrong. row->end is set at the end of display_line() in xdisp.c as row->end = it->current;. That is, position of the iterator at the end of the just displayed line is recorded. In the case of dpvec_index == 0, the iterator is pointing at the first character of a dpvec (or display table vector for long) and none of the chracters are yet displayed from dpvec. It means that the row doesn't end in the middle of a character but just before that character. Same could be said of overlay_string_index, but I'm not sure yet. Following is the explanation of the situation the bug revieals it's existance. On a emacs running on a terminal, assume content of a buffer to be displayed continued like this. Axxxxxxxxxxxxxxxxxx\ ^@ (^@ is ?\x00.) Here, ^@ is displayed using dpvec. Doing (vertical-motion 1) with a cursor on the character 'A', is expected to bring the cursor on ^@, but actually the cursor is displayed on the continuation glyph \ . This is a bug in the display side of the code. A cursor's position of display is decided in the following lines of display_line(). if (it->w->cursor.vpos < 0 && PT >= MATRIX_ROW_START_CHARPOS (row) && PT <= MATRIX_ROW_END_CHARPOS (row) && cursor_row_p (it->w, row)) set_cursor_from_row (it->w, row, it->w->desired_matrix, 0, 0, 0, 0); Meaning of these are, * If a line to have a cursor on it is not known yet, * and if the point is bitween start and end of the line(glyph_row), * and if invocation of cursor_row_p returns true, * then the cursor is on the line(glyph_row), * so call set_cursor_from_row to calculate the position in per pixel resolution * and set the final values to the window. If MATRIX_ROW_ENDS_IN_MIDDLE_OF_CHAR_P called in cursor_row_p returns true, cursor_row_p returns row->continued_p. It is true with the above example. BTW, at a first glance it looks like equal(==) of PT <= MATRIX_ROW_END_CHARPOS (row) is useless, but, you know, it is necessary when continuation occurs between ^ and @ of ^@. $(C":(B Change in dispnew.c $(C"9(BChange of buffer_posn_from_coords. Likewise try_window and try_window_id of xdisp.c, made it set members of it to 0 after start_display. $(C":(B Change in indent.c $(C"9(BChange of compute_motion - part1 Fixed that tab_offset was calculated but not set to val_compute_motion. Formerly val_compute_motion.tab_offset was always 0. Following is the situation the bug revieals it's existance. On a emacs running on a terminal, assume content of a buffer to be displayed like this. x x x x x x \ A x x x x \ B C x (all spaces are tabs) Doing (vertical-motion 1) with a cursor on the character 'A', is expected to bring the cursor to 'B', but actually it is brought to 'C' $(C"9(BChange of compute_motion - part2 Fixed wrong calculation of tab_offset. While compute_motion process geometries proceeding 'pos' toward 'to', 'pos' always overtake 'to' by one, and then 'pos' is drawn back to 'to'. And the geometry infomation at 'to' are returned. (Here, unit of 'pos' is 'character' in a buffer. For example, mutibyte- characters, newlines, tabs and control-codes, each one are characters.) This behavior is to handle continuation, but the handling of tab_offset was wrong. Formerly, tab_offset was always set back to prev_tab_offset when 'pos' was drawn back. In case of continuation, tab_offset is supposed to be set to the horizontal start position of the continuation line, witch is indicated by the horizontal position on the imaginaly line of infinite length without continuation. Thus, tab_offset is updated only if continuation occurs. When calculating geometry infomation at the drawn back position, setting tab_offset back to it's previous value is needed only if the last character processed is a character which produces multiple glyphs. This is the case with tabs and cotrol-codes. Following is the actual condition. if (contin_hpos && prev_hpos == 0 && contin_hpos < width && !wide_column_end_hpos) It is a bit hard to understand this code, witch reads as follows, if there is room for more than or equal to a single non-wide-column glyph and there is continuation and it is not caused by a wide-column glyph. Then, as both the very first space(?\x20) of tabs and ^ of control-codes are supposed to fit in the end of the previous line, tab_offset must be also set back to prev_tab_offset. $(C"9(BFiexed vertical-motion 's return value so as to follow document. This fix is simple. Made it to return the difference between it.vpos stored just after start_display and after move_it_by_lines (&it, XINT (lines), 0); . $(C":(B Change in window.c $(C"9(BFixed wrong setting process of w->start_at_line_beg within if (! vscrolled) of window_scroll_pixel_based(). Formerly a result of Fbolp() was set. But here we can't say that IT_CHARPOS(it) == PT . So consulting other parts, I made it like this. w->start_at_line_beg = ((IT_CHARPOS (it) == BEGV || FETCH_BYTE (IT_BYTEPOS (it) - 1) == '\n') ? Qt : Qnil); It seems like Fbolp() came from other code such like move-to-window-line witch set_marker_both (w->start, w->buffer, PT, PT_BYTE); beforehand. $(C":(B Change in xdisp.c $(C"9(BChange of start_display - part1 Commented out same code, witch imply that coder was taking a bug in move_it_to as a specification. As the bug in move_it_to has been fixed, there is no need for these code. By the way, with only MOVE_TO_POS specified move_it_to always take iterator to the position of to_charpos unless the line including the character at the position of to_charpos is beeing eclipsed by selective display. If the line is beeing eclipsed iterator is taken to the begining of the next line not beeing eclipsed or to ZV. $(C"9(BChange of start_display - part2 Moved the code commented as follows /* We're starting a new display line, not affected by the height of the continued line, so clear the appropriate fields in the iterator structure. */ to the else block of the following condition. if (!start_at_line_beg_p) But this can be a needless code too. I'm not sure though. $(C"9(BChange of move_it_in_display_line_to - part1 /* Stop when ZV or TO_CHARPOS reached. */ if (!get_next_display_element (it) || ((op & MOVE_TO_POS) != 0 && BUFFERP (it->object) && IT_CHARPOS (*it) >= to_charpos)) Splited above condition in to two parts and added code to the latter. In case of !get_next_display_element that is when the iterator reached end of the buffer (or string it could be,) return MOVE_POS_MATCH_OR_ZV as original code did. If the iterator reached to_charpos and we are directed to do continuation check if the charactor at that position can be fit in the current line. If it can't be fit in, I made the function to return MOVE_LINE_CONTINUED for the present call to let the caller know that continuation occured. I made a change in move_it_to which corespond to this situation, but it is unknown whether handling this way is safe for all the other callers. $(C"9(BChange of move_it_in_display_line_to - part2 /* We want to leave anything reaching TO_X to the caller. */ The objective mentioned in the above comment can't be accomplished due to the code which handle continuation of tabs. Thus added comment to the above one. $(C"9(BChange of move_it_in_display_line_to - part3 As for the code handling glyphs which can not be fitted in to a line, made it handle tabs specially. When a glyph which should be pushed out was found to be of a tab, advance it->current_x even when it goes beyond last_visible_x. Thus, a situation where it->current_x > it->last_visible_x occures. I made move_it_to handle this situation correctly, but I'm not sure if there are any other parts which can be affected by this. Apart from move_it_to there are 4 invocations of move_it_in_display_line_to. It might be better to push out whole tab when space left between it->current_x and it->last_visible_x is less than CANON_X_UNIT (f). $(C"9(BChange of move_it_to - part1 I modified the code handling MOVE_TO_VPOS so that it can handle the case MOVE_TO_X is specified as well. Currently there is no such invocation. But I wanted this 'cause I'd like to make use of it in time. Note that move_it_display_line_to doesn't change it->vpos, and that is the roll of move_it_to. Among the display stuff, display_line which is in charge of displaying a line is changing it->vpos. That is a kind of poor symmetry. move_it_to has a chance of abort()-ing when it gets only MOVE_TO_X specified. Such invocation might be inhibited, I suppose. $(C"9(BChange of move_it_to - part2 . . .