From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Keith David Bershatsky Newsgroups: gmane.emacs.bugs Subject: bug#22763: 25.1.50; Feature Request -- A faster method to obtain line number at position. Date: Sun, 21 Feb 2016 18:42:52 -0800 Message-ID: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 (generated by - "") Content-Type: text/plain; charset=US-ASCII X-Trace: ger.gmane.org 1456110216 2739 80.91.229.3 (22 Feb 2016 03:03:36 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Mon, 22 Feb 2016 03:03:36 +0000 (UTC) To: 22763@debbugs.gnu.org Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Mon Feb 22 04:03:24 2016 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1aXgmR-0005MA-Ez for geb-bug-gnu-emacs@m.gmane.org; Mon, 22 Feb 2016 04:03:23 +0100 Original-Received: from localhost ([::1]:46358 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXgmR-0005aB-0s for geb-bug-gnu-emacs@m.gmane.org; Sun, 21 Feb 2016 22:03:23 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:60425) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXgTl-0006r7-B7 for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:44:06 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aXgTi-0007ng-2u for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:44:05 -0500 Original-Received: from debbugs.gnu.org ([208.118.235.43]:39602) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXgTh-0007nb-Ul for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:44:01 -0500 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84) (envelope-from ) id 1aXgTh-0005EB-Nc for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:44:01 -0500 X-Loop: help-debbugs@gnu.org Resent-From: Keith David Bershatsky Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Mon, 22 Feb 2016 02:44:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 22763 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Original-Received: via spool by submit@debbugs.gnu.org id=B.145610898820024 (code B ref -1); Mon, 22 Feb 2016 02:44:01 +0000 Original-Received: (at submit) by debbugs.gnu.org; 22 Feb 2016 02:43:08 +0000 Original-Received: from localhost ([127.0.0.1]:36729 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84) (envelope-from ) id 1aXgSq-0005Cu-9i for submit@debbugs.gnu.org; Sun, 21 Feb 2016 21:43:08 -0500 Original-Received: from eggs.gnu.org ([208.118.235.92]:40996) by debbugs.gnu.org with esmtp (Exim 4.84) (envelope-from ) id 1aXgSo-0005CZ-Lu for submit@debbugs.gnu.org; Sun, 21 Feb 2016 21:43:07 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aXgSi-0007h1-9L for submit@debbugs.gnu.org; Sun, 21 Feb 2016 21:43:01 -0500 Original-Received: from lists.gnu.org ([2001:4830:134:3::11]:51856) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXgSi-0007gw-61 for submit@debbugs.gnu.org; Sun, 21 Feb 2016 21:43:00 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:60198) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXgSg-0004LS-K1 for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:43:00 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aXgSd-0007ge-CH for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:42:58 -0500 Original-Received: from cobb.liquidweb.com ([50.28.13.150]:44488) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aXgSd-0007ga-3Y for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:42:55 -0500 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; bh=5lI0zwL3CR/uVTT4TfqHPsDW2tdrw7DrslV0r9N/Sog=; b=7owZ5omdiLX5dUAg4b+FbbzJy1h1OTR7nb+EVcMJwnEDl0Uqx7Bnv5xyTtQqa+xIrKS8WgGF0MEL3+ahctqL2RTFzdt/uSaf1rTXkwQi2VSQhRcUGjCCctkXhqFAWmB+; Original-Received: from cpe-45-48-239-195.socal.res.rr.com ([45.48.239.195]:53357 helo=server.private.localhost) by cobb.liquidweb.com with esmtp (Exim 4.82) (envelope-from ) id 1aXgSZ-0003Rc-Gg for bug-gnu-emacs@gnu.org; Sun, 21 Feb 2016 21:42:51 -0500 X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - cobb.liquidweb.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-Get-Message-Sender-Via: cobb.liquidweb.com: acl_c_relayhosts_text_entry: lawlist|lawlist.com X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.bugs:113439 Archived-At: A while back, I posed a question on emacs.stackexchange.com for a faster method to obtain `line-number-at-pos`. A user by the name of Constantine came up with `(format-mode-line "%l")`, which is indeed much faster. I think the draft code below may be just a tad faster, with the added feature of the POS argument. http://emacs.stackexchange.com/questions/3821/a-faster-method-to-obtain-line-number-at-pos-in-large-buffers A user named wasamasa posted a comment: "Be aware that this method will give you "??" for lines exceeding line-number-display-limit-width which is set to a value of 200 per default as I found out here." And Stefan posted a comment: "IIRC the result may also be unreliable if there have been modifications in the buffer since the last redisplay." The thread has received 555 hits in the past year, and several have star-ed it and up-voted the question and answer. The following is a draft in C based on the existing function `decode_mode_spec` that lets the user input the POS as an argument without the necessity to use `goto-char`. I'm not sure if it resolves either of the comments above. The draft is not meant to be a patch per se, because I'm not a programmer and am just beginning my tinkering quest into the language of C. I have been using it in my own setup for about a week and I haven't seen any ill effects. It can of course use some TLC by someone more knowledgeable than myself. static const char * internal_line_number_at_position (struct window *w, register int c, int field_width, Lisp_Object *string) { Lisp_Object obj; struct frame *f = XFRAME (WINDOW_FRAME (w)); char *decode_mode_spec_buf = f->decode_mode_spec_buffer; /* We are going to use f->decode_mode_spec_buffer as the buffer to produce strings from numerical values, so limit preposterously large values of FIELD_WIDTH to avoid overrunning the buffer's end. The size of the buffer is enough for FRAME_MESSAGE_BUF_SIZE bytes plus the terminating null. */ int width = min (field_width, FRAME_MESSAGE_BUF_SIZE (f)); struct buffer *b = current_buffer; obj = Qnil; *string = Qnil; switch (c) { case 'l': { ptrdiff_t startpos, startpos_byte, line, linepos, linepos_byte; ptrdiff_t topline, nlines, height; ptrdiff_t junk; /* %c and %l are ignored in `frame-title-format'. */ if (mode_line_target == MODE_LINE_TITLE) return ""; startpos = marker_position (w->start); startpos_byte = marker_byte_position (w->start); height = WINDOW_TOTAL_LINES (w); /* If we decided that this buffer isn't suitable for line numbers, don't forget that too fast. */ if (w->base_line_pos == -1) goto no_value; /* If the buffer is very big, don't waste time. */ if (INTEGERP (Vline_number_display_limit) && BUF_ZV (b) - BUF_BEGV (b) > XINT (Vline_number_display_limit)) { w->base_line_pos = 0; w->base_line_number = 0; goto no_value; } if (w->base_line_number > 0 && w->base_line_pos > 0 && w->base_line_pos <= startpos) { line = w->base_line_number; linepos = w->base_line_pos; linepos_byte = buf_charpos_to_bytepos (b, linepos); } else { line = 1; linepos = BUF_BEGV (b); linepos_byte = BUF_BEGV_BYTE (b); } /* Count lines from base line to window start position. */ nlines = display_count_lines (linepos_byte, startpos_byte, startpos, &junk); topline = nlines + line; /* Determine a new base line, if the old one is too close or too far away, or if we did not have one. "Too close" means it's plausible a scroll-down would go back past it. */ if (startpos == BUF_BEGV (b)) { w->base_line_number = topline; w->base_line_pos = BUF_BEGV (b); } else if (nlines < height + 25 || nlines > height * 3 + 50 || linepos == BUF_BEGV (b)) { ptrdiff_t limit = BUF_BEGV (b); ptrdiff_t limit_byte = BUF_BEGV_BYTE (b); ptrdiff_t position; ptrdiff_t distance = (height * 2 + 30) * line_number_display_limit_width; if (startpos - distance > limit) { limit = startpos - distance; limit_byte = CHAR_TO_BYTE (limit); } nlines = display_count_lines (startpos_byte, limit_byte, - (height * 2 + 30), &position); /* If we couldn't find the lines we wanted within line_number_display_limit_width chars per line, give up on line numbers for this window. */ if (position == limit_byte && limit == startpos - distance) { w->base_line_pos = -1; w->base_line_number = 0; goto no_value; } w->base_line_number = topline - nlines; w->base_line_pos = BYTE_TO_CHAR (position); } /* Now count lines from the start pos to point. */ nlines = display_count_lines (startpos_byte, PT_BYTE, PT, &junk); /* Record that we did display the line number. */ line_number_displayed = true; /* Make the string to show. */ pint2str (decode_mode_spec_buf, width, topline + nlines); return decode_mode_spec_buf; no_value: { char *p = decode_mode_spec_buf; int pad = width - 2; while (pad-- > 0) *p++ = ' '; *p++ = '?'; *p++ = '?'; *p = '\0'; return decode_mode_spec_buf; } } break; } if (STRINGP (obj)) { *string = obj; return SSDATA (obj); } else return ""; } DEFUN ("line-number-at-position", Fline_number_at_position, Sline_number_at_position, 1, 2, 0, doc: /* Return line number at position. */) (Lisp_Object window, Lisp_Object pos) { struct window *w = decode_live_window (window); Lisp_Object buf; struct buffer *b; buf = w->contents; CHECK_BUFFER (buf); b = XBUFFER (buf); struct buffer *old_buffer = NULL; Lisp_Object foo_string; const char *spec; EMACS_INT opoint; EMACS_INT posint; Lisp_Object value; if (b != current_buffer) { old_buffer = current_buffer; set_buffer_internal (b); } if (!NILP (pos)) { opoint = PT; posint = XINT (pos); SET_PT (posint); } spec = internal_line_number_at_position (w, 'l', 0, &foo_string); if (!NILP (pos)) SET_PT (opoint); if (old_buffer) set_buffer_internal (old_buffer); value = build_string (spec); value = Fstring_to_number (value, make_number (10)); return value; } DEFSYM (Qline_number_at_position, "line-number-at-position");