mirror of
https://github.com/cp2k/cp2k.git
synced 2026-07-28 14:15:19 -04:00
Add emacs mode for editing CP2K input files (and locate it alongside the vim tools) (Lianheng Tong)
svn-origin-rev: 13495
This commit is contained in:
parent
16a09171f0
commit
4c382dc944
4 changed files with 312 additions and 0 deletions
69
tools/input_editing/emacs/README
Normal file
69
tools/input_editing/emacs/README
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
# -*- mode: org -*-
|
||||
|
||||
#+title: cp2k-mode.el README
|
||||
#+author: Lianheng Tong
|
||||
#+date: Wednesday, 2014/01/22
|
||||
|
||||
cp2k-mode.el is provides a major mode in emacs for editing CP2K input
|
||||
files. It has been tested on emacs 2.1, 2.3 and 2.4.
|
||||
|
||||
* Functionalities
|
||||
- Recognises and font-locks:
|
||||
- the full CP2K input preprocessor syntax
|
||||
- the sections and subsections
|
||||
- the keywords
|
||||
- the comment lines
|
||||
- Indents lines according to the CP2K input syntax using <tab> key
|
||||
- New interactive functions:
|
||||
- cp2k-indent-line: indents the line according to CP2K
|
||||
input syntax.
|
||||
- cp2k-beginning-of-block: goes to the beginning of the subsection,
|
||||
marks the current cursor position.
|
||||
- cp2k-end-of-block: goes to the ending of the subsection,
|
||||
marks the current cursor position.
|
||||
- Key Bindings:
|
||||
- <tab> cp2k-indent-line
|
||||
- C-j newline-and-indent
|
||||
- C-c ; comment-region
|
||||
- C-M-a cp2k-beginning-of-block
|
||||
- C-M-e cp2k-end-of-block
|
||||
|
||||
* Installation
|
||||
You need to put cp2k-mode.el in one of your local emacs lisp
|
||||
directories, which is in the search path of your emacs installation.
|
||||
|
||||
** Adding to emacs's search path
|
||||
|
||||
If you have never installed any packages manually before, and do not
|
||||
know the search path of your emacs installation, then in your home
|
||||
directory create directory:
|
||||
|
||||
~/.emacs.d/lisp/
|
||||
|
||||
This is the usual place where the local/user defined emacs lisp
|
||||
files are installed. Move cp2k-mode.el to ~/.emacs.d/lisp/
|
||||
|
||||
Then, add the following in your .emacs file (which should be in your
|
||||
home directory, and if it does not exist, create one):
|
||||
|
||||
(add-to-list 'load-path "~/.emacs.d/lisp/")
|
||||
|
||||
This tells emacs to add ~/.emacs.d/lisp/ to its search path for *.el
|
||||
files.
|
||||
|
||||
** Tell emacs to load cp2k-mode.el at startup
|
||||
|
||||
Once cp2k-mode.el is in the search path, we need to tell emacs to
|
||||
load it at start up, this is done by adding
|
||||
|
||||
(require 'cp2k-mode nil 'noerror)
|
||||
|
||||
to your .emacs file.
|
||||
|
||||
** Tell emacs to recognise *.inp automatically as a cp2k input file
|
||||
|
||||
Add
|
||||
|
||||
(add-to-list 'auto-mode-alist '("\\.inp\\'" . cp2k-mode))
|
||||
|
||||
to your .emacs file.
|
||||
243
tools/input_editing/emacs/cp2k-mode.el
Normal file
243
tools/input_editing/emacs/cp2k-mode.el
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
;;;;; Emacs major mode for cp2k input, written by Lianheng Tong
|
||||
;;;;; Copyright (c) Lianheng Tong
|
||||
;;;;; Last modify date: Thursday, 2013/12/05
|
||||
|
||||
;;;; Syntax highlighting of keywords
|
||||
(defconst cp2k-font-lock-keywords
|
||||
(list
|
||||
;; blocks
|
||||
'("^[ \t]*\\(&\\(END[ \t]*\\)?\\(\\sw+\\)\\)"
|
||||
(1 font-lock-function-name-face))
|
||||
;; keywords
|
||||
'("^[ \t]*\\<\\([^&@$]\\sw*\\)\\>"
|
||||
(1 font-lock-keyword-face))
|
||||
;; preprocessor type 1
|
||||
'("^[ \t]*\\(@\\(\\(I\\(F\\|NCLUDE\\)\\)\\|ENDIF\\)\\)"
|
||||
(1 font-lock-preprocessor-face))
|
||||
;; preprocessor type 2
|
||||
'("^[ \t]*\\(@SET\\)[ \t]+\\(\\sw+\\)"
|
||||
(1 font-lock-preprocessor-face) (2 font-lock-variable-name-face nil t))
|
||||
;; variables
|
||||
'("\\${?\\(\\sw+\\)}?"
|
||||
(1 font-lock-variable-name-face)))
|
||||
"Highlighting keywords for `cp2k-mode'.")
|
||||
|
||||
;;;; Syntax table
|
||||
(defconst cp2k-mode-syntax-table
|
||||
(let ((st (make-syntax-table)))
|
||||
(modify-syntax-entry ?# "<" st) ; # is beg. comment
|
||||
(modify-syntax-entry ?\n ">" st) ; \n is end. comment
|
||||
(modify-syntax-entry ?_ "w" st) ; underscore is part of names
|
||||
(modify-syntax-entry ?\' "\"" st) ; string quote
|
||||
(modify-syntax-entry ?\" "\"" st) ; string quote
|
||||
(modify-syntax-entry ?\r "-" st) ; return is whitespace
|
||||
(modify-syntax-entry ?+ "." st) ; + is puntuation
|
||||
(modify-syntax-entry ?- "." st) ; - is puntuation
|
||||
(modify-syntax-entry ?* "." st) ; * is puntuation
|
||||
(modify-syntax-entry ?/ "." st) ; / is puntuation
|
||||
(modify-syntax-entry ?= "." st) ; = is puntuation
|
||||
(modify-syntax-entry ?\\ "\\" st) ; \ is escape char
|
||||
st)
|
||||
"Syntax table for `cp2k-mode'.")
|
||||
|
||||
;;;; Define keymap for the major mode
|
||||
(defvar cp2k-mode-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
;; Define mode specific key-bindings here
|
||||
(define-key map (kbd "C-j") 'newline-and-indent)
|
||||
(define-key map (kbd "C-c ;") 'comment-region)
|
||||
(define-key map (kbd "TAB") 'cp2k-indent-line)
|
||||
(define-key map (kbd "C-M-a") 'cp2k-beginning-of-block)
|
||||
(define-key map (kbd "C-M-e") 'cp2k-end-of-block)
|
||||
map)
|
||||
"Keymap for `cp2k-mode'.")
|
||||
|
||||
;;;; Syntax indentation
|
||||
(defvar cp2k-indent
|
||||
2
|
||||
"standard indentation for in `cp2k-mode'")
|
||||
|
||||
(defconst cp2k-emptyline
|
||||
"^\\s-*$"
|
||||
"regexp matching an empty line in `cp2k-mode'")
|
||||
|
||||
(defconst cp2k-opening
|
||||
;; note that this definition also matches cp2k-closing, so for
|
||||
;; positive identification of cp2k-opening, one must use AND
|
||||
;; construct with (not lookingat cp2k-closing). One way to avoid
|
||||
;; this is to construct search for line that does NOT contain END,
|
||||
;; however, practical implementation of that leads to emacs
|
||||
;; occasionally throwing the exception "regex stack overflow"...
|
||||
;; The emacs regex search is pretty crudely implemented, and it is
|
||||
;; far more robust to do a positive search, than negative
|
||||
;; searches. So I opted for this more crude method here.
|
||||
"^[ \t]*\\(\\(&\\sw+\\)\\|\\(@IF\\>\\)\\)"
|
||||
"regexp matching lines starting (or closing --- due to
|
||||
limitations in regex implementation) a cp2k block in
|
||||
`cp2k-mode'")
|
||||
|
||||
(defconst cp2k-closing
|
||||
"^[ \t]*\\(\\(&END[ \t]*.*$\\)\\|\\(@ENDIF\\>\\)\\).*$"
|
||||
"regexp matching lines closing a cp2k block in `cp2k-mode'")
|
||||
|
||||
(defun cp2k-beginning-of-block (&optional not-set-mark)
|
||||
"move the cursor to the beginning of the block in `cp2k-mode'"
|
||||
(interactive)
|
||||
(if (not not-set-mark)
|
||||
(push-mark))
|
||||
(beginning-of-line)
|
||||
(let ((find_opening t)
|
||||
(in_nested nil)
|
||||
(initial_opening nil))
|
||||
;; if looking at opening now, search for the parent opening
|
||||
(if (and (looking-at cp2k-opening)
|
||||
(not (looking-at cp2k-closing))
|
||||
(not (bobp)))
|
||||
(setq initial_opening t))
|
||||
(while (and find_opening (not (bobp)))
|
||||
(if (and (looking-at cp2k-opening)
|
||||
(not (looking-at cp2k-closing))
|
||||
(not in_nested)
|
||||
(not initial_opening))
|
||||
(setq find_opening nil)
|
||||
(progn
|
||||
(when (and (looking-at cp2k-opening)
|
||||
(not (looking-at cp2k-closing)))
|
||||
(setq in_nested nil)
|
||||
(setq initial_opening nil))
|
||||
(forward-line -1)
|
||||
;; if the line is a closing statement then
|
||||
;; skip to the line of the opening statement
|
||||
(if (looking-at cp2k-closing)
|
||||
(progn
|
||||
(setq in_nested t)
|
||||
(cp2k-beginning-of-block t))))))))
|
||||
|
||||
(defun cp2k-end-of-block (&optional not-set-mark)
|
||||
"move the cursor to the ending of the block in `cp2k-mode'"
|
||||
(interactive)
|
||||
(if (not not-set-mark)
|
||||
(push-mark))
|
||||
(beginning-of-line)
|
||||
(let ((find_closing t)
|
||||
(in_nested nil)
|
||||
(initial_closing nil))
|
||||
;; if looking at closing now, search for the parent closing
|
||||
(if (and (looking-at cp2k-closing)
|
||||
(not (eobp)))
|
||||
(setq initial_closing t))
|
||||
(while (and find_closing (not (eobp)))
|
||||
(if (and (looking-at cp2k-closing)
|
||||
(not in_nested)
|
||||
(not initial_closing))
|
||||
(setq find_closing nil)
|
||||
(progn
|
||||
(when (looking-at cp2k-closing)
|
||||
(setq in_nested nil)
|
||||
(setq initial_closing nil))
|
||||
(forward-line 1)
|
||||
;; if the line is a opening statement then
|
||||
;; skip to the line of the closing statement
|
||||
(if (and (looking-at cp2k-opening)
|
||||
(not (looking-at cp2k-closing)))
|
||||
(progn
|
||||
(setq in_nested t)
|
||||
(cp2k-end-of-block t))))))))
|
||||
|
||||
(defun cp2k-forward-one-line ()
|
||||
"move the cursor foward one line, ignore empty or comment lines, in `cp2k-mode'"
|
||||
(beginning-of-line)
|
||||
(forward-line 1)
|
||||
(while (and (or (looking-at cp2k-emptyline)
|
||||
(looking-at "^[ \t]*#"))
|
||||
(not (eobp)))
|
||||
(forward-line 1)))
|
||||
|
||||
(defun cp2k-backward-one-line ()
|
||||
"move the cursor foward one line, ignore empty or comment lines, in `cp2k-mode'"
|
||||
(beginning-of-line)
|
||||
(forward-line -1)
|
||||
(while (and (or (looking-at cp2k-emptyline)
|
||||
(looking-at "^[ \t]*#"))
|
||||
(not (bobp)))
|
||||
(forward-line -1)))
|
||||
|
||||
(defun cp2k-left-of-point-is-empty ()
|
||||
"check if the left of the point is only white space in `cp2k-mode'"
|
||||
(let (not-empty)
|
||||
(save-excursion
|
||||
(setq not-empty
|
||||
(re-search-backward "[^ \t]" (line-beginning-position) t 1)))
|
||||
(not not-empty)))
|
||||
|
||||
(defun cp2k-indent-line ()
|
||||
"indent current line in `cp2k-mode'"
|
||||
(interactive)
|
||||
(let ((indent 0)
|
||||
(position (point-marker)))
|
||||
;; record initial indentation position
|
||||
(back-to-indentation)
|
||||
(indent-line-to
|
||||
(max
|
||||
0
|
||||
(catch 'indentation
|
||||
(save-excursion
|
||||
(beginning-of-line)
|
||||
(if (bobp) (throw 'indentation 0))
|
||||
;; get the block indentation
|
||||
(save-excursion
|
||||
(cp2k-beginning-of-block t)
|
||||
(setq indent (current-indentation)))
|
||||
;; look at the current line
|
||||
(if (looking-at cp2k-closing)
|
||||
(throw 'indentation indent))
|
||||
;; move up one non-empty line
|
||||
(cp2k-backward-one-line)
|
||||
(setq indent (current-indentation))
|
||||
(if (and (looking-at cp2k-opening)
|
||||
(not (looking-at cp2k-closing)))
|
||||
(setq indent (+ indent cp2k-indent)))
|
||||
(throw 'indentation indent)))))
|
||||
;; move cursor to indentation point if in the beginning white
|
||||
;; space otherwise leave unchanged
|
||||
(goto-char position)
|
||||
(if (cp2k-left-of-point-is-empty)
|
||||
(back-to-indentation))
|
||||
(set-marker position nil)))
|
||||
|
||||
;;;; Define mode hook
|
||||
(defvar cp2k-mode-hook nil)
|
||||
|
||||
;;;; Entry function
|
||||
(define-derived-mode cp2k-mode fundamental-mode "cp2k"
|
||||
"Major mode for editing cp2k input. Copyright (c) Lianheng Tong 2013/12/06"
|
||||
:syntax-table cp2k-mode-syntax-table
|
||||
;; setq-local is undefined in emacs versions prior 24.3, it is
|
||||
;; equivalent to make-local-variable, and followed by setq, and this
|
||||
;; is what has been used here. This works for older versions of
|
||||
;; emacs.
|
||||
(make-local-variable 'comment-start)
|
||||
(setq comment-start "# ")
|
||||
(make-local-variable 'comment-start-skip)
|
||||
(setq comment-start-skip "#+\\s-*")
|
||||
;; see emacs manual on font-lock-defaults, nil here means also
|
||||
;; font-lock comments and strings, and t means the value of
|
||||
;; font-lock-keywords-case-fold-search is set to non-nil, allowing
|
||||
;; case insensitive search
|
||||
(make-local-variable 'font-lock-defaults)
|
||||
(setq font-lock-defaults '(cp2k-font-lock-keywords nil t))
|
||||
;; whether the indentation key-word search case-sensitive or not (in
|
||||
;; my implementation, using looking-at function) is effected only by
|
||||
;; the variable case-fold-search, and is uneffected by
|
||||
;; font-lock-keywords-case-fold-search. So turn case-fold-search on
|
||||
;; just in case
|
||||
(make-local-variable 'case-fold-search)
|
||||
(setq case-fold-search t)
|
||||
(make-local-variable 'indent-line-function)
|
||||
(setq indent-line-function 'cp2k-indent-line))
|
||||
|
||||
;;;; Add to autoload alist
|
||||
(add-to-list 'auto-mode-alist '("\\.cp2kin\\'" . cp2k-mode))
|
||||
|
||||
;;;; Last line
|
||||
(provide 'cp2k-mode)
|
||||
Loading…
Add table
Add a link
Reference in a new issue