Single and multiline comments in emacs mode using syntax table - emacs

I am trying to create an emacs syntax highlighting for a language in which the comments are written as
; A single line comment
;; This comment has
multipline lines ;;
To do this I need to modify the entries in the syntax table. I have found that the following works perfectly for comments on multiple lines:
(modify-syntax-entry ?\; ". 1234" sbgl-mode-syntax-table)
And the following works perfectly for single line comments:
(modify-syntax-entry ?\; "< b" sbgl-mode-syntax-table)
(modify-syntax-entry ?\n "> b" sbgl-mode-syntax-table)
Does anybody know of a way to combine these?

If you can survive adding a space after each semicolon starting a single-line comment, you can treat it as an second character for one of the comment-start sequences and then here's a snippet that works for me:
(define-derived-mode sbgl-mode prog-mode "sbgl"
(set (make-local-variable 'font-lock-defaults)
'(nil ;; keywords
nil ;; keywords-only
nil ;; case-fold
((?\; . ". 1234b")
(?\n . ">")
(?\ . "- 2")))))
If not, then you always have an option to do the syntactic analysis prior to fontification via syntax-propertize-function variable (or font-lock-syntactic-keywords variable for pre-Emacs24).

You can try something like:
(modify-syntax-entry ?\; "< 1234b" sbgl-mode-syntax-table)
(modify-syntax-entry ?\n ">" sbgl-mode-syntax-table)

Related

Emacs Major Mode - Keywords "special char" and "one char" Keywords

