experiments, projects, miscellany

Sunday, January 23, 2011

Syntax highlighting for CNC G-Code files in Emacs

Here's a snippet of Emacs Lisp code that enables syntax highlighting for G-Code, the language used by CNC machines for machining under computer control. This highlighting is based on generic-mode, which is a kind of catch-all mode that Emacs uses for highlighting of all files with relatively simple syntax. It allows for highlighting of comments, keywords, and anything else that can be matched by a regular expression.

To use it, insert the following code into your .emacs file. I've selected '.ngc' as the file suffix for G-Code files, but you can make it anything you want if your system uses some other suffix. I chose '.ngc' because that's what's used by EMC which is the CNC software I'm using for my Laser machine.
(require 'generic-x)

(define-generic-mode gcode-generic-mode
  '(("(" . ")"))
  (apply 'append 
         (mapcar #'(lambda (s) (list (upcase s) (downcase s) (capitalize s)))
                 '("sub" "endsub" "if" "do" "while" "endwhile" "call" "endif" 
                   "sqrt" "return" "mod" "eq" "ne" "gt" "ge" "lt" "le" "and" 
                   "or" "xor" "atan" "abs" "acos" "asin" "cos" "exp" 
                   "fix" "fup" "round" "ln" "sin" "tan" "repeat" "endrepeat")))
  '(("\\(#<_?[A-Za-z0-9_]+>\\)" (1 font-lock-type-face))
    ("\\([NnGgMmFfSsTtOo]\\)" (1 font-lock-function-name-face))
    ("\\([XxYyZzAaBbCcUuVvWwIiJjKkPpQqRr]\\)" (1 font-lock-string-face))
    ("\\([\-+]?[0-9]*\\.[0-9]+\\)" (1 font-lock-constant-face))
    ("\\(#[0-9]+\\)" (1 font-lock-type-face))
    ("\\([0-9]+\\)" (1 font-lock-constant-face)))
  '("\\.ngc\\'")
  nil
  "Generic mode for g-code files.")

Here's a screen-cap that gives an idea of how it looks in action. I took this example from section 3.4 of the EMC Wiki "OWord" chapter.




HTML generated by org-mode 6.33x in emacs 23


Saturday, January 22, 2011

Setting multiple text properties in elisp

Recently I was creating some simple elisp functions to make journal entries, and wanted to be able to define a keybinding that would set some combination of text properties on the selected text, or on text subsequently entered.

For some reason, this didn't seem to work in any obvious (at least to me) manner, but eventually with help from gnu.emacs.help I found a method that works. The function to be used is (put-text-property start end prop value).

The name of this function implies that it sets only a single text property. This is more or less correct, as the property I want to set is the "face" property. This property controls many aspects of the appearance of thetext, but the ones I was interested in were bold, italic, and foreground color, and it is not at all clear from the emacs documentation how to set more than one of these.

The answer is that if the property you are setting is the "face" property, you can supply as list as the value, and the face will be set to a combination of the values in the list.

Here are some examples of how to do this (tested on Emacs 23). These calls set properties on the entire line containing point.

;; Italic only 
(put-text-property (line-beginning-position) (line-end-position) 
  'face 'italic) 

;; Blue only: 
(put-text-property (line-beginning-position) (line-end-position) 
  'face '(:foreground "blue")) 

;; Blue and bold: 
(put-text-property (line-beginning-position) (line-end-position) 
  'face '((:foreground "blue") bold)) 

;; Blue and italic: 
(put-text-property (line-beginning-position) (line-end-position) 
  'face '((:foreground "blue") italic)) 

;; Bold, italic, and red: 
(put-text-property (line-beginning-position) (line-end-position) 
  'face '(bold italic (:foreground "red")))