Emacs Specifying Rules for font-lock - emacs

I'm putting the parsing techniques I'm learning into practice. I'm trying to write a programming mode in Emacs,so I can take advantage of syntax highlighting and the like. unfortunately, font-lock isn't working. Searching on Google and following the tutorials found there yielded no results. Below is my code. Any advice is appreciated.
;;;###autoload
(defgroup use-mode nil
"Mode for editing Use source files."
:group 'languages)
;;;###autoload
(defcustom use-mode-hook nil
"Hook run when use-mode is started.")
(defvar use-mode-map (make-sparse-keymap)
"Keymap for use-mode.")
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.use\\'" . use-mode))
(defvar use-keywords-1 '("use" . font-lock-keyword-face)
"First level of font-lock in Use")
(defvar use-font-lock-keywords use-keywords-1
"Code highlighting.")
;;;###autoload
(define-derived-mode use-mode prog-mode "Use"
"Major mode for editing Use source files."
(setq font-lock-defaults '(use-font-lock-keywords)))
(provide 'use-mode)

When you define font-lock keywords, you should supply a list of entries. So, if you replace:
(defvar use-keywords-1 '("use" . font-lock-keyword-face)
"First level of font-lock in Use")
With the following, it will work:
(defvar use-keywords-1 '(("use" . font-lock-keyword-face))
"First level of font-lock in Use")
Note that unless you plan to write a really advanced system, you don't need to provide different levels, so you can drop the *-1 variables.
(Just in case you haven't seen it already, I would like to recommend one of my packages, font-lock-studio. It is a interactive debugger for font-lock keywords.)

Related

Where am I going wrong in defining emacs major mode?

I am trying to define a new mode which inherits everything from Org mode, called web mode.
Here is a preliminary amateur stab at this.
(defvar web-mode-syntax-table
org-mode-syntax-table
"Syntax table used while in `web-mode'.")
;; Create the keymap for this mode.
(defvar web-mode-map
org-mode-map
"Keymap for `web-mode'.")
(setq web-highlights
'(("Sin\\|Cos\\|Sum" . font-lock-function-name-face)
("Pi\\|Infinity" . font-lock-warning-face)))
;; set files ending in .web to open in web mode.
(add-to-list 'auto-mode-alist '("\\.web\\'" . web-mode))
(define-derived-mode web-mode org-mode "web-mode"
"Major mode based on Org-mode"
(kill-all-local-variables)
(setq major-mode 'web-mode)
(setq mode-name "Web Mode")
;; Tell font-lock mode about some things which
;; need to be highlighted.
(setq font-lock-defaults '(web-highlights))
)
However, when web-mode is loaded in a text file it seems identical to the plain-vanilla text mode. The key-words Sin, Cos and Sum get highlighted in blue correctly and the Pi and Infinity in bold red font, but otherwise nothing seems to have been inherited from Org mode, and seems indistinguishable from text mode.
Why is this?

My Emacs mode does not highlight keywords

I am trying to write an Emacs major mode but it is not working; specifically, my keywords are not being displayed in keyword font face. I have tried to follow the tutorials but I must be doing something wrong. I know a little Lisp but I do not know Emacs scripting.
My Emacs mode script:
;; emacs mode for OldRope
;; does no work for some reason
(setq oldrope-directive-keywords-regexp (regexp-opt '("page" "link" "goto" "act" "end" "div" "span" "include")))
(defvar oldrope-font-lock-defaults '((
(oldrope-directive-keywords-regexp . font-lock-keyword-face))))
(define-derived-mode oldrope-mode fundamental-mode
"oldrope mode"
"Major mode for editing OldRope games"
(setq comment-start "/*")
(setq comment-end "*/")
(setq font-lock-defaults oldrope-font-lock-defaults))
(provide 'oldrope-mode)
Test file:
$[page start]$ Hello $[link]$ Click me $[act]$ That is right. $[end]$
(For context, this is part of https://github.com/martinellison/oldrope but that is not really relevant to the question).
You need this - the rest is OK:
(defvar oldrope-font-lock-defaults
`(((,oldrope-directive-keywords-regexp . font-lock-keyword-face))))
By simply quoting the list you were not evaluating oldrope-directive-keywords-regexp - your quoted list just had that symbol as its car.
Using either backquote (`) plus comma (,) or (list (list (cons oldrope-directive-keywords-regexp 'font-lock-keyword-face))) you evaluate that variable and use its value in the resulting list.

Create a new mode in Emacs

I know nothing about Emacs Lisp (or any Lisp, for that matter). I want to do something that seems very simple, yet I have had no luck with online guides. I want to create "packet-mode.el" for .packet files. I want to do the following:
Enable C++ mode
Make packet a keyword, while leaving the rest of C++ mode unchanged
(define-derived-mode packet-mode fundamental-mode
(font-lock-add-keywords 'c++-mode `(("packet" . font-lock-keyword-face)))
(c++-mode))
(add-to-list 'auto-mode-alist '("\\.packet\\'" . packet-mode)
(provide 'packet-mode)
I've also tried switching the order of the statements in packet mode, but then the C++ highlighting breaks.
I would like packet to behave like struct in the sense that
packet foo {
int bar;
}
is highlighted the same way it would be if struct were used in place of packet.
Here is what you need to put into packet-mode.el:
(defvar packet-mode-font-lock-keywords
'(("\\<packet\\>" . font-lock-keyword-face)))
(define-derived-mode packet-mode c++-mode "Packet"
"A major mode to edit GNU ld script files."
(font-lock-add-keywords nil packet-mode-font-lock-keywords))
(add-to-list 'auto-mode-alist '("\\.packet\\'" . packet-mode))
(provide 'packet-mode)
Place packet-mode.el into a directory in your load-path and
(optionally) byte compile it.
Now, add (require 'packet-mode) into your .emacs.el.

Sublime Text 2's "Goto Anything" (or instant search) for Emacs?

I tried out Sublime Text 2 recently, and I found Goto Anything superbly useful for navigating source code (Ctrl-P file#symbol seems to work really well). Is there something similar for Emacs? Preferably something that just works, without a ton of custom elisp.
What I've tried so far:
I've seen Helm and Anything, but as far as I understand neither of them is capable of actual "instant" search (see edit below).
I've used multi-occur-in-matching-buffers, but it too seems unable to satisfy the "instant" criterion.
imenu / idomenu works well for single files, but doesn't work across files.
I currently use #2 and #3 together, as a poor substitute for Goto Anything.
If not an exact clone of Goto Anything, then I could make do with a naive instant search solution (one that searches for a given string across all open buffers and displays results dynamically). So that's acceptable too.
I use Emacs 24.2, so any v24-only elisp is also fine.
EDIT: I gave Helm another shot, at event_jr's suggestion, and I found that it does support instant searching across all open buffers. helm-multi-occur + helm-follow-mode comes surprisingly close to meeting my needs, the only minor issues being (at the risk of sounding nit-picky):
I haven't found a way to turn on helm-follow-mode automatically when I run helm-multi-occur. I have to invoke it manually with C-c C-f. Anyone care to take a shot at this with a snippet of elisp? (see edit #2 below)
it isn't "intelligent" like ST2's Goto Anything (i.e., it doesn't understand "symbols" in source code, like Goto Anything does).
EDIT #2: Now I've got most of Goto Anything, thanks to event_jr's answer below (and of course, thanks to Helm's creator, Thierry Volpiatto). I recommend it heartily to anyone looking for a similar feature. Below is the elisp I'm currently using:
;; instant recursive grep on a directory with helm
(defun instant-rgrep-using-helm ()
"Recursive grep in a directory."
(interactive)
(let ((helm-after-initialize-hook #'helm-follow-mode))
(helm-do-grep)))
;; instant search across all buffers with helm
(defun instant-search-using-helm ()
"Multi-occur in all buffers backed by files."
(interactive)
(let ((helm-after-initialize-hook #'helm-follow-mode))
(helm-multi-occur
(delq nil
(mapcar (lambda (b)
(when (buffer-file-name b) (buffer-name b)))
(buffer-list))))))
;; set keybindings
(global-set-key (kbd "C-M-s") 'instant-search-using-helm)
(global-set-key (kbd "C-M-S-s") 'helm-resume)
(global-set-key (kbd "C-M-g") 'instant-rgrep-using-helm)
Just use helm.
It is perhaps more configuration than you asked for, but once you get it
configured how you like, it should be quite comfortable. Very much like Emacs
;).
And you should file a bug with Thierry for getting some more newbie friendly
defaults. He is quite responsive with issues.
helm-multi-occur
Primarily multi-buffer interactive "occur" is provided through
helm-multi-occur. If you execute the command, you'll notice that you have
to pick some buffers first (use C-SPC to select from the list,
M-SPC to select all). Then you can enter your query at the next
prompt. It's easy to make your own version that skips the buffer selection
like so:
(eval-after-load "helm-regexp"
'(setq helm-source-moccur
(helm-make-source "Moccur"
'helm-source-multi-occur :follow 1)))
(defun my-helm-multi-all ()
"multi-occur in all buffers backed by files."
(interactive)
(helm-multi-occur
(delq nil
(mapcar (lambda (b)
(when (buffer-file-name b) (buffer-name b)))
(buffer-list)))))
helm-buffers-list
Often you don't care about the exact occurrences of the query string, but want a
list of all buffers that contain it.
helm-buffers-list has some tricks up its sleeve. The first symbol you
specify is filtering by major-mode, and you can use the "#" prefix to narrow
the list to buffers that contain a string.
To wit, "ruby #prompt" will show you a list of buffers whose major-mode
contains "ruby" and whose contents contains "prompt". Or you can just use "#prompt" to show all buffers that contain "prompt".
Powerful and comfortable once you get used to it.
EDIT modified my-helm-multi-all to enable helm-follow-mode.
EDIT 2 update helm-follow-mode code to reflect helm changes.
EDIT 3 updated again to reflect helm changes
Emacs has Projectile satisfy your need:
jump to a file in project
multi-occur in project buffers
Heml is far from the fuzzy searching of ST3.
Fiplr looks promising but doesn't work on my laptop (see first issue on the github)
Simp.el looks like Fiplr but doesn't work either on my end.
Projectile works for me! Here's your solution!
I used also ido-mode and flx-ido for the fuzzy searching,
and for the vertical way of displaying results I use this in my .emacs:
;; Display ido results vertically, rather than horizontally
(setq ido-decorations (quote ("\n-> " "" "\n " "\n ..." "[" "]" " [No match]" " [Matched]" " [Not readable]" " [Too big]" " [Confirm]")))
(defun ido-disable-line-truncation () (set (make-local-variable 'truncate-lines) nil))
(add-hook 'ido-minibuffer-setup-hook 'ido-disable-line-truncation)
(defun ido-define-keys () ;; C-n/p is more intuitive in vertical layout
(define-key ido-completion-map (kbd "C-n") 'ido-next-match)
(define-key ido-completion-map (kbd "C-p") 'ido-prev-match))
(add-hook 'ido-setup-hook 'ido-define-keys)
Icicles offers some features that are similar to what it seems you are looking for.
C-x b and C-x C-f, to choose buffers or files, allow multi-completion: you can type a pattern to match the buffer/file name and/or a pattern to match content in the buffer/file. Candidates are filtered incrementally as you type (what you call "instant" is what Emacs calls "incremental"). You can refine either or both search patterns progressively, narrowing the choices in different ways. You can visit any number of buffers/files that match, at the same time. You can also use the same method to search the marked files in Dired: C-F.
C-c `(icicle-search) incrementally searches across multiple buffers or files. Again, progressive refinement etc.
The main difference between #1 and #2 is this:
For #1, you just want to find matching buffers or files. You don't care immediately about finding particular occurrences --- any match suffices.
For #2, you provide the buffers or files to search, and you want to navigate among search hits.
You can also use #1 to locate the buffers and files you want, then search their contents: The content-matching pattern you last used is available as the search pattern for Isearch (C-s).
for emacs I customize and modify this solution (for use install helm):
(defun helm-occur-from-point (initial-value)
"Invoke `helm-occur' from point."
(interactive)
(let ((input initial-value)
(bufs (list (buffer-name (current-buffer)))))
;; (isearch-exit)
(helm-occur-init-source)
(helm-attrset 'moccur-buffers bufs helm-source-occur)
(helm-set-local-variable 'helm-multi-occur-buffer-list bufs)
(helm-set-local-variable
'helm-multi-occur-buffer-tick
(cl-loop for b in bufs
collect (buffer-chars-modified-tick (get-buffer b))))
(helm :sources 'helm-source-occur
:buffer "*helm occur*"
:history 'helm-grep-history
:input input
:truncate-lines t)))
(defun get-point-text ()
"Get 'interesting' text at point; either word, or region"
(if mark-active
(buffer-substring (mark) (point))
(thing-at-point 'symbol)))
(defun helm-occur-1 (initial-value)
"Preconfigured helm for Occur with initial input."
(helm-occur-from-point initial-value))
(defun bk-helm-occur ()
"Invoke helm-occur with initial input configured from text at point"
(interactive)
(helm-occur-1 (get-point-text)))
(global-set-key (kbd "M-s-o") 'bk-helm-occur)
primary it based on
#see https://news.ycombinator.com/item?id=6872508 but on last helm versions not work but fixed with my changes (just copy/paste from some internal helm modules)

Emacs: highlighting TODO *only* in comments

This question is related to another one, Emacs :TODO indicator at left side. I recently came across a minor mode I like a lot called FixmeMode. It supports auto highlighting of TODO marks, and navigating between them. However, I think it makes more sense to recognize the "TODO" strings only in comments, rather than polluting the whole file. Is it possible?
Check out the library fic-mode.el, it has been verified in C++ and Emacs-Lisp.
It was written specifically to answer this question.
The installation is like any standard package:
(require 'fic-mode)
(add-hook 'c++-mode-hook 'turn-on-fic-mode)
Though Wei Hu did ask for an easy way to add it to multiple modes, so here goes:
(defun add-something-to-mode-hooks (mode-list something)
"helper function to add a callback to multiple hooks"
(dolist (mode mode-list)
(add-hook (intern (concat (symbol-name mode) "-mode-hook")) something)))
(add-something-to-mode-hooks '(c++ tcl emacs-lisp) 'turn-on-fic-mode)
It's possible but quite a bit trickier. Fixme mode uses font-lock to do its highlighting, so it works on an as-you-type basis to highlight the keywords. Font-lock hooks in at a very low level, basically running after every change is made to the buffer's contents. It is highly optimized, though, which allows it to appear instantaneous on modern computers.
The TODO indicator in the left fringe is static. Execute the function and all current TODO's are highlighted; change the buffer (adding or removing TODO's) does not change the fringe indicator; that's only changed when the function runs again.
Your approach would have to get into syntax tables, determining first when you're in a comment and then looking for the keywords. The tricky part comes in doing this interactively (i.e. as you type). You should be able to hook into the font-lock constructs to do this, but the function you provide to search for the comment syntax table and then for the keywords better be very efficient, as it will be run each and every time a buffer changes (though it will only run on the changed region, I think). You would want to stuff all of this in font-lock-syntactic-keywords rather than font-lock-keywords because the syntactic-keyword pass happens before the syntactic pass (which happens before the keyword pass), and you need to set TODO inside comments before comments themselves are set.
Sorry it's not a full working-code answer.....
Maybe this will help: there's a fn c-in-literal in
cc-mode, and a similar csharp-in-literal in csharp mode. The
return value is c if in a C-style comment, c++ if in a C++
style comment. You could add that to the code at
Emacs :TODO indicator at left side
to get what you want.
(defun annotate-todo ()
"put fringe marker on TODO: lines in the curent buffer"
(interactive)
(let (lit)
(save-excursion
(goto-char (point-min))
(while (re-search-forward "TODO:" nil t)
(progn
(setq lit (c-in-literal)) ;; or csharp-in-literal
(if (or (eq lit 'c) (eq lit 'c++))
(let ((overlay (make-overlay (- (point) 5) (point))))
(overlay-put overlay 'before-string
(propertize "A"
'display
'(left-fringe ;; right
horizontal-bar
better-fringes-important-bitmap))))))))))
https://github.com/tarsius/hl-todo seems to do exactly what you want. I just tried it and love it.