Package: emacs;
Reported by: Yifan Zhu <fanzhuyifan <at> gmail.com>
Date: Sun, 23 Mar 2025 18:46:01 UTC
Severity: normal
Found in version 31.0.50
Done: Eli Zaretskii <eliz <at> gnu.org>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 77217 in the body.
You can then email your comments to 77217 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Sun, 23 Mar 2025 18:46:02 GMT) Full text and rfc822 format available.Yifan Zhu <fanzhuyifan <at> gmail.com>
:bug-gnu-emacs <at> gnu.org
.
(Sun, 23 Mar 2025 18:46:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Yifan Zhu <fanzhuyifan <at> gmail.com> To: bug-gnu-emacs <at> gnu.org Subject: 31.0.50; cursor stuck on long image under display-line-numbers-mode and visual-line-mode Date: Sun, 23 Mar 2025 11:45:12 -0700
[Message part 1 (text/plain, inline)]
--text follows this line-- emacs -Q test.txt (attached) insert image (long.png, attached) after last word in second line, no space (set-frame-size (selected-frame) 80 36) increase size (ctrl+scroll) (see reference.png, attached) move cursor to bottom and try to move cursor back up cursor gets stuck at the image In GNU Emacs 31.0.50 (build 22, x86_64-pc-linux-gnu, GTK+ Version 3.24.49, cairo version 1.18.4) Repository revision: 9e005e9da06f71441e643f7ecbe309e35f68680a Repository branch: master System Description: Arch Linux Configured using: 'configure --with-pgtk --sysconfdir=/etc --localstatedir=/var --disable-build-details --with-cairo --with-harfbuzz --with-libsystemd --with-modules --with-native-compilation=aot --with-tree-sitter 'CFLAGS=-ggdb3 -O0' 'CXXFLAGS=-ggdb3 -O0' LDFLAGS=-ggdb3 --prefix=/home/yifan/packages/emacs-git/build --exec-prefix=/home/yifan/packages/emacs-git/build' Configured features: ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG LCMS2 LIBOTF LIBSYSTEMD LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PGTK PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER WEBP XIM GTK3 ZLIB Important settings: value of $LANG: en_US.utf8 value of $XMODIFIERS: @im=fcitx locale-coding-system: utf-8-unix Major mode: Text Minor modes in effect: text-scale-mode: t display-line-numbers-mode: t tooltip-mode: t global-eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t tool-bar-mode: t menu-bar-mode: t file-name-shadow-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t minibuffer-regexp-mode: t line-number-mode: t visual-line-mode: t indent-tabs-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t Load-path shadows: None found. Features: (shadow sort mail-extr emacsbug lisp-mnt message mailcap yank-media puny dired dired-loaddefs rfc822 mml mml-sec password-cache epa derived epg rfc6068 epg-config gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils face-remap compile text-property-search comint ansi-osc ansi-color ring comp-run bytecomp byte-compile comp-common rx time-date subr-x cl-loaddefs cl-lib display-line-numbers rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/pgtk-win pgtk-win term/common-win touch-screen pgtk-dnd tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads dbusbind inotify dynamic-setting system-font-setting font-render-setting cairo gtk pgtk lcms2 multi-tty move-toolbar make-network-process tty-child-frames native-compile emacs) Memory information: ((conses 16 67339 20133) (symbols 48 6859 0) (strings 32 17412 2459) (string-bytes 1 703591) (vectors 16 10908) (vector-slots 8 151951 9248) (floats 8 28 20) (intervals 56 284 0) (buffers 992 14))
[reference.png (image/png, attachment)]
[test.txt (text/plain, attachment)]
[long.png (image/png, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Tue, 25 Mar 2025 17:15:02 GMT) Full text and rfc822 format available.Message #8 received at 77217 <at> debbugs.gnu.org (full text, mbox):
From: Yifan Zhu <fanzhuyifan <at> gmail.com> To: 77217 <at> debbugs.gnu.org Subject: issue seems to be in vertical-motion Date: Tue, 25 Mar 2025 10:14:04 -0700
The issue seems to be in `vertical-motion`, as the cursor is stuck on that image when directly executing (vertical-motion (cons 10 -1)) (both display-line-numbers-mode and visual-line-mode need to be enabled. Forgot to mention that in the original email)
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Tue, 25 Mar 2025 18:23:02 GMT) Full text and rfc822 format available.Message #11 received at 77217 <at> debbugs.gnu.org (full text, mbox):
From: Yifan Zhu <fanzhuyifan <at> gmail.com> To: 77217 <at> debbugs.gnu.org Subject: move_it_to moves point to line after to_charpos when to_charpos is an image. Date: Tue, 25 Mar 2025 11:21:47 -0700
When to_charpos is an image, move_it_to moves the point to to_charpos+1, which is on the next line. This effetively undoes the move_it_by_lines (&it, max (PTRDIFF_MIN, nlines)); later. Unsure how this should be fixed though. See gdb log below: charpos=126 is long image; charpos=127 is on next visual line Thread 1 "emacs" hit Breakpoint 9, Fvertical_motion (lines=0x5e34b7cbbb63, window=0x0, cur_col=0x0) at indent.c:2191 2191 { +next 2195 Lisp_Object lcols = Qnil; +next 2196 void *itdata = NULL; +next 2197 specpdl_ref count = SPECPDL_INDEX (); +next 2200 if (CONSP (lines)) +next 2202 lcols = XCAR (lines); +next 2203 CHECK_NUMBER (lcols); +next 2204 lines = XCDR (lines); +next 2207 CHECK_FIXNUM (lines); +next 2208 w = decode_live_window (window); +next 2210 if (XBUFFER (w->contents) != current_buffer) +next 2222 if (noninteractive) +next 2231 ptrdiff_t it_start, it_overshoot_count = 0; +next 2233 bool overshoot_handled = 0; +next 2234 bool disp_string_at_start_p = 0; +next 2235 ptrdiff_t nlines = XFIXNUM (lines); +next 2236 int vpos_init = 0; +next 2237 double start_col UNINIT; +next 2238 int start_x UNINIT; +next 2239 int to_x = -1; +next 2241 bool start_x_given = !NILP (cur_col); +next 2242 if (start_x_given) +next 2252 int lnum_width = 0; +next 2253 int lnum_pixel_width = 0; +next 2254 if (!NILP (Vdisplay_line_numbers)) +next 2255 line_number_display_width (w, &lnum_width, &lnum_pixel_width); +next 2256 SET_TEXT_POS (pt, PT, PT_BYTE); +next 2257 itdata = bidi_shelve_cache (); +next 2258 record_unwind_protect_void (unwind_display_working_on_window); +next 2259 display_working_on_window_p = true; +next 2260 start_display (&it, w, pt); 2: it->current->pos = {charpos = 0, bytepos = 0} +next 2261 it.lnum_width = lnum_width; 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2262 first_x = it.first_visible_x; +next 2263 it_start = IT_CHARPOS (it); +next 2266 if (it.cmp_it.id >= 0) +next 2268 else if (it.method == GET_FROM_STRING) +next 2294 !((it.method == GET_FROM_IMAGE && it.image_id >= 0) +next 2291 it_overshoot_count = +next 2297 if (start_x_given) +next 2307 reseat_at_previous_visible_line_start (&it); 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2308 it.current_x = it.hpos = 0; 2: it->current->pos = {charpos = 121, bytepos = 121} +next 2310 if (IT_CHARPOS (it) != PT) +next 2324 (!disp_string_at_start_p +next Thread 1 "emacs" hit Breakpoint 4, Fvertical_motion (lines=0xfffffffffffffffe, window=0x0, cur_col=0x0) at indent.c:2323 2323 move_it_to (&it, +next 2326 ? PT +next 2323 move_it_to (&it, 2: it->current->pos = {charpos = 121, bytepos = 121} +next Thread 1 "emacs" hit Breakpoint 8, Fvertical_motion (lines=0xfffffffffffffffe, window=0x0, cur_col=0x0) at indent.c:2335 2335 if (IT_CHARPOS (it) > it_start) 2: it->current->pos = {charpos = 127, bytepos = 127} +next 2341 if (it_overshoot_count < 0 +next 2345 else if (it_overshoot_count == 1 && it.vpos == 0 +next 2354 else if (disp_string_at_start_p && it.vpos > 0) +next 2364 if (it.line_wrap == TRUNCATE && it.current_x >= it.last_visible_x +next 2367 if (it_overshoot_count > 0) +next 2370 overshoot_handled = 1; +next 2388 if (!NILP (lcols)) +next 2390 window_column_x (w, window, XFLOATINT (lcols), lcols) +next 2391 + lnum_pixel_width; +next 2389 to_x = +next 2392 if (nlines <= 0) +next 2394 it.vpos = vpos_init; +next 2395 it.current_y = 0; +next 2398 if ((nlines < 0 && IT_CHARPOS (it) > BEGV) +next 2400 move_it_by_lines (&it, max (PTRDIFF_MIN, nlines)); 2: it->current->pos = {charpos = 127, bytepos = 127} +next 2449 if (!NILP (lcols)) 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2451 move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X); 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2458 if (nlines >= 0 && it.area == TEXT_AREA) 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2472 SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it)); 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2473 bidi_unshelve_cache (itdata, 0); 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2476 return unbind_to (count, make_fixnum (it.vpos)); 2: it->current->pos = {charpos = 126, bytepos = 126} +next 2477 } 2: it->current->pos = {charpos = 126, bytepos = 126} +next 0x000073b6f2385ddd in F6c696e652d6d6f76652d76697375616c_line_move_visual_0 () from /home/yifan/packages/emacs-git/build/bin/../lib/emacs/31.0.50/native-lisp/31.0.50-28637a6f/preloaded/simple-fab5b0cf-4c8dda8b.eln +next Single stepping until exit from function F6c696e652d6d6f76652d76697375616c_line_move_visual_0, which has no line number information.
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Wed, 26 Mar 2025 14:49:02 GMT) Full text and rfc822 format available.Message #14 received at 77217 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Yifan Zhu <fanzhuyifan <at> gmail.com> Cc: 77217 <at> debbugs.gnu.org Subject: Re: bug#77217: move_it_to moves point to line after to_charpos when to_charpos is an image. Date: Wed, 26 Mar 2025 16:47:51 +0200
> Date: Tue, 25 Mar 2025 11:21:47 -0700 > From: Yifan Zhu <fanzhuyifan <at> gmail.com> > > When to_charpos is an image, move_it_to moves the point to to_charpos+1, > which is on the next line. This effetively undoes the move_it_by_lines > (&it, max (PTRDIFF_MIN, nlines)); later. > > > Unsure how this should be fixed though. 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;
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Wed, 26 Mar 2025 16:40:01 GMT) Full text and rfc822 format available.Message #17 received at 77217 <at> debbugs.gnu.org (full text, mbox):
From: Yifan Zhu <fanzhuyifan <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 77217 <at> debbugs.gnu.org Subject: Re: bug#77217: move_it_to moves point to line after to_charpos when to_charpos is an image. Date: Wed, 26 Mar 2025 09:39:18 -0700
[Message part 1 (text/plain, inline)]
Hi, Thank you for your prompt response! On 3/26/25 7:47 AM, Eli Zaretskii wrote: > 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?
[Message part 2 (text/html, inline)]
[stuck.png (image/png, attachment)]
[bad_clipping.png (image/png, attachment)]
[0001-correctly-handle-image-cropping-under-display-line-n.patch (text/x-patch, attachment)]
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Wed, 26 Mar 2025 17:18:02 GMT) Full text and rfc822 format available.Message #20 received at 77217 <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Yifan Zhu <fanzhuyifan <at> gmail.com> Cc: 77217 <at> debbugs.gnu.org Subject: Re: bug#77217: move_it_to moves point to line after to_charpos when to_charpos is an image. Date: Wed, 26 Mar 2025 19:16:53 +0200
> Date: Wed, 26 Mar 2025 09:39:18 -0700 > Cc: 77217 <at> debbugs.gnu.org > From: Yifan Zhu <fanzhuyifan <at> gmail.com> > > 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; Thanks, this is almost the same as my original patch, with the addition of one more fix. So I merged your addition with my original changes and installed that on the master branch. > 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? You could file a bug, but I'm not sure this will or even should be changed. I certainly don't plan working on such a change. Emacs behaved like it does now since v21.1: wide images are cropped at the right edge of the window. That's because, unlike with text, there's no way of continuing a wide image on the next screen line. Starting such images on the next line will not solve the problem completely, because an image could be wider than the window to begin with; the clear disadvantage is that you waste one more screen line. So we use a heuristic: if the image's width is more than 1/4th of the window, we always crop it. I don't think there are better alternatives. If this is somehow problematic in the specific case where you bumped into this, my suggestion is to break wide images into several narrower ones, or maybe use the 'slice' feature of the Emacs display of images.
bug-gnu-emacs <at> gnu.org
:bug#77217
; Package emacs
.
(Wed, 26 Mar 2025 17:58:02 GMT) Full text and rfc822 format available.Message #23 received at 77217 <at> debbugs.gnu.org (full text, mbox):
From: Yifan Zhu <fanzhuyifan <at> gmail.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: 77217 <at> debbugs.gnu.org Subject: Re: bug#77217: move_it_to moves point to line after to_charpos when to_charpos is an image. Date: Wed, 26 Mar 2025 10:57:24 -0700
On 3/26/25 10:16 AM, Eli Zaretskii wrote: >> Date: Wed, 26 Mar 2025 09:39:18 -0700 >> Cc: 77217 <at> debbugs.gnu.org >> From: Yifan Zhu <fanzhuyifan <at> gmail.com> >> >> 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; > Thanks, this is almost the same as my original patch, with the > addition of one more fix. So I merged your addition with my original > changes and installed that on the master branch. Thanks! I had a small nit about the redundant "0 +"s in your original patch. But it doesn't really matter. > >> 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? > You could file a bug, but I'm not sure this will or even should be > changed. I certainly don't plan working on such a change. Emacs > behaved like it does now since v21.1: wide images are cropped at the > right edge of the window. That's because, unlike with text, there's > no way of continuing a wide image on the next screen line. Starting > such images on the next line will not solve the problem completely, > because an image could be wider than the window to begin with; the > clear disadvantage is that you waste one more screen line. So we use > a heuristic: if the image's width is more than 1/4th of the window, we > always crop it. I don't think there are better alternatives. > > If this is somehow problematic in the specific case where you bumped > into this, my suggestion is to break wide images into several narrower > ones, or maybe use the 'slice' feature of the Emacs display of images. Makes sense -- it was just a small issue I found when testing out the change, and not really something that annoys me in my workflow. Thanks again!
Eli Zaretskii <eliz <at> gnu.org>
:Yifan Zhu <fanzhuyifan <at> gmail.com>
:Message #28 received at 77217-done <at> debbugs.gnu.org (full text, mbox):
From: Eli Zaretskii <eliz <at> gnu.org> To: Yifan Zhu <fanzhuyifan <at> gmail.com> Cc: 77217-done <at> debbugs.gnu.org Subject: Re: bug#77217: move_it_to moves point to line after to_charpos when to_charpos is an image. Date: Thu, 03 Apr 2025 10:23:51 +0300
> Date: Wed, 26 Mar 2025 10:57:24 -0700 > Cc: 77217 <at> debbugs.gnu.org > From: Yifan Zhu <fanzhuyifan <at> gmail.com> > > On 3/26/25 10:16 AM, Eli Zaretskii wrote: > >> Date: Wed, 26 Mar 2025 09:39:18 -0700 > >> Cc: 77217 <at> debbugs.gnu.org > >> From: Yifan Zhu <fanzhuyifan <at> gmail.com> > >> > >> 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; > > Thanks, this is almost the same as my original patch, with the > > addition of one more fix. So I merged your addition with my original > > changes and installed that on the master branch. > Thanks! I had a small nit about the redundant "0 +"s in your original > patch. But it doesn't really matter. > > > >> 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? > > You could file a bug, but I'm not sure this will or even should be > > changed. I certainly don't plan working on such a change. Emacs > > behaved like it does now since v21.1: wide images are cropped at the > > right edge of the window. That's because, unlike with text, there's > > no way of continuing a wide image on the next screen line. Starting > > such images on the next line will not solve the problem completely, > > because an image could be wider than the window to begin with; the > > clear disadvantage is that you waste one more screen line. So we use > > a heuristic: if the image's width is more than 1/4th of the window, we > > always crop it. I don't think there are better alternatives. > > > > If this is somehow problematic in the specific case where you bumped > > into this, my suggestion is to break wide images into several narrower > > ones, or maybe use the 'slice' feature of the Emacs display of images. > > Makes sense -- it was just a small issue I found when testing out the > change, and not really something that annoys me in my workflow. No further comments, so I'm now closing this bug.
Debbugs Internal Request <help-debbugs <at> gnu.org>
to internal_control <at> debbugs.gnu.org
.
(Thu, 01 May 2025 11:24:06 GMT) Full text and rfc822 format available.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.