From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2.migadu.com ([2001:41d0:403:58f0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms13.migadu.com with LMTPS id iLqSJTkly2bWAwEAe85BDQ:P1 (envelope-from ) for ; Sun, 25 Aug 2024 12:36:09 +0000 Received: from aspmx1.migadu.com ([2001:41d0:403:58f0::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2.migadu.com with LMTPS id iLqSJTkly2bWAwEAe85BDQ (envelope-from ) for ; Sun, 25 Aug 2024 14:36:09 +0200 X-Envelope-To: larch@yhetil.org Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=HkM6QYma; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1724589369; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=gVStuiqkkRpZdC8GFywJetAaug5wirpyxdsJbc4NP2k=; b=JzUJ06i49J2Fd8kZpLo899ztsMVk+eX/mEBn60KOgmXTQ6I5WW00E+k3dLDNGDH4gEQfpm DtBAGwuB3GR/FoMrVg9So6WYnSKunDmJqddv/WJwnqQq0DJrp2CC4JR8UGghbrKWASKydy 1WF7nQb5klVa/7K0IRvg0GCZN9UWI5rBBBNoaxf3eTGyfW/gd5Rd+BBR9Db2o/dENr2zoe bxqSSSffeNaSsRWFi3VQ5Zcu6IuvG8hslO9I+wad8dCikEoxRuSQxPzJsNMSUVa923UPBg nAsshlKqpRpnNuR0VkyHL+7geNvM6wfBNGL1+5k8EVyFYf9i63NG9n9LSuMmlQ== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1724589369; a=rsa-sha256; cv=none; b=O2T17yBui6oZsk4R9bVZeo3d79y2oZGJ6/OdzTlSKU+oexz0clunRYA+PRunwbMFDrBzm6 qzgsyLd6N0OCarxUZBB8WfAfJ+eFrPJOIxKC/pIM8Hap2PPi5nEdUIa4KFOUUNMJA9AQTC YjT2MkhU4N0JhfaNAVm+0a2ddyt5PARkhfD8UOg1oAafGMe3XU07A7C/MsJnacf3BOp6K9 UzT2sIC8fiI/Nsi73jpKkcXDMuSQrEW1QB5MXYDIh0OLERzerqS1HMBQQBlbfcGxmAFwvs xVPPFluUx8PpobN26GOd8OBuyehx0ewKqH6STU/YlKWakoae11wDiTtfw40ZUw== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=gmail.com header.s=20230601 header.b=HkM6QYma; dmarc=pass (policy=none) header.from=gmail.com; spf=pass (aspmx1.migadu.com: domain of "emacs-orgmode-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="emacs-orgmode-bounces+larch=yhetil.org@gnu.org" 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 38A2F7346E for ; Sun, 25 Aug 2024 14:36:09 +0200 (CEST) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1siCSw-0006Rl-IQ; Sun, 25 Aug 2024 08:35:30 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1siCSu-0006Ra-0z for emacs-orgmode@gnu.org; Sun, 25 Aug 2024 08:35:28 -0400 Received: from mail-lj1-x22e.google.com ([2a00:1450:4864:20::22e]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1siCSs-0005jd-7E for emacs-orgmode@gnu.org; Sun, 25 Aug 2024 08:35:27 -0400 Received: by mail-lj1-x22e.google.com with SMTP id 38308e7fff4ca-2f4f2868621so29974601fa.0 for ; Sun, 25 Aug 2024 05:35:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1724589323; x=1725194123; darn=gnu.org; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:from:to:cc:subject:date:message-id:reply-to; bh=gVStuiqkkRpZdC8GFywJetAaug5wirpyxdsJbc4NP2k=; b=HkM6QYmael8R9414vDh/oUbunjzL/WbV7gUstoC+i+PCKQEu5xzRzrtPCPKYNXqNce V+fdE/6abr5S3gY+JFIM75dFOGHY1YY23EKhDhJxgQAev60xY8AUxgBm6D7tzqS355yT xVDr2CiznfuAuSyEXh5nIIFdRbatcknf+AI6TEgnwMMg+Ib7iJfM5JJCEyP5gjczq5I2 anZjnnUPThBe/pwLYcwhpx6XI0QPNSG/B4956LfRUfyUaxPjlFK+geozUY0Zm+aB/ue3 0TYrCO59LlKItezsY9pHa/KnT8CSZ6qxAzREyxgXV/MQkv9hDa2CFWIKWgYsfcTjuU3/ zZHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724589323; x=1725194123; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=gVStuiqkkRpZdC8GFywJetAaug5wirpyxdsJbc4NP2k=; b=MqqRwO3nbRayxt9pFGzSuFznadRVUeU+C8Oz+P3ijgljhfb60cesiN+zGgfxECf08q oTNaF8m/ojU7tNGfmAzdTZn2oV/PplK4JYLho+iU/WC+WSrajNsH/HkmcSUadoMM6MJl 4HEfer62z4X0UjcEncOotag4ug4kYgmNYBjaKIhrWr/mEW20ElT+8rfhQaiWA2I0LXge wmzsUObT3GrJf5JdO/+hJRX5B3XLw1wB8fPHtrUNAWRnS3wmSL38MTt/KpvfB5QFn1AU SlpAeO+gChSU4SRvmorAfMOcmGnBDklb9/iNXvXuZdAhiazUt1N8Z7LCKG+BiD4deMOz V1Vw== X-Gm-Message-State: AOJu0Yxm5P7oYuLzjj6A8tjPaF0NPUFhm+eygN9dvLj5Ln3B4F78mIff S8Y1zYW1Qq+0kHTXl9EDMVrEdOWrT+eZj1lqXjrParNwaCGm71b+quVlZg== X-Google-Smtp-Source: AGHT+IGfjcL6AFOF3KipD40DxK2kC9mU5Tl8qViYnDci5gA7haGBWaR2O+hpURGSGJRCa6pPZOXtNQ== X-Received: by 2002:a2e:8818:0:b0:2f3:f501:f4e7 with SMTP id 38308e7fff4ca-2f4f5762d90mr43829471fa.16.1724589322186; Sun, 25 Aug 2024 05:35:22 -0700 (PDT) Received: from windows (83.24.136.39.ipv4.supernova.orange.pl. [83.24.136.39]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-2f4047dee52sm9703701fa.60.2024.08.25.05.35.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 25 Aug 2024 05:35:21 -0700 (PDT) From: =?utf-8?Q?S=C5=82awomir?= Grochowski To: Ihor Radchenko Cc: emacs-orgmode@gnu.org Subject: Re: [BUG] colview.el regexp - capture operator when title is empty In-Reply-To: <87zfp6cmbh.fsf@gmail.com> References: <877ccczt83.fsf@gmail.com> <87o75nawdk.fsf@localhost> <87zfp6cmbh.fsf@gmail.com> Date: Sun, 25 Aug 2024 14:35:20 +0200 Message-ID: <875xrobx13.fsf@gmail.com> MIME-Version: 1.0 Content-Type: text/plain Received-SPF: pass client-ip=2a00:1450:4864:20::22e; envelope-from=slawomir.grochowski@gmail.com; helo=mail-lj1-x22e.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-orgmode@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "General discussions about Org-mode." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-orgmode-bounces+larch=yhetil.org@gnu.org Sender: emacs-orgmode-bounces+larch=yhetil.org@gnu.org X-Migadu-Flow: FLOW_IN X-Migadu-Country: US X-Migadu-Spam-Score: -6.79 X-Spam-Score: -6.79 X-Migadu-Queue-Id: 38A2F7346E X-Migadu-Scanner: mx11.migadu.com X-TUID: 4q/7HnF3W1GA I tried to describe the problem better as well as my thought process: The `org-columns-compile-format' function has a bug in regexp. When an empty parentheses `()` is in the 'column format string' - and it always is when user do not provide a column title - then the regexp can't capture the operator which is in curly brackets `{}`. Try yourself with code below: #+begin_src elisp (org-columns-compile-format"%ITEM(){operator}") ; return => (("ITEM" "ITEM" nil nil nil)) ; should be => (("ITEM" "ITEM" nil operator nil)) #+end_src I'm not very skilled in regex, so following Ihor's advice I decided to write the regex in the form of 'rx' which is more readable. Below is the modified function: #+begin_src elisp (defun org-columns-compile-format-rx (fmt) "Turn a column format string FMT into an alist of specifications. The alist has one entry for each column in the format. The elements of that list are: property the property name, as an upper-case string title the title field for the columns, as a string width the column width in characters, can be nil for automatic width operator the summary operator, as a string, or nil printf a printf format for computed values, as a string, or nil This function updates `org-columns-current-fmt-compiled'." (setq org-columns-current-fmt-compiled nil) (let ((start 0)) (while (string-match (rx "%" (optional (group (+ digit))) (group (one-or-more (in alnum "_-"))) (optional "(" (group (one-or-more (not (any ")")))) ")") (optional "{" (group (one-or-more (not (any "}")))) "}") (zero-or-more space)) fmt start) (setq start (match-end 0)) (let* ((width (and (match-end 1) (string-to-number (match-string 1 fmt)))) (prop (match-string-no-properties 2 fmt)) (title (or (match-string-no-properties 3 fmt) prop)) (operator (match-string-no-properties 4 fmt))) (push (if (not operator) (list (upcase prop) title width nil nil) (let (printf) (when (string-match ";" operator) (setq printf (substring operator (match-end 0))) (setq operator (substring operator 0 (match-beginning 0)))) (list (upcase prop) title width operator printf))) org-columns-current-fmt-compiled))) (setq org-columns-current-fmt-compiled (nreverse org-columns-current-fmt-compiled)))) #+end_src I am checking if in this particular case it returns the same result as 'org-columns-compile-format': #+begin_src elisp (org-columns-compile-format-rx "%ITEM(){operator}") ;; => (("ITEM" "ITEM" nil nil nil)) #+end_src #+begin_src elisp (equal (org-columns-compile-format "%ITEM(){operator}") (org-columns-compile-format-rx "%ITEM(){operator}")) ;; => t #+end_src Yes, in this particular case it works the same. To make it easier to capture the error, I only take a piece of code responsible for the regexp: #+begin_src elisp (let ((text "%25ITEM(){operator}") (pattern (rx "%" (optional (group (+ digit))) (group (one-or-more (in alnum "_-"))) (optional "(" (group (one-or-more (not (any ")")))) ")") (optional "{" (group (one-or-more (not (any "}")))) "}") (zero-or-more space)))) (if (string-match pattern text) (mapcar (lambda (i) (match-string i text)) (number-sequence 0 (/ (length (match-data)) 2))))) ;=> ("%25ITEM" "25" "ITEM" nil) #+end_src Through trial and error, I came to a solution that provides correct results. I changed the expression 'one-or-more' to 'zero-or-more' for 'title' and 'operator': #+begin_src elisp (let ((text "%25ITEM(){operator}") (pattern (rx "%" (optional (group (+ digit))) (group (one-or-more (in alnum "_-"))) (optional "(" (group (zero-or-more (not (any ")")))) ")") (optional "{" (group (zero-or-more (not (any "}")))) "}") (zero-or-more space)))) (if (string-match pattern text) (mapcar (lambda (i) (match-string i text)) (number-sequence 0 (/ (length (match-data)) 2))))) ;=> ("%25ITEM(){operator}" "25" "ITEM" "" "operator" nil) #+end_src This fixed a problem but also changed the return value. Now, when we have empty parentheses '()', it will return an empty string instead of null. Therefore, in the function `org-columns-compile-format`, I added calls to `org-string-nw-p` for the variables 'title' and 'operator'. Additionally, I think that adding empty parentheses '()' should be removed when we do not specify a 'column title'. Because it does not provide any value. So I added another call to `org-string-nw-p' in function `org-columns-new'. Patch below: <#part type="text/x-diff" filename="~/.emacs.d/straight/repos/org/0001-lisp-org-colview.el-org-columns-compile-format-regex.patch" disposition=inline> <#/part> Regards, -- Slawomir Grochowski