elispcscope

Wrapping a quoted function in emacs-lisp


I use the cscope emacs extension (and find it quite useful). Unfortunately, it's default behaviour of only searching the current directory and below is insufficient for me, so I use the cscope-set-initial-directory to the directory of my choice. Unfortunately this has become insufficient for me as well because I have multiple different projects each with their own "initial" directory.

I have set up hot keys for the three cscope methods I use the most in emacs

(global-set-key [f9] 'cscope-find-this-text-string)
(global-set-key [f8] 'cscope-find-global-definition)
(global-set-key [f7] 'cscope-find-this-symbol)

I figured it would be pretty easy to somehow wrap those calls with a function to run cscope-set-initial-directory on a given path (generated by looking at what the buffer-file-name is). But I have as-yet been unsuccessful!

(global-set-key [f9] (lambda () (interactive) (cscope-set-initial-directory "blah") 'cscope-find-this-text-string))

doesn't work. I've also tried adding hooks to the two cscope-hooks, but neither of those seem to ever get called during my normal usage patterns. I wouldn't even mind running it once every time I switch buffers, but I didn't see a hook for that anywhere either :/.

Can someone help? :)


Solution

  • Disclaimer: I've not installed cscope so cannot test this.

    (global-set-key (kbd "<f9>") 'my-cscope-find-this-text-string)
    (defun my-cscope-find-this-text-string (dir)
      (interactive "DRoot area to start search:")
      (let ((default-directory dir))
        (call-interactively 'cscope-find-this-text-string)))
    

    The basic idea being you want to prompt for a directory to start from: that's the call to interactive. Then you set the directory: the let statement does that for you. Then you call the original routine you wanted, and by calling it with 'call-interactively you get prompted.

    You'd wrap the other two routines similarly.

    Once that's working for you, you can get fancier by customizing prompt for a root area to have its own history variable that's shared across the three routines.

    Regarding your initial solution, that was a good try. Most don't realize the need for 'interactive to turn the function into a command. The reason the quoted name doesn't work for you is that the quote simply tells the interpreter to treat the symbol as a symbol and not do to anything with it. To call the routine, you'd generally do:

    (lambda ()
        (c-scope-find-this-text-string "some-string"))
    

    Unfortunately, with a direct call like the one just above, you have to provide an argument (the string to search for). So, you can either add some code to prompt for the string, or use the command's built-in code to do the prompting. That's what the 'call-interactively is used for, it calls the command and invokes its 'interactive form which does the prompting.

    Also, it's generally a good idea to bind keystrokes to names of commands, as opposed to bare lambdas, for two reasons: first, if you ever do C-h k (M-x describe-key), you get a meaningful command name, and second, if/when you modify the function, you can do so without having to muck with the binding as well.