[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
n3-mode.el: a major mode for editing Notation3 (and Turtle) data
From: |
Ivan Shmakov |
Subject: |
n3-mode.el: a major mode for editing Notation3 (and Turtle) data |
Date: |
Thu, 18 Jul 2013 21:50:50 +0000 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/23.4 (gnu/linux) |
Archive-name: n3-mode.el-2013-is
Submitted-by: address@hidden
Last-modified: 2013-07-18 21:16:42 +00:00
Copyright-Notice: Both the README and the code are under GNU GPL v3+.
[Replacing news:alt.sources with news:alt.sources.d within
Followup-To:, as per the former’s charter.]
README.n3-mode -*- Text -*-
Synopsis
### foo.n3 — Describing foo in Notation3 -*- N3 -*-
Load the library with M-x load-file or M-x load-library.
Add ‘-*- N3 -*-’ to the comment at the topmost line of an N3
data file (as shown above); use M-x normal-mode RET to turn the
mode on for the first time.
Use TAB, C-M-\, M-;, C-j, etc. as needed.
Summary
This Emacs major mode provides indentation support for Notation3
(and thus Turtle) files. The indentation style is influenced by
the n3-indent-level (customizable) variable, and follows the
following general rules:
• an element immediately (i. e., with no intervening newlines)
following an opening bracket or parenthesis sets the
indentation level for its “siblings,” like:
[ :foo :bar ;
:baz :qux ] .
• the indentation level is incremented after each “word,” like:
:foo
:bar
:baz
:qux
.
(even though this example isn’t valid Notation3);
• the indentation level is decremented by 1 after a comma, and
by 2 after a semicolon, like:
:foo
:bar :baz ,
:qux ;
:hello
:world .
• the indentation level of an element immediately after a period
is assumed to be the same as that of the element immediately
after the innermost enclosing pair of brackets or parentheses,
or zero if there’re none.
Bugs
The code assumes that a ‘#’ preceded by a whitespace character
(or beginning of the line) starts a comment; even though it
doesn’t, should it occur within a URI or a string literal.
Multiline (or “long”) string literals are not supported.
The closing brackets and parentheses have the same indentation
level as the enclosed (child) elements, while the other modes
generally indent them in line with the sibling elements instead.
Arguably, an opening curly brace should increment the
indentation level. Also, a period within a formula doesn’t seem
to set the indentation to the one of the preceding “sibling”
statement. (This particular issue is not relevant to Turtle.)
There’s no font-lock-mode (highlighting) support.
Be sure to check the FIXME: comments within the code itself.
README.n3-mode ends here
;;; n3-mode.el — Major mode for editing Notation3 -*- Emacs-Lisp -*-
;;; Copyright © 2013 Ivan Shmakov
;; Author: Ivan Shmakov
;; Version: 0.1
;; Keywords: languages
;; This program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or (at
;; your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
;;; Code:
(defcustom n3-indent-level 4
"*Indentation of Notation3 statements with respect to containing block."
:type 'integer
:group 'n3)
(defvar n3-mode-syntax-table
(let ((s (make-syntax-table)))
(modify-syntax-entry ?\n "> " s)
(modify-syntax-entry ?\r "> " s)
(modify-syntax-entry ?\f "> " s)
(modify-syntax-entry ?\# "< " s)
(modify-syntax-entry ?\\ "\\" s)
(modify-syntax-entry ?< "(>" s)
(modify-syntax-entry ?> ")<" s)
;; FIXME: shouldn’t ?: be a symbol constituent (_) instead?
(modify-syntax-entry ?: "w" s)
(modify-syntax-entry ?! "." s)
(modify-syntax-entry ?^ "." s)
s))
(defconst n3-token-re
(concat "\\([.,;]"
"\\|\\s(\\|\\s)"
"\\|\\S\\\"\\(?:.*\\S\\\\)?\""
"\\|\\<\\sw+\\>"
"\\|\\s<.*?\\s>"
"\\)")
"A regular expression for matching Notation3 tokens.")
(defconst n3-token-start-re
(concat "\\(\"\\|\\s>\\)\\|" n3-token-re)
"A regular expression for matching either \", \\s>, or an N3 token.")
;;;###autoload
(defun n3-mode ()
"Major mode for editing Notation3 data.
Turning on Notation3 mode runs the `n3-mode-hook' hook."
(interactive)
(kill-all-local-variables)
; (use-local-map n3-mode-map)
(setq major-mode 'n3-mode
mode-name "N3")
(set-syntax-table n3-mode-syntax-table)
(set (make-local-variable 'indent-line-function)
'n3-indent-line)
(set (make-local-variable 'comment-start) "# ")
;; FIXME: fails to handle ‘ #’ in strings and URIs properly
(set (make-local-variable 'comment-start-skip)
"\\(^\\|\\s-\\)#+ *")
(set (make-local-variable 'comment-end) "")
;; FIXME: with comment-use-syntax set to nil, ‘ #’ within a string
;; will be confused for a comment
(set (make-local-variable 'comment-use-syntax) nil)
;; however, with comment-use-syntax being non-nil, so will be ‘#’
;; within < >; (alas, ‘ #’ within < > will be confused either way)
; (set (make-local-variable 'comment-use-syntax) t)
(run-mode-hooks 'n3-mode-hook))
(defun n3-compute-indentation nil
"Compute the current line indentation according to the syntactic context."
(save-excursion
;; FIXME: assumes no token can contain a newline
;; FIXME: thus disallowing multi-line string literals
(forward-line 0)
(let (indent
(depth 0))
(while (and (not indent)
(> (point) (point-min)))
(if (re-search-backward n3-token-start-re (point-min) t)
(let* ((c (aref (match-string 0) 0))
(s (char-syntax c)))
; (message "@ %S (%S %S) %S: %S"
; (point) c (string s) depth (match-string 0))
(cond ((equal ?> s)
;; skip the comment, if any
(let ((p (point)))
(forward-line 0)
(save-match-data
;; NB: or use comment-search-forward here
(unless (re-search-forward comment-start-skip p t)
(goto-char p)))))
((or (equal ?\" c) (equal ?\) s))
;; skip this string or URI literal or a group
(goto-char (match-end 0))
;; FIXME: really using backward-sexp?
(backward-sexp)
(setq depth (+ 1 depth)))
((equal ? s)) ; ignore the whitespace
((equal ?w s)
;; increment the depth
(setq depth (+ 1 depth)))
((equal ?\( s)
;; check if this same line has a non-whitespace
(save-match-data
(when (looking-at "\\(\\s(\\s *\\)\\sw")
(goto-char (match-end 1))
;; we can compute the indentation right now
(setq indent
(+ (current-column)
(* (max 0 depth) n3-indent-level))))))
((equal ?. c)
;; we can compute the indentation right now
(setq indent (* (max 0 depth) n3-indent-level)))
((equal ?, c)
(setq depth (+ -1 depth)))
((equal ?\; c)
(setq depth (+ -2 depth)))))
;; no tokens found?
(setq indent 0)))
(or indent 0))))
(defun n3-indent-line nil
"Indent the current line according to the syntactic context."
(let ((c (n3-compute-indentation)))
(unless (= (current-indentation) c)
(save-excursion
(indent-line-to c)))
(when (< (current-column) c)
(forward-to-indentation 0))))
;;; The trailer
;; Local variables:
;; coding: utf-8
;; indent-tabs-mode: nil
;; End:
;;; n3-mode.el ends here
--
FSF associate member #7257
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- n3-mode.el: a major mode for editing Notation3 (and Turtle) data,
Ivan Shmakov <=