word boundary in Emacs font lock keywords - emacs

The following code fails to highlight 23's in 23-23 if pasted and evaluated in the scratch buffer, but not if done in a text buffer.
;; Example 1
'(1234 23 23-23 end)
(progn
(font-lock-add-keywords nil
`(("\\b23\\b"
(0 'success))
"end"))
(font-lock-fontify-buffer))
Why does it fail when M-x isearch-forward-regexp RET \b23\b still matches 23's in 23-23?
Even if I change to the following code, only the first 23 in 23-23 gets highlighted.
;;; Example 2
'(1234 23 23-23 end)
(progn
(font-lock-add-keywords nil
`((,(rx (or word-boundary
"-")
(group "23")
(or word-boundary
"-"))
(1 'success))
"end"))
(font-lock-fontify-buffer))
Side note: "end" is there so that I can detect if the highlighter for 23 is ill formed. If it is ill formed or signals errors silently, end won't get highlighted.
;;; Example 3 (with xy instead of 23. also passing t and 'append.)
;;; if evaluated in the scratch buffer, it doesn't highlight xy in xy-xy
'(wxyz xy xy-xy end)
(progn
(font-lock-add-keywords nil
`(("\\bxy\\b"
(0 'success t))
"end")
'append)
(font-lock-fontify-buffer))

The fact that it does not in buffer *scratch* suggests that it is a problem with the current mode. There are two main possibilities:
What #wvcvw suggested: check what the syntax class of chars 2 and 3 is.
The font-lock-keywords already defined for the mode interact with your code -- e.g., they override it. Try adding 'APPEND as a third arg to font-lock-add-keywords. Try adding t as a HIGHLIGHT expression to your highlighter sexp (see the doc). That should let your highlighting override any that might already be there otherwise.
BTW, you say it does not work in a "text buffer", but what does that mean? From emacs -Q, evaluating your code in a buffer in text-mode shows that it does work. Investigate what your "text buffer" mode is and try the suggestions above (both bullets if necessary, but try the second one first).

Related

org-capture and time clocking misbehaving

I am sure some of you may have gathered (from my recent barrage of questions) that I am setting up org-mode on emacs and walking through Brent Hansen's impressive org set up. He is a clocking fanatic, and I like a lot of the stuff he does to track time spent on projects.
I (think) haven't messed up in setting things up, but whenever I try to clock in our out of a task I get an error with a lot of gibberish (reported below). I've tried to see if there are some patterns to how the error emerges but am unable to discover them. They seem to happen pretty often but not all the time which makes debugging them an even bigger pain.
Typically, when I clock out of a task (but sometime when I clock in too), I get a message like this
save-excursion: Wrong number of arguments: #[(drawer pos) "rÂ!
Ã!pq~bÄÅ ÆQÇ\"$ÈÉ!+" [pos drawer markerp marker-buffer org-in-regexp "^[ ]*:" ":[ ]*
[ ]*:END:[ ]*
?" 2 replace-match ""] 4 ("/Users/krishnan/.emacs.d/elpa/org-20140210/org.elc" . 450779)], 1
[a-z..]:Set [SPC]:clear [2 times]
As always, I am happy to follow up to questions that might help discover the source of the error. I have not been able to discern if it standard practice to include my entire .emacs etc, but am happy to post follow up information as is needed.
Many thanks in advance!
edit 1: Following #iqbal-ansari , I did M-x toggle-debug-on-error which produces the following gunk:
Debugger entered--Lisp error: (wrong-number-of-arguments #[(drawer pos) "r\302!\203
\303!\202pq\210\212\214~\210b\210\304\305 \306Q\307\"\205$\310\311!+\207" [pos drawer markerp marker-buffer org-in-regexp "^[ ]*:" ":[ ]*
[ ]*:END:[ ]*
?" 2 replace-match ""] 4 ("/Users/krishnan/.emacs.d/elpa/org-20140210/org.elc" . 450779)] 1)
org-remove-empty-drawer-at(307)
(save-excursion (beginning-of-line 0) (org-remove-empty-drawer-at (point)))
bh/remove-empty-drawer-on-clock-out()
#[(f) " \207" [f] 1](bh/remove-empty-drawer-on-clock-out)
mapc(#[(f) " \207" [f] 1] (org-clock-remove-empty-clock-drawer bh/remove-empty-drawer-on-clock-out bh/clock-out-maybe))
byte-code("\306 \204\307\310\" \311 \210\203\312\313\314\"\210\202\315\316!\210\f\2035\317\320r\321
!q\210#)\322\314\323%\2027A\324B!\322\211\211\211\211\211CDEFGHIAIJ\212\325 q\210\214~\210
b\210\326\327!\210\330\331KP!\203~\332\327!L\232\203~\332\333!H\202\216\203\212\312\313\322\"\210\202\216\334\335!\210\336\225b\210`\337 |\210\340c\210\341M\206\242I\342\343#G\344\345\346\347G!\"!\344\345\346\347H!\"!ZF\350F\351\245!EFE\351_ZF\350F\352\245!DF\211\352_ZF\353\354\355ED#\261\210N\205\364ED\\\336U\211C\203\326\327!\210`\337 |\210\330\356!\203d`TV\203\357\327!\210
\322\211\223\210O\322\211\223\210P\2033\360\361\322\211\211\211\362\363\314!\364Q&\210Q\203#\365Q!\210\322QR\203M\365R!\210\322R\307\310\" A\203\234\212\366\314!\210\314\322ST\367A!\203\205\330U!\210A\332\333!!\211V\203\201\370V!\210)\202\233A\203\233\330W\331A\371R!\204\233\370A!\210+\311 \210\372\373\374E\352_D\\!\375QGC\203\267\376\202\270\377#\210XEYZ\232\203\335[\201]=\203\335S\203\335\307\201^E\"E\201_\201`E\"\210)\306 ?\205\362\322\211\\.\n\207" [global-mode-string org-frame-title-format-backup frame-title-format fail-quietly switch-to-state org-clock-marker org-clocking-p delq org-mode-line-string force-mode-line-update throw exit t user-error "No active clock" completing-read "Switch to state: " marker-buffer nil "DONE" org-current-time org-clocking-buffer beginning-of-line 1 looking-at "[ ]*" match-string 2 error "Clock start time is gone" 0 point-at-eol "--" org-insert-time-stamp with-hm inactive org-float-time apply encode-time org-parse-time-string floor 3600 60 " => " format "%2d:%02d" "\n" delete-char org-add-log-setup clock-out ...] 10)
org-clock-out()
org-clock-out-if-current()
run-hooks(org-after-todo-state-change-hook)
byte-code("\306\307!\210\310\311P!\203\312 \210\307\310\n!\203\313\225Sb\210\310\314\315Q!\204)\310\316!\210\304 \317 \304 #\320\216\321\322\323\307\211$*ABBCCDDE\313\232\203X\322E\324\202ZFF\325\326!G\313\224H\327G!I\330IJ\"\211KA#L\331K8M\332K8NG\206\212\333O\307PGQ\235\211RAST\203\303E\334\232\203\255U\335=\204\276E\204\303U\203\303U\335=\204\303\336 \202E\337\232\203\341U\203\324T\204\341\340\341\342\343Q\"\322\307$\202E\344=\203\376G\203\370S\205S#\202Q#\202E\345=\203/RQ\232?\205G\203\"\346QGSG\347#Q8\202Q#\350#!#)\202U\307=\203DE\351\232\203D\322\211E\206E\203\310E\333\232\203T\322\202E\352=\203_\322\202E\353=\203qM\206V#\202E\354=\203\210IW\235A#\206W#\202E\355=\203\246\356W!WIW\235A#\206\242W#)\202EQ\235#\206E;\203\275\357\360E\"\202\361E!SQ8\202R\204\330I\206Q#\202GN\232\203\344\322\202S\204\355\322\202L\362>\203XY=\203S#\202SG\313V\205M\206V#\202S#Z\363\364ZO#\206&Z\211Z\2034\365Z\365Q\2025\365[\366\367\370G\371Z\372
\257\\\322\211]^=\203\230GV\235?_\212\304 #\373\216\212\214~\210\374\375\\\"-\204\230\376\377!\203\201\357\201jGZ`$\210\202\230\201k\201jGZ`$\210\201l\201m\322\"\210\201n\f!\210\201o[\307\211#\210\201pH!\204\276\201k\201q\201r[!\"\210I\204\342\327Z!I\330IJ\"\211KA#L\331K8M\332K8NE\201s>\203\201k\201t\346aG\201u\330Za\"a>G#aG\201v\201w\330Za\"\365#$\210ZV\235?_ZV\235\205,GV\235?^A\203:\201xA!\210D\204DB\203\357F\307=\204\357E\201y>\204\357\330ZD\"A#\206g\347\330GD\"8\211]\324=\203{F\324=\203{\201z]Z\204\205b\203\232Z\203\244Zc\235\203\244Gc\235\204\244\201{\322\211\201|#\210^\203\324B\203\324\201{\201|\201} \"\210]\204\324B\324=\203\324\201~\353ZG\201\324%\210Z\203\357]\203\357\201~\201\200ZG\201]%\210\201\201Z!\210d\203e\204\201\202\322\307\"\210f\203\201\203 \210\201\204\201\205!\210E\203,ZV\235\204,\327Z!I\201\206\317 \201\207 \201\210I$\210^\203a\201\211\201g!\203Z\304 #\201\212\216\201\213 g*\201\214Z!\210\201\215 \203\235n\204\235\212\201\216\326!\210\310h!)\203\235`\347\211\225\206\204\326\225\\W\203\235\347\225\206\220\326\225b\210\310\365!\203\235\201\217 \210i\203\256\212\201\220\201i\\\"\210) \205\264\312 .\207" [org-comment-string commentp org-outline-regexp org-todo-regexp match-data startpos org-back-to-heading t looking-at "^\\*+ " org-toggle-comment 0 " +" "\\( +\\|[ ]*$\\)" "\\(?: *\\|[ ]*$\\)" point-at-bol ((byte-code "\301\302\"\207" [save-match-data-internal set-match-data evaporate] 3)) org-entry-get nil "LOGGING" note match-string 1 org-get-todo-sequence-head assoc 3 4 "" (4) prefix org-fast-todo-selection (4) org-icompleting-read "State: " mapcar list right left - 2 last (4) none done nextset previousset reverse user-error "State `%s' not valid in this file" prefix-numeric-value ...] 10)
org-todo(nil)
call-interactively(org-todo)
org-agenda-todo(nil)
call-interactively(org-agenda-todo nil nil)
The issue is caused by the line (org-remove-empty-drawer-at (point)) in the function bh/remove-empty-drawer-on-clock-out. If you read the documentation of the function org-remove-empty-drawer-at (do C-hforg-remove-empty-drawer-atRET, it says that the function accepts two arguments drawer and point while the function bh/remove-empty-drawer-on-clock-out passes only one argument (point). This causes the error you reported. It seems the code was written for an older version of org-mode.
This is a temporary solution, remove the line
(add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append)
from your init file (and restart emacs). This will get rid of the error.
UPDATE
I got (I think) a permanent solution to the problem. The first argument to the function org-remove-empty-drawer-at is the name of the drawer to remove, from Brent Hansen's setup it seems he wants to remove empty 'LOGBOOK' drawers, in this case the modify the function bh/remove-empty-drawer-on-clock-out as follows
(defun bh/remove-empty-drawer-on-clock-out ()
(interactive)
(save-excursion
(beginning-of-line 0)
(org-remove-empty-drawer-at "LOGBOOK" (point))))
Note that the argument "LOGBOOK" has been added to the call to function org-remove-empty-drawer-at. Also now you do not need to remove the line
(add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append)
from your init file.
Faced this issue after updating to Org-mode version 8.3.3 (8.3.3-51-g30bcff-elpa). Before the update, it was already working on my Emacs 24.4 (Linux OS, built from sources), thanks to the answer from user2053036.
Looks like the extra parameter is no longer needed in this version. My working init file now looks like:
(defun bh/remove-empty-drawer-on-clock-out ()
(interactive)
(save-excursion
(beginning-of-line 0)
(org-remove-empty-drawer-at (point))))
(add-hook 'org-clock-out-hook 'bh/remove-empty-drawer-on-clock-out 'append)

Persistent colors in an emacs text buffer

After highlighting text in an emacs buffer using a regexp (1), it's easy enough to write the setting in the file (2), but I am missing a third step for persistence.
(1) Set
Doing M-s h r (highlight-regexp) and, say, \{.*\} followed by italic will highlight everything between curly braces in that style.
(2) Write
Subsequently calling C-x w b (hi-lock-write-interactive-patterns) will write the string
# Hi-lock: (("\\{.*\\}" (0 (quote italic) t)))
in the buffer, after asking for the comment string (I used #).
(3) Re-use
What is the third step needed to make this highlighting persistent, i.e., to make it survive saving/loading the file from disk?
If you C-h f hi-lock-write-interactive-pattern, you'll see in the help buffer a link to hi-lock.el. Often Lisp libraries have some usage information at the beginning of the file and it's handy to check.
In this case, it tells how to make it persistent:
;; To enable the use of patterns found in files (presumably placed
;; there by hi-lock) include the following in your init file:
;;
;; (setq hi-lock-file-patterns-policy 'ask)
;;
;; If you get tired of being asked each time a file is loaded replace
;; `ask' with a function that returns t if patterns should be read.
How about the possibility of creating a function that has a hook relating to the file you want to load -- e.g., a text-mode-hook or perhaps a specific file hook (if something like that exists)?
;; M-x ae-hi-lock-features
(global-hi-lock-mode 1)
(defface af-bold-yellow-box '((t (:background "black"
:foreground "yellow"
:underline "red"
:height 200
:bold t
))) "yellow-box-face")
(defun z-hi-lock-quizzes ()
;; this next line is necessary to correct sloppy hi-locking
(if (not hi-lock-mode)
(progn (hi-lock-mode -1)
(hi-lock-mode 1))
(hi-lock-mode)
(hi-lock-mode))
(highlight-regexp "^%-\\*-mode:LaTeX.*$" (quote hi-conceal-content));
(highlight-regexp "^%-#-(.+$" (quote hi-lock-page-break));
(highlight-regexp "food" (quote af-bold-yellow-box));
)
(defun ae-hi-lock-features ()
(interactive)
(z-hi-lock-quizzes)
;; ... call other functions ...
)
(add-hook 'text-mode-hook 'ae-hi-lock-features)
https://www.gnu.org/software/emacs/manual/html_node/emacs/Highlight-Interactively.html
C-x w i
Extract regexp/face pairs from comments in the current buffer (hi-lock-find-patterns).
Thus, you can enter patterns interactively
with highlight-regexp, store them into the file with
hi-lock-write-interactive-patterns, edit them (perhaps including
different faces for different parenthesized parts of the match), and
finally use this command (hi-lock-find-patterns) to have Hi Lock
highlight the edited patterns.

yasnippets with % ending the line after $0 acts strange when used with AUCTeX

Yasnippet snippets that has a percent sign, %, ending a line with the last point of the snippet, $0, before the percent sign acts strange in that the cursor gets placed after the percent sign and not before it. I wonder how I can avoid this strange behavior.
Consider the following snippet:
# -*- mode: snippet -*-
# name: test snippet
# key: ts
# --
{
$0%
}
I take it that as it's activated it should insert three lines where the first contains {, the last line } and the second line % and place the cursor before % on the second line as in the following example:
{
[cursor]%
}
But what happens is the following:
{
% [cursor]
}
How can I make it so that the snippet behaves as I think it should?
My guess is that this is due to something in AUCTeX because it happens with AUCTeX activated but not in the major mode Lisp Interaction.
It works right with my configuration, but I suspect it has to do with auto indenting (mine is heavily customized so that may be the difference). Do you still see the problem if you add
# expand-env: ((yas/indent-line 'fixed))
or
# expand-env: ((yas/indent-line t))
to the snippet's header? You can also try adding $> to the line(s) that you want indented to see if that makes a difference (if it does that would narrow things down a lot). There is a note in the yasnippet code about some problems with markers changing places, but that looks like it was fixed a few years ago.
You should also check that indent-line-function has the proper value namely LaTeX-indent-line.
You could add some sit-for's to the definition of yas/indent-according-to-mode to see where point is at different stages. For example put the following in a scratch buffer, position your cursor after the end of it and type C-x C-e. Then insert your snippet as usual and it will pause for 1 second every where in the code you see a (sit-for 1). So if the cursor starts out in the wrong place, then you know the problem is before indentation, etc. You will have to watch it for every line that is indented, so you may wish to turn off indentation except for the problematic line via $>. Adding or removing sit-for's will allow you to narrow it down.
(defun yas/indent-according-to-mode (snippet-markers)
"Indent current line according to mode, preserving
SNIPPET-MARKERS."
(sit-for 1)
(goto-char (yas/real-line-beginning))
(sit-for 1)
(let ((trouble-markers (remove-if-not #'(lambda (marker)
(= marker (point)))
snippet-markers)))
(save-restriction
(widen)
(sit-for 1)
(condition-case err
(indent-according-to-mode)
(error (message "[yas] warning: yas/indent-according-to-mode habing problems running %s" indent-line-function)
nil)))
(sit-for 1)
(mapc #'(lambda (marker)
(set-marker marker (point)))
trouble-markers)))

How to use vimpulse together with autopair.el

It seems that when vimpulse is running, autopair only works partially in the sense that pressing backspace in empty bracket pairs will no longer remove the closing bracket but only the opening one (which means backspace functions as normal backspace now). An example:
(When Vimpulse and autopair are both active, and current mode is INSERT mode, "|" denotes the cursor)
begin: (|)
Now press "backspace"
expected result: | (both opening and closing brackets are removed)
actual result: |) (only the opening bracket is removed)
I know this has to do with the fact that vimpulse (or rather viper-mode) remapped [backspace] from delete-backward-char to something else (viper-delete-backward-char I think). But I could not find a fix to it.
Could anybody find a solution to this? (so that backspace key will remove both opening and closing bracket when the bracket is empty and cursor is in between).
Thanks!
i think something like this in your init file would work:
(add-hook 'autopair-mode-hook
'(lambda ()
(define-key autopair-emulation-alist [remap viper-delete-backward-char] 'autopair-backspace)))
I will answer this question myself.
I could not figure out an "orthodoxy" way to solve the problem and I came up with a hack.
The function that is bound to in viper insert mode (viper-del-backward-char-in-insert) is adviced to check whether cursor is currently in a matched pair, if so, the character after the cursor is deleted before the actual function is called. This also takes into account possible problem caused by prefix character (backslash).
Just copy the code below into your .emacs file after viper-mode or vimpulse is loaded.
(defun not-escaped (escape-char)
"Character immediately before cursor is not prefixed by escape-char"
(let ((count 0))
(save-excursion
(if (char-before)
(backward-char))
(while (and (char-before)
(= (char-before) escape-char))
(setq count (+ count 1))
(backward-char))
(if (= 0
(% count 2))
t
nil))))
(defun in-matched-empty-pair (pair-list)
"tell if cursor is in an empty pair in pair-list"
(let ((next-char (char-after))
(prev-char (char-before))
(matched nil)
(pair)
(pair-left)
(pair-right))
(if (and next-char
prev-char)
(while (and (setq pair
(pop pair-list))
(not matched))
(setq pair-left (pop pair)
pair-right (pop pair))
(if (= next-char pair-right)
(if (and
(= prev-char pair-left)
(not-escaped ?\\))
(setq matched t)))))
(if matched
t
nil)))
(defvar viper-workaround-pairs
'(
(?\" ?\")
(?\' ?\')
(?\` ?\`)
(?\( ?\))
(?\[ ?\])
(?\{ ?\})
))
;; Workaround for integration problem with autopair
(defadvice viper-del-backward-char-in-insert (before viper-auto-delete-pair-backward())
(if (in-matched-empty-pair viper-workaround-pairs)
(delete-char 1)))
;; Activate advice
(ad-activate 'viper-del-backward-char-in-insert)
This is a hack but it is probably the best I could do now.
Here is my updated solution. Put the following in your .emacs file after the code that loads autopair and vimpulse:
(add-to-ordered-list 'emulation-mode-map-alists (car (last emulation-mode-map-alists)) 400)
It moves autopair's keymap in front of viper's one, giving it higher priority.
Maybe you have to adept the order number (here 400), depending on whether you are using additional emulation-modes.
The result can be checked with C-x v emulation-mode-map-alists. In my case:
(viper--intercept-key-maps cua--keymap-alist autopair-emulation-alist viper--key-maps)
Now, autopair-emulation-alist should be listed before viper--key-maps.
baumichel found the trick. I just add a quick snippet to help :
First, as autopair-mode simply appends autopair-emulation-alist, evaluate:
(defadvice viper-change-state-to-insert (after autopair nil activate)
(add-to-ordered-list 'emulation-mode-map-alists 'autopair-emulation-alist 300))
Then, remember that vimpulse-normalize-minor-mode-map-alist removes all viper keymaps in front of the alist, so execute:
(defadvice vimpulse-normalize-minor-mode-map-alist (after order-viper--key-maps nil activate)
(add-to-ordered-list 'emulation-mode-map-alists 'viper--key-maps 500))
That works for me! I evaluate these snippets in an embedded eval-after-load for both vimpulse and autopair.
My idea is that Emacs dev should rethink the emulation-mode-map-alists and use a property list indexing priority order like this: ((:name viper--key-maps :after (cua--keymap-alist autopair-emulation-alist)) (:name viper--intercept-key-maps :before (cua--keymap-alist autopair-emulation-alist))). Old packages like viper, CUA and so on should be better maintained because our setup becomes ugly after years with Emacs.

(re)number numbered lists in emacs (muse)

suppose I have a text list in emacs like this:
a
b
c
...
d
Is there a way to assign numbers to those items in Emacs, by selecting the region? End results should look like:
1. a
2. b
3. c
j. ...
n. d
Thanks.
The way I do this, which may not be optimal, is to use regex search and replace. This, of course, requires that you be able to define a regex to match the start of the lines you want numbers on. Taking your example, I'd use a search regex like this:
\([a-z]\)
note the capturing brackets, we'll need that first letter soon. And a replace regex like this:
\#. \1
where:
\# is a special form which is replaced, by Emacs, by the right number (though see the warning below);
. writes a stop; and
\1 writes a space and the captured group.
WARNING: Emacs will number your items 0, 1, 2, .... Until someone posts to tell us how to start at 1, I always insert a dummy 0th element before the edit, then delete it.
You can use the Emacs Keyboard Macro Counter.
Put the cursor one line ABOVE your list.
Start a macro: F3
Insert the counter value: C-x C-k C-i. A 0 will appear
Insert the DOT and a space: .
Move the cursor to the next line
Stop the macro: F4
Select your list
M-x apply-macro-to-region-lines
You can delete the 0 you added on the top and enjoy :)
NOTE: This will create a numbered list. It will not use letters.
A much simpler way is to use the CUA library's advanced rectangle editing commands. CUA is included in Emacs (at least 23.1, I think it's in earlier versions as well), so there isn't any new code to get.
You can use cua-set-rectangle-mark (bound to C-Return by default) to start a rectangle, and then use cua-sequence-rectangle to insert increasing values. It also gives you control over the format and starting value, so there is a lot of flexibility.
As an aside, CUA is primarily designed to make Emacs operate more like standard text editors (with C-c for copy, C-v for paste, etc), but it also includes some unrelated niceties, like rectangle editing. Don't ask me why :). If you want to use the rectangle editing without enabling the CUA keybindings (which is what I do), set cua-enable-cua-keys to nil, which can be done via customize.
(defun number-region (start end)
(interactive "r")
(let* ((count 1)
(indent-region-function (lambda (start end)
(save-excursion
(setq end (copy-marker end))
(goto-char start)
(while (< (point) end)
(or (and (bolp) (eolp))
(insert (format "%d. " count))
(setq count (1+ count)))
(forward-line 1))
(move-marker end nil)))))
(indent-region start end)))
Here's some elisp code to do it; would be easy to customize if you like tinkering.
This will number the current region (unless it is already numbered), and also the last line binds to the M-n keys. You could use a function key "[F6]" as needed.
Modified to take a format string to use. The default is 1. but you could do something like %d) to get a bracket instead of a . and so on.
(defun number-region(fmt)
(interactive "sFormat : ")
(if (or (null fmt) (= 0 (length fmt)))
(setf fmt "%d. "))
(save-excursion
(save-restriction
(narrow-to-region (point) (mark))
(goto-char (point-min))
(let ((num 1))
(while (> (point-max) (point))
(if (null (number-at-point))
(insert (format fmt num)))
(incf num)
(forward-line))))))
(global-set-key "\M-n" 'number-region)
Not a direct answer to your question, but if you find yourself manipulating numbered lists frequently, you may want to look into org-mode. In particular, the section on plain lists.