I think the problem is not in vertical-motion at all. The problem is that the "normal" display of embedded images allows us to get into a situation with layout which vertical-motion doesn't expect to happen, when these two minor modes are turned on. Please try the patch below and see if it gives good results. diff --git a/src/xdisp.c b/src/xdisp.c index 4e8bb7d..7afa64d 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -31956,12 +31956,13 @@ produce_image_glyph (struct it *it) word-wrap, unless the image starts at column zero, because wrapping correctly needs the real pixel width of the image. */ if ((it->line_wrap != WORD_WRAP - || it->hpos == 0 + || it->hpos == 0 + (it->lnum_width ? it->lnum_width + 2 : 0) /* Always crop images larger than the window-width, minus 1 space. */ || it->pixel_width > it->last_visible_x - FRAME_COLUMN_WIDTH (it->f)) && (crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0) - && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4)) + && (it->hpos == 0 + (it->lnum_width ? it->lnum_width + 2 : 0) + || it->pixel_width > it->last_visible_x / 4)) { it->pixel_width -= crop; slice.width -= crop;
Unfortunately with this patch, I could still get the cursor stuck. See stuck.png and following gdb logs when it gets stuck:
+bt
#0 produce_image_glyph (it=0x7fff258031d0) at xdisp.c:31958
#1 0x000057ba672d79e1 in gui_produce_glyphs (it=0x7fff258031d0)
at xdisp.c:33672
#2 0x000057ba672bcb18 in display_line (it=0x7fff258031d0,
cursor_vpos=6) at xdisp.c:25720
#3 0x000057ba672aeb0a in try_window (window=0x57baa27b9c2d,
pos=..., flags=1) at xdisp.c:21413
#4 0x000057ba672abaa3 in redisplay_window (window=0x57baa27b9c2d,
just_this_one_p=true) at xdisp.c:20784
#5 0x000057ba672a2fa9 in redisplay_window_1
(window=0x57baa27b9c2d) at xdisp.c:18268
#6 0x000057ba67460bf1 in internal_condition_case_1
(bfun=0x57ba672a2f67 <redisplay_window_1>,
arg=0x57baa27b9c2d, handlers=0x710b5b9a7d33, hfun=0x57ba672a2df7
<redisplay_window_error>) at eval.c:1644
#7 0x000057ba672a207d in redisplay_internal () at xdisp.c:17774
#8 0x000057ba6729fb21 in redisplay () at xdisp.c:16802
#9 0x000057ba6739a0cb in read_char (commandflag=1,
map=0x57baa32452f3, prev_event=0x0,
used_mouse_menu=0x7fff2580871a, end_time=0x0) at keyboard.c:2672
#10 0x000057ba673ad0fb in read_key_sequence
(keybuf=0x7fff25808990, prompt=0x0, dont_downcase_last=false,
can_return_switch_frame=true, fix_current_buffer=true,
prevent_redisplay=false, disable_text_conversion_p=false) at
keyboard.c:10848
#11 0x000057ba67396751 in command_loop_1 () at keyboard.c:1424
#12 0x000057ba67460b4a in internal_condition_case
(bfun=0x57ba67396343 <command_loop_1>, handlers=0x90,
hfun=0x57ba67395874 <cmd_error>) at eval.c:1620
#13 0x000057ba67395f90 in command_loop_2 (handlers=0x90) at
keyboard.c:1163
#14 0x000057ba6746009f in internal_catch (tag=0x11f40,
func=0x57ba67395f66 <command_loop_2>, arg=0x90) at
eval.c:1300
#15 0x000057ba67395f22 in command_loop () at keyboard.c:1141
#16 0x000057ba67395416 in recursive_edit_1 () at keyboard.c:749
#17 0x000057ba673955c2 in Frecursive_edit () at keyboard.c:832
#18 0x000057ba6739167f in main (argc=3, argv=0x7fff25808e78) at
emacs.c:2560
+p *it
$11 = {window = 0x57baa27b9c2d, w = 0x57baa27b9c28, f =
0x57baa27b99d0, method = GET_FROM_IMAGE, stop_charpos = 127,
prev_stop = 126, base_level_stop = 126, end_charpos = 302,
medium_narrowing_begv = 0, medium_narrowing_zv = 0,
large_narrowing_begv = 0, large_narrowing_zv = 0, s = 0x0,
string_nchars = 0, multibyte_p = true, tab_line_p = false,
header_line_p = false, string_from_display_prop_p = false,
string_from_prefix_prop_p = false, from_disp_prop_p = true,
ellipsis_p = false, avoid_cursor_p = false, dp = 0x0, dpvec = 0x0,
dpend = 0x0, dpvec_char_len = 0, dpvec_face_id = 0, saved_face_id
= 34, ctl_chars = {0x0 <repeats 16 times>}, start = {pos =
{charpos = 121, bytepos = 121}, overlay_string_index = -1,
string_pos = {charpos = -1, bytepos = -1}, dpvec_index = -1},
current = {pos = {charpos = 126, bytepos = 126},
overlay_string_index = -1, string_pos = {charpos = -1, bytepos =
-1}, dpvec_index = -1}, n_overlay_strings = 0,
overlay_strings_charpos = 126, overlay_strings = {0x0 <repeats
16 times>}, string_overlays = {0x0 <repeats 16 times>},
string = 0x0, from_overlay = 0x0, stack = {{string = 0x0,
string_nchars = 0, end_charpos = 302, stop_charpos = 127,
prev_stop = 126, base_level_stop = 126, cmp_it = {stop_pos = 129,
id = -1, ch = -2, rule_idx = 0, lookback = 0, nglyphs = 0,
reversed_p = false, parent_it = 0x7fff258031d0, charpos = 0,
nchars = 0, nbytes = 0, from = 0, to = 0, width = 0}, face_id =
34, u = {image = {object = 0x0, slice = {x = 0x0, y = 0x0, width =
0x0, height = 0x0}, image_id = 0}, stretch = {object = 0x0},
xwidget = {object = 0x0}}, position = {charpos = 127, bytepos =
127}, current = {pos = {charpos = 127, bytepos = 127},
overlay_string_index = -1, string_pos = {charpos = -1, bytepos =
-1}, dpvec_index = -1}, from_overlay = 0x0, area = TEXT_AREA,
method = GET_FROM_BUFFER, paragraph_embedding = NEUTRAL_DIR,
multibyte_p = true, string_from_display_prop_p = false,
string_from_prefix_prop_p = false, display_ellipsis_p = false,
avoid_cursor_p = false, bidi_p = true, from_disp_prop_p = false,
line_wrap = WORD_WRAP, voffset = 0, space_width = 0x0, font_height
= 0x0}, {string = 0x0, string_nchars = 0, end_charpos = 0,
stop_charpos = 0, prev_stop = 0, base_level_stop = 0, cmp_it =
{stop_pos = 0, id = 0, ch = 0, rule_idx = 0, lookback = 0, nglyphs
= 0, reversed_p = false, parent_it = 0x0, charpos = 0, nchars = 0,
nbytes = 0, from = 0, to = 0, width = 0}, face_id = 0, u = {image
= {object = 0x0, slice = {x = 0x0, y = 0x0, width = 0x0, height =
0x0}, image_id = 0}, stretch = {object = 0x0}, xwidget = {object =
0x0}}, position = {charpos = 0, bytepos = 0}, current = {pos =
{charpos = 0, bytepos = 0}, overlay_string_index = 0, string_pos =
{charpos = 0, bytepos = 0}, dpvec_index = 0}, from_overlay = 0x0,
area = LEFT_MARGIN_AREA, method = GET_FROM_BUFFER,
paragraph_embedding = NEUTRAL_DIR, multibyte_p = false,
string_from_display_prop_p = false, string_from_prefix_prop_p =
false, display_ellipsis_p = false, avoid_cursor_p = false, bidi_p
= false, from_disp_prop_p = false, line_wrap = TRUNCATE, voffset =
0, space_width = 0x0, font_height = 0x0}, {string = 0x0,
string_nchars = 0, end_charpos = 0, stop_charpos = 0, prev_stop =
0, base_level_stop = 0, cmp_it = {stop_pos = 0, id = 0, ch = 0,
rule_idx = 0, lookback = 0, nglyphs = 0, reversed_p = false,
parent_it = 0x0, charpos = 0, nchars = 0, nbytes = 0, from = 0, to
= 0, width = 0}, face_id = 0, u = {image = {object = 0x0, slice =
{x = 0x0, y = 0x0, width = 0x0, height = 0x0}, image_id = 0},
stretch = {object = 0x0}, xwidget = {object = 0x0}}, position =
{charpos = 0, bytepos = 0}, current = {pos = {charpos = 0, bytepos
= 0}, overlay_string_index = 0, string_pos = {charpos = 0, bytepos
= 0}, dpvec_index = 0}, from_overlay = 0x0, area =
LEFT_MARGIN_AREA, method = GET_FROM_BUFFER, paragraph_embedding =
NEUTRAL_DIR, multibyte_p = false, string_from_display_prop_p =
false, string_from_prefix_prop_p = false, display_ellipsis_p =
false, avoid_cursor_p = false, bidi_p = false, from_disp_prop_p =
false, line_wrap = TRUNCATE, voffset = 0, space_width = 0x0,
font_height = 0x0}, {string = 0x0, string_nchars = 0, end_charpos
= 0, stop_charpos = 0, prev_stop = 0, base_level_stop = 0, cmp_it
= {stop_pos = 0, id = 0, ch = 0, rule_idx = 0, lookback = 0,
nglyphs = 0, reversed_p = false, parent_it = 0x0, charpos = 0,
nchars = 0, nbytes = 0, from = 0, to = 0, width = 0}, face_id = 0,
u = {image = {object = 0x0, slice = {x = 0x0, y = 0x0, width =
0x0, height = 0x0}, image_id = 0}, stretch = {object = 0x0},
xwidget = {object = 0x0}}, position = {charpos = 0, bytepos = 0},
current = {pos = {charpos = 0, bytepos = 0}, overlay_string_index
= 0, string_pos = {charpos = 0, bytepos = 0}, dpvec_index = 0},
from_overlay = 0x0, area = LEFT_MARGIN_AREA, method =
GET_FROM_BUFFER, paragraph_embedding = NEUTRAL_DIR, multibyte_p =
false, string_from_display_prop_p = false,
string_from_prefix_prop_p = false, display_ellipsis_p = false,
avoid_cursor_p = false, bidi_p = false, from_disp_prop_p = false,
line_wrap = TRUNCATE, voffset = 0, space_width = 0x0, font_height
= 0x0}, {string = 0x0, string_nchars = 0, end_charpos = 0,
stop_charpos = 0, prev_stop = 0, base_level_stop = 0, cmp_it =
{stop_pos = 0, id = 0, ch = 0, rule_idx = 0, lookback = 0, nglyphs
= 0, reversed_p = false, parent_it = 0x0, charpos = 0, nchars = 0,
nbytes = 0, from = 0, to = 0, width = 0}, face_id = 0, u = {image
= {object = 0x0, slice = {x = 0x0, y = 0x0, width = 0x0, height =
0x0}, image_id = 0}, stretch = {object = 0x0}, xwidget = {object =
0x0}}, position = {charpos = 0, bytepos = 0}, current = {pos =
{charpos = 0, bytepos = 0}, overlay_string_index = 0, string_pos =
{charpos = 0, bytepos = 0}, dpvec_index = 0}, from_overlay = 0x0,
area = LEFT_MARGIN_AREA, method = GET_FROM_BUFFER,
paragraph_embedding = NEUTRAL_DIR, multibyte_p = false,
string_from_display_prop_p = false, string_from_prefix_prop_p =
false, display_ellipsis_p = false, avoid_cursor_p = false, bidi_p
= false, from_disp_prop_p = false, line_wrap = TRUNCATE, voffset =
0, space_width = 0x0, font_height = 0x0}}, sp = 1, selective = 0,
what = IT_IMAGE, face_id = 34, selective_display_ellipsis_p =
true, ctl_arrow_p = true, face_box_p = false, start_of_box_run_p =
false, end_of_box_run_p = false,
overlay_strings_at_end_processed_p = false,
ignore_overlay_strings_at_pos_p = false, glyph_not_available_p =
false, starts_in_middle_of_char_p = false, face_before_selective_p
= false, constrain_row_ascent_descent_p = false,
line_number_produced_p = true, align_visually_p = false, line_wrap
= WORD_WRAP, base_face_id = 34, c = 101, len = 1, cmp_it =
{stop_pos = 129, id = -1, ch = -2, rule_idx = 0, lookback = 0,
nglyphs = 0, reversed_p = false, parent_it = 0x7fff258031d0,
charpos = 0, nchars = 0, nbytes = 0, from = 0, to = 0, width = 0},
char_to_display = 101, glyphless_method =
GLYPHLESS_DISPLAY_THIN_SPACE, image_id = 13, xwidget = 0x0, slice
= {x = 0x0, y = 0x0, width = 0x0, height = 0x0}, space_width =
0x0, voffset = 0, tab_width = 8, font_height = 0x0, object =
0x57baa2a18f9d, position = {charpos = 126, bytepos = 126},
truncation_pixel_width = 0, continuation_pixel_width = 20,
first_visible_x = 0, last_visible_x = 1012, last_visible_y = 918,
extra_line_spacing = 0, max_extra_line_spacing = 0,
override_ascent = -1, override_descent = 0, override_boff = 0,
glyph_row = 0x57baa2af4120, area = TEXT_AREA, nglyphs = 1,
pixel_width = 948, ascent = 20, descent = 20, max_ascent = 36,
max_descent = 10, phys_ascent = 20, phys_descent = 20,
max_phys_ascent = 25, max_phys_descent = 8, current_x = 180,
wrap_prefix_width = 0, continuation_lines_width = 0, eol_pos =
{charpos = 0, bytepos = 0}, current_y = 230, first_vpos = 0, vpos
= 5, hpos = 9, lnum = 3, lnum_bytepos = 121, lnum_width = 2,
lnum_pixel_width = 80, pt_lnum = 0, stretch_adjust = 0,
left_user_fringe_bitmap = 0, right_user_fringe_bitmap = 0,
left_user_fringe_face_id = 0, right_user_fringe_face_id = 0,
bidi_p = true, bidi_it = {bytepos = 126, charpos = 126, ch =
65532, nchars = 1, ch_len = 1, type = STRONG_L, type_after_wn =
NEUTRAL_ON, orig_type = NEUTRAL_ON, resolved_level = 0 '\000',
isolate_level = 0 '\000', invalid_levels = 0, invalid_isolates =
0, prev = {charpos = 125, type = STRONG_L, orig_type = STRONG_L},
last_strong = {charpos = 125, type = STRONG_L, orig_type =
STRONG_L}, next_for_neutral = {charpos = -1, type = UNKNOWN_BT,
orig_type = UNKNOWN_BT}, prev_for_neutral = {charpos = 125, type =
STRONG_L, orig_type = STRONG_L}, next_for_ws = {charpos = -1, type
= UNKNOWN_BT, orig_type = UNKNOWN_BT}, bracket_pairing_pos = -1,
bracket_enclosed_type = UNKNOWN_BT, next_en_pos = 0, next_en_type
= UNKNOWN_BT, sos = L2R, scan_dir = 1, disp_pos = 302, disp_prop =
0, stack_idx = 0, level_stack = {{next_for_neutral_pos = 0,
next_for_neutral_type = 0, last_strong_type = 0,
prev_for_neutral_type = 0, level = 0 '\000', flags = 0 '\000'}
<repeats 128 times>}, string = {lstring = 0x0, s = 0x0,
schars = 0, bufpos = 0, from_disp_str = false, unibyte = false}, w
= 0x57baa27b9c28, paragraph_dir = L2R, separator_limit = -1,
first_elt = false, new_paragraph = false, frame_window_p = true},
paragraph_embedding = NEUTRAL_DIR, min_width_property = 0x0,
min_width_start = 0}
An updated patch resolves the issue (also attached):
diff --git a/src/xdisp.c b/src/xdisp.c
index 4e8bb7d9b97..c6b87b08ae9 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -31956,12 +31956,14 @@ produce_image_glyph (struct it *it)
word-wrap, unless the image starts at column zero, because
wrapping correctly needs the real pixel width of the image.
*/
if ((it->line_wrap != WORD_WRAP
- || it->hpos == 0
+ || it->hpos == (it->lnum_width ? it->lnum_width +
2 : 0)
/* Always crop images larger than the window-width, minus
1 space. */
- || it->pixel_width > it->last_visible_x -
FRAME_COLUMN_WIDTH (it->f))
+ || it->pixel_width > it->last_visible_x -
FRAME_COLUMN_WIDTH (it->f)
+ - it->lnum_pixel_width)
&& (crop = it->pixel_width -
(it->last_visible_x - it->current_x),
- crop > 0)
- && (it->hpos == 0 || it->pixel_width >
it->last_visible_x / 4))
+ crop > 0)
+ && (it->hpos == (it->lnum_width ?
it->lnum_width + 2 : 0)
+ || it->pixel_width > it->last_visible_x / 4))
{
it->pixel_width -= crop;
slice.width -= crop;
However, I think that images wider than the line should always start on a new line, instead of being almost clipped on the current line. E.g., see bad_clipping.png. Do you think I should file a separate bug report for this?