diff --git a/lisp/org.el b/lisp/org.el index 3e8c7142e..f6828f706 100755 --- a/lisp/org.el +++ b/lisp/org.el @@ -16195,6 +16195,26 @@ in the current file." (unless (equal (org-entry-get nil property) value) (org-entry-put nil property value)))) +(defun org-find-property (property &optional value) + "Find first entry in buffer that sets PROPERTY. + +When optional argument VALUE is non-nil, only consider an entry +if it contains PROPERTY set to this value. If PROPERTY should be +explicitly set to nil, use string \"nil\" for VALUE. + +Return position where the entry begins, or nil if there is no +such entry. If narrowing is in effect, only search the visible +part of the buffer." + (save-excursion + (goto-char (point-min)) + (let ((case-fold-search t) + (re (org-re-property property nil (not value)))) + (catch 'exit + (while (re-search-forward re nil t) + (when (if value (equal value (org-entry-get (point) property nil t)) + (org-entry-get (point) property nil t)) + (throw 'exit (progn (org-back-to-heading t) (point))))))))) + (defun org-delete-property (property) "In the current entry, delete PROPERTY." (interactive diff --git a/testing/lisp/test-org.el b/testing/lisp/test-org.el index 3d4f050a9..f936e3db3 100644 --- a/testing/lisp/test-org.el +++ b/testing/lisp/test-org.el @@ -2642,6 +2642,54 @@ Text. (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:A+: 2\n:END:" (org-property-values "A"))))) +(ert-deftest test-org/find-property () + "Test `org-find-property' specifications." + ;; Regular test. + (should + (= 1 + (org-test-with-temp-text "* H\n:PROPERTIES:\n:PROP: value\n:END:" + (org-find-property "prop")))) + ;; Ignore false positives. + (should + (= 27 + (org-test-with-temp-text + "* H1\n:DRAWER:\n:A: 1\n:END:\n* H2\n:PROPERTIES:\n:A: 1\n:END:" + (org-find-property "A")))) + ;; Return first entry found in buffer. + (should + (= 1 + (org-test-with-temp-text + "* H1\n:PROPERTIES:\n:A: 1\n:END:\n* H2\n:PROPERTIES:\n:A: 1\n:END:" + (org-find-property "A")))) + ;; Only search visible part of the buffer. + (should + (= 31 + (org-test-with-temp-text + "* H1\n:PROPERTIES:\n:A: 1\n:END:\n* H2\n:PROPERTIES:\n:A: 1\n:END:" + (org-narrow-to-subtree) + (org-find-property "A")))) + ;; With optional argument, only find entries with a specific value. + (should-not + (org-test-with-temp-text "* H\n:PROPERTIES:\n:A: 1\n:END:" + (org-find-property "A" "2"))) + (should + (= 31 + (org-test-with-temp-text + "* H1\n:PROPERTIES:\n:A: 1\n:END:\n* H2\n:PROPERTIES:\n:A: 2\n:END:" + (org-find-property "A" "2")))) + ;; Use "nil" for explicit nil values. + (should + (= 31 + (org-test-with-temp-text + "* H1\n:PROPERTIES:\n:A: 1\n:END:\n* H2\n:PROPERTIES:\n:A: nil\n:END:" + (org-find-property "A" "nil")))) + ;; Optional argument is matched against real value, including PROP+ + ;; syntax. + (should + (= 1 + (org-test-with-temp-text "* H1\n:PROPERTIES:\n:A: 1\n:A+: 2\n:END:" + (org-find-property "A" "1 2"))))) + (ert-deftest test-org/entry-delete () "Test `org-entry-delete' specifications." ;; Regular test.