i want to write a major mode for emacs which should do syntax highlighting for mml (music macro language) keywords. I followed this tutorial:
http://ergoemacs.org/emacs/elisp_syntax_coloring.html
here is my current code
(under x-events there are still placeholders, and x-functions I haven't adjusted yet and took over from the tutorial):
;;
;; to install this mode, put the following lines
;; (add-to-list 'load-path "~/.emacs.d/lisp/")
;; (load "mml-mode.el")
;; into your init.el file and activate it with
;; ALT+X mml-mode RET
;;
;; create the list for font-lock.
;; each category of keyword is given a particular face
(setq mml-font-lock-keywords
(let* (
;; define several category of keywords
(x-keywords '("#author" "#title" "#game" "#comment"))
(x-types '("&" "?" "/" "=" "[" "]" "^" "<" ">"))
(x-constants '("w" "t" "o" "#" "v" "y" "h" "q" "p" "n" "*" "!"))
(x-events '("#" "##" "ooo" "oooo"))
(x-functions '("llAbs" "llAcos" "llAddToLandBanList"
"llAddToLandPassList"))
;; generate regex string for each category of keywords
(x-keywords-regexp (regexp-opt x-keywords 'words))
(x-types-regexp (regexp-opt x-types 'words))
(x-constants-regexp (regexp-opt x-constants 'words))
(x-events-regexp (regexp-opt x-events 'words))
(x-functions-regexp (regexp-opt x-functions 'words)))
`(
(,x-types-regexp . font-lock-type-face)
(,x-constants-regexp . font-lock-constant-face)
(,x-events-regexp . font-lock-builtin-face)
(,x-functions-regexp . font-lock-function-name-face)
(,x-keywords-regexp . font-lock-keyword-face)
)))
;;;###autoload
(define-derived-mode mml-mode text-mode "mml mode"
"Major mode for editing mml (Music Macro Language)"
;; code for syntax highlighting
(setq font-lock-defaults '((mml-font-lock-keywords))))
;; add the mode to the `features' list
(provide 'mml-mode)
But now there are two problems:
First, I have several keywords that start with a # (e.g. #author). But the # doesn't seem to work, because if I leave it out, it works.
(x-keywords '("#author"))
does not work.
(x-keywords '("author"))
works, but the # is not colored. The same problem also occurs with the #. Possibly also with others, but I'll try to get them working one by one.
second, a keyword seems to need at least two letters.
(x-keywords '("o"))
does not work.
(x-keywords '("oo"))
works.
But I have several "keywords" which are followed by only one letter and two (arbitrary) hex numbers (0-F) (e.g. o7D)
How can I specify that these one letter keywords are found? (preferably together with the number, but no must).
Both problems arise from the same issue: it has to do with the way you construct the regular expressions:
(regexp-opt x-blabla 'words)
The problem is the 'words parameter. What this does is to enclose the generated regular expression in a \< ... \> pair. According to the Emacs manual, these special character classes are defined as follows:
\<
matches the empty string, but only at the beginning of a word.
‘\<’ matches at the beginning of the buffer only if a word-constituent
character follows.
\>
matches the empty string, but only at the end of a word.
‘\>’ matches at the end of the buffer only if the contents end with a
word-constituent character.
Now, what does "beginning of a word" mean to Emacs? That is mode-dependent. In fact, every major mode defines its own syntax-table which is a mapping of characters to syntax codes. There are a number of pre-defined classes, and one of them is "w" which defines a character as a word constituent. Normally, a text-based mode would define the letters a...z and A...Z to have the syntax code "w", but perhaps also other characters (e.g. a hyphen -).
Okay, back to the problem at hand. For, say x-keywords, the resulting x-keywords-regexp according to your definition is:
"\\<\\(#\\(?:author\\|comment\\|\\(?:gam\\|titl\\)e\\)\\)\\>"
(Note that inside strings, the backslash is a special character used to escape other special characters, e.g., \n or \t. So in order to encode a simple backslash itself, you have to quote it with another backslash.)
As discussed above, we see \< and \> (or, in string parlance: "\\<" and "\\>") at the beginning and the end of the regexp respectively. But, as we've just learned, in order for this regexp to match, both the first and the last character of the potential match need to have word-constituent syntax.
The letters are uncritical, but let's check the syntax code for # by typing C-h s:
The parent syntax table is:
C-# .. C-h . which means: punctuation
TAB .. C-j which means: whitespace
C-k . which means: punctuation
C-l .. RET which means: whitespace
C-n .. C-_ . which means: punctuation
SPC which means: whitespace
! . which means: punctuation
" " which means: string
# . which means: punctuation
...
(Obviously truncated.)
And there you have it! The # character does not have word constituent syntax, it is considered a punctuation.
But we can change that by putting the following line into the definition of your major-mode:
(modify-syntax-entry ?# "w" mml-mode-syntax-table)
?# is how chars are encoded in Emacs lisp (think '#' in C).
Regarding the second part of your question, in order to match something like o75, we'd have to do something similar: define all numbers to be word constituents:
(modify-syntax-entry '(?0 . ?9) "w" mml-mode-syntax-table)
However, we'd also need to write an appropriate regular expression to match such keywords. The regexp itself is not difficult:
"o[0-9A-F]\\{2\\}"
However, where to put that? Since it is already a regexp, we cannot simply add it to x-keywords because that is a list of simple strings.
However, we can concatenate it to x-keywords-regexp instead, by changing the respective line in your above code to read like this:
(x-keywords-regexp (concat (regexp-opt x-keywords 'words)
"\\|\\<[o][0-9A-F]\\{2\\}\\>"))
Note the "\\|" at the beginning of the string parameter, which is the regexp syntax for alternative matches.

How to add a comment style to an emacs mode

I am looking to add an additional single line style of comments !* to the Fortran mode on emacs, I'd add this to my init.el file.
From what I can see this should be doable using the modify-syntax-entry command, but I am struggling to succeed and there doesn't seem to be a fortran-mode-syntax-table so I can't see how I'd hook it to the mode.
My current effort (which causes an error).
(modify-syntax-entry ?\!\* "< \n")
(modify-syntax-entry ?\n "< \!\*")
The error reads An error occurred while loading 'init.el':
Invalid read syntax: ?
I finally figured out how to do this, and it's worth mentioning that with a normal Fortran setup ! causes comments, but not in mine.
So what I add to my init.el is
(add-hook 'fortran-mode-hook
(lambda ()
(modify-syntax-entry ?\! ". 1")
(modify-syntax-entry ?\* ". 2")
(modify-syntax-entry ?\n ">") ))
The first two modify-syntax-entry use the numeric syntax flags for a two character comment start sequence !* and > is the syntax class for comment ended, for which I have used \n to end the comment with a newline.
See https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-Flags.html and https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-Class-Table.html#Syntax-Class-Table for more details

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.

Emacs global-abbrev-table with bracketed definition

See the following abbrev-table for emacs:
(define-abbrev-table 'global-abbrev-table '(
("8in" "∈")
("(x)" "⊗")
))
(setq-default abbrev-mode t)
If I evaluate the region above and then type in "8in", this string is abbreviated to ∈ in my emacs buffer. Great. However, if I type in "(x)", this is not abbreviated to anything. I was hoping for an abbreviation to ⊗. What have I got wrong in my global-abbrev-table definition? I have also tried with \(x\) and \\(x\\), but neither result in an abbreviation of "(x)".
(let ((syntab (copy-syntax-table)))
(modify-syntax-entry ?\( "w" syntab)
(modify-syntax-entry ?\) "w" syntab)
(set-syntax-table syntab))
(define-abbrev-table 'global-abbrev-table '(("(x)" "⊗")))
Of course, you might not want ( and ) to have word-constituent syntax in general...
Seems Emacs currently only accepts word syntax for characters composing an abbreviation.
BTW can't see a reason for that.

Customizing check-parens to check double-quotes

I have check-parens set to a save hook for my files, my Markdown files in particular, to alert me about unbalanced parentheses. They are almost always errors, and this has saved me from a great many errors involving Markdown links inside parenthetical asides:
;In Markdown files, there are few excuses for unbalanced delimiters
(add-hook 'markdown-mode-hook
(lambda ()
(when buffer-file-name
(add-hook 'after-save-hook
'check-parens
nil t))))
I've noticed that I have similar issues with quoting - I will drop a trailing quote, or I will forget to convert single and doubles appropriately, etc. (This sometimes overlaps with link errors when I put paper titles into the tooltip.) There's little more reason for imbalanced "s than there are for (s or )s, and it's the same task check-parens is already doing. So naturally I'd like to have check-parens cover quotes as well.
But I can't seem to do so! The right way seems to involve hacking the Markdown syntax table, but nothing I try seems to work –
(modify-syntax-entry ?\" "(\"" markdown-mode-syntax-table)
(modify-syntax-entry ?\" ")\"" markdown-mode-syntax-table)
(modify-syntax-entry ?\" "$\"" markdown-mode-syntax-table)
(modify-syntax-entry ?\" "^\"" markdown-mode-syntax-table)
(modify-syntax-entry ?\" ".\"" markdown-mode-syntax-table)
(modify-syntax-entry ?' "\"" markdown-mode-syntax-table)
etc etc etc. They all either do nothing or cause check-parens to spit out errors early in the file where as far as I can tell everything works just fine.
I've read through a number of links on the topic and the C-h f documentation for modify-syntax-entry:
http://www.emacswiki.org/emacs/ParenthesisMatching#toc1
https://www.gnu.org/software/emacs/manual/html_node/elisp/Syntax-for-Strings.html
http://www.emacswiki.org/emacs/EmacsSyntaxTable
http://zvon.org/other/elisp/Output/SEC561.html
http://www.chemie.fu-berlin.de/chemnet/use/info/elisp/elisp_32.html
http://www.delorie.com/gnu/docs/elisp-manual-21/elisp_350.html
and asked on #emacs, to no avail.
(The version is Emacs 24.0.93.1 on Debian unstable.)
Try
(modify-syntax-entry ?\" "\"" markdown-mode-syntax-table)