??? means which-function-mode
can't find current function name.
Read code of which-function-mode
you will find that imenu
setup in your major mode hook provides function names used by other plugins like which-function-mode
.
So the real problem is how to setup imenu in major mode hook.
Here is a simplified version of my setup for js-mode
,
(setq javascript-common-imenu-regex-list
'(("Controller" "[. \t]controller([ \t]*['\"]\\([^'\"]+\\)" 1)
("Controller" "[. \t]controllerAs:[ \t]*['\"]\\([^'\"]+\\)" 1)
("Filter" "[. \t]filter([ \t]*['\"]\\([^'\"]+\\)" 1)
("State" "[. \t]state[(:][ \t]*['\"]\\([^'\"]+\\)" 1)
("Factory" "[. \t]factory([ \t]*['\"]\\([^'\"]+\\)" 1)
("Service" "[. \t]service([ \t]*['\"]\\([^'\"]+\\)" 1)
("Module" "[. \t]module( *['\"]\\([a-zA-Z0-9_.]+\\)['\"], *\\[" 1)
("ngRoute" "[. \t]when(\\(['\"][a-zA-Z0-9_\/]+['\"]\\)" 1)
("Directive" "[. \t]directive([ \t]*['\"]\\([^'\"]+\\)" 1)
("Event" "[. \t]\$on([ \t]*['\"]\\([^'\"]+\\)" 1)
("Config" "[. \t]config([ \t]*function *( *\\([^\)]+\\)" 1)
("Config" "[. \t]config([ \t]*\\[ *['\"]\\([^'\"]+\\)" 1)
("OnChange" "[ \t]*\$(['\"]\\([^'\"]*\\)['\"]).*\.change *( *function" 1)
("OnClick" "[ \t]*\$([ \t]*['\"]\\([^'\"]*\\)['\"]).*\.click *( *function" 1)
("Watch" "[. \t]\$watch( *['\"]\\([^'\"]+\\)" 1)
("Function" "function[ \t]+\\([a-zA-Z0-9_$.]+\\)[ \t]*(" 1)
("Function" "^[ \t]*\\([a-zA-Z0-9_$.]+\\)[ \t]*=[ \t]*function[ \t]*(" 1)
;; {{ es6 beginning
("Function" "^[ \t]*\\([A-Za-z_$][A-Za-z0-9_$]+\\)[ \t]*([a-zA-Z0-9, ]*) *\{ *$" 1) ;; es6 fn1 () { }
("Function" "^[ \t]*\\([A-Za-z_$][A-Za-z0-9_$]+\\)[ \t]*=[ \t]*(?[a-zA-Z0-9, ]*)?[ \t]*=>[ \t]*\{ *$" 1) ;; es6 fn1 = (e) => (var, var2) {
;; }}
("Task" "[. \t]task([ \t]*['\"]\\([^'\"]+\\)" 1)
))
;; js-mode imenu enhancement
;; @see http://stackoverflow.com/questions/20863386/idomenu-not-working-in-javascript-mode
(defun mo-js-imenu-make-index ()
(save-excursion
(imenu--generic-function javascript-common-imenu-regex-list)))
(defun mo-js-mode-hook ()
(setq imenu-create-index-function 'mo-js-imenu-make-index))
(add-hook 'js-mode-hook 'mo-js-mode-hook)
My actual setup is more complicated (https://github.com/redguardtoo/emacs.d/blob/master/lisp/init-javascript.el)
Some major modes provide advanced imenu utilities out of the box.
If there are multiple major modes for one programming language, the solution could be as simple as choosing a better major mode.
For example, both js-mode and js2-mode supports javascript, but js2-mode provides better imenu utilities. If you use js2-mode for javascript code, your which-function-mode
works with much less manual imenu setup code.
My article http://blog.binchen.org/posts/why-emacs-is-better-editor.html discuss the technical details on hacking js2-mode imenu code if you are still not satisfied with js2-mode's default imenu setup.
The reason you need hacking is that some major modes will provide their own imenu framework. For example, in web-mode
you need change web-mode-imenu-regexp-list
instead of standard imenu variables.
Grep my emacs configuration at https://github.com/redguardtoo/emacs.d/tree/master/lisp , you will find many samples on imenu setup.