13

for those who don't know, imenu is a thing in emacs that lets a mode insert one or more menu items into the menu bar. The most common usage is to make a "table of contents" accessible from a drop-down menu, so the user can quickly jump to declarations of functions or classes or sections in a document, etc.

imenu has a couple different ways of working - in the first and more commonly used way, a major mode provides regexps to imenu, and imenu uses those regexps to perform the scan of the buffer and build the index. A major mode sets this up by putting the list of regexps into imenu-generic-expression. The second way is for the major mode to perform its own scan. It can do this by instead setting the variable imenu-create-index-function to the name of a function defined by themode, which returns a list containing the table of contents.

I'm doing the latter - imenu-create-index-function - but sometimes the fn takes a looong time to run, say 3 or 4 seconds or more, which freezes the UI. If I make the operation asynchronous, that would solve that problem.

I know about asynch processes. The scan logic is implemented in elisp. Is it possible to run elisp in an asynch process? If so, how?

Or, is there a way to run regular elisp asynchronously in emacs, without resorting to an asynch process?

I think the way font-lock does it is, it fontifies on idle. It keeps state and fontifies a little at a time, always remembering where it left off, what else needs to be fontified, what has changed since the last fontification run, etc. Is my understanding correct? Maybe I could use this incremental approach .

Recommendations?

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Cheeso
  • 189,189
  • 101
  • 473
  • 713

3 Answers3

11

To run elisp asynchronously you can use either run-with-idle-timer or run-with-timer. I imagine you'll want the idle version. Check the documentation links for more details.

Note: If the code takes 3 or 4 seconds to run, it'll still take that long (and freeze your Emacs while it runs), so if you can break the work up into small enough chunks that it only takes .5 seconds or so at a time, that might work well.

One package that I use all the time, pabbrev.el, uses idle timers really well - I never notice it running. That might be a good package to examine to see how it breaks up the work (it is scanning all open buffers and building up a word frequency list).

Trey Jackson
  • 73,529
  • 11
  • 197
  • 229
  • 2
    Now, in 2018, emacs documents the following: http://www.gnu.org/software/emacs/manual/html_node/elisp/Asynchronous-Processes.html#Asynchronous-Processes – user1404316 Aug 31 '18 at 17:13
4

The answers posted by TreyJackson and jeremiahd were valid back in year 2011. Now, in 2018, here is a link to the emacs documentation for asynchronous processes.

user1404316
  • 463
  • 6
  • 11
  • 2
    That section only documents how to use external processes asynchronously, not how to evaluate elisp code asynchronously. – dalanicolai Sep 13 '22 at 11:07
  • 1
    @dalanicolai is correct. The question asked about how to run elisp asynchronously, not external processes. This answer is both misleading and does not answer the question. Rare downvote from me. – eeowaa Oct 05 '22 at 17:15
1

You can run elisp in an asynch process by spawning emacs in batch mode as the process, see http://www.emacswiki.org/emacs/BatchMode . Other than that, there's basically nothing as far as I know.

It looks like http://nschum.de/src/emacs/async-eval/ basically wraps the boilerplate necessary to do this. No clue if it's actively maintained or anything though.

jdd
  • 4,301
  • 1
  • 27
  • 28