diff options
| -rw-r--r-- | lisp/apropos.el | 5 | ||||
| -rw-r--r-- | lisp/emacs-lisp/shortdoc.el | 18 | ||||
| -rw-r--r-- | lisp/outline.el | 158 |
3 files changed, 145 insertions, 36 deletions
diff --git a/lisp/apropos.el b/lisp/apropos.el index d9d8f4c372b..a731926f458 100644 --- a/lisp/apropos.el +++ b/lisp/apropos.el | |||
| @@ -492,7 +492,7 @@ Intended as a value for `revert-buffer-function'." | |||
| 492 | \\{apropos-mode-map}" | 492 | \\{apropos-mode-map}" |
| 493 | (make-local-variable 'apropos--current) | 493 | (make-local-variable 'apropos--current) |
| 494 | (setq-local revert-buffer-function #'apropos--revert-buffer) | 494 | (setq-local revert-buffer-function #'apropos--revert-buffer) |
| 495 | (setq-local outline-regexp "^[^ \n]+" | 495 | (setq-local outline-search-function #'outline-search-level |
| 496 | outline-level (lambda () 1) | 496 | outline-level (lambda () 1) |
| 497 | outline-minor-mode-cycle t | 497 | outline-minor-mode-cycle t |
| 498 | outline-minor-mode-highlight t | 498 | outline-minor-mode-highlight t |
| @@ -1188,7 +1188,8 @@ as a heading." | |||
| 1188 | (insert-text-button (symbol-name symbol) | 1188 | (insert-text-button (symbol-name symbol) |
| 1189 | 'type 'apropos-symbol | 1189 | 'type 'apropos-symbol |
| 1190 | 'skip apropos-multi-type | 1190 | 'skip apropos-multi-type |
| 1191 | 'face 'apropos-symbol) | 1191 | 'face 'apropos-symbol |
| 1192 | 'outline-level 1) | ||
| 1192 | (setq button-end (point)) | 1193 | (setq button-end (point)) |
| 1193 | (if (and (eq apropos-sort-by-scores 'verbose) | 1194 | (if (and (eq apropos-sort-by-scores 'verbose) |
| 1194 | (cadr apropos-item)) | 1195 | (cadr apropos-item)) |
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 022bf1e7360..83283247150 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el | |||
| @@ -1374,13 +1374,20 @@ If SAME-WINDOW, don't pop to a new window." | |||
| 1374 | (unless (bobp) | 1374 | (unless (bobp) |
| 1375 | (insert "\n")) | 1375 | (insert "\n")) |
| 1376 | (insert (propertize | 1376 | (insert (propertize |
| 1377 | (concat (substitute-command-keys data) "\n\n") | 1377 | (substitute-command-keys data) |
| 1378 | 'face 'shortdoc-heading | ||
| 1379 | 'shortdoc-section t | ||
| 1380 | 'outline-level 1)) | ||
| 1381 | (insert (propertize | ||
| 1382 | "\n\n" | ||
| 1378 | 'face 'shortdoc-heading | 1383 | 'face 'shortdoc-heading |
| 1379 | 'shortdoc-section t))) | 1384 | 'shortdoc-section t))) |
| 1380 | ;; There may be functions not yet defined in the data. | 1385 | ;; There may be functions not yet defined in the data. |
| 1381 | ((fboundp (car data)) | 1386 | ((fboundp (car data)) |
| 1382 | (when prev | 1387 | (when prev |
| 1383 | (insert (make-separator-line))) | 1388 | (insert (make-separator-line) |
| 1389 | ;; This helps with hidden outlines (bug#53981) | ||
| 1390 | (propertize "\n" 'face '(:height 0)))) | ||
| 1384 | (setq prev t) | 1391 | (setq prev t) |
| 1385 | (shortdoc--display-function data)))) | 1392 | (shortdoc--display-function data)))) |
| 1386 | (cdr (assq group shortdoc--groups)))) | 1393 | (cdr (assq group shortdoc--groups)))) |
| @@ -1397,7 +1404,7 @@ If SAME-WINDOW, don't pop to a new window." | |||
| 1397 | (start-section (point)) | 1404 | (start-section (point)) |
| 1398 | arglist-start) | 1405 | arglist-start) |
| 1399 | ;; Function calling convention. | 1406 | ;; Function calling convention. |
| 1400 | (insert (propertize "(" 'shortdoc-function function)) | 1407 | (insert (propertize "(" 'shortdoc-function function 'outline-level 2)) |
| 1401 | (if (plist-get data :no-manual) | 1408 | (if (plist-get data :no-manual) |
| 1402 | (insert-text-button | 1409 | (insert-text-button |
| 1403 | (symbol-name function) | 1410 | (symbol-name function) |
| @@ -1531,7 +1538,10 @@ Example: | |||
| 1531 | 1538 | ||
| 1532 | (define-derived-mode shortdoc-mode special-mode "shortdoc" | 1539 | (define-derived-mode shortdoc-mode special-mode "shortdoc" |
| 1533 | "Mode for shortdoc." | 1540 | "Mode for shortdoc." |
| 1534 | :interactive nil) | 1541 | :interactive nil |
| 1542 | (setq-local outline-search-function #'outline-search-level | ||
| 1543 | outline-level (lambda () | ||
| 1544 | (get-text-property (point) 'outline-level)))) | ||
| 1535 | 1545 | ||
| 1536 | (defun shortdoc--goto-section (arg sym &optional reverse) | 1546 | (defun shortdoc--goto-section (arg sym &optional reverse) |
| 1537 | (unless (natnump arg) | 1547 | (unless (natnump arg) |
diff --git a/lisp/outline.el b/lisp/outline.el index 92135f8b483..7d9e7e10d08 100644 --- a/lisp/outline.el +++ b/lisp/outline.el | |||
| @@ -59,6 +59,18 @@ The recommended way to set this is with a `Local Variables:' list | |||
| 59 | in the file it applies to.") | 59 | in the file it applies to.") |
| 60 | ;;;###autoload(put 'outline-heading-end-regexp 'safe-local-variable 'stringp) | 60 | ;;;###autoload(put 'outline-heading-end-regexp 'safe-local-variable 'stringp) |
| 61 | 61 | ||
| 62 | (defvar outline-search-function nil | ||
| 63 | "Function to search the next outline heading. | ||
| 64 | The function is called with four optional arguments: BOUND, MOVE, BACKWARD, | ||
| 65 | LOOKING-AT. The first two arguments BOUND and MOVE are almost the same as | ||
| 66 | the BOUND and NOERROR arguments of `re-search-forward', with the difference | ||
| 67 | that MOVE accepts only a boolean, either nil or non-nil. When the argument | ||
| 68 | BACKWARD is non-nil, the search should search backward like | ||
| 69 | `re-search-backward' does. In case of a successful search, the | ||
| 70 | function should return non-nil, move point, and set match-data | ||
| 71 | appropriately. When the argument LOOKING-AT is non-nil, it should | ||
| 72 | imitate the function `looking-at'.") | ||
| 73 | |||
| 62 | (defvar outline-mode-prefix-map | 74 | (defvar outline-mode-prefix-map |
| 63 | (let ((map (make-sparse-keymap))) | 75 | (let ((map (make-sparse-keymap))) |
| 64 | (define-key map "@" 'outline-mark-subtree) | 76 | (define-key map "@" 'outline-mark-subtree) |
| @@ -233,7 +245,8 @@ This option is only in effect when `outline-minor-mode-cycle' is non-nil." | |||
| 233 | (defvar outline-font-lock-keywords | 245 | (defvar outline-font-lock-keywords |
| 234 | '( | 246 | '( |
| 235 | ;; Highlight headings according to the level. | 247 | ;; Highlight headings according to the level. |
| 236 | (eval . (list (concat "^\\(?:" outline-regexp "\\).*") | 248 | (eval . (list (or outline-search-function |
| 249 | (concat "^\\(?:" outline-regexp "\\).*")) | ||
| 237 | 0 '(if outline-minor-mode | 250 | 0 '(if outline-minor-mode |
| 238 | (if outline-minor-mode-highlight | 251 | (if outline-minor-mode-highlight |
| 239 | (list 'face (outline-font-lock-face))) | 252 | (list 'face (outline-font-lock-face))) |
| @@ -366,7 +379,9 @@ data reflects the `outline-regexp'.") | |||
| 366 | "Return one of `outline-font-lock-faces' for current level." | 379 | "Return one of `outline-font-lock-faces' for current level." |
| 367 | (save-excursion | 380 | (save-excursion |
| 368 | (goto-char (match-beginning 0)) | 381 | (goto-char (match-beginning 0)) |
| 369 | (looking-at outline-regexp) | 382 | (if outline-search-function |
| 383 | (funcall outline-search-function nil nil nil t) | ||
| 384 | (looking-at outline-regexp)) | ||
| 370 | (aref outline-font-lock-faces | 385 | (aref outline-font-lock-faces |
| 371 | (% (1- (funcall outline-level)) | 386 | (% (1- (funcall outline-level)) |
| 372 | (length outline-font-lock-faces))))) | 387 | (length outline-font-lock-faces))))) |
| @@ -474,8 +489,11 @@ outline font-lock faces to those of major mode." | |||
| 474 | ;; Fallback to overlays when font-lock is unsupported. | 489 | ;; Fallback to overlays when font-lock is unsupported. |
| 475 | (save-excursion | 490 | (save-excursion |
| 476 | (goto-char (point-min)) | 491 | (goto-char (point-min)) |
| 477 | (let ((regexp (concat "^\\(?:" outline-regexp "\\).*$"))) | 492 | (let ((regexp (unless outline-search-function |
| 478 | (while (re-search-forward regexp nil t) | 493 | (concat "^\\(?:" outline-regexp "\\).*$")))) |
| 494 | (while (if outline-search-function | ||
| 495 | (funcall outline-search-function) | ||
| 496 | (re-search-forward regexp nil t)) | ||
| 479 | (let ((overlay (make-overlay (match-beginning 0) (match-end 0)))) | 497 | (let ((overlay (make-overlay (match-beginning 0) (match-end 0)))) |
| 480 | (overlay-put overlay 'outline-highlight t) | 498 | (overlay-put overlay 'outline-highlight t) |
| 481 | ;; FIXME: Is it possible to override all underlying face attributes? | 499 | ;; FIXME: Is it possible to override all underlying face attributes? |
| @@ -592,26 +610,37 @@ or else the number of characters matched by `outline-regexp'." | |||
| 592 | "Skip forward to just before the next heading line. | 610 | "Skip forward to just before the next heading line. |
| 593 | If there's no following heading line, stop before the newline | 611 | If there's no following heading line, stop before the newline |
| 594 | at the end of the buffer." | 612 | at the end of the buffer." |
| 595 | (if (re-search-forward (concat "\n\\(?:" outline-regexp "\\)") | 613 | (when (if outline-search-function |
| 596 | nil 'move) | 614 | (progn |
| 597 | (goto-char (match-beginning 0))) | 615 | ;; Emulate "\n" to force finding the next preface |
| 598 | (if (and (bolp) (or outline-blank-line (eobp)) (not (bobp))) | 616 | (unless (eobp) (forward-char 1)) |
| 599 | (forward-char -1))) | 617 | (funcall outline-search-function nil t)) |
| 618 | (re-search-forward (concat "\n\\(?:" outline-regexp "\\)") | ||
| 619 | nil 'move)) | ||
| 620 | (goto-char (match-beginning 0)) | ||
| 621 | ;; Compensate "\n" from the beginning of regexp | ||
| 622 | (when (and outline-search-function (not (bobp))) (forward-char -1))) | ||
| 623 | (when (and (bolp) (or outline-blank-line (eobp)) (not (bobp))) | ||
| 624 | (forward-char -1))) | ||
| 600 | 625 | ||
| 601 | (defun outline-next-heading () | 626 | (defun outline-next-heading () |
| 602 | "Move to the next (possibly invisible) heading line." | 627 | "Move to the next (possibly invisible) heading line." |
| 603 | (interactive) | 628 | (interactive) |
| 604 | ;; Make sure we don't match the heading we're at. | 629 | ;; Make sure we don't match the heading we're at. |
| 605 | (if (and (bolp) (not (eobp))) (forward-char 1)) | 630 | (when (and (bolp) (not (eobp))) (forward-char 1)) |
| 606 | (if (re-search-forward (concat "^\\(?:" outline-regexp "\\)") | 631 | (when (if outline-search-function |
| 607 | nil 'move) | 632 | (funcall outline-search-function nil t) |
| 608 | (goto-char (match-beginning 0)))) | 633 | (re-search-forward (concat "^\\(?:" outline-regexp "\\)") |
| 634 | nil 'move)) | ||
| 635 | (goto-char (match-beginning 0)))) | ||
| 609 | 636 | ||
| 610 | (defun outline-previous-heading () | 637 | (defun outline-previous-heading () |
| 611 | "Move to the previous (possibly invisible) heading line." | 638 | "Move to the previous (possibly invisible) heading line." |
| 612 | (interactive) | 639 | (interactive) |
| 613 | (re-search-backward (concat "^\\(?:" outline-regexp "\\)") | 640 | (if outline-search-function |
| 614 | nil 'move)) | 641 | (funcall outline-search-function nil t t) |
| 642 | (re-search-backward (concat "^\\(?:" outline-regexp "\\)") | ||
| 643 | nil 'move))) | ||
| 615 | 644 | ||
| 616 | (defsubst outline-invisible-p (&optional pos) | 645 | (defsubst outline-invisible-p (&optional pos) |
| 617 | "Non-nil if the character after POS has outline invisible property. | 646 | "Non-nil if the character after POS has outline invisible property. |
| @@ -628,8 +657,10 @@ Only visible heading lines are considered, unless INVISIBLE-OK is non-nil." | |||
| 628 | (let (found) | 657 | (let (found) |
| 629 | (save-excursion | 658 | (save-excursion |
| 630 | (while (not found) | 659 | (while (not found) |
| 631 | (or (re-search-backward (concat "^\\(?:" outline-regexp "\\)") | 660 | (or (if outline-search-function |
| 632 | nil t) | 661 | (funcall outline-search-function nil nil t) |
| 662 | (re-search-backward (concat "^\\(?:" outline-regexp "\\)") | ||
| 663 | nil t)) | ||
| 633 | (signal 'outline-before-first-heading nil)) | 664 | (signal 'outline-before-first-heading nil)) |
| 634 | (setq found (and (or invisible-ok (not (outline-invisible-p))) | 665 | (setq found (and (or invisible-ok (not (outline-invisible-p))) |
| 635 | (point))))) | 666 | (point))))) |
| @@ -642,7 +673,9 @@ If INVISIBLE-OK is non-nil, an invisible heading line is ok too." | |||
| 642 | (save-excursion | 673 | (save-excursion |
| 643 | (beginning-of-line) | 674 | (beginning-of-line) |
| 644 | (and (bolp) (or invisible-ok (not (outline-invisible-p))) | 675 | (and (bolp) (or invisible-ok (not (outline-invisible-p))) |
| 645 | (looking-at outline-regexp)))) | 676 | (if outline-search-function |
| 677 | (funcall outline-search-function nil nil nil t) | ||
| 678 | (looking-at outline-regexp))))) | ||
| 646 | 679 | ||
| 647 | (defun outline-insert-heading () | 680 | (defun outline-insert-heading () |
| 648 | "Insert a new heading at same depth at point." | 681 | "Insert a new heading at same depth at point." |
| @@ -754,7 +787,9 @@ nil for WHICH, or do not pass any argument)." | |||
| 754 | (while (and (progn (outline-next-heading) (not (eobp))) | 787 | (while (and (progn (outline-next-heading) (not (eobp))) |
| 755 | (<= (funcall outline-level) level)))) | 788 | (<= (funcall outline-level) level)))) |
| 756 | (unless (eobp) | 789 | (unless (eobp) |
| 757 | (looking-at outline-regexp) | 790 | (if outline-search-function |
| 791 | (funcall outline-search-function nil nil nil t) | ||
| 792 | (looking-at outline-regexp)) | ||
| 758 | (match-string-no-properties 0)))) | 793 | (match-string-no-properties 0)))) |
| 759 | ;; Bummer!! There is no higher-level heading in the buffer. | 794 | ;; Bummer!! There is no higher-level heading in the buffer. |
| 760 | (outline-invent-heading head nil)))) | 795 | (outline-invent-heading head nil)))) |
| @@ -805,7 +840,9 @@ the match data is set appropriately." | |||
| 805 | (save-excursion | 840 | (save-excursion |
| 806 | (setq end (copy-marker end)) | 841 | (setq end (copy-marker end)) |
| 807 | (goto-char beg) | 842 | (goto-char beg) |
| 808 | (when (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t) | 843 | (when (if outline-search-function |
| 844 | (funcall outline-search-function end) | ||
| 845 | (re-search-forward (concat "^\\(?:" outline-regexp "\\)") end t)) | ||
| 809 | (goto-char (match-beginning 0)) | 846 | (goto-char (match-beginning 0)) |
| 810 | (funcall fun) | 847 | (funcall fun) |
| 811 | (while (and (progn | 848 | (while (and (progn |
| @@ -873,21 +910,23 @@ A heading line is one that starts with a `*' (or that | |||
| 873 | (if (< arg 0) | 910 | (if (< arg 0) |
| 874 | (beginning-of-line) | 911 | (beginning-of-line) |
| 875 | (end-of-line)) | 912 | (end-of-line)) |
| 876 | (let (found-heading-p) | 913 | (let ((regexp (unless outline-search-function |
| 914 | (concat "^\\(?:" outline-regexp "\\)"))) | ||
| 915 | found-heading-p) | ||
| 877 | (while (and (not (bobp)) (< arg 0)) | 916 | (while (and (not (bobp)) (< arg 0)) |
| 878 | (while (and (not (bobp)) | 917 | (while (and (not (bobp)) |
| 879 | (setq found-heading-p | 918 | (setq found-heading-p |
| 880 | (re-search-backward | 919 | (if outline-search-function |
| 881 | (concat "^\\(?:" outline-regexp "\\)") | 920 | (funcall outline-search-function nil t t) |
| 882 | nil 'move)) | 921 | (re-search-backward regexp nil 'move))) |
| 883 | (outline-invisible-p))) | 922 | (outline-invisible-p))) |
| 884 | (setq arg (1+ arg))) | 923 | (setq arg (1+ arg))) |
| 885 | (while (and (not (eobp)) (> arg 0)) | 924 | (while (and (not (eobp)) (> arg 0)) |
| 886 | (while (and (not (eobp)) | 925 | (while (and (not (eobp)) |
| 887 | (setq found-heading-p | 926 | (setq found-heading-p |
| 888 | (re-search-forward | 927 | (if outline-search-function |
| 889 | (concat "^\\(?:" outline-regexp "\\)") | 928 | (funcall outline-search-function nil t) |
| 890 | nil 'move)) | 929 | (re-search-forward regexp nil 'move))) |
| 891 | (outline-invisible-p (match-beginning 0)))) | 930 | (outline-invisible-p (match-beginning 0)))) |
| 892 | (setq arg (1- arg))) | 931 | (setq arg (1- arg))) |
| 893 | (if found-heading-p (beginning-of-line)))) | 932 | (if found-heading-p (beginning-of-line)))) |
| @@ -1107,8 +1146,11 @@ of the current heading, or to 1 if the current line is not a heading." | |||
| 1107 | (interactive (list | 1146 | (interactive (list |
| 1108 | (cond | 1147 | (cond |
| 1109 | (current-prefix-arg (prefix-numeric-value current-prefix-arg)) | 1148 | (current-prefix-arg (prefix-numeric-value current-prefix-arg)) |
| 1110 | ((save-excursion (beginning-of-line) | 1149 | ((save-excursion |
| 1111 | (looking-at outline-regexp)) | 1150 | (beginning-of-line) |
| 1151 | (if outline-search-function | ||
| 1152 | (funcall outline-search-function nil nil nil t) | ||
| 1153 | (looking-at outline-regexp))) | ||
| 1112 | (funcall outline-level)) | 1154 | (funcall outline-level)) |
| 1113 | (t 1)))) | 1155 | (t 1)))) |
| 1114 | (if (< levels 1) | 1156 | (if (< levels 1) |
| @@ -1255,7 +1297,9 @@ If INVISIBLE-OK is non-nil, also consider invisible lines." | |||
| 1255 | (setq level (funcall outline-level))) | 1297 | (setq level (funcall outline-level))) |
| 1256 | (setq start-level level)) | 1298 | (setq start-level level)) |
| 1257 | (setq arg (- arg 1)))) | 1299 | (setq arg (- arg 1)))) |
| 1258 | (looking-at outline-regexp)) | 1300 | (if outline-search-function |
| 1301 | (funcall outline-search-function nil nil nil t) | ||
| 1302 | (looking-at outline-regexp))) | ||
| 1259 | 1303 | ||
| 1260 | (defun outline-forward-same-level (arg) | 1304 | (defun outline-forward-same-level (arg) |
| 1261 | "Move forward to the ARG'th subheading at same level as this one. | 1305 | "Move forward to the ARG'th subheading at same level as this one. |
| @@ -1313,6 +1357,60 @@ If there is no such heading, return nil." | |||
| 1313 | (if (< (funcall outline-level) level) | 1357 | (if (< (funcall outline-level) level) |
| 1314 | nil | 1358 | nil |
| 1315 | (point))))) | 1359 | (point))))) |
| 1360 | |||
| 1361 | |||
| 1362 | ;;; Search text-property for outline headings | ||
| 1363 | |||
| 1364 | ;;;###autoload | ||
| 1365 | (defun outline-search-level (&optional bound move backward looking-at) | ||
| 1366 | "Search for the next text property `outline-level'. | ||
| 1367 | The arguments are the same as in `outline-search-text-property', | ||
| 1368 | except the hard-coded property name `outline-level'. | ||
| 1369 | This function is intended to be used in `outline-search-function'." | ||
| 1370 | (outline-search-text-property 'outline-level nil bound move backward looking-at)) | ||
| 1371 | |||
| 1372 | (autoload 'text-property-search-forward "text-property-search") | ||
| 1373 | (autoload 'text-property-search-backward "text-property-search") | ||
| 1374 | |||
| 1375 | (defun outline-search-text-property (property &optional value bound move backward looking-at) | ||
| 1376 | "Search for the next text property PROPERTY with VALUE. | ||
| 1377 | The rest of arguments are described in `outline-search-function'." | ||
| 1378 | (if looking-at | ||
| 1379 | (when (if value (eq (get-text-property (point) property) value) | ||
| 1380 | (get-text-property (point) property)) | ||
| 1381 | (set-match-data (list (pos-bol) (pos-eol))) | ||
| 1382 | t) | ||
| 1383 | ;; Go to the end when in the middle of heading | ||
| 1384 | (when (and (not backward) | ||
| 1385 | (if value (eq (get-text-property (point) property) value) | ||
| 1386 | (get-text-property (point) property)) | ||
| 1387 | (not (or (bobp) | ||
| 1388 | (not (if value | ||
| 1389 | (eq (get-text-property (1- (point)) property) value) | ||
| 1390 | (get-text-property (1- (point)) property)))))) | ||
| 1391 | (goto-char (1+ (pos-eol)))) | ||
| 1392 | (let ((prop-match (if backward | ||
| 1393 | (text-property-search-backward property value (and value t)) | ||
| 1394 | (text-property-search-forward property value (and value t))))) | ||
| 1395 | (if prop-match | ||
| 1396 | (let ((beg (prop-match-beginning prop-match)) | ||
| 1397 | (end (prop-match-end prop-match))) | ||
| 1398 | (if (or (null bound) (if backward (>= beg bound) (<= end bound))) | ||
| 1399 | (cond (backward | ||
| 1400 | (goto-char beg) | ||
| 1401 | (goto-char (pos-bol)) | ||
| 1402 | (set-match-data (list (point) end)) | ||
| 1403 | t) | ||
| 1404 | (t | ||
| 1405 | (goto-char end) | ||
| 1406 | (goto-char (if (bolp) (1- (point)) (pos-eol))) | ||
| 1407 | (set-match-data (list beg (point))) | ||
| 1408 | t)) | ||
| 1409 | (when move (goto-char bound)) | ||
| 1410 | nil)) | ||
| 1411 | (when move (goto-char (or bound (if backward (point-min) (point-max))))) | ||
| 1412 | nil)))) | ||
| 1413 | |||
| 1316 | 1414 | ||
| 1317 | (defun outline-headers-as-kill (beg end) | 1415 | (defun outline-headers-as-kill (beg end) |
| 1318 | "Save the visible outline headers between BEG and END to the kill ring. | 1416 | "Save the visible outline headers between BEG and END to the kill ring. |