Skip to content

Instantly share code, notes, and snippets.

@dotemacs
Last active April 20, 2026 13:23
Show Gist options
  • Select an option

  • Save dotemacs/48b66241e664524eb691177b776bef38 to your computer and use it in GitHub Desktop.

Select an option

Save dotemacs/48b66241e664524eb691177b776bef38 to your computer and use it in GitHub Desktop.

Revisions

  1. dotemacs revised this gist Apr 20, 2026. 1 changed file with 17 additions and 0 deletions.
    17 changes: 17 additions & 0 deletions rdfox-datalog-mode.el
    Original file line number Diff line number Diff line change
    @@ -93,6 +93,22 @@
    st)
    "Syntax table for `rdfox-datalog-mode'.")

    (defun rdfox-datalog-syntax-propertize (start end)
    "Prevent comment syntax from applying to # inside IRI refs between START and END."
    (save-excursion
    (goto-char start)
    (remove-text-properties start end '(syntax-table nil))
    (while (re-search-forward "<[^>\n]*>" end t)
    (let ((iri-start (match-beginning 0))
    (iri-end (match-end 0)))
    (save-excursion
    (goto-char iri-start)
    (while (search-forward "#" iri-end t)
    (put-text-property (1- (point))
    (point)
    'syntax-table
    (string-to-syntax "."))))))))

    (defun rdfox-datalog--previous-significant-line ()
    "Move point to previous non-empty, non-comment line.
    Return point if found, otherwise nil."
    @@ -153,6 +169,7 @@ Return point if found, otherwise nil."
    "Major mode for editing RDFox Datalog files."
    :syntax-table rdfox-datalog-mode-syntax-table
    (setq-local font-lock-defaults '(rdfox-datalog-font-lock-keywords))
    (setq-local syntax-propertize-function #'rdfox-datalog-syntax-propertize)
    (setq-local comment-start "#")
    (setq-local comment-end "")
    (setq-local indent-line-function #'rdfox-datalog-indent-line)
  2. dotemacs created this gist Apr 20, 2026.
    166 changes: 166 additions & 0 deletions rdfox-datalog-mode.el
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,166 @@
    ;;; rdfox-datalog-mode.el --- Major mode for editing RDFox Datalog files -*- lexical-binding: t; -*-

    ;; Author: Aleksandar Simic <a@repl.ist>
    ;; Keywords: languages, convenience
    ;; Version: 0.1.0

    ;; This file is NOT part of GNU Emacs.

    ;;; Commentary:
    ;;
    ;; A major mode for editing .dlog files.
    ;;
    ;; Features:
    ;; - Syntax highlighting for RDFox Datalog keywords, built-ins, variables,
    ;; IRIs, literals, and operators.
    ;; - # comments.
    ;; - Basic indentation.
    ;; - Automatic activation for .dlog files.

    ;;; Code:

    (require 'rx)

    (defgroup rdfox-datalog nil
    "Major mode for RDFox Datalog files."
    :group 'languages)

    (defcustom rdfox-datalog-indent-offset 2
    "Indentation width for `rdfox-datalog-mode'."
    :type 'integer
    :group 'rdfox-datalog)

    (defconst rdfox-datalog--keywords
    '("PREFIX" "NOT" "EXIST" "EXISTS" "IN" "FILTER" "BIND" "AS" "AGGREGATE" "ON"
    "COUNT" "MIN" "MAX" "SUM" "AVG" "DISTINCT")
    "Datalog keywords understood by the parser package.")

    (defconst rdfox-datalog--builtins
    '("CONCAT" "STR" "IF" "IRI" "SKOLEM" "ROUND" "REGEX")
    "Built-in RDFox Datalog function names.")

    (defconst rdfox-datalog-font-lock-keywords
    `((,(rx symbol-start (regexp (regexp-opt rdfox-datalog--keywords t)) symbol-end)
    . font-lock-keyword-face)
    (,(rx symbol-start (regexp (regexp-opt rdfox-datalog--builtins t)) symbol-end)
    . font-lock-builtin-face)
    (,(rx symbol-start (or "true" "false") symbol-end)
    . font-lock-constant-face)
    (,(rx "?" (one-or-more (or word ?_)))
    . font-lock-variable-name-face)
    (,(rx "_:" (one-or-more (or word ?_)))
    . font-lock-constant-face)
    (,(rx "<" (zero-or-more (not (any "\n" ">"))) ">")
    . font-lock-constant-face)
    (,(rx symbol-start
    (one-or-more (or word ?_))
    ":"
    (one-or-more (or word ?_))
    symbol-end)
    . font-lock-constant-face)
    (,(rx symbol-start
    (or ":"
    (seq (one-or-more (or word ?_)) ":"))
    symbol-end)
    . font-lock-constant-face)
    (,(rx ":" (one-or-more (or word ?_)))
    . font-lock-constant-face)
    (,(rx (or ":-" "!=" "<=" ">=" "&&" "||"))
    . font-lock-keyword-face)
    (,(rx symbol-start
    (optional (any "+" "-"))
    (one-or-more digit)
    (optional "." (zero-or-more digit))
    (optional (any "e" "E") (optional (any "+" "-")) (one-or-more digit))
    symbol-end)
    . font-lock-constant-face))
    "Font lock rules for `rdfox-datalog-mode'.")

    (defvar rdfox-datalog-mode-syntax-table
    (let ((st (make-syntax-table)))
    ;; # comments
    (modify-syntax-entry ?# "<" st)
    (modify-syntax-entry ?\n ">" st)

    ;; Strings
    (modify-syntax-entry ?\" "\"" st)
    (modify-syntax-entry ?' "\"" st)

    ;; Word constituents for common Datalog tokens.
    (modify-syntax-entry ?? "_" st)
    (modify-syntax-entry ?_ "w" st)
    (modify-syntax-entry ?: "_" st)
    st)
    "Syntax table for `rdfox-datalog-mode'.")

    (defun rdfox-datalog--previous-significant-line ()
    "Move point to previous non-empty, non-comment line.
    Return point if found, otherwise nil."
    (catch 'found
    (while (zerop (forward-line -1))
    (back-to-indentation)
    (unless (or (eolp) (looking-at-p "#"))
    (throw 'found (point))))
    nil))

    (defun rdfox-datalog--line-starts-with-closing-delimiter-p ()
    "Return non-nil if current line starts with a closing delimiter or terminal dot."
    (save-excursion
    (back-to-indentation)
    (looking-at-p (rx (or ")" "]" ".")))))

    (defun rdfox-datalog--previous-line-opens-body-p ()
    "Return non-nil if the previous significant line opens a continuation block."
    (save-excursion
    (when (rdfox-datalog--previous-significant-line)
    (end-of-line)
    (skip-chars-backward " \t")
    (or (looking-back ":-" (line-beginning-position))
    (looking-back "[][(),]$" (line-beginning-position))
    (looking-back ",$" (line-beginning-position))))))

    (defun rdfox-datalog-compute-indentation ()
    "Compute indentation for the current line."
    (save-excursion
    (back-to-indentation)
    (cond
    ((bobp) 0)
    ((rdfox-datalog--line-starts-with-closing-delimiter-p)
    (when (ignore-errors (backward-up-list) t)
    (current-indentation)))
    ((rdfox-datalog--previous-line-opens-body-p)
    (+ (save-excursion
    (rdfox-datalog--previous-significant-line)
    (current-indentation))
    rdfox-datalog-indent-offset))
    (t
    (or (save-excursion
    (when (rdfox-datalog--previous-significant-line)
    (current-indentation)))
    0)))))

    (defun rdfox-datalog-indent-line ()
    "Indent current line for `rdfox-datalog-mode'."
    (interactive)
    (let ((indent (rdfox-datalog-compute-indentation))
    (offset (- (current-column) (current-indentation))))
    (indent-line-to (max indent 0))
    (when (> offset 0)
    (move-to-column (+ indent offset)))))

    ;;;###autoload
    (define-derived-mode rdfox-datalog-mode prog-mode "RDFox-Datalog"
    "Major mode for editing RDFox Datalog files."
    :syntax-table rdfox-datalog-mode-syntax-table
    (setq-local font-lock-defaults '(rdfox-datalog-font-lock-keywords))
    (setq-local comment-start "#")
    (setq-local comment-end "")
    (setq-local indent-line-function #'rdfox-datalog-indent-line)
    (setq-local indent-tabs-mode nil))

    ;;;###autoload
    (add-to-list 'auto-mode-alist '("\\.dlog\\'" . rdfox-datalog-mode))

    (provide 'rdfox-datalog-mode)

    ;;; rdfox-datalog-mode.el ends here