From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Keith David Bershatsky Newsgroups: gmane.emacs.devel Subject: Problems with move_it_in_display_line_to X when tabs exist. Date: Tue, 28 Nov 2017 22:12:35 -0800 Message-ID: NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=US-ASCII X-Trace: blaine.gmane.org 1511936018 30928 195.159.176.226 (29 Nov 2017 06:13:38 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 29 Nov 2017 06:13:38 +0000 (UTC) To: Emacs Devel Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Nov 29 07:13:33 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eJvcb-0007BR-F3 for ged-emacs-devel@m.gmane.org; Wed, 29 Nov 2017 07:13:26 +0100 Original-Received: from localhost ([::1]:41425 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eJvci-0004K4-Rr for ged-emacs-devel@m.gmane.org; Wed, 29 Nov 2017 01:13:32 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:52908) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eJvcA-0004Jm-17 for emacs-devel@gnu.org; Wed, 29 Nov 2017 01:12:59 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eJvc6-0003Hb-Q6 for emacs-devel@gnu.org; Wed, 29 Nov 2017 01:12:57 -0500 Original-Received: from gateway30.websitewelcome.com ([192.185.145.3]:44917) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1eJvc6-00039z-GL for emacs-devel@gnu.org; Wed, 29 Nov 2017 01:12:54 -0500 Original-Received: from cm14.websitewelcome.com (cm14.websitewelcome.com [100.42.49.7]) by gateway30.websitewelcome.com (Postfix) with ESMTP id 720D14E74 for ; Wed, 29 Nov 2017 00:12:37 -0600 (CST) Original-Received: from gator3053.hostgator.com ([50.87.144.69]) by cmsmtp with SMTP id JvboeWln0HEImJvboeY09o; Wed, 29 Nov 2017 00:12:37 -0600 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lawlist.com ; s=default; h=Content-Type:MIME-Version:Subject:To:From:Message-ID:Date: Sender:Reply-To:Cc:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=bP92QVNBNfOjF6/NIicokCzoBKZbZNkTlxN1o20F3sc=; b=EuLm/AwLxc/kdm0cMW1p7uaYh3 Rj/KPMEd23kPjpVLVz7XNfovlBRXzSLpcGSdtFgmzg+2zVJgDNlQhK3yJ9lLv0aZjbAXNgo1QsA1m 6zhrAdabKzoWKdYLuABYgwTgPhv2gcKitW5pPA4iLrB01pr5c1UOmKwMT+vUqhD2XkC/45FuN1vdM 8L4NJbW8G8YCcqoLyTNgd6qOdUf8cDzzQ0OuMBzKF8yAIgjPS+syEEUKM4rgFoQYnxxNGXj/j2gYD EJF/ub8SAkhnprHHfS+tsOngy/huMLeSoUK1GlliKGRpMNZk7/mXfGBrHMUd4kYXtyeeKXRRb/Wks 6OFhFu+A==; Original-Received: from cpe-45-48-239-195.socal.res.rr.com ([45.48.239.195]:58619 helo=server.private) by gator3053.hostgator.com with esmtpsa (TLSv1:DHE-RSA-AES256-SHA:256) (Exim 4.89) (envelope-from ) id 1eJvbo-003nbg-4N for emacs-devel@gnu.org; Wed, 29 Nov 2017 00:12:36 -0600 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - gator3053.hostgator.com X-AntiAbuse: Original Domain - gnu.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - lawlist.com X-BWhitelist: no X-Source-IP: 45.48.239.195 X-Source-L: No X-Exim-ID: 1eJvbo-003nbg-4N X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: cpe-45-48-239-195.socal.res.rr.com (server.private) [45.48.239.195]:58619 X-Source-Auth: lawlist X-Email-Count: 1 X-Source-Cap: bGF3bGlzdDtsYXdsaXN0O2dhdG9yMzA1My5ob3N0Z2F0b3IuY29t X-Local-Domain: yes X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 192.185.145.3 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:220516 Archived-At: I have reached a road block calculating X and HPOS when dealing with tabs while working on feature requests 17684 (crosshairs) and 22873 (multiple fake cursors). DETAILS: Native line numbers are visible. No overlays are present. No special text properties are present. GOAL: The goal is to move IT from it.first_visible_x to it.last_visible_x on the line containing POINT and place fake cursors on each tab, adjustable tab-width, and/or character. As I move IT over the line containing POINT, I want to reliably obtain X and HPOS. This works well if there are no tabs. And, it works well if there are just a couple of tabs with a tab-width of 2. At some point, however, it stops working when there are more than just a couple of tabs on the same line, especially when they are mixed somewhere within the middle of the line. I am using draw_window_cursor to create multiple fake cursors (with the underscore shape) on the entire current line, to create a horizontal ruler spanning the window-body-width. I can see that X and/or HPOS are wrong when tabs are present on the current line because I get superimposed letters and double of the same word slightly off to the left and/or the right of where the word should be. HYPOTHESIS: I would venture to say that what is displayed on screen does _not_ coincide with what IT reports when running move_it_in_display_line_to. IDEAS: Erase the entire current line and redraw it so that what is displayed on screen matches exactly what IT reports when running move_it_in_display_line_to. Any additional ideas or thoughts on how to deal with tabs in this scenario would be greatly appreciated. SNIPPET USED TO CREATE HORIZONTAL LINE: while (true) { flavor = (it.c != '\t') ? Qmc_glyph : Qmc_glyph_tab; if (hscl) { relative_x = it.current_x - (hscl_first_hpos * frame_char_width); hpos = it.hpos - hscl_first_hpos; } else { relative_x = it.current_x - first_x; hpos = it.hpos; } if (header_line_height > 0) vpos = it.vpos + 1; else vpos = it.vpos; bool lpw_reached_p = ((hscl && it.current_x >= hscl_first_x + lnum_pixel_width) || (!hscl && it.current_x >= first_x + lnum_pixel_width)); bool final_loop_p = (ITERATOR_AT_END_OF_LINE_P (&it) || FETCH_BYTE (IT_BYTEPOS (it)) == '\n' || rc == MOVE_POS_MATCH_OR_ZV); bool tab_invisible_p = (it.c == '\t'); bool tab_visible_p = (it.c != '\t' && FETCH_BYTE (IT_BYTEPOS (it)) == '\t'); bool real_fake_cursor_p = (opoint_x == relative_x && opoint_y == it.current_y && opoint_hpos == hpos && opoint_vpos == vpos); if (!real_fake_cursor_p && lpw_reached_p && !tab_invisible_p) draw_fake_cursor (w, relative_x, it.current_y, hpos, vpos, HBAR_CURSOR, cursor_width, foreground, color_vector (w, it.face_id), flavor, IT_CHARPOS (it), &result); if (!real_fake_cursor_p && lpw_reached_p && tab_invisible_p) { int i, count = it.pixel_width / frame_char_width; for (i = 0; i < count; i++) { draw_fake_cursor (w, relative_x, it.current_y, hpos, vpos, HBAR_CURSOR, cursor_width, foreground, color_vector (w, it.face_id), flavor, IT_CHARPOS (it), &result); relative_x = relative_x + frame_char_width; } } if (final_loop_p) break; rc = mc_move_it_in_display_line (w, &it, it.current_x + it.pixel_width); if (rc == MOVE_LINE_CONTINUED) break; relative_x = (hscl) ? it.current_x - (hscl_first_hpos * frame_char_width) : it.current_x - first_x; if (relative_x + frame_char_width >= text_area_width) break; } int mc_move_it_in_display_line (struct window *w, struct it *it, int target_x) { if (IT_CHARPOS (*it) == ZV) return MOVE_POS_MATCH_OR_ZV; struct it saved_it; void *saved_data = bidi_shelve_cache (); enum move_it_result rc = MOVE_X_REACHED; int new_x, prev_x; /* When `auto-hscroll-mode' is set to `current-line` and we are horizontal scrolling a long line that approaches or exceeds an `it.current.x` of approximately 1000, `rc` will erroneously return early with a MOVE_LINE_TRUNCATED indicator without pushing forwards until IT reaches the target_x. As a workaround, ignore MOVE_LINE_TRUNCATED. */ while (it->current_x + it->pixel_width <= target_x && (rc == MOVE_X_REACHED || rc == MOVE_LINE_TRUNCATED || (it->line_wrap == WORD_WRAP && rc == MOVE_POS_MATCH_OR_ZV))) { SAVE_IT (saved_it, *it, saved_data); new_x = it->current_x + it->pixel_width; if (new_x == it->current_x) new_x++; rc = move_it_in_display_line_to (it, ZV, new_x, MOVE_TO_POS | MOVE_TO_X); if (ITERATOR_AT_END_OF_LINE_P (it) || FETCH_BYTE (IT_BYTEPOS (*it)) == '\n' /* #28936: `move_it_in_display_line_to' returns MOVE_POS_MATCH_OR_ZV before reaching ZV when the latter is at the end of the line AND `word-wrap' is non-nil: abcdefg[ZV]. The workaround is to add an extra check using IT_CHARPOS and comparing it to ZV. */ || (rc == MOVE_POS_MATCH_OR_ZV && IT_CHARPOS (*it) == ZV)) break; } /* When word-wrap is on, TO_X may lie past the end of a wrapped line. Then it->current is the character on the next line, so backtrack to the space before the wrap point. */ if (it->line_wrap == WORD_WRAP && rc == MOVE_LINE_CONTINUED) { prev_x = max (it->current_x - 1, 0); RESTORE_IT (it, &saved_it, saved_data); move_it_in_display_line_to (it, -1, prev_x, MOVE_TO_X); } bidi_unshelve_cache (saved_data, true); /* Workaround for bug #28936 -- correct the erroneous MOVE_POS_MATCH_OR_ZV. */ if (it->current_x == target_x && rc == MOVE_POS_MATCH_OR_ZV && IT_CHARPOS (*it) != ZV) rc = MOVE_X_REACHED; return rc; }