From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp0 ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms11 with LMTPS id +PsgIiWYYl/hVwAA0tVLHw (envelope-from ) for ; Wed, 16 Sep 2020 22:56:37 +0000 Received: from aspmx1.migadu.com ([2001:41d0:2:4a6f::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp0 with LMTPS id YOcIHiWYYl9LAwAA1q6Kng (envelope-from ) for ; Wed, 16 Sep 2020 22:56:37 +0000 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 2988C9403C5 for ; Wed, 16 Sep 2020 22:56:36 +0000 (UTC) Received: from localhost ([::1]:39262 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kIgLr-0001Vg-3f for larch@yhetil.org; Wed, 16 Sep 2020 18:56:35 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:33094) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kIgLH-0001TL-Vy for emacs-orgmode@gnu.org; Wed, 16 Sep 2020 18:56:00 -0400 Received: from coral.adamspiers.org ([2001:ba8:1f1:f27f::2]:38356) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kIgLF-000321-7Z for emacs-orgmode@gnu.org; Wed, 16 Sep 2020 18:55:59 -0400 Received: from localhost (243.103.2.81.in-addr.arpa [81.2.103.243]) by coral.adamspiers.org (Postfix) with ESMTPSA id 2644E2E674; Wed, 16 Sep 2020 23:55:54 +0100 (BST) Date: Wed, 16 Sep 2020 23:55:53 +0100 From: Adam Spiers To: Jeff Filipovits Subject: Re: variable-pitch-mode misaligns org-mode heading tags Message-ID: <20200916225553.hrtxitzt46dzln7i@ionian.linksys.moosehall> X-OS: GNU/Linux References: <87wo1483r5.fsf@protesilaos.com> <87v9gnl4on.fsf@gnu.org> <87mu1znrf1.fsf@ucl.ac.uk> <87eenbj9p2.fsf@gnu.org> <878sdblyz3.fsf@gmail.com> <20200916162143.xyg7j5rg6xalmv2j@ionian.linksys.moosehall> <87mu1pa6jd.fsf@gmail.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="esem3fxwruxdixtb" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <87mu1pa6jd.fsf@gmail.com> Received-SPF: pass client-ip=2001:ba8:1f1:f27f::2; envelope-from=orgmode@adamspiers.org; helo=coral.adamspiers.org X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Protesilaos Stavrou , emacs-orgmode@gnu.org, Eric S Fraga Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: "Emacs-orgmode" X-Scanner: scn0 Authentication-Results: aspmx1.migadu.com; dkim=none; dmarc=fail reason="SPF not aligned (relaxed), No valid DKIM" header.from=adamspiers.org (policy=none); spf=pass (aspmx1.migadu.com: domain of emacs-orgmode-bounces@gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=emacs-orgmode-bounces@gnu.org X-Spam-Score: -0.91 X-TUID: gz/oVN3X0rEt --esem3fxwruxdixtb Content-Type: text/plain; charset=utf-8; format=flowed Content-Disposition: inline Content-Transfer-Encoding: 8bit On Wed, Sep 16, 2020 at 03:03:02PM -0400, Jeff Filipovits wrote: >It looks like (window-text-pixel-size) could be used to calculate the >pixel length of the tags list? Ahah! This indeed did the trick! I have no idea how I missed this handy function previously when I was scouring the manual... >I am having trouble deciphering the >manual (https://www.gnu.org/software/emacs/manual/html_node/elisp/Pixel-Specification.html#Pixel-Specification) >for pixel specification for spaces, though. The right alignment >specification for some reason sends the tags to the next line, as do >most other solutions that I would expect to align the text to the >right side of the window. > >I can experiment more in a couple days, but in the meantime maybe >someone smarter than me give some hints on how to use the pixel >specification properties. I've actually managed it get it working now! See the attached patch. However unfortunately it is not ready to be merged yet. Firstly, it breaks `test-org/tag-align'. Secondly, since this changes the method of alignment from simply using raw spaces to using a single space with a display text property, when the file is saved and reloaded, it just displays a single space and the alignment is lost. Another unfortunate side-effect is that if the file is simultaneously displayed in a graphical window and a text window via the same emacs server (e.g. via emacsclient -t), then one of the two windows will have incorrect alignment. So I think the correct fix will be to keep the original number of spaces, but use a display text property to redisplay those spaces as a single space with the given width. I'm guessing that the display text property will be ignored on text-only (tty) windows, fixing both problems in one go. So I'll take another stab at this soon, if Bastien or some other Org guru can confirm I'm on the right track. >>BTW I tried your code and for some reason it didn't insert any space >>for me, but I didn't look into that yet. > >The way it’s written it would only reduce the gap between the headline >and tags to a space, and it assumes there are multiple spaces there >already. If there’s no space between the two, I don’t think it’ll >insert one. Probably not the best way as it was thrown together to >test the text property fix. I figured out that it wasn't working because my `org-tags-column' is a negative value in order to align flush-right, and your code didn't support that. >I accepted long ago that the solution to using a variable pitch font >for org headings was that the tags would not be aligned to the right >and never looked back, so maybe this is not worth the price of fixing >it if it is messy. And diving down to calculating the pixel width of >text seems like it’s getting pretty messy. Actually I think it ended up fairly clean. Huge thanks to you for giving me the hint I needed! I just adapted your code a bit. I've marked you as a co-author in the commit message. For now your contribution probably still falls into the category of "Tiny changes": https://orgmode.org/worg/org-contribute.html#org9fbb342 However you might want to preemptively sign the copyright assignment papers: https://orgmode.org/worg/org-contribute.html#copyrighted-contributors --esem3fxwruxdixtb Content-Type: text/x-patch; charset=us-ascii Content-Disposition: attachment; filename="0001-org.el-Align-tags-using-specified-space-display-prop.patch" >From 7655c32847d7abd9da7603b1a1a314b7d1b87ba5 Mon Sep 17 00:00:00 2001 From: Adam Spiers Date: Wed, 16 Sep 2020 23:12:04 +0100 Subject: [PATCH] [WIP] org.el: Align tags using specified space display property To: emacs-orgmode@gnu.org Previously tags on heading lines were aligned using spaces, which assumed a fixed width font. However variable pitch fonts are becoming increasingly popular, so ensure there is always a single space in between the heading text and the (colon-delimited) list of tags, and then if necessary use a display text property to specify the exact width required by that space to align it in accordance with the value of `org-tags-column' which the user has chosen: https://www.gnu.org/software/emacs/manual/html_node/elisp/Pixel-Specification.html#Pixel-Specification If the value is positive, align flush-left; if negative, align flush-right; and if zero, just leave a normal width space. See the following links for the discussion threads leading to this patch: - https://lists.gnu.org/archive/html/emacs-orgmode/2020-09/msg00415.html - https://gitlab.com/protesilaos/modus-themes/-/issues/85 Signed-off-by: Adam Spiers Co-authored-by: Jeff Filipovits --- lisp/org.el | 68 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/lisp/org.el b/lisp/org.el index 053635c85..e800eb642 100644 --- a/lisp/org.el +++ b/lisp/org.el @@ -11831,35 +11831,45 @@ (defun org-toggle-tag (tag &optional onoff) res))) (defun org--align-tags-here (to-col) - "Align tags on the current headline to TO-COL. -Assume point is on a headline. Preserve point when aligning -tags." - (when (org-match-line org-tag-line-re) - (let* ((tags-start (match-beginning 1)) - (blank-start (save-excursion - (goto-char tags-start) - (skip-chars-backward " \t") - (point))) - (new (max (if (>= to-col 0) to-col - (- (abs to-col) (string-width (match-string 1)))) - ;; Introduce at least one space after the heading - ;; or the stars. - (save-excursion - (goto-char blank-start) - (1+ (current-column))))) - (current - (save-excursion (goto-char tags-start) (current-column))) - (origin (point-marker)) - (column (current-column)) - (in-blank? (and (> origin blank-start) (<= origin tags-start)))) - (when (/= new current) - (delete-region blank-start tags-start) - (goto-char blank-start) - (let ((indent-tabs-mode nil)) (indent-to new)) - ;; Try to move back to original position. If point was in the - ;; blanks before the tags, ORIGIN marker is of no use because - ;; it now points to BLANK-START. Use COLUMN instead. - (if in-blank? (org-move-to-column column) (goto-char origin)))))) + "Align tags on the current headline to TO-COL. Since TO-COL is +derived from `org-tags-column', a negative value is interpreted as +alignment flush-right, a positive value as flush-left, and 0 means +insert a single space in between the headline and the tags. + +Assume point is on a headline. Preserve point when aligning tags." + (save-excursion + (when (org-match-line org-tag-line-re) + (let* ((tags-start (match-beginning 1)) + (tags-end (match-end 1)) + (tags-pixel-width + (car (window-text-pixel-size (selected-window) + tags-start tags-end))) + (blank-start (progn + (goto-char tags-start) + (skip-chars-backward " \t") + (point)))) + ;; If there is more than one space between the headline and + ;; tags, delete the extra spaces. Might be better to make the + ;; delete region one space smaller rather than inserting a new + ;; space? + (when (> tags-start (1+ blank-start)) + (delete-region blank-start tags-start) + (goto-char blank-start) + (insert " ")) + (if (= to-col 0) + ;; Just leave one normal space width + (remove-text-properties blank-start (1+ blank-start) '(display nil)) + (let ((align-expr + (if (> to-col 0) + ;; Left-align positive values + to-col + ;; Right-align negative values by subtracting the + ;; width of the tags. Conveniently, the pixel + ;; specification allows us to mix units, + ;; subtracting a pixel width from a column number. + `(- ,(- to-col) (,tags-pixel-width))))) + (put-text-property blank-start (1+ blank-start) + 'display `(space . (:align-to ,align-expr))))))))) (defun org-set-tags-command (&optional arg) "Set the tags for the current visible entry. -- 2.28.0 --esem3fxwruxdixtb